From 94638a21ddcd969e013ba0cc80bc3900b04da4d4 Mon Sep 17 00:00:00 2001 From: Anrimian Date: Sat, 21 Sep 2024 10:00:46 +0200 Subject: [PATCH] + version up: 0.9.8.1 (175) --- app/build.gradle | 11 +- app/lite/build.gradle | 10 +- app/lite/proguard-rules-lite.pro | 4 + app/lite/release/output-metadata.json | 6 +- .../anrimian/musicplayer/lite/LiteApp.kt | 14 +- .../musicplayer/lite/di/LiteComponents.kt | 40 +- .../musicplayer/lite/di/app/LiteAppModule.kt | 42 +- .../lite/ui/ActionStateBinderImpl.kt | 13 + app/proguard-rules.pro | 8 +- .../widget/PublicActionMenuPresenter.java | 2 +- .../com/github/anrimian/musicplayer/App.java | 18 +- .../anrimian/musicplayer/Constants.java | 8 +- .../anrimian/musicplayer/di/Components.java | 70 ++ .../musicplayer/di/app/AppComponent.java | 6 +- .../musicplayer/di/app/AppModule.java | 1 + .../musicplayer/di/app/MusicModule.java | 5 + .../musicplayer/di/app/PlayListsModule.kt | 163 ++-- .../musicplayer/di/app/SchedulerModule.java | 9 + .../app/editor/album/AlbumEditorComponent.kt | 13 +- .../di/app/editor/album/AlbumEditorModule.kt | 57 +- .../CompositionEditorComponent.java | 10 - .../composition/CompositionEditorModule.kt | 58 +- .../ExternalPlayerComponent.kt | 12 +- .../external_player/ExternalPlayerModule.kt | 38 +- .../di/app/library/LibraryComponent.kt | 59 +- .../di/app/library/LibraryModule.kt | 153 ++-- .../di/app/library/LibraryScope.kt | 17 +- .../LibraryCompositionsComponent.kt | 15 +- .../compositions/LibraryCompositionsModule.kt | 72 +- .../library/files/LibraryFilesComponent.kt | 21 +- .../app/library/files/LibraryFilesModule.kt | 70 +- .../di/app/library/files/LibraryFilesScope.kt | 17 +- .../library/files/folder/FolderComponent.kt | 14 +- .../app/library/files/folder/FolderModule.kt | 83 +- .../di/app/library/genres/GenresComponent.kt | 19 +- .../di/app/library/genres/GenresModule.kt | 56 +- .../genres/items/GenreItemsComponent.kt | 14 +- .../library/genres/items/GenreItemsModule.kt | 80 +- .../di/app/play_list/PlayListComponent.kt | 17 +- .../di/app/play_list/PlayListModule.kt | 95 ++- .../infrastructure/MediaSessionHandler.kt | 78 +- .../service/SystemServiceControllerImpl.java | 75 +- .../media_browser/AppMediaBrowserService.kt | 93 +-- .../service/music/MusicService.kt | 23 +- .../activity/BaseAppCompatActivity.java | 17 +- .../activity/BaseMvpAppCompatActivity.kt | 15 + .../ui/common/dialogs/DialogUtils.kt | 33 +- .../composition/CompositionPopupMenu.kt | 4 + .../dialogs/input/InputTextDialogFragment.kt | 73 +- .../ui/common/format/FormatUtils.kt | 47 +- .../ui/common/format/MessageTextFormatter.kt | 57 ++ .../ui/common/format/MessagesUtils.java | 2 +- .../DescriptionSpannableStringBuilder.java | 9 + .../format/wrappers/CompositionItemWrapper.kt | 17 +- .../ui/common/locale/LocaleControllerImpl.kt | 4 +- .../musicplayer/ui/common/mvp/AppPresenter.kt | 23 + .../ui/common/toolbar/AdvancedToolbar.kt | 174 +++-- .../ui/editor/album/AlbumEditorActivity.kt | 13 +- .../ui/editor/album/AlbumEditorPresenter.kt | 2 +- .../ui/editor/batch/BatchEditorPresenter.kt | 2 +- .../composition/CompositionEditorActivity.kt | 15 +- .../composition/CompositionEditorPresenter.kt | 2 +- .../ui/editor/lyrics/LyricsEditorActivity.kt | 13 +- .../ui/editor/lyrics/LyricsEditorPresenter.kt | 2 +- .../albums/items/AlbumItemsFragment.kt | 10 +- .../artists/items/ArtistItemsFragment.kt | 4 +- .../BaseLibraryCompositionsFragment.kt | 5 +- .../BaseLibraryCompositionsPresenter.kt | 4 +- .../library/folders/LibraryFoldersFragment.kt | 28 +- .../folders/LibraryFoldersPresenter.kt | 11 +- .../ui/library/folders/LibraryFoldersView.kt | 3 +- .../genres/items/GenreItemsFragment.kt | 12 +- .../genres/items/GenreItemsPresenter.kt | 6 +- .../musicplayer/ui/main/MainActivity.kt | 12 +- .../external_player/ExternalPlayerActivity.kt | 12 +- .../ui/main/setup/SetupFragment.kt | 1 + .../ui/main/setup/SetupPresenter.kt | 7 +- .../ui/player_screen/PlayerFragment.kt | 71 +- .../ui/player_screen/PlayerPresenter.kt | 30 +- .../ui/player_screen/PlayerView.kt | 4 + .../player_screen/lyrics/LyricsPresenter.kt | 2 +- .../player_screen/queue/PlayQueueFragment.kt | 22 +- .../player_screen/queue/PlayQueuePresenter.kt | 12 +- .../queue/adapter/PlayQueueViewHolder.kt | 7 +- .../player_screen/view/ActionStateBinder.kt | 10 + .../view/wrappers/PlayerPanelWrapperImpl.java | 11 +- .../playlist/PlayListFragment.kt | 25 +- .../playlist/PlayListPresenter.kt | 40 +- .../playlist_screens/playlist/PlayListView.kt | 4 + .../playlist/adapter/PlayListItemAdapter.kt | 14 +- .../adapter/PlayListItemViewHolder.kt | 37 +- .../playlists/PlayListsFragment.kt | 3 +- .../playlists/PlayListsPresenter.kt | 9 +- .../folders/ExcludedFoldersPresenter.kt | 14 +- .../settings/folders/ExcludedFoldersView.kt | 6 +- .../library/LibrarySettingsFragment.kt | 2 +- .../musicplayer/ui/utils/AndroidUtils.kt | 50 +- .../musicplayer/ui/utils/RepeatListener.java | 4 +- .../utils/dialogs/ProgressDialogFragment.kt | 34 +- .../ui/utils/fragments/FragmentUtils.kt | 13 + .../utils/views/progress_bar/ProgressView.kt | 164 ++-- .../progress_state/ProgressStateView.java | 2 +- .../short_swipe/ShortSwipeCallback.kt | 8 +- .../views/seek_bar/SeekBarViewWrapper.java | 23 +- .../ui/widgets/WidgetActionsReceiver.kt | 4 +- .../musicplayer/ui/widgets/WidgetUpdater.kt | 77 +- .../ui/widgets/menu/WidgetMenuActivity.kt | 11 +- .../widgets/providers/BaseWidgetProvider.kt | 12 + .../res/drawable/bg_accent_text_cursor.xml | 6 + app/src/main/res/drawable/ic_folder_up.xml | 9 + app/src/main/res/drawable/ic_menu.xml | 9 - .../res/layout-large-land/fragment_drawer.xml | 7 +- .../res/layout/dialog_common_input_simple.xml | 69 +- app/src/main/res/layout/dialog_progress.xml | 6 +- app/src/main/res/layout/fragment_drawer.xml | 6 +- .../res/layout/fragment_library_folders.xml | 25 +- .../main/res/layout/fragment_play_lists.xml | 2 +- app/src/main/res/layout/item_play_queue.xml | 8 +- app/src/main/res/layout/partial_toolbar.xml | 60 +- app/src/main/res/values-large/dimens.xml | 2 +- .../res/values-small-land/styles_content.xml | 4 + app/src/main/res/values/dimens.xml | 14 +- .../res/values/strings_non_translatable.xml | 2 + app/src/main/res/values/styles_content.xml | 4 +- build.gradle | 3 +- .../16.json | 722 ++++++++++++++++++ .../data/database/MigrationsTest.java | 9 + .../data/utils/TestDataProvider.java | 16 +- .../data/database/DatabaseManager.java | 3 +- .../data/database/LibraryDatabase.java | 6 +- .../musicplayer/data/database/Migrations.java | 26 + .../dao/compositions/CompositionsDao.java | 53 +- .../compositions/CompositionsDaoWrapper.java | 40 +- .../data/database/dao/folders/FoldersDao.java | 31 +- .../dao/folders/FoldersDaoWrapper.java | 7 +- .../database/dao/play_list/PlayListDao.java | 4 +- .../dao/play_list/PlayListsDaoWrapper.java | 9 +- .../database/dao/play_queue/PlayQueueDao.kt | 338 ++++---- .../dao/play_queue/PlayQueueDaoWrapper.kt | 436 +++++------ .../data/database/entities/IdPair.java | 20 - .../entities/play_queue/PlayQueueItemDto.java | 37 - .../play_queue/TrackPositionEntity.kt | 23 + .../entities/playlist/PlayListEntryDto.java | 36 - .../library/LibraryRepositoryImpl.java | 58 +- .../play_queue/PlayQueueRepositoryImpl.kt | 441 ++++++----- .../playlists/PlayListsRepositoryImpl.java | 2 +- .../scanner/StorageCompositionAnalyzer.kt | 11 +- .../repositories/scanner/files/FileScanner.kt | 13 +- .../playlists/StoragePlaylistsAnalyzer.kt | 1 + .../settings/SettingsRepositoryImpl.java | 16 +- .../state/UiStateRepositoryImpl.java | 42 +- .../files/StorageFilesDataSourceImpl.kt | 40 +- .../providers/music/StorageMusicProvider.java | 10 +- .../source/CompositionSourceEditor.java | 4 +- .../FileUtils.java => image/BitmapUtils.java} | 42 +- .../musicplayer/data/utils/rx/RxUtils.kt | 18 + .../library/edit/EditorRepositoryImplTest.kt | 107 +++ .../data/utils/TestDataProvider.java | 16 +- dependencies.gradle | 11 +- .../controllers/SystemServiceController.kt | 4 +- .../interactors/editor/EditorInteractor.kt | 3 +- .../library/LibraryFoldersInteractor.kt | 28 +- .../library/LibraryFoldersScreenInteractor.kt | 7 +- .../library/LibraryGenresInteractor.kt | 8 + .../domain/interactors/player/ActionState.kt | 7 + .../player/ExternalPlayerInteractor.kt | 4 + .../player/LibraryPlayerInteractor.kt | 359 ++++++--- .../player/MusicServiceInteractor.java | 21 +- .../player/PlayerCoordinatorInteractor.kt | 64 +- .../interactors/player/PlayerInteractor.kt | 43 +- .../player/PlayerScreenInteractor.java | 6 +- .../domain/models/albums/AlbumComposition.kt | 10 +- .../domain/models/composition/Composition.kt | 5 +- .../composition/CurrentComposition.java | 8 +- .../domain/models/folders/FolderInfo.kt | 21 + .../models/play_queue/PlayQueueEvent.kt | 58 +- .../domain/models/play_queue/PlayQueueItem.kt | 95 +-- .../domain/models/player/PlayerState.kt | 12 +- .../domain/models/playlist/PlayListItem.kt | 39 +- .../domain/models/scanner/FileScannerState.kt | 2 +- .../domain/models/sync/RemoteFileInfo.kt | 3 + .../models/utils/CompositionHelper.java | 4 +- .../models/utils/PlayListItemHelper.java | 4 +- .../models/utils/PlayQueueItemHelper.java | 6 +- .../repositories/LibraryRepository.java | 13 +- .../repositories/PlayQueueRepository.kt | 68 +- .../repositories/SettingsRepository.java | 6 +- .../repositories/UiStateRepository.java | 8 +- .../musicplayer/domain/utils/FileUtils.java | 37 + .../musicplayer/domain/utils/TextUtils.java | 13 + .../musicplayer/domain/utils/rx/RxUtils.java | 8 +- .../musicplayer/domain/utils/rx/RxUtils.kt | 41 + .../player/LibraryPlayerInteractorTest.kt | 219 ++++-- .../player/PlayerInteractorTest.kt | 62 +- gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43453 bytes gradle/wrapper/gradle-wrapper.properties | 7 +- gradlew | 409 ++++++---- gradlew.bat | 86 ++- .../anrimian/filesync/SyncInteractor.kt | 17 +- .../filesync/models/repo/RepoSetupTemplate.kt | 4 +- .../models/state/file/FileSyncState.kt | 8 +- .../filesync/models/task/ExcludeReason.kt | 1 + .../filesync/stubs/StubSyncInteractor.kt | 17 +- settings.gradle | 2 - 204 files changed, 4855 insertions(+), 2929 deletions(-) create mode 100644 app/lite/proguard-rules-lite.pro create mode 100644 app/lite/src/main/java/com/github/anrimian/musicplayer/lite/ui/ActionStateBinderImpl.kt delete mode 100644 app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/composition/CompositionEditorComponent.java create mode 100644 app/src/main/java/com/github/anrimian/musicplayer/ui/common/activity/BaseMvpAppCompatActivity.kt create mode 100644 app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/MessageTextFormatter.kt create mode 100644 app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/view/ActionStateBinder.kt create mode 100644 app/src/main/res/drawable/bg_accent_text_cursor.xml create mode 100644 app/src/main/res/drawable/ic_folder_up.xml delete mode 100644 app/src/main/res/drawable/ic_menu.xml create mode 100644 data/schemas/com.github.anrimian.musicplayer.data.database.LibraryDatabase/16.json delete mode 100644 data/src/main/java/com/github/anrimian/musicplayer/data/database/entities/IdPair.java delete mode 100644 data/src/main/java/com/github/anrimian/musicplayer/data/database/entities/play_queue/PlayQueueItemDto.java create mode 100644 data/src/main/java/com/github/anrimian/musicplayer/data/database/entities/play_queue/TrackPositionEntity.kt delete mode 100644 data/src/main/java/com/github/anrimian/musicplayer/data/database/entities/playlist/PlayListEntryDto.java rename data/src/main/java/com/github/anrimian/musicplayer/data/utils/{file/FileUtils.java => image/BitmapUtils.java} (70%) create mode 100644 data/src/test/java/com/github/anrimian/musicplayer/data/repositories/library/edit/EditorRepositoryImplTest.kt create mode 100644 domain/src/main/java/com/github/anrimian/musicplayer/domain/interactors/player/ActionState.kt create mode 100644 domain/src/main/java/com/github/anrimian/musicplayer/domain/models/folders/FolderInfo.kt create mode 100644 domain/src/main/java/com/github/anrimian/musicplayer/domain/models/sync/RemoteFileInfo.kt create mode 100644 gradle/wrapper/gradle-wrapper.jar diff --git a/app/build.gradle b/app/build.gradle index 41d9dd11b..025778525 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,12 +19,11 @@ android { vectorDrawables.useSupportLibrary = true resConfigs 'en', 'be', 'cs', 'de', 'el', 'es', 'fr', 'in', 'pt', 'ru', 'tr', 'uk' - } buildTypes { release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + minifyEnabled false + consumerProguardFiles 'proguard-rules.pro' } QA { initWith release @@ -33,7 +32,9 @@ android { minifyEnabled false } } - + lintOptions { + abortOnError false + } buildFeatures { viewBinding true } @@ -51,7 +52,7 @@ android { '**/kotlin/**', '**/*.txt', '**/*.xml', - '**/*.properties' + '/*.properties' ] } } diff --git a/app/lite/build.gradle b/app/lite/build.gradle index 14a1953ea..86cca4350 100644 --- a/app/lite/build.gradle +++ b/app/lite/build.gradle @@ -26,11 +26,11 @@ android { targetSdkVersion config.androidTargetSdkVersion applicationId 'com.github.anrimian.musicplayer' - versionCode 167 - versionName "0.9.8" + versionCode 175 + versionName "0.9.8.1" testInstrumentationRunner config.testInstrumentationRunner testApplicationId "${applicationId}.test" - archivesBaseName = "$applicationId-v$versionName($versionCode)" + archivesBaseName = "$applicationId-v$versionName-b$versionCode" vectorDrawables.useSupportLibrary = true } @@ -38,7 +38,7 @@ android { release { minifyEnabled true shrinkResources true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', 'proguard-rules-lite.pro' } QA { initWith release @@ -68,7 +68,7 @@ android { '**/kotlin/**', '**/*.txt', '**/*.xml', - '**/*.properties' + '/*.properties' ] } } diff --git a/app/lite/proguard-rules-lite.pro b/app/lite/proguard-rules-lite.pro new file mode 100644 index 000000000..63e45abf8 --- /dev/null +++ b/app/lite/proguard-rules-lite.pro @@ -0,0 +1,4 @@ +-keepclassmembers class com.github.anrimian.musicplayer.lite.di.LiteComponents { + public void init(android.content.Context); + public getLiteAppComponent(); +} \ No newline at end of file diff --git a/app/lite/release/output-metadata.json b/app/lite/release/output-metadata.json index e8024499e..d297bb6d1 100644 --- a/app/lite/release/output-metadata.json +++ b/app/lite/release/output-metadata.json @@ -11,9 +11,9 @@ "type": "SINGLE", "filters": [], "attributes": [], - "versionCode": 162, - "versionName": "0.9.7.1", - "outputFile": "com.github.anrimian.musicplayer-v0.9.7.1(162)-release.apk" + "versionCode": 167, + "versionName": "0.9.8", + "outputFile": "com.github.anrimian.musicplayer-v0.9.8(167)-release.apk" } ], "elementType": "File" diff --git a/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/LiteApp.kt b/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/LiteApp.kt index 4548580e1..35bc8a7cb 100644 --- a/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/LiteApp.kt +++ b/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/LiteApp.kt @@ -1,13 +1,13 @@ -package com.github.anrimian.musicplayer.lite; +package com.github.anrimian.musicplayer.lite -import com.github.anrimian.musicplayer.App; -import com.github.anrimian.musicplayer.lite.di.LiteComponents; +import android.content.Context +import com.github.anrimian.musicplayer.App +import com.github.anrimian.musicplayer.lite.di.LiteComponents -public class LiteApp extends App { +class LiteApp : App() { - @Override - protected void initComponents() { - LiteComponents.init(getApplicationContext()); + override fun initComponents(appContext: Context) { + LiteComponents.init(appContext) } } diff --git a/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/di/LiteComponents.kt b/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/di/LiteComponents.kt index 6acc11487..0fd4123e2 100644 --- a/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/di/LiteComponents.kt +++ b/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/di/LiteComponents.kt @@ -1,34 +1,24 @@ -package com.github.anrimian.musicplayer.lite.di; +package com.github.anrimian.musicplayer.lite.di -import android.content.Context; +import android.content.Context +import com.github.anrimian.musicplayer.di.Components +import com.github.anrimian.musicplayer.di.app.AppModule +import com.github.anrimian.musicplayer.lite.di.app.DaggerLiteAppComponent +import com.github.anrimian.musicplayer.lite.di.app.LiteAppComponent -import com.github.anrimian.musicplayer.di.Components; -import com.github.anrimian.musicplayer.di.app.AppModule; -import com.github.anrimian.musicplayer.lite.di.app.DaggerLiteAppComponent; -import com.github.anrimian.musicplayer.lite.di.app.LiteAppComponent; +object LiteComponents { -public class LiteComponents { + private lateinit var liteAppComponent: LiteAppComponent - private static LiteComponents instance; - - private final LiteAppComponent liteAppComponent; - - public static void init(Context appContext) { - instance = new LiteComponents(appContext); - } - - private static LiteComponents getInstance() { - if (instance == null) { - throw new IllegalStateException("components must be initialized first"); - } - return instance; + fun init(appContext: Context) { + liteAppComponent = DaggerLiteAppComponent.builder() + .appModule(AppModule(appContext)) + .build() + Components.init(liteAppComponent) } - private LiteComponents(Context appContext) { - liteAppComponent = DaggerLiteAppComponent.builder() - .appModule(new AppModule(appContext)) - .build(); - Components.init(liteAppComponent); + fun getLiteAppComponent(): LiteAppComponent { + return liteAppComponent } } diff --git a/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/di/app/LiteAppModule.kt b/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/di/app/LiteAppModule.kt index a92ff84fd..2600da0cc 100644 --- a/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/di/app/LiteAppModule.kt +++ b/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/di/app/LiteAppModule.kt @@ -8,15 +8,26 @@ import com.github.anrimian.musicplayer.data.controllers.music.players.utils.ExoP import com.github.anrimian.musicplayer.data.controllers.music.players.utils.MediaPlayerDataSourceBuilder import com.github.anrimian.musicplayer.data.storage.providers.music.StorageMusicProvider import com.github.anrimian.musicplayer.data.storage.source.ContentSourceHelper +import com.github.anrimian.musicplayer.domain.controllers.SystemMusicController import com.github.anrimian.musicplayer.domain.interactors.analytics.Analytics +import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor import com.github.anrimian.musicplayer.domain.interactors.player.PlayerErrorParser +import com.github.anrimian.musicplayer.domain.interactors.player.PlayerScreenInteractor +import com.github.anrimian.musicplayer.domain.interactors.sleep_timer.SleepTimerInteractor import com.github.anrimian.musicplayer.domain.models.sync.FileKey +import com.github.anrimian.musicplayer.domain.repositories.MediaScannerRepository +import com.github.anrimian.musicplayer.domain.repositories.PlayQueueRepository +import com.github.anrimian.musicplayer.domain.repositories.SettingsRepository +import com.github.anrimian.musicplayer.domain.repositories.UiStateRepository import com.github.anrimian.musicplayer.lite.ui.AboutTextBinderImpl +import com.github.anrimian.musicplayer.lite.ui.ActionStateBinderImpl import com.github.anrimian.musicplayer.lite.ui.SpecialNavigationImpl import com.github.anrimian.musicplayer.ui.about.AboutTextBinder import com.github.anrimian.musicplayer.ui.common.error.parser.DefaultErrorParser import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.common.format.MessageTextFormatter import com.github.anrimian.musicplayer.ui.common.navigation.SpecialNavigation +import com.github.anrimian.musicplayer.ui.player_screen.view.ActionStateBinder import dagger.Module import dagger.Provides import javax.inject.Singleton @@ -39,14 +50,14 @@ class LiteAppModule { @Provides @Singleton fun contentSourceUriBuilder( - storageMusicProvider: StorageMusicProvider + storageMusicProvider: StorageMusicProvider, ) = ContentSourceHelper(storageMusicProvider) @Provides @Singleton fun mediaPlayerDataSourceBuilder( context: Context, - storageMusicProvider: StorageMusicProvider + storageMusicProvider: StorageMusicProvider, ) = MediaPlayerDataSourceBuilder( context, storageMusicProvider @@ -67,4 +78,31 @@ class LiteAppModule { @Provides fun aboutTextBinder(): AboutTextBinder = AboutTextBinderImpl() + @Provides + fun actionStateBinder(): ActionStateBinder = ActionStateBinderImpl() + + @Provides + fun playerScreenInteractor( + sleepTimerInteractor: SleepTimerInteractor, + libraryPlayerInteractor: LibraryPlayerInteractor, + syncInteractor: SyncInteractor, + playQueueRepository: PlayQueueRepository, + uiStateRepository: UiStateRepository, + settingsRepository: SettingsRepository, + mediaScannerRepository: MediaScannerRepository, + systemMusicController: SystemMusicController, + ) = PlayerScreenInteractor( + sleepTimerInteractor, + libraryPlayerInteractor, + syncInteractor, + playQueueRepository, + uiStateRepository, + settingsRepository, + mediaScannerRepository, + systemMusicController + ) + + @Provides + fun messageTextFormatter() = MessageTextFormatter() + } \ No newline at end of file diff --git a/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/ui/ActionStateBinderImpl.kt b/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/ui/ActionStateBinderImpl.kt new file mode 100644 index 000000000..4cd84bc26 --- /dev/null +++ b/app/lite/src/main/java/com/github/anrimian/musicplayer/lite/ui/ActionStateBinderImpl.kt @@ -0,0 +1,13 @@ +package com.github.anrimian.musicplayer.lite.ui + +import com.github.anrimian.musicplayer.domain.interactors.player.ActionState +import com.github.anrimian.musicplayer.ui.common.toolbar.AdvancedToolbar +import com.github.anrimian.musicplayer.ui.player_screen.view.ActionStateBinder + +class ActionStateBinderImpl: ActionStateBinder { + + override fun bind(toolbar: AdvancedToolbar, actionState: ActionState) { + toolbar.setNavigationButtonHintIcon(-1) + } + +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index f7e5275be..2feb74ee7 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -32,7 +32,7 @@ #don't remember why -dontwarn java.lang.invoke** -#RxJava2 +#RxJava3 -dontwarn io.reactivex** #slidr @@ -40,16 +40,16 @@ #chips layout manager #https://github.com/BelooS/ChipsLayoutManager/issues/31 +-keep class com.beloo.widget.chipslayoutmanager.Orientation { *; } #kotlin -dontwarn kotlin.** -assumenosideeffects class kotlin.jvm.internal.Intrinsics { + public static void checkNotNull(...); public static void checkExpressionValueIsNotNull(...); public static void checkNotNullExpressionValue(...); public static void checkReturnedValueIsNotNull(...); public static void checkFieldIsNotNull(...); public static void checkParameterIsNotNull(...); + public static void checkNotNullParameter(...); } - - - diff --git a/app/src/main/java/androidx/appcompat/widget/PublicActionMenuPresenter.java b/app/src/main/java/androidx/appcompat/widget/PublicActionMenuPresenter.java index 8acc612de..7986e5a70 100644 --- a/app/src/main/java/androidx/appcompat/widget/PublicActionMenuPresenter.java +++ b/app/src/main/java/androidx/appcompat/widget/PublicActionMenuPresenter.java @@ -38,6 +38,6 @@ public boolean showOverflowMenu() { } public interface OverflowMenuRunnable { - void call(View anchorView, ArrayList items); + void call(View anchorView, @SuppressLint("RestrictedApi") ArrayList items); } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/App.java b/app/src/main/java/com/github/anrimian/musicplayer/App.java index eb763fa4b..a399a851d 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/App.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/App.java @@ -1,6 +1,7 @@ package com.github.anrimian.musicplayer; import android.app.Application; +import android.content.Context; import androidx.appcompat.app.AppCompatDelegate; @@ -18,14 +19,21 @@ public abstract class App extends Application { - @Override - public void onCreate() { - super.onCreate(); + public App() { + super(); RxJavaPlugins.setErrorHandler(new RxJavaErrorConsumer()); AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); + } - initComponents(); + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + initComponents(base); + } + @Override + public void onCreate() { + super.onCreate(); DevTools.run(this); AppComponent appComponent = Components.getAppComponent(); @@ -39,6 +47,6 @@ public void onCreate() { } } - protected abstract void initComponents(); + protected abstract void initComponents(Context appContext); } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/Constants.java b/app/src/main/java/com/github/anrimian/musicplayer/Constants.java index ddc2d59f5..4e78740f1 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/Constants.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/Constants.java @@ -28,6 +28,7 @@ interface Arguments { String TITLE_ARG = "title_arg"; String POSITIVE_BUTTON_ARG = "positive_button_arg"; String NEGATIVE_BUTTON_ARG = "negative_button_arg"; + String NEUTRAL_BUTTON_ARG = "neutral_button_arg"; String EDIT_TEXT_HINT = "edit_text_hint"; String EDIT_TEXT_VALUE = "edit_text_value"; String CAN_BE_EMPTY_ARG = "can_be_empty_arg"; @@ -43,6 +44,9 @@ interface Arguments { String DIGITS_ARG = "digits_arg"; String CLOSE_MULTISELECT_ARG = "close_multiselect_arg"; String PLAYLIST_IMPORT_ARG = "playlist_import_arg"; + String DESCRIPTION_ARG = "description_arg"; + String MESSAGE_ARG = "message_arg"; + String MESSAGE_RES_ARG = "message_res_arg"; } interface Tags { @@ -62,9 +66,7 @@ interface Tags { String ADD_GENRE_TAG = "add_genre_tag"; String EDIT_GENRE_TAG = "edit_genre_tag"; String NEW_FOLDER_NAME_TAG = "new_folder_name_tag"; - String MESSAGE_ARG = "message_arg"; - String MESSAGE_RES_ARG = "message_res_arg"; - String PROGRESS_DIALOG_TAG = "progress_dialog_arg"; + String PROGRESS_DIALOG_TAG = "progress_dialog_tag"; String EDIT_COVER_TAG = "edit_cover_tag"; String ENABLED_MEDIA_PLAYERS = "enabled_media_players"; String SPEED_SELECTOR_TAG = "speed_selector_tag"; diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/Components.java b/app/src/main/java/com/github/anrimian/musicplayer/di/Components.java index b1c4fee91..f835a231c 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/Components.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/Components.java @@ -1,6 +1,8 @@ package com.github.anrimian.musicplayer.di; +import android.content.Context; + import com.github.anrimian.musicplayer.di.app.AppComponent; import com.github.anrimian.musicplayer.di.app.editor.album.AlbumEditorComponent; import com.github.anrimian.musicplayer.di.app.editor.album.AlbumEditorModule; @@ -43,6 +45,10 @@ import com.github.anrimian.musicplayer.di.app.share.ShareModule; import com.github.anrimian.musicplayer.domain.models.order.Order; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + import javax.annotation.Nullable; @@ -62,6 +68,66 @@ public static void init(AppComponent appComponent) { instance = new Components(appComponent); } + /* + * Experiment: + * After refactor MainActivity to kt crashes started to appear: uninitialized components here + * 1) Moved this method to base java class + * Observe how it works + * - has no effect + * 2) Moved components initialization to Application.attachBaseContext + * Based on answer https://stackoverflow.com/a/56676594/5541688 + * Observe how it works - doesn't work + * 3) Possible next option: separate singleton and builder for locale controller + * Implemented separate initialization for this case + * Observe how it works - crashes later + * 4) Initialize here if not initialized - observe how it works + * Doesn't work either + * 5) Add to proguard rule to keep getInstance() in LiteComponents + * If it helps - remove initialization from attempt 4 + * Issue: can't find method init() + * 5) Remake LiteComponents to kotlin object + * If works: try to remote reflection initializer(with r8 rules?); copy approach to SyncComponents; + * No, doesn't work + * 5.1) Fixed reflection initializer + * Spotted crashes in AppWidgets(after system restart) and in MediaBrowserService + */ + public static void checkInitialization(Context appContext) { + if (!Components.isInitialized()) { + try { + Class clazz; + try { + clazz = Class.forName("com.github.anrimian.musicplayer.lite.di.LiteComponents"); + } catch (ClassNotFoundException e) { + clazz = Class.forName("com.github.anrimian.musicplayer.sync.di.SyncComponents"); + } + // looking for method init(Context) + Method method = null; + for (Method m : clazz.getDeclaredMethods()) { + if (m.getParameterCount() == 1 && m.getParameterTypes()[0].equals(Context.class)) { + method = m; + break; + } + } + if (method == null) { + throw new NoSuchMethodException(); + } + Field[] fields = clazz.getDeclaredFields(); + Object instance = null; + for (Field field : fields) { + if (Modifier.isFinal(field.getModifiers())) { + instance = field.get(null); + } + } + if (instance == null) { + throw new NoSuchFieldException(); + } + method.invoke(instance, appContext); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + private static Components getInstance() { if (instance == null) { throw new IllegalStateException("components must be initialized first"); @@ -77,6 +143,10 @@ public static AppComponent getAppComponent() { return getInstance().appComponent; } + public static boolean isInitialized() { + return instance != null; + } + public static LibraryComponent getLibraryComponent() { return getInstance().buildLibraryComponent(); } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/AppComponent.java b/app/src/main/java/com/github/anrimian/musicplayer/di/app/AppComponent.java index 22973cf38..bfba1e3fa 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/AppComponent.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/AppComponent.java @@ -45,6 +45,7 @@ import com.github.anrimian.musicplayer.infrastructure.MediaSessionHandler; import com.github.anrimian.musicplayer.ui.about.AboutTextBinder; import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; +import com.github.anrimian.musicplayer.ui.common.format.MessageTextFormatter; import com.github.anrimian.musicplayer.ui.common.images.CoverImageLoader; import com.github.anrimian.musicplayer.ui.common.locale.LocaleController; import com.github.anrimian.musicplayer.ui.common.navigation.SpecialNavigation; @@ -52,6 +53,7 @@ import com.github.anrimian.musicplayer.ui.equalizer.EqualizerPresenter; import com.github.anrimian.musicplayer.ui.notifications.MediaNotificationsDisplayer; import com.github.anrimian.musicplayer.ui.notifications.NotificationsDisplayer; +import com.github.anrimian.musicplayer.ui.player_screen.view.ActionStateBinder; import com.github.anrimian.musicplayer.ui.playlist_screens.choose.ChoosePlayListPresenter; import com.github.anrimian.musicplayer.ui.playlist_screens.create.CreatePlayListPresenter; import com.github.anrimian.musicplayer.ui.playlist_screens.playlists.PlayListsPresenter; @@ -131,8 +133,10 @@ public interface AppComponent { LocaleController localeController(); EqualizerController equalizerController(); SystemMusicController systemMusicController(); - SystemServiceController systemServiceController(); + SpecialNavigation specificNavigation(); AboutTextBinder aboutTextBinder(); + ActionStateBinder actionStateBinder(); + MessageTextFormatter messageTextFormatter(); } \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/AppModule.java b/app/src/main/java/com/github/anrimian/musicplayer/di/app/AppModule.java index a37264649..24b80d877 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/AppModule.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/AppModule.java @@ -183,4 +183,5 @@ WidgetMenuPresenter widgetMenuPresenter(LibraryPlayerInteractor libraryPlayerInt ErrorParser errorParser) { return new WidgetMenuPresenter(libraryPlayerInteractor, uiScheduler, errorParser); } + } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/MusicModule.java b/app/src/main/java/com/github/anrimian/musicplayer/di/app/MusicModule.java index a278c3510..1f88cda71 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/MusicModule.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/MusicModule.java @@ -1,6 +1,7 @@ package com.github.anrimian.musicplayer.di.app; +import static com.github.anrimian.musicplayer.di.app.SchedulerModule.COMPUTATION_SCHEDULER; import static com.github.anrimian.musicplayer.di.app.SchedulerModule.DB_SCHEDULER; import static com.github.anrimian.musicplayer.di.app.SchedulerModule.IO_SCHEDULER; import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; @@ -86,6 +87,7 @@ PlayerInteractor playerInteractor(MusicPlayerController musicPlayerController, SystemMusicController systemMusicController, SystemServiceController systemServiceController, SettingsRepository settingsRepository, + @Named(COMPUTATION_SCHEDULER) Scheduler delayedEventsScheduler, Analytics analytics) { return new PlayerInteractor(musicPlayerController, compositionSourceInteractor, @@ -93,6 +95,7 @@ PlayerInteractor playerInteractor(MusicPlayerController musicPlayerController, systemMusicController, systemServiceController, settingsRepository, + delayedEventsScheduler, analytics, 2); } @@ -131,6 +134,7 @@ LibraryPlayerInteractor libraryPlayerInteractor(PlayerCoordinatorInteractor play PlayQueueRepository playQueueRepository, LibraryRepository musicProviderRepository, UiStateRepository uiStateRepository, + SystemServiceController systemServiceController, Analytics analytics) { return new LibraryPlayerInteractor(playerCoordinatorInteractor, syncInteractor, @@ -138,6 +142,7 @@ LibraryPlayerInteractor libraryPlayerInteractor(PlayerCoordinatorInteractor play playQueueRepository, musicProviderRepository, uiStateRepository, + systemServiceController, analytics); } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/PlayListsModule.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/PlayListsModule.kt index 22764207d..4810f7c93 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/PlayListsModule.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/PlayListsModule.kt @@ -1,102 +1,95 @@ -package com.github.anrimian.musicplayer.di.app; +package com.github.anrimian.musicplayer.di.app -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.DB_SCHEDULER; -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.SLOW_BG_SCHEDULER; -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; - -import android.content.Context; - -import com.github.anrimian.musicplayer.data.database.dao.compositions.CompositionsDaoWrapper; -import com.github.anrimian.musicplayer.data.database.dao.play_list.PlayListsDaoWrapper; -import com.github.anrimian.musicplayer.data.repositories.playlists.PlayListsRepositoryImpl; -import com.github.anrimian.musicplayer.data.repositories.scanner.storage.playlists.PlaylistFilesStorage; -import com.github.anrimian.musicplayer.data.storage.providers.playlists.StoragePlayListsProvider; -import com.github.anrimian.musicplayer.domain.interactors.analytics.Analytics; -import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor; -import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor; -import com.github.anrimian.musicplayer.domain.repositories.PlayListsRepository; -import com.github.anrimian.musicplayer.domain.repositories.SettingsRepository; -import com.github.anrimian.musicplayer.domain.repositories.UiStateRepository; -import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; -import com.github.anrimian.musicplayer.ui.playlist_screens.choose.ChoosePlayListPresenter; -import com.github.anrimian.musicplayer.ui.playlist_screens.create.CreatePlayListPresenter; -import com.github.anrimian.musicplayer.ui.playlist_screens.playlists.PlayListsPresenter; - -import javax.annotation.Nonnull; -import javax.inject.Named; -import javax.inject.Singleton; - -import dagger.Module; -import dagger.Provides; -import io.reactivex.rxjava3.core.Scheduler; +import android.content.Context +import com.github.anrimian.musicplayer.data.database.dao.compositions.CompositionsDaoWrapper +import com.github.anrimian.musicplayer.data.database.dao.play_list.PlayListsDaoWrapper +import com.github.anrimian.musicplayer.data.repositories.playlists.PlayListsRepositoryImpl +import com.github.anrimian.musicplayer.data.repositories.scanner.storage.playlists.PlaylistFilesStorage +import com.github.anrimian.musicplayer.data.storage.providers.playlists.StoragePlayListsProvider +import com.github.anrimian.musicplayer.domain.interactors.analytics.Analytics +import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor +import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor +import com.github.anrimian.musicplayer.domain.repositories.PlayListsRepository +import com.github.anrimian.musicplayer.domain.repositories.SettingsRepository +import com.github.anrimian.musicplayer.domain.repositories.UiStateRepository +import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.playlist_screens.choose.ChoosePlayListPresenter +import com.github.anrimian.musicplayer.ui.playlist_screens.create.CreatePlayListPresenter +import com.github.anrimian.musicplayer.ui.playlist_screens.playlists.PlayListsPresenter +import dagger.Module +import dagger.Provides +import io.reactivex.rxjava3.core.Scheduler +import javax.inject.Named +import javax.inject.Singleton @Module -public class PlayListsModule { - +class PlayListsModule { + @Provides - @Nonnull - PlayListsPresenter playListsPresenter(PlayListsInteractor playListsInteractor, - LibraryPlayerInteractor playerInteractor, - @Named(UI_SCHEDULER) Scheduler uiSchedule, - ErrorParser errorParser) { - return new PlayListsPresenter(playListsInteractor, playerInteractor, uiSchedule, errorParser); - } + fun playListsPresenter( + playListsInteractor: PlayListsInteractor, + playerInteractor: LibraryPlayerInteractor, + @Named(SchedulerModule.UI_SCHEDULER) uiSchedule: Scheduler, + errorParser: ErrorParser + ) = PlayListsPresenter( + playListsInteractor, + playerInteractor, + uiSchedule, + errorParser + ) @Provides - @Nonnull - ChoosePlayListPresenter choosePlayListPresenter(PlayListsInteractor playListsInteractor, - @Named(UI_SCHEDULER) Scheduler uiSchedule, - ErrorParser errorParser) { - return new ChoosePlayListPresenter(playListsInteractor, uiSchedule, errorParser); - } + fun choosePlayListPresenter( + playListsInteractor: PlayListsInteractor, + @Named(SchedulerModule.UI_SCHEDULER) uiSchedule: Scheduler, + errorParser: ErrorParser + ) = ChoosePlayListPresenter(playListsInteractor, uiSchedule, errorParser) @Provides - @Nonnull - CreatePlayListPresenter createPlayListPresenter(PlayListsInteractor playListsInteractor, - @Named(UI_SCHEDULER) Scheduler uiSchedule, - ErrorParser errorParser) { - return new CreatePlayListPresenter(playListsInteractor, uiSchedule, errorParser); - } + fun createPlayListPresenter( + playListsInteractor: PlayListsInteractor, + @Named(SchedulerModule.UI_SCHEDULER) uiSchedule: Scheduler, + errorParser: ErrorParser + ) = CreatePlayListPresenter(playListsInteractor, uiSchedule, errorParser) @Provides - @Nonnull - PlayListsInteractor playListsInteractor(LibraryPlayerInteractor playerInteractor, - PlayListsRepository playListsRepository, - SettingsRepository settingsRepository, - UiStateRepository uiStateRepository, - Analytics analytics) { - return new PlayListsInteractor(playerInteractor, - playListsRepository, - settingsRepository, - uiStateRepository, - analytics); - } + fun playListsInteractor( + playerInteractor: LibraryPlayerInteractor, + playListsRepository: PlayListsRepository, + settingsRepository: SettingsRepository, + uiStateRepository: UiStateRepository, + analytics: Analytics + ) = PlayListsInteractor( + playerInteractor, + playListsRepository, + settingsRepository, + uiStateRepository, + analytics + ) @Provides - @Nonnull @Singleton - PlayListsRepository storagePlayListDataSource(Context context, - SettingsRepository settingsRepository, - StoragePlayListsProvider playListsProvider, - CompositionsDaoWrapper compositionsDaoWrapper, - PlayListsDaoWrapper playListsDaoWrapper, - PlaylistFilesStorage playlistFilesStorage, - @Named(DB_SCHEDULER) Scheduler dbScheduler, - @Named(SLOW_BG_SCHEDULER) Scheduler slowBgScheduler) { - return new PlayListsRepositoryImpl(context, - settingsRepository, - playListsProvider, - compositionsDaoWrapper, - playListsDaoWrapper, - playlistFilesStorage, - dbScheduler, - slowBgScheduler); - } + fun storagePlayListDataSource( + context: Context, + settingsRepository: SettingsRepository, + playListsProvider: StoragePlayListsProvider, + compositionsDaoWrapper: CompositionsDaoWrapper, + playListsDaoWrapper: PlayListsDaoWrapper, + playlistFilesStorage: PlaylistFilesStorage, + @Named(SchedulerModule.DB_SCHEDULER) dbScheduler: Scheduler, + @Named(SchedulerModule.SLOW_BG_SCHEDULER) slowBgScheduler: Scheduler + ): PlayListsRepository = PlayListsRepositoryImpl( + context, + settingsRepository, + playListsProvider, + compositionsDaoWrapper, + playListsDaoWrapper, + playlistFilesStorage, + dbScheduler, + slowBgScheduler + ) @Provides - @Nonnull - StoragePlayListsProvider storagePlayListsProvider(Context context) { - return new StoragePlayListsProvider(context); - } + fun storagePlayListsProvider(context: Context) = StoragePlayListsProvider(context) } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/SchedulerModule.java b/app/src/main/java/com/github/anrimian/musicplayer/di/app/SchedulerModule.java index d07836aa7..1b91aeae6 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/SchedulerModule.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/SchedulerModule.java @@ -22,6 +22,7 @@ public class SchedulerModule { public static final String IO_SCHEDULER = "io_scheduler"; public static final String UI_SCHEDULER = "ui_scheduler"; + public static final String COMPUTATION_SCHEDULER = "computation_scheduler"; //replace db scheduler with io scheduler. Check sequential write operations //+play queue skipTo public static final String DB_SCHEDULER = "db_scheduler"; @@ -43,6 +44,14 @@ Scheduler provideUiScheduler() { return AndroidSchedulers.mainThread(); } + @Provides + @NonNull + @Named(COMPUTATION_SCHEDULER) + @Singleton + Scheduler provideComputationScheduler() { + return Schedulers.computation(); + } + @Provides @NonNull @Named(DB_SCHEDULER) diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/album/AlbumEditorComponent.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/album/AlbumEditorComponent.kt index 9e4348e69..ca3ece447 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/album/AlbumEditorComponent.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/album/AlbumEditorComponent.kt @@ -1,10 +1,9 @@ -package com.github.anrimian.musicplayer.di.app.editor.album; +package com.github.anrimian.musicplayer.di.app.editor.album -import com.github.anrimian.musicplayer.ui.editor.album.AlbumEditorPresenter; +import com.github.anrimian.musicplayer.ui.editor.album.AlbumEditorPresenter +import dagger.Subcomponent -import dagger.Subcomponent; - -@Subcomponent(modules = AlbumEditorModule.class) -public interface AlbumEditorComponent { - AlbumEditorPresenter albumEditorPresenter(); +@Subcomponent(modules = [ AlbumEditorModule::class ]) +interface AlbumEditorComponent { + fun albumEditorPresenter(): AlbumEditorPresenter } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/album/AlbumEditorModule.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/album/AlbumEditorModule.kt index e9dba2a1b..4af0d885f 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/album/AlbumEditorModule.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/album/AlbumEditorModule.kt @@ -1,36 +1,31 @@ -package com.github.anrimian.musicplayer.di.app.editor.album; - -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; - -import com.github.anrimian.filesync.SyncInteractor; -import com.github.anrimian.musicplayer.domain.interactors.editor.EditorInteractor; -import com.github.anrimian.musicplayer.domain.models.sync.FileKey; -import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; -import com.github.anrimian.musicplayer.ui.editor.album.AlbumEditorPresenter; - -import javax.annotation.Nonnull; -import javax.inject.Named; - -import dagger.Module; -import dagger.Provides; -import io.reactivex.rxjava3.core.Scheduler; +package com.github.anrimian.musicplayer.di.app.editor.album + +import com.github.anrimian.filesync.SyncInteractor +import com.github.anrimian.musicplayer.di.app.SchedulerModule +import com.github.anrimian.musicplayer.domain.interactors.editor.EditorInteractor +import com.github.anrimian.musicplayer.domain.models.sync.FileKey +import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.editor.album.AlbumEditorPresenter +import dagger.Module +import dagger.Provides +import io.reactivex.rxjava3.core.Scheduler +import javax.inject.Named @Module -public class AlbumEditorModule { - - private final long albumId; - - public AlbumEditorModule(long albumId) { - this.albumId = albumId; - } - +class AlbumEditorModule(private val albumId: Long) { + @Provides - @Nonnull - AlbumEditorPresenter compositionEditorPresenter(EditorInteractor interactor, - SyncInteractor syncInteractor, - @Named(UI_SCHEDULER) Scheduler uiScheduler, - ErrorParser errorParser) { - return new AlbumEditorPresenter(albumId, interactor, syncInteractor, uiScheduler, errorParser); - } + fun compositionEditorPresenter( + interactor: EditorInteractor, + syncInteractor: SyncInteractor, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler, + errorParser: ErrorParser + ) = AlbumEditorPresenter( + albumId, + interactor, + syncInteractor, + uiScheduler, + errorParser + ) } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/composition/CompositionEditorComponent.java b/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/composition/CompositionEditorComponent.java deleted file mode 100644 index 924e67202..000000000 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/composition/CompositionEditorComponent.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.github.anrimian.musicplayer.di.app.editor.composition; - -import com.github.anrimian.musicplayer.ui.editor.composition.CompositionEditorPresenter; - -import dagger.Subcomponent; - -@Subcomponent(modules = CompositionEditorModule.class) -public interface CompositionEditorComponent { - CompositionEditorPresenter compositionEditorPresenter(); -} diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/composition/CompositionEditorModule.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/composition/CompositionEditorModule.kt index 494600b24..92ba535b2 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/composition/CompositionEditorModule.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/editor/composition/CompositionEditorModule.kt @@ -1,35 +1,31 @@ -package com.github.anrimian.musicplayer.di.app.editor.composition; - -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; - -import com.github.anrimian.filesync.SyncInteractor; -import com.github.anrimian.musicplayer.domain.interactors.editor.EditorInteractor; -import com.github.anrimian.musicplayer.domain.models.sync.FileKey; -import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; -import com.github.anrimian.musicplayer.ui.editor.composition.CompositionEditorPresenter; - -import javax.annotation.Nonnull; -import javax.inject.Named; - -import dagger.Module; -import dagger.Provides; -import io.reactivex.rxjava3.core.Scheduler; +package com.github.anrimian.musicplayer.di.app.editor.composition + +import com.github.anrimian.filesync.SyncInteractor +import com.github.anrimian.musicplayer.di.app.SchedulerModule +import com.github.anrimian.musicplayer.domain.interactors.editor.EditorInteractor +import com.github.anrimian.musicplayer.domain.models.sync.FileKey +import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.editor.composition.CompositionEditorPresenter +import dagger.Module +import dagger.Provides +import io.reactivex.rxjava3.core.Scheduler +import javax.inject.Named @Module -public class CompositionEditorModule { - - private final long compositionId; - - public CompositionEditorModule(long compositionId) { - this.compositionId = compositionId; - } - +class CompositionEditorModule(private val compositionId: Long) { + @Provides - @Nonnull - CompositionEditorPresenter compositionEditorPresenter(EditorInteractor interactor, - SyncInteractor syncInteractor, - @Named(UI_SCHEDULER) Scheduler uiScheduler, - ErrorParser errorParser) { - return new CompositionEditorPresenter(compositionId, interactor, syncInteractor, uiScheduler, errorParser); - } + fun compositionEditorPresenter( + interactor: EditorInteractor, + syncInteractor: SyncInteractor, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler, + errorParser: ErrorParser + ) = CompositionEditorPresenter( + compositionId, + interactor, + syncInteractor, + uiScheduler, + errorParser + ) + } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/external_player/ExternalPlayerComponent.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/external_player/ExternalPlayerComponent.kt index 86bb1f47e..b80a8b832 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/external_player/ExternalPlayerComponent.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/external_player/ExternalPlayerComponent.kt @@ -1,11 +1,11 @@ -package com.github.anrimian.musicplayer.di.app.external_player; +package com.github.anrimian.musicplayer.di.app.external_player -import com.github.anrimian.musicplayer.ui.main.external_player.ExternalPlayerPresenter; +import com.github.anrimian.musicplayer.ui.main.external_player.ExternalPlayerPresenter +import dagger.Subcomponent -import dagger.Subcomponent; +@Subcomponent(modules = [ ExternalPlayerModule::class ]) +interface ExternalPlayerComponent { -@Subcomponent(modules = ExternalPlayerModule.class) -public interface ExternalPlayerComponent { + fun externalPlayerPresenter(): ExternalPlayerPresenter - ExternalPlayerPresenter externalPlayerPresenter(); } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/external_player/ExternalPlayerModule.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/external_player/ExternalPlayerModule.kt index 65129e24b..a9ab67b38 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/external_player/ExternalPlayerModule.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/external_player/ExternalPlayerModule.kt @@ -1,26 +1,22 @@ -package com.github.anrimian.musicplayer.di.app.external_player; +package com.github.anrimian.musicplayer.di.app.external_player -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; - -import com.github.anrimian.musicplayer.domain.interactors.player.ExternalPlayerInteractor; -import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; -import com.github.anrimian.musicplayer.ui.main.external_player.ExternalPlayerPresenter; - -import javax.annotation.Nonnull; -import javax.inject.Named; - -import dagger.Module; -import dagger.Provides; -import io.reactivex.rxjava3.core.Scheduler; +import com.github.anrimian.musicplayer.di.app.SchedulerModule +import com.github.anrimian.musicplayer.domain.interactors.player.ExternalPlayerInteractor +import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.main.external_player.ExternalPlayerPresenter +import dagger.Module +import dagger.Provides +import io.reactivex.rxjava3.core.Scheduler +import javax.inject.Named @Module -public class ExternalPlayerModule { - +class ExternalPlayerModule { + @Provides - @Nonnull - ExternalPlayerPresenter externalPlayerPresenter(ExternalPlayerInteractor interactor, - @Named(UI_SCHEDULER) Scheduler uiScheduler, - ErrorParser errorParser) { - return new ExternalPlayerPresenter(interactor, uiScheduler, errorParser); - } + fun externalPlayerPresenter( + interactor: ExternalPlayerInteractor, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler, + errorParser: ErrorParser + ) = ExternalPlayerPresenter(interactor, uiScheduler, errorParser) + } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryComponent.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryComponent.kt index 1dacbedda..244299330 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryComponent.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryComponent.kt @@ -1,38 +1,37 @@ -package com.github.anrimian.musicplayer.di.app.library; +package com.github.anrimian.musicplayer.di.app.library -import com.github.anrimian.musicplayer.di.app.library.albums.AlbumsComponent; -import com.github.anrimian.musicplayer.di.app.library.albums.AlbumsModule; -import com.github.anrimian.musicplayer.di.app.library.artists.ArtistsComponent; -import com.github.anrimian.musicplayer.di.app.library.artists.ArtistsModule; -import com.github.anrimian.musicplayer.di.app.library.compositions.LibraryCompositionsComponent; -import com.github.anrimian.musicplayer.di.app.library.compositions.LibraryCompositionsModule; -import com.github.anrimian.musicplayer.di.app.library.files.LibraryFilesComponent; -import com.github.anrimian.musicplayer.di.app.library.files.LibraryFilesModule; -import com.github.anrimian.musicplayer.di.app.library.genres.GenresComponent; -import com.github.anrimian.musicplayer.di.app.library.genres.GenresModule; -import com.github.anrimian.musicplayer.ui.player_screen.PlayerPresenter; -import com.github.anrimian.musicplayer.ui.player_screen.lyrics.LyricsPresenter; -import com.github.anrimian.musicplayer.ui.player_screen.queue.PlayQueuePresenter; -import com.github.anrimian.musicplayer.ui.settings.folders.ExcludedFoldersPresenter; - -import dagger.Subcomponent; +import com.github.anrimian.musicplayer.di.app.library.albums.AlbumsComponent +import com.github.anrimian.musicplayer.di.app.library.albums.AlbumsModule +import com.github.anrimian.musicplayer.di.app.library.artists.ArtistsComponent +import com.github.anrimian.musicplayer.di.app.library.artists.ArtistsModule +import com.github.anrimian.musicplayer.di.app.library.compositions.LibraryCompositionsComponent +import com.github.anrimian.musicplayer.di.app.library.compositions.LibraryCompositionsModule +import com.github.anrimian.musicplayer.di.app.library.files.LibraryFilesComponent +import com.github.anrimian.musicplayer.di.app.library.files.LibraryFilesModule +import com.github.anrimian.musicplayer.di.app.library.genres.GenresComponent +import com.github.anrimian.musicplayer.di.app.library.genres.GenresModule +import com.github.anrimian.musicplayer.ui.player_screen.PlayerPresenter +import com.github.anrimian.musicplayer.ui.player_screen.lyrics.LyricsPresenter +import com.github.anrimian.musicplayer.ui.player_screen.queue.PlayQueuePresenter +import com.github.anrimian.musicplayer.ui.settings.folders.ExcludedFoldersPresenter +import dagger.Subcomponent /** * Created on 29.10.2017. */ - @LibraryScope -@Subcomponent(modules = LibraryModule.class) -public interface LibraryComponent { - - LibraryFilesComponent libraryFilesComponent(LibraryFilesModule module); - LibraryCompositionsComponent libraryCompositionsComponent(LibraryCompositionsModule module); - ArtistsComponent artistsComponent(ArtistsModule module); - AlbumsComponent albumsComponent(AlbumsModule module); - GenresComponent genresComponent(GenresModule module); +@Subcomponent(modules = [ LibraryModule::class ]) +interface LibraryComponent { + + fun libraryFilesComponent(module: LibraryFilesModule): LibraryFilesComponent + fun libraryCompositionsComponent(module: LibraryCompositionsModule): LibraryCompositionsComponent + fun artistsComponent(module: ArtistsModule): ArtistsComponent + fun albumsComponent(module: AlbumsModule): AlbumsComponent + fun genresComponent(module: GenresModule): GenresComponent - PlayerPresenter playerPresenter(); - PlayQueuePresenter playQueuePresenter(); - LyricsPresenter lyricsPresenter(); - ExcludedFoldersPresenter excludedFoldersPresenter(); + fun playerPresenter(): PlayerPresenter + fun playQueuePresenter(): PlayQueuePresenter + fun lyricsPresenter(): LyricsPresenter + fun excludedFoldersPresenter(): ExcludedFoldersPresenter + } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryModule.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryModule.kt index 17cee94f8..ef5b70896 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryModule.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryModule.kt @@ -1,107 +1,76 @@ -package com.github.anrimian.musicplayer.di.app.library; +package com.github.anrimian.musicplayer.di.app.library -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; - -import androidx.annotation.NonNull; - -import com.github.anrimian.filesync.SyncInteractor; -import com.github.anrimian.musicplayer.domain.controllers.SystemMusicController; -import com.github.anrimian.musicplayer.domain.interactors.library.LibraryFoldersInteractor; -import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor; -import com.github.anrimian.musicplayer.domain.interactors.player.PlayerScreenInteractor; -import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor; -import com.github.anrimian.musicplayer.domain.interactors.sleep_timer.SleepTimerInteractor; -import com.github.anrimian.musicplayer.domain.models.sync.FileKey; -import com.github.anrimian.musicplayer.domain.repositories.MediaScannerRepository; -import com.github.anrimian.musicplayer.domain.repositories.PlayQueueRepository; -import com.github.anrimian.musicplayer.domain.repositories.SettingsRepository; -import com.github.anrimian.musicplayer.domain.repositories.UiStateRepository; -import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; -import com.github.anrimian.musicplayer.ui.player_screen.PlayerPresenter; -import com.github.anrimian.musicplayer.ui.player_screen.lyrics.LyricsPresenter; -import com.github.anrimian.musicplayer.ui.player_screen.queue.PlayQueuePresenter; -import com.github.anrimian.musicplayer.ui.settings.folders.ExcludedFoldersPresenter; - -import javax.annotation.Nonnull; -import javax.inject.Named; - -import dagger.Module; -import dagger.Provides; -import io.reactivex.rxjava3.core.Scheduler; +import com.github.anrimian.filesync.SyncInteractor +import com.github.anrimian.musicplayer.di.app.SchedulerModule +import com.github.anrimian.musicplayer.domain.interactors.library.LibraryFoldersInteractor +import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor +import com.github.anrimian.musicplayer.domain.interactors.player.PlayerScreenInteractor +import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor +import com.github.anrimian.musicplayer.domain.models.sync.FileKey +import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.player_screen.PlayerPresenter +import com.github.anrimian.musicplayer.ui.player_screen.lyrics.LyricsPresenter +import com.github.anrimian.musicplayer.ui.player_screen.queue.PlayQueuePresenter +import com.github.anrimian.musicplayer.ui.settings.folders.ExcludedFoldersPresenter +import dagger.Module +import dagger.Provides +import io.reactivex.rxjava3.core.Scheduler +import javax.inject.Named /** * Created on 29.10.2017. */ @Module -public class LibraryModule { - +class LibraryModule { + @Provides - @Nonnull - PlayerPresenter playerPresenter(LibraryPlayerInteractor musicPlayerInteractor, - PlayerScreenInteractor playerScreenInteractor, - PlayListsInteractor playListsInteractor, - ErrorParser errorParser, - @Named(UI_SCHEDULER) Scheduler uiScheduler) { - return new PlayerPresenter(musicPlayerInteractor, - playerScreenInteractor, - playListsInteractor, - errorParser, - uiScheduler); - } + fun playerPresenter( + musicPlayerInteractor: LibraryPlayerInteractor, + playerScreenInteractor: PlayerScreenInteractor, + playListsInteractor: PlayListsInteractor, + errorParser: ErrorParser, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler + ) = PlayerPresenter( + musicPlayerInteractor, + playerScreenInteractor, + playListsInteractor, + errorParser, + uiScheduler + ) @Provides - @Nonnull - PlayQueuePresenter playQueuePresenter(LibraryPlayerInteractor musicPlayerInteractor, - PlayerScreenInteractor playerScreenInteractor, - SyncInteractor syncInteractor, - PlayListsInteractor playListsInteractor, - ErrorParser errorParser, - @Named(UI_SCHEDULER) Scheduler uiScheduler) { - return new PlayQueuePresenter(musicPlayerInteractor, - playerScreenInteractor, - syncInteractor, - playListsInteractor, - errorParser, - uiScheduler); - } + fun playQueuePresenter( + musicPlayerInteractor: LibraryPlayerInteractor, + playerScreenInteractor: PlayerScreenInteractor, + syncInteractor: SyncInteractor, + playListsInteractor: PlayListsInteractor, + errorParser: ErrorParser, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler + ) = PlayQueuePresenter( + musicPlayerInteractor, + playerScreenInteractor, + syncInteractor, + playListsInteractor, + errorParser, + uiScheduler + ) @Provides - @Nonnull - LyricsPresenter lyricsPresenter(LibraryPlayerInteractor libraryPlayerInteractor, - ErrorParser errorParser, - @Named(UI_SCHEDULER) Scheduler uiScheduler) { - return new LyricsPresenter( - libraryPlayerInteractor, - errorParser, - uiScheduler); - } + fun lyricsPresenter( + libraryPlayerInteractor: LibraryPlayerInteractor, + errorParser: ErrorParser, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler + ) = LyricsPresenter( + libraryPlayerInteractor, + errorParser, + uiScheduler + ) @Provides - @NonNull - @LibraryScope - PlayerScreenInteractor playerScreenInteractor(SleepTimerInteractor sleepTimerInteractor, - LibraryPlayerInteractor libraryPlayerInteractor, - SyncInteractor syncInteractor, - PlayQueueRepository playQueueRepository, - UiStateRepository uiStateRepository, - SettingsRepository settingsRepository, - MediaScannerRepository mediaScannerRepository, - SystemMusicController systemMusicController) { - return new PlayerScreenInteractor(sleepTimerInteractor, - libraryPlayerInteractor, - syncInteractor, - playQueueRepository, - uiStateRepository, - settingsRepository, - mediaScannerRepository, - systemMusicController); - } + fun excludedFoldersPresenter( + interactor: LibraryFoldersInteractor, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler, + errorParser: ErrorParser + ) = ExcludedFoldersPresenter(interactor, uiScheduler, errorParser) - @Provides - @Nonnull - ExcludedFoldersPresenter excludedFoldersPresenter(LibraryFoldersInteractor interactor, - @Named(UI_SCHEDULER) Scheduler uiScheduler, - ErrorParser errorParser) { - return new ExcludedFoldersPresenter(interactor, uiScheduler, errorParser); - } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryScope.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryScope.kt index 3bbbebea9..0eb4745ac 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryScope.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/LibraryScope.kt @@ -1,18 +1,11 @@ -package com.github.anrimian.musicplayer.di.app.library; +package com.github.anrimian.musicplayer.di.app.library -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; - -import javax.inject.Scope; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; +import javax.inject.Scope /** * Created on 29.10.2017. */ - @Scope -@Documented -@Retention(RUNTIME) -@interface LibraryScope { -} +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +internal annotation class LibraryScope diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/compositions/LibraryCompositionsComponent.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/compositions/LibraryCompositionsComponent.kt index cc8fc5c3a..5bbe35d4c 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/compositions/LibraryCompositionsComponent.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/compositions/LibraryCompositionsComponent.kt @@ -1,15 +1,12 @@ -package com.github.anrimian.musicplayer.di.app.library.compositions; +package com.github.anrimian.musicplayer.di.app.library.compositions -import com.github.anrimian.musicplayer.ui.library.compositions.LibraryCompositionsPresenter; -import com.github.anrimian.musicplayer.ui.library.folders.LibraryFoldersPresenter; - -import dagger.Subcomponent; +import com.github.anrimian.musicplayer.ui.library.compositions.LibraryCompositionsPresenter +import dagger.Subcomponent /** * Created on 31.10.2017. */ -@Subcomponent(modules = LibraryCompositionsModule.class) -public interface LibraryCompositionsComponent { - - LibraryCompositionsPresenter libraryCompositionsPresenter(); +@Subcomponent(modules = [ LibraryCompositionsModule::class ]) +interface LibraryCompositionsComponent { + fun libraryCompositionsPresenter(): LibraryCompositionsPresenter } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/compositions/LibraryCompositionsModule.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/compositions/LibraryCompositionsModule.kt index 895607ab2..e9041cdb6 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/compositions/LibraryCompositionsModule.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/compositions/LibraryCompositionsModule.kt @@ -1,46 +1,42 @@ -package com.github.anrimian.musicplayer.di.app.library.compositions; - -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; - -import com.github.anrimian.filesync.SyncInteractor; -import com.github.anrimian.musicplayer.domain.interactors.library.LibraryCompositionsInteractor; -import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor; -import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor; -import com.github.anrimian.musicplayer.domain.interactors.settings.DisplaySettingsInteractor; -import com.github.anrimian.musicplayer.domain.models.sync.FileKey; -import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; -import com.github.anrimian.musicplayer.ui.library.compositions.LibraryCompositionsPresenter; - -import javax.annotation.Nonnull; -import javax.inject.Named; - -import dagger.Module; -import dagger.Provides; -import io.reactivex.rxjava3.core.Scheduler; +package com.github.anrimian.musicplayer.di.app.library.compositions + +import com.github.anrimian.filesync.SyncInteractor +import com.github.anrimian.musicplayer.di.app.SchedulerModule +import com.github.anrimian.musicplayer.domain.interactors.library.LibraryCompositionsInteractor +import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor +import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor +import com.github.anrimian.musicplayer.domain.interactors.settings.DisplaySettingsInteractor +import com.github.anrimian.musicplayer.domain.models.sync.FileKey +import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.library.compositions.LibraryCompositionsPresenter +import dagger.Module +import dagger.Provides +import io.reactivex.rxjava3.core.Scheduler +import javax.inject.Named /** * Created on 31.10.2017. */ - @Module -public class LibraryCompositionsModule { - +class LibraryCompositionsModule { + @Provides - @Nonnull - LibraryCompositionsPresenter libraryCompositionsPresenter(LibraryCompositionsInteractor interactor, - LibraryPlayerInteractor playerInteractor, - DisplaySettingsInteractor displaySettingsInteractor, - SyncInteractor syncInteractor, - PlayListsInteractor playListsInteractor, - ErrorParser errorParser, - @Named(UI_SCHEDULER) Scheduler uiScheduler) { - return new LibraryCompositionsPresenter(interactor, - playerInteractor, - displaySettingsInteractor, - syncInteractor, - playListsInteractor, - errorParser, - uiScheduler); - } + fun libraryCompositionsPresenter( + interactor: LibraryCompositionsInteractor, + playerInteractor: LibraryPlayerInteractor, + displaySettingsInteractor: DisplaySettingsInteractor, + syncInteractor: SyncInteractor, + playListsInteractor: PlayListsInteractor, + errorParser: ErrorParser, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler + ) = LibraryCompositionsPresenter( + interactor, + playerInteractor, + displaySettingsInteractor, + syncInteractor, + playListsInteractor, + errorParser, + uiScheduler + ) } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesComponent.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesComponent.kt index 942dcf1c3..91805b4e1 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesComponent.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesComponent.kt @@ -1,16 +1,13 @@ -package com.github.anrimian.musicplayer.di.app.library.files; +package com.github.anrimian.musicplayer.di.app.library.files -import com.github.anrimian.musicplayer.di.app.library.files.folder.FolderComponent; -import com.github.anrimian.musicplayer.di.app.library.files.folder.FolderModule; -import com.github.anrimian.musicplayer.ui.library.folders.root.FolderRootPresenter; +import com.github.anrimian.musicplayer.di.app.library.files.folder.FolderComponent +import com.github.anrimian.musicplayer.di.app.library.files.folder.FolderModule +import com.github.anrimian.musicplayer.ui.library.folders.root.FolderRootPresenter +import dagger.Subcomponent -import dagger.Subcomponent; - -@Subcomponent(modules = LibraryFilesModule.class) +@Subcomponent(modules = [ LibraryFilesModule::class ]) @LibraryFilesScope -public interface LibraryFilesComponent { - - FolderRootPresenter folderRootPresenter(); - - FolderComponent folderComponent(FolderModule module); +interface LibraryFilesComponent { + fun folderRootPresenter(): FolderRootPresenter + fun folderComponent(module: FolderModule): FolderComponent } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesModule.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesModule.kt index 3d2189d56..13910db55 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesModule.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesModule.kt @@ -1,43 +1,41 @@ -package com.github.anrimian.musicplayer.di.app.library.files; - -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; - -import com.github.anrimian.musicplayer.domain.interactors.library.LibraryFoldersInteractor; -import com.github.anrimian.musicplayer.domain.interactors.library.LibraryFoldersScreenInteractor; -import com.github.anrimian.musicplayer.domain.repositories.LibraryRepository; -import com.github.anrimian.musicplayer.domain.repositories.UiStateRepository; -import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; -import com.github.anrimian.musicplayer.ui.library.folders.root.FolderRootPresenter; - -import javax.annotation.Nonnull; -import javax.inject.Named; - -import dagger.Module; -import dagger.Provides; -import io.reactivex.rxjava3.core.Scheduler; +package com.github.anrimian.musicplayer.di.app.library.files + +import com.github.anrimian.musicplayer.di.app.SchedulerModule +import com.github.anrimian.musicplayer.domain.interactors.library.LibraryFoldersInteractor +import com.github.anrimian.musicplayer.domain.interactors.library.LibraryFoldersScreenInteractor +import com.github.anrimian.musicplayer.domain.repositories.LibraryRepository +import com.github.anrimian.musicplayer.domain.repositories.UiStateRepository +import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.library.folders.root.FolderRootPresenter +import dagger.Module +import dagger.Provides +import io.reactivex.rxjava3.core.Scheduler +import javax.inject.Named @Module -public class LibraryFilesModule { - +class LibraryFilesModule { + @Provides - @Nonnull - FolderRootPresenter folderRootPresenter(LibraryFoldersScreenInteractor interactor, - ErrorParser errorParser, - @Named(UI_SCHEDULER) Scheduler uiScheduler) { - return new FolderRootPresenter(interactor, - errorParser, - uiScheduler); - } + fun folderRootPresenter( + interactor: LibraryFoldersScreenInteractor, + errorParser: ErrorParser, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler + ) = FolderRootPresenter( + interactor, + errorParser, + uiScheduler + ) @Provides - @Nonnull @LibraryFilesScope - LibraryFoldersScreenInteractor libraryFilesInteractor(LibraryFoldersInteractor foldersInteractor, - LibraryRepository libraryRepository, - UiStateRepository uiStateRepository) { - return new LibraryFoldersScreenInteractor(foldersInteractor, - libraryRepository, - uiStateRepository); - } - + fun libraryFilesInteractor( + foldersInteractor: LibraryFoldersInteractor, + libraryRepository: LibraryRepository, + uiStateRepository: UiStateRepository + ) = LibraryFoldersScreenInteractor( + foldersInteractor, + libraryRepository, + uiStateRepository + ) + } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesScope.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesScope.kt index 1026c92f8..76d55d1a1 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesScope.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/LibraryFilesScope.kt @@ -1,18 +1,11 @@ -package com.github.anrimian.musicplayer.di.app.library.files; +package com.github.anrimian.musicplayer.di.app.library.files -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; - -import javax.inject.Scope; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; +import javax.inject.Scope /** * Created on 29.10.2017. */ - @Scope -@Documented -@Retention(RUNTIME) -@interface LibraryFilesScope { -} +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +internal annotation class LibraryFilesScope diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/folder/FolderComponent.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/folder/FolderComponent.kt index 5ce761635..ebae6222a 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/folder/FolderComponent.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/folder/FolderComponent.kt @@ -1,14 +1,12 @@ -package com.github.anrimian.musicplayer.di.app.library.files.folder; +package com.github.anrimian.musicplayer.di.app.library.files.folder -import com.github.anrimian.musicplayer.ui.library.folders.LibraryFoldersPresenter; - -import dagger.Subcomponent; +import com.github.anrimian.musicplayer.ui.library.folders.LibraryFoldersPresenter +import dagger.Subcomponent /** * Created on 31.10.2017. */ -@Subcomponent(modules = FolderModule.class) -public interface FolderComponent { - - LibraryFoldersPresenter storageLibraryPresenter(); +@Subcomponent(modules = [ FolderModule::class ]) +interface FolderComponent { + fun storageLibraryPresenter(): LibraryFoldersPresenter } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/folder/FolderModule.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/folder/FolderModule.kt index 3bbf71036..4f227ecf8 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/folder/FolderModule.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/files/folder/FolderModule.kt @@ -1,54 +1,43 @@ -package com.github.anrimian.musicplayer.di.app.library.files.folder; - -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; - -import com.github.anrimian.filesync.SyncInteractor; -import com.github.anrimian.musicplayer.domain.interactors.library.LibraryFoldersScreenInteractor; -import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor; -import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor; -import com.github.anrimian.musicplayer.domain.interactors.settings.DisplaySettingsInteractor; -import com.github.anrimian.musicplayer.domain.models.sync.FileKey; -import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; -import com.github.anrimian.musicplayer.ui.library.folders.LibraryFoldersPresenter; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.inject.Named; - -import dagger.Module; -import dagger.Provides; -import io.reactivex.rxjava3.core.Scheduler; +package com.github.anrimian.musicplayer.di.app.library.files.folder + +import com.github.anrimian.filesync.SyncInteractor +import com.github.anrimian.musicplayer.di.app.SchedulerModule +import com.github.anrimian.musicplayer.domain.interactors.library.LibraryFoldersScreenInteractor +import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor +import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor +import com.github.anrimian.musicplayer.domain.interactors.settings.DisplaySettingsInteractor +import com.github.anrimian.musicplayer.domain.models.sync.FileKey +import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.library.folders.LibraryFoldersPresenter +import dagger.Module +import dagger.Provides +import io.reactivex.rxjava3.core.Scheduler +import javax.inject.Named /** * Created on 31.10.2017. */ - @Module -public class FolderModule { - - @Nullable - private final Long folderId; - - public FolderModule(@Nullable Long folderId) { - this.folderId = folderId; - } - +class FolderModule(private val folderId: Long?) { + @Provides - @Nonnull - LibraryFoldersPresenter libraryFoldersPresenter(LibraryFoldersScreenInteractor interactor, - LibraryPlayerInteractor playerInteractor, - DisplaySettingsInteractor displaySettingsInteractor, - SyncInteractor syncInteractor, - PlayListsInteractor playListsInteractor, - ErrorParser errorParser, - @Named(UI_SCHEDULER) Scheduler uiScheduler) { - return new LibraryFoldersPresenter(folderId, - interactor, - playerInteractor, - displaySettingsInteractor, - syncInteractor, - playListsInteractor, - errorParser, - uiScheduler); - } + fun libraryFoldersPresenter( + interactor: LibraryFoldersScreenInteractor, + playerInteractor: LibraryPlayerInteractor, + displaySettingsInteractor: DisplaySettingsInteractor, + syncInteractor: SyncInteractor, + playListsInteractor: PlayListsInteractor, + errorParser: ErrorParser, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler + ) = LibraryFoldersPresenter( + folderId, + interactor, + playerInteractor, + displaySettingsInteractor, + syncInteractor, + playListsInteractor, + errorParser, + uiScheduler + ) + } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/GenresComponent.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/GenresComponent.kt index 896a07bdd..5368b43cd 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/GenresComponent.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/GenresComponent.kt @@ -1,15 +1,14 @@ -package com.github.anrimian.musicplayer.di.app.library.genres; +package com.github.anrimian.musicplayer.di.app.library.genres -import com.github.anrimian.musicplayer.di.app.library.genres.items.GenreItemsComponent; -import com.github.anrimian.musicplayer.di.app.library.genres.items.GenreItemsModule; -import com.github.anrimian.musicplayer.ui.library.genres.list.GenresListPresenter; +import com.github.anrimian.musicplayer.di.app.library.genres.items.GenreItemsComponent +import com.github.anrimian.musicplayer.di.app.library.genres.items.GenreItemsModule +import com.github.anrimian.musicplayer.ui.library.genres.list.GenresListPresenter +import dagger.Subcomponent -import dagger.Subcomponent; +@Subcomponent(modules = [ GenresModule::class ]) +interface GenresComponent { -@Subcomponent(modules = GenresModule.class) -public interface GenresComponent { + fun genreItemsComponent(module: GenreItemsModule): GenreItemsComponent + fun genresListPresenter(): GenresListPresenter - GenreItemsComponent genreItemsComponent(GenreItemsModule module); - - GenresListPresenter genresListPresenter(); } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/GenresModule.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/GenresModule.kt index bee7e9e31..fd54109d4 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/GenresModule.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/GenresModule.kt @@ -1,34 +1,32 @@ -package com.github.anrimian.musicplayer.di.app.library.genres; +package com.github.anrimian.musicplayer.di.app.library.genres -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; - -import com.github.anrimian.musicplayer.domain.interactors.library.LibraryGenresInteractor; -import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor; -import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor; -import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; -import com.github.anrimian.musicplayer.ui.library.genres.list.GenresListPresenter; - -import javax.annotation.Nonnull; -import javax.inject.Named; - -import dagger.Module; -import dagger.Provides; -import io.reactivex.rxjava3.core.Scheduler; +import com.github.anrimian.musicplayer.di.app.SchedulerModule +import com.github.anrimian.musicplayer.domain.interactors.library.LibraryGenresInteractor +import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor +import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor +import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.library.genres.list.GenresListPresenter +import dagger.Module +import dagger.Provides +import io.reactivex.rxjava3.core.Scheduler +import javax.inject.Named @Module -public class GenresModule { - +class GenresModule { + @Provides - @Nonnull - GenresListPresenter genreListPresenter(LibraryGenresInteractor interactor, - LibraryPlayerInteractor playerInteractor, - PlayListsInteractor playListsInteractor, - ErrorParser errorParser, - @Named(UI_SCHEDULER) Scheduler uiScheduler) { - return new GenresListPresenter(interactor, - playerInteractor, - playListsInteractor, - errorParser, - uiScheduler); - } + fun genreListPresenter( + interactor: LibraryGenresInteractor, + playerInteractor: LibraryPlayerInteractor, + playListsInteractor: PlayListsInteractor, + errorParser: ErrorParser, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler + ) = GenresListPresenter( + interactor, + playerInteractor, + playListsInteractor, + errorParser, + uiScheduler + ) + } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/items/GenreItemsComponent.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/items/GenreItemsComponent.kt index 4931010bd..9327751e6 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/items/GenreItemsComponent.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/items/GenreItemsComponent.kt @@ -1,11 +1,9 @@ -package com.github.anrimian.musicplayer.di.app.library.genres.items; +package com.github.anrimian.musicplayer.di.app.library.genres.items -import com.github.anrimian.musicplayer.ui.library.genres.items.GenreItemsPresenter; +import com.github.anrimian.musicplayer.ui.library.genres.items.GenreItemsPresenter +import dagger.Subcomponent -import dagger.Subcomponent; - -@Subcomponent(modules = GenreItemsModule.class) -public interface GenreItemsComponent { - - GenreItemsPresenter genreItemsPresenter(); +@Subcomponent(modules = [ GenreItemsModule::class ]) +interface GenreItemsComponent { + fun genreItemsPresenter(): GenreItemsPresenter } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/items/GenreItemsModule.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/items/GenreItemsModule.kt index 2e4a855bd..0e786e8b1 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/items/GenreItemsModule.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/library/genres/items/GenreItemsModule.kt @@ -1,48 +1,40 @@ -package com.github.anrimian.musicplayer.di.app.library.genres.items; - -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; - -import com.github.anrimian.filesync.SyncInteractor; -import com.github.anrimian.musicplayer.domain.interactors.library.LibraryGenresInteractor; -import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor; -import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor; -import com.github.anrimian.musicplayer.domain.interactors.settings.DisplaySettingsInteractor; -import com.github.anrimian.musicplayer.domain.models.sync.FileKey; -import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; -import com.github.anrimian.musicplayer.ui.library.genres.items.GenreItemsPresenter; - -import javax.annotation.Nonnull; -import javax.inject.Named; - -import dagger.Module; -import dagger.Provides; -import io.reactivex.rxjava3.core.Scheduler; +package com.github.anrimian.musicplayer.di.app.library.genres.items + +import com.github.anrimian.filesync.SyncInteractor +import com.github.anrimian.musicplayer.di.app.SchedulerModule +import com.github.anrimian.musicplayer.domain.interactors.library.LibraryGenresInteractor +import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor +import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor +import com.github.anrimian.musicplayer.domain.interactors.settings.DisplaySettingsInteractor +import com.github.anrimian.musicplayer.domain.models.sync.FileKey +import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.library.genres.items.GenreItemsPresenter +import dagger.Module +import dagger.Provides +import io.reactivex.rxjava3.core.Scheduler +import javax.inject.Named @Module -public class GenreItemsModule { - - private final long id; - - public GenreItemsModule(long id) { - this.id = id; - } - +class GenreItemsModule(private val id: Long) { + @Provides - @Nonnull - GenreItemsPresenter genreItemsPresenter(LibraryGenresInteractor interactor, - LibraryPlayerInteractor playerInteractor, - DisplaySettingsInteractor displaySettingsInteractor, - SyncInteractor syncInteractor, - PlayListsInteractor playListsInteractor, - ErrorParser errorParser, - @Named(UI_SCHEDULER) Scheduler uiScheduler) { - return new GenreItemsPresenter(id, - interactor, - playerInteractor, - displaySettingsInteractor, - syncInteractor, - playListsInteractor, - errorParser, - uiScheduler); - } + fun genreItemsPresenter( + interactor: LibraryGenresInteractor, + playerInteractor: LibraryPlayerInteractor, + displaySettingsInteractor: DisplaySettingsInteractor, + syncInteractor: SyncInteractor, + playListsInteractor: PlayListsInteractor, + errorParser: ErrorParser, + @Named(SchedulerModule.UI_SCHEDULER) uiScheduler: Scheduler + ) = GenreItemsPresenter( + id, + interactor, + playerInteractor, + displaySettingsInteractor, + syncInteractor, + playListsInteractor, + errorParser, + uiScheduler + ) + } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/play_list/PlayListComponent.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/play_list/PlayListComponent.kt index a6fd2f0f9..5d166830d 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/play_list/PlayListComponent.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/play_list/PlayListComponent.kt @@ -1,14 +1,13 @@ -package com.github.anrimian.musicplayer.di.app.play_list; +package com.github.anrimian.musicplayer.di.app.play_list -import com.github.anrimian.musicplayer.ui.playlist_screens.playlist.PlayListPresenter; -import com.github.anrimian.musicplayer.ui.playlist_screens.rename.RenamePlayListPresenter; +import com.github.anrimian.musicplayer.ui.playlist_screens.playlist.PlayListPresenter +import com.github.anrimian.musicplayer.ui.playlist_screens.rename.RenamePlayListPresenter +import dagger.Subcomponent -import dagger.Subcomponent; +@Subcomponent(modules = [ PlayListModule::class ]) +interface PlayListComponent { -@Subcomponent(modules = PlayListModule.class) -public interface PlayListComponent { - - PlayListPresenter playListPresenter(); - RenamePlayListPresenter changePlayListPresenter(); + fun playListPresenter(): PlayListPresenter + fun changePlayListPresenter(): RenamePlayListPresenter } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/di/app/play_list/PlayListModule.kt b/app/src/main/java/com/github/anrimian/musicplayer/di/app/play_list/PlayListModule.kt index bf9d078fe..a35cfd9f1 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/di/app/play_list/PlayListModule.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/di/app/play_list/PlayListModule.kt @@ -1,57 +1,50 @@ -package com.github.anrimian.musicplayer.di.app.play_list; - -import static com.github.anrimian.musicplayer.di.app.SchedulerModule.UI_SCHEDULER; - -import com.github.anrimian.filesync.SyncInteractor; -import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor; -import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor; -import com.github.anrimian.musicplayer.domain.interactors.settings.DisplaySettingsInteractor; -import com.github.anrimian.musicplayer.domain.models.sync.FileKey; -import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser; -import com.github.anrimian.musicplayer.ui.playlist_screens.playlist.PlayListPresenter; -import com.github.anrimian.musicplayer.ui.playlist_screens.rename.RenamePlayListPresenter; - -import javax.annotation.Nonnull; -import javax.inject.Named; - -import dagger.Module; -import dagger.Provides; -import io.reactivex.rxjava3.core.Scheduler; +package com.github.anrimian.musicplayer.di.app.play_list + +import com.github.anrimian.filesync.SyncInteractor +import com.github.anrimian.musicplayer.di.app.SchedulerModule +import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor +import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor +import com.github.anrimian.musicplayer.domain.interactors.settings.DisplaySettingsInteractor +import com.github.anrimian.musicplayer.domain.models.sync.FileKey +import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser +import com.github.anrimian.musicplayer.ui.playlist_screens.playlist.PlayListPresenter +import com.github.anrimian.musicplayer.ui.playlist_screens.rename.RenamePlayListPresenter +import dagger.Module +import dagger.Provides +import io.reactivex.rxjava3.core.Scheduler +import javax.inject.Named @Module -public class PlayListModule { - - private final long playListId; - - public PlayListModule(long playListId) { - this.playListId = playListId; - } - +class PlayListModule(private val playListId: Long) { + @Provides - @Nonnull - PlayListPresenter playListsPresenter(LibraryPlayerInteractor musicPlayerInteractor, - PlayListsInteractor playListsInteractor, - DisplaySettingsInteractor displaySettingsInteractor, - SyncInteractor syncInteractor, - @Named(UI_SCHEDULER) Scheduler uiSchedule, - ErrorParser errorParser) { - return new PlayListPresenter(playListId, - musicPlayerInteractor, - playListsInteractor, - displaySettingsInteractor, - syncInteractor, - errorParser, - uiSchedule); - } + fun playListsPresenter( + musicPlayerInteractor: LibraryPlayerInteractor, + playListsInteractor: PlayListsInteractor, + displaySettingsInteractor: DisplaySettingsInteractor, + syncInteractor: SyncInteractor, + @Named(SchedulerModule.UI_SCHEDULER) uiSchedule: Scheduler, + errorParser: ErrorParser + ) = PlayListPresenter( + playListId, + musicPlayerInteractor, + playListsInteractor, + displaySettingsInteractor, + syncInteractor, + errorParser, + uiSchedule + ) @Provides - @Nonnull - RenamePlayListPresenter changePlayListPresenter(PlayListsInteractor playListsInteractor, - @Named(UI_SCHEDULER) Scheduler uiSchedule, - ErrorParser errorParser) { - return new RenamePlayListPresenter(playListId, - playListsInteractor, - uiSchedule, - errorParser); - } + fun changePlayListPresenter( + playListsInteractor: PlayListsInteractor, + @Named(SchedulerModule.UI_SCHEDULER) uiSchedule: Scheduler, + errorParser: ErrorParser + ) = RenamePlayListPresenter( + playListId, + playListsInteractor, + uiSchedule, + errorParser + ) + } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/MediaSessionHandler.kt b/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/MediaSessionHandler.kt index 907813df5..d0bc53307 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/MediaSessionHandler.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/MediaSessionHandler.kt @@ -31,24 +31,25 @@ import com.github.anrimian.musicplayer.domain.models.player.service.MusicNotific import com.github.anrimian.musicplayer.domain.models.utils.CompositionHelper import com.github.anrimian.musicplayer.domain.utils.functions.Optional import com.github.anrimian.musicplayer.infrastructure.receivers.AppMediaButtonReceiver -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.ALBUM_ID_ARG -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.ALBUM_ITEMS_ACTION_ID -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.ARTIST_ID_ARG -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.ARTIST_ITEMS_ACTION_ID -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.COMPOSITIONS_ACTION_ID -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.COMPOSITION_ID_ARG -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.FOLDERS_ACTION_ID -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.FOLDER_ID_ARG -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.GENRE_ID_ARG -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.GENRE_ITEMS_ACTION_ID -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.PAUSE_ACTION_ID -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.PLAYLIST_ID_ARG -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.PLAYLIST_ITEMS_ACTION_ID -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.POSITION_ARG -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.RESUME_ACTION_ID -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.SEARCH_ITEMS_ACTION_ID -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.SEARCH_QUERY_ARG -import com.github.anrimian.musicplayer.infrastructure.service.media_browser.SHUFFLE_ALL_AND_PLAY_ACTION_ID +import com.github.anrimian.musicplayer.infrastructure.service.SystemServiceControllerImpl +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.ALBUM_ID_ARG +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.ALBUM_ITEMS_ACTION_ID +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.ARTIST_ID_ARG +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.ARTIST_ITEMS_ACTION_ID +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.COMPOSITIONS_ACTION_ID +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.COMPOSITION_ID_ARG +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.FOLDERS_ACTION_ID +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.FOLDER_ID_ARG +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.GENRE_ID_ARG +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.GENRE_ITEMS_ACTION_ID +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.PAUSE_ACTION_ID +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.PLAYLIST_ID_ARG +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.PLAYLIST_ITEMS_ACTION_ID +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.POSITION_ARG +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.RESUME_ACTION_ID +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.SEARCH_ITEMS_ACTION_ID +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.SEARCH_QUERY_ARG +import com.github.anrimian.musicplayer.infrastructure.service.media_browser.AppMediaBrowserService.Companion.SHUFFLE_ALL_AND_PLAY_ACTION_ID import com.github.anrimian.musicplayer.infrastructure.service.music.CompositionSourceModelHelper import com.github.anrimian.musicplayer.infrastructure.service.music.MusicService import com.github.anrimian.musicplayer.ui.common.AppAndroidUtils @@ -78,7 +79,7 @@ class MediaSessionHandler( private val musicServiceInteractor: MusicServiceInteractor, private val ioScheduler: Scheduler, private val uiScheduler: Scheduler, - private val errorParser: ErrorParser + private val errorParser: ErrorParser, ) { private var mediaSession: MediaSessionCompat? = null @@ -240,7 +241,7 @@ class MediaSessionHandler( // } setMediaState(playbackStateBuilder, playbackState) - val playQueueCurrentItemId = playbackState.playQueueCurrentItem.playQueueItem?.id ?: 0L + val playQueueCurrentItemId = playbackState.playQueueCurrentItem.playQueueItem?.itemId ?: 0L playbackStateBuilder.setActiveQueueItemId(playQueueCurrentItemId) getMediaSession().setPlaybackState(playbackStateBuilder.build()) @@ -307,35 +308,36 @@ class MediaSessionHandler( private fun toSessionQueueItems( playQueue: List, - isLibrarySource: Boolean + isLibrarySource: Boolean, ): List { return if (isLibrarySource) playQueue.map(this::toSessionQueueItem) else emptyList() } private fun toSessionQueueItem(item: PlayQueueItem): MediaSessionCompat.QueueItem { - val composition = item.composition val mediaDescription = MediaDescriptionCompat.Builder() - .setTitle(CompositionHelper.formatCompositionName(composition)) - .setSubtitle(formatCompositionAdditionalInfoForMediaBrowser(context, composition)) + .setTitle(CompositionHelper.formatCompositionName(item)) + .setSubtitle(formatCompositionAdditionalInfoForMediaBrowser(context, item)) .build() - return MediaSessionCompat.QueueItem(mediaDescription, item.id) + return MediaSessionCompat.QueueItem(mediaDescription, item.itemId) } private fun setMediaState( playbackStateBuilder: PlaybackStateCompat.Builder, - playbackState: PlaybackState + playbackState: PlaybackState, ) { val playerState = when (val playerState = playbackState.playerState) { PlayerState.IDLE -> PlaybackStateCompat.STATE_NONE PlayerState.PREPARING, - PlayerState.LOADING -> PlaybackStateCompat.STATE_CONNECTING + PlayerState.LOADING, + -> PlaybackStateCompat.STATE_CONNECTING PlayerState.PAUSE -> PlaybackStateCompat.STATE_PAUSED PlayerState.PLAY -> PlaybackStateCompat.STATE_PLAYING PlayerState.STOP -> PlaybackStateCompat.STATE_STOPPED is PlayerState.Error -> { val errorCode = when(playerState.throwable) { is UnsupportedSourceException, - is CorruptedMediaFileException -> PlaybackStateCompat.ERROR_CODE_NOT_SUPPORTED + is CorruptedMediaFileException, + -> PlaybackStateCompat.ERROR_CODE_NOT_SUPPORTED else -> PlaybackStateCompat.ERROR_CODE_APP_ERROR } val errorMessage = errorParser.parseError(playerState.throwable).message @@ -355,7 +357,7 @@ class MediaSessionHandler( fun set( currentSource: Optional, - settings: MusicNotificationSetting + settings: MusicNotificationSetting, ): MetadataState { this.currentSource = currentSource this.settings = settings @@ -379,7 +381,7 @@ class MediaSessionHandler( trackPosition: Long, playbackSpeed: Float, repeatMode: Int, - randomMode: Boolean + randomMode: Boolean, ): PlaybackState { this.playerState = playerState this.playQueueCurrentItem = playQueueCurrentItem @@ -423,11 +425,13 @@ class MediaSessionHandler( override fun onSetRepeatMode(repeatMode: Int) { val appRepeatMode = when (repeatMode) { PlaybackStateCompat.REPEAT_MODE_INVALID, - PlaybackStateCompat.REPEAT_MODE_NONE -> { + PlaybackStateCompat.REPEAT_MODE_NONE, + -> { RepeatMode.NONE } PlaybackStateCompat.REPEAT_MODE_GROUP, - PlaybackStateCompat.REPEAT_MODE_ALL -> { + PlaybackStateCompat.REPEAT_MODE_ALL, + -> { RepeatMode.REPEAT_PLAY_QUEUE } PlaybackStateCompat.REPEAT_MODE_ONE -> { @@ -456,7 +460,7 @@ class MediaSessionHandler( override fun onPlayFromMediaId(mediaId: String, extras: Bundle) { when(mediaId) { - RESUME_ACTION_ID -> libraryPlayerInteractor.play() + RESUME_ACTION_ID -> SystemServiceControllerImpl.startPlayForegroundService(context) PAUSE_ACTION_ID -> libraryPlayerInteractor.pause() SHUFFLE_ALL_AND_PLAY_ACTION_ID -> { actionDisposable = musicServiceInteractor.shuffleAllAndPlay() @@ -528,15 +532,15 @@ class MediaSessionHandler( .subscribe({}, this::processError) } + override fun onPrepare() { + musicServiceInteractor.prepare() + } + //next - not implemented override fun onCommand(command: String, extras: Bundle, cb: ResultReceiver) { super.onCommand(command, extras, cb) } - override fun onPrepare() { - super.onPrepare() - } - override fun onPrepareFromMediaId(mediaId: String, extras: Bundle) { super.onPrepareFromMediaId(mediaId, extras) } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/SystemServiceControllerImpl.java b/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/SystemServiceControllerImpl.java index 36d76001a..eaece9394 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/SystemServiceControllerImpl.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/SystemServiceControllerImpl.java @@ -1,7 +1,5 @@ package com.github.anrimian.musicplayer.infrastructure.service; -import static com.github.anrimian.musicplayer.domain.Constants.TRIGGER; - import android.app.ForegroundServiceStartNotAllowedException; import android.content.ComponentName; import android.content.Context; @@ -13,6 +11,7 @@ import android.os.Looper; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import com.github.anrimian.musicplayer.Constants; @@ -32,9 +31,8 @@ public class SystemServiceControllerImpl implements SystemServiceController { private final Context context; private final SettingsRepository settingsRepository; - private final PublishSubject stopForegroundSubject = PublishSubject.create(); + private final PublishSubject stopForegroundSubject = PublishSubject.create(); - private static final Handler handler = new Handler(Looper.getMainLooper()); private static final Handler stopHandler = new Handler(Looper.getMainLooper()); public static void startPlayForegroundService(Context context) { @@ -60,24 +58,23 @@ public SystemServiceControllerImpl(Context context, @Override public void startMusicService() { stopHandler.removeCallbacksAndMessages(null); - handler.post(() -> { - Intent intent = new Intent(context, MusicService.class); - checkPermissionsAndStartServiceSafe(context, intent); - }); + Intent intent = new Intent(context, MusicService.class); + checkPermissionsAndStartServiceSafe(context, intent); } @Override - public void stopMusicService(boolean forceStop) { + public void stopMusicService(boolean forceStop, boolean hideUi) { long stopDelayMillis = settingsRepository.getKeepNotificationTime(); if (forceStop || stopDelayMillis == 0L) { - stopForegroundService(); + stopForegroundService(hideUi); return; } - stopHandler.postDelayed(this::stopForegroundService, stopDelayMillis); + stopHandler.postDelayed(() -> stopForegroundService(hideUi), stopDelayMillis); } + @NonNull @Override - public Observable getStopForegroundSignal() { + public Observable getStopForegroundSignal() { return stopForegroundSubject; } @@ -102,41 +99,43 @@ private static void checkPermissionsAndStartServiceFromBg(Context context, Inten } private static void startServiceSafe(Context context, Intent intent) { - handler.post(() -> { - try { - ServiceConnection connection = new ForegroundServiceStarterConnection(context, intent); - context.bindService(intent, connection, Context.BIND_AUTO_CREATE); - } catch (RuntimeException ignored) { - // Workaround for background calls - startServiceFromBg(context, intent); - } - }); + try { + ServiceConnection connection = new ForegroundServiceStarterConnection(context, intent); + context.bindService(intent, connection, Context.BIND_AUTO_CREATE); + } catch (RuntimeException ignored) { + // Workaround for background calls + startServiceFromBg(context, intent); + } } private static void startServiceFromBg(Context context, Intent intent) { Intent bgIntent = new Intent(intent); intent.putExtra(MusicService.START_FOREGROUND_SIGNAL, true); - //let's see how try-catch will work try { ContextCompat.startForegroundService(context, bgIntent); } catch (Exception e) { - int sdkVersion = Build.VERSION.SDK_INT; - if (sdkVersion >= Build.VERSION_CODES.S && sdkVersion < Build.VERSION_CODES.TIRAMISU - && e instanceof ForegroundServiceStartNotAllowedException) { - AppComponent appComponent = Components.getAppComponent(); - appComponent.analytics().processNonFatalError(e); - appComponent.notificationsDisplayer().showErrorNotification(R.string.app_has_no_system_permission_to_start); - //check toast on this api version(S) - Toast.makeText(context, R.string.app_has_no_system_permission_to_start, Toast.LENGTH_LONG).show(); + if (processServiceStartError(context, e)) { return; } throw e; } } - private void stopForegroundService() { - handler.removeCallbacksAndMessages(null); - stopForegroundSubject.onNext(TRIGGER); + private static boolean processServiceStartError(Context context, Exception e) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S + && e instanceof ForegroundServiceStartNotAllowedException) { + AppComponent appComponent = Components.getAppComponent(); + appComponent.analytics().processNonFatalError(e); + appComponent.notificationsDisplayer().showErrorNotification(R.string.app_has_no_system_permission_to_start); + //check toast on this api version(S) + Toast.makeText(context, R.string.app_has_no_system_permission_to_start, Toast.LENGTH_LONG).show(); + return true; + } + return false; + } + + private void stopForegroundService(boolean hideUi) { + stopForegroundSubject.onNext(hideUi); } private static class ForegroundServiceStarterConnection implements ServiceConnection { @@ -153,7 +152,15 @@ public ForegroundServiceStarterConnection(Context context, Intent intent) { public void onServiceConnected(ComponentName name, IBinder iBinder) { MusicService.LocalBinder binder = (MusicService.LocalBinder) iBinder; MusicService service = binder.getService(); - ContextCompat.startForegroundService(context, intent); + try { + ContextCompat.startForegroundService(context, intent); + } catch (Exception e) { + if (processServiceStartError(context, e)) { + context.unbindService(this); + return; + } + throw e; + } service.startForeground(); context.unbindService(this); } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/media_browser/AppMediaBrowserService.kt b/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/media_browser/AppMediaBrowserService.kt index cac3fc5fd..6b636a7b5 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/media_browser/AppMediaBrowserService.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/media_browser/AppMediaBrowserService.kt @@ -47,45 +47,6 @@ import io.reactivex.rxjava3.disposables.Disposable // ? can we set media session in such state when service will be bound again // A3: do something with media session before service launch? -const val PERMISSION_ERROR_ACTION_ID = "permission_error_action_id" -const val DEFAULT_ERROR_ACTION_ID = "default_error_action_id" -const val RECENT_MEDIA_ACTION_ID = "recent_media_action_id" -const val RESUME_ACTION_ID = "resume_action_id" -const val PAUSE_ACTION_ID = "pause_action_id" -const val SHUFFLE_ALL_AND_PLAY_ACTION_ID = "shuffle_all_and_play_action_id" -const val COMPOSITIONS_ACTION_ID = "compositions_action_id" -const val FOLDERS_ACTION_ID = "folders_action_id" -const val ARTIST_ITEMS_ACTION_ID = "artist_items_action_id" -const val ALBUM_ITEMS_ACTION_ID = "album_items_action_id" -const val GENRE_ITEMS_ACTION_ID = "genre_items_action_id" -const val PLAYLIST_ITEMS_ACTION_ID = "playlist_items_action_id" -const val SEARCH_ITEMS_ACTION_ID = "search_items_action_id" - -const val POSITION_ARG = "position_arg" -const val COMPOSITION_ID_ARG = "composition_id_arg" -const val FOLDER_ID_ARG = "folder_id_arg" -const val ARTIST_ID_ARG = "artist_id_arg" -const val ALBUM_ID_ARG = "artist_id_arg" -const val GENRE_ID_ARG = "genre_id_arg" -const val PLAYLIST_ID_ARG = "artist_id_arg" -const val SEARCH_QUERY_ARG = "search_query_arg" - -private const val ROOT_ID = "root_id" -private const val RECENT_MEDIA_ROOT_ID = "recent_media_root_id" - -private const val COMPOSITIONS_NODE_ID = "compositions_node_id" -private const val FOLDERS_NODE_ID = "folders_node_id" -private const val ARTISTS_NODE_ID = "artists_node_id" -private const val ALBUMS_NODE_ID = "albums_node_id" -private const val GENRES_NODE_ID = "genres_node_id" -private const val PLAYLISTS_NODE_ID = "playlists_node_id" -private const val ARTIST_ITEMS_NODE_ID = "artist_items_node_id" -private const val ALBUM_ITEMS_NODE_ID = "album_items_node_id" -private const val GENRE_ITEMS_NODE_ID = "genre_items_node_id" -private const val PLAYLIST_ITEMS_NODE_ID = "playlist_items_node_id" - -const val DELIMITER = '-' - //strange initial state(random? just in case of install while android auto is active?) //later improvements: @@ -99,6 +60,7 @@ class AppMediaBrowserService: MediaBrowserServiceCompat() { override fun onCreate() { super.onCreate() + Components.checkInitialization(applicationContext) val mediaSessionHandler = Components.getAppComponent().mediaSessionHandler() mediaSessionHandler.dispatchServiceCreated() this.sessionToken = mediaSessionHandler.getMediaSession().sessionToken @@ -402,12 +364,11 @@ class AppMediaBrowserService: MediaBrowserServiceCompat() { private fun toRecentItem(playQueueEvent: PlayQueueEvent): Single> { val queueItem = playQueueEvent.playQueueItem ?: return Single.just(emptyList()) - val composition = queueItem.composition val appComponent = Components.getAppComponent() val coverUriSingle = if (appComponent.musicServiceInteractor().isCoversInNotificationEnabled) { - appComponent.imageLoader().loadImageUri(composition) + appComponent.imageLoader().loadImageUri(queueItem) } else { Single.just(Optional(null)) } @@ -416,8 +377,8 @@ class AppMediaBrowserService: MediaBrowserServiceCompat() { val item = MediaBrowserCompat.MediaItem( MediaDescriptionCompat.Builder() .setMediaId(RECENT_MEDIA_ACTION_ID) - .setTitle(formatCompositionName(composition)) - .setSubtitle(formatCompositionAuthor(composition, this)) + .setTitle(formatCompositionName(queueItem)) + .setSubtitle(formatCompositionAuthor(queueItem, this)) .setIconUri(coverUriOpt.value) .build(), MediaBrowserCompat.MediaItem.FLAG_PLAYABLE @@ -507,11 +468,10 @@ class AppMediaBrowserService: MediaBrowserServiceCompat() { playlistItem: PlayListItem, playlistId: Long ): MediaBrowserCompat.MediaItem { - val composition = playlistItem.composition return actionItem( PLAYLIST_ITEMS_ACTION_ID, - formatCompositionName(composition), - formatCompositionAdditionalInfoForMediaBrowser(this, composition), + formatCompositionName(playlistItem), + formatCompositionAdditionalInfoForMediaBrowser(this, playlistItem), Bundle().apply { putInt(POSITION_ARG, position) putLong(PLAYLIST_ID_ARG, playlistId) @@ -578,4 +538,45 @@ class AppMediaBrowserService: MediaBrowserServiceCompat() { MediaBrowserCompat.MediaItem.FLAG_BROWSABLE ) + companion object { + const val PERMISSION_ERROR_ACTION_ID = "permission_error_action_id" + const val DEFAULT_ERROR_ACTION_ID = "default_error_action_id" + const val RECENT_MEDIA_ACTION_ID = "recent_media_action_id" + const val RESUME_ACTION_ID = "resume_action_id" + const val PAUSE_ACTION_ID = "pause_action_id" + const val SHUFFLE_ALL_AND_PLAY_ACTION_ID = "shuffle_all_and_play_action_id" + const val COMPOSITIONS_ACTION_ID = "compositions_action_id" + const val FOLDERS_ACTION_ID = "folders_action_id" + const val ARTIST_ITEMS_ACTION_ID = "artist_items_action_id" + const val ALBUM_ITEMS_ACTION_ID = "album_items_action_id" + const val GENRE_ITEMS_ACTION_ID = "genre_items_action_id" + const val PLAYLIST_ITEMS_ACTION_ID = "playlist_items_action_id" + const val SEARCH_ITEMS_ACTION_ID = "search_items_action_id" + + const val POSITION_ARG = "position_arg" + const val COMPOSITION_ID_ARG = "composition_id_arg" + const val FOLDER_ID_ARG = "folder_id_arg" + const val ARTIST_ID_ARG = "artist_id_arg" + const val ALBUM_ID_ARG = "artist_id_arg" + const val GENRE_ID_ARG = "genre_id_arg" + const val PLAYLIST_ID_ARG = "artist_id_arg" + const val SEARCH_QUERY_ARG = "search_query_arg" + + private const val ROOT_ID = "root_id" + private const val RECENT_MEDIA_ROOT_ID = "recent_media_root_id" + + private const val COMPOSITIONS_NODE_ID = "compositions_node_id" + private const val FOLDERS_NODE_ID = "folders_node_id" + private const val ARTISTS_NODE_ID = "artists_node_id" + private const val ALBUMS_NODE_ID = "albums_node_id" + private const val GENRES_NODE_ID = "genres_node_id" + private const val PLAYLISTS_NODE_ID = "playlists_node_id" + private const val ARTIST_ITEMS_NODE_ID = "artist_items_node_id" + private const val ALBUM_ITEMS_NODE_ID = "album_items_node_id" + private const val GENRE_ITEMS_NODE_ID = "genre_items_node_id" + private const val PLAYLIST_ITEMS_NODE_ID = "playlist_items_node_id" + + const val DELIMITER = '-' + } + } \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/music/MusicService.kt b/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/music/MusicService.kt index f96db49b0..869bde60f 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/music/MusicService.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/infrastructure/service/music/MusicService.kt @@ -5,6 +5,7 @@ import android.content.Intent import android.os.Binder import android.os.Build import android.support.v4.media.session.MediaSessionCompat +import androidx.core.app.ServiceCompat import com.github.anrimian.musicplayer.Constants import com.github.anrimian.musicplayer.R import com.github.anrimian.musicplayer.data.utils.Permissions @@ -49,7 +50,7 @@ class MusicService : Service() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { if (intent == null) { - stopForeground(true) + stopForegroundCompat(true) stopSelf() return START_NOT_STICKY } @@ -58,7 +59,7 @@ class MusicService : Service() { this, R.string.no_file_permission ) - stopForeground(true) + stopForegroundCompat(true) stopSelf() return START_NOT_STICKY } @@ -108,7 +109,7 @@ class MusicService : Service() { when (requestCode) { Constants.Actions.PLAY -> { val playDelay = intent.getLongExtra(PLAY_DELAY_MILLIS, 0) - playerInteractor().play(playDelay) + musicServiceInteractor().play(playDelay) } Constants.Actions.PAUSE -> playerInteractor().pause() Constants.Actions.SKIP_TO_NEXT -> musicServiceInteractor().skipToNext() @@ -136,7 +137,8 @@ class MusicService : Service() { serviceDisposable.add(Components.getAppComponent().systemServiceController() .getStopForegroundSignal() .observeOn(AndroidSchedulers.mainThread()) - .subscribe { stopForeground(false) }) + .subscribe(::stopForegroundCompat) + ) } private fun onServiceStateReceived(serviceState: ServiceState) { @@ -188,7 +190,7 @@ class MusicService : Service() { } if (stopService) { mediaNotificationsDisplayer().cancelCoverLoadingForForegroundNotification() - stopForeground(true) + stopForegroundCompat(true) stopSelf() } else { if (!mediaSession().isActive) { @@ -242,7 +244,7 @@ class MusicService : Service() { compositionSource: Optional, repeatMode: Int, settings: MusicNotificationSetting, - appTheme: AppTheme + appTheme: AppTheme, ): ServiceState { this.isPlaying = isPlaying this.playerState = playerState @@ -254,6 +256,15 @@ class MusicService : Service() { } } + private fun stopForegroundCompat(removeNotification: Boolean) { + val flags = if (removeNotification) { + ServiceCompat.STOP_FOREGROUND_REMOVE + } else { + 0 + } + ServiceCompat.stopForeground(this, flags) + } + inner class LocalBinder : Binder() { fun getService() = this@MusicService } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/activity/BaseAppCompatActivity.java b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/activity/BaseAppCompatActivity.java index bab0f3d5a..72dc2329c 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/activity/BaseAppCompatActivity.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/activity/BaseAppCompatActivity.java @@ -6,17 +6,18 @@ import com.github.anrimian.musicplayer.di.Components; + public class BaseAppCompatActivity extends AppCompatActivity { - /* - * Experiment: - * After refactor MainActivity to kt crashes started to appear: uninitialized components here - * Moved this method to base java class - * Observe how it works - * - has no effect - */ @Override protected void attachBaseContext(Context base) { - super.attachBaseContext(Components.getAppComponent().localeController().dispatchAttachBaseContext(base)); + // should be always initialized here, but bug is somewhere in Android sdk + // so initialize manually in this case + Components.checkInitialization(base.getApplicationContext()); + Context localizedContext = Components.getAppComponent() + .localeController() + .dispatchAttachBaseContext(base); + super.attachBaseContext(localizedContext); } + } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/activity/BaseMvpAppCompatActivity.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/activity/BaseMvpAppCompatActivity.kt new file mode 100644 index 000000000..0f9cba977 --- /dev/null +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/activity/BaseMvpAppCompatActivity.kt @@ -0,0 +1,15 @@ +package com.github.anrimian.musicplayer.ui.common.activity + +import android.content.Context +import com.github.anrimian.musicplayer.di.Components +import moxy.MvpAppCompatActivity + +open class BaseMvpAppCompatActivity : MvpAppCompatActivity() { + + override fun attachBaseContext(base: Context) { + super.attachBaseContext( + Components.getAppComponent().localeController().dispatchAttachBaseContext(base) + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/DialogUtils.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/DialogUtils.kt index b0df90e4a..befb7dc27 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/DialogUtils.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/DialogUtils.kt @@ -23,7 +23,6 @@ import com.github.anrimian.musicplayer.domain.models.composition.content.Composi import com.github.anrimian.musicplayer.domain.models.folders.FolderFileSource import com.github.anrimian.musicplayer.domain.models.player.SoundBalance import com.github.anrimian.musicplayer.domain.models.playlist.PlayList -import com.github.anrimian.musicplayer.domain.models.utils.CompositionHelper import com.github.anrimian.musicplayer.ui.common.dialogs.share.ShareCompositionsDialogFragment import com.github.anrimian.musicplayer.ui.utils.ViewUtils import com.github.anrimian.musicplayer.ui.utils.fragments.safeShow @@ -205,16 +204,9 @@ fun showConfirmDeleteDialog( compositions: List, deleteCallback: () -> Unit, ) { - val count = compositions.size - val countMessage = if (count == 1) { - context.getString( - R.string.delete_composition_template, - CompositionHelper.formatCompositionName(compositions[0]) - ) - } else { - getDeleteCompositionsMessage(context, count) - } - val message = context.getString(R.string.undone_action_template, countMessage) + val message = Components.getAppComponent() + .messageTextFormatter() + .getConfirmDeleteCompositionsText(context, compositions) val hasExistingFiles = compositions.find { composition -> composition.isFileExists && composition.initialSource == InitialSource.LOCAL } != null @@ -226,18 +218,9 @@ fun showConfirmDeleteDialog( folder: FolderFileSource, deleteCallback: () -> Unit, ) { - val filesCount = folder.filesCount - val name = folder.name - val countMessage = if (filesCount == 0) { - context.getString(R.string.delete_empty_folder, name) - } else { - context.getString( - R.string.delete_folder_template, - name, - getDeleteCompositionsMessage(context, filesCount) - ) - } - val message = context.getString(R.string.undone_action_template, countMessage) + val message = Components.getAppComponent() + .messageTextFormatter() + .getConfirmDeleteFoldersText(context, folder) showConfirmDeleteFileDialog(context, message, deleteCallback, folder.hasAnyStorageFile) } @@ -351,8 +334,4 @@ fun showNumberPickerDialog( .setPositiveButton(android.R.string.ok) { _, _ -> pickAction() } .setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() } .show() -} - -private fun getDeleteCompositionsMessage(context: Context, count: Int): String { - return context.resources.getQuantityString(R.plurals.delete_compositions_template, count, count) } \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/composition/CompositionPopupMenu.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/composition/CompositionPopupMenu.kt index 85e52a6bc..b953e37ad 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/composition/CompositionPopupMenu.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/composition/CompositionPopupMenu.kt @@ -57,6 +57,10 @@ fun showCompositionPopupMenu( sb.append(FormatUtils.formatCompositionAuthor(composition, context)) sb.append(FormatUtils.formatMilliseconds(composition.duration)) sb.append(FormatUtils.formatSize(context, composition.size)) + val comment = composition.comment + if (!comment.isNullOrBlank()) { + sb.appendNewLine(comment) + } binding.tvCompositionInfo.text = sb } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/input/InputTextDialogFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/input/InputTextDialogFragment.kt index 80320c684..9d6bb769c 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/input/InputTextDialogFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/dialogs/input/InputTextDialogFragment.kt @@ -7,13 +7,16 @@ import android.text.InputType import android.text.TextUtils import android.text.method.DigitsKeyListener import android.view.LayoutInflater -import android.view.inputmethod.EditorInfo +import android.view.View +import android.view.inputmethod.EditorInfo.IME_ACTION_DONE +import android.view.inputmethod.EditorInfo.IME_ACTION_UNSPECIFIED import android.widget.ArrayAdapter import android.widget.AutoCompleteTextView import androidx.annotation.StringRes import androidx.fragment.app.DialogFragment import com.github.anrimian.musicplayer.Constants.Arguments.CAN_BE_EMPTY_ARG import com.github.anrimian.musicplayer.Constants.Arguments.COMPLETE_ON_ENTER_ARG +import com.github.anrimian.musicplayer.Constants.Arguments.DESCRIPTION_ARG import com.github.anrimian.musicplayer.Constants.Arguments.DIGITS_ARG import com.github.anrimian.musicplayer.Constants.Arguments.EDIT_TEXT_HINT import com.github.anrimian.musicplayer.Constants.Arguments.EDIT_TEXT_VALUE @@ -21,6 +24,7 @@ import com.github.anrimian.musicplayer.Constants.Arguments.EXTRA_DATA_ARG import com.github.anrimian.musicplayer.Constants.Arguments.HINTS_ARG import com.github.anrimian.musicplayer.Constants.Arguments.INPUT_TYPE_ARG import com.github.anrimian.musicplayer.Constants.Arguments.NEGATIVE_BUTTON_ARG +import com.github.anrimian.musicplayer.Constants.Arguments.NEUTRAL_BUTTON_ARG import com.github.anrimian.musicplayer.Constants.Arguments.POSITIVE_BUTTON_ARG import com.github.anrimian.musicplayer.Constants.Arguments.TITLE_ARG import com.github.anrimian.musicplayer.R @@ -38,6 +42,8 @@ class InputTextDialogFragment : DialogFragment() { @StringRes negativeButtonText: Int, @StringRes editTextHint: Int, editTextValue: String?, + @StringRes description: Int = 0, + @StringRes neutralButtonText: Int = 0, canBeEmpty: Boolean = true, completeOnEnterButton: Boolean = true, inputType: Int = InputType.TYPE_CLASS_TEXT, @@ -50,6 +56,8 @@ class InputTextDialogFragment : DialogFragment() { putInt(POSITIVE_BUTTON_ARG, positiveButtonText) putInt(NEGATIVE_BUTTON_ARG, negativeButtonText) putInt(EDIT_TEXT_HINT, editTextHint) + putInt(DESCRIPTION_ARG, description) + putInt(NEUTRAL_BUTTON_ARG, neutralButtonText) putString(EDIT_TEXT_VALUE, editTextValue) putBoolean(CAN_BE_EMPTY_ARG, canBeEmpty) putBoolean(COMPLETE_ON_ENTER_ARG, completeOnEnterButton) @@ -65,7 +73,8 @@ class InputTextDialogFragment : DialogFragment() { private var onCompleteListener: ((String) -> Unit)? = null private var complexCompleteListener: ((String, Bundle) -> Unit)? = null - + private var onNeutralClickListener: (() -> Unit)? = null + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val binding = DialogCommonInputSimpleBinding.inflate( LayoutInflater.from(requireActivity()) @@ -74,17 +83,49 @@ class InputTextDialogFragment : DialogFragment() { val args = requireArguments() val dialog = AlertDialog.Builder(activity) .setTitle(args.getInt(TITLE_ARG)) - .setPositiveButton(args.getInt(POSITIVE_BUTTON_ARG), null) - .setNegativeButton(args.getInt(NEGATIVE_BUTTON_ARG)) { _, _ -> } .setView(binding.root) .create() + + binding.btnPositive.setText(args.getInt(POSITIVE_BUTTON_ARG)) + binding.btnPositive.setOnClickListener { onCompleteButtonClicked() } + val canBeEmpty = args.getBoolean(CAN_BE_EMPTY_ARG) + val startText = args.getString(EDIT_TEXT_VALUE) + if (!canBeEmpty) { + binding.btnPositive.isEnabled = isEnterButtonEnabled(startText) + SimpleTextWatcher.onTextChanged(editText) { text -> + binding.btnPositive.isEnabled = isEnterButtonEnabled(text) + } + } + + binding.btnNegative.setText(args.getInt(NEGATIVE_BUTTON_ARG)) + binding.btnNegative.setOnClickListener { dismissAllowingStateLoss() } + + val neutralButtonArg = args.getInt(NEUTRAL_BUTTON_ARG) + if (neutralButtonArg > 0) { + binding.btnNeutral.visibility = View.VISIBLE + binding.btnNeutral.setText(neutralButtonArg) + binding.btnNeutral.setOnClickListener { + dismissAllowingStateLoss() + onNeutralClickListener?.invoke() + } + } + AndroidUtils.setSoftInputVisible(dialog.window) dialog.show() - - val canBeEmpty = args.getBoolean(CAN_BE_EMPTY_ARG) + val completeOnEnterButton = args.getBoolean(COMPLETE_ON_ENTER_ARG) - editText.setHint(args.getInt(EDIT_TEXT_HINT)) - editText.imeOptions = if (completeOnEnterButton) EditorInfo.IME_ACTION_DONE else EditorInfo.IME_ACTION_UNSPECIFIED + val hint = args.getInt(EDIT_TEXT_HINT) + if (hint > 0) { + editText.setHint(hint) + } + val description = args.getInt(DESCRIPTION_ARG) + if (description > 0) { + binding.tvDescription.setText(description) + binding.tvDescription.visibility = View.VISIBLE + } else { + binding.tvDescription.visibility = View.GONE + } + editText.imeOptions = if (completeOnEnterButton) IME_ACTION_DONE else IME_ACTION_UNSPECIFIED editText.setRawInputType(args.getInt(INPUT_TYPE_ARG)) val digits = args.getString(DIGITS_ARG) if (digits != null) { @@ -94,13 +135,12 @@ class InputTextDialogFragment : DialogFragment() { if (!canBeEmpty && !isEnterButtonEnabled(editText.text.toString().trim())) { return@setOnEditorActionListener true } - if (actionId == EditorInfo.IME_ACTION_DONE) { + if (actionId == IME_ACTION_DONE) { onCompleteButtonClicked() return@setOnEditorActionListener true } false } - val startText = args.getString(EDIT_TEXT_VALUE) ViewUtils.setEditableText(editText, startText) val hints = args.getStringArray(HINTS_ARG) if (hints != null) { @@ -113,14 +153,7 @@ class InputTextDialogFragment : DialogFragment() { editText.setAdapter(adapter) } editText.requestFocus() - val btnCreate = dialog.getButton(AlertDialog.BUTTON_POSITIVE) - btnCreate.setOnClickListener { onCompleteButtonClicked() } - if (!canBeEmpty) { - btnCreate.isEnabled = isEnterButtonEnabled(startText) - SimpleTextWatcher.onTextChanged(editText) { text -> - btnCreate.isEnabled = isEnterButtonEnabled(text) - } - } + return dialog } @@ -132,6 +165,10 @@ class InputTextDialogFragment : DialogFragment() { this.complexCompleteListener = complexCompleteListener } + fun setOnNeutralClickListener(onNeutralClickListener: () -> Unit) { + this.onNeutralClickListener = onNeutralClickListener + } + private fun onCompleteButtonClicked() { val text = editText.text.toString() if (!TextUtils.equals(text, requireArguments().getString(EDIT_TEXT_VALUE))) { diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/FormatUtils.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/FormatUtils.kt index cc3d92d16..c731399e4 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/FormatUtils.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/FormatUtils.kt @@ -25,26 +25,55 @@ fun getMediaPlayerName(mediaPlayerId: Int) = when(mediaPlayerId) { else -> R.string.android_media_player } -fun showFileSyncState( +fun ProgressView.showFileSyncState( fileSyncState: FileSyncState?, isFileRemote: Boolean, - progressView: ProgressView, + animate: Boolean = true ) { + /*//debug view + val time = 3000L + val timer = java.util.Timer() + timer.scheduleAtFixedRate(object : java.util.TimerTask() { + override fun run() { + post { + clearProgress() + setIconResource(R.drawable.ic_cloud) + setVisible(true, true) + postDelayed({ + setProgressInfo(ProgressInfo()) + setIconResource(R.drawable.ic_upload) + setVisible(true, true) + postDelayed({ + setProgressInfo(ProgressInfo(5, 10)) + setIconResource(R.drawable.ic_upload) + setVisible(true, true) + postDelayed({ + setVisible(false, true, true, true) + }, time) + }, time) + }, time) + } + } + }, 0, time * 4) + return*/ when(fileSyncState) { is FileSyncState.Uploading -> { - progressView.setProgressInfo(fileSyncState.getProgress()) - progressView.setIconResource(R.drawable.ic_upload) + setVisible(true, animate) + setProgressInfo(fileSyncState.getProgress()) + setIconResource(R.drawable.ic_upload) } is FileSyncState.Downloading -> { - progressView.setProgressInfo(fileSyncState.getProgress()) - progressView.setIconResource(R.drawable.ic_download) + setVisible(true, animate) + setProgressInfo(fileSyncState.getProgress()) + setIconResource(R.drawable.ic_download) } else -> { - progressView.clearProgress() if (isFileRemote) { - progressView.setIconResource(R.drawable.ic_cloud) + clearProgress() + setVisible(true, animate) + setIconResource(R.drawable.ic_cloud) } else { - progressView.clearIcon() + setVisible(false, animate, clearIcon = true, clearProgress = true) } } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/MessageTextFormatter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/MessageTextFormatter.kt new file mode 100644 index 000000000..1ae5a0ba3 --- /dev/null +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/MessageTextFormatter.kt @@ -0,0 +1,57 @@ +package com.github.anrimian.musicplayer.ui.common.format + +import android.content.Context +import com.github.anrimian.musicplayer.R +import com.github.anrimian.musicplayer.domain.models.composition.Composition +import com.github.anrimian.musicplayer.domain.models.folders.FolderFileSource +import com.github.anrimian.musicplayer.domain.models.utils.CompositionHelper + +open class MessageTextFormatter { + + open fun getConfirmDeleteCompositionsText( + context: Context, + compositions: List + ): String { + val countMessage = getCompositionsCountMessage(context, compositions) + return context.getString(R.string.undone_action_template, countMessage) + } + + open fun getConfirmDeleteFoldersText(context: Context, folder: FolderFileSource): String { + val countMessage = getFolderCountMessage(context, folder) + return context.getString(R.string.undone_action_template, countMessage) + } + + protected fun getCompositionsCountMessage( + context: Context, + compositions: List + ): String { + val count = compositions.size + return if (count == 1) { + context.getString( + R.string.delete_composition_template, + CompositionHelper.formatCompositionName(compositions[0]) + ) + } else { + getDeleteCompositionsMessage(context, count) + } + } + + protected fun getFolderCountMessage(context: Context, folder: FolderFileSource): String { + val filesCount = folder.filesCount + val name = folder.name + return if (filesCount == 0) { + context.getString(R.string.delete_empty_folder, name) + } else { + context.getString( + R.string.delete_folder_template, + name, + getDeleteCompositionsMessage(context, filesCount) + ) + } + } + + private fun getDeleteCompositionsMessage(context: Context, count: Int): String { + return context.resources.getQuantityString(R.plurals.delete_compositions_template, count, count) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/MessagesUtils.java b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/MessagesUtils.java index 5c00cb63b..8899627bb 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/MessagesUtils.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/MessagesUtils.java @@ -44,7 +44,7 @@ public static String getDeletePlayListItemCompleteMessage(Context context, int size = items.size(); if (size == 1) { return context.getString(R.string.delete_from_playlist_success_template, - formatCompositionName(items.get(0).getComposition()), + formatCompositionName(items.get(0)), playList.getName()); } else { return context.getResources().getQuantityString( diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/description/DescriptionSpannableStringBuilder.java b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/description/DescriptionSpannableStringBuilder.java index 3fac7c6e3..80f387e28 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/description/DescriptionSpannableStringBuilder.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/description/DescriptionSpannableStringBuilder.java @@ -58,4 +58,13 @@ public SpannableStringBuilder append(CharSequence text) { } return super.append(text); } + + public SpannableStringBuilder appendNewLine(CharSequence text) { + if (length() > 0) { + super.append("\n"); + super.append(text); + } + return this; + } + } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/wrappers/CompositionItemWrapper.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/wrappers/CompositionItemWrapper.kt index 81ef38546..9021b2b1c 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/wrappers/CompositionItemWrapper.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/format/wrappers/CompositionItemWrapper.kt @@ -69,7 +69,7 @@ open class CompositionItemWrapper( showCorrupted() showCompositionImage(showCovers) showAsPlaying(isPlaying = false, animate = false) - updateFileSyncState() + updateFileSyncState(false) } fun update(composition: T, payloads: List<*>) { @@ -95,7 +95,7 @@ open class CompositionItemWrapper( showAdditionalInfo() } if (payload == Payloads.FILE_EXISTS) { - updateFileSyncState() + updateFileSyncState(true) } onUpdate(payload) } @@ -169,7 +169,7 @@ open class CompositionItemWrapper( fun showFileSyncState(fileSyncState: FileSyncState?) { this.fileSyncState = fileSyncState - updateFileSyncState() + updateFileSyncState(true) } protected fun showAdditionalInfo() { @@ -226,10 +226,6 @@ open class CompositionItemWrapper( val alpha = if (composition.corruptionType == null) 1f else 0.5f tvMusicName.alpha = alpha tvAdditionalInfo.alpha = alpha - ivMusicIcon.alpha = alpha - ivPlay.alpha = alpha - btnActionsMenu.alpha = alpha - pvFileState.alpha = alpha } private fun showAsDragging(dragging: Boolean) { @@ -250,12 +246,11 @@ open class CompositionItemWrapper( } } - private fun updateFileSyncState() { - //TODO play queue small-land placement - showFileSyncState( + private fun updateFileSyncState(animate: Boolean) { + pvFileState.showFileSyncState( fileSyncState, CompositionHelper.isCompositionFileRemote(composition), - pvFileState + animate ) } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/locale/LocaleControllerImpl.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/locale/LocaleControllerImpl.kt index 014f6e864..0a17d141b 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/locale/LocaleControllerImpl.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/locale/LocaleControllerImpl.kt @@ -10,7 +10,7 @@ import java.util.Locale class LocaleControllerImpl(private val context: Context): LocaleController { private val preferences = SharedPreferencesHelper( - context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE) + context.getSharedPreferences(LOCALE_PREFERENCES, Context.MODE_PRIVATE) ) override fun dispatchAttachBaseContext(baseContext: Context): Context { @@ -56,7 +56,7 @@ class LocaleControllerImpl(private val context: Context): LocaleController { } private companion object { - const val PREFERENCES_NAME = "locale_preferences" + const val LOCALE_PREFERENCES = "locale_preferences" const val CURRENT_LANGUAGE_CODE = "current_language_code" const val SYSTEM_LANGUAGE = "system_language" diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/mvp/AppPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/mvp/AppPresenter.kt index 1307d4855..6d385eb5a 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/mvp/AppPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/mvp/AppPresenter.kt @@ -4,6 +4,7 @@ import com.github.anrimian.musicplayer.ui.common.error.ErrorCommand import com.github.anrimian.musicplayer.ui.common.error.parser.ErrorParser import com.github.anrimian.musicplayer.ui.utils.moxy.RxMvpPresenter import io.reactivex.rxjava3.core.Completable +import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Scheduler import io.reactivex.rxjava3.core.Single @@ -72,6 +73,24 @@ abstract class AppPresenter( .autoDispose() } + //--Flowable + + protected fun Flowable.runOnUi( + onNext: (K) -> Unit, + onError: (ErrorCommand) -> Unit + ) { + this.subscribeOnUi(onNext) { t -> onError(errorParser.parseError(t)) } + } + + protected fun Flowable.subscribeOnUi( + onNext: (K) -> Unit, + onError: (Throwable) -> Unit + ) { + this.observeOn(uiScheduler) + .subscribe(onNext, onError) + .autoDispose() + } + //--Single protected fun Single.runOnUi(onNext: (K) -> Unit, onError: (ErrorCommand) -> Unit) { @@ -133,6 +152,10 @@ abstract class AppPresenter( return subscribe({}, { t -> onError(errorParser.parseError(t)) }, presenterDisposable) } + protected fun Completable.justRunOnUi(onError: (ErrorCommand) -> Unit) { + this.justSubscribe { t -> onError(errorParser.parseError(t)) } + } + protected fun Completable.justSubscribe(onError: (Throwable) -> Unit) { this.observeOn(uiScheduler) .subscribe({}, onError) diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/toolbar/AdvancedToolbar.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/toolbar/AdvancedToolbar.kt index 6d0ed2790..64105acde 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/common/toolbar/AdvancedToolbar.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/common/toolbar/AdvancedToolbar.kt @@ -10,25 +10,24 @@ import android.text.TextUtils import android.util.AttributeSet import android.view.Gravity import android.view.KeyEvent +import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem -import android.view.View import android.view.Window import android.view.animation.AccelerateInterpolator import android.view.animation.DecelerateInterpolator -import android.widget.EditText import android.widget.FrameLayout import android.widget.TextView import android.widget.TextView.OnEditorActionListener import androidx.annotation.ColorInt +import androidx.annotation.DrawableRes import androidx.annotation.MenuRes import androidx.annotation.StringRes -import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.graphics.drawable.DrawerArrowDrawable import androidx.appcompat.widget.ActionMenuView -import androidx.appcompat.widget.Toolbar import com.github.anrimian.musicplayer.Constants import com.github.anrimian.musicplayer.R +import com.github.anrimian.musicplayer.databinding.PartialToolbarBinding import com.github.anrimian.musicplayer.ui.common.menu.PopupMenuWindow.showPopup import com.github.anrimian.musicplayer.ui.utils.AndroidUtils import com.github.anrimian.musicplayer.ui.utils.ViewUtils @@ -41,24 +40,26 @@ import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.subjects.BehaviorSubject class AdvancedToolbar : FrameLayout { - constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context) : this(context, null) + constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init() + } + + constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int, + ) : super(context, attrs, defStyleAttr, defStyleRes) { + init() + } + + private lateinit var binding: PartialToolbarBinding private val stackChangeListener: FragmentStackListener = StackChangeListenerImpl() private lateinit var window: Window - private lateinit var toolbar: Toolbar - private lateinit var clTitleContainer: View - private lateinit var tvTitle: TextView - private lateinit var tvSubtitle: TextView - private lateinit var actionIcon: View - private lateinit var etSearch: EditText - private lateinit var actionMenuView: ActionMenuView - private lateinit var flTitleArea: FrameLayout - private lateinit var selectionModeContainer: View - private lateinit var tvSelectionCount: TextView - private lateinit var acvSelection: ActionMenuView @ColorInt private var controlButtonColor = 0 @@ -86,54 +87,40 @@ class AdvancedToolbar : FrameLayout { private var isInSearchMode = false private var isInActionMode = false - fun initializeViews(window: Window) { - this.window = window - toolbar = findViewById(R.id.toolbarInternal) - actionMenuView = findViewById(R.id.acvMain) - clTitleContainer = findViewById(R.id.titleContainer) - tvTitle = findViewById(R.id.tvTitle) - tvSubtitle = findViewById(R.id.tvSubtitle) - actionIcon = findViewById(R.id.ivActionIcon) - etSearch = findViewById(R.id.etSearch) - flTitleArea = findViewById(R.id.flTitleArea) - selectionModeContainer = findViewById(R.id.selectionModeContainer) - tvSelectionCount = findViewById(R.id.tvSelectionCount) - acvSelection = findViewById(R.id.acvSelection) - - etSearch.addTextChangedListener(SimpleTextWatcher(::onSearchTextChanged)) - etSearch.setOnEditorActionListener(OnEditorActionListener(::onSearchTextViewAction)) - - etSearch.visibility = INVISIBLE - actionIcon.visibility = GONE - selectionModeContainer.visibility = INVISIBLE + fun init() { + binding = PartialToolbarBinding.inflate(LayoutInflater.from(context), this) + + binding.etSearch.addTextChangedListener(SimpleTextWatcher(::onSearchTextChanged)) + binding.etSearch.setOnEditorActionListener(OnEditorActionListener(::onSearchTextViewAction)) + + binding.etSearch.visibility = INVISIBLE + binding.ivActionIcon.visibility = GONE + binding.clSelectionMode.visibility = INVISIBLE controlButtonColor = context.attrColor(R.attr.toolbarTextColorPrimary) controlButtonActionModeColor = context.attrColor(R.attr.actionModeTextColor) backgroundColor = context.attrColor(R.attr.colorPrimary) backgroundActionModeColor = context.attrColor(R.attr.actionModeBackgroundColor) - statusBarColor = window.context.attrColor(android.R.attr.statusBarColor) - statusBarActionModeColor = window.context.attrColor(R.attr.actionModeStatusBarColor) } - fun setupWithActivity(activity: AppCompatActivity) { - //now its only using for back button - activity.setSupportActionBar(toolbar) - val actionBar = activity.supportActionBar - if (actionBar != null) { - actionBar.setDisplayShowHomeEnabled(true) - actionBar.setHomeButtonEnabled(true) - actionBar.setDisplayHomeAsUpEnabled(true) - } + fun setWindow(window: Window) { + this.window = window + statusBarColor = window.context.attrColor(android.R.attr.statusBarColor) + statusBarActionModeColor = window.context.attrColor(R.attr.actionModeStatusBarColor) } fun setupWithNavigation( navigation: FragmentNavigation, drawerArrowDrawable: DrawerArrowDrawable, bottomSheetListener: () -> Boolean, + onNavigationClick: () -> Unit ) { this.navigation = navigation this.drawerArrowDrawable = drawerArrowDrawable this.bottomSheetListener = bottomSheetListener + + binding.ivNavigation.setImageDrawable(drawerArrowDrawable) + binding.ivNavigation.setOnClickListener { onNavigationClick() } onFragmentStackChanged(navigation.screensCount, true) navigation.addStackChangeListener(stackChangeListener) } @@ -152,29 +139,29 @@ class AdvancedToolbar : FrameLayout { } isInSearchMode = enabled searchModeSubject.onNext(enabled) - etSearch.visibility = if (enabled) VISIBLE else GONE - clTitleContainer.alpha = if (!enabled && isContentVisible) 1f else 0f - actionMenuView.visibility = if (enabled) GONE else VISIBLE + binding.etSearch.visibility = if (enabled) VISIBLE else GONE + binding.clTitleContainer.alpha = if (!enabled && isContentVisible) 1f else 0f + binding.acvMain.visibility = if (enabled) GONE else VISIBLE if (!isDrawerArrowLocked()) { setCommandButtonMode(!enabled, !jumpToState) } if (enabled) { - etSearch.requestFocus() + binding.etSearch.requestFocus() if (showKeyboard) { - AndroidUtils.showKeyboard(etSearch) + AndroidUtils.showKeyboard(binding.etSearch) } } else { - etSearch.text = null - AndroidUtils.hideKeyboard(etSearch) + binding.etSearch.text = null + AndroidUtils.hideKeyboard(binding.etSearch) } } fun setupOptionsMenu(@MenuRes menuResId: Int, listener: ((MenuItem) -> Unit)) { - ActionMenuUtil.setupMenu(actionMenuView, menuResId, listener) + ActionMenuUtil.setupMenu(binding.acvMain, menuResId, listener) } fun clearOptionsMenu() { - ActionMenuUtil.setupMenu(actionMenuView, R.menu.empty_stub_menu) { } + ActionMenuUtil.setupMenu(binding.acvMain, R.menu.empty_stub_menu) { } } fun release() { @@ -186,7 +173,7 @@ class AdvancedToolbar : FrameLayout { bundle.putParcelable("superState", super.onSaveInstanceState()) bundle.putBoolean(IN_SEARCH_MODE, isInSearchMode) bundle.putBoolean(IN_SELECTION_MODE, isInActionMode) - bundle.putBoolean(IS_KEYBOARD_SHOWN, AndroidUtils.isKeyboardWasShown(etSearch)) + bundle.putBoolean(IS_KEYBOARD_SHOWN, AndroidUtils.isKeyboardWasShown(binding.etSearch)) return bundle } @@ -224,36 +211,36 @@ class AdvancedToolbar : FrameLayout { return this } - fun getTitle() = tvTitle.text + fun getTitle() = binding.tvTitle.text fun setTitle(@StringRes titleId: Int) { setTitle(context.getString(titleId)) } fun setTitle(title: CharSequence?) { - tvTitle.visibility = if (TextUtils.isEmpty(title)) GONE else VISIBLE - tvTitle.text = title - flTitleArea.contentDescription = title + binding.tvTitle.visibility = if (TextUtils.isEmpty(title)) GONE else VISIBLE + binding.tvTitle.text = title + binding.flTitleArea.contentDescription = title } - fun getSubtitle() = tvSubtitle.text + fun getSubtitle() = binding.tvSubtitle.text fun setSubtitle(@StringRes titleId: Int) { setSubtitle(context.getString(titleId)) } fun setSubtitle(subtitle: CharSequence?) { - tvSubtitle.visibility = if (TextUtils.isEmpty(subtitle)) GONE else VISIBLE - tvSubtitle.text = subtitle + binding.tvSubtitle.visibility = if (TextUtils.isEmpty(subtitle)) GONE else VISIBLE + binding.tvSubtitle.text = subtitle if (!TextUtils.isEmpty(subtitle)) { - flTitleArea.contentDescription = getTitle().toString() + ", " + subtitle + binding.flTitleArea.contentDescription = getTitle().toString() + ", " + subtitle } } fun setTitleClickListener(listener: OnClickListener?) { - actionIcon.visibility = if (listener == null) GONE else VISIBLE - flTitleArea.isEnabled = listener != null - flTitleArea.setOnClickListener(listener) + binding.ivActionIcon.visibility = if (listener == null) GONE else VISIBLE + binding.flTitleArea.isEnabled = listener != null + binding.flTitleArea.setOnClickListener(listener) } fun clearTitleMenu() { @@ -274,11 +261,11 @@ class AdvancedToolbar : FrameLayout { fun isInActionMode() = isInActionMode - fun getActionMenuView(): ActionMenuView? = actionMenuView + fun getActionMenuView(): ActionMenuView? = binding.acvMain fun setupSearch(textChangeListener: ((String) -> Unit)?, text: String?) { setupSearch(textChangeListener) - etSearch.setText(text) + binding.etSearch.setText(text) setSearchModeEnabled(!TextUtils.isEmpty(text)) } @@ -287,13 +274,13 @@ class AdvancedToolbar : FrameLayout { textConfirmListener = textChangeListener } - fun isSearchLocked() = !etSearch.isEnabled + fun isSearchLocked() = !binding.etSearch.isEnabled fun setSearchLocked(locked: Boolean) { - etSearch.isEnabled = !locked + binding.etSearch.isEnabled = !locked } - fun getSearchText() = etSearch.text.toString() + fun getSearchText() = binding.etSearch.text.toString() fun getSearchModeObservable(): Observable = searchModeSubject @@ -357,11 +344,11 @@ class AdvancedToolbar : FrameLayout { } fun setupSelectionModeMenu(@MenuRes menuResource: Int, listener: ((MenuItem) -> Unit)?) { - ActionMenuUtil.setupMenu(acvSelection, menuResource, listener, 1) + ActionMenuUtil.setupMenu(binding.acvSelection, menuResource, listener, 1) } fun editActionMenu(callback: (Menu) -> Unit) { - callback(acvSelection.menu) + callback(binding.acvSelection.menu) } fun showSelectionMode(count: Int) { @@ -372,19 +359,19 @@ class AdvancedToolbar : FrameLayout { if (!isInActionMode) { setSelectionModeEnabled(true, true) } - tvSelectionCount.text = count.toString() + binding.tvSelectionCount.text = count.toString() } } fun updateSelectionMenu(itemCallback: (MenuItem) -> Unit) { - val menu = acvSelection.menu + val menu = binding.acvSelection.menu for (i in 0 until menu.size()) { itemCallback(menu.getItem(i)) } } fun setContentAlpha(alpha: Float) { - clTitleContainer.alpha = alpha + binding.clTitleContainer.alpha = alpha isContentVisible = alpha == 1f } @@ -392,6 +379,17 @@ class AdvancedToolbar : FrameLayout { isContentVisible = visible } + fun getToolbarModesViewGroup() = binding.flToolbarModes + + fun setNavigationButtonHintIcon(@DrawableRes iconRes: Int) { + if (iconRes == -1) { + binding.ivNavHint.visibility = INVISIBLE + return + } + binding.ivNavHint.visibility = VISIBLE + binding.ivNavHint.setImageResource(iconRes) + } + private fun setSelectionModeEnabled(enabled: Boolean, animate: Boolean) { isInActionMode = enabled selectionModeSubject.onNext(enabled) @@ -434,20 +432,20 @@ class AdvancedToolbar : FrameLayout { if (isInSearchMode) { baseAnimators.add( ViewUtils.getVisibilityAnimator( - etSearch, + binding.etSearch, anotherElementsVisibility ) ) } else { baseAnimators.add( ViewUtils.getVisibilityAnimator( - clTitleContainer, + binding.clTitleContainer, anotherElementsVisibility ) ) baseAnimators.add( ViewUtils.getVisibilityAnimator( - actionMenuView, anotherElementsVisibility + binding.acvMain, anotherElementsVisibility ) ) } @@ -457,7 +455,7 @@ class AdvancedToolbar : FrameLayout { val modeAnimators: MutableList = ArrayList() modeAnimators.add( ViewUtils.getVisibilityAnimator( - selectionModeContainer, + binding.clSelectionMode, modeElementsVisibility ) ) @@ -477,12 +475,12 @@ class AdvancedToolbar : FrameLayout { } else { setCommandButtonMode(isHamburger, false) if (isInSearchMode) { - etSearch.visibility = anotherElementsVisibility + binding.etSearch.visibility = anotherElementsVisibility } else { - clTitleContainer.visibility = anotherElementsVisibility - actionMenuView.visibility = anotherElementsVisibility + binding.clTitleContainer.visibility = anotherElementsVisibility + binding.acvMain.visibility = anotherElementsVisibility } - selectionModeContainer.visibility = modeElementsVisibility + binding.clSelectionMode.visibility = modeElementsVisibility drawerArrowDrawable.color = endControlButtonColor setBackgroundColor(endBackgroundColor) AndroidUtils.setStatusBarColor(window, endStatusBarColor) diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/album/AlbumEditorActivity.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/album/AlbumEditorActivity.kt index c2e6687ab..02a0238d3 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/album/AlbumEditorActivity.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/album/AlbumEditorActivity.kt @@ -12,6 +12,7 @@ import com.github.anrimian.musicplayer.databinding.ActivityAlbumEditBinding import com.github.anrimian.musicplayer.di.Components import com.github.anrimian.musicplayer.domain.models.albums.Album import com.github.anrimian.musicplayer.ui.common.AppAndroidUtils +import com.github.anrimian.musicplayer.ui.common.activity.BaseMvpAppCompatActivity import com.github.anrimian.musicplayer.ui.common.dialogs.input.InputTextDialogFragment import com.github.anrimian.musicplayer.ui.common.error.ErrorCommand import com.github.anrimian.musicplayer.ui.common.format.FormatUtils @@ -21,16 +22,14 @@ import com.github.anrimian.musicplayer.ui.editor.common.ErrorHandler import com.github.anrimian.musicplayer.ui.utils.AndroidUtils import com.github.anrimian.musicplayer.ui.utils.ViewUtils import com.github.anrimian.musicplayer.ui.utils.dialogs.ProgressDialogFragment -import com.github.anrimian.musicplayer.ui.utils.dialogs.newProgressDialogFragment import com.github.anrimian.musicplayer.ui.utils.fragments.DialogFragmentDelayRunner import com.github.anrimian.musicplayer.ui.utils.fragments.DialogFragmentRunner import com.github.anrimian.musicplayer.ui.utils.setToolbar import com.github.anrimian.musicplayer.ui.utils.slidr.SlidrPanel import com.google.android.material.snackbar.Snackbar -import moxy.MvpAppCompatActivity import moxy.ktx.moxyPresenter -class AlbumEditorActivity : MvpAppCompatActivity(), AlbumEditorView { +class AlbumEditorActivity : BaseMvpAppCompatActivity(), AlbumEditorView { companion object { fun newIntent( @@ -96,12 +95,6 @@ class AlbumEditorActivity : MvpAppCompatActivity(), AlbumEditorView { }) } - override fun attachBaseContext(base: Context) { - super.attachBaseContext( - Components.getAppComponent().localeController().dispatchAttachBaseContext(base) - ) - } - override fun closeScreen() { finish() } @@ -124,7 +117,7 @@ class AlbumEditorActivity : MvpAppCompatActivity(), AlbumEditorView { } override fun showRenameProgress() { - progressDialogRunner.show(newProgressDialogFragment(R.string.rename_progress)) + progressDialogRunner.show(ProgressDialogFragment.newInstance(R.string.rename_progress)) } override fun hideRenameProgress() { diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/album/AlbumEditorPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/album/AlbumEditorPresenter.kt index bd23998a2..bfbaa0344 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/album/AlbumEditorPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/album/AlbumEditorPresenter.kt @@ -70,7 +70,7 @@ class AlbumEditorPresenter( if (lastEditAction != null) { RxUtils.dispose(changeDisposable, presenterDisposable) changeDisposable = lastEditAction!! - .doFinally { lastEditAction = null } + .doOnComplete { lastEditAction = null } .subscribe(viewState::showErrorMessage) } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/batch/BatchEditorPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/batch/BatchEditorPresenter.kt index 138d42ec7..ba552f512 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/batch/BatchEditorPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/batch/BatchEditorPresenter.kt @@ -55,7 +55,7 @@ abstract class BatchEditorPresenter( fun onRetryFailedEditActionClicked() { if (lastEditAction != null) { - lastEditAction!!.doFinally { lastEditAction = null } + lastEditAction!!.doOnComplete { lastEditAction = null } .subscribe(viewState::closeScreen, viewState::showError) } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/composition/CompositionEditorActivity.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/composition/CompositionEditorActivity.kt index 281c47445..80c7ba36c 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/composition/CompositionEditorActivity.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/composition/CompositionEditorActivity.kt @@ -23,6 +23,7 @@ import com.github.anrimian.musicplayer.domain.models.composition.InitialSource import com.github.anrimian.musicplayer.domain.utils.FileUtils import com.github.anrimian.musicplayer.domain.utils.TextUtils import com.github.anrimian.musicplayer.ui.common.AppAndroidUtils +import com.github.anrimian.musicplayer.ui.common.activity.BaseMvpAppCompatActivity import com.github.anrimian.musicplayer.ui.common.activity.PickImageContract import com.github.anrimian.musicplayer.ui.common.dialogs.input.InputTextDialogFragment import com.github.anrimian.musicplayer.ui.common.error.ErrorCommand @@ -39,7 +40,6 @@ import com.github.anrimian.musicplayer.ui.utils.AndroidUtils import com.github.anrimian.musicplayer.ui.utils.ViewUtils import com.github.anrimian.musicplayer.ui.utils.dialogs.ProgressDialogFragment import com.github.anrimian.musicplayer.ui.utils.dialogs.menu.MenuDialogFragment -import com.github.anrimian.musicplayer.ui.utils.dialogs.newProgressDialogFragment import com.github.anrimian.musicplayer.ui.utils.fragments.DialogFragmentDelayRunner import com.github.anrimian.musicplayer.ui.utils.fragments.DialogFragmentRunner import com.github.anrimian.musicplayer.ui.utils.setDrawableStart @@ -48,10 +48,9 @@ import com.github.anrimian.musicplayer.ui.utils.slidr.SlidrPanel import com.github.anrimian.musicplayer.ui.utils.views.recycler_view.SingleItemAdapter import com.github.anrimian.musicplayer.ui.utils.views.recycler_view.touch_helper.drag_and_drop.SimpleItemTouchHelperCallback import com.google.android.material.snackbar.Snackbar -import moxy.MvpAppCompatActivity import moxy.ktx.moxyPresenter -class CompositionEditorActivity : MvpAppCompatActivity(), CompositionEditorView { +class CompositionEditorActivity : BaseMvpAppCompatActivity(), CompositionEditorView { companion object { fun newIntent(context: Context, compositionId: Long): Intent { @@ -208,12 +207,6 @@ class CompositionEditorActivity : MvpAppCompatActivity(), CompositionEditorView ) } - override fun attachBaseContext(base: Context) { - super.attachBaseContext( - Components.getAppComponent().localeController().dispatchAttachBaseContext(base) - ) - } - override fun closeScreen() { finish() } @@ -436,7 +429,7 @@ class CompositionEditorActivity : MvpAppCompatActivity(), CompositionEditorView } override fun showChangeFileProgress() { - val fragment = newProgressDialogFragment(R.string.changing_file_progress) + val fragment = ProgressDialogFragment.newInstance(R.string.changing_file_progress) progressDialogRunner.show(fragment) } @@ -446,7 +439,7 @@ class CompositionEditorActivity : MvpAppCompatActivity(), CompositionEditorView override fun showSyncState(fileSyncState: FileSyncState, composition: FullComposition) { val isFileRemote = composition.storageId == null && composition.initialSource == InitialSource.REMOTE - showFileSyncState(fileSyncState, isFileRemote, binding.pvFileState) + binding.pvFileState.showFileSyncState(fileSyncState, isFileRemote) progressDialogRunner.runAction { dialog -> val message = if (fileSyncState is FileSyncState.Downloading) { val progress = fileSyncState.getProgress() diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/composition/CompositionEditorPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/composition/CompositionEditorPresenter.kt index 8ae6b7eab..f82b90387 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/composition/CompositionEditorPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/composition/CompositionEditorPresenter.kt @@ -267,7 +267,7 @@ class CompositionEditorPresenter( if (lastEditAction != null) { RxUtils.dispose(changeDisposable, presenterDisposable) changeDisposable = lastEditAction!! - .doFinally { lastEditAction = null } + .doOnComplete { lastEditAction = null } .subscribe({}, this::onDefaultError, presenterDisposable) } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/lyrics/LyricsEditorActivity.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/lyrics/LyricsEditorActivity.kt index 08347e621..a0a742ebb 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/lyrics/LyricsEditorActivity.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/lyrics/LyricsEditorActivity.kt @@ -7,22 +7,21 @@ import com.github.anrimian.musicplayer.Constants import com.github.anrimian.musicplayer.R import com.github.anrimian.musicplayer.databinding.ActivityLyricsEditBinding import com.github.anrimian.musicplayer.di.Components +import com.github.anrimian.musicplayer.ui.common.activity.BaseMvpAppCompatActivity import com.github.anrimian.musicplayer.ui.common.error.ErrorCommand import com.github.anrimian.musicplayer.ui.common.format.showSnackbar import com.github.anrimian.musicplayer.ui.editor.common.ErrorHandler import com.github.anrimian.musicplayer.ui.utils.AndroidUtils import com.github.anrimian.musicplayer.ui.utils.ViewUtils import com.github.anrimian.musicplayer.ui.utils.dialogs.ProgressDialogFragment -import com.github.anrimian.musicplayer.ui.utils.dialogs.newProgressDialogFragment import com.github.anrimian.musicplayer.ui.utils.fragments.DialogFragmentDelayRunner import com.github.anrimian.musicplayer.ui.utils.setToolbar import com.github.anrimian.musicplayer.ui.utils.slidr.SlidrPanel import com.github.anrimian.musicplayer.ui.utils.views.text_view.SimpleTextWatcher import com.google.android.material.snackbar.Snackbar -import moxy.MvpAppCompatActivity import moxy.ktx.moxyPresenter -class LyricsEditorActivity : MvpAppCompatActivity(), LyricsEditorView { +class LyricsEditorActivity : BaseMvpAppCompatActivity(), LyricsEditorView { companion object { fun newIntent(context: Context, compositionId: Long): Intent { @@ -78,12 +77,6 @@ class LyricsEditorActivity : MvpAppCompatActivity(), LyricsEditorView { ) } - override fun attachBaseContext(base: Context) { - super.attachBaseContext( - Components.getAppComponent().localeController().dispatchAttachBaseContext(base) - ) - } - override fun showLyrics(text: String) { binding.progressStateView.hideAll() ViewUtils.setEditableText(binding.evLyrics, text) @@ -94,7 +87,7 @@ class LyricsEditorActivity : MvpAppCompatActivity(), LyricsEditorView { } override fun showChangeFileProgress() { - val fragment = newProgressDialogFragment(R.string.changing_file_progress) + val fragment = ProgressDialogFragment.newInstance(R.string.changing_file_progress) progressDialogRunner.show(fragment) } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/lyrics/LyricsEditorPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/lyrics/LyricsEditorPresenter.kt index 047db405b..09741c84a 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/lyrics/LyricsEditorPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/editor/lyrics/LyricsEditorPresenter.kt @@ -54,7 +54,7 @@ class LyricsEditorPresenter( if (lastEditAction != null) { RxUtils.dispose(changeDisposable, presenterDisposable) changeDisposable = lastEditAction!! - .doFinally { lastEditAction = null } + .doOnComplete { lastEditAction = null } .subscribe(viewState::showErrorMessage) } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/albums/items/AlbumItemsFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/albums/items/AlbumItemsFragment.kt index b2d64bf1c..e083b0124 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/albums/items/AlbumItemsFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/albums/items/AlbumItemsFragment.kt @@ -24,6 +24,7 @@ import com.github.anrimian.musicplayer.ui.common.dialogs.showConfirmDeleteDialog import com.github.anrimian.musicplayer.ui.common.error.ErrorCommand import com.github.anrimian.musicplayer.ui.common.format.FormatUtils import com.github.anrimian.musicplayer.ui.common.format.MessagesUtils +import com.github.anrimian.musicplayer.ui.common.format.showSnackbar import com.github.anrimian.musicplayer.ui.common.toolbar.AdvancedToolbar import com.github.anrimian.musicplayer.ui.common.view.ViewUtils import com.github.anrimian.musicplayer.ui.editor.album.AlbumEditorActivity @@ -279,17 +280,16 @@ class AlbumItemsFragment : BaseLibraryCompositionsFragment(), AlbumItemsView, private fun onOptionsItemClicked(item: MenuItem) { when (item.itemId) { R.id.menu_edit -> presenter.onEditAlbumClicked() - R.id.menu_sleep_timer -> SleepTimerDialogFragment().safeShow(childFragmentManager) - R.id.menu_equalizer -> EqualizerDialogFragment().safeShow(childFragmentManager) + R.id.menu_sleep_timer -> SleepTimerDialogFragment().safeShow(this) + R.id.menu_equalizer -> EqualizerDialogFragment().safeShow(this) } } private fun showEditorRequestDeniedMessage() { - MessagesUtils.makeSnackbar( - binding.listContainer, + binding.listContainer.showSnackbar( R.string.android_r_edit_file_permission_denied, Snackbar.LENGTH_LONG - ).show() + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/artists/items/ArtistItemsFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/artists/items/ArtistItemsFragment.kt index 585202ddc..08505a8af 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/artists/items/ArtistItemsFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/artists/items/ArtistItemsFragment.kt @@ -354,8 +354,8 @@ class ArtistItemsFragment : BaseLibraryCompositionsFragment(), ArtistItemsView, private fun onOptionsItemClicked(item: MenuItem) { when (item.itemId) { R.id.menu_rename -> presenter.onRenameArtistClicked() - R.id.menu_sleep_timer -> SleepTimerDialogFragment().safeShow(childFragmentManager) - R.id.menu_equalizer -> EqualizerDialogFragment().safeShow(childFragmentManager) + R.id.menu_sleep_timer -> SleepTimerDialogFragment().safeShow(this) + R.id.menu_equalizer -> EqualizerDialogFragment().safeShow(this) } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/common/compositions/BaseLibraryCompositionsFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/common/compositions/BaseLibraryCompositionsFragment.kt index 41b4470fc..a1205c69e 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/common/compositions/BaseLibraryCompositionsFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/common/compositions/BaseLibraryCompositionsFragment.kt @@ -38,13 +38,14 @@ abstract class BaseLibraryCompositionsFragment : BaseLibraryFragment() { @MenuRes menuItemId: Int, position: Int ) { + val act = activity ?: return when (menuItemId) { R.id.menu_play -> getLibraryPresenter().onPlayActionSelected(position) R.id.menu_play_next -> getLibraryPresenter().onPlayNextCompositionClicked(composition) R.id.menu_add_to_queue -> getLibraryPresenter().onAddToQueueCompositionClicked(composition) R.id.menu_add_to_playlist -> getLibraryPresenter().onAddToPlayListButtonClicked(composition) - R.id.menu_edit -> startActivity(CompositionEditorActivity.newIntent(requireContext(), composition.id)) - R.id.menu_show_in_folders -> MainActivity.showInFolders(requireActivity(), composition) + R.id.menu_edit -> startActivity(CompositionEditorActivity.newIntent(act, composition.id)) + R.id.menu_show_in_folders -> MainActivity.showInFolders(act, composition) R.id.menu_share -> shareComposition(this, composition) R.id.menu_delete -> getLibraryPresenter().onDeleteCompositionButtonClicked(composition) } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/common/compositions/BaseLibraryCompositionsPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/common/compositions/BaseLibraryCompositionsPresenter.kt index a91e0b4d5..b7dc19b4b 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/common/compositions/BaseLibraryCompositionsPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/common/compositions/BaseLibraryCompositionsPresenter.kt @@ -203,7 +203,7 @@ abstract class BaseLibraryCompositionsPresenter = selectedCompositions @@ -272,7 +272,7 @@ abstract class BaseLibraryCompositionsPresenter + interactor.deleteIgnoredFolder(folder).justSubscribe(this::onDefaultError) + } } fun onRetryFailedEditActionClicked() { if (lastEditAction != null) { RxUtils.dispose(fileActionDisposable, presenterDisposable) fileActionDisposable = lastEditAction!! - .doFinally { lastEditAction = null } + .doOnComplete { lastEditAction = null } .subscribe(viewState::updateMoveFilesList, this::onDefaultError, presenterDisposable) } } @@ -369,7 +370,7 @@ class LibraryFoldersPresenter( } fun onChangeRandomModePressed() { - playerInteractor.setRandomPlayingEnabled(!playerInteractor.isRandomPlayingEnabled()) + playerInteractor.changeRandomMode() } fun getSelectedMoveFiles(): LinkedHashSet = interactor.getFilesToMove() @@ -527,7 +528,7 @@ class LibraryFoldersPresenter( private fun subscribeOnCurrentComposition() { playerInteractor.getCurrentCompositionObservable() - .subscribeOnUi(this::onCurrentCompositionReceived, errorParser::logError) + .runOnUi(this::onCurrentCompositionReceived, viewState::showErrorMessage) } private fun onCurrentCompositionReceived(currentComposition: CurrentComposition) { diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/folders/LibraryFoldersView.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/folders/LibraryFoldersView.kt index cffcac3c0..e4e970450 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/folders/LibraryFoldersView.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/folders/LibraryFoldersView.kt @@ -6,6 +6,7 @@ import com.github.anrimian.musicplayer.domain.models.composition.CurrentComposit import com.github.anrimian.musicplayer.domain.models.composition.DeletedComposition import com.github.anrimian.musicplayer.domain.models.folders.FileSource import com.github.anrimian.musicplayer.domain.models.folders.FolderFileSource +import com.github.anrimian.musicplayer.domain.models.folders.FolderInfo import com.github.anrimian.musicplayer.domain.models.folders.IgnoredFolder import com.github.anrimian.musicplayer.domain.models.order.Order import com.github.anrimian.musicplayer.domain.models.utils.ListPosition @@ -38,7 +39,7 @@ interface LibraryFoldersView : BaseLibraryView { fun showError(errorCommand: ErrorCommand) @AddToEndSingle - fun showFolderInfo(folder: FolderFileSource?) + fun showFolderInfo(folder: FolderInfo?) @StateStrategyType(value = AddToEndSingleTagStrategy::class, tag = PROGRESS_DIALOG_STATE) fun hideProgressDialog() diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/genres/items/GenreItemsFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/genres/items/GenreItemsFragment.kt index a017c4c66..4f1dcb213 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/genres/items/GenreItemsFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/genres/items/GenreItemsFragment.kt @@ -66,6 +66,7 @@ class GenreItemsFragment : BaseLibraryCompositionsFragment(), GenreItemsView, private lateinit var toolbar: AdvancedToolbar private lateinit var adapter: CompositionsAdapter + private lateinit var layoutManager: LinearLayoutManager private lateinit var choosePlayListDialogRunner: DialogFragmentRunner @@ -99,7 +100,7 @@ class GenreItemsFragment : BaseLibraryCompositionsFragment(), GenreItemsView, this::onCompositionMenuClicked ) binding.recyclerView.adapter = adapter - val layoutManager = LinearLayoutManager(context) + layoutManager = LinearLayoutManager(context) binding.recyclerView.layoutManager = layoutManager val callback = ShortSwipeCallback(requireContext(), @@ -139,6 +140,11 @@ class GenreItemsFragment : BaseLibraryCompositionsFragment(), GenreItemsView, toolbar.setupOptionsMenu(R.menu.library_genre_items_menu, this::onOptionsItemClicked) } + override fun onStop() { + super.onStop() + presenter.onStop(ViewUtils.getListPosition(layoutManager)) + } + override fun onBackPressed(): Boolean { if (toolbar.isInActionMode()) { presenter.onSelectionModeBackPressed() @@ -187,7 +193,9 @@ class GenreItemsFragment : BaseLibraryCompositionsFragment(), GenreItemsView, adapter.submitList(genres) } - override fun restoreListPosition(listPosition: ListPosition) {} + override fun restoreListPosition(listPosition: ListPosition) { + ViewUtils.scrollToPosition(layoutManager, listPosition) + } override fun onCompositionSelected(composition: Composition, position: Int) { adapter.setItemSelected(position) diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/genres/items/GenreItemsPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/genres/items/GenreItemsPresenter.kt index f1643968a..b9942b20f 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/library/genres/items/GenreItemsPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/library/genres/items/GenreItemsPresenter.kt @@ -44,10 +44,12 @@ class GenreItemsPresenter( } override fun getSavedListPosition(): ListPosition? { - return null + return interactor.getSavedItemsListPosition(genreId) } - override fun saveListPosition(listPosition: ListPosition) {} + override fun saveListPosition(listPosition: ListPosition) { + interactor.saveItemsListPosition(genreId, listPosition) + } fun onFragmentResumed() { interactor.setSelectedGenreScreen(genreId) diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/main/MainActivity.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/main/MainActivity.kt index e9c35c19e..34eb15650 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/main/MainActivity.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/main/MainActivity.kt @@ -51,13 +51,18 @@ class MainActivity : BaseAppCompatActivity() { setContentView(R.layout.activity_main) + val loggerRepository = Components.getAppComponent().loggerRepository() + val wasCriticalFatalError = loggerRepository.wasCriticalFatalError() + if (Permissions.hasFilePermission(this) && !wasCriticalFatalError) { + Components.getAppComponent().musicServiceInteractor().prepare() + } + if (savedInstanceState == null) { - val loggerRepository = Components.getAppComponent().loggerRepository() if (loggerRepository.wasFatalError() && loggerRepository.isReportDialogOnStartEnabled() - || loggerRepository.wasCriticalFatalError() + || wasCriticalFatalError ) { ErrorReportDialogFragment().safeShow(supportFragmentManager, null) - if (loggerRepository.wasCriticalFatalError()) { + if (wasCriticalFatalError) { return } } @@ -193,6 +198,7 @@ class MainActivity : BaseAppCompatActivity() { if (Permissions.hasFilePermission(requireContext())) { appComponent.widgetUpdater().start() appComponent.mediaScannerRepository().runStorageObserver() + appComponent.musicServiceInteractor().prepare() } } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/main/external_player/ExternalPlayerActivity.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/main/external_player/ExternalPlayerActivity.kt index dafe85e06..f8a2f23bc 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/main/external_player/ExternalPlayerActivity.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/main/external_player/ExternalPlayerActivity.kt @@ -1,6 +1,5 @@ package com.github.anrimian.musicplayer.ui.main.external_player -import android.content.Context import android.content.Intent import android.media.MediaMetadataRetriever import android.net.Uri @@ -18,6 +17,7 @@ import com.github.anrimian.musicplayer.databinding.ActivityExternalPlayerBinding import com.github.anrimian.musicplayer.di.Components import com.github.anrimian.musicplayer.domain.models.utils.CompositionHelper import com.github.anrimian.musicplayer.domain.models.volume.VolumeState +import com.github.anrimian.musicplayer.ui.common.activity.BaseMvpAppCompatActivity import com.github.anrimian.musicplayer.ui.common.compat.CompatUtils import com.github.anrimian.musicplayer.ui.common.dialogs.speed.SpeedSelectorDialogFragment import com.github.anrimian.musicplayer.ui.common.error.ErrorCommand @@ -35,12 +35,11 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.schedulers.Schedulers -import moxy.MvpAppCompatActivity import moxy.ktx.moxyPresenter import java.io.IOException import java.util.concurrent.TimeUnit -class ExternalPlayerActivity : MvpAppCompatActivity(), ExternalPlayerView { +class ExternalPlayerActivity : BaseMvpAppCompatActivity(), ExternalPlayerView { private val presenter by moxyPresenter { Components.getExternalPlayerComponent().externalPlayerPresenter() @@ -94,10 +93,6 @@ class ExternalPlayerActivity : MvpAppCompatActivity(), ExternalPlayerView { } } - override fun attachBaseContext(base: Context) { - super.attachBaseContext(Components.getAppComponent().localeController().dispatchAttachBaseContext(base)) - } - override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) val uriToPlay = intent.data @@ -114,7 +109,6 @@ class ExternalPlayerActivity : MvpAppCompatActivity(), ExternalPlayerView { override fun displayComposition(source: ExternalCompositionSource) { binding.tvComposition.text = CompositionHelper.formatCompositionName(source.title, source.displayName) binding.tvCompositionAuthor.text = FormatUtils.formatAuthor(source.artist, this) - seekBarViewWrapper.setMax(source.duration) binding.tvTotalTime.text = FormatUtils.formatMilliseconds(source.duration) Components.getAppComponent() @@ -137,7 +131,7 @@ class ExternalPlayerActivity : MvpAppCompatActivity(), ExternalPlayerView { } override fun showTrackState(currentPosition: Long, duration: Long) { - seekBarViewWrapper.setProgress(currentPosition) + seekBarViewWrapper.setProgress(currentPosition, duration) val formattedTime = FormatUtils.formatMilliseconds(currentPosition) binding.sbTrackState.contentDescription = getString(R.string.position_template, formattedTime) binding.tvPlayedTime.text = formattedTime diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/main/setup/SetupFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/main/setup/SetupFragment.kt index 6b8c747af..71d66d59f 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/main/setup/SetupFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/main/setup/SetupFragment.kt @@ -64,6 +64,7 @@ class SetupFragment : MvpAppCompatFragment(), SetupView { appComponent.widgetUpdater().start() appComponent.notificationsDisplayer().removeErrorNotification() appComponent.mediaScannerRepository().runStorageObserver() + appComponent.musicServiceInteractor().prepare() } override fun goToMainScreen() { diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/main/setup/SetupPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/main/setup/SetupPresenter.kt index 5b537acef..496fbf0bf 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/main/setup/SetupPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/main/setup/SetupPresenter.kt @@ -6,14 +6,17 @@ import moxy.MvpPresenter * Created on 19.10.2017. */ class SetupPresenter : MvpPresenter() { - + + private var isPermissionGranted = false + override fun onFirstViewAttach() { super.onFirstViewAttach() requestFilesPermissions() } fun onFilesPermissionResult(granted: Boolean) { - if (granted) { + if (granted && !isPermissionGranted) { + isPermissionGranted = true viewState.startSystemServices() viewState.goToMainScreen() } else { diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerFragment.kt index 29ade4111..8b941550d 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerFragment.kt @@ -8,8 +8,6 @@ import android.view.View import android.view.ViewGroup import android.widget.LinearLayout import androidx.annotation.DrawableRes -import androidx.appcompat.app.ActionBarDrawerToggle -import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.graphics.drawable.DrawerArrowDrawable import androidx.constraintlayout.motion.widget.MotionLayout import androidx.core.view.GravityCompat @@ -26,6 +24,7 @@ import com.github.anrimian.musicplayer.databinding.PartialDetailedMusicBinding import com.github.anrimian.musicplayer.databinding.PartialDrawerHeaderBinding import com.github.anrimian.musicplayer.databinding.PartialQueueToolbarBinding import com.github.anrimian.musicplayer.di.Components +import com.github.anrimian.musicplayer.domain.interactors.player.ActionState import com.github.anrimian.musicplayer.domain.interactors.sleep_timer.NO_TIMER import com.github.anrimian.musicplayer.domain.models.Screens import com.github.anrimian.musicplayer.domain.models.composition.Composition @@ -155,7 +154,7 @@ class PlayerFragment : BaseLibraryFragment(), BackButtonListener, PlayerView { savedInstanceState: Bundle?, ): View { binding = FragmentDrawerBinding.inflate(inflater, container, false) - toolbar = binding.toolbar.root + toolbar = binding.toolbar toolbarPlayQueueBinding = binding.toolbarPlayQueue panelBinding = binding.clMusicPanel!! return binding.root @@ -165,8 +164,7 @@ class PlayerFragment : BaseLibraryFragment(), BackButtonListener, PlayerView { super.onViewCreated(view, savedInstanceState) AndroidUtils.setNavigationBarColorAttr(requireActivity(), R.attr.playerPanelBackground) - toolbar.initializeViews(requireActivity().window) - toolbar.setupWithActivity(requireActivity() as AppCompatActivity) + toolbar.setWindow(requireActivity().window) navigation = FragmentNavigation.from(childFragmentManager) navigation.initialize(binding.drawerFragmentContainer!!, savedInstanceState) @@ -213,19 +211,14 @@ class PlayerFragment : BaseLibraryFragment(), BackButtonListener, PlayerView { } drawerHeaderBinding = PartialDrawerHeaderBinding.bind(headerView) - val drawerToggle = ActionBarDrawerToggle( - requireActivity(), - binding.drawer, - R.string.open_drawer, - R.string.close_drawer - ) - val drawerArrowDrawable = createDrawerArrowDrawable() - drawerToggle.drawerArrowDrawable = drawerArrowDrawable binding.drawer.addDrawerListener(SimpleDrawerListener(this::onDrawerClosed)) - toolbar.setupWithNavigation(navigation, drawerArrowDrawable) { - playerPanelWrapper.isBottomPanelExpanded - } + toolbar.setupWithNavigation( + navigation, + createDrawerArrowDrawable(), + { playerPanelWrapper.isBottomPanelExpanded }, + this::onNavigationClick + ) panelBinding.ivSkipToPrevious.setOnClickListener { presenter.onSkipToPreviousButtonClicked() } panelBinding.ivSkipToPrevious.onRewindHold(presenter::onFastSeekBackwardCalled) @@ -329,17 +322,6 @@ class PlayerFragment : BaseLibraryFragment(), BackButtonListener, PlayerView { } } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == android.R.id.home) { - if (binding.drawer.getDrawerLockMode(GravityCompat.START) != DrawerLayout.LOCK_MODE_LOCKED_CLOSED) { - binding.drawer.openDrawer(GravityCompat.START) - } else { - onBackPressed() - } - } - return super.onOptionsItemSelected(item) - } - override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) navigation.onSaveInstanceState(outState) @@ -474,13 +456,11 @@ class PlayerFragment : BaseLibraryFragment(), BackButtonListener, PlayerView { panelBinding.sbTrackState.contentDescription = noCompositionMessage previousCoverComposition = null } else { - val composition = item.composition - val compositionName = CompositionHelper.formatCompositionName(composition) + val compositionName = CompositionHelper.formatCompositionName(item) panelBinding.tvCurrentComposition.text = compositionName - panelBinding.tvTotalTime.text = FormatUtils.formatMilliseconds(composition.duration) + panelBinding.tvTotalTime.text = FormatUtils.formatMilliseconds(item.duration) panelBinding.tvCurrentCompositionAuthor.text = - FormatUtils.formatCompositionAuthor(composition, requireContext()) - seekBarViewWrapper.setMax(composition.duration) + FormatUtils.formatCompositionAuthor(item, requireContext()) panelBinding.topPanel.contentDescription = getString(R.string.now_playing_template, compositionName) panelBinding.sbTrackState.contentDescription = null @@ -493,16 +473,15 @@ class PlayerFragment : BaseLibraryFragment(), BackButtonListener, PlayerView { panelBinding.ivMusicIcon.setImageResource(R.drawable.ic_music_placeholder) return } - val composition = item.composition Components.getAppComponent() .imageLoader() .displayImageInReusableTarget( panelBinding.ivMusicIcon, - composition, + item, previousCoverComposition, R.drawable.ic_music_placeholder ) - previousCoverComposition = composition + previousCoverComposition = item } override fun showRepeatMode(mode: Int) { @@ -529,7 +508,7 @@ class PlayerFragment : BaseLibraryFragment(), BackButtonListener, PlayerView { } override fun showTrackState(currentPosition: Long, duration: Long) { - seekBarViewWrapper.setProgress(currentPosition) + seekBarViewWrapper.setProgress(currentPosition, duration) val formattedTime = FormatUtils.formatMilliseconds(currentPosition) panelBinding.sbTrackState.contentDescription = getString(R.string.position_template, formattedTime) panelBinding.tvPlayedTime.text = formattedTime @@ -630,13 +609,9 @@ class PlayerFragment : BaseLibraryFragment(), BackButtonListener, PlayerView { isFileRemote = false } else { formattedState = syncState - isFileRemote = CompositionHelper.isCompositionFileRemote(item.composition) + isFileRemote = CompositionHelper.isCompositionFileRemote(item) } - showFileSyncState( - formattedState, - isFileRemote, - panelBinding.pvFileState - ) + panelBinding.pvFileState.showFileSyncState(formattedState, isFileRemote) } override fun locateCompositionInFolders(composition: Composition) { @@ -666,6 +641,10 @@ class PlayerFragment : BaseLibraryFragment(), BackButtonListener, PlayerView { panelBinding.tvVolume.setSmallDrawableStart(getVolumeIcon(volumePercent)) } + override fun showActionState(actionState: ActionState) { + Components.getAppComponent().actionStateBinder().bind(binding.toolbar, actionState) + } + fun openPlayerPanel() { presenter.onOpenPlayerPanelClicked() playerPanelWrapper.openPlayerPanel() @@ -795,4 +774,12 @@ class PlayerFragment : BaseLibraryFragment(), BackButtonListener, PlayerView { ).show() } + private fun onNavigationClick() { + if (binding.drawer.getDrawerLockMode(GravityCompat.START) != DrawerLayout.LOCK_MODE_LOCKED_CLOSED) { + binding.drawer.openDrawer(GravityCompat.START) + } else { + onBackPressed() + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerPresenter.kt index ad305ea27..5992a5f5b 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerPresenter.kt @@ -2,6 +2,7 @@ package com.github.anrimian.musicplayer.ui.player_screen import com.github.anrimian.filesync.models.state.file.FileSyncState import com.github.anrimian.musicplayer.data.storage.exceptions.UnavailableMediaStoreException +import com.github.anrimian.musicplayer.domain.interactors.player.ActionState import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor import com.github.anrimian.musicplayer.domain.interactors.player.PlayerScreenInteractor import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor @@ -44,6 +45,7 @@ class PlayerPresenter( override fun onFirstViewAttach() { super.onFirstViewAttach() viewState.setButtonPanelState(playerScreenInteractor.isPlayerPanelOpen) + viewState.showActionState(ActionState.NO_STATE) subscribeOnUiSettings() subscribeOnRandomMode() subscribeOnSpeedAvailableState() @@ -59,6 +61,7 @@ class PlayerPresenter( playerScreenInteractor.playerScreensSwipeObservable .unsafeSubscribeOnUi(viewState::showScreensSwipeEnabled) playerScreenInteractor.volumeObservable.unsafeSubscribeOnUi(viewState::onVolumeChanged) + playerScreenInteractor.actionStateObservable.unsafeSubscribeOnUi(viewState::showActionState) } fun onSetupScreenStateRequested() { @@ -130,7 +133,7 @@ class PlayerPresenter( } fun onShareCompositionButtonClicked() { - currentItem?.let { item -> viewState.showShareCompositionDialog(item.composition) } + currentItem?.let { item -> viewState.showShareCompositionDialog(item) } } fun onTrackRewoundTo(progress: Int) { @@ -138,13 +141,13 @@ class PlayerPresenter( } fun onDeleteCurrentCompositionButtonClicked() { - currentItem?.let { item -> viewState.showConfirmDeleteDialog(listOf(item.composition)) } + currentItem?.let { item -> viewState.showConfirmDeleteDialog(listOf(item)) } } fun onAddCurrentCompositionToPlayListButtonClicked() { currentItem?.let { item -> compositionsForPlayList.clear() - compositionsForPlayList.add(item.composition) + compositionsForPlayList.add(item) viewState.showSelectPlayListDialog() } } @@ -166,11 +169,11 @@ class PlayerPresenter( } fun onEditCompositionButtonClicked() { - currentItem?.let { item -> viewState.startEditCompositionScreen(item.composition.id) } + currentItem?.let { item -> viewState.startEditCompositionScreen(item.id) } } fun onShowCurrentCompositionInFoldersClicked() { - currentItem?.let { item -> viewState.locateCompositionInFolders(item.composition) } + currentItem?.let { item -> viewState.locateCompositionInFolders(item) } } fun onRestoreDeletedItemClicked() { @@ -239,18 +242,16 @@ class PlayerPresenter( if (currentItem == null || currentItem != newItem - || !CompositionHelper.areSourcesTheSame(newItem.composition, currentItem.composition)) { + || !CompositionHelper.areSourcesTheSame(newItem, currentItem)) { var updateCover = false if ((currentItem == null) != (newItem == null)) { updateCover = true } else if (currentItem != null && newItem != null) { - val newComposition = newItem.composition - val currentComposition = currentItem.composition - updateCover = currentComposition.dateModified != newComposition.dateModified - || currentComposition.coverModifyTime != newComposition.coverModifyTime - || currentComposition.size != newComposition.size - || currentComposition.isFileExists != newComposition.isFileExists + updateCover = currentItem.dateModified != newItem.dateModified + || currentItem.coverModifyTime != newItem.coverModifyTime + || currentItem.size != newItem.size + || currentItem.isFileExists != newItem.isFileExists } this.currentItem = newItem @@ -293,10 +294,7 @@ class PlayerPresenter( } private fun onTrackPositionChanged(currentPosition: Long) { - currentItem?.let { item -> - val duration = item.composition.duration - viewState.showTrackState(currentPosition, duration) - } + currentItem?.let { item -> viewState.showTrackState(currentPosition, item.duration) } } private fun subscribeOnUiSettings() { diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerView.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerView.kt index ae8c35678..b3548b43d 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerView.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/PlayerView.kt @@ -1,6 +1,7 @@ package com.github.anrimian.musicplayer.ui.player_screen import com.github.anrimian.filesync.models.state.file.FileSyncState +import com.github.anrimian.musicplayer.domain.interactors.player.ActionState import com.github.anrimian.musicplayer.domain.models.composition.Composition import com.github.anrimian.musicplayer.domain.models.composition.DeletedComposition import com.github.anrimian.musicplayer.domain.models.play_queue.PlayQueueItem @@ -100,4 +101,7 @@ interface PlayerView : BaseLibraryView { @AddToEndSingle fun onVolumeChanged(volume: VolumeState) + @AddToEndSingle + fun showActionState(actionState: ActionState) + } \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/lyrics/LyricsPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/lyrics/LyricsPresenter.kt index 39a0b977a..f796450f3 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/lyrics/LyricsPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/lyrics/LyricsPresenter.kt @@ -35,7 +35,7 @@ class LyricsPresenter( } private fun onCurrentQueueItemChanged(event: PlayQueueEvent) { - currentComposition = event.playQueueItem?.composition + currentComposition = event.playQueueItem viewState.resetTextPosition() } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/PlayQueueFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/PlayQueueFragment.kt index 21013e0cb..67e087b54 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/PlayQueueFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/PlayQueueFragment.kt @@ -18,7 +18,6 @@ import com.github.anrimian.musicplayer.di.Components import com.github.anrimian.musicplayer.domain.models.composition.Composition import com.github.anrimian.musicplayer.domain.models.composition.DeletedComposition import com.github.anrimian.musicplayer.domain.models.play_queue.PlayQueueItem -import com.github.anrimian.musicplayer.domain.models.playlist.PlayList import com.github.anrimian.musicplayer.ui.common.dialogs.composition.showCompositionPopupMenu import com.github.anrimian.musicplayer.ui.common.dialogs.shareComposition import com.github.anrimian.musicplayer.ui.common.dialogs.showConfirmDeleteDialog @@ -36,8 +35,8 @@ import com.github.anrimian.musicplayer.ui.player_screen.queue.adapter.PlayQueueA import com.github.anrimian.musicplayer.ui.playlist_screens.choose.ChoosePlayListDialogFragment import com.github.anrimian.musicplayer.ui.playlist_screens.create.CreatePlayListDialogFragment import com.github.anrimian.musicplayer.ui.sleep_timer.SleepTimerDialogFragment -import com.github.anrimian.musicplayer.ui.utils.AndroidUtils import com.github.anrimian.musicplayer.ui.utils.ViewUtils +import com.github.anrimian.musicplayer.ui.utils.attrColor import com.github.anrimian.musicplayer.ui.utils.colorFromAttr import com.github.anrimian.musicplayer.ui.utils.fragments.DialogFragmentRunner import com.github.anrimian.musicplayer.ui.utils.fragments.safeShow @@ -116,7 +115,7 @@ class PlayQueueFragment: BaseLibraryFragment(), PlayQueueView { binding.rvPlayQueue.adapter = playQueueAdapter val callback = FormatUtils.withSwipeToDelete( binding.rvPlayQueue, - AndroidUtils.getColorFromAttr(requireContext(), R.attr.listItemBottomBackground), + attrColor(R.attr.listItemBottomBackground), presenter::onItemSwipedToDelete, ItemTouchHelper.START, R.drawable.ic_remove_from_queue, @@ -273,16 +272,15 @@ class PlayQueueFragment: BaseLibraryFragment(), PlayQueueView { } } - private fun onPlayItemMenuClicked(view: View, playQueueItem: PlayQueueItem) { - val composition = playQueueItem.composition - showCompositionPopupMenu(view, R.menu.play_queue_item_menu, composition) { item -> + private fun onPlayItemMenuClicked(view: View, queueItem: PlayQueueItem) { + showCompositionPopupMenu(view, R.menu.play_queue_item_menu, queueItem) { item -> when (item.itemId) { - R.id.menu_add_to_playlist -> presenter.onAddQueueItemToPlayListButtonClicked(composition) - R.id.menu_edit -> startActivity(CompositionEditorActivity.newIntent(requireContext(), composition.id)) - R.id.menu_show_in_folders -> MainActivity.showInFolders(requireActivity(), composition) - R.id.menu_share -> shareComposition(this, composition) - R.id.menu_delete_from_queue -> presenter.onDeleteQueueItemClicked(playQueueItem) - R.id.menu_delete -> presenter.onDeleteCompositionButtonClicked(composition) + R.id.menu_add_to_playlist -> presenter.onAddQueueItemToPlayListButtonClicked(queueItem) + R.id.menu_edit -> startActivity(CompositionEditorActivity.newIntent(requireContext(), queueItem.id)) + R.id.menu_show_in_folders -> MainActivity.showInFolders(requireActivity(), queueItem) + R.id.menu_share -> shareComposition(this, queueItem) + R.id.menu_delete_from_queue -> presenter.onDeleteQueueItemClicked(queueItem) + R.id.menu_delete -> presenter.onDeleteCompositionButtonClicked(queueItem) } } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/PlayQueuePresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/PlayQueuePresenter.kt index ebaba23fb..1a3b325e7 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/PlayQueuePresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/PlayQueuePresenter.kt @@ -1,6 +1,7 @@ package com.github.anrimian.musicplayer.ui.player_screen.queue import com.github.anrimian.filesync.SyncInteractor +import com.github.anrimian.musicplayer.data.utils.rx.retryWithDelay import com.github.anrimian.musicplayer.domain.Constants.NO_POSITION import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerInteractor import com.github.anrimian.musicplayer.domain.interactors.player.PlayerScreenInteractor @@ -21,6 +22,7 @@ import io.reactivex.rxjava3.core.Scheduler import io.reactivex.rxjava3.disposables.Disposable import java.util.Collections import java.util.LinkedList +import java.util.concurrent.TimeUnit class PlayQueuePresenter( private val playerInteractor: LibraryPlayerInteractor, @@ -74,7 +76,7 @@ class PlayQueuePresenter( } currentPosition = position currentItem = item - playerInteractor.skipToItem(item.id) + playerInteractor.skipToItem(item.itemId) viewState.showCurrentQueueItem(currentItem) } @@ -146,7 +148,7 @@ class PlayQueuePresenter( } fun onPlayListForAddingCreated(playList: PlayList) { - val compositionsToAdd = playQueue.map(PlayQueueItem::getComposition) + val compositionsToAdd = ArrayList(playQueue) performAddToPlaylist(compositionsToAdd, playList) {} } @@ -252,7 +254,11 @@ class PlayQueuePresenter( currentPosition = NO_POSITION positionDisposable = playerInteractor.getCurrentItemPositionObservable() .observeOn(uiScheduler) - .subscribe(this::onItemPositionReceived) + .retryWithDelay(10, 10, TimeUnit.SECONDS) + .subscribe( + this::onItemPositionReceived, + { t -> viewState.showErrorMessage(errorParser.parseError(t)) } + ) presenterDisposable.add(positionDisposable!!) } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/adapter/PlayQueueViewHolder.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/adapter/PlayQueueViewHolder.kt index c13000c29..7c16013a2 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/adapter/PlayQueueViewHolder.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/queue/adapter/PlayQueueViewHolder.kt @@ -52,13 +52,12 @@ class PlayQueueViewHolder( fun bind(item: PlayQueueItem, showCovers: Boolean) { playQueueItem = item - val composition = item.composition - compositionItemWrapper.bind(composition, showCovers) + compositionItemWrapper.bind(item, showCovers) } fun update(item: PlayQueueItem, payloads: List<*>) { playQueueItem = item - compositionItemWrapper.update(item.composition, payloads) + compositionItemWrapper.update(item, payloads) } fun setCoversVisible(visible: Boolean) { @@ -74,7 +73,7 @@ class PlayQueueViewHolder( } fun setFileSyncStates(fileSyncStates: Map) { - compositionItemWrapper.showFileSyncState(fileSyncStates[playQueueItem.composition.id]) + compositionItemWrapper.showFileSyncState(fileSyncStates[playQueueItem.id]) } fun getPlayQueueItem() = playQueueItem diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/view/ActionStateBinder.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/view/ActionStateBinder.kt new file mode 100644 index 000000000..b57ed8b33 --- /dev/null +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/view/ActionStateBinder.kt @@ -0,0 +1,10 @@ +package com.github.anrimian.musicplayer.ui.player_screen.view + +import com.github.anrimian.musicplayer.domain.interactors.player.ActionState +import com.github.anrimian.musicplayer.ui.common.toolbar.AdvancedToolbar + +interface ActionStateBinder { + + fun bind(toolbar: AdvancedToolbar, actionState: ActionState) + +} \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/view/wrappers/PlayerPanelWrapperImpl.java b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/view/wrappers/PlayerPanelWrapperImpl.java index 7a1f22eb1..5afbca01e 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/view/wrappers/PlayerPanelWrapperImpl.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/player_screen/view/wrappers/PlayerPanelWrapperImpl.java @@ -19,7 +19,6 @@ import com.github.anrimian.musicplayer.databinding.FragmentDrawerBinding; import com.github.anrimian.musicplayer.databinding.PartialDetailedMusicBinding; import com.github.anrimian.musicplayer.databinding.PartialQueueToolbarBinding; -import com.github.anrimian.musicplayer.databinding.PartialToolbarBinding; import com.github.anrimian.musicplayer.domain.utils.functions.Callback; import com.github.anrimian.musicplayer.ui.common.toolbar.AdvancedToolbar; import com.github.anrimian.musicplayer.ui.player_screen.view.slide.ToolbarDelegate; @@ -44,7 +43,6 @@ public class PlayerPanelWrapperImpl implements PlayerPanelWrapper { private final PartialDetailedMusicBinding panelBinding; private final FragmentDrawerBinding viewBinding; private final PartialQueueToolbarBinding queueToolbarBinding; - private final PartialToolbarBinding toolbarBinding; private final MotionLayout mlBottomSheet; @Nullable private final CoordinatorLayout bottomSheetCoordinator; @@ -86,11 +84,10 @@ public PlayerPanelWrapperImpl(View view, this.bottomSheetStateListener = bottomSheetStateListener; queueToolbarBinding = viewBinding.toolbarPlayQueue; - toolbarBinding = viewBinding.toolbar; clPlayQueueContainer = viewBinding.clPlayQueueContainer; bottomSheetCoordinator = view.findViewById(R.id.coordinator_bottom_sheet); tvCurrentComposition = panelBinding.tvCurrentComposition; - toolbar = toolbarBinding.getRoot(); + toolbar = viewBinding.toolbar; bottomSheetLeftShadow = view.findViewById(R.id.bottom_sheet_left_shadow); bottomSheetTopLeftShadow = view.findViewById(R.id.bottom_sheet_top_left_shadow); contentViewContainer = view.findViewById(R.id.drawer_fragment_container); @@ -198,9 +195,9 @@ private SlideDelegate createBottomSheetDelegate() { boundDelegateManager .addDelegate(new BoundValuesDelegate(0.4f, 1f, new VisibilityDelegate(queueToolbarBinding.getRoot()))) .addDelegate(new ReverseDelegate(new BoundValuesDelegate(0.0f, 0.8f, new ToolbarVisibilityDelegate(toolbar)))) - .addDelegate(new BoundValuesDelegate(0f, 0.6f, new ReverseDelegate(new VisibilityDelegate(toolbarBinding.flToolbarContentContainer)))) + .addDelegate(new BoundValuesDelegate(0f, 0.6f, new ReverseDelegate(new VisibilityDelegate(toolbar.getToolbarModesViewGroup())))) .addDelegate(new BoundValuesDelegate(1f, 1f, new ReverseDelegate(new VisibilityDelegate(contentViewContainer)))) - .addDelegate(new TextSizeDelegate(tvCurrentComposition, R.dimen.current_composition_expand_text_size, R.dimen.current_composition_expand_text_size)) + .addDelegate(new TextSizeDelegate(tvCurrentComposition, R.dimen.current_composition_expand_text_size, R.dimen.current_composition_expand_text_size))//no sense .addDelegate(new MotionLayoutDelegate(mlBottomSheet)) .addDelegate(new BoundValuesDelegate(0.7f, 0.95f, new ReverseDelegate(new VisibilityDelegate(viewBinding.drawerFragmentContainer)))) .addDelegate(new BoundValuesDelegate(0.3f, 1.0f, new ExpandViewDelegate(R.dimen.panel_cover_size, panelBinding.ivMusicIcon))) @@ -247,7 +244,7 @@ private void setViewStartState() { clPlayQueueContainer.setVisibility(INVISIBLE); queueToolbarBinding.getRoot().setVisibility(INVISIBLE); queueToolbarBinding.getRoot().setAlpha(0f); - toolbarBinding.flToolbarContentContainer.setVisibility(INVISIBLE); + toolbar.getToolbarModesViewGroup().setVisibility(INVISIBLE); toolbar.setContentAlpha(0f); contentViewContainer.setVisibility(INVISIBLE); } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListFragment.kt index 6d81b1ad4..dd219c4e6 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListFragment.kt @@ -17,6 +17,7 @@ import com.github.anrimian.musicplayer.data.models.folders.UriFileReference import com.github.anrimian.musicplayer.databinding.FragmentBaseFabListBinding import com.github.anrimian.musicplayer.di.Components import com.github.anrimian.musicplayer.domain.models.composition.Composition +import com.github.anrimian.musicplayer.domain.models.composition.CurrentComposition import com.github.anrimian.musicplayer.domain.models.composition.DeletedComposition import com.github.anrimian.musicplayer.domain.models.playlist.PlayList import com.github.anrimian.musicplayer.domain.models.playlist.PlayListItem @@ -127,7 +128,7 @@ class PlayListFragment : BaseLibraryFragment(), PlayListView, BackButtonListener binding.recyclerView, presenter.isCoversEnabled(), this::onItemMenuClicked, - presenter::onItemIconClicked + presenter::onItemClicked ) binding.recyclerView.adapter = adapter @@ -297,6 +298,10 @@ class PlayListFragment : BaseLibraryFragment(), PlayListView, BackButtonListener FormatUtils.formatPlayAllButton(binding.fab, isRandomModeEnabled) } + override fun showCurrentComposition(currentComposition: CurrentComposition) { + adapter.showCurrentComposition(currentComposition) + } + override fun setDragEnabled(enabled: Boolean) { touchHelperCallback.setDragEnabled(enabled) } @@ -312,8 +317,7 @@ class PlayListFragment : BaseLibraryFragment(), PlayListView, BackButtonListener } private fun onItemMenuClicked(view: View, position: Int, playListItem: PlayListItem) { - val composition = playListItem.composition - showCompositionPopupMenu(view, R.menu.play_list_item_menu, composition) { item -> + showCompositionPopupMenu(view, R.menu.play_list_item_menu, playListItem) { item -> onCompositionActionSelected(playListItem, item.itemId, position) } } @@ -323,18 +327,17 @@ class PlayListFragment : BaseLibraryFragment(), PlayListView, BackButtonListener @MenuRes menuItemId: Int, position: Int ) { - val composition = item.composition when (menuItemId) { R.id.menu_play -> presenter.onPlayActionSelected(position) - R.id.menu_play_next -> presenter.onPlayNextCompositionClicked(composition) - R.id.menu_add_to_queue -> presenter.onAddToQueueCompositionClicked(composition) - R.id.menu_add_to_playlist -> presenter.onAddToPlayListButtonClicked(composition) + R.id.menu_play_next -> presenter.onPlayNextCompositionClicked(item) + R.id.menu_add_to_queue -> presenter.onAddToQueueCompositionClicked(item) + R.id.menu_add_to_playlist -> presenter.onAddToPlayListButtonClicked(item) R.id.menu_edit -> - startActivity(CompositionEditorActivity.newIntent(requireContext(), composition.id)) - R.id.menu_show_in_folders -> MainActivity.showInFolders(requireActivity(), composition) - R.id.menu_share -> shareComposition(this, composition) + startActivity(CompositionEditorActivity.newIntent(requireContext(), item.id)) + R.id.menu_show_in_folders -> MainActivity.showInFolders(requireActivity(), item) + R.id.menu_share -> shareComposition(this, item) R.id.menu_delete_from_play_list -> presenter.onDeleteFromPlayListButtonClicked(item) - R.id.menu_delete -> presenter.onDeleteCompositionButtonClicked(composition) + R.id.menu_delete -> presenter.onDeleteCompositionButtonClicked(item) } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListPresenter.kt index 112016e17..13427fbb0 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListPresenter.kt @@ -6,9 +6,8 @@ import com.github.anrimian.musicplayer.domain.interactors.player.LibraryPlayerIn import com.github.anrimian.musicplayer.domain.interactors.playlists.PlayListsInteractor import com.github.anrimian.musicplayer.domain.interactors.settings.DisplaySettingsInteractor import com.github.anrimian.musicplayer.domain.models.composition.Composition +import com.github.anrimian.musicplayer.domain.models.composition.CurrentComposition import com.github.anrimian.musicplayer.domain.models.folders.FileReference -import com.github.anrimian.musicplayer.domain.models.play_queue.PlayQueueEvent -import com.github.anrimian.musicplayer.domain.models.play_queue.PlayQueueItem import com.github.anrimian.musicplayer.domain.models.playlist.PlayList import com.github.anrimian.musicplayer.domain.models.playlist.PlayListItem import com.github.anrimian.musicplayer.domain.models.sync.FileKey @@ -52,7 +51,7 @@ class PlayListPresenter( private val compositionsToDelete: MutableList = LinkedList() private var startDragPosition = 0 - private var currentItem: PlayQueueItem? = null + private var currentComposition: Composition? = null private var lastDeleteAction: Completable? = null @@ -62,8 +61,10 @@ class PlayListPresenter( super.onFirstViewAttach() subscribeOnCompositions() subscribePlayList() - subscribeOnCurrentComposition() - subscribeOnRepeatMode() + playerInteractor.getCurrentCompositionObservable() + .subscribeOnUi(this::onCurrentCompositionReceived, errorParser::logError) + playerInteractor.getRandomPlayingObservable() + .subscribeOnUi(viewState::showRandomMode, errorParser::logError) syncInteractor.getFilesSyncStateObservable() .unsafeSubscribeOnUi(viewState::showFilesSyncState) } @@ -77,8 +78,14 @@ class PlayListPresenter( playListsInteractor.saveItemsListPosition(playListId, listPosition) } - fun onItemIconClicked(position: Int) { - startPlaying(position) + fun onItemClicked(item: PlayListItem, position: Int) { + if (item.id == currentComposition?.id) { + playerInteractor.playOrPause() + } else { + startPlaying(position) + viewState.showCurrentComposition(CurrentComposition(item, true)) + } + return } fun onPlayAllButtonClicked() { @@ -191,7 +198,7 @@ class PlayListPresenter( } fun onChangeRandomModePressed() { - playerInteractor.setRandomPlayingEnabled(!playerInteractor.isRandomPlayingEnabled()) + playerInteractor.changeRandomMode() } fun onFolderForExportSelected(folder: FileReference) { @@ -314,22 +321,13 @@ class PlayListPresenter( } } - private fun subscribeOnCurrentComposition() { - playerInteractor.getCurrentQueueItemObservable() - .subscribeOnUi(this::onCurrentCompositionReceived, errorParser::logError) - } - - private fun onCurrentCompositionReceived(playQueueEvent: PlayQueueEvent) { - currentItem = playQueueEvent.playQueueItem - } - - private fun subscribeOnRepeatMode() { - playerInteractor.getRandomPlayingObservable() - .subscribeOnUi(viewState::showRandomMode, errorParser::logError) + private fun onCurrentCompositionReceived(currentComposition: CurrentComposition) { + this.currentComposition = currentComposition.composition + viewState.showCurrentComposition(currentComposition) } private fun startPlaying(position: Int = Constants.NO_POSITION) { - playerInteractor.setQueueAndPlay(items.map { item -> item.composition.id }, position) + playerInteractor.setQueueAndPlay(items.map { item -> item.id }, position) .runOnUi(viewState::showErrorMessage) } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListView.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListView.kt index 27c540c3b..12295ed90 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListView.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/PlayListView.kt @@ -2,6 +2,7 @@ package com.github.anrimian.musicplayer.ui.playlist_screens.playlist import com.github.anrimian.filesync.models.state.file.FileSyncState import com.github.anrimian.musicplayer.domain.models.composition.Composition +import com.github.anrimian.musicplayer.domain.models.composition.CurrentComposition import com.github.anrimian.musicplayer.domain.models.composition.DeletedComposition import com.github.anrimian.musicplayer.domain.models.playlist.PlayList import com.github.anrimian.musicplayer.domain.models.playlist.PlayListItem @@ -79,6 +80,9 @@ interface PlayListView : BaseLibraryView { @AddToEndSingle fun showRandomMode(isRandomModeEnabled: Boolean) + @AddToEndSingle + fun showCurrentComposition(currentComposition: CurrentComposition) + @AddToEndSingle fun setDragEnabled(enabled: Boolean) diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/adapter/PlayListItemAdapter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/adapter/PlayListItemAdapter.kt index 11b315286..2c75b2d9d 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/adapter/PlayListItemAdapter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/adapter/PlayListItemAdapter.kt @@ -6,6 +6,7 @@ import android.view.ViewGroup import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.RecyclerView import com.github.anrimian.filesync.models.state.file.FileSyncState +import com.github.anrimian.musicplayer.domain.models.composition.CurrentComposition import com.github.anrimian.musicplayer.domain.models.playlist.PlayListItem import com.github.anrimian.musicplayer.domain.models.utils.PlayListItemHelper import com.github.anrimian.musicplayer.ui.utils.views.recycler_view.diff_utils.SimpleDiffItemCallback @@ -19,13 +20,14 @@ class PlayListItemAdapter( recyclerView: RecyclerView, private val coversEnabled: Boolean, private val menuClickListener: (View, Int, PlayListItem) -> Unit, - private val onIconClickListener: (Int) -> Unit + private val onItemClickListener: (PlayListItem, Int) -> Unit ) : MvpDiffAdapter( lifecycleOwner, recyclerView, SimpleDiffItemCallback(PlayListItemHelper::areSourcesTheSame, PlayListItemHelper::getChangePayload) ) { + private var currentComposition: CurrentComposition? = null private var syncStates = emptyMap() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlayListItemViewHolder { @@ -33,7 +35,7 @@ class PlayListItemAdapter( LayoutInflater.from(parent.context), parent, menuClickListener, - onIconClickListener + onItemClickListener ) } @@ -41,9 +43,17 @@ class PlayListItemAdapter( super.onBindViewHolder(holder, position) val composition = getItem(position) holder.bind(composition, coversEnabled) + holder.showCurrentComposition(currentComposition, false) holder.setFileSyncStates(syncStates) } + fun showCurrentComposition(currentComposition: CurrentComposition?) { + this.currentComposition = currentComposition + forEachHolder { holder -> + holder.showCurrentComposition(currentComposition, true) + } + } + fun showFileSyncStates(states: Map) { this.syncStates = states forEachHolder { holder -> diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/adapter/PlayListItemViewHolder.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/adapter/PlayListItemViewHolder.kt index 38499d0b3..ccce985f2 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/adapter/PlayListItemViewHolder.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlist/adapter/PlayListItemViewHolder.kt @@ -6,6 +6,7 @@ import android.view.ViewGroup import com.github.anrimian.filesync.models.state.file.FileSyncState import com.github.anrimian.musicplayer.R import com.github.anrimian.musicplayer.domain.models.composition.Composition +import com.github.anrimian.musicplayer.domain.models.composition.CurrentComposition import com.github.anrimian.musicplayer.domain.models.playlist.PlayListItem import com.github.anrimian.musicplayer.ui.common.format.wrappers.CompositionItemWrapper import com.github.anrimian.musicplayer.ui.utils.views.recycler_view.mvp.MvpDiffAdapter @@ -19,7 +20,7 @@ class PlayListItemViewHolder( inflater: LayoutInflater, parent: ViewGroup, menuClickListener: (View, Int, PlayListItem) -> Unit, - onIconClickListener: (Int) -> Unit, + onItemClickListener: (PlayListItem, Int) -> Unit, ) : MvpDiffAdapter.MvpViewHolder(inflater.inflate(R.layout.item_storage_music, parent, false)), DragListener, SwipeListener { @@ -27,11 +28,14 @@ class PlayListItemViewHolder( private lateinit var item: PlayListItem + private var isCurrent = false + init { compositionItemWrapper = CompositionItemWrapper( itemView, - { onIconClickListener(bindingAdapterPosition) } - ) { onIconClickListener(bindingAdapterPosition) } + { onItemClickListener(item, bindingAdapterPosition) }, + { onItemClickListener(item, bindingAdapterPosition) } + ) itemView.findViewById(R.id.btnActionsMenu).setOnClickListener { v -> menuClickListener(v, bindingAdapterPosition, item) } @@ -51,11 +55,32 @@ class PlayListItemViewHolder( fun bind(item: PlayListItem, coversEnabled: Boolean) { this.item = item - val composition = item.composition - compositionItemWrapper.bind(composition, coversEnabled) + compositionItemWrapper.bind(item, coversEnabled) } fun setFileSyncStates(fileSyncStates: Map) { - compositionItemWrapper.showFileSyncState(fileSyncStates[item.composition.id]) + compositionItemWrapper.showFileSyncState(fileSyncStates[item.id]) + } + + fun showCurrentComposition( + currentComposition: CurrentComposition?, + animate: Boolean + ) { + var isCurrent = false + var isPlaying = false + if (currentComposition != null) { + isCurrent = item.id == currentComposition.composition?.id + isPlaying = isCurrent && currentComposition.isPlaying + } + showAsCurrentComposition(isCurrent) + compositionItemWrapper.showAsPlaying(isPlaying, animate) } + + private fun showAsCurrentComposition(isCurrent: Boolean) { + if (this.isCurrent != isCurrent) { + this.isCurrent = isCurrent + compositionItemWrapper.showAsCurrentComposition(isCurrent) + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlists/PlayListsFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlists/PlayListsFragment.kt index 39fc97c70..b41bf19a6 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlists/PlayListsFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlists/PlayListsFragment.kt @@ -48,6 +48,7 @@ import com.github.anrimian.musicplayer.ui.utils.fragments.navigation.FragmentNav import com.github.anrimian.musicplayer.ui.utils.fragments.navigation.FragmentNavigationListener import com.github.anrimian.musicplayer.ui.utils.fragments.safeShow import com.github.anrimian.musicplayer.ui.utils.getMenuItems +import com.github.anrimian.musicplayer.ui.utils.safeLaunch import com.github.anrimian.musicplayer.ui.utils.views.recycler_view.RecyclerViewUtils import com.github.anrimian.musicplayer.ui.utils.views.recycler_view.touch_helper.short_swipe.ShortSwipeCallback import moxy.ktx.moxyPresenter @@ -331,7 +332,7 @@ class PlayListsFragment : BaseLibraryFragment(), PlayListsView, FragmentNavigati private fun onOptionsItemClicked(item: MenuItem) { when (item.itemId) { R.id.menu_search -> toolbar.setSearchModeEnabled(true) - R.id.menu_import_playlist -> pickPlaylistFileLauncher.launch(PLAYLIST_MIME_TYPE) + R.id.menu_import_playlist -> pickPlaylistFileLauncher.safeLaunch(requireContext(), PLAYLIST_MIME_TYPE) R.id.menu_sleep_timer -> SleepTimerDialogFragment().safeShow(childFragmentManager) R.id.menu_equalizer -> EqualizerDialogFragment().safeShow(childFragmentManager) } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlists/PlayListsPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlists/PlayListsPresenter.kt index bd95dd465..45ceda27d 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlists/PlayListsPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/playlist_screens/playlists/PlayListsPresenter.kt @@ -150,7 +150,7 @@ class PlayListsPresenter( fun onDeletePlayListDialogConfirmed(playLists: Collection) { playListsInteractor.deletePlayLists(playLists) .subscribe( - { viewState.showPlayListsDeleteSuccess(playLists) }, + { onDeletePlaylistsSuccess(playLists) }, viewState::showDeletePlayListError ) } @@ -194,6 +194,13 @@ class PlayListsPresenter( fun getSearchText() = searchText + private fun onDeletePlaylistsSuccess(playLists: Collection) { + viewState.showPlayListsDeleteSuccess(playLists) + if (selectedPlaylists.isNotEmpty()) { + closeSelectionMode() + } + } + private fun sharePlaylistsCompositions(playlists: List) { playListsInteractor.getCompositionsInPlaylists(playlists) .mapError(::ReceiveCompositionsForSendException) diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/folders/ExcludedFoldersPresenter.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/folders/ExcludedFoldersPresenter.kt index b379c180f..6ced97bd2 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/folders/ExcludedFoldersPresenter.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/folders/ExcludedFoldersPresenter.kt @@ -23,7 +23,7 @@ class ExcludedFoldersPresenter( fun onDeleteFolderClicked(folder: IgnoredFolder) { interactor.deleteIgnoredFolder(folder) .toSingleDefault(folder) - .subscribeOnUi(this::onFolderRemoved, this::onDefaultError) + .launchOnUi(this::onFolderRemoved, viewState::showErrorMessage) } fun onRestoreRemovedFolderClicked() { @@ -31,7 +31,7 @@ class ExcludedFoldersPresenter( return } interactor.addFolderToIgnore(recentlyRemovedFolder!!) - .justSubscribe(this::onFoldersListError) + .justRunOnUi(viewState::showErrorMessage) } private fun onFolderRemoved(folder: IgnoredFolder) { @@ -41,7 +41,7 @@ class ExcludedFoldersPresenter( private fun subscribeOnIgnoredFoldersList() { interactor.getIgnoredFoldersObservable() - .subscribeOnUi(this::onFoldersListReceived, this::onFoldersListError) + .runOnUi(this::onFoldersListReceived, viewState::showErrorState) } private fun onFoldersListReceived(folders: List) { @@ -53,12 +53,4 @@ class ExcludedFoldersPresenter( } } - private fun onFoldersListError(throwable: Throwable) { - viewState.showErrorState(errorParser.parseError(throwable)) - } - - private fun onDefaultError(throwable: Throwable) { - viewState.showErrorMessage(errorParser.parseError(throwable)) - } - } \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/folders/ExcludedFoldersView.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/folders/ExcludedFoldersView.kt index 6a8725457..55cfc4b34 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/folders/ExcludedFoldersView.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/folders/ExcludedFoldersView.kt @@ -8,8 +8,6 @@ import moxy.viewstate.strategy.StateStrategyType import moxy.viewstate.strategy.alias.AddToEndSingle import moxy.viewstate.strategy.alias.OneExecution -private const val LIST_STATE = "list_state" - interface ExcludedFoldersView : MvpView { @StateStrategyType(value = AddToEndSingleTagStrategy::class, tag = LIST_STATE) @@ -30,4 +28,8 @@ interface ExcludedFoldersView : MvpView { @OneExecution fun showErrorMessage(errorCommand: ErrorCommand) + private companion object { + const val LIST_STATE = "list_state" + } + } \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/library/LibrarySettingsFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/library/LibrarySettingsFragment.kt index 7e9234ba0..7d3f88ab8 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/library/LibrarySettingsFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/settings/library/LibrarySettingsFragment.kt @@ -101,7 +101,7 @@ class LibrarySettingsFragment : MvpAppCompatFragment(), showNumberPickerDialog( requireContext(), 0, - 60, + 120, currentValue / 1000L ) { value -> presenter.onAudioFileMinDurationMillisPicked(value * 1000L) } } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/AndroidUtils.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/AndroidUtils.kt index 4e71b117b..698a00e84 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/AndroidUtils.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/AndroidUtils.kt @@ -4,8 +4,12 @@ import android.annotation.SuppressLint import android.app.Activity import android.app.AlertDialog import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.content.ActivityNotFoundException +import android.content.ComponentName import android.content.Context import android.content.Intent +import android.content.res.Resources import android.graphics.Color import android.net.Uri import android.os.Build @@ -16,16 +20,24 @@ import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.widget.LinearLayout +import android.widget.RemoteViews import android.widget.TextView +import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher import androidx.annotation.AttrRes +import androidx.annotation.ColorRes import androidx.annotation.DimenRes import androidx.annotation.DrawableRes +import androidx.annotation.IntegerRes import androidx.annotation.MenuRes import androidx.annotation.RequiresApi +import androidx.annotation.StringRes import androidx.appcompat.view.SupportMenuInflater import androidx.appcompat.view.menu.MenuBuilder import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.RecyclerView import java.io.Serializable fun Context.getDimensionPixelSize(@DimenRes resId: Int): Int { @@ -36,6 +48,28 @@ fun Context.colorFromAttr(@AttrRes attr: Int) = AndroidUtils.getColorFromAttr(th fun Context.attrColor(@AttrRes attr: Int) = AndroidUtils.getColorFromAttr(this, attr) +val Fragment.args get() = arguments!! + +fun Fragment.attrColor(@AttrRes attr: Int) = context!!.attrColor(attr) + +fun Fragment.getDimensionPixelSize(@DimenRes resId: Int): Int { + return resources.getDimensionPixelSize(resId) +} + +val RecyclerView.ViewHolder.context: Context get() = itemView.context + +val RecyclerView.ViewHolder.resources: Resources get() = itemView.resources + +fun RecyclerView.ViewHolder.getString(@StringRes id: Int) = context.getString(id) + +fun RecyclerView.ViewHolder.getString(@StringRes id: Int, vararg format: Any): String { + return context.getString(id, *format) +} + +fun RecyclerView.ViewHolder.getColor(@ColorRes id: Int) = ContextCompat.getColor(context, id) + +fun RecyclerView.ViewHolder.getInteger(@IntegerRes id: Int) = this.resources.getInteger(id) + fun startAppSettings(activity: Activity) { val intent = Intent() intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS @@ -99,7 +133,7 @@ inline fun Bundle.getSerializableExtra(key: String): fun getMenuItems( context: Context, @MenuRes menuRes: Int, - menuModifier: (MenuItem) -> Unit + menuModifier: (MenuItem) -> Unit, ): List { val menu = MenuBuilder(context) SupportMenuInflater(context).inflate(menuRes, menu) @@ -125,6 +159,20 @@ fun TextView.setDrawableStart(@DrawableRes id: Int, @DimenRes sizeRes: Int) { } } +fun AppWidgetManager.safeUpdateAppWidget(provider: ComponentName, views: RemoteViews) { + try { + updateAppWidget(provider, views) + } catch (ignored: Exception) {} +} + +fun ActivityResultLauncher.safeLaunch(context: Context, input: I) { + try { + launch(input) + } catch (e: ActivityNotFoundException) { + Toast.makeText(context, "App to launch not found", Toast.LENGTH_SHORT).show() + } +} + @Suppress("unused") fun showSystemColors(context: Context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/RepeatListener.java b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/RepeatListener.java index 67a7a8194..c682c9d3c 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/RepeatListener.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/RepeatListener.java @@ -7,7 +7,7 @@ import android.view.View; import android.view.View.OnTouchListener; -//support levels? +//support levels - just pass callCount to action listener public class RepeatListener implements OnTouchListener { private final static int TOUCH_OFFSET = 20; @@ -23,7 +23,7 @@ public class RepeatListener implements OnTouchListener { private final Rect touchHoldRect = new Rect(); private View touchedView; - private boolean calledAtLeastOnce = false; + private boolean calledAtLeastOnce = false;//can it be replaced with callCount? private short callCount = 0; diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/dialogs/ProgressDialogFragment.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/dialogs/ProgressDialogFragment.kt index 6bb9875fc..3dea9a94b 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/dialogs/ProgressDialogFragment.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/dialogs/ProgressDialogFragment.kt @@ -14,19 +14,23 @@ import com.github.anrimian.musicplayer.ui.common.format.indeterminate import com.github.anrimian.musicplayer.ui.common.format.setExtProgress import com.google.android.material.progressindicator.CircularProgressIndicator -fun newProgressDialogFragment(message: String?) = ProgressDialogFragment().apply { - arguments = Bundle().apply { - putString(Constants.Tags.MESSAGE_ARG, message) - } -} +class ProgressDialogFragment : DialogFragment() { -fun newProgressDialogFragment(@StringRes messageResId: Int) = ProgressDialogFragment().apply { - arguments = Bundle().apply { - putInt(Constants.Tags.MESSAGE_RES_ARG, messageResId) - } -} + companion object { -class ProgressDialogFragment : DialogFragment() { + fun newInstance(message: String?) = ProgressDialogFragment().apply { + arguments = Bundle().apply { + putString(Constants.Arguments.MESSAGE_ARG, message) + } + } + + fun newInstance(@StringRes messageResId: Int) = ProgressDialogFragment().apply { + arguments = Bundle().apply { + putInt(Constants.Arguments.MESSAGE_RES_ARG, messageResId) + } + } + + } private lateinit var progressBar: CircularProgressIndicator private lateinit var tvProgress: TextView @@ -60,7 +64,7 @@ class ProgressDialogFragment : DialogFragment() { fun setMessage(message: String?) { tvProgress.text = message - requireArguments().putString(Constants.Tags.MESSAGE_ARG, message) + requireArguments().putString(Constants.Arguments.MESSAGE_ARG, message) } fun setIndeterminate(indeterminate: Boolean) { @@ -77,13 +81,13 @@ class ProgressDialogFragment : DialogFragment() { private fun getMessage(): String? { val args = requireArguments() - val message = args.getString(Constants.Tags.MESSAGE_ARG) + val message = args.getString(Constants.Arguments.MESSAGE_ARG) return if (message == null) { - val resId = args.getInt(Constants.Tags.MESSAGE_RES_ARG) + val resId = args.getInt(Constants.Arguments.MESSAGE_RES_ARG) if (resId == 0) { null } else { - getString(args.getInt(Constants.Tags.MESSAGE_RES_ARG)) + getString(args.getInt(Constants.Arguments.MESSAGE_RES_ARG)) } } else { message diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/fragments/FragmentUtils.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/fragments/FragmentUtils.kt index 85c89fb32..bc0e67214 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/fragments/FragmentUtils.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/fragments/FragmentUtils.kt @@ -1,8 +1,21 @@ package com.github.anrimian.musicplayer.ui.utils.fragments import androidx.fragment.app.DialogFragment +import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager +fun DialogFragment.safeShow( + parentFragment: Fragment, + tag: String? = null +) { + try { + //we don't have showAllowingStateLoss, so just consume error + //https://issuetracker.google.com/issues/37133130 + //Fragment.getChildFragmentManager() also can throw IllegalStateException, consume too + show(parentFragment.childFragmentManager, tag) + } catch (ignored: IllegalStateException) {} +} + fun DialogFragment.safeShow( fragmentManager: FragmentManager, tag: String? = null diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/progress_bar/ProgressView.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/progress_bar/ProgressView.kt index d11575276..d71c57f74 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/progress_bar/ProgressView.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/progress_bar/ProgressView.kt @@ -10,21 +10,16 @@ import android.util.AttributeSet import android.view.View import android.view.animation.AccelerateInterpolator import android.view.animation.DecelerateInterpolator +import android.view.animation.LinearInterpolator import androidx.annotation.DrawableRes +import androidx.core.animation.addListener +import androidx.core.animation.doOnEnd import androidx.core.content.ContextCompat import com.github.anrimian.musicplayer.R import com.github.anrimian.musicplayer.ui.utils.colorFromAttr import kotlin.math.min -//TODO (?) change design, draw circular progress bar in cover. -// but where to draw download/upload icon? - -//TODO check redraw engine, consider copying circular progress indicator -//TODO short blinking (cloud icon after start) -//TODO close animation is too fast or just not works -//TODO when state is translucent overlap is visible -// A: just set different color to corrupted composition -//based on https://github.com/2hamed/ProgressCircula/blob/master/progresscircula/src/main/java/com/hmomeni/progresscircula/ProgressCircula.kt +//short blinking (cloud icon after start) - reproduce class ProgressView( context: Context, attributeSet: AttributeSet? = null, @@ -35,31 +30,31 @@ class ProgressView( context: Context, attributeSet: AttributeSet? = null ) : this(context, attributeSet, 0) { - speed = 0.5f iconTint = context.colorFromAttr(android.R.attr.textColorPrimaryInverse) } + private val progressBarPadding = 2f + private val progressStrokeWidth = 4f + private val intermediateSweepAngle = 6f + private val iconPaddingExtra = 1 + private val strokeSize = 2f + + private val progressRect = RectF() - private var progressBarPadding = 2f - private val intermediateSweepAngle = 6f - private var sweepAngle = 0f - private var sweepStep = 4 private var startAngle = 0f - private var speed = 4f + private var sweepAngle = 0f private var bgRadius = 0f private var centerX = 0f private var centerY = 0f - private var progressStrokeWidth = 3f - private var progress = -1 private var indeterminate = false private var iconDrawable: Drawable? = null - private var iconPadding = 10//can be calculated + private var iconPadding = 0 private var iconTint = 0 private var scale = 0f @@ -72,8 +67,7 @@ class ProgressView( isAntiAlias = true } - private val cornerSize = 2f - private val cornerPaint = Paint().apply { + private val strokePaint = Paint().apply { color = context.colorFromAttr(R.attr.listItemBackground) } @@ -81,6 +75,8 @@ class ProgressView( color = context.colorFromAttr(R.attr.colorAccent) } + private val invalidateAnimator = createInvalidateAnimator() + private var sweepAngleAnimator: ValueAnimator? = null private var visibilityAnimator: ValueAnimator? = null override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { @@ -90,7 +86,9 @@ class ProgressView( bgRadius = min(width, height)/2 - val progressBarRadius = bgRadius - paddingBottom - progressStrokeWidth/2 - progressBarPadding - cornerSize + val pbCenter = paddingBottom + progressStrokeWidth/2 + progressBarPadding + strokeSize + val progressBarRadius = bgRadius - pbCenter + iconPadding = (pbCenter + progressStrokeWidth/2).toInt() + iconPaddingExtra centerX = width/2 centerY = height/2 @@ -115,52 +113,33 @@ class ProgressView( canvas.scale(scale, scale, centerX, centerY) - if (iconDrawable != null || isProgressActive()) { - canvas.drawCircle(centerX, centerX, bgRadius, cornerPaint) - canvas.drawCircle(centerX, centerX, bgRadius - cornerSize, bgPaint) - } + canvas.drawCircle(centerX, centerX, bgRadius, strokePaint) + canvas.drawCircle(centerX, centerX, bgRadius - strokeSize, bgPaint) iconDrawable?.draw(canvas) if (isProgressActive()) { - startAngle += sweepStep * speed - if (startAngle > 360f) { - startAngle = 0f - } - - sweepAngle = if (indeterminate) { - intermediateSweepAngle - } else { - (progress / 100f * 360).coerceAtLeast(intermediateSweepAngle) - } - canvas.drawArc(progressRect, startAngle, sweepAngle, false, progressPaint) - postInvalidate() } - } fun setProgress(progress: Int) { - this.progress = progress - this.indeterminate = false - invalidate() - startVisibilityAnimation() + updateProgress(progress, false) + setProgressInvalidation(true) } fun setIndeterminate(indeterminate: Boolean) { - this.indeterminate = indeterminate - invalidate() - startVisibilityAnimation() + updateProgress(progress, indeterminate) + setProgressInvalidation(true) } fun clearProgress() { - this.indeterminate = false - progress = -1 - startVisibilityAnimation() + updateProgress(-1, false) + setProgressInvalidation(false) } fun setIconResource(@DrawableRes resId: Int) { - iconDrawable = ContextCompat.getDrawable(context, resId) + val iconDrawable = ContextCompat.getDrawable(context, resId) iconDrawable?.run { setBounds( iconPadding, @@ -170,26 +149,32 @@ class ProgressView( ) setTint(iconTint) } + setIconDrawable(iconDrawable) + } + + fun setIconDrawable(drawable: Drawable?) { + iconDrawable = drawable invalidate() - startVisibilityAnimation() } fun clearIcon() { iconDrawable = null invalidate() - startVisibilityAnimation() } - private fun isProgressActive() = indeterminate || progress >= 0 - - private fun startVisibilityAnimation() { - val targetScale = if (isProgressActive()) 1f else 0f - if (iconDrawable != null) { - scale = 1f - invalidate() + fun setVisible( + isVisible: Boolean, + animate: Boolean, + clearIcon: Boolean = false, + clearProgress: Boolean = false, + ) { + val targetScale = if (isVisible) 1f else 0f + if (targetScale == scale) { return } - if (targetScale == scale) { + if (!animate) { + scale = targetScale + invalidate() return } visibilityAnimator?.cancel() @@ -198,10 +183,67 @@ class ProgressView( scale = animator.animatedValue as Float invalidate() } - interpolator = if (targetScale == 1f) DecelerateInterpolator() else AccelerateInterpolator() - duration = 300 + addListener { + doOnEnd { + if (clearIcon) { + clearIcon() + } + if (clearProgress) { + clearProgress() + } + } + } + interpolator = if (isVisible) DecelerateInterpolator() else AccelerateInterpolator() + duration = if (isVisible) 300 else 150 start() } } + private fun isProgressActive() = indeterminate || progress >= 0 + + private fun setProgressInvalidation(isStarted: Boolean) { + if (isStarted) { + if (!invalidateAnimator.isRunning) { + invalidateAnimator.start() + } + } else { + invalidateAnimator.cancel() + } + } + + private fun updateProgress(progress: Int, indeterminate: Boolean) { + this.indeterminate = indeterminate + this.progress = progress + + val newSweepAngle = if (indeterminate) { + intermediateSweepAngle + } else { + (progress / 100f * 360).coerceAtLeast(intermediateSweepAngle) + } + if (sweepAngle != newSweepAngle) { + sweepAngleAnimator?.cancel() + val anim = ValueAnimator.ofFloat(sweepAngle, newSweepAngle) + anim.duration = 900 + anim.addUpdateListener { a -> + sweepAngle = a.animatedValue as Float + } + anim.interpolator = LinearInterpolator() + anim.start() + sweepAngleAnimator = anim + } + } + + private fun createInvalidateAnimator(): ValueAnimator { + val anim = ValueAnimator.ofFloat(0f, 360f) + anim.duration = 2500 + anim.repeatCount = ValueAnimator.INFINITE + anim.repeatMode = ValueAnimator.RESTART + anim.addUpdateListener { a -> + startAngle = a.animatedValue as Float + invalidate() + } + anim.interpolator = LinearInterpolator() + return anim + } + } \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/progress_state/ProgressStateView.java b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/progress_state/ProgressStateView.java index 46868f49d..321815298 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/progress_state/ProgressStateView.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/progress_state/ProgressStateView.java @@ -209,7 +209,7 @@ private void showProgress() { root.setVisibility(VISIBLE); root.setClickable(true); progressBar.setIndeterminate(true); - animateVisibility(progressBar, VISIBLE); + progressBar.setVisibility(VISIBLE); tvMessage.setVisibility(GONE); btnTryAgain.setVisibility(GONE); ivEmpty.setVisibility(GONE); diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/recycler_view/touch_helper/short_swipe/ShortSwipeCallback.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/recycler_view/touch_helper/short_swipe/ShortSwipeCallback.kt index 2357f25f5..047cb666b 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/recycler_view/touch_helper/short_swipe/ShortSwipeCallback.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/recycler_view/touch_helper/short_swipe/ShortSwipeCallback.kt @@ -14,7 +14,11 @@ import androidx.annotation.StringRes import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import com.github.anrimian.musicplayer.R -import com.github.anrimian.musicplayer.ui.utils.* +import com.github.anrimian.musicplayer.ui.utils.AndroidUtils +import com.github.anrimian.musicplayer.ui.utils.colorFromAttr +import com.github.anrimian.musicplayer.ui.utils.createStaticLayout +import com.github.anrimian.musicplayer.ui.utils.getDimensionPixelSize +import com.github.anrimian.musicplayer.ui.utils.getDrawableCompat import com.github.anrimian.musicplayer.ui.utils.views.recycler_view.short_swipe.SwipeListener import kotlin.math.abs import kotlin.math.max @@ -137,7 +141,7 @@ class ShortSwipeCallback( val swipeEffectAnimator = this.swipeEffectAnimator if (swipeEffectAnimator?.isRunning == true) { start = swipeEffectAnimator.animatedValue as Float - animationDuration = swipeEffectAnimator.currentPlayTime + animationDuration = swipeEffectAnimator.currentPlayTime.coerceAtLeast(0L) swipeEffectAnimator.cancel() } val end = if (isInfoVisible) APPEAR_ANIM_SCALE_END else APPEAR_ANIM_SCALE_START diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/seek_bar/SeekBarViewWrapper.java b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/seek_bar/SeekBarViewWrapper.java index 69bffec96..a7b9f8923 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/seek_bar/SeekBarViewWrapper.java +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/utils/views/seek_bar/SeekBarViewWrapper.java @@ -15,6 +15,7 @@ public class SeekBarViewWrapper { private boolean isOnTouch; private int progress; + private int max; public SeekBarViewWrapper(SeekBar seekBar) { this.seekBar = seekBar; @@ -52,21 +53,23 @@ public void setProgress(long progress) { } } - public void setProgress(int progress) { + public void setProgress(long progress, long max) { + int newMax = (int) max; + if (this.max != newMax) { + this.max = newMax; + seekBar.setMax(newMax); + } if (!isOnTouch) { - this.progress = progress; + this.progress = (int) progress; seekBar.setProgress(this.progress); } } - public void setMax(long max) { - seekBar.setMax((int) max); - seekBar.setProgress(progress); - } - - public void setMax(int max) { - seekBar.setMax(max); - seekBar.setProgress(progress); + public void setProgress(int progress) { + if (!isOnTouch) { + this.progress = progress; + seekBar.setProgress(this.progress); + } } public void setOnSeekStartListener(OnSeekStartListener onSeekStartListener) { diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/WidgetActionsReceiver.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/WidgetActionsReceiver.kt index 61338bfd2..9a74d7be8 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/WidgetActionsReceiver.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/WidgetActionsReceiver.kt @@ -33,9 +33,7 @@ class WidgetActionsReceiver : BroadcastReceiver() { AppAndroidUtils.playPause(context, appComponent.playerInteractor()) } Constants.Actions.CHANGE_REPEAT_MODE -> interactor.changeRepeatMode() - Constants.Actions.CHANGE_SHUFFLE_NODE -> { - interactor.setRandomPlayingEnabled(!interactor.isRandomPlayingEnabled()) - } + Constants.Actions.CHANGE_SHUFFLE_NODE -> interactor.changeRandomMode() Constants.Actions.REWIND -> interactor.fastSeekBackward() Constants.Actions.FAST_FORWARD -> interactor.fastSeekForward() } diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/WidgetUpdater.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/WidgetUpdater.kt index 991d1817a..c2ee8dd42 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/WidgetUpdater.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/WidgetUpdater.kt @@ -9,15 +9,18 @@ import com.github.anrimian.musicplayer.domain.interactors.settings.DisplaySettin import com.github.anrimian.musicplayer.domain.models.play_queue.PlayQueueEvent import com.github.anrimian.musicplayer.domain.models.player.PlayerState import com.github.anrimian.musicplayer.domain.models.utils.CompositionHelper +import com.github.anrimian.musicplayer.domain.utils.rx.RxUtils import com.github.anrimian.musicplayer.ui.common.format.FormatUtils import com.github.anrimian.musicplayer.ui.common.format.getRemoteViewPlayerState import com.github.anrimian.musicplayer.ui.common.theme.ThemeController +import com.github.anrimian.musicplayer.ui.utils.safeUpdateAppWidget import com.github.anrimian.musicplayer.ui.widgets.binders.MediumWidgetBinder import com.github.anrimian.musicplayer.ui.widgets.binders.SmallExtWidgetBinder import com.github.anrimian.musicplayer.ui.widgets.binders.SmallWidgetBinder import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Scheduler import io.reactivex.rxjava3.disposables.CompositeDisposable +import io.reactivex.rxjava3.subjects.BehaviorSubject import java.util.concurrent.TimeUnit @@ -35,25 +38,42 @@ class WidgetUpdater( MediumWidgetBinder() ) + private val widgetActiveSubject = BehaviorSubject.create() + + private val disposable = CompositeDisposable() private val updateDisposable = CompositeDisposable() fun start() { - if (updateDisposable.size() > 0) { - return + disposable.add(RxUtils.withDefaultValue(widgetActiveSubject) { isAnyWidgetActive() } + .distinctUntilChanged() + .subscribe(this::onWidgetsActiveStateReceived)) + } + + fun onAnyWidgetEnabledStateChanged() { + widgetActiveSubject.onNext(isAnyWidgetActive()) + } + + private fun onWidgetsActiveStateReceived(isActive: Boolean) { + if (isActive) { + if (updateDisposable.size() > 0) { + return + } + updateDisposable.add(Observable.combineLatest( + musicPlayerInteractor.getCurrentQueueItemObservable(), + musicPlayerInteractor.getPlayQueueSizeObservable(), + musicPlayerInteractor.getIsPlayingStateObservable(), + musicPlayerInteractor.getPlayerStateObservable(), + displaySettingsInteractor.getCoversEnabledObservable(), + musicPlayerInteractor.getRepeatModeObservable(), + musicPlayerInteractor.getRandomPlayingObservable(), + themeController.getRoundCoversObservable(), + this::applyWidgetState + ).observeOn(uiScheduler) + .retryWithDelay(10, 10, TimeUnit.SECONDS) + .subscribe(this::onWidgetStateChanged)) + } else { + updateDisposable.clear() } - updateDisposable.add(Observable.combineLatest( - musicPlayerInteractor.getCurrentQueueItemObservable(), - musicPlayerInteractor.getPlayQueueSizeObservable(), - musicPlayerInteractor.getIsPlayingStateObservable(), - musicPlayerInteractor.getPlayerStateObservable(), - displaySettingsInteractor.getCoversEnabledObservable(), - musicPlayerInteractor.getRepeatModeObservable(), - musicPlayerInteractor.getRandomPlayingObservable(), - themeController.getRoundCoversObservable(), - this::applyWidgetState - ).observeOn(uiScheduler) - .retryWithDelay(10, 10, TimeUnit.SECONDS) - .subscribe(this::onWidgetStateChanged)) } private fun applyWidgetState( @@ -75,14 +95,13 @@ class WidgetUpdater( var isFileExists = false val item = playQueueEvent.playQueueItem if (item != null) { - val composition = item.composition - compositionName = CompositionHelper.formatCompositionName(composition) - compositionAuthor = FormatUtils.formatCompositionAuthor(composition, context).toString() - compositionId = composition.id - compositionUpdateTime = composition.dateModified.time - coverModifyTime = composition.coverModifyTime.time - compositionSize = composition.size - isFileExists = composition.isFileExists + compositionName = CompositionHelper.formatCompositionName(item) + compositionAuthor = FormatUtils.formatCompositionAuthor(item, context).toString() + compositionId = item.id + compositionUpdateTime = item.dateModified.time + coverModifyTime = item.coverModifyTime.time + compositionSize = item.size + isFileExists = item.isFileExists } val remotePlayerState = getRemoteViewPlayerState(isPlaying, playerState) @@ -110,7 +129,7 @@ class WidgetUpdater( } val appWidgetManager = AppWidgetManager.getInstance(context) widgetBinders.forEach { widgetBinder -> - appWidgetManager.updateAppWidget( + appWidgetManager.safeUpdateAppWidget( ComponentName(context, widgetBinder.getWidgetProviderClass()), widgetBinder.getBoundRemoteViews( context, @@ -120,4 +139,14 @@ class WidgetUpdater( } } + private fun isAnyWidgetActive(): Boolean { + var count = 0 + for (widgetBinder in widgetBinders) { + val appWidgetManager = AppWidgetManager.getInstance(context) + val cn = ComponentName(context, widgetBinder.getWidgetProviderClass()) + count += appWidgetManager.getAppWidgetIds(cn).size + } + return count > 0 + } + } \ No newline at end of file diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/menu/WidgetMenuActivity.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/menu/WidgetMenuActivity.kt index b37f80c4c..19779a424 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/menu/WidgetMenuActivity.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/menu/WidgetMenuActivity.kt @@ -1,6 +1,5 @@ package com.github.anrimian.musicplayer.ui.widgets.menu -import android.content.Context import android.content.Intent import android.os.Bundle import android.view.MenuItem @@ -14,6 +13,7 @@ import com.github.anrimian.musicplayer.databinding.PartialWidgetMenuHeaderBindin import com.github.anrimian.musicplayer.di.Components import com.github.anrimian.musicplayer.domain.models.composition.Composition import com.github.anrimian.musicplayer.domain.models.composition.DeletedComposition +import com.github.anrimian.musicplayer.ui.common.activity.BaseMvpAppCompatActivity import com.github.anrimian.musicplayer.ui.common.dialogs.shareComposition import com.github.anrimian.musicplayer.ui.common.dialogs.showConfirmDeleteDialog import com.github.anrimian.musicplayer.ui.common.error.ErrorCommand @@ -25,10 +25,9 @@ import com.github.anrimian.musicplayer.ui.editor.common.ErrorHandler import com.github.anrimian.musicplayer.ui.utils.AndroidUtils import com.github.anrimian.musicplayer.ui.utils.dialogs.menu.MenuAdapter import com.github.anrimian.musicplayer.ui.utils.views.recycler_view.SingleItemAdapter -import moxy.MvpAppCompatActivity import moxy.ktx.moxyPresenter -class WidgetMenuActivity: MvpAppCompatActivity(), WidgetMenuView { +class WidgetMenuActivity: BaseMvpAppCompatActivity(), WidgetMenuView { private val presenter by moxyPresenter { Components.getAppComponent().widgetMenuPresenter() } @@ -66,12 +65,6 @@ class WidgetMenuActivity: MvpAppCompatActivity(), WidgetMenuView { } } - override fun attachBaseContext(base: Context) { - super.attachBaseContext( - Components.getAppComponent().localeController().dispatchAttachBaseContext(base) - ) - } - override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) applyCompositionId(intent) diff --git a/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/providers/BaseWidgetProvider.kt b/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/providers/BaseWidgetProvider.kt index bc475d480..fcd6cb14c 100644 --- a/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/providers/BaseWidgetProvider.kt +++ b/app/src/main/java/com/github/anrimian/musicplayer/ui/widgets/providers/BaseWidgetProvider.kt @@ -5,11 +5,23 @@ import android.appwidget.AppWidgetProvider import android.content.ComponentName import android.content.Context import android.content.Intent +import com.github.anrimian.musicplayer.di.Components import com.github.anrimian.musicplayer.ui.widgets.WidgetDataHolder import com.github.anrimian.musicplayer.ui.widgets.binders.WidgetBinder abstract class BaseWidgetProvider : AppWidgetProvider() { + override fun onEnabled(context: Context) { + super.onEnabled(context) + Components.checkInitialization(context.applicationContext) + Components.getAppComponent().widgetUpdater().onAnyWidgetEnabledStateChanged() + } + + override fun onDisabled(context: Context?) { + super.onDisabled(context) + Components.getAppComponent().widgetUpdater().onAnyWidgetEnabledStateChanged() + } + override fun onReceive(context: Context, intent: Intent) { super.onReceive(context, intent) diff --git a/app/src/main/res/drawable/bg_accent_text_cursor.xml b/app/src/main/res/drawable/bg_accent_text_cursor.xml new file mode 100644 index 000000000..0d4b9e009 --- /dev/null +++ b/app/src/main/res/drawable/bg_accent_text_cursor.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_folder_up.xml b/app/src/main/res/drawable/ic_folder_up.xml new file mode 100644 index 000000000..c20667d1c --- /dev/null +++ b/app/src/main/res/drawable/ic_folder_up.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml deleted file mode 100644 index 5398f4b7d..000000000 --- a/app/src/main/res/drawable/ic_menu.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout-large-land/fragment_drawer.xml b/app/src/main/res/layout-large-land/fragment_drawer.xml index ab5cc0407..39cf696a6 100644 --- a/app/src/main/res/layout-large-land/fragment_drawer.xml +++ b/app/src/main/res/layout-large-land/fragment_drawer.xml @@ -25,11 +25,12 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> - diff --git a/app/src/main/res/layout/dialog_common_input_simple.xml b/app/src/main/res/layout/dialog_common_input_simple.xml index 304303bea..ed36e3b9d 100644 --- a/app/src/main/res/layout/dialog_common_input_simple.xml +++ b/app/src/main/res/layout/dialog_common_input_simple.xml @@ -1,23 +1,80 @@ - + android:layout_height="wrap_content"> - \ No newline at end of file + + +