├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── core-ui ├── .gitignore ├── build.gradle.kts └── src │ ├── androidMain │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── coreui │ │ ├── SoulSearchingContext.android.kt │ │ ├── ext │ │ └── ModifierExt.android.kt │ │ ├── feedbackmanager │ │ ├── FeedbackPopUpAndroidManager.kt │ │ └── FeedbackPopUpScaffold.android.kt │ │ ├── list │ │ ├── SoulHorizontalScrollBar.android.kt │ │ ├── SoulVerticalGridScrollBar.android.kt │ │ └── SoulVerticalScrollBar.android.kt │ │ ├── navigation │ │ └── SoulBackHandler.android.kt │ │ └── utils │ │ └── WindowSize.android.kt │ ├── commonMain │ ├── composeResources │ │ └── drawable │ │ │ └── app_icon.png │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── coreui │ │ ├── ScreenOrientation.kt │ │ ├── SoulCircularProgressIndicator.kt │ │ ├── SoulPlayerSpacer.kt │ │ ├── SoulSearchingContext.kt │ │ ├── UiConstants.kt │ │ ├── bottomsheet │ │ ├── SoulBottomSheet.kt │ │ ├── SoulBottomSheetHandler.kt │ │ └── SoulDrawer.kt │ │ ├── button │ │ ├── SoulButton.kt │ │ ├── SoulButtonDefaults.kt │ │ ├── SoulCheckBox.kt │ │ ├── SoulIconButton.kt │ │ └── SoulSegmentedButton.kt │ │ ├── dialog │ │ ├── SoulAlertDialog.kt │ │ └── SoulDialog.kt │ │ ├── ext │ │ ├── ColorExt.kt │ │ ├── Conversions.kt │ │ ├── FloatExt.kt │ │ └── ModifierExt.kt │ │ ├── feedbackmanager │ │ ├── FeedbackPopUpManager.kt │ │ └── FeedbackPopUpScaffold.kt │ │ ├── image │ │ ├── SoulBitmapImage.kt │ │ ├── SoulIcon.kt │ │ └── SoulSearchingLogo.kt │ │ ├── list │ │ ├── LazyColumnCompat.kt │ │ ├── LazyRowCompat.kt │ │ ├── LazyVerticalGridCompat.kt │ │ ├── SoulHorizontalScrollBar.kt │ │ ├── SoulVerticalGridScrollBar.kt │ │ └── SoulVerticalScrollBar.kt │ │ ├── loading │ │ ├── LoadingManager.kt │ │ └── LoadingScaffold.kt │ │ ├── menu │ │ ├── SoulMenuAction.kt │ │ ├── SoulMenuBody.kt │ │ ├── SoulMenuElement.kt │ │ ├── SoulMenuExpand.kt │ │ └── SoulMenuSwitch.kt │ │ ├── multiselection │ │ ├── MultiSelectionManagerImpl.kt │ │ ├── MultiSelectionScaffold.kt │ │ ├── MultiSelectionState.kt │ │ └── composable │ │ │ └── SoulSelectedIcon.kt │ │ ├── navigation │ │ ├── SoulBackHandler.kt │ │ └── SoulPageIndicator.kt │ │ ├── screen │ │ ├── SoulErrorScreen.kt │ │ ├── SoulLoadingScreen.kt │ │ ├── SoulScreen.kt │ │ └── SoulTemplateScreen.kt │ │ ├── slider │ │ └── SoulSlider.kt │ │ ├── strings │ │ ├── EnStrings.kt │ │ ├── FrStrings.kt │ │ └── strings.kt │ │ ├── textfield │ │ ├── SoulDropdownTextField.kt │ │ ├── SoulTextField.kt │ │ ├── SoulTextFieldColors.kt │ │ ├── SoulTextFieldDefaults.kt │ │ ├── SoulTextFieldHolder.kt │ │ ├── SoulTextFieldLeadingIconSpec.kt │ │ ├── SoulTextFieldStyle.kt │ │ └── SoulTextFieldViewHolder.kt │ │ ├── theme │ │ └── color │ │ │ ├── AnimatedColorPaletteBuilder.kt │ │ │ ├── Color.kt │ │ │ ├── ColorThemeType.kt │ │ │ ├── DynamicColorThemeBuilder.kt │ │ │ ├── SoulSearchingColorTheme.kt │ │ │ ├── SoulSearchingDarkLightTheme.kt │ │ │ ├── SoulSearchingPalette.kt │ │ │ └── SoulSearchingTheme.kt │ │ ├── topbar │ │ ├── SoulTopBar.kt │ │ └── TopBarActionSpec.kt │ │ └── utils │ │ ├── ColorPaletteUtils.kt │ │ ├── LaunchInit.kt │ │ ├── PlayerUtils.kt │ │ ├── SystemBarsUtils.kt │ │ └── WindowSize.kt │ └── desktopMain │ └── kotlin │ └── com │ └── github │ └── enteraname74 │ └── soulsearching │ └── coreui │ ├── SoulSearchingContext.desktop.kt │ ├── ext │ └── ModifierExt.desktop.kt │ ├── feedbackmanager │ ├── FeedbackPopUpDesktopManager.kt │ └── FeedbackPopUpScaffold.desktop.kt │ ├── list │ ├── SoulHorizontalScrollBar.desktop.kt │ ├── SoulVerticalGridScrollBar.desktop.kt │ └── SoulVerticalScrollBar.desktop.kt │ ├── navigation │ └── SoulBackHandler.desktop.kt │ └── utils │ └── WindowSize.desktop.kt ├── desktopApp ├── .gitignore ├── README.md ├── build.gradle.kts ├── io.github.enteraname74.soulsearching.desktop ├── io.github.enteraname74.soulsearching.yml ├── proguard-rules.pro └── src │ └── main │ ├── composeResources │ └── drawable │ │ ├── app_icon.png │ │ └── app_icon_bg.png │ └── kotlin │ └── Main.kt ├── domain ├── .gitignore ├── build.gradle.kts └── src │ ├── commonMain │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── domain │ │ ├── di │ │ └── DomainModule.kt │ │ ├── ext │ │ ├── ListExt.kt │ │ └── MusicExt.kt │ │ ├── model │ │ ├── Album.kt │ │ ├── AlbumArtist.kt │ │ ├── AlbumWithArtist.kt │ │ ├── AlbumWithMusics.kt │ │ ├── Artist.kt │ │ ├── ArtistWithMusics.kt │ │ ├── Cover.kt │ │ ├── FlowOperation.kt │ │ ├── Folder.kt │ │ ├── MonthMusicList.kt │ │ ├── MonthMusics.kt │ │ ├── Music.kt │ │ ├── MusicAlbum.kt │ │ ├── MusicArtist.kt │ │ ├── MusicFolder.kt │ │ ├── MusicFolderList.kt │ │ ├── MusicLyrics.kt │ │ ├── MusicPlaylist.kt │ │ ├── PlayerMode.kt │ │ ├── PlayerMusic.kt │ │ ├── PlayerWithMusicItem.kt │ │ ├── Playlist.kt │ │ ├── PlaylistWithMusics.kt │ │ ├── PlaylistWithMusicsNumber.kt │ │ ├── QuickAccessible.kt │ │ ├── Release.kt │ │ ├── SortDirection.kt │ │ ├── SortType.kt │ │ └── settings │ │ │ ├── SettingsFlowSystem.kt │ │ │ └── SoulSearchingSettings.kt │ │ ├── repository │ │ ├── AlbumArtistRepository.kt │ │ ├── AlbumRepository.kt │ │ ├── ArtistRepository.kt │ │ ├── CoverRepository.kt │ │ ├── FolderRepository.kt │ │ ├── LyricsRepository.kt │ │ ├── MusicAlbumRepository.kt │ │ ├── MusicArtistRepository.kt │ │ ├── MusicPlaylistRepository.kt │ │ ├── MusicRepository.kt │ │ ├── PlayerMusicRepository.kt │ │ ├── PlaylistRepository.kt │ │ └── ReleaseRepository.kt │ │ ├── usecase │ │ ├── album │ │ │ ├── DeleteAlbumIfEmptyUseCase.kt │ │ │ ├── DeleteAlbumUseCase.kt │ │ │ ├── DeleteAllAlbumsUseCase.kt │ │ │ ├── GetAlbumUseCase.kt │ │ │ ├── GetAlbumWithMusicsUseCase.kt │ │ │ ├── GetAlbumsNameFromSearchStringUseCase.kt │ │ │ ├── GetAlbumsOfArtistUseCase.kt │ │ │ ├── GetAlbumsWithMusicsOfArtistUseCase.kt │ │ │ ├── GetAllAlbumWithMusicsSortedUseCase.kt │ │ │ ├── GetAllAlbumsUseCase.kt │ │ │ ├── GetAllAlbumsWithArtistUseCase.kt │ │ │ ├── GetAllAlbumsWithMusicsFromQuickAccessUseCase.kt │ │ │ ├── GetAllAlbumsWithMusicsUseCase.kt │ │ │ ├── GetCorrespondingAlbumUseCase.kt │ │ │ ├── GetDuplicatedAlbumUseCase.kt │ │ │ ├── GetNumberOfAlbumsWithCoverIdUseCase.kt │ │ │ ├── UpdateAlbumCoverUseCase.kt │ │ │ ├── UpdateAlbumNbPlayedUseCase.kt │ │ │ ├── UpsertAlbumUseCase.kt │ │ │ └── UpsertAllAlbumsUseCase.kt │ │ ├── albumartist │ │ │ ├── GetAllAlbumArtistUseCase.kt │ │ │ ├── UpsertAlbumArtistUseCase.kt │ │ │ └── UpsertAllAlbumArtistUseCase.kt │ │ ├── artist │ │ │ ├── DeleteAllArtistsUseCase.kt │ │ │ ├── DeleteArtistIfEmptyUseCase.kt │ │ │ ├── DeleteArtistUseCase.kt │ │ │ ├── GetAllArtistWithMusicsFromQuickAccessUseCase.kt │ │ │ ├── GetAllArtistWithMusicsSortedByMostSongsUseCase.kt │ │ │ ├── GetAllArtistWithMusicsSortedUseCase.kt │ │ │ ├── GetAllArtistWithMusicsUseCase.kt │ │ │ ├── GetAllArtistsUseCase.kt │ │ │ ├── GetAllArtistsWithNameUseCase.kt │ │ │ ├── GetArtistFromNameUseCase.kt │ │ │ ├── GetArtistWithMusicsUseCase.kt │ │ │ ├── GetArtistsNameFromSearchStringUseCase.kt │ │ │ ├── GetArtistsOfMusicUseCase.kt │ │ │ ├── GetDuplicatedArtistUseCase.kt │ │ │ ├── UpdateArtistCoverUseCase.kt │ │ │ ├── UpdateArtistNbPlayedUseCase.kt │ │ │ ├── UpsertAllArtistsUseCase.kt │ │ │ └── UpsertArtistUseCase.kt │ │ ├── cover │ │ │ ├── DeleteCoverUseCase.kt │ │ │ ├── IsCoverUsedUseCase.kt │ │ │ └── UpsertImageCoverUseCase.kt │ │ ├── folder │ │ │ ├── DeleteAllFoldersUseCase.kt │ │ │ ├── DeleteFolderUseCase.kt │ │ │ ├── GetAllFoldersUseCase.kt │ │ │ ├── GetHiddenFoldersPathUseCase.kt │ │ │ ├── UpsertAllFoldersUseCase.kt │ │ │ └── UpsertFolderUseCase.kt │ │ ├── lyrics │ │ │ └── GetLyricsOfSongUseCase.kt │ │ ├── month │ │ │ ├── GetAllMonthMusicUseCase.kt │ │ │ └── GetMonthMusicListUseCase.kt │ │ ├── music │ │ │ ├── DeleteAllMusicsUseCase.kt │ │ │ ├── DeleteMusicUseCase.kt │ │ │ ├── GetAllMusicFromFolderPathUseCase.kt │ │ │ ├── GetAllMusicFromQuickAccessUseCase.kt │ │ │ ├── GetAllMusicUseCase.kt │ │ │ ├── GetAllMusicsSortedUseCase.kt │ │ │ ├── GetMusicUseCase.kt │ │ │ ├── IsMusicAlreadySavedUseCase.kt │ │ │ ├── IsMusicInFavoritePlaylistUseCase.kt │ │ │ ├── ToggleMusicFavoriteStatusUseCase.kt │ │ │ ├── UpdateAlbumOfMusicUseCase.kt │ │ │ ├── UpdateMusicNbPlayedUseCase.kt │ │ │ ├── UpsertAllMusicsUseCase.kt │ │ │ └── UpsertMusicUseCase.kt │ │ ├── musicalbum │ │ │ ├── GetAlbumIdFromMusicIdUseCase.kt │ │ │ ├── GetAllMusicAlbumUseCase.kt │ │ │ ├── UpdateMusicsAlbumUseCase.kt │ │ │ ├── UpsertAllMusicAlbumUseCase.kt │ │ │ └── UpsertMusicIntoAlbumUseCase.kt │ │ ├── musicartist │ │ │ ├── GetAllMusicArtistUseCase.kt │ │ │ ├── UpsertAllMusicArtistsUseCase.kt │ │ │ └── UpsertMusicIntoArtistUseCase.kt │ │ ├── musicfolder │ │ │ ├── GetAllMusicFolderListUseCase.kt │ │ │ └── GetMusicFolderListUseCase.kt │ │ ├── musicplaylist │ │ │ ├── DeleteMusicFromPlaylistUseCase.kt │ │ │ └── UpsertMusicIntoPlaylistUseCase.kt │ │ ├── playlist │ │ │ ├── DeleteAllPlaylistsUseCase.kt │ │ │ ├── DeletePlaylistUseCase.kt │ │ │ ├── GetAllPlaylistWithMusicsNumberFromQuickAccessUseCase.kt │ │ │ ├── GetAllPlaylistWithMusicsSortedUseCase.kt │ │ │ ├── GetAllPlaylistWithMusicsUseCase.kt │ │ │ ├── GetAllPlaylistsUseCase.kt │ │ │ ├── GetFavoritePlaylistWithMusicsUseCase.kt │ │ │ ├── GetPlaylistUseCase.kt │ │ │ ├── GetPlaylistWithMusicsUseCase.kt │ │ │ ├── GetSelectablePlaylistWithMusicsForMusicUseCase.kt │ │ │ ├── UpdatePlaylistNbPlayedUseCase.kt │ │ │ ├── UpsertAllPlaylistsUseCase.kt │ │ │ └── UpsertPlaylistUseCase.kt │ │ ├── quickaccess │ │ │ └── GetAllQuickAccessElementsUseCase.kt │ │ └── release │ │ │ ├── DeleteLatestReleaseUseCase.kt │ │ │ ├── FetchLatestReleaseUseCase.kt │ │ │ ├── GetLatestReleaseUseCase.kt │ │ │ ├── GetLatestViewedReleaseUseCase.kt │ │ │ └── SetLatestViewedReleaseUseCase.kt │ │ └── util │ │ ├── DateUtils.kt │ │ ├── LocalDatabaseVersion.kt │ │ └── serializer │ │ ├── LocalDateTimeSerializer.kt │ │ └── UUIDSerializer.kt │ └── desktopMain │ └── kotlin │ └── com │ └── github │ └── enteraname74 │ └── domain │ └── util │ └── AppEnvironment.kt ├── features ├── filemanager │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── androidMain │ │ └── kotlin │ │ │ └── com │ │ │ └── github │ │ │ └── enteraname74 │ │ │ └── soulsearching │ │ │ └── features │ │ │ └── filemanager │ │ │ ├── cover │ │ │ ├── CachedCoverManagerAndroidImpl.kt │ │ │ └── CoverFileManagerAndroidImpl.kt │ │ │ └── di │ │ │ └── FileManagerPlatformModule.android.kt │ │ ├── commonMain │ │ └── kotlin │ │ │ └── com │ │ │ └── github │ │ │ └── enteraname74 │ │ │ └── soulsearching │ │ │ └── features │ │ │ └── filemanager │ │ │ ├── cover │ │ │ ├── CachedCoverManager.kt │ │ │ ├── CoverFileManager.kt │ │ │ └── CoverRetriever.kt │ │ │ ├── di │ │ │ ├── FileManagerModule.kt │ │ │ └── FileManagerPlatformModule.kt │ │ │ ├── usecase │ │ │ ├── UpdateAlbumUseCase.kt │ │ │ ├── UpdateArtistNameOfMusicUseCase.kt │ │ │ ├── UpdateArtistUseCase.kt │ │ │ └── UpdateMusicUseCase.kt │ │ │ └── util │ │ │ └── MusicFileUpdater.kt │ │ └── desktopMain │ │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── features │ │ └── filemanager │ │ ├── cover │ │ ├── CachedCoverManagerDesktopImpl.kt │ │ └── CoverFileManagerDesktopImpl.kt │ │ └── di │ │ └── FileManagerPlatformModule.desktop.kt ├── musicmanager │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── androidMain │ │ └── kotlin │ │ │ └── com │ │ │ └── github │ │ │ └── enteraname74 │ │ │ └── soulsearching │ │ │ └── features │ │ │ └── musicmanager │ │ │ ├── di │ │ │ └── MusicManagerModule.android.kt │ │ │ └── fetching │ │ │ └── MusicFetcherAndroidImpl.kt │ │ ├── commonMain │ │ └── kotlin │ │ │ └── com │ │ │ └── github │ │ │ └── enteraname74 │ │ │ └── soulsearching │ │ │ └── features │ │ │ └── musicmanager │ │ │ ├── di │ │ │ └── MusicManagerModule.kt │ │ │ ├── domain │ │ │ ├── AlbumInformation.kt │ │ │ └── OptimizedCachedData.kt │ │ │ ├── fetching │ │ │ ├── MusicFetcher.kt │ │ │ └── SelectableMusicItem.kt │ │ │ ├── multipleartists │ │ │ ├── AddNewSongsMultipleArtistManagerImpl.kt │ │ │ ├── FetchAllMultipleArtistManagerImpl.kt │ │ │ ├── MultipleArtistManager.kt │ │ │ └── RepositoryMultipleArtistManagerImpl.kt │ │ │ └── persistence │ │ │ └── MusicPersistence.kt │ │ └── desktopMain │ │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── features │ │ └── musicmanager │ │ ├── di │ │ └── MusicManagerModule.desktop.kt │ │ └── fetching │ │ └── MusicFetcherDesktopImpl.kt ├── playback │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ ├── androidMain │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── enteraname74 │ │ │ │ └── soulsearching │ │ │ │ └── features │ │ │ │ └── playback │ │ │ │ ├── PlaybackManagerAndroidImpl.kt │ │ │ │ ├── PlayerService.kt │ │ │ │ ├── di │ │ │ │ └── PlaybackPlatformModule.android.kt │ │ │ │ ├── mediasession │ │ │ │ └── MediaSessionManager.kt │ │ │ │ ├── notification │ │ │ │ ├── impl │ │ │ │ │ ├── SoulSearchingAndroidNotification.kt │ │ │ │ │ ├── SoulSearchingAndroidNotificationState.kt │ │ │ │ │ ├── SoulSearchingNotificationAndroid13.kt │ │ │ │ │ └── SoulSearchingNotificationBelowAndroid13.kt │ │ │ │ └── receivers │ │ │ │ │ ├── ChangeFavoriteStateNotificationReceiver.kt │ │ │ │ │ ├── DeletedNotificationIntentReceiver.kt │ │ │ │ │ ├── NextMusicNotificationReceiver.kt │ │ │ │ │ ├── PausePlayNotificationReceiver.kt │ │ │ │ │ └── PreviousMusicNotificationReceiver.kt │ │ │ │ └── player │ │ │ │ ├── AndroidPlayerNormalizer.kt │ │ │ │ ├── PlayerAudioManager.kt │ │ │ │ ├── SoulSearchingAndroidExoPlayerImpl.kt │ │ │ │ └── SoulSearchingAndroidPlayerImpl.kt │ │ └── res │ │ │ └── drawable │ │ │ ├── app_logo.xml │ │ │ ├── ic_pause.xml │ │ │ ├── ic_play_arrow.xml │ │ │ ├── ic_saxophone_svg.xml │ │ │ ├── ic_skip_next.xml │ │ │ ├── ic_skip_previous.xml │ │ │ ├── new_notification_default.png │ │ │ └── notification_default.png │ │ ├── commonMain │ │ └── kotlin │ │ │ └── com │ │ │ └── github │ │ │ └── enteraname74 │ │ │ └── soulsearching │ │ │ └── features │ │ │ └── playback │ │ │ ├── di │ │ │ ├── PlaybackModule.kt │ │ │ └── PlaybackPlatformModule.kt │ │ │ ├── list │ │ │ ├── PlaybackListCallbacks.kt │ │ │ ├── PlaybackListManager.kt │ │ │ └── PlaybackListState.kt │ │ │ ├── manager │ │ │ ├── PlaybackManager.kt │ │ │ └── PlaybackManagerState.kt │ │ │ ├── notification │ │ │ └── SoulSearchingNotification.kt │ │ │ ├── player │ │ │ ├── PlayerNormalizer.kt │ │ │ └── SoulSearchingPlayer.kt │ │ │ └── progressjob │ │ │ ├── PlaybackProgressJob.kt │ │ │ └── PlaybackProgressJobCallbacks.kt │ │ └── desktopMain │ │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── features │ │ └── playback │ │ ├── PlaybackManagerDesktopImpl.kt │ │ ├── di │ │ └── PlaybackPlatformModule.desktop.kt │ │ ├── notification │ │ └── SoulSearchingDesktopNotification.kt │ │ └── player │ │ └── SoulSearchingDesktopPlayerImpl.kt └── serialization │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ ├── androidMain │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── features │ │ └── serialization │ │ └── SerializationUtils.android.kt │ ├── commonMain │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── features │ │ └── serialization │ │ └── SerializationUtils.kt │ └── desktopMain │ └── kotlin │ └── com │ └── github │ └── enteraname74 │ └── soulsearching │ └── features │ └── serialization │ └── SerializationUtils.desktop.kt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local-android ├── .gitignore ├── build.gradle.kts └── src │ └── androidMain │ └── kotlin │ └── com │ └── github │ └── enteraname74 │ └── localdb │ ├── AppDatabase.kt │ ├── DbModule.kt │ ├── converters │ └── Converters.kt │ ├── dao │ ├── AlbumArtistDao.kt │ ├── AlbumDao.kt │ ├── ArtistDao.kt │ ├── FolderDao.kt │ ├── MusicAlbumDao.kt │ ├── MusicArtistDao.kt │ ├── MusicDao.kt │ ├── MusicPlaylistDao.kt │ ├── PlayerMusicDao.kt │ └── PlaylistDao.kt │ ├── datasourceimpl │ ├── RoomAlbumArtistDataSourceImpl.kt │ ├── RoomAlbumDataSourceImpl.kt │ ├── RoomArtistDataSourceImpl.kt │ ├── RoomFolderDataSourceImpl.kt │ ├── RoomMusicAlbumDataSourceImpl.kt │ ├── RoomMusicArtistDataSourceImpl.kt │ ├── RoomMusicDataSourceImpl.kt │ ├── RoomMusicPlaylistDataSourceImpl.kt │ ├── RoomPlayerMusicDataSourceImpl.kt │ └── RoomPlaylistDataSourceImpl.kt │ ├── migration │ ├── EndMigrationCallback.kt │ ├── Migration16To17.kt │ └── Migration17To18.kt │ └── model │ ├── RoomAlbum.kt │ ├── RoomAlbumArtist.kt │ ├── RoomAlbumWithArtist.kt │ ├── RoomAlbumWithMusics.kt │ ├── RoomArtist.kt │ ├── RoomArtistWithMusics.kt │ ├── RoomFolder.kt │ ├── RoomImageCover.kt │ ├── RoomMusic.kt │ ├── RoomMusicAlbum.kt │ ├── RoomMusicArtist.kt │ ├── RoomMusicPlaylist.kt │ ├── RoomPlayerMusic.kt │ ├── RoomPlayerWithMusicItem.kt │ ├── RoomPlaylist.kt │ └── RoomPlaylistWithMusics.kt ├── local-desktop ├── .gitignore ├── build.gradle.kts └── src │ └── desktopMain │ └── kotlin │ └── com │ └── github │ └── enteraname74 │ └── soulsearching │ └── localdesktop │ ├── AppDatabase.kt │ ├── DbModule.kt │ ├── dao │ ├── AlbumArtistDao.kt │ ├── AlbumDao.kt │ ├── ArtistDao.kt │ ├── FolderDao.kt │ ├── MusicAlbumDao.kt │ ├── MusicArtistDao.kt │ ├── MusicDao.kt │ ├── MusicPlaylistDao.kt │ ├── PlayerMusicDao.kt │ └── PlaylistDao.kt │ ├── datasourceimpl │ ├── AlbumArtistDataSourceImpl.kt │ ├── AlbumDataSourceImpl.kt │ ├── ArtistDataSourceImpl.kt │ ├── FolderDataSourceImpl.kt │ ├── MusicAlbumDataSourceImpl.kt │ ├── MusicArtistDataSourceImpl.kt │ ├── MusicDataSourceImpl.kt │ ├── MusicPlaylistDataSourceImpl.kt │ ├── PlayerMusicDataSourceImpl.kt │ └── PlaylistDataSourceImpl.kt │ ├── migration │ ├── ExposedMigration.kt │ ├── ExposedMigrationHandler.kt │ └── impl │ │ └── Migration16To17.kt │ └── tables │ ├── AlbumArtistTable.kt │ ├── AlbumTable.kt │ ├── ArtistTable.kt │ ├── FolderTable.kt │ ├── MusicAlbumTable.kt │ ├── MusicArtistTable.kt │ ├── MusicPlaylistTable.kt │ ├── MusicTable.kt │ ├── PlayerMusicTable.kt │ └── PlaylistTable.kt ├── metadata ├── en-US │ ├── full_description.txt │ ├── images │ │ ├── icon.png │ │ └── phoneScreenshots │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ └── 8.png │ ├── short_description.txt │ └── title.txt └── fr │ ├── full_description.txt │ ├── images │ ├── icon.png │ └── phoneScreenshots │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ └── 8.png │ ├── short_description.txt │ └── title.txt ├── remote ├── .gitignore ├── build.gradle.kts └── src │ ├── androidMain │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── remote │ │ └── di │ │ └── HttpClient.android.kt │ ├── commonMain │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── remote │ │ ├── datasourceimpl │ │ ├── LyricsRemoteDataSourceImpl.kt │ │ └── ReleaseDataSourceImpl.kt │ │ ├── di │ │ ├── HttpClient.kt │ │ └── RemoteModule.kt │ │ └── model │ │ ├── RemoteLyrics.kt │ │ ├── RemoteRelease.kt │ │ └── StringTimestampConverter.kt │ ├── commonTest │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── remote │ │ └── model │ │ ├── RemoteLyricsTests.kt │ │ └── StringTimestampConverterTests.kt │ └── desktopMain │ └── kotlin │ └── com │ └── github │ └── enteraname74 │ └── soulsearching │ └── remote │ └── di │ └── HttpClient.desktop.kt ├── repository ├── .gitignore ├── build.gradle.kts └── src │ └── commonMain │ └── kotlin │ └── com │ └── github │ └── enteraname74 │ └── soulsearching │ └── repository │ ├── datasource │ ├── AlbumArtistDataSource.kt │ ├── AlbumDataSource.kt │ ├── ArtistDataSource.kt │ ├── FolderDataSource.kt │ ├── LyricsRemoteDataSource.kt │ ├── MusicAlbumDataSource.kt │ ├── MusicArtistDataSource.kt │ ├── MusicDataSource.kt │ ├── MusicPlaylistDataSource.kt │ ├── PlayerMusicDataSource.kt │ ├── PlaylistDataSource.kt │ └── ReleaseDataSource.kt │ ├── di │ └── RepositoryModule.kt │ └── repositoryimpl │ ├── AlbumArtistRepositoryImpl.kt │ ├── AlbumRepositoryImpl.kt │ ├── ArtistRepositoryImpl.kt │ ├── CoverRepositoryImpl.kt │ ├── FolderRepositoryImpl.kt │ ├── LyricsRepositoryImpl.kt │ ├── MusicAlbumRepositoryImpl.kt │ ├── MusicArtistRepositoryImpl.kt │ ├── MusicPlaylistRepositoryImpl.kt │ ├── MusicRepositoryImpl.kt │ ├── PlayerMusicRepositoryImpl.kt │ ├── PlaylistRepositoryImpl.kt │ └── ReleaseRepositoryImpl.kt ├── screenshots ├── all_albums_view.png ├── app_logo_uni.svg ├── dynamic_example_album.png ├── dynamic_example_artist.png ├── dynamic_example_player.png ├── lyrics.png ├── main_dynamic_theme.png ├── modify_music.png ├── perso_first_example.png ├── search_view.png ├── second_dynamic_example_main.png ├── soul_searching_android.png ├── soul_searching_desktop.png └── soul_searching_platforms.png ├── settings.gradle.kts ├── shared-di ├── .gitignore ├── build.gradle.kts └── src │ ├── androidMain │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── shareddi │ │ ├── LocalDatabaseInitializer.android.kt │ │ └── LocalModule.android.kt │ ├── commonMain │ └── kotlin │ │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ └── shareddi │ │ ├── LocalDatabaseInitializer.kt │ │ ├── LocalModule.kt │ │ └── MainModule.kt │ └── desktopMain │ └── kotlin │ └── com │ └── github │ └── enteraname74 │ └── soulsearching │ └── shareddi │ ├── LocalDatabaseInitializer.desktop.kt │ └── LocalModule.desktop.kt └── shared-ui ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src ├── androidMain ├── AndroidManifest.xml ├── ic_launcher-playstore.png ├── kotlin │ └── com │ │ └── github │ │ └── enteraname74 │ │ └── soulsearching │ │ ├── App.kt │ │ ├── MainActivity.kt │ │ ├── di │ │ └── PlatformModule.android.kt │ │ ├── domain │ │ └── AppVersion.android.kt │ │ ├── ext │ │ └── ImageBitmapExt.android.kt │ │ ├── feature │ │ └── editableelement │ │ │ └── WriteFileCheck.android.kt │ │ ├── model │ │ └── utils │ │ │ └── AndroidUtils.kt │ │ └── ui │ │ └── theme │ │ └── Theme.kt └── res │ ├── drawable-v24 │ └── ic_saxophone_svg.xml │ ├── drawable │ ├── add_new_songs_settings.png │ ├── dynamic_main.png │ ├── dynamic_player.png │ ├── folders_settings.png │ ├── ic_baseline_favorite_border.xml │ ├── ic_launcher_background.xml │ ├── ic_launcher_foreground.xml │ ├── ic_pause.xml │ ├── ic_play_arrow.xml │ ├── ic_skip_next.xml │ ├── ic_skip_previous.xml │ ├── modify_album.png │ ├── notification_default.png │ ├── perso_first_example.png │ ├── perso_second_example.png │ ├── perso_third_example.png │ ├── system_dark_theme_main.png │ ├── system_dark_theme_player.png │ ├── system_light_theme_main.png │ └── system_light_theme_player.png │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.webp │ ├── ic_launcher_foreground.webp │ └── ic_launcher_round.webp │ ├── mipmap-mdpi │ ├── ic_launcher.webp │ ├── ic_launcher_foreground.webp │ └── ic_launcher_round.webp │ ├── mipmap-xhdpi │ ├── ic_launcher.webp │ ├── ic_launcher_foreground.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxhdpi │ ├── ic_launcher.webp │ ├── ic_launcher_foreground.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxxhdpi │ ├── ic_launcher.webp │ ├── ic_launcher_foreground.webp │ └── ic_launcher_round.webp │ ├── values-fr │ └── strings.xml │ ├── values │ ├── colors.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── commonMain ├── composeResources │ └── drawable │ │ ├── add_new_songs_settings.png │ │ ├── app_logo.svg │ │ ├── app_logo_uni.svg │ │ ├── app_logo_uni_png.png │ │ ├── app_logo_uni_xml.xml │ │ ├── dynamic_main.png │ │ ├── dynamic_player.png │ │ ├── folders_settings.png │ │ ├── modify_album.png │ │ ├── perso_first_example.png │ │ ├── perso_third_example.png │ │ └── system_dark_theme_main.png └── kotlin │ └── com │ └── github │ └── enteraname74 │ └── soulsearching │ ├── PlayerViewScaffold.kt │ ├── SoulSearchingAppTheme.kt │ ├── SoulSearchingApplication.kt │ ├── commondelegate │ ├── AlbumBottomSheetDelegate.kt │ ├── ArtistBottomSheetDelegate.kt │ ├── MultiAlbumBottomSheetDelegate.kt │ ├── MultiArtistBottomSheetDelegate.kt │ ├── MultiMusicBottomSheetDelegate.kt │ ├── MultiPlaylistBottomSheetDelegate.kt │ ├── MusicBottomSheetDelegate.kt │ └── PlaylistBottomSheetDelegate.kt │ ├── composables │ ├── BigPreviewComposable.kt │ ├── MusicItemComposable.kt │ ├── PlaylistSelectableComposable.kt │ ├── ProgressIndicatorComposable.kt │ ├── SoulByteArrayImage.kt │ ├── SoulImage.kt │ ├── StartTopBar.kt │ ├── bottomsheets │ │ ├── BottomSheetElementInformation.kt │ │ ├── BottomSheetRow.kt │ │ ├── QuickAccessBottomSheetMenu.kt │ │ ├── album │ │ │ ├── AlbumBottomSheet.kt │ │ │ └── AlbumBottomSheetMenu.kt │ │ ├── artist │ │ │ ├── ArtistBottomSheet.kt │ │ │ └── ArtistBottomSheetMenu.kt │ │ ├── multialbum │ │ │ ├── MultiAlbumBottomSheet.kt │ │ │ └── MultiAlbumBottomSheetMenu.kt │ │ ├── multiartist │ │ │ ├── MultiArtistBottomSheet.kt │ │ │ └── MultiArtistBottomSheetMenu.kt │ │ ├── multimusic │ │ │ ├── MultiMusicBottomSheet.kt │ │ │ └── MultiMusicBottomSheetMenu.kt │ │ ├── multiplaylist │ │ │ ├── MultiPlaylistBottomSheet.kt │ │ │ └── MultiPlaylistBottomSheetMenu.kt │ │ ├── music │ │ │ ├── AddToPlaylistBottomSheet.kt │ │ │ ├── MusicBottomSheet.kt │ │ │ └── MusicBottomSheetMenu.kt │ │ └── playlist │ │ │ ├── PlaylistBottomSheet.kt │ │ │ └── PlaylistBottomSheetMenu.kt │ ├── dialog │ │ ├── CreatePlaylistDialog.kt │ │ ├── DeleteAlbumDialog.kt │ │ ├── DeleteArtistDialog.kt │ │ ├── DeleteMultiAlbumDialog.kt │ │ ├── DeleteMultiArtistDialog.kt │ │ ├── DeleteMultiMusicDialog.kt │ │ ├── DeleteMultiPlaylistDialog.kt │ │ ├── DeleteMusicDialog.kt │ │ ├── DeletePlaylistDialog.kt │ │ ├── RemoveMultiMusicFromPlaylistDialog.kt │ │ └── RemoveMusicFromPlaylistDialog.kt │ ├── navigation │ │ ├── NavigationPanel.kt │ │ ├── NavigationRow.kt │ │ └── NavigationRowSpec.kt │ └── remembers │ │ ├── rememberPlayerDraggableState.kt │ │ ├── rememberPlayerMusicDraggableState.kt │ │ └── rememberSearchDraggableState.kt │ ├── di │ ├── AppModule.kt │ ├── DelegateModule.kt │ ├── PlatformModule.kt │ ├── ViewModelModule.kt │ └── injectors.kt │ ├── domain │ ├── AppVersion.kt │ ├── Type.kt │ ├── model │ │ ├── ElementsVisibility.kt │ │ ├── TabData.kt │ │ ├── ViewSettingsManager.kt │ │ ├── settings │ │ │ └── SoulSearchingSettingsImpl.kt │ │ └── types │ │ │ ├── BottomSheetStates.kt │ │ │ └── MusicBottomSheetState.kt │ ├── usecase │ │ └── ShouldInformOfNewReleaseUseCase.kt │ └── utils │ │ └── Utils.kt │ ├── ext │ ├── ElementEnumExt.kt │ ├── ImageBitmapExt.kt │ ├── NavigatorExt.kt │ └── ReleaseExt.kt │ ├── feature │ ├── appinit │ │ ├── MissingPermissionsComposable.kt │ │ ├── composable │ │ │ ├── AppFeatureComposable.kt │ │ │ └── FetchingMusicTabLayoutComposable.kt │ │ └── songfetching │ │ │ ├── AppInitSongFetchingScreen.kt │ │ │ ├── AppInitSongFetchingViewModel.kt │ │ │ └── state │ │ │ ├── AppInitSongFetchingNavigationState.kt │ │ │ └── AppInitSongFetchingState.kt │ ├── application │ │ ├── ApplicationState.kt │ │ ├── ApplicationViewModel.kt │ │ └── ApplicationWindow.kt │ ├── editableelement │ │ ├── WriteFilesCheck.kt │ │ ├── composable │ │ │ ├── EditableElementAddArtist.kt │ │ │ ├── EditableElementColumnView.kt │ │ │ ├── EditableElementCoverSection.kt │ │ │ ├── EditableElementCoverSelectionItem.kt │ │ │ ├── EditableElementCoversBottomSheet.kt │ │ │ ├── EditableElementCoversChoice.kt │ │ │ ├── EditableElementRowView.kt │ │ │ ├── EditableElementScreen.kt │ │ │ ├── EditableElementTextFieldsView.kt │ │ │ └── EditableElementView.kt │ │ ├── domain │ │ │ ├── CoverListState.kt │ │ │ └── EditableElement.kt │ │ ├── modifyalbum │ │ │ ├── domain │ │ │ │ ├── ModifyAlbumViewModel.kt │ │ │ │ └── state │ │ │ │ │ ├── ModifyAlbumFormState.kt │ │ │ │ │ ├── ModifyAlbumNavigationState.kt │ │ │ │ │ └── ModifyAlbumState.kt │ │ │ └── presentation │ │ │ │ └── ModifyAlbumScreen.kt │ │ ├── modifyartist │ │ │ ├── domain │ │ │ │ ├── ModifyArtistViewModel.kt │ │ │ │ └── state │ │ │ │ │ ├── ModifyArtistFormState.kt │ │ │ │ │ ├── ModifyArtistNavigationState.kt │ │ │ │ │ └── ModifyArtistState.kt │ │ │ └── presentation │ │ │ │ └── ModifyArtistScreen.kt │ │ ├── modifymusic │ │ │ ├── domain │ │ │ │ ├── ModifyMusicViewModel.kt │ │ │ │ └── state │ │ │ │ │ ├── ModifyMusicFormState.kt │ │ │ │ │ ├── ModifyMusicNavigationState.kt │ │ │ │ │ └── ModifyMusicState.kt │ │ │ └── presentation │ │ │ │ ├── ModifyMusicScreen.kt │ │ │ │ └── MusicCoversBottomSheet.kt │ │ └── modifyplaylist │ │ │ ├── domain │ │ │ ├── ModifyPlaylistViewModel.kt │ │ │ └── state │ │ │ │ ├── ModifyPlaylistFormState.kt │ │ │ │ ├── ModifyPlaylistNavigationState.kt │ │ │ │ └── ModifyPlaylistState.kt │ │ │ └── presentation │ │ │ └── ModifyPlaylistScreen.kt │ ├── mainpage │ │ ├── domain │ │ │ ├── model │ │ │ │ ├── ElementEnum.kt │ │ │ │ ├── PagerData.kt │ │ │ │ ├── PagerScreen.kt │ │ │ │ └── SortingInformation.kt │ │ │ ├── state │ │ │ │ ├── AllAlbumsState.kt │ │ │ │ ├── AllArtistsState.kt │ │ │ │ ├── AllMusicFoldersState.kt │ │ │ │ ├── AllMusicsState.kt │ │ │ │ ├── AllPlaylistsState.kt │ │ │ │ ├── AllQuickAccessState.kt │ │ │ │ └── MainPageNavigationState.kt │ │ │ └── viewmodel │ │ │ │ ├── MainPageViewModel.kt │ │ │ │ └── SortingInformationDelegate.kt │ │ └── presentation │ │ │ ├── MainPageScreen.kt │ │ │ ├── composable │ │ │ ├── AllMusicsComposable.kt │ │ │ ├── GitHubReleaseBottomSheet.kt │ │ │ ├── MainMenuHeaderComposable.kt │ │ │ ├── MainPageHorizontalShortcut.kt │ │ │ ├── MainPageList.kt │ │ │ ├── MainPageVerticalShortcut.kt │ │ │ ├── MusicMonthsHorizontalList.kt │ │ │ ├── NoElementView.kt │ │ │ ├── SortOptionsComposable.kt │ │ │ ├── SoulMixDialog.kt │ │ │ └── SubMenuComposable.kt │ │ │ └── tab │ │ │ ├── AllAlbumsTab.kt │ │ │ ├── AllArtistsTab.kt │ │ │ ├── AllMusicFoldersTab.kt │ │ │ ├── AllMusicsTab.kt │ │ │ ├── AllPlaylistsTab.kt │ │ │ └── AllQuickAccessTab.kt │ ├── migration │ │ └── MigrationScreen.kt │ ├── multipleartistschoice │ │ ├── MultipleArtistsChoiceMode.kt │ │ ├── MultipleArtistsChoiceScreen.kt │ │ ├── MultipleArtistsChoiceViewModel.kt │ │ ├── composable │ │ │ ├── MultipleArtistsChoiceItem.kt │ │ │ └── MultipleArtistsWarningCard.kt │ │ └── state │ │ │ ├── MultipleArtistsChoiceNavigationState.kt │ │ │ └── MultipleArtistsChoiceState.kt │ ├── player │ │ ├── domain │ │ │ ├── PlayerUiUtils.kt │ │ │ ├── PlayerViewModel.kt │ │ │ ├── model │ │ │ │ ├── LyricsFetchState.kt │ │ │ │ ├── PlayerMusicListViewManager.kt │ │ │ │ ├── PlayerViewManager.kt │ │ │ │ └── SoulSearchingPlayer.kt │ │ │ └── state │ │ │ │ ├── PlayerNavigationState.kt │ │ │ │ ├── PlayerViewSettingsState.kt │ │ │ │ └── PlayerViewState.kt │ │ ├── ext │ │ │ └── PlayerModeExt.kt │ │ └── presentation │ │ │ ├── PlayerSwipeableView.kt │ │ │ ├── composable │ │ │ ├── PlayerMinimisedMainInfo.kt │ │ │ ├── PlayerMusicCover.kt │ │ │ ├── PlayerTopInformation.kt │ │ │ └── playercontrols │ │ │ │ ├── ExpandedPlayerControlsComposable.kt │ │ │ │ └── MinimisedPlayerControlsComposable.kt │ │ │ └── screen │ │ │ ├── PlayerSwipeableDataScreen.kt │ │ │ └── PlayerSwipeableLoadingScreen.kt │ ├── playerpanel │ │ ├── PlayerPanelDraggableView.kt │ │ └── composable │ │ │ ├── MusicLyricsView.kt │ │ │ ├── PlayerListView.kt │ │ │ ├── PlayerPanelContent.kt │ │ │ └── PlayerPanelTab.kt │ ├── playlistdetail │ │ ├── albumpage │ │ │ ├── domain │ │ │ │ ├── SelectedAlbumNavigationState.kt │ │ │ │ ├── SelectedAlbumState.kt │ │ │ │ └── SelectedAlbumViewModel.kt │ │ │ └── presentation │ │ │ │ └── SelectedAlbumScreen.kt │ │ ├── artistpage │ │ │ ├── domain │ │ │ │ ├── SelectedArtistNavigationState.kt │ │ │ │ ├── SelectedArtistState.kt │ │ │ │ └── SelectedArtistViewModel.kt │ │ │ └── presentation │ │ │ │ ├── SelectedArtistScreen.kt │ │ │ │ └── composable │ │ │ │ └── ArtistAlbums.kt │ │ ├── composable │ │ │ ├── PageHeader.kt │ │ │ ├── PlaylistDetailScreen.kt │ │ │ ├── PlaylistPanel.kt │ │ │ ├── PlaylistPartTitle.kt │ │ │ ├── PlaylistScreen.kt │ │ │ └── view │ │ │ │ ├── PlaylistLargeView.kt │ │ │ │ ├── PlaylistRowView.kt │ │ │ │ └── PlaylistSmallView.kt │ │ ├── domain │ │ │ ├── PlaylistDetail.kt │ │ │ ├── PlaylistDetailListener.kt │ │ │ ├── PlaylistType.kt │ │ │ └── PlaylistViewUiUtils.kt │ │ ├── ext │ │ │ └── PlaylistDetailTypeExt.kt │ │ ├── folderpage │ │ │ ├── domain │ │ │ │ ├── SelectedFolderNavigationState.kt │ │ │ │ ├── SelectedFolderState.kt │ │ │ │ └── SelectedFolderViewModel.kt │ │ │ └── presentation │ │ │ │ └── SelectedFolderScreen.kt │ │ ├── monthpage │ │ │ ├── domain │ │ │ │ ├── SelectedMonthNavigationState.kt │ │ │ │ ├── SelectedMonthState.kt │ │ │ │ └── SelectedMonthViewModel.kt │ │ │ └── presentation │ │ │ │ └── SelectedMonthScreen.kt │ │ └── playlistpage │ │ │ ├── domain │ │ │ ├── SelectedPlaylistNavigationState.kt │ │ │ ├── SelectedPlaylistState.kt │ │ │ └── SelectedPlaylistViewModel.kt │ │ │ └── presentation │ │ │ └── SelectedPlaylistScreen.kt │ ├── search │ │ ├── SearchAll.kt │ │ ├── SearchMusics.kt │ │ ├── SearchView.kt │ │ └── composable │ │ │ ├── LinearPreviewComposable.kt │ │ │ ├── SearchType.kt │ │ │ └── SoulSearchBar.kt │ └── settings │ │ ├── SettingPage.kt │ │ ├── aboutpage │ │ ├── SettingsAboutScreen.kt │ │ ├── developers │ │ │ ├── Developer.kt │ │ │ └── SettingsDevelopersScreen.kt │ │ └── domain │ │ │ ├── SettingsAboutState.kt │ │ │ └── SettingsAboutViewModel.kt │ │ ├── advanced │ │ ├── SettingsAdvancedAction.kt │ │ ├── SettingsAdvancedScreen.kt │ │ ├── SettingsAdvancedViewModel.kt │ │ └── state │ │ │ ├── SettingsAdvancedNavigationState.kt │ │ │ ├── SettingsAdvancedPermissionState.kt │ │ │ └── SettingsAdvancedState.kt │ │ ├── colortheme │ │ ├── SettingsColorThemeScreen.kt │ │ ├── SettingsColorThemeState.kt │ │ ├── SettingsColorThemeViewModel.kt │ │ ├── composable │ │ │ ├── ColorCard.kt │ │ │ ├── ColorThemeCard.kt │ │ │ └── PersonalizedColorThemeCard.kt │ │ └── themeselection │ │ │ ├── domain │ │ │ └── SettingsThemeSelectionViewModel.kt │ │ │ └── presentation │ │ │ ├── SettingsThemeSelectionScreen.kt │ │ │ └── composable │ │ │ └── SettingsThemeItem.kt │ │ ├── managemusics │ │ ├── addmusics │ │ │ ├── domain │ │ │ │ ├── MultipleArtistListener.kt │ │ │ │ ├── SettingsAddMusicsViewModel.kt │ │ │ │ └── state │ │ │ │ │ ├── SettingsAddMusicsNavigationState.kt │ │ │ │ │ └── SettingsAddMusicsState.kt │ │ │ └── presentation │ │ │ │ ├── SettingsAddMusicsScreen.kt │ │ │ │ ├── composable │ │ │ │ └── MusicSelectableComposable.kt │ │ │ │ └── screens │ │ │ │ ├── SettingsAddMusicsDataScreen.kt │ │ │ │ ├── SettingsAddMusicsFetchingScreen.kt │ │ │ │ ├── SettingsAddMusicsSavedSongsScreen.kt │ │ │ │ └── SettingsAddMusicsSavingScreen.kt │ │ ├── managefolders │ │ │ ├── domain │ │ │ │ ├── FolderState.kt │ │ │ │ └── SettingsAllFoldersViewModel.kt │ │ │ └── presentation │ │ │ │ ├── SettingsUsedFoldersScreen.kt │ │ │ │ └── composable │ │ │ │ └── FolderStateComposable.kt │ │ └── presentation │ │ │ ├── SettingsManageMusicsScreen.kt │ │ │ └── composable │ │ │ └── LoadingComposable.kt │ │ ├── personalisation │ │ ├── SettingsMusicViewPersonalisationScreen.kt │ │ ├── SettingsPersonalisationScreen.kt │ │ ├── mainpage │ │ │ ├── domain │ │ │ │ ├── SettingsMainPagePersonalisationState.kt │ │ │ │ └── SettingsMainPagePersonalisationViewModel.kt │ │ │ └── presentation │ │ │ │ └── SettingsMainPagePersonalisationScreen.kt │ │ └── player │ │ │ ├── domain │ │ │ ├── SettingsPlayerPersonalisationState.kt │ │ │ └── SettingsPlayerPersonalisationViewModel.kt │ │ │ └── presentation │ │ │ └── SettingsPlayerPersonalisationScreen.kt │ │ ├── presentation │ │ ├── SettingsScreen.kt │ │ ├── SettingsScreenViewModel.kt │ │ └── composable │ │ │ └── SettingPage.kt │ │ └── statistics │ │ ├── domain │ │ ├── ListenedElement.kt │ │ ├── SettingsStatisticsState.kt │ │ └── SettingsStatisticsViewModel.kt │ │ └── presentation │ │ ├── SettingsStatisticsScreen.kt │ │ └── composable │ │ ├── SettingsStatisticsSection.kt │ │ ├── SettingsStatisticsSectionFactory.kt │ │ ├── SettingsStatisticsSectionHeader.kt │ │ ├── SettingsStatisticsSectionIndicatorList.kt │ │ └── SettingsStatisticsSectionTitle.kt │ ├── theme │ ├── ColorThemeManager.kt │ ├── ColorThemeSettings.kt │ ├── DefaultThemeSettings.kt │ ├── PlaylistDetailCover.kt │ └── SoulSearchingPaletteExt.kt │ └── util │ └── CoverUtils.kt └── desktopMain └── kotlin └── com └── github └── enteraname74 └── soulsearching ├── SoulSearchingDesktop.kt ├── di └── PlatformModule.desktop.kt ├── domain └── AppVersion.desktop.kt ├── ext └── ImageBitmapExt.desktop.kt └── feature └── editableelement └── WriteFileCheck.desktop.kt /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | .idea/ 17 | database.db 18 | 19 | .kotlin 20 | 21 | desktopApp/*.log 22 | -------------------------------------------------------------------------------- /core-ui/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .gradle -------------------------------------------------------------------------------- /core-ui/src/androidMain/kotlin/com/github/enteraname74/soulsearching/coreui/feedbackmanager/FeedbackPopUpAndroidManager.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.feedbackmanager 2 | 3 | import android.content.Context 4 | import android.widget.Toast 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.withContext 7 | 8 | class FeedbackPopUpAndroidManager(private val context: Context): FeedbackPopUpManager { 9 | override suspend fun showFeedback(feedback: String) { 10 | withContext(Dispatchers.Main) { 11 | Toast.makeText( 12 | context, 13 | feedback, 14 | Toast.LENGTH_SHORT, 15 | ).show() 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /core-ui/src/androidMain/kotlin/com/github/enteraname74/soulsearching/coreui/feedbackmanager/FeedbackPopUpScaffold.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.feedbackmanager 2 | 3 | import androidx.compose.foundation.layout.Box 4 | import androidx.compose.foundation.layout.fillMaxSize 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.ui.Modifier 7 | 8 | @Composable 9 | actual fun FeedbackPopUpScaffold( 10 | feedbackPopUpManager: FeedbackPopUpManager, 11 | content: @Composable () -> Unit 12 | ) { 13 | Box(modifier = Modifier.fillMaxSize()) { 14 | content() 15 | } 16 | } -------------------------------------------------------------------------------- /core-ui/src/androidMain/kotlin/com/github/enteraname74/soulsearching/coreui/list/SoulHorizontalScrollBar.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.list 2 | 3 | import androidx.compose.foundation.lazy.LazyListState 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.Modifier 6 | 7 | @Composable 8 | actual fun SoulHorizontalScrollBar( 9 | lazyListState: LazyListState, 10 | modifier: Modifier, 11 | ) { 12 | /* nothing */ 13 | } -------------------------------------------------------------------------------- /core-ui/src/androidMain/kotlin/com/github/enteraname74/soulsearching/coreui/list/SoulVerticalGridScrollBar.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.list 2 | 3 | import androidx.compose.foundation.lazy.grid.LazyGridState 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.Modifier 6 | 7 | @Composable 8 | actual fun SoulVerticalGridScrollBar( 9 | lazyGridState: LazyGridState, 10 | modifier: Modifier 11 | ) { 12 | /*nothing*/ 13 | } -------------------------------------------------------------------------------- /core-ui/src/androidMain/kotlin/com/github/enteraname74/soulsearching/coreui/list/SoulVerticalScrollBar.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.list 2 | 3 | import androidx.compose.foundation.lazy.LazyListState 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.Modifier 6 | 7 | @Composable 8 | actual fun SoulVerticalScrollBar( 9 | lazyListState: LazyListState, 10 | modifier: Modifier 11 | ) { 12 | /*nothing*/ 13 | } -------------------------------------------------------------------------------- /core-ui/src/androidMain/kotlin/com/github/enteraname74/soulsearching/coreui/navigation/SoulBackHandler.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.navigation 2 | 3 | import androidx.activity.compose.BackHandler 4 | import androidx.compose.runtime.Composable 5 | 6 | @Composable 7 | actual fun SoulBackHandler(enabled: Boolean, onBack: () -> Unit) { 8 | BackHandler( 9 | enabled = enabled, 10 | onBack = onBack 11 | ) 12 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/composeResources/drawable/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/core-ui/src/commonMain/composeResources/drawable/app_icon.png -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/ScreenOrientation.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui 2 | 3 | /** 4 | * Define the possible screens orientations. 5 | */ 6 | enum class ScreenOrientation { 7 | HORIZONTAL, 8 | VERTICAL 9 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/SoulCircularProgressIndicator.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui 2 | 3 | import androidx.compose.material3.CircularProgressIndicator 4 | import androidx.compose.runtime.Composable 5 | import com.github.enteraname74.soulsearching.coreui.theme.color.SoulSearchingColorTheme 6 | 7 | @Composable 8 | fun SoulCircularProgressIndicator() { 9 | CircularProgressIndicator( 10 | color = SoulSearchingColorTheme.colorScheme.onPrimary, 11 | ) 12 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/SoulPlayerSpacer.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui 2 | 3 | import androidx.compose.foundation.layout.Spacer 4 | import androidx.compose.foundation.layout.height 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.ui.Modifier 7 | import androidx.compose.ui.unit.Dp 8 | import androidx.compose.ui.unit.dp 9 | import com.github.enteraname74.soulsearching.coreui.ext.toDp 10 | import com.github.enteraname74.soulsearching.coreui.utils.OptionalPaddingForPlayerSpacer 11 | import com.github.enteraname74.soulsearching.coreui.utils.PlayerMinimisedHeight 12 | 13 | @Composable 14 | fun SoulPlayerSpacer() { 15 | Spacer( 16 | modifier = Modifier 17 | .height( 18 | PlayerMinimisedHeight.toDp() + OptionalPaddingForPlayerSpacer 19 | ) 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/bottomsheet/SoulBottomSheet.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.bottomsheet 2 | 3 | import androidx.compose.runtime.Composable 4 | 5 | interface SoulBottomSheet { 6 | @Composable 7 | fun BottomSheet() 8 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/dialog/SoulDialog.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.dialog 2 | 3 | import androidx.compose.runtime.Composable 4 | 5 | interface SoulDialog { 6 | @Composable 7 | fun Dialog() 8 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/ext/ColorExt.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.ext 2 | 3 | import androidx.annotation.FloatRange 4 | import androidx.compose.ui.graphics.Color 5 | import androidx.compose.ui.graphics.luminance 6 | 7 | fun Color.isDark(): Boolean = 8 | this.luminance() < 0.5 9 | 10 | fun Color.blend( 11 | other: Color, 12 | @FloatRange(from = 0.0, to = 1.0) ratio: Float 13 | ): Color { 14 | val inverseRatio = 1 - ratio 15 | val a = this.alpha * inverseRatio + other.alpha * ratio 16 | val r = this.red * inverseRatio + other.red * ratio 17 | val g = this.green * inverseRatio + other.green * ratio 18 | val b = this.blue * inverseRatio + other.blue * ratio 19 | return Color( 20 | red = r, 21 | green = g, 22 | blue = b, 23 | alpha = a 24 | ) 25 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/ext/Conversions.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.ext 2 | 3 | import androidx.compose.runtime.Composable 4 | import androidx.compose.ui.platform.LocalDensity 5 | import androidx.compose.ui.unit.Dp 6 | 7 | @Composable 8 | fun Int.toDp(): Dp = with(LocalDensity.current) { 9 | this@toDp.toDp() 10 | } 11 | 12 | @Composable 13 | fun Float.toDp(): Dp = with(LocalDensity.current) { 14 | this@toDp.toDp() 15 | } 16 | 17 | @Composable 18 | fun Dp.toPx(): Float = with(LocalDensity.current) { 19 | this@toPx.toPx() 20 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/ext/FloatExt.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.ext 2 | 3 | fun Float.coerceForProgressBar(): Float = 4 | this.coerceIn( 5 | minimumValue = 0f, 6 | maximumValue = 1f, 7 | ) -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/feedbackmanager/FeedbackPopUpManager.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.feedbackmanager 2 | 3 | /** 4 | * Manages the feedbacks sent to the user after performing an action. 5 | */ 6 | interface FeedbackPopUpManager { 7 | /** 8 | * Shows a feedback notification to the user. 9 | */ 10 | suspend fun showFeedback(feedback: String) 11 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/feedbackmanager/FeedbackPopUpScaffold.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.feedbackmanager 2 | 3 | import androidx.compose.runtime.Composable 4 | 5 | @Composable 6 | expect fun FeedbackPopUpScaffold( 7 | feedbackPopUpManager: FeedbackPopUpManager, 8 | content: @Composable () -> Unit 9 | ) -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/list/SoulHorizontalScrollBar.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.list 2 | 3 | import androidx.compose.foundation.lazy.LazyListState 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.Modifier 6 | 7 | @Composable 8 | expect fun SoulHorizontalScrollBar( 9 | lazyListState: LazyListState, 10 | modifier: Modifier = Modifier, 11 | ) -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/list/SoulVerticalGridScrollBar.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.list 2 | 3 | import androidx.compose.foundation.lazy.grid.LazyGridState 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.Modifier 6 | 7 | @Composable 8 | expect fun SoulVerticalGridScrollBar( 9 | lazyGridState: LazyGridState, 10 | modifier: Modifier = Modifier, 11 | ) -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/list/SoulVerticalScrollBar.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.list 2 | 3 | import androidx.compose.foundation.lazy.LazyListState 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.Modifier 6 | 7 | @Composable 8 | expect fun SoulVerticalScrollBar( 9 | lazyListState: LazyListState, 10 | modifier: Modifier = Modifier, 11 | ) -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/loading/LoadingManager.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.loading 2 | 3 | import kotlinx.coroutines.flow.MutableStateFlow 4 | import kotlinx.coroutines.flow.StateFlow 5 | import kotlinx.coroutines.flow.asStateFlow 6 | 7 | class LoadingManager { 8 | private val _state: MutableStateFlow = MutableStateFlow(false) 9 | val state: StateFlow = _state.asStateFlow() 10 | 11 | fun startLoading() { 12 | _state.value = true 13 | } 14 | 15 | fun stopLoading() { 16 | _state.value = false 17 | } 18 | 19 | suspend fun withLoading( 20 | block: suspend () -> Unit 21 | ) { 22 | startLoading() 23 | block() 24 | stopLoading() 25 | } 26 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/multiselection/MultiSelectionState.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.multiselection 2 | 3 | import java.util.UUID 4 | 5 | data class MultiSelectionState( 6 | val selectedIds: List, 7 | ) 8 | -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/navigation/SoulBackHandler.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.navigation 2 | 3 | import androidx.compose.runtime.Composable 4 | 5 | @Composable 6 | expect fun SoulBackHandler( 7 | enabled: Boolean = true, 8 | onBack: () -> Unit 9 | ) -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/screen/SoulErrorScreen.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.screen 2 | 3 | import androidx.compose.material.icons.Icons 4 | import androidx.compose.material.icons.rounded.ErrorOutline 5 | import androidx.compose.runtime.Composable 6 | import com.github.enteraname74.soulsearching.coreui.strings.strings 7 | import com.github.enteraname74.soulsearching.coreui.topbar.TopBarActionSpec 8 | 9 | @Composable 10 | fun SoulErrorScreen( 11 | leftAction: TopBarActionSpec, 12 | text: String, 13 | title: String? = strings.anErrorOccurred, 14 | ) { 15 | SoulTemplateScreen( 16 | leftAction = leftAction, 17 | text = text, 18 | buttonSpec = null, 19 | rightAction = null, 20 | title = title, 21 | icon = Icons.Rounded.ErrorOutline 22 | ) 23 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/textfield/SoulTextFieldColors.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.textfield 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | data class SoulTextFieldColors( 6 | val contentColor: Color, 7 | val containerColor: Color, 8 | val labelColor: Color, 9 | val selectionContentColor: Color, 10 | val selectionContainerColor: Color, 11 | ) 12 | -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/textfield/SoulTextFieldLeadingIconSpec.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.textfield 2 | 3 | import androidx.compose.ui.graphics.vector.ImageVector 4 | 5 | data class SoulTextFieldLeadingIconSpec( 6 | val icon: ImageVector, 7 | val onClick: () -> Unit, 8 | ) -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/theme/color/Color.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.theme.color 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | val primaryColorLight = Color(0xFFFEFEFE) 6 | val secondaryColorLight = Color(0xFFF3F3F5) 7 | val thirdColorLight = Color(0xFFF9F9FB) 8 | val textColorLight = Color(0xFF212121) 9 | val subTextColorLight = Color(0xFF514141) 10 | 11 | val primaryColorDark = Color(0xFF100E2C) 12 | val secondaryColorDark = Color(0xFF1D1A48) 13 | val thirdColorDark = Color(0xFF27244d) 14 | val textColorDark = Color(0xFFB4B9C7) 15 | val subTextColorDark = Color(0xFF1A8E92) -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/theme/color/ColorThemeType.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.theme.color 2 | 3 | /** 4 | * Define the type of color theme used for the application. 5 | */ 6 | object ColorThemeType { 7 | /** 8 | * Use the current played music for defining the color theme. 9 | */ 10 | const val DYNAMIC = 0 11 | 12 | /** 13 | * Use the system theme for defining the color theme. 14 | */ 15 | const val SYSTEM = 1 16 | 17 | /** 18 | * Use a personalized theme for defining the color theme. 19 | */ 20 | const val PERSONALIZED = 2 21 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/theme/color/SoulSearchingColorTheme.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.theme.color 2 | 3 | import androidx.compose.runtime.Composable 4 | import androidx.compose.runtime.compositionLocalOf 5 | 6 | /** 7 | * Dynamic colors used in the application. 8 | */ 9 | object SoulSearchingColorTheme { 10 | val colorScheme: SoulSearchingPalette 11 | @Composable 12 | get() = LocalColors.current 13 | } 14 | 15 | val LocalColors = compositionLocalOf { SoulSearchingPalettes.lightTheme } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/theme/color/SoulSearchingTheme.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.theme.color 2 | 3 | enum class SoulSearchingTheme(val value: String) { 4 | MainTheme("SS_MAIN_THEME"), 5 | SteelTheme("SS_STEEL_THEME"), 6 | GlacierTheme("SS_GLACIER_THEME"), 7 | DuskTheme("SS_DUSK_THEME"), 8 | PassionTheme("SS_PASSION_THEME"), 9 | GreeneryTheme("SS_GREENERY_THEME"), 10 | TreeBarkTheme("SS_TREE_BARK_THEME"), 11 | ; 12 | 13 | companion object { 14 | fun from(id: String): SoulSearchingTheme = 15 | entries.find { it.value == id } ?: MainTheme 16 | } 17 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/utils/LaunchInit.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.utils 2 | 3 | import androidx.compose.runtime.* 4 | import androidx.compose.runtime.saveable.rememberSaveable 5 | import kotlinx.coroutines.CoroutineScope 6 | 7 | @Composable 8 | fun LaunchInit( 9 | block: suspend CoroutineScope.() -> Unit, 10 | ) { 11 | var hasBeenInit by rememberSaveable { 12 | mutableStateOf(false) 13 | } 14 | 15 | LaunchedEffect(hasBeenInit) { 16 | if (!hasBeenInit) { 17 | block() 18 | hasBeenInit = true 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/utils/PlayerUtils.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.utils 2 | 3 | import androidx.compose.runtime.Composable 4 | import androidx.compose.ui.unit.Dp 5 | import androidx.compose.ui.unit.dp 6 | import com.github.enteraname74.soulsearching.coreui.UiConstants 7 | import com.github.enteraname74.soulsearching.coreui.ext.toPx 8 | 9 | val PlayerMinimisedHeight: Float 10 | @Composable 11 | get() { 12 | return PlayerBasedMinimisedHeight.toPx() + getNavigationBarPadding().toFloat() 13 | } 14 | 15 | val OptionalPaddingForPlayerSpacer: Dp = 10.dp 16 | 17 | private val PlayerBasedMinimisedHeight: Dp 18 | @Composable 19 | get() = UiConstants.CoverSize.small + 15.dp -------------------------------------------------------------------------------- /core-ui/src/commonMain/kotlin/com/github/enteraname74/soulsearching/coreui/utils/SystemBarsUtils.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.utils 2 | 3 | import androidx.compose.foundation.layout.WindowInsets 4 | import androidx.compose.foundation.layout.navigationBars 5 | import androidx.compose.foundation.layout.statusBars 6 | import androidx.compose.runtime.Composable 7 | import androidx.compose.ui.platform.LocalDensity 8 | 9 | @Composable 10 | fun getNavigationBarPadding(): Int = with(LocalDensity.current) { 11 | WindowInsets.navigationBars.getBottom(this) 12 | } 13 | 14 | @Composable 15 | fun getStatusBarPadding(): Int = with(LocalDensity.current) { 16 | WindowInsets.statusBars.getTop(this) 17 | } -------------------------------------------------------------------------------- /core-ui/src/desktopMain/kotlin/com/github/enteraname74/soulsearching/coreui/feedbackmanager/FeedbackPopUpDesktopManager.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.feedbackmanager 2 | 3 | import kotlinx.coroutines.flow.MutableStateFlow 4 | import kotlinx.coroutines.flow.StateFlow 5 | import kotlinx.coroutines.flow.asStateFlow 6 | 7 | class FeedbackPopUpDesktopManager: FeedbackPopUpManager { 8 | private var _state: MutableStateFlow = MutableStateFlow(null) 9 | val state: StateFlow = _state.asStateFlow() 10 | 11 | override suspend fun showFeedback(feedback: String) { 12 | _state.value = feedback 13 | } 14 | 15 | fun consumeFeedback() { 16 | _state.value = null 17 | } 18 | } -------------------------------------------------------------------------------- /core-ui/src/desktopMain/kotlin/com/github/enteraname74/soulsearching/coreui/navigation/SoulBackHandler.desktop.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.coreui.navigation 2 | 3 | import androidx.compose.runtime.Composable 4 | 5 | @Composable 6 | actual fun SoulBackHandler(enabled: Boolean, onBack: () -> Unit) { 7 | /* 8 | Does nothing on desktop 9 | */ 10 | } -------------------------------------------------------------------------------- /desktopApp/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .gradle 3 | 4 | *.db 5 | 6 | # Flatpak 7 | build-dir 8 | repo 9 | .flatpak-builder 10 | *.flatpak -------------------------------------------------------------------------------- /desktopApp/README.md: -------------------------------------------------------------------------------- 1 | # Soul Searching Desktop 2 | 3 | Originally an Android application, *Soul Searching* is now also available as a desktop application. 4 | For now, it works for Linux. The best way to use the application is with a flatpak, as it holds all the needed dependencies for the app to work properly. 5 | 6 | ## Building the application 7 | Use the `packageFlatpakReleaseDistributable` gradle task to build a flatpak of the application. -------------------------------------------------------------------------------- /desktopApp/io.github.enteraname74.soulsearching.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Soul Searching 3 | GenericName=Music Player 4 | Exec=SoulSearching 5 | Comment=Music player application. 6 | Icon=io.github.enteraname74.soulsearching 7 | Terminal=false 8 | Type=Application 9 | Categories=Audio;Player;Music; 10 | Keywords=Music;Player;Audio;Songs;Playlist;Albums;Artists; -------------------------------------------------------------------------------- /desktopApp/src/main/composeResources/drawable/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/desktopApp/src/main/composeResources/drawable/app_icon.png -------------------------------------------------------------------------------- /desktopApp/src/main/composeResources/drawable/app_icon_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/desktopApp/src/main/composeResources/drawable/app_icon_bg.png -------------------------------------------------------------------------------- /domain/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/ext/ListExt.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.ext 2 | 3 | fun List.getFirstsOrMax(total: Int): List { 4 | return if (total >= this.size) { 5 | this 6 | } else { 7 | this.subList(0, total) 8 | } 9 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/ext/MusicExt.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.ext 2 | 3 | import com.github.enteraname74.domain.model.Cover 4 | import com.github.enteraname74.domain.model.Music 5 | 6 | fun List.coverFromSongs(): Cover? = 7 | this.firstOrNull { !it.cover.isEmpty() }?.cover -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/Album.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import java.time.LocalDateTime 4 | import java.util.UUID 5 | 6 | /** 7 | * Represent an Album and information related to it. 8 | * It does not possess its musics or its cover directly. 9 | */ 10 | data class Album( 11 | val albumId: UUID = UUID.randomUUID(), 12 | var albumName: String = "", 13 | var cover: Cover? = null, 14 | var addedDate: LocalDateTime = LocalDateTime.now(), 15 | var nbPlayed: Int = 0, 16 | var isInQuickAccess: Boolean = false 17 | ) -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/AlbumArtist.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import java.util.UUID 4 | 5 | /** 6 | * Used to link an album to its corresponding artist. 7 | */ 8 | data class AlbumArtist( 9 | val id: Long = 0, 10 | val albumId: UUID = UUID.randomUUID(), 11 | val artistId: UUID = UUID.randomUUID() 12 | ) -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/AlbumWithArtist.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | /** 4 | * Represent an album with its artist. 5 | */ 6 | data class AlbumWithArtist( 7 | val album: Album, 8 | val artist: Artist?, 9 | val cover: Cover?, 10 | ) -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/AlbumWithMusics.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import com.github.enteraname74.domain.ext.coverFromSongs 4 | 5 | /** 6 | * Represent an album with its songs and artist. 7 | */ 8 | data class AlbumWithMusics( 9 | val album: Album, 10 | val musics : List, 11 | val artist: Artist?, 12 | override var isInQuickAccess: Boolean = album.isInQuickAccess, 13 | ): QuickAccessible { 14 | 15 | val cover: Cover? = if (album.cover?.isEmpty() == false) { 16 | album.cover 17 | } else { 18 | musics.coverFromSongs() 19 | } 20 | 21 | /** 22 | * Convert an AlbumWithMusics to an AlbumWithArtist only. 23 | */ 24 | fun toAlbumWithArtist() : AlbumWithArtist = AlbumWithArtist( 25 | album = album, 26 | artist = artist, 27 | cover = cover, 28 | ) 29 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/ArtistWithMusics.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import com.github.enteraname74.domain.ext.coverFromSongs 4 | 5 | /** 6 | * Represent an artist with its musics. 7 | */ 8 | data class ArtistWithMusics( 9 | val artist: Artist, 10 | val musics : List, 11 | override var isInQuickAccess: Boolean = artist.isInQuickAccess, 12 | ) : QuickAccessible { 13 | val cover: Cover? = if (artist.cover?.isEmpty() == false) { 14 | artist.cover 15 | } else { 16 | musics.coverFromSongs() 17 | } 18 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/Cover.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import java.util.UUID 4 | 5 | sealed interface Cover { 6 | 7 | fun isEmpty(): Boolean 8 | 9 | data class CoverFile( 10 | val initialCoverPath: String? = null, 11 | val fileCoverId: UUID? = null, 12 | ): Cover { 13 | override fun isEmpty(): Boolean = 14 | initialCoverPath == null && fileCoverId == null 15 | } 16 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/FlowOperation.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | sealed interface FlowOperation { 4 | data object Loading: FlowOperation 5 | data class Error(val throwable: Throwable): FlowOperation 6 | data object Success: FlowOperation 7 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/Folder.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | /** 4 | * Represent a Folder. 5 | * The isSelected value indicate if the folder is used in the application. 6 | */ 7 | data class Folder( 8 | val folderPath: String = "", 9 | val isSelected: Boolean = true 10 | ) -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/MonthMusicList.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import com.github.enteraname74.domain.ext.coverFromSongs 4 | import java.util.UUID 5 | 6 | /** 7 | * Represent a list of music from a given month 8 | */ 9 | data class MonthMusicList( 10 | val month: String = "", 11 | val musics: List = emptyList(), 12 | ) { 13 | val cover: Cover? = musics.coverFromSongs() 14 | } 15 | -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/MonthMusics.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | data class MonthMusics( 4 | val month: String, 5 | val cover: Cover?, 6 | val allMusicsSize: Int, 7 | ) 8 | -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/MusicAlbum.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import java.util.UUID 4 | 5 | /** 6 | * Used to link a song to its corresponding album. 7 | */ 8 | data class MusicAlbum( 9 | val id: Long = 0, 10 | val musicId: UUID = UUID.randomUUID(), 11 | val albumId: UUID = UUID.randomUUID() 12 | ) -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/MusicArtist.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import java.util.UUID 4 | 5 | /** 6 | * Used to link a song to its artist. 7 | */ 8 | data class MusicArtist( 9 | val id: Long = 0, 10 | val musicId: UUID = UUID.randomUUID(), 11 | val artistId: UUID = UUID.randomUUID() 12 | ) -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/MusicFolder.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import java.util.* 4 | 5 | data class MusicFolder( 6 | val path: String, 7 | val coverId: UUID?, 8 | val allMusicsSize: Int, 9 | ) 10 | -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/MusicFolderList.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import com.github.enteraname74.domain.ext.coverFromSongs 4 | import java.io.File 5 | import java.util.UUID 6 | 7 | /** 8 | * Represent a list of musics from a folder. 9 | */ 10 | data class MusicFolderList( 11 | val path: String, 12 | val musics: List, 13 | ) { 14 | val name: String = File(path).name 15 | val cover: Cover? = musics.coverFromSongs() 16 | } 17 | -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/MusicLyrics.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | data class MusicLyrics( 4 | val plainLyrics: List, 5 | val syncedLyrics: List?, 6 | ) 7 | 8 | data class SyncedLyric( 9 | val line: String, 10 | val timestampMs: Long, 11 | ) 12 | -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/MusicPlaylist.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import java.util.UUID 4 | 5 | /** 6 | * Used to link a song to a playlist. 7 | */ 8 | data class MusicPlaylist( 9 | val id: Long = 0, 10 | val musicId: UUID = UUID.randomUUID(), 11 | val playlistId: UUID = UUID.randomUUID() 12 | ) -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/PlayerMode.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | /** 4 | * Possibles playback mode of the player. 5 | */ 6 | enum class PlayerMode(val value: String) { 7 | Normal(value = "NORMAL"), 8 | Shuffle(value = "SHUFFLE"), 9 | Loop(value = "LOOP"); 10 | 11 | companion object { 12 | fun from(value: String) = entries.firstOrNull { it.value == value } ?: Normal 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/PlayerMusic.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import java.util.UUID 4 | 5 | /** 6 | * Used to save a played music. 7 | * It is used to save multiple musics from the player and retrieve theme later. 8 | */ 9 | data class PlayerMusic( 10 | val id: Long = 0, 11 | val playerMusicId: UUID = UUID.randomUUID() 12 | ) -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/PlayerWithMusicItem.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | /** 4 | * Link a PlayerMusic with its corresponding song. 5 | */ 6 | data class PlayerWithMusicItem( 7 | val playerMusic: PlayerMusic = PlayerMusic(), 8 | val music: Music? = null 9 | ) -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/Playlist.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import java.time.LocalDateTime 4 | import java.util.UUID 5 | 6 | /** 7 | * Represent a playlist with information related to it. 8 | * It does not possess its musics or its cover directly. 9 | */ 10 | data class Playlist( 11 | val playlistId: UUID = UUID.randomUUID(), 12 | var name: String = "", 13 | var cover: Cover? = null, 14 | val isFavorite: Boolean = false, 15 | var addedDate: LocalDateTime = LocalDateTime.now(), 16 | var nbPlayed: Int = 0, 17 | var isInQuickAccess: Boolean = false 18 | ) -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/PlaylistWithMusicsNumber.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | /** 4 | * Represent a playlist with the total of songs it possess. 5 | */ 6 | data class PlaylistWithMusicsNumber( 7 | val playlist: Playlist, 8 | val musicsNumber : Int, 9 | val cover: Cover?, 10 | override var isInQuickAccess: Boolean = playlist.isInQuickAccess, 11 | ): QuickAccessible 12 | -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/QuickAccessible.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | sealed interface QuickAccessible { 4 | var isInQuickAccess: Boolean 5 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/Release.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | /** 6 | * Information about a release of the application 7 | */ 8 | @Serializable 9 | data class Release( 10 | val name: String, 11 | val tag: String, 12 | val githubUrl: String, 13 | ) 14 | -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/SortDirection.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | /** 4 | * Possible values of sorts. 5 | */ 6 | object SortDirection { 7 | const val ASC = 0 8 | const val DESC = 1 9 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/model/SortType.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.model 2 | 3 | /** 4 | * Possible types of sorts. 5 | */ 6 | object SortType { 7 | const val NAME = 0 8 | const val ADDED_DATE = 1 9 | const val NB_PLAYED = 2 10 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/repository/AlbumArtistRepository.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.repository 2 | 3 | import com.github.enteraname74.domain.model.AlbumArtist 4 | import java.util.* 5 | 6 | /** 7 | * Repository of an AlbumArtist. 8 | */ 9 | interface AlbumArtistRepository { 10 | suspend fun getAll(): List 11 | /** 12 | * Insert or updates an AlbumArtist. 13 | */ 14 | suspend fun upsert(albumArtist: AlbumArtist) 15 | 16 | suspend fun upsertAll(albumArtists: List) 17 | 18 | /** 19 | * Update the artist of an album. 20 | */ 21 | suspend fun update(albumId: UUID, newArtistId: UUID) 22 | 23 | /** 24 | * Delete an album from an artist. 25 | */ 26 | suspend fun delete(albumId: UUID) 27 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/repository/CoverRepository.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.repository 2 | 3 | import com.github.enteraname74.domain.model.Cover 4 | import java.util.* 5 | 6 | interface CoverRepository { 7 | suspend fun upsert(id: UUID, data: ByteArray) 8 | 9 | suspend fun delete(cover: Cover) 10 | 11 | suspend fun delete(coverId: UUID) 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/repository/FolderRepository.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.repository 2 | 3 | import com.github.enteraname74.domain.model.Folder 4 | import kotlinx.coroutines.flow.Flow 5 | 6 | interface FolderRepository { 7 | /** 8 | * Inserts or updates a Folder. 9 | */ 10 | suspend fun upsert(folder: Folder) 11 | 12 | suspend fun upsertAll(folders: List) 13 | 14 | /** 15 | * Deletes a Folder. 16 | */ 17 | suspend fun delete(folder: Folder) 18 | 19 | suspend fun deleteAll(folders: List) 20 | 21 | /** 22 | * Retrieves a flow of all Folder. 23 | */ 24 | fun getAll(): Flow> 25 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/repository/LyricsRepository.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.repository 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | import com.github.enteraname74.domain.model.MusicLyrics 5 | 6 | /** 7 | * Repository for songs lyrics 8 | */ 9 | interface LyricsRepository { 10 | /** 11 | * Retrieves the lyrics of a song. 12 | * If no lyrics are found, returns null. 13 | */ 14 | suspend fun getLyricsOfSong(music: Music): MusicLyrics? 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/repository/MusicArtistRepository.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.repository 2 | 3 | import com.github.enteraname74.domain.model.MusicArtist 4 | import java.util.* 5 | 6 | interface MusicArtistRepository { 7 | suspend fun getAll(): List 8 | 9 | suspend fun get(artistId: UUID, musicId: UUID): MusicArtist? 10 | 11 | /** 12 | * Inserts or updates a MusicArtist. 13 | * It is the equivalent of adding a Music to an Artist. 14 | */ 15 | suspend fun upsertMusicIntoArtist(musicArtist: MusicArtist) 16 | 17 | suspend fun upsertAll(musicArtists: List) 18 | 19 | suspend fun deleteMusicArtist(musicArtist: MusicArtist) 20 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/DeleteAllAlbumsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.repository.AlbumRepository 4 | import java.util.UUID 5 | 6 | class DeleteAllAlbumsUseCase( 7 | private val albumRepository: AlbumRepository 8 | ) { 9 | suspend operator fun invoke(albumsIds: List) { 10 | albumRepository.deleteAll( 11 | ids = albumsIds, 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/GetAlbumUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.Album 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import java.util.UUID 7 | 8 | class GetAlbumUseCase( 9 | private val albumRepository: AlbumRepository, 10 | ) { 11 | operator fun invoke(albumId: UUID): Flow = 12 | albumRepository.getFromId( 13 | albumId = albumId, 14 | ) 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/GetAlbumWithMusicsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.AlbumWithMusics 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import java.util.UUID 7 | 8 | class GetAlbumWithMusicsUseCase( 9 | private val albumRepository: AlbumRepository, 10 | ) { 11 | operator fun invoke(albumId: UUID): Flow = 12 | albumRepository.getAlbumWithMusics( 13 | albumId = albumId, 14 | ) 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/GetAlbumsNameFromSearchStringUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.repository.AlbumRepository 4 | import kotlinx.coroutines.flow.first 5 | 6 | class GetAlbumsNameFromSearchStringUseCase( 7 | private val albumRepository: AlbumRepository, 8 | ) { 9 | suspend operator fun invoke(searchString: String): List = 10 | if (searchString.isBlank()) { 11 | emptyList() 12 | } else { 13 | albumRepository.getAlbumNamesContainingSearch(searchString) 14 | } 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/GetAlbumsOfArtistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.Album 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import java.util.UUID 7 | 8 | class GetAlbumsOfArtistUseCase( 9 | private val albumRepository: AlbumRepository, 10 | ) { 11 | operator fun invoke(artistId: UUID): Flow> = 12 | albumRepository.getAlbumsOfArtist( 13 | artistId = artistId, 14 | ) 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/GetAlbumsWithMusicsOfArtistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.AlbumWithMusics 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import kotlinx.coroutines.flow.flow 7 | import java.util.UUID 8 | 9 | class GetAlbumsWithMusicsOfArtistUseCase( 10 | private val albumRepository: AlbumRepository, 11 | ) { 12 | operator fun invoke(artistId: UUID): Flow> = 13 | albumRepository.getAlbumsWithMusicsOfArtist( 14 | artistId = artistId, 15 | ) 16 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/GetAllAlbumsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.Album 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class GetAllAlbumsUseCase( 8 | private val albumRepository: AlbumRepository, 9 | ) { 10 | operator fun invoke(): Flow> = 11 | albumRepository.getAll() 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/GetAllAlbumsWithArtistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.AlbumWithArtist 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class GetAllAlbumsWithArtistUseCase( 8 | private val albumRepository: AlbumRepository 9 | ) { 10 | operator fun invoke(): Flow> = 11 | albumRepository.getAllAlbumsWithArtist() 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/GetAllAlbumsWithMusicsFromQuickAccessUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.AlbumWithMusics 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import kotlinx.coroutines.flow.map 7 | 8 | class GetAllAlbumsWithMusicsFromQuickAccessUseCase( 9 | private val albumRepository: AlbumRepository, 10 | ) { 11 | operator fun invoke(): Flow> = 12 | albumRepository.getAllAlbumWithMusics().map { list -> 13 | list.filter { it.album.isInQuickAccess } 14 | } 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/GetAllAlbumsWithMusicsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.AlbumWithMusics 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class GetAllAlbumsWithMusicsUseCase( 8 | private val albumRepository: AlbumRepository, 9 | ) { 10 | operator fun invoke(): Flow> = 11 | albumRepository.getAllAlbumWithMusics() 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/GetNumberOfAlbumsWithCoverIdUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.Cover 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | import kotlinx.coroutines.flow.first 6 | import java.util.* 7 | 8 | class GetNumberOfAlbumsWithCoverIdUseCase( 9 | private val albumRepository: AlbumRepository, 10 | ) { 11 | suspend operator fun invoke(coverId: UUID): Int { 12 | val allAlbums = albumRepository.getAll().first() 13 | return allAlbums.count { (it.cover as? Cover.CoverFile)?.fileCoverId == coverId } 14 | } 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/UpdateAlbumCoverUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.Album 4 | import com.github.enteraname74.domain.model.Cover 5 | import com.github.enteraname74.domain.repository.AlbumRepository 6 | import kotlinx.coroutines.flow.first 7 | import java.util.UUID 8 | 9 | class UpdateAlbumCoverUseCase( 10 | private val albumRepository: AlbumRepository, 11 | ) { 12 | suspend operator fun invoke( 13 | newCoverId: UUID, 14 | albumId: UUID, 15 | ) { 16 | val album: Album = albumRepository.getFromId(albumId = albumId).first() ?: return 17 | albumRepository.upsert( 18 | album = album.copy( 19 | cover = Cover.CoverFile(fileCoverId = newCoverId), 20 | ) 21 | ) 22 | } 23 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/UpdateAlbumNbPlayedUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.Album 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | import kotlinx.coroutines.flow.first 6 | import java.util.UUID 7 | 8 | class UpdateAlbumNbPlayedUseCase( 9 | private val albumRepository: AlbumRepository, 10 | ) { 11 | suspend operator fun invoke(albumId: UUID) { 12 | val album: Album = albumRepository.getFromId(albumId = albumId).first() ?: return 13 | albumRepository.upsert( 14 | album = album.copy( 15 | nbPlayed = album.nbPlayed + 1, 16 | ) 17 | ) 18 | } 19 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/UpsertAlbumUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.Album 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | 6 | class UpsertAlbumUseCase( 7 | private val albumRepository: AlbumRepository, 8 | ) { 9 | suspend operator fun invoke(album: Album) { 10 | albumRepository.upsert( 11 | album = album, 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/album/UpsertAllAlbumsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.album 2 | 3 | import com.github.enteraname74.domain.model.Album 4 | import com.github.enteraname74.domain.repository.AlbumRepository 5 | 6 | class UpsertAllAlbumsUseCase( 7 | private val albumRepository: AlbumRepository 8 | ) { 9 | suspend operator fun invoke(albums: List) { 10 | albumRepository.upsertAll(albums) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/albumartist/GetAllAlbumArtistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.albumartist 2 | 3 | import com.github.enteraname74.domain.model.AlbumArtist 4 | import com.github.enteraname74.domain.repository.AlbumArtistRepository 5 | 6 | class GetAllAlbumArtistUseCase( 7 | private val albumArtistRepository: AlbumArtistRepository 8 | ) { 9 | suspend operator fun invoke(): List = 10 | albumArtistRepository.getAll() 11 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/albumartist/UpsertAlbumArtistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.albumartist 2 | 3 | import com.github.enteraname74.domain.model.AlbumArtist 4 | import com.github.enteraname74.domain.repository.AlbumArtistRepository 5 | 6 | class UpsertAlbumArtistUseCase( 7 | private val albumArtistRepository: AlbumArtistRepository 8 | ) { 9 | suspend operator fun invoke( 10 | albumArtist: AlbumArtist, 11 | ) { 12 | albumArtistRepository.upsert( 13 | albumArtist = albumArtist, 14 | ) 15 | } 16 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/albumartist/UpsertAllAlbumArtistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.albumartist 2 | 3 | import com.github.enteraname74.domain.model.AlbumArtist 4 | import com.github.enteraname74.domain.repository.AlbumArtistRepository 5 | 6 | class UpsertAllAlbumArtistUseCase( 7 | private val albumArtistRepository: AlbumArtistRepository 8 | ) { 9 | suspend operator fun invoke(allAlbumArtists: List) { 10 | albumArtistRepository.upsertAll(allAlbumArtists) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/DeleteAllArtistsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.repository.ArtistRepository 4 | import java.util.UUID 5 | 6 | class DeleteAllArtistsUseCase( 7 | private val artistRepository: ArtistRepository 8 | ) { 9 | suspend operator fun invoke(artistsIds: List) { 10 | artistRepository.deleteAll( 11 | artistsIds = artistsIds, 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/DeleteArtistIfEmptyUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.ArtistWithMusics 4 | import com.github.enteraname74.domain.repository.ArtistRepository 5 | import kotlinx.coroutines.flow.first 6 | import java.util.UUID 7 | 8 | class DeleteArtistIfEmptyUseCase( 9 | private val artistRepository: ArtistRepository, 10 | ) { 11 | suspend operator fun invoke( 12 | artistId: UUID 13 | ) { 14 | val artistWithMusics: ArtistWithMusics = 15 | artistRepository.getArtistWithMusics(artistId = artistId).first() ?: return 16 | 17 | if (artistWithMusics.musics.isEmpty()) { 18 | artistRepository.delete(artist = artistWithMusics.artist) 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/GetAllArtistWithMusicsFromQuickAccessUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.ArtistWithMusics 4 | import com.github.enteraname74.domain.repository.ArtistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import kotlinx.coroutines.flow.map 7 | 8 | class GetAllArtistWithMusicsFromQuickAccessUseCase( 9 | private val artistRepository: ArtistRepository, 10 | ) { 11 | operator fun invoke(): Flow> = 12 | artistRepository.getAllArtistWithMusics().map { list -> 13 | list.filter { it.artist.isInQuickAccess } 14 | } 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/GetAllArtistWithMusicsSortedByMostSongsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.ArtistWithMusics 4 | import com.github.enteraname74.domain.repository.ArtistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import kotlinx.coroutines.flow.map 7 | 8 | class GetAllArtistWithMusicsSortedByMostSongsUseCase( 9 | private val artistRepository: ArtistRepository 10 | ) { 11 | operator fun invoke(): Flow> = 12 | artistRepository 13 | .getAllArtistWithMusics() 14 | .map { list -> 15 | list.sortedByDescending { it.musics.size } 16 | } 17 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/GetAllArtistWithMusicsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.ArtistWithMusics 4 | import com.github.enteraname74.domain.repository.ArtistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class GetAllArtistWithMusicsUseCase( 8 | private val artistRepository: ArtistRepository 9 | ) { 10 | operator fun invoke(): Flow> = 11 | artistRepository.getAllArtistWithMusics() 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/GetAllArtistsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.Artist 4 | import com.github.enteraname74.domain.repository.ArtistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class GetAllArtistsUseCase( 8 | private val artistRepository: ArtistRepository, 9 | ) { 10 | operator fun invoke(): Flow> = 11 | artistRepository.getAll() 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/GetAllArtistsWithNameUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.repository.ArtistRepository 4 | 5 | class GetAllArtistsWithNameUseCase( 6 | private val artistRepository: ArtistRepository 7 | ) { 8 | suspend operator fun invoke(artistsNames: List) = 9 | artistRepository.getAllFromName(artistsNames) 10 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/GetArtistFromNameUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.Artist 4 | import com.github.enteraname74.domain.repository.ArtistRepository 5 | 6 | class GetArtistFromNameUseCase( 7 | private val artistRepository: ArtistRepository, 8 | ) { 9 | suspend operator fun invoke(artistName: String): Artist? = 10 | artistRepository.getFromName(artistName = artistName) 11 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/GetArtistWithMusicsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.ArtistWithMusics 4 | import com.github.enteraname74.domain.repository.ArtistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import java.util.UUID 7 | 8 | class GetArtistWithMusicsUseCase( 9 | private val artistRepository: ArtistRepository, 10 | ) { 11 | operator fun invoke(artistId: UUID): Flow = 12 | artistRepository.getArtistWithMusics( 13 | artistId = artistId, 14 | ) 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/GetArtistsNameFromSearchStringUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.repository.ArtistRepository 4 | 5 | class GetArtistsNameFromSearchStringUseCase( 6 | private val artistRepository: ArtistRepository, 7 | ) { 8 | suspend operator fun invoke(searchString: String): List = 9 | if (searchString.isBlank()) { 10 | emptyList() 11 | } else { 12 | artistRepository.getArtistNamesContainingSearch(searchString) 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/GetArtistsOfMusicUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.Artist 4 | import com.github.enteraname74.domain.repository.ArtistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import java.util.* 7 | 8 | class GetArtistsOfMusicUseCase( 9 | private val artistRepository: ArtistRepository, 10 | ) { 11 | operator fun invoke(musicId: UUID): Flow> = 12 | artistRepository.getArtistsOfMusic(musicId) 13 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/UpdateArtistCoverUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.Artist 4 | import com.github.enteraname74.domain.model.Cover 5 | import com.github.enteraname74.domain.repository.ArtistRepository 6 | import kotlinx.coroutines.flow.first 7 | import java.util.* 8 | 9 | class UpdateArtistCoverUseCase( 10 | private val artistRepository: ArtistRepository, 11 | ) { 12 | suspend operator fun invoke( 13 | newCoverId: UUID, 14 | artistId: UUID, 15 | ) { 16 | val artist: Artist = artistRepository.getFromId(artistId = artistId).first() ?: return 17 | artistRepository.upsert( 18 | artist = artist.copy( 19 | cover = Cover.CoverFile(fileCoverId = newCoverId), 20 | ) 21 | ) 22 | } 23 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/UpdateArtistNbPlayedUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.Artist 4 | import com.github.enteraname74.domain.repository.ArtistRepository 5 | import kotlinx.coroutines.flow.first 6 | import java.util.UUID 7 | 8 | class UpdateArtistNbPlayedUseCase( 9 | private val artistRepository: ArtistRepository, 10 | ) { 11 | suspend operator fun invoke(artistId: UUID) { 12 | val artist: Artist = artistRepository.getFromId(artistId).first() ?: return 13 | artistRepository.upsert( 14 | artist = artist.copy( 15 | nbPlayed = artist.nbPlayed + 1, 16 | ) 17 | ) 18 | } 19 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/UpsertAllArtistsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.Artist 4 | import com.github.enteraname74.domain.repository.ArtistRepository 5 | 6 | class UpsertAllArtistsUseCase( 7 | private val artistRepository: ArtistRepository, 8 | ) { 9 | suspend operator fun invoke(allArtists: List) { 10 | artistRepository.upsertAll(allArtists) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/artist/UpsertArtistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.artist 2 | 3 | import com.github.enteraname74.domain.model.Artist 4 | import com.github.enteraname74.domain.repository.ArtistRepository 5 | 6 | class UpsertArtistUseCase( 7 | private val artistRepository: ArtistRepository, 8 | ) { 9 | suspend operator fun invoke(artist: Artist) { 10 | artistRepository.upsert(artist) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/cover/DeleteCoverUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.cover 2 | 3 | import com.github.enteraname74.domain.repository.CoverRepository 4 | import java.util.UUID 5 | 6 | class DeleteCoverUseCase( 7 | private val coverRepository: CoverRepository, 8 | ) { 9 | suspend operator fun invoke(coverId: UUID) { 10 | coverRepository.delete( 11 | coverId = coverId, 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/cover/UpsertImageCoverUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.cover 2 | 3 | import com.github.enteraname74.domain.repository.CoverRepository 4 | import java.util.UUID 5 | 6 | class UpsertImageCoverUseCase( 7 | private val coverRepository: CoverRepository, 8 | ) { 9 | suspend operator fun invoke( 10 | id: UUID, 11 | data: ByteArray, 12 | ) { 13 | coverRepository.upsert( 14 | id = id, 15 | data = data, 16 | ) 17 | } 18 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/folder/DeleteAllFoldersUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.folder 2 | 3 | import com.github.enteraname74.domain.model.Folder 4 | import com.github.enteraname74.domain.repository.FolderRepository 5 | 6 | class DeleteAllFoldersUseCase( 7 | private val folderRepository: FolderRepository 8 | ) { 9 | suspend operator fun invoke(folders: List) = 10 | folderRepository.deleteAll(folders = folders) 11 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/folder/DeleteFolderUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.folder 2 | 3 | import com.github.enteraname74.domain.model.Folder 4 | import com.github.enteraname74.domain.repository.FolderRepository 5 | 6 | class DeleteFolderUseCase( 7 | private val folderRepository: FolderRepository, 8 | ) { 9 | suspend operator fun invoke(folder: Folder) { 10 | folderRepository.delete( 11 | folder = folder, 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/folder/GetAllFoldersUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.folder 2 | 3 | import com.github.enteraname74.domain.model.Folder 4 | import com.github.enteraname74.domain.repository.FolderRepository 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class GetAllFoldersUseCase( 8 | private val folderRepository: FolderRepository, 9 | ) { 10 | operator fun invoke(): Flow> = 11 | folderRepository.getAll() 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/folder/GetHiddenFoldersPathUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.folder 2 | 3 | import com.github.enteraname74.domain.repository.FolderRepository 4 | import kotlinx.coroutines.flow.first 5 | 6 | class GetHiddenFoldersPathUseCase( 7 | private val folderRepository: FolderRepository, 8 | ) { 9 | suspend operator fun invoke(): List = 10 | folderRepository 11 | .getAll() 12 | .first() 13 | .filterNot { it.isSelected } 14 | .map { it.folderPath } 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/folder/UpsertAllFoldersUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.folder 2 | 3 | import com.github.enteraname74.domain.model.Folder 4 | import com.github.enteraname74.domain.repository.FolderRepository 5 | 6 | class UpsertAllFoldersUseCase( 7 | private val folderRepository: FolderRepository 8 | ) { 9 | suspend operator fun invoke(allFolders: List) { 10 | folderRepository.upsertAll(allFolders) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/folder/UpsertFolderUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.folder 2 | 3 | import com.github.enteraname74.domain.model.Folder 4 | import com.github.enteraname74.domain.repository.FolderRepository 5 | 6 | class UpsertFolderUseCase( 7 | private val folderRepository: FolderRepository, 8 | ) { 9 | suspend operator fun invoke(folder: Folder) { 10 | folderRepository.upsert( 11 | folder = folder 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/lyrics/GetLyricsOfSongUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.lyrics 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | import com.github.enteraname74.domain.model.MusicLyrics 5 | import com.github.enteraname74.domain.repository.LyricsRepository 6 | 7 | class GetLyricsOfSongUseCase( 8 | private val lyricsRepository: LyricsRepository, 9 | ) { 10 | suspend operator fun invoke(music: Music): MusicLyrics? = 11 | lyricsRepository.getLyricsOfSong(music = music) 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/music/DeleteAllMusicsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.music 2 | 3 | import com.github.enteraname74.domain.repository.MusicRepository 4 | import java.util.UUID 5 | 6 | class DeleteAllMusicsUseCase( 7 | private val musicRepository: MusicRepository, 8 | ) { 9 | suspend operator fun invoke(ids: List) { 10 | musicRepository.deleteAll( 11 | ids = ids, 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/music/GetAllMusicFromFolderPathUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.music 2 | 3 | import com.github.enteraname74.domain.repository.MusicRepository 4 | import kotlinx.coroutines.flow.flow 5 | import kotlinx.coroutines.flow.map 6 | 7 | class GetAllMusicFromFolderPathUseCase( 8 | private val musicRepository: MusicRepository, 9 | ) { 10 | operator fun invoke(folderPath: String) = 11 | musicRepository.getAll().map { list -> 12 | list.filter { 13 | it.folder == folderPath 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/music/GetAllMusicFromQuickAccessUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.music 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | import com.github.enteraname74.domain.repository.MusicRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import kotlinx.coroutines.flow.map 7 | 8 | class GetAllMusicFromQuickAccessUseCase( 9 | private val musicRepository: MusicRepository, 10 | ) { 11 | operator fun invoke(): Flow> = 12 | musicRepository.getAll().map { list -> 13 | list.filter { it.isInQuickAccess } 14 | } 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/music/GetAllMusicUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.music 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | import com.github.enteraname74.domain.repository.MusicRepository 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class GetAllMusicUseCase( 8 | private val musicRepository: MusicRepository, 9 | ) { 10 | operator fun invoke(): Flow> = 11 | musicRepository.getAll() 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/music/GetMusicUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.music 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | import com.github.enteraname74.domain.repository.MusicRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import java.util.UUID 7 | 8 | class GetMusicUseCase( 9 | private val musicRepository: MusicRepository, 10 | ) { 11 | operator fun invoke(musicId: UUID): Flow = 12 | musicRepository.getFromId(musicId = musicId) 13 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/music/IsMusicAlreadySavedUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.music 2 | 3 | import com.github.enteraname74.domain.repository.MusicRepository 4 | import kotlinx.coroutines.flow.first 5 | import java.util.UUID 6 | 7 | class IsMusicAlreadySavedUseCase( 8 | private val musicRepository: MusicRepository 9 | ) { 10 | suspend operator fun invoke(musicPath: String): Boolean = 11 | musicRepository.getFromPath(musicPath) != null 12 | 13 | suspend operator fun invoke(musicId: UUID): Boolean = 14 | musicRepository.getFromId(musicId).first() != null 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/music/IsMusicInFavoritePlaylistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.music 2 | 3 | import com.github.enteraname74.domain.usecase.playlist.GetFavoritePlaylistWithMusicsUseCase 4 | import kotlinx.coroutines.flow.Flow 5 | import kotlinx.coroutines.flow.first 6 | import kotlinx.coroutines.flow.map 7 | import java.util.UUID 8 | 9 | class IsMusicInFavoritePlaylistUseCase( 10 | private val getFavoritePlaylistWithMusicsUseCase: GetFavoritePlaylistWithMusicsUseCase, 11 | ) { 12 | operator fun invoke(musicId: UUID): Flow = 13 | getFavoritePlaylistWithMusicsUseCase().map { favoritePlaylist -> 14 | favoritePlaylist?.musics?.any { it.musicId == musicId } ?: false 15 | } 16 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/music/UpdateMusicNbPlayedUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.music 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | import com.github.enteraname74.domain.repository.MusicRepository 5 | import kotlinx.coroutines.flow.first 6 | import java.util.UUID 7 | 8 | class UpdateMusicNbPlayedUseCase( 9 | private val musicRepository: MusicRepository, 10 | ) { 11 | suspend operator fun invoke(musicId: UUID) { 12 | val music: Music = musicRepository.getFromId(musicId).first() ?: return 13 | musicRepository.upsert( 14 | music = music.copy( 15 | nbPlayed = music.nbPlayed + 1 16 | ) 17 | ) 18 | } 19 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/music/UpsertAllMusicsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.music 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | import com.github.enteraname74.domain.repository.MusicRepository 5 | 6 | class UpsertAllMusicsUseCase( 7 | private val musicRepository: MusicRepository, 8 | ) { 9 | suspend operator fun invoke(allMusics: List) { 10 | musicRepository.upsertAll(allMusics) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/music/UpsertMusicUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.music 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | import com.github.enteraname74.domain.repository.MusicRepository 5 | 6 | class UpsertMusicUseCase( 7 | private val musicRepository: MusicRepository, 8 | ) { 9 | suspend operator fun invoke(music: Music) { 10 | musicRepository.upsert(music = music) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/musicalbum/GetAlbumIdFromMusicIdUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.musicalbum 2 | 3 | import com.github.enteraname74.domain.repository.MusicAlbumRepository 4 | import java.util.UUID 5 | 6 | class GetAlbumIdFromMusicIdUseCase( 7 | private val musicAlbumRepository: MusicAlbumRepository, 8 | ) { 9 | suspend operator fun invoke(musicId: UUID) = 10 | musicAlbumRepository.getAlbumIdFromMusicId(musicId) 11 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/musicalbum/GetAllMusicAlbumUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.musicalbum 2 | 3 | import com.github.enteraname74.domain.model.MusicAlbum 4 | import com.github.enteraname74.domain.repository.MusicAlbumRepository 5 | 6 | class GetAllMusicAlbumUseCase( 7 | private val musicAlbumRepository: MusicAlbumRepository 8 | ) { 9 | suspend operator fun invoke(): List = 10 | musicAlbumRepository.getAll() 11 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/musicalbum/UpdateMusicsAlbumUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.musicalbum 2 | 3 | import com.github.enteraname74.domain.repository.MusicAlbumRepository 4 | import java.util.* 5 | 6 | class UpdateMusicsAlbumUseCase( 7 | private val musicAlbumRepository: MusicAlbumRepository 8 | ) { 9 | suspend operator fun invoke( 10 | newAlbumId: UUID, 11 | legacyAlbumId: UUID 12 | ) { 13 | musicAlbumRepository.updateMusicsAlbum( 14 | newAlbumId = newAlbumId, 15 | legacyAlbumId = legacyAlbumId, 16 | ) 17 | } 18 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/musicalbum/UpsertAllMusicAlbumUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.musicalbum 2 | 3 | import com.github.enteraname74.domain.model.MusicAlbum 4 | import com.github.enteraname74.domain.repository.MusicAlbumRepository 5 | 6 | class UpsertAllMusicAlbumUseCase( 7 | private val musicAlbumRepository: MusicAlbumRepository, 8 | ) { 9 | suspend operator fun invoke(allMusicAlbums: List) { 10 | musicAlbumRepository.upsertAll(allMusicAlbums) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/musicalbum/UpsertMusicIntoAlbumUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.musicalbum 2 | 3 | import com.github.enteraname74.domain.model.MusicAlbum 4 | import com.github.enteraname74.domain.repository.MusicAlbumRepository 5 | 6 | class UpsertMusicIntoAlbumUseCase( 7 | private val musicAlbumRepository: MusicAlbumRepository, 8 | ) { 9 | suspend operator fun invoke(musicAlbum: MusicAlbum) { 10 | musicAlbumRepository.upsertMusicIntoAlbum( 11 | musicAlbum = musicAlbum, 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/musicartist/GetAllMusicArtistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.musicartist 2 | 3 | import com.github.enteraname74.domain.model.MusicArtist 4 | import com.github.enteraname74.domain.repository.MusicArtistRepository 5 | 6 | class GetAllMusicArtistUseCase( 7 | private val musicArtistRepository: MusicArtistRepository 8 | ) { 9 | suspend operator fun invoke(): List = 10 | musicArtistRepository.getAll() 11 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/musicartist/UpsertAllMusicArtistsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.musicartist 2 | 3 | import com.github.enteraname74.domain.model.MusicArtist 4 | import com.github.enteraname74.domain.repository.MusicArtistRepository 5 | 6 | class UpsertAllMusicArtistsUseCase( 7 | private val musicArtistRepository: MusicArtistRepository, 8 | ) { 9 | suspend operator fun invoke(allMusicArtists: List) { 10 | musicArtistRepository.upsertAll(allMusicArtists) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/musicartist/UpsertMusicIntoArtistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.musicartist 2 | 3 | import com.github.enteraname74.domain.model.MusicArtist 4 | import com.github.enteraname74.domain.repository.MusicArtistRepository 5 | 6 | class UpsertMusicIntoArtistUseCase( 7 | private val musicArtistRepository: MusicArtistRepository, 8 | ) { 9 | suspend operator fun invoke(musicArtist: MusicArtist) { 10 | musicArtistRepository.upsertMusicIntoArtist(musicArtist) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/musicplaylist/DeleteMusicFromPlaylistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.musicplaylist 2 | 3 | import com.github.enteraname74.domain.repository.MusicPlaylistRepository 4 | import java.util.UUID 5 | 6 | class DeleteMusicFromPlaylistUseCase( 7 | private val musicPlaylistRepository: MusicPlaylistRepository, 8 | ) { 9 | suspend operator fun invoke( 10 | musicId: UUID, 11 | playlistId: UUID 12 | ) { 13 | musicPlaylistRepository.deleteMusicFromPlaylist( 14 | musicId = musicId, 15 | playlistId = playlistId, 16 | ) 17 | } 18 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/musicplaylist/UpsertMusicIntoPlaylistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.musicplaylist 2 | 3 | import com.github.enteraname74.domain.model.MusicPlaylist 4 | import com.github.enteraname74.domain.repository.MusicPlaylistRepository 5 | 6 | class UpsertMusicIntoPlaylistUseCase( 7 | private val musicPlaylistRepository: MusicPlaylistRepository 8 | ) { 9 | suspend operator fun invoke(musicPlaylist: MusicPlaylist) { 10 | musicPlaylistRepository.upsertMusicIntoPlaylist( 11 | musicPlaylist = musicPlaylist, 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/DeleteAllPlaylistsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.repository.PlaylistRepository 4 | import java.util.UUID 5 | 6 | class DeleteAllPlaylistsUseCase( 7 | private val playlistRepository: PlaylistRepository 8 | ) { 9 | suspend operator fun invoke(playlistIds: List) { 10 | playlistRepository.deleteAll(playlistIds) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/DeletePlaylistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.model.Playlist 4 | import com.github.enteraname74.domain.repository.PlaylistRepository 5 | 6 | class DeletePlaylistUseCase( 7 | private val playlistRepository: PlaylistRepository, 8 | ) { 9 | suspend operator fun invoke(playlist: Playlist) { 10 | playlistRepository.delete(playlist = playlist) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/GetAllPlaylistWithMusicsNumberFromQuickAccessUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.model.PlaylistWithMusicsNumber 4 | import com.github.enteraname74.domain.repository.PlaylistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import kotlinx.coroutines.flow.map 7 | 8 | class GetAllPlaylistWithMusicsNumberFromQuickAccessUseCase( 9 | private val playlistRepository: PlaylistRepository, 10 | ) { 11 | operator fun invoke(): Flow> = 12 | playlistRepository.getAllPlaylistWithMusics().map { list -> 13 | list 14 | .filter { it.playlist.isInQuickAccess } 15 | .map { it.toPlaylistWithMusicsNumber() } 16 | } 17 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/GetAllPlaylistWithMusicsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.model.PlaylistWithMusics 4 | import com.github.enteraname74.domain.repository.PlaylistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class GetAllPlaylistWithMusicsUseCase( 8 | private val playlistRepository: PlaylistRepository, 9 | ) { 10 | operator fun invoke(): Flow> = 11 | playlistRepository.getAllPlaylistWithMusics() 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/GetAllPlaylistsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.model.Playlist 4 | import com.github.enteraname74.domain.repository.PlaylistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class GetAllPlaylistsUseCase( 8 | private val playlistRepository: PlaylistRepository 9 | ) { 10 | operator fun invoke(): Flow> = 11 | playlistRepository.getAll() 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/GetFavoritePlaylistWithMusicsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.model.PlaylistWithMusics 4 | import com.github.enteraname74.domain.repository.PlaylistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import kotlinx.coroutines.flow.map 7 | 8 | class GetFavoritePlaylistWithMusicsUseCase( 9 | private val playlistRepository: PlaylistRepository, 10 | ) { 11 | operator fun invoke(): Flow = 12 | playlistRepository.getAllPlaylistWithMusics().map { list -> 13 | list.firstOrNull { it.playlist.isFavorite } 14 | } 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/GetPlaylistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.model.Playlist 4 | import com.github.enteraname74.domain.repository.PlaylistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import java.util.UUID 7 | 8 | class GetPlaylistUseCase( 9 | private val playlistRepository: PlaylistRepository 10 | ) { 11 | operator fun invoke(playlistId: UUID): Flow = 12 | playlistRepository.getFromId( 13 | playlistId = playlistId, 14 | ) 15 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/GetPlaylistWithMusicsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.model.PlaylistWithMusics 4 | import com.github.enteraname74.domain.repository.PlaylistRepository 5 | import kotlinx.coroutines.flow.Flow 6 | import java.util.UUID 7 | 8 | class GetPlaylistWithMusicsUseCase( 9 | private val playlistRepository: PlaylistRepository, 10 | ) { 11 | operator fun invoke(playlistId: UUID): Flow = 12 | playlistRepository.getPlaylistWithMusics(playlistId) 13 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/GetSelectablePlaylistWithMusicsForMusicUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.model.PlaylistWithMusics 4 | import com.github.enteraname74.domain.repository.PlaylistRepository 5 | import kotlinx.coroutines.flow.first 6 | import java.util.UUID 7 | 8 | class GetSelectablePlaylistWithMusicsForMusicUseCase( 9 | private val playlistRepository: PlaylistRepository, 10 | ) { 11 | suspend operator fun invoke(musicId: UUID): List = 12 | playlistRepository 13 | .getAllPlaylistWithMusics() 14 | .first() 15 | .filter { playlistWithMusics -> 16 | playlistWithMusics.musics.none { it.musicId == musicId } 17 | } 18 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/UpdatePlaylistNbPlayedUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.model.Playlist 4 | import com.github.enteraname74.domain.repository.PlaylistRepository 5 | import kotlinx.coroutines.flow.first 6 | import java.util.UUID 7 | 8 | class UpdatePlaylistNbPlayedUseCase( 9 | private val playlistRepository: PlaylistRepository, 10 | ) { 11 | suspend operator fun invoke(playlistId: UUID) { 12 | val playlist: Playlist = playlistRepository.getFromId(playlistId).first() ?: return 13 | playlistRepository.upsert( 14 | playlist.copy( 15 | nbPlayed = playlist.nbPlayed + 1 16 | ) 17 | ) 18 | } 19 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/UpsertAllPlaylistsUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.model.Playlist 4 | import com.github.enteraname74.domain.repository.PlaylistRepository 5 | 6 | class UpsertAllPlaylistsUseCase( 7 | private val playlistRepository: PlaylistRepository, 8 | ) { 9 | suspend operator fun invoke(playlists: List) { 10 | playlistRepository.upsertAll(playlists) 11 | } 12 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/playlist/UpsertPlaylistUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.playlist 2 | 3 | import com.github.enteraname74.domain.model.Playlist 4 | import com.github.enteraname74.domain.repository.PlaylistRepository 5 | 6 | class UpsertPlaylistUseCase( 7 | private val playlistRepository: PlaylistRepository, 8 | ) { 9 | suspend operator fun invoke(playlist: Playlist) { 10 | playlistRepository.upsert( 11 | playlist = playlist, 12 | ) 13 | } 14 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/release/DeleteLatestReleaseUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.release 2 | 3 | import com.github.enteraname74.domain.repository.ReleaseRepository 4 | 5 | class DeleteLatestReleaseUseCase( 6 | private val releaseRepository: ReleaseRepository, 7 | ) { 8 | suspend operator fun invoke() { 9 | releaseRepository.deleteLatestRelease() 10 | } 11 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/release/FetchLatestReleaseUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.release 2 | 3 | import com.github.enteraname74.domain.repository.ReleaseRepository 4 | 5 | class FetchLatestReleaseUseCase( 6 | private val releaseRepository: ReleaseRepository, 7 | ) { 8 | suspend operator fun invoke() { 9 | releaseRepository.fetchLatestRelease() 10 | } 11 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/release/GetLatestReleaseUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.release 2 | 3 | import com.github.enteraname74.domain.model.Release 4 | import com.github.enteraname74.domain.repository.ReleaseRepository 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class GetLatestReleaseUseCase( 8 | private val releaseRepository: ReleaseRepository, 9 | ) { 10 | operator fun invoke(): Flow = releaseRepository.getLatestRelease() 11 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/release/GetLatestViewedReleaseUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.release 2 | 3 | import com.github.enteraname74.domain.repository.ReleaseRepository 4 | import kotlinx.coroutines.flow.Flow 5 | 6 | class GetLatestViewedReleaseUseCase( 7 | private val releaseRepository: ReleaseRepository, 8 | ) { 9 | operator fun invoke(): Flow = 10 | releaseRepository.getLatestViewedReleaseTag() 11 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/usecase/release/SetLatestViewedReleaseUseCase.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.usecase.release 2 | 3 | import com.github.enteraname74.domain.repository.ReleaseRepository 4 | 5 | class SetLatestViewedReleaseUseCase( 6 | private val releaseRepository: ReleaseRepository, 7 | ) { 8 | suspend operator fun invoke(releaseTag: String) { 9 | releaseRepository.setLatestViewedReleaseTag(releaseTag) 10 | } 11 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/util/DateUtils.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.util 2 | 3 | import java.time.LocalDateTime 4 | import java.time.format.DateTimeFormatter 5 | 6 | object DateUtils { 7 | /** 8 | * Retrieve the month and the year of a date in MM/yyyy format. 9 | */ 10 | fun getMonthAndYearOfDate(date: LocalDateTime): String { 11 | return date.format(DateTimeFormatter.ofPattern("MM/yyyy")) 12 | } 13 | } -------------------------------------------------------------------------------- /domain/src/commonMain/kotlin/com/github/enteraname74/domain/util/LocalDatabaseVersion.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.util 2 | 3 | object LocalDatabaseVersion { 4 | const val VERSION: Int = 18 5 | } -------------------------------------------------------------------------------- /domain/src/desktopMain/kotlin/com/github/enteraname74/domain/util/AppEnvironment.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.domain.util 2 | 3 | object AppEnvironment { 4 | val IS_IN_DEVELOPMENT: Boolean = System.getenv("SOUL_DEV")?.toBoolean() ?: false 5 | } -------------------------------------------------------------------------------- /features/filemanager/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /features/filemanager/src/androidMain/kotlin/com/github/enteraname74/soulsearching/features/filemanager/cover/CoverFileManagerAndroidImpl.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.filemanager.cover 2 | 3 | import android.content.Context 4 | import java.io.File 5 | 6 | internal class CoverFileManagerAndroidImpl( 7 | private val context: Context, 8 | ): CoverFileManager { 9 | 10 | override fun getCoverFolder(): File { 11 | val filesDir: File = context.filesDir 12 | val folder = File(filesDir, COVER_FOLDER) 13 | if (!folder.exists()) { 14 | folder.mkdirs() 15 | } 16 | 17 | return folder 18 | } 19 | 20 | companion object { 21 | private const val COVER_FOLDER = "covers" 22 | } 23 | } -------------------------------------------------------------------------------- /features/filemanager/src/commonMain/kotlin/com/github/enteraname74/soulsearching/features/filemanager/di/FileManagerPlatformModule.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.filemanager.di 2 | 3 | import org.koin.core.module.Module 4 | 5 | internal expect val fileManagerPlatformModule: Module -------------------------------------------------------------------------------- /features/musicmanager/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /features/musicmanager/src/androidMain/kotlin/com/github/enteraname74/soulsearching/features/musicmanager/di/MusicManagerModule.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.musicmanager.di 2 | 3 | import com.github.enteraname74.soulsearching.features.musicmanager.fetching.MusicFetcher 4 | import com.github.enteraname74.soulsearching.features.musicmanager.fetching.MusicFetcherAndroidImpl 5 | import org.koin.core.module.Module 6 | import org.koin.core.module.dsl.singleOf 7 | import org.koin.dsl.bind 8 | import org.koin.dsl.module 9 | 10 | actual val musicManagerModule: Module = module { 11 | singleOf(::MusicFetcherAndroidImpl) bind MusicFetcher::class 12 | } -------------------------------------------------------------------------------- /features/musicmanager/src/commonMain/kotlin/com/github/enteraname74/soulsearching/features/musicmanager/di/MusicManagerModule.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.musicmanager.di 2 | 3 | import org.koin.core.module.Module 4 | 5 | expect val musicManagerModule: Module -------------------------------------------------------------------------------- /features/musicmanager/src/commonMain/kotlin/com/github/enteraname74/soulsearching/features/musicmanager/domain/AlbumInformation.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.musicmanager.domain 2 | 3 | data class AlbumInformation( 4 | val name: String, 5 | val artist: String, 6 | ) 7 | -------------------------------------------------------------------------------- /features/musicmanager/src/commonMain/kotlin/com/github/enteraname74/soulsearching/features/musicmanager/fetching/SelectableMusicItem.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.musicmanager.fetching 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | 5 | /** 6 | * Define information about a song, its cover and if it is selected. 7 | */ 8 | data class SelectableMusicItem( 9 | val music: Music, 10 | var isSelected: Boolean 11 | ) 12 | -------------------------------------------------------------------------------- /features/musicmanager/src/desktopMain/kotlin/com/github/enteraname74/soulsearching/features/musicmanager/di/MusicManagerModule.desktop.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.musicmanager.di 2 | 3 | import com.github.enteraname74.soulsearching.features.musicmanager.fetching.MusicFetcher 4 | import com.github.enteraname74.soulsearching.features.musicmanager.fetching.MusicFetcherDesktopImpl 5 | import org.koin.core.module.Module 6 | import org.koin.core.module.dsl.singleOf 7 | import org.koin.dsl.bind 8 | import org.koin.dsl.module 9 | 10 | actual val musicManagerModule: Module = module { 11 | singleOf(::MusicFetcherDesktopImpl) bind MusicFetcher::class 12 | } -------------------------------------------------------------------------------- /features/playback/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /features/playback/src/androidMain/kotlin/com/github/enteraname74/soulsearching/features/playback/PlaybackManagerAndroidImpl.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.playback 2 | 3 | //class PlaybackManagerAndroidImpl( 4 | // private val context: Context 5 | //): PlaybackManager() { 6 | // override val player: SoulSearchingPlayer by lazy { 7 | // SoulSearchingExoPlayerImpl( 8 | // context = context, 9 | // playbackManager = this, 10 | // ) 11 | // } 12 | // 13 | // override val notification: SoulSearchingNotification by inject() 14 | //} -------------------------------------------------------------------------------- /features/playback/src/androidMain/kotlin/com/github/enteraname74/soulsearching/features/playback/notification/impl/SoulSearchingAndroidNotificationState.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.playback.notification.impl 2 | 3 | import android.support.v4.media.session.MediaSessionCompat 4 | import androidx.compose.ui.graphics.ImageBitmap 5 | import com.github.enteraname74.domain.model.Music 6 | 7 | sealed interface SoulSearchingAndroidNotificationState { 8 | data object Inactive: SoulSearchingAndroidNotificationState 9 | data class Active( 10 | val music: Music, 11 | val cover: ImageBitmap?, 12 | val isPlaying: Boolean, 13 | val mediaSessionToken: MediaSessionCompat.Token, 14 | ): SoulSearchingAndroidNotificationState 15 | } -------------------------------------------------------------------------------- /features/playback/src/androidMain/kotlin/com/github/enteraname74/soulsearching/features/playback/notification/impl/SoulSearchingNotificationAndroid13.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.playback.notification.impl 2 | 3 | import android.app.Notification 4 | import android.content.Context 5 | 6 | /** 7 | * Specification of a SoulSearchingNotification for Android 13 and above. 8 | */ 9 | class SoulSearchingNotificationAndroid13( 10 | context: Context, 11 | ) : SoulSearchingAndroidNotification( 12 | context = context, 13 | ) { 14 | 15 | override fun provideNotification(state: SoulSearchingAndroidNotificationState.Active): Notification = 16 | notificationBuilder 17 | .soulNotificationBuilder(state) 18 | .build() 19 | } -------------------------------------------------------------------------------- /features/playback/src/androidMain/res/drawable/ic_pause.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /features/playback/src/androidMain/res/drawable/ic_play_arrow.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /features/playback/src/androidMain/res/drawable/ic_skip_next.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /features/playback/src/androidMain/res/drawable/ic_skip_previous.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /features/playback/src/androidMain/res/drawable/new_notification_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/features/playback/src/androidMain/res/drawable/new_notification_default.png -------------------------------------------------------------------------------- /features/playback/src/androidMain/res/drawable/notification_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/features/playback/src/androidMain/res/drawable/notification_default.png -------------------------------------------------------------------------------- /features/playback/src/commonMain/kotlin/com/github/enteraname74/soulsearching/features/playback/di/PlaybackModule.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.playback.di 2 | 3 | import org.koin.core.module.Module 4 | import org.koin.core.module.dsl.singleOf 5 | import org.koin.dsl.module 6 | import com.github.enteraname74.soulsearching.features.playback.manager.PlaybackManager 7 | 8 | val playbackModule: Module = module { 9 | includes(playbackPlatformModule) 10 | singleOf(::PlaybackManager) 11 | } -------------------------------------------------------------------------------- /features/playback/src/commonMain/kotlin/com/github/enteraname74/soulsearching/features/playback/di/PlaybackPlatformModule.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.playback.di 2 | 3 | import org.koin.core.module.Module 4 | 5 | internal expect val playbackPlatformModule: Module -------------------------------------------------------------------------------- /features/playback/src/commonMain/kotlin/com/github/enteraname74/soulsearching/features/playback/list/PlaybackListCallbacks.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.playback.list 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | 5 | interface PlaybackListCallbacks { 6 | suspend fun onlyLoadMusic( 7 | seekTo: Int = 0, 8 | music: Music 9 | ) 10 | suspend fun getMusicPosition(): Int 11 | suspend fun stopPlayback() 12 | suspend fun next() 13 | suspend fun setAndPlayMusic(music: Music) 14 | } -------------------------------------------------------------------------------- /features/playback/src/commonMain/kotlin/com/github/enteraname74/soulsearching/features/playback/manager/PlaybackManagerState.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.playback.manager 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | import com.github.enteraname74.domain.model.PlayerMode 5 | 6 | sealed interface PlaybackManagerState { 7 | data object Stopped: PlaybackManagerState 8 | data class Data( 9 | val currentMusic: Music, 10 | val currentMusicIndex: Int, 11 | val playedList: List, 12 | val playerMode: PlayerMode, 13 | val isPlaying: Boolean, 14 | val minimisePlayer: Boolean, 15 | ): PlaybackManagerState { 16 | val currentMusicDuration: Int = currentMusic.duration.toInt() 17 | } 18 | 19 | fun isEmpty(): Boolean = 20 | (this as? Data)?.playedList?.isEmpty() != false 21 | } -------------------------------------------------------------------------------- /features/playback/src/commonMain/kotlin/com/github/enteraname74/soulsearching/features/playback/notification/SoulSearchingNotification.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.playback.notification 2 | 3 | import androidx.compose.ui.graphics.ImageBitmap 4 | import com.github.enteraname74.soulsearching.features.playback.manager.PlaybackManagerState 5 | 6 | interface SoulSearchingNotification { 7 | suspend fun updateNotification( 8 | playbackManagerState: PlaybackManagerState.Data, 9 | cover: ImageBitmap?, 10 | ) 11 | fun dismissNotification() 12 | } -------------------------------------------------------------------------------- /features/playback/src/commonMain/kotlin/com/github/enteraname74/soulsearching/features/playback/progressjob/PlaybackProgressJobCallbacks.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.playback.progressjob 2 | 3 | interface PlaybackProgressJobCallbacks { 4 | fun isPlaying(): Boolean 5 | fun getMusicPosition(): Int 6 | } -------------------------------------------------------------------------------- /features/playback/src/desktopMain/kotlin/com/github/enteraname74/soulsearching/features/playback/PlaybackManagerDesktopImpl.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.playback 2 | 3 | import com.github.enteraname74.soulsearching.features.playback.manager.PlaybackManager 4 | import com.github.enteraname74.soulsearching.features.playback.notification.SoulSearchingNotification 5 | import com.github.enteraname74.soulsearching.features.playback.player.SoulSearchingDesktopPlayerImpl 6 | import com.github.enteraname74.soulsearching.features.playback.player.SoulSearchingPlayer 7 | import org.koin.core.component.inject 8 | 9 | //class PlaybackManagerDesktopImpl: PlaybackManager() { 10 | // override val player: SoulSearchingPlayer by inject() 11 | // override val notification: SoulSearchingNotification by inject() 12 | //} -------------------------------------------------------------------------------- /features/serialization/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /features/serialization/src/androidMain/kotlin/com/github/enteraname74/soulsearching/features/serialization/SerializationUtils.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.serialization 2 | 3 | import kotlinx.serialization.encodeToString 4 | import kotlinx.serialization.json.Json 5 | 6 | actual object SerializationUtils { 7 | val JSON = Json { 8 | encodeDefaults = true 9 | ignoreUnknownKeys = true 10 | } 11 | 12 | actual inline fun deserialize(json: String): T = 13 | JSON.decodeFromString(json) 14 | 15 | actual inline fun serialize(obj: T): String = 16 | JSON.encodeToString(obj) 17 | } -------------------------------------------------------------------------------- /features/serialization/src/commonMain/kotlin/com/github/enteraname74/soulsearching/features/serialization/SerializationUtils.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.serialization 2 | 3 | expect object SerializationUtils { 4 | inline fun deserialize(json: String): T 5 | inline fun serialize(obj: T): String 6 | } -------------------------------------------------------------------------------- /features/serialization/src/desktopMain/kotlin/com/github/enteraname74/soulsearching/features/serialization/SerializationUtils.desktop.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.features.serialization 2 | 3 | import com.google.gson.Gson 4 | 5 | actual object SerializationUtils { 6 | val gson = Gson() 7 | 8 | actual inline fun deserialize(json: String): T = 9 | gson.fromJson(json, T::class.java) 10 | 11 | actual inline fun serialize(obj: T): String = 12 | gson.toJson(obj) 13 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Jan 04 15:40:31 CET 2025 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /local-android/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /local-android/src/androidMain/kotlin/com/github/enteraname74/localdb/converters/Converters.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.localdb.converters 2 | 3 | import androidx.room.TypeConverter 4 | import java.time.LocalDateTime 5 | 6 | /** 7 | * Used for converting complex types to more simple ones for the database. 8 | */ 9 | internal class Converters { 10 | @TypeConverter 11 | fun localDateToString(date : LocalDateTime) : String { 12 | return date.toString() 13 | } 14 | 15 | @TypeConverter 16 | fun stringToLocalDate(string : String) : LocalDateTime { 17 | return LocalDateTime.parse(string) 18 | } 19 | } -------------------------------------------------------------------------------- /local-android/src/androidMain/kotlin/com/github/enteraname74/localdb/migration/EndMigrationCallback.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.localdb.migration 2 | 3 | import androidx.room.RoomDatabase 4 | import androidx.sqlite.db.SupportSQLiteDatabase 5 | import com.github.enteraname74.domain.model.settings.SoulSearchingSettings 6 | import com.github.enteraname74.domain.model.settings.SoulSearchingSettingsKeys 7 | import com.github.enteraname74.domain.util.LocalDatabaseVersion 8 | 9 | class EndMigrationCallback( 10 | private val settings: SoulSearchingSettings, 11 | ): RoomDatabase.Callback() { 12 | override fun onOpen(db: SupportSQLiteDatabase) { 13 | super.onOpen(db) 14 | settings.set( 15 | key = SoulSearchingSettingsKeys.System.CURRENT_DB_VERSION.key, 16 | value = LocalDatabaseVersion.VERSION, 17 | ) 18 | } 19 | } -------------------------------------------------------------------------------- /local-android/src/androidMain/kotlin/com/github/enteraname74/localdb/migration/Migration17To18.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.localdb.migration 2 | 3 | import androidx.room.migration.Migration 4 | import androidx.sqlite.db.SupportSQLiteDatabase 5 | 6 | object Migration17To18: Migration(17, 18) { 7 | override fun migrate(db: SupportSQLiteDatabase) { 8 | try { 9 | db.execSQL("ALTER TABLE RoomMusic DROP COLUMN initialCoverPath") 10 | } catch (e: Exception) { 11 | println("DATABASE -- Error while migrating from 17 to 18") 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /local-android/src/androidMain/kotlin/com/github/enteraname74/localdb/model/RoomAlbumWithArtist.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.localdb.model 2 | 3 | import androidx.room.Embedded 4 | import androidx.room.Junction 5 | import androidx.room.Relation 6 | import com.github.enteraname74.domain.model.AlbumWithArtist 7 | 8 | /** 9 | * Room representation of an AlbumWithArtist. 10 | */ 11 | internal data class RoomAlbumWithArtist( 12 | @Embedded val roomAlbum: RoomAlbum = RoomAlbum(), 13 | @Relation( 14 | parentColumn = "albumId", 15 | entityColumn = "artistId", 16 | associateBy = Junction(RoomAlbumArtist::class) 17 | ) 18 | val roomArtist: RoomArtist? = RoomArtist() 19 | ) -------------------------------------------------------------------------------- /local-android/src/androidMain/kotlin/com/github/enteraname74/localdb/model/RoomFolder.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.localdb.model 2 | 3 | import androidx.room.Entity 4 | import androidx.room.PrimaryKey 5 | import com.github.enteraname74.domain.model.Folder 6 | 7 | /** 8 | * Room representation of a Folder. 9 | */ 10 | @Entity 11 | internal data class RoomFolder( 12 | @PrimaryKey 13 | val folderPath: String = "", 14 | val isSelected: Boolean = true 15 | ) 16 | 17 | /** 18 | * Converts a RoomFolder to a Folder. 19 | */ 20 | internal fun RoomFolder.toFolder(): Folder = Folder( 21 | folderPath = folderPath, 22 | isSelected = isSelected 23 | ) 24 | 25 | /** 26 | * Converts a Folder to a RoomFolder. 27 | */ 28 | internal fun Folder.toRoomFolder(): RoomFolder = RoomFolder( 29 | folderPath = folderPath, 30 | isSelected = isSelected 31 | ) -------------------------------------------------------------------------------- /local-android/src/androidMain/kotlin/com/github/enteraname74/localdb/model/RoomImageCover.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.localdb.model 2 | 3 | import android.graphics.Bitmap 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | import java.util.UUID 7 | 8 | /** 9 | * Room representation of an ImageCover. 10 | */ 11 | @Entity 12 | internal data class RoomImageCover( 13 | @PrimaryKey(autoGenerate = true) val id: Long = 0L, 14 | val coverId: UUID = UUID.randomUUID(), 15 | val cover: Bitmap? = null 16 | ) -------------------------------------------------------------------------------- /local-desktop/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /local-desktop/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.kotlinMultiplatform) 3 | } 4 | 5 | kotlin { 6 | jvm("desktop") 7 | 8 | sourceSets { 9 | val desktopMain by getting { 10 | dependencies { 11 | implementation(project(":domain")) 12 | implementation(project(":repository")) 13 | implementation(project(":filemanager")) 14 | implementation(libs.koin.core) 15 | implementation(libs.bundles.exposed) 16 | implementation(libs.sqlite.jdbc) 17 | } 18 | } 19 | } 20 | } 21 | 22 | java { 23 | sourceCompatibility = JavaVersion.VERSION_17 24 | targetCompatibility = JavaVersion.VERSION_17 25 | } -------------------------------------------------------------------------------- /metadata/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 | Soul Searching is an application for listening to your music files. 2 | 3 | With the latter, you can: 4 | 5 | - manage your music, folders, albums and artists 6 | - access the lyrics (both normal and synced) of the played music 7 | - manage several artists linked to a music 8 | - create playlists 9 | - manage your played list 10 | - see statistics on your listenings 11 | - use a quick access system 12 | 13 | The application also offers several customization elements (color theme, player view...). 14 | -------------------------------------------------------------------------------- /metadata/en-US/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/en-US/images/icon.png -------------------------------------------------------------------------------- /metadata/en-US/images/phoneScreenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/en-US/images/phoneScreenshots/1.png -------------------------------------------------------------------------------- /metadata/en-US/images/phoneScreenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/en-US/images/phoneScreenshots/2.png -------------------------------------------------------------------------------- /metadata/en-US/images/phoneScreenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/en-US/images/phoneScreenshots/3.png -------------------------------------------------------------------------------- /metadata/en-US/images/phoneScreenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/en-US/images/phoneScreenshots/4.png -------------------------------------------------------------------------------- /metadata/en-US/images/phoneScreenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/en-US/images/phoneScreenshots/5.png -------------------------------------------------------------------------------- /metadata/en-US/images/phoneScreenshots/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/en-US/images/phoneScreenshots/6.png -------------------------------------------------------------------------------- /metadata/en-US/images/phoneScreenshots/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/en-US/images/phoneScreenshots/7.png -------------------------------------------------------------------------------- /metadata/en-US/images/phoneScreenshots/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/en-US/images/phoneScreenshots/8.png -------------------------------------------------------------------------------- /metadata/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | Music player for Android. -------------------------------------------------------------------------------- /metadata/en-US/title.txt: -------------------------------------------------------------------------------- 1 | Soul Searching -------------------------------------------------------------------------------- /metadata/fr/full_description.txt: -------------------------------------------------------------------------------- 1 | Soul Searching est une application pour écouter vos musiques locales. 2 | 3 | Avec cette dernière, vous pouvez : 4 | 5 | - gérer vos musiques, dossiers, albums et artistes 6 | - créer des playlists 7 | - voir les paroles (normales et synchronisées) de la musique jouée 8 | - gérer plusieurs artistes liés à une musique 9 | - gérer votre liste de lecture 10 | - voir des statistiques sur vos écoutes 11 | - utiliser un système d'accès rapide 12 | 13 | L'application propose aussi plusieurs éléments de personnalisation (thème de couleur, vue du lecteur...). 14 | -------------------------------------------------------------------------------- /metadata/fr/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/fr/images/icon.png -------------------------------------------------------------------------------- /metadata/fr/images/phoneScreenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/fr/images/phoneScreenshots/1.png -------------------------------------------------------------------------------- /metadata/fr/images/phoneScreenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/fr/images/phoneScreenshots/2.png -------------------------------------------------------------------------------- /metadata/fr/images/phoneScreenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/fr/images/phoneScreenshots/3.png -------------------------------------------------------------------------------- /metadata/fr/images/phoneScreenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/fr/images/phoneScreenshots/4.png -------------------------------------------------------------------------------- /metadata/fr/images/phoneScreenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/fr/images/phoneScreenshots/5.png -------------------------------------------------------------------------------- /metadata/fr/images/phoneScreenshots/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/fr/images/phoneScreenshots/6.png -------------------------------------------------------------------------------- /metadata/fr/images/phoneScreenshots/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/fr/images/phoneScreenshots/7.png -------------------------------------------------------------------------------- /metadata/fr/images/phoneScreenshots/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/metadata/fr/images/phoneScreenshots/8.png -------------------------------------------------------------------------------- /metadata/fr/short_description.txt: -------------------------------------------------------------------------------- 1 | Lecteur de musique pour Android. -------------------------------------------------------------------------------- /metadata/fr/title.txt: -------------------------------------------------------------------------------- 1 | Soul Searching -------------------------------------------------------------------------------- /remote/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /remote/src/androidMain/kotlin/com/github/enteraname74/soulsearching/remote/di/HttpClient.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.remote.di 2 | 3 | import io.ktor.client.* 4 | import io.ktor.client.engine.cio.* 5 | import io.ktor.client.plugins.contentnegotiation.* 6 | import io.ktor.serialization.kotlinx.json.* 7 | import kotlinx.serialization.json.Json 8 | 9 | actual fun provideHttpClient(): HttpClient = 10 | HttpClient(CIO) { 11 | install(ContentNegotiation) { 12 | json( 13 | Json { 14 | ignoreUnknownKeys = true 15 | } 16 | ) 17 | } 18 | } -------------------------------------------------------------------------------- /remote/src/commonMain/kotlin/com/github/enteraname74/soulsearching/remote/di/HttpClient.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.remote.di 2 | 3 | import io.ktor.client.* 4 | 5 | expect fun provideHttpClient(): HttpClient -------------------------------------------------------------------------------- /remote/src/commonMain/kotlin/com/github/enteraname74/soulsearching/remote/di/RemoteModule.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.remote.di 2 | 3 | import com.github.enteraname74.soulsearching.remote.datasourceimpl.LyricsRemoteDataSourceImpl 4 | import com.github.enteraname74.soulsearching.remote.datasourceimpl.ReleaseDataSourceImpl 5 | import com.github.enteraname74.soulsearching.repository.datasource.LyricsRemoteDataSource 6 | import com.github.enteraname74.soulsearching.repository.datasource.ReleaseDataSource 7 | import org.koin.core.module.dsl.factoryOf 8 | import org.koin.dsl.bind 9 | import org.koin.dsl.module 10 | 11 | val remoteModule = module { 12 | factory { provideHttpClient() } 13 | factoryOf(::LyricsRemoteDataSourceImpl) bind LyricsRemoteDataSource::class 14 | factoryOf(::ReleaseDataSourceImpl) bind ReleaseDataSource::class 15 | } -------------------------------------------------------------------------------- /remote/src/commonMain/kotlin/com/github/enteraname74/soulsearching/remote/model/RemoteRelease.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.remote.model 2 | 3 | import com.github.enteraname74.domain.model.Release 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class RemoteRelease( 8 | val html_url: String, 9 | val tag_name: String, 10 | val name: String, 11 | ) { 12 | fun toRelease(): Release = 13 | Release( 14 | name = name, 15 | tag = tag_name, 16 | githubUrl = html_url, 17 | ) 18 | } -------------------------------------------------------------------------------- /remote/src/desktopMain/kotlin/com/github/enteraname74/soulsearching/remote/di/HttpClient.desktop.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.remote.di 2 | 3 | import io.ktor.client.* 4 | import io.ktor.client.engine.cio.* 5 | import io.ktor.client.plugins.contentnegotiation.* 6 | import io.ktor.serialization.gson.* 7 | 8 | actual fun provideHttpClient(): HttpClient = 9 | HttpClient(CIO) { 10 | install(ContentNegotiation) { 11 | gson { 12 | serializeNulls() 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /repository/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .gradle -------------------------------------------------------------------------------- /repository/src/commonMain/kotlin/com/github/enteraname74/soulsearching/repository/datasource/AlbumArtistDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.repository.datasource 2 | 3 | import com.github.enteraname74.domain.model.AlbumArtist 4 | import java.util.UUID 5 | 6 | /** 7 | * Data source of an AlbumArtist. 8 | */ 9 | interface AlbumArtistDataSource { 10 | suspend fun getAll(): List 11 | 12 | /** 13 | * Insert or updates an AlbumArtist. 14 | */ 15 | suspend fun upsert(albumArtist: AlbumArtist) 16 | 17 | suspend fun upsertAll(albumArtists: List) 18 | 19 | /** 20 | * Update the artist of an album. 21 | */ 22 | suspend fun update(albumId: UUID, newArtistId: UUID) 23 | 24 | /** 25 | * Delete an album from an artist. 26 | */ 27 | suspend fun delete(albumId: UUID) 28 | } -------------------------------------------------------------------------------- /repository/src/commonMain/kotlin/com/github/enteraname74/soulsearching/repository/datasource/FolderDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.repository.datasource 2 | 3 | import com.github.enteraname74.domain.model.Folder 4 | import kotlinx.coroutines.flow.Flow 5 | 6 | /** 7 | * Data source of a Folder 8 | */ 9 | interface FolderDataSource { 10 | /** 11 | * Inserts or updates a Folder. 12 | */ 13 | suspend fun upsert(folder : Folder) 14 | 15 | suspend fun upsertAll(folders: List) 16 | 17 | /** 18 | * Deletes a Folder. 19 | */ 20 | suspend fun delete(folder: Folder) 21 | 22 | suspend fun deleteAll(folders: List) 23 | 24 | /** 25 | * Retrieves a flow of all Folder. 26 | */ 27 | fun getAll(): Flow> 28 | } -------------------------------------------------------------------------------- /repository/src/commonMain/kotlin/com/github/enteraname74/soulsearching/repository/datasource/LyricsRemoteDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.repository.datasource 2 | 3 | import com.github.enteraname74.domain.model.Music 4 | import com.github.enteraname74.domain.model.MusicLyrics 5 | 6 | interface LyricsRemoteDataSource { 7 | suspend fun getLyricsOfSong(music: Music, principalArtistName: String): MusicLyrics? 8 | } -------------------------------------------------------------------------------- /repository/src/commonMain/kotlin/com/github/enteraname74/soulsearching/repository/datasource/MusicArtistDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.repository.datasource 2 | 3 | import com.github.enteraname74.domain.model.MusicArtist 4 | import java.util.UUID 5 | 6 | /** 7 | * Data source of a MusicArtist. 8 | */ 9 | interface MusicArtistDataSource { 10 | suspend fun getAll(): List 11 | 12 | suspend fun get(artistId: UUID, musicId: UUID): MusicArtist? 13 | 14 | /** 15 | * Inserts or updates a MusicArtist. 16 | * It is the equivalent of adding a Music to an Artist. 17 | */ 18 | suspend fun upsertMusicIntoArtist(musicArtist: MusicArtist) 19 | 20 | suspend fun upsertAll(musicArtists: List) 21 | 22 | suspend fun deleteMusicArtist(musicArtist: MusicArtist) 23 | } -------------------------------------------------------------------------------- /repository/src/commonMain/kotlin/com/github/enteraname74/soulsearching/repository/datasource/ReleaseDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.repository.datasource 2 | 3 | import com.github.enteraname74.domain.model.Release 4 | 5 | interface ReleaseDataSource { 6 | suspend fun getLatestRelease(): Release? 7 | } -------------------------------------------------------------------------------- /screenshots/all_albums_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/all_albums_view.png -------------------------------------------------------------------------------- /screenshots/app_logo_uni.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /screenshots/dynamic_example_album.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/dynamic_example_album.png -------------------------------------------------------------------------------- /screenshots/dynamic_example_artist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/dynamic_example_artist.png -------------------------------------------------------------------------------- /screenshots/dynamic_example_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/dynamic_example_player.png -------------------------------------------------------------------------------- /screenshots/lyrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/lyrics.png -------------------------------------------------------------------------------- /screenshots/main_dynamic_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/main_dynamic_theme.png -------------------------------------------------------------------------------- /screenshots/modify_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/modify_music.png -------------------------------------------------------------------------------- /screenshots/perso_first_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/perso_first_example.png -------------------------------------------------------------------------------- /screenshots/search_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/search_view.png -------------------------------------------------------------------------------- /screenshots/second_dynamic_example_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/second_dynamic_example_main.png -------------------------------------------------------------------------------- /screenshots/soul_searching_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/soul_searching_android.png -------------------------------------------------------------------------------- /screenshots/soul_searching_desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/soul_searching_desktop.png -------------------------------------------------------------------------------- /screenshots/soul_searching_platforms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/screenshots/soul_searching_platforms.png -------------------------------------------------------------------------------- /shared-di/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .gradle -------------------------------------------------------------------------------- /shared-di/src/androidMain/kotlin/com/github/enteraname74/soulsearching/shareddi/LocalDatabaseInitializer.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.shareddi 2 | 3 | actual object LocalDatabaseInitializer { 4 | actual fun init() { 5 | } 6 | } -------------------------------------------------------------------------------- /shared-di/src/androidMain/kotlin/com/github/enteraname74/soulsearching/shareddi/LocalModule.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.shareddi 2 | 3 | import com.github.enteraname74.localdb.localAndroidModule 4 | import org.koin.core.module.Module 5 | import org.koin.dsl.module 6 | 7 | internal actual val localModule: Module = module { 8 | includes(localAndroidModule) 9 | } -------------------------------------------------------------------------------- /shared-di/src/commonMain/kotlin/com/github/enteraname74/soulsearching/shareddi/LocalDatabaseInitializer.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.shareddi 2 | 3 | expect object LocalDatabaseInitializer { 4 | fun init() 5 | } -------------------------------------------------------------------------------- /shared-di/src/commonMain/kotlin/com/github/enteraname74/soulsearching/shareddi/LocalModule.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.shareddi 2 | 3 | import org.koin.core.module.Module 4 | 5 | internal expect val localModule: Module -------------------------------------------------------------------------------- /shared-di/src/desktopMain/kotlin/com/github/enteraname74/soulsearching/shareddi/LocalDatabaseInitializer.desktop.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.shareddi 2 | 3 | import com.github.enteraname74.soulsearching.localdesktop.AppDatabase 4 | 5 | actual object LocalDatabaseInitializer { 6 | actual fun init() { 7 | AppDatabase.connectToDatabase() 8 | } 9 | } -------------------------------------------------------------------------------- /shared-di/src/desktopMain/kotlin/com/github/enteraname74/soulsearching/shareddi/LocalModule.desktop.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.shareddi 2 | 3 | import com.github.enteraname74.soulsearching.localdesktop.localDesktopModule 4 | import org.koin.core.module.Module 5 | import org.koin.dsl.module 6 | 7 | internal actual val localModule: Module = module { 8 | includes(localDesktopModule) 9 | } -------------------------------------------------------------------------------- /shared-ui/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /release -------------------------------------------------------------------------------- /shared-ui/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # For Jaudiotagger to work properly when making a release of the app and minifying it. 2 | -dontwarn org.slf4j.impl.StaticLoggerBinder 3 | -dontwarn java.awt.image.BufferedImage 4 | -dontwarn javax.imageio.ImageIO 5 | -dontwarn javax.imageio.stream.ImageInputStream 6 | 7 | -dontwarn java.sql.JDBCType 8 | -dontwarn org.jetbrains.skia.Bitmap 9 | -dontwarn org.jetbrains.skia.Data 10 | -dontwarn org.jetbrains.skia.EncodedImageFormat 11 | -dontwarn org.jetbrains.skia.Image$Companion 12 | -dontwarn org.jetbrains.skia.Image 13 | -dontwarn org.jetbrains.skia.ImageInfo 14 | 15 | #-dontobfuscate 16 | #-keepattributes SourceFile,LineNumberTable 17 | -keep class org.jaudiotagger.audio.asf.io.** { *; } 18 | -------------------------------------------------------------------------------- /shared-ui/src/androidMain/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/ic_launcher-playstore.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/kotlin/com/github/enteraname74/soulsearching/domain/AppVersion.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.domain 2 | import com.github.soulsearching.BuildConfig 3 | 4 | 5 | actual object AppVersion { 6 | actual val versionName: String 7 | get() = BuildConfig.VERSION_NAME 8 | } -------------------------------------------------------------------------------- /shared-ui/src/androidMain/kotlin/com/github/enteraname74/soulsearching/ext/ImageBitmapExt.android.kt: -------------------------------------------------------------------------------- 1 | package com.github.enteraname74.soulsearching.ext 2 | 3 | import android.graphics.Bitmap 4 | import androidx.compose.ui.graphics.ImageBitmap 5 | import androidx.compose.ui.graphics.asAndroidBitmap 6 | import java.io.ByteArrayOutputStream 7 | 8 | actual fun ImageBitmap.toByteArray(): ByteArray { 9 | val bitmap = this.asAndroidBitmap() // Converts to Android Bitmap 10 | val outputStream = ByteArrayOutputStream() 11 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream) 12 | return outputStream.toByteArray() 13 | } -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/add_new_songs_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/add_new_songs_settings.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/dynamic_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/dynamic_main.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/dynamic_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/dynamic_player.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/folders_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/folders_settings.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/ic_baseline_favorite_border.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/ic_pause.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/ic_play_arrow.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/ic_skip_next.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/ic_skip_previous.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/modify_album.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/modify_album.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/notification_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/notification_default.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/perso_first_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/perso_first_example.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/perso_second_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/perso_second_example.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/perso_third_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/perso_third_example.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/system_dark_theme_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/system_dark_theme_main.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/system_dark_theme_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/system_dark_theme_player.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/system_light_theme_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/system_light_theme_main.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/drawable/system_light_theme_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/drawable/system_light_theme_player.png -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-hdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-hdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-mdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-mdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-xhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-xhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enteraname74/SoulSearching/dea03e5d7c41c7615d8e8a250c17bd081e53fd61/shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #100E2C 4 | -------------------------------------------------------------------------------- /shared-ui/src/androidMain/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |