From c48634ec9cb8c50e8fefb193b8346518cda86e75 Mon Sep 17 00:00:00 2001 From: Konstantinos Paparas Date: Fri, 3 Jan 2025 23:11:57 +0100 Subject: [PATCH] refactor: migrate from legacy libraries Finishes migration from dbflow to room keeping the schema, Also includes the jackson to moshi migration to drop reflection, drops the last remaining usages of rxjava, and finalizes migration from mvp to mvvm. --- app/build.gradle.kts | 50 +- .../com.kelsos.mbrc.data.Database/3.json | 378 ++++++++++++ app/src/main/AndroidManifest.xml | 6 +- app/src/main/java/com/kelsos/mbrc/App.kt | 7 - .../main/java/com/kelsos/mbrc/AppModule.kt | 286 ++++----- .../main/java/com/kelsos/mbrc/BaseActivity.kt | 28 +- .../com/kelsos/mbrc/UpdateRequiredActivity.kt | 6 +- .../kelsos/mbrc/annotations/PlayerState.kt | 14 - .../java/com/kelsos/mbrc/annotations/Queue.kt | 17 - .../com/kelsos/mbrc/annotations/Repeat.kt | 13 - .../com/kelsos/mbrc/annotations/Search.kt | 8 - .../kelsos/mbrc/annotations/SocketAction.kt | 27 - .../commands/CancelNotificationCommand.kt | 13 - .../ConnectionStatusChangedCommand.kt | 25 - .../kelsos/mbrc/commands/HandleHandshake.kt | 18 - .../commands/InitiateConnectionCommand.kt | 14 - .../mbrc/commands/KeyVolumeDownCommand.kt | 31 - .../mbrc/commands/KeyVolumeUpCommand.kt | 31 - .../kelsos/mbrc/commands/ProcessUserAction.kt | 20 - .../kelsos/mbrc/commands/ProtocolRequest.kt | 19 - .../commands/ReduceVolumeOnRingCommand.kt | 20 - .../mbrc/commands/RestartConnectionCommand.kt | 14 - .../commands/SocketDataAvailableCommand.kt | 13 - .../mbrc/commands/StartDiscoveryCommand.kt | 13 - .../commands/TerminateConnectionCommand.kt | 18 - .../mbrc/commands/TerminateServiceCommand.kt | 20 - .../mbrc/commands/VersionCheckCommand.kt | 80 ++- .../visual/HandshakeCompletionActions.kt | 55 -- .../visual/NotifyNotAllowedCommand.kt | 25 - .../mbrc/common/data/LocalDataSource.kt | 20 - .../mbrc/common/data/RemoteDataSource.kt | 14 - .../com/kelsos/mbrc/common/data/Repository.kt | 20 +- .../kelsos/mbrc/common/mvp/BasePresenter.kt | 64 -- .../com/kelsos/mbrc/common/mvp/BaseView.kt | 3 - .../com/kelsos/mbrc/common/mvp/Presenter.kt | 9 - .../kelsos/mbrc/common/mvvm/BaseViewModel.kt | 16 + .../com/kelsos/mbrc/common/state/AppState.kt | 11 + .../mbrc/common/state/AppStateManager.kt | 100 ++++ .../mbrc/common/state/ConnectionModel.kt | 47 -- .../mbrc/common/state/ConnectionState.kt | 7 + .../mbrc/common/state/ConnectionStatus.kt | 9 + .../com/kelsos/mbrc/common/state/LfmRating.kt | 21 + .../kelsos/mbrc/common/state/MainDataModel.kt | 92 --- .../mbrc/common/state/NowPlayingTrack.kt | 18 + .../kelsos/mbrc/common/state/PlayerState.kt | 28 + .../kelsos/mbrc/common/state/PlayerStatus.kt | 21 + .../mbrc/common/state/PlayerStatusModel.kt | 13 + .../mbrc/common/state/PlayingPosition.kt | 23 + .../kelsos/mbrc/common/state/PlayingTrack.kt | 49 ++ .../state/PlayingTrackCache.kt} | 57 +- .../com/kelsos/mbrc/common/state/Repeat.kt | 24 + .../kelsos/mbrc/common/state/ShuffleMode.kt | 24 + .../kelsos/mbrc/common/state/TrackRating.kt | 8 + .../kelsos/mbrc/common/ui/CircleImageView.kt | 43 +- .../kelsos/mbrc/common/utilities/Helpers.kt | 30 + .../mbrc/common/utilities/RemoteUtils.kt | 52 +- .../java/com/kelsos/mbrc/constants/Const.kt | 1 - .../main/java/com/kelsos/mbrc/data/Data.kt | 3 - .../java/com/kelsos/mbrc/data/Database.kt | 122 ++-- .../mbrc/data/DeserializationAdapter.kt | 50 ++ .../kelsos/mbrc/data/SerializationAdapter.kt | 17 + .../java/com/kelsos/mbrc/data/UserAction.kt | 15 - .../events/DefaultSettingsChangedEvent.kt | 7 - .../com/kelsos/mbrc/events/MessageEvent.kt | 24 - .../java/com/kelsos/mbrc/events/bus/RxBus.kt | 28 - .../com/kelsos/mbrc/events/bus/RxBusImpl.kt | 78 --- .../events/ui/ConnectionSettingsChanged.kt | 9 - .../mbrc/events/ui/CoverChangedEvent.kt | 5 - .../kelsos/mbrc/events/ui/DiscoveryStopped.kt | 7 - .../kelsos/mbrc/events/ui/LfmRatingChanged.kt | 7 - .../mbrc/events/ui/LyricsUpdatedEvent.kt | 5 - .../com/kelsos/mbrc/events/ui/NotifyUser.kt | 18 +- .../kelsos/mbrc/events/ui/PlayStateChange.kt | 8 - .../kelsos/mbrc/events/ui/RatingChanged.kt | 5 - .../mbrc/events/ui/RemoteClientMetaData.kt | 9 - .../com/kelsos/mbrc/events/ui/RepeatChange.kt | 7 - .../events/ui/RequestConnectionStateEvent.kt | 3 - .../kelsos/mbrc/events/ui/ScrobbleChange.kt | 5 - .../kelsos/mbrc/events/ui/ShuffleChange.kt | 17 - .../mbrc/events/ui/TrackInfoChangeEvent.kt | 7 - .../com/kelsos/mbrc/events/ui/TrackMoved.kt | 11 - .../com/kelsos/mbrc/events/ui/TrackRemoval.kt | 10 - .../kelsos/mbrc/events/ui/UpdateDuration.kt | 6 - .../com/kelsos/mbrc/events/ui/VolumeChange.kt | 18 - .../com/kelsos/mbrc/extensions/EnableHome.kt | 9 - .../kelsos/mbrc/extensions/FileExtensions.kt | 29 - .../mbrc/extensions/StringExtensions.kt | 3 - .../features/dragsort/OnStartDragListener.kt | 2 + .../dragsort/SimpleItemTouchHelper.kt | 6 +- .../mbrc/features/help/FeedbackFragment.kt | 44 +- .../kelsos/mbrc/features/help/HelpFragment.kt | 14 +- .../com/kelsos/mbrc/features/library/Album.kt | 35 -- .../features/library/AlbumEntryAdapter.kt | 121 ---- .../mbrc/features/library/AlbumRepository.kt | 10 - .../features/library/AlbumRepositoryImpl.kt | 63 -- .../features/library/AlbumTracksActivity.kt | 163 ----- .../features/library/AlbumTracksContract.kt | 29 - .../library/AlbumTracksPresenterImpl.kt | 57 -- .../kelsos/mbrc/features/library/Artist.kt | 26 - .../features/library/ArtistAlbumsActivity.kt | 135 ----- .../features/library/ArtistAlbumsContract.kt | 24 - .../library/ArtistAlbumsPresenterImpl.kt | 34 -- .../features/library/ArtistEntryAdapter.kt | 97 --- .../mbrc/features/library/ArtistRepository.kt | 12 - .../features/library/ArtistRepositoryImpl.kt | 49 -- .../features/library/BaseBrowseFragment.kt | 98 +++ .../features/library/BaseDetailsActivity.kt | 97 +++ .../features/library/BaseLibraryViewModel.kt | 25 + .../features/library/BrowseAlbumContract.kt | 28 - .../features/library/BrowseAlbumFragment.kt | 130 ---- .../library/BrowseAlbumPresenterImpl.kt | 63 -- .../features/library/BrowseArtistContract.kt | 27 - .../features/library/BrowseArtistFragment.kt | 122 ---- .../library/BrowseArtistPresenterImpl.kt | 78 --- .../features/library/BrowseGenreContract.kt | 28 - .../features/library/BrowseGenreFragment.kt | 127 ---- .../library/BrowseGenrePresenterImpl.kt | 70 --- .../features/library/BrowseTrackContract.kt | 28 - .../features/library/BrowseTrackFragment.kt | 122 ---- .../library/BrowseTrackPresenterImpl.kt | 74 --- .../mbrc/features/library/CachedAlbumInfo.kt | 6 - .../com/kelsos/mbrc/features/library/Cover.kt | 12 +- .../mbrc/features/library/CoverCache.kt | 93 +-- .../kelsos/mbrc/features/library/CoverInfo.kt | 14 - .../kelsos/mbrc/features/library/Extras.kt | 29 + .../com/kelsos/mbrc/features/library/Genre.kt | 30 - .../features/library/GenreArtistsActivity.kt | 129 ---- .../features/library/GenreArtistsContract.kt | 24 - .../library/GenreArtistsPresenterImpl.kt | 34 -- .../features/library/GenreEntryAdapter.kt | 95 --- .../mbrc/features/library/GenreRepository.kt | 5 - .../features/library/GenreRepositoryImpl.kt | 41 -- .../com/kelsos/mbrc/features/library/Key.kt | 5 +- .../mbrc/features/library/LibraryActivity.kt | 48 +- .../mbrc/features/library/LibraryContract.kt | 30 - .../features/library/LibraryPagerAdapter.kt | 15 +- .../features/library/LibraryPresenterImpl.kt | 82 --- .../library/LibrarySyncUseCaseImpl.kt | 9 +- .../features/library/LocalAlbumDataSource.kt | 130 ---- .../features/library/LocalArtistDataSource.kt | 10 - .../library/LocalArtistDataSourceImpl.kt | 102 ---- .../features/library/LocalGenreDataSource.kt | 73 --- .../features/library/LocalTrackDataSource.kt | 178 ------ .../mbrc/features/library/PagePosition.kt | 8 + .../kelsos/mbrc/features/library/PopupMenu.kt | 19 + .../features/library/RemoteAlbumDataSource.kt | 12 - .../library/RemoteArtistDataSource.kt | 12 - .../features/library/RemoteGenreDataSource.kt | 12 - .../features/library/RemoteTrackDataSource.kt | 12 - .../com/kelsos/mbrc/features/library/Track.kt | 51 -- .../features/library/TrackEntryAdapter.kt | 125 ---- .../mbrc/features/library/TrackRepository.kt | 24 - .../features/library/TrackRepositoryImpl.kt | 63 -- .../mbrc/features/library/albums/Actions.kt | 31 + .../mbrc/features/library/albums/Album.kt | 46 ++ .../features/library/albums/AlbumCover.kt | 19 + .../mbrc/features/library/albums/AlbumDao.kt | 66 +++ .../library/albums/AlbumEntryAdapter.kt | 105 ++++ .../library/{ => albums}/AlbumInfo.kt | 2 +- .../library/albums/AlbumRepository.kt | 96 +++ .../features/library/albums/AlbumUiMessage.kt | 15 + .../library/albums/ArtistAlbumsActivity.kt | 82 +++ .../library/albums/ArtistAlbumsViewModel.kt | 30 + .../library/albums/BaseAlbumViewModel.kt | 40 ++ .../library/albums/BrowseAlbumFragment.kt | 73 +++ .../library/albums/BrowseAlbumViewModel.kt | 39 ++ .../mbrc/features/library/albums/Mappers.kt | 25 + .../mbrc/features/library/artists/Actions.kt | 30 + .../mbrc/features/library/artists/Artist.kt | 35 ++ .../features/library/artists/ArtistDao.kt | 54 ++ .../library/artists/ArtistEntryAdapter.kt | 85 +++ .../library/artists/ArtistRepository.kt | 77 +++ .../library/artists/ArtistUiMessage.kt | 15 + .../library/artists/BaseArtistViewModel.kt | 40 ++ .../library/artists/BrowseArtistFragment.kt | 73 +++ .../library/artists/BrowseArtistViewModel.kt | 44 ++ .../library/artists/GenreArtistsActivity.kt | 83 +++ .../library/artists/GenreArtistsViewModel.kt | 31 + .../mbrc/features/library/artists/Mappers.kt | 19 + .../mbrc/features/library/genres/Actions.kt | 30 + .../library/genres/BrowseGenreFragment.kt | 74 +++ .../library/genres/BrowseGenreViewModel.kt | 60 ++ .../mbrc/features/library/genres/Genre.kt | 35 ++ .../mbrc/features/library/genres/GenreDao.kt | 38 ++ .../library/genres/GenreEntryAdapter.kt | 74 +++ .../library/genres/GenreRepository.kt | 77 +++ .../features/library/genres/GenreUiMessage.kt | 15 + .../mbrc/features/library/genres/Mappers.kt | 19 + .../mbrc/features/library/tracks/Actions.kt | 15 + .../library/tracks/AlbumTracksActivity.kt | 121 ++++ .../library/tracks/AlbumTracksViewModel.kt | 45 ++ .../library/tracks/BaseTrackViewModel.kt | 42 ++ .../library/tracks/BrowseTrackFragment.kt | 74 +++ .../library/tracks/BrowseTrackViewModel.kt | 35 ++ .../mbrc/features/library/tracks/Mappers.kt | 37 ++ .../mbrc/features/library/tracks/Track.kt | 74 +++ .../mbrc/features/library/tracks/TrackDao.kt | 96 +++ .../library/tracks/TrackEntryAdapter.kt | 105 ++++ .../library/tracks/TrackRepository.kt | 39 ++ .../library/tracks/TrackRepositoryImpl.kt | 93 +++ .../features/library/tracks/TrackUiMessage.kt | 11 + .../mbrc/features/lyrics/LyricsActivity.kt | 50 +- .../mbrc/features/lyrics/LyricsAdapter.kt | 37 +- .../mbrc/features/lyrics/LyricsContract.kt | 14 - .../mbrc/features/lyrics/LyricsModel.kt | 31 - .../mbrc/features/lyrics/LyricsPayload.kt | 10 +- .../features/lyrics/LyricsPresenterImpl.kt | 50 -- .../mbrc/features/lyrics/LyricsViewModel.kt | 11 + .../features/minicontrol/MiniControlAction.kt | 9 + .../minicontrol/MiniControlContract.kt | 26 - .../minicontrol/MiniControlFragment.kt | 82 ++- .../minicontrol/MiniControlPresenterImpl.kt | 59 -- .../minicontrol/MiniControlViewModel.kt | 51 ++ .../nowplaying/LocalNowPlayingDataSource.kt | 88 --- .../mbrc/features/nowplaying/Mappers.kt | 28 + .../mbrc/features/nowplaying/MoveManager.kt | 12 + .../features/nowplaying/MoveManagerImpl.kt | 31 + .../mbrc/features/nowplaying/NowPlaying.kt | 81 +-- .../features/nowplaying/NowPlayingActivity.kt | 172 ++++-- .../features/nowplaying/NowPlayingAdapter.kt | 203 ++++--- .../features/nowplaying/NowPlayingContract.kt | 38 -- .../mbrc/features/nowplaying/NowPlayingDao.kt | 128 ++++ .../nowplaying/NowPlayingPresenterImpl.kt | 84 --- .../nowplaying/NowPlayingRepository.kt | 99 +++- .../nowplaying/NowPlayingRepositoryImpl.kt | 40 -- .../nowplaying/NowPlayingUiMessages.kt | 11 + .../nowplaying/NowPlayingViewModel.kt | 86 +++ .../nowplaying/RemoteNowPlayingDataSource.kt | 12 - .../mbrc/features/nowplaying/VisibleRange.kt | 13 + .../mbrc/features/output/OutputApiImpl.kt | 4 +- .../mbrc/features/output/OutputResponse.kt | 12 +- .../output/OutputSelectionViewModel.kt | 17 +- .../mbrc/features/player/CoverPayload.kt | 10 +- .../kelsos/mbrc/features/player/IsEmpty.kt | 3 - .../mbrc/features/player/ModelInitializer.kt | 47 -- .../mbrc/features/player/PlayerAction.kt | 23 + .../mbrc/features/player/PlayerActivity.kt | 304 ++++------ .../mbrc/features/player/PlayerContract.kt | 76 --- .../features/player/PlayerStateSerializer.kt | 26 - .../mbrc/features/player/PlayerUiMessage.kt | 9 + .../mbrc/features/player/PlayerViewModel.kt | 94 +++ .../player/PlayerViewPresenterImpl.kt | 204 ------- .../features/player/ProgressSeekerHelper.kt | 63 -- .../features/player/RatingDialogFragment.kt | 48 +- .../features/player/RatingDialogViewModel.kt | 40 ++ .../mbrc/features/player/SeekBarThrottler.kt | 50 -- .../kelsos/mbrc/features/player/TrackInfo.kt | 43 -- .../playlists/LocalPlaylistDataSource.kt | 74 --- .../kelsos/mbrc/features/playlists/Mappers.kt | 24 + .../mbrc/features/playlists/Playlist.kt | 56 +- .../features/playlists/PlaylistActivity.kt | 97 ++- .../features/playlists/PlaylistAdapter.kt | 40 +- .../features/playlists/PlaylistContract.kt | 19 - .../mbrc/features/playlists/PlaylistDao.kt | 31 + .../playlists/PlaylistPresenterImpl.kt | 38 -- .../features/playlists/PlaylistRepository.kt | 52 ++ .../playlists/PlaylistRepositoryImpl.kt | 40 -- .../features/playlists/PlaylistViewModel.kt | 72 +++ .../playlists/RemotePlaylistDataSource.kt | 12 - .../kelsos/mbrc/features/queue/AlbumMapper.kt | 4 +- .../mbrc/features/queue/PopupActionHandler.kt | 133 ----- .../com/kelsos/mbrc/features/queue/Queue.kt | 41 ++ .../mbrc/features/queue/QueueHandler.kt | 94 +-- .../mbrc/features/queue/QueuePayload.kt | 14 +- .../mbrc/features/queue/QueueResponse.kt | 6 +- .../features/radio/LocalRadioDataSource.kt | 81 --- .../com/kelsos/mbrc/features/radio/Mappers.kt | 20 + .../mbrc/features/radio/RadioActivity.kt | 94 +-- .../mbrc/features/radio/RadioAdapter.kt | 39 +- .../mbrc/features/radio/RadioContract.kt | 27 - .../mbrc/features/radio/RadioPresenterImpl.kt | 48 -- .../mbrc/features/radio/RadioRepository.kt | 62 ++ .../features/radio/RadioRepositoryImpl.kt | 40 -- .../mbrc/features/radio/RadioStation.kt | 59 +- .../mbrc/features/radio/RadioStationDao.kt | 31 + .../mbrc/features/radio/RadioViewModel.kt | 71 +++ .../features/radio/RemoteRadioDataSource.kt | 12 - .../settings/ClientInformationStore.kt | 31 + .../features/settings/ConnectionAdapter.kt | 87 ++- .../mbrc/features/settings/ConnectionDao.kt | 61 ++ .../settings/ConnectionManagerActivity.kt | 121 ++-- .../settings/ConnectionManagerPresenter.kt | 13 - .../ConnectionManagerPresenterImpl.kt | 64 -- .../settings/ConnectionManagerView.kt | 11 - .../settings/ConnectionManagerViewModel.kt | 77 +++ .../mbrc/features/settings/ConnectionModel.kt | 6 - .../features/settings/ConnectionRepository.kt | 14 +- .../settings/ConnectionRepositoryImpl.kt | 145 ++--- .../features/settings/ConnectionSettings.kt | 57 +- .../features/settings/SettingsActivity.kt | 6 +- .../settings/SettingsDialogFragment.kt | 19 +- .../features/settings/SettingsFragment.kt | 21 +- .../features/settings/SettingsManagerImpl.kt | 9 +- .../mbrc/features/settings/WebViewDialog.kt | 5 +- .../mbrc/features/widgets/BundleData.kt | 10 +- .../mbrc/features/widgets/WidgetBase.kt | 8 +- .../mbrc/features/widgets/WidgetNormal.kt | 4 +- .../mbrc/features/widgets/WidgetSmall.kt | 4 +- .../mbrc/features/widgets/WidgetUpdater.kt | 17 +- .../java/com/kelsos/mbrc/logging/LogHelper.kt | 116 ++-- .../mbrc/networking/ActiveConnection.kt | 5 +- .../com/kelsos/mbrc/networking/ApiBase.kt | 61 +- .../com/kelsos/mbrc/networking/ApiStatus.kt | 6 + .../mbrc/networking/RequestManagerImpl.kt | 103 ++-- .../mbrc/networking/SocketActivityChecker.kt | 76 ++- .../client/ClientConnectionManager.kt | 236 ++++++++ .../networking/client/ConnectivityVerifier.kt | 45 ++ .../client/ConnectivityVerifierImpl.kt | 39 -- .../networking/client/GenericSocketMessage.kt | 12 +- .../mbrc/networking/client/MessageHandler.kt | 166 ++++++ .../mbrc/networking/client/MessageQueue.kt | 25 + .../mbrc/networking/client/SocketMessage.kt | 39 +- .../mbrc/networking/client/SocketService.kt | 239 -------- .../mbrc/networking/client/UiMessageQueue.kt | 21 + .../connections/ConnectionMapper.kt | 19 +- .../connections/InetAddressMapper.kt | 4 +- .../networking/discovery/DiscoveryMessage.kt | 31 +- .../networking/discovery/DiscoveryStop.kt | 14 +- .../discovery/RemoteServiceDiscovery.kt | 277 ++++----- .../networking/protocol/CommandFactory.kt | 46 ++ .../protocol/CommandRegistration.kt | 145 ----- .../mbrc/networking/protocol/MessageEvent.kt | 8 + .../protocol/NowPlayingMoveRequest.kt | 10 +- .../protocol/NowPlayingMoveResponse.kt | 14 + .../protocol/NowPlayingTrackRemoveResponse.kt | 12 + .../kelsos/mbrc/networking/protocol/Page.kt | 16 +- .../mbrc/networking/protocol/PageRange.kt | 12 +- .../mbrc/networking/protocol/Position.kt | 12 + .../mbrc/networking/protocol/Protocol.kt | 155 ++++- .../networking/protocol/ProtocolAction.kt | 2 +- .../networking/protocol/ProtocolActions.kt | 560 ++++++++---------- .../networking/protocol/ProtocolHandler.kt | 78 --- .../networking/protocol/ProtocolMessage.kt | 4 +- .../networking/protocol/ProtocolPayload.kt | 18 +- .../networking/protocol/RemoteController.kt | 72 --- .../mbrc/networking/protocol/UserAction.kt | 17 + .../networking/protocol/UserActionUseCase.kt | 49 ++ .../protocol/UserActionUseCaseImpl.kt | 26 + .../protocol/VolumeModifyUseCase.kt | 21 + .../protocol/VolumeModifyUseCaseImpl.kt | 81 +++ .../mbrc/platform/RemoteBroadcastReceiver.kt | 29 +- .../com/kelsos/mbrc/platform/RemoteService.kt | 106 +--- .../AppNotificationManagerImpl.kt | 217 +++++++ .../mediasession/MediaIntentHandler.kt | 27 +- .../platform/mediasession/NotificationData.kt | 11 + .../mediasession/NotificationModel.kt | 10 +- .../mediasession/RemoteSessionManager.kt | 159 ++--- .../mediasession/RemoteVolumeProvider.kt | 66 ++- .../SessionNotificationManager.kt | 180 ------ .../main/res/layout/activity_album_tracks.xml | 75 +-- .../res/layout/activity_artist_albums.xml | 4 +- .../res/layout/activity_genre_artists.xml | 2 +- app/src/main/res/layout/empty_list.xml | 5 +- .../layout/ui_activity_connection_manager.xml | 8 +- app/src/main/res/values/strings.xml | 5 + .../library/LibrarySyncUseCaseImplTest.kt | 13 +- .../client/ConnectivityVerifierImplTest.kt | 16 +- gradle/libs.versions.toml | 46 +- 358 files changed, 8416 insertions(+), 8974 deletions(-) create mode 100644 app/schemas/com.kelsos.mbrc.data.Database/3.json delete mode 100644 app/src/main/java/com/kelsos/mbrc/annotations/PlayerState.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/annotations/Queue.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/annotations/Repeat.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/annotations/Search.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/annotations/SocketAction.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/CancelNotificationCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/ConnectionStatusChangedCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/HandleHandshake.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/InitiateConnectionCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/KeyVolumeDownCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/KeyVolumeUpCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/ProcessUserAction.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/ProtocolRequest.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/ReduceVolumeOnRingCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/RestartConnectionCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/SocketDataAvailableCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/StartDiscoveryCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/TerminateConnectionCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/TerminateServiceCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/visual/HandshakeCompletionActions.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/commands/visual/NotifyNotAllowedCommand.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/common/data/LocalDataSource.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/common/data/RemoteDataSource.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/common/mvp/BasePresenter.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/common/mvp/BaseView.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/common/mvp/Presenter.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/mvvm/BaseViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/AppState.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/AppStateManager.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/ConnectionModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/ConnectionState.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/ConnectionStatus.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/LfmRating.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/MainDataModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/NowPlayingTrack.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/PlayerState.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/PlayerStatus.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/PlayerStatusModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/PlayingPosition.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/PlayingTrack.kt rename app/src/main/java/com/kelsos/mbrc/{features/player/ModelCache.kt => common/state/PlayingTrackCache.kt} (60%) create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/Repeat.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/ShuffleMode.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/common/state/TrackRating.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/data/Data.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/data/DeserializationAdapter.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/data/SerializationAdapter.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/data/UserAction.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/DefaultSettingsChangedEvent.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/MessageEvent.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/bus/RxBus.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/bus/RxBusImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/ConnectionSettingsChanged.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/CoverChangedEvent.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/DiscoveryStopped.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/LfmRatingChanged.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/LyricsUpdatedEvent.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/PlayStateChange.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/RatingChanged.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/RemoteClientMetaData.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/RepeatChange.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/RequestConnectionStateEvent.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/ScrobbleChange.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/ShuffleChange.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/TrackInfoChangeEvent.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/TrackMoved.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/TrackRemoval.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/UpdateDuration.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/events/ui/VolumeChange.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/extensions/EnableHome.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/extensions/FileExtensions.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/extensions/StringExtensions.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/Album.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/AlbumEntryAdapter.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/AlbumRepository.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/AlbumRepositoryImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/AlbumTracksActivity.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/AlbumTracksContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/AlbumTracksPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/Artist.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/ArtistAlbumsActivity.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/ArtistAlbumsContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/ArtistAlbumsPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/ArtistEntryAdapter.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/ArtistRepository.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/ArtistRepositoryImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BaseBrowseFragment.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BaseDetailsActivity.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BaseLibraryViewModel.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseAlbumContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseAlbumFragment.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseAlbumPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseArtistContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseArtistFragment.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseArtistPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseGenreContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseGenreFragment.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseGenrePresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseTrackContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseTrackFragment.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/BrowseTrackPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/CachedAlbumInfo.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/CoverInfo.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/Extras.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/Genre.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/GenreArtistsActivity.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/GenreArtistsContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/GenreArtistsPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/GenreEntryAdapter.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/GenreRepository.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/GenreRepositoryImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/LibraryContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/LibraryPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/LocalAlbumDataSource.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/LocalArtistDataSource.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/LocalArtistDataSourceImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/LocalGenreDataSource.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/LocalTrackDataSource.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/PagePosition.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/PopupMenu.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/RemoteAlbumDataSource.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/RemoteArtistDataSource.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/RemoteGenreDataSource.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/RemoteTrackDataSource.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/Track.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/TrackEntryAdapter.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/TrackRepository.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/TrackRepositoryImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/Actions.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/Album.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/AlbumCover.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/AlbumDao.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/AlbumEntryAdapter.kt rename app/src/main/java/com/kelsos/mbrc/features/library/{ => albums}/AlbumInfo.kt (94%) create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/AlbumRepository.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/AlbumUiMessage.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/ArtistAlbumsActivity.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/ArtistAlbumsViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/BaseAlbumViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/BrowseAlbumFragment.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/BrowseAlbumViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/albums/Mappers.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/Actions.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/Artist.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/ArtistDao.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/ArtistEntryAdapter.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/ArtistRepository.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/ArtistUiMessage.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/BaseArtistViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/BrowseArtistFragment.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/BrowseArtistViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/GenreArtistsActivity.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/GenreArtistsViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/artists/Mappers.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/genres/Actions.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/genres/BrowseGenreFragment.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/genres/BrowseGenreViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/genres/Genre.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/genres/GenreDao.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/genres/GenreEntryAdapter.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/genres/GenreRepository.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/genres/GenreUiMessage.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/genres/Mappers.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/Actions.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/AlbumTracksActivity.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/AlbumTracksViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/BaseTrackViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/BrowseTrackFragment.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/BrowseTrackViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/Mappers.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/Track.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/TrackDao.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/TrackEntryAdapter.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/TrackRepository.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/TrackRepositoryImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/library/tracks/TrackUiMessage.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/lyrics/LyricsContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/lyrics/LyricsModel.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/lyrics/LyricsPresenterImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/lyrics/LyricsViewModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/minicontrol/MiniControlAction.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/minicontrol/MiniControlContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/minicontrol/MiniControlPresenterImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/minicontrol/MiniControlViewModel.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/LocalNowPlayingDataSource.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/Mappers.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/MoveManager.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/MoveManagerImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/NowPlayingContract.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/NowPlayingDao.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/NowPlayingPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/NowPlayingRepositoryImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/NowPlayingUiMessages.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/NowPlayingViewModel.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/RemoteNowPlayingDataSource.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/nowplaying/VisibleRange.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/IsEmpty.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/ModelInitializer.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/PlayerAction.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/PlayerContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/PlayerStateSerializer.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/PlayerUiMessage.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/PlayerViewModel.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/PlayerViewPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/ProgressSeekerHelper.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/RatingDialogViewModel.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/SeekBarThrottler.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/player/TrackInfo.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/playlists/LocalPlaylistDataSource.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/playlists/Mappers.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/playlists/PlaylistContract.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/playlists/PlaylistDao.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/playlists/PlaylistPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/playlists/PlaylistRepositoryImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/playlists/PlaylistViewModel.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/playlists/RemotePlaylistDataSource.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/queue/PopupActionHandler.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/queue/Queue.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/radio/LocalRadioDataSource.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/radio/Mappers.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/radio/RadioContract.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/radio/RadioPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/radio/RadioRepositoryImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/radio/RadioStationDao.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/radio/RadioViewModel.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/radio/RemoteRadioDataSource.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/settings/ClientInformationStore.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/settings/ConnectionDao.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/settings/ConnectionManagerPresenter.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/settings/ConnectionManagerPresenterImpl.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/settings/ConnectionManagerView.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/features/settings/ConnectionManagerViewModel.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/features/settings/ConnectionModel.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/ApiStatus.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/client/ClientConnectionManager.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/networking/client/ConnectivityVerifierImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/client/MessageHandler.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/client/MessageQueue.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/networking/client/SocketService.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/client/UiMessageQueue.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/CommandFactory.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/CommandRegistration.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/MessageEvent.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/NowPlayingMoveResponse.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/NowPlayingTrackRemoveResponse.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/Position.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/ProtocolHandler.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/RemoteController.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/UserAction.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/UserActionUseCase.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/UserActionUseCaseImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/VolumeModifyUseCase.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/networking/protocol/VolumeModifyUseCaseImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/platform/mediasession/AppNotificationManagerImpl.kt create mode 100644 app/src/main/java/com/kelsos/mbrc/platform/mediasession/NotificationData.kt delete mode 100644 app/src/main/java/com/kelsos/mbrc/platform/mediasession/SessionNotificationManager.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e71f2f497..2dcf0f060 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -98,6 +98,10 @@ android { buildConfigField("String", "BUILD_TIME", "\"${buildTime()}\"") testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + ksp { + arg("room.schemaLocation", "$projectDir/schemas") + } } testOptions { @@ -205,18 +209,6 @@ dependencies { implementation(projects.changelog) - testImplementation(libs.androidx.arch.core.testing) - testImplementation(libs.androidx.test.core) - testImplementation(libs.androidx.test.runner) - testImplementation(libs.androidx.test.junit) - testImplementation(libs.androidx.test.truth) - testImplementation(libs.bundles.androidx.test.espresso) - testImplementation(libs.truth) - testImplementation(libs.koin.test) - testImplementation(libs.kotlin.coroutines.test) - testImplementation(libs.mockk) - testImplementation(libs.robolectric) - implementation(libs.androidx.annotation) implementation(libs.androidx.appcompat) implementation(libs.androidx.core.ktx) @@ -233,23 +225,30 @@ dependencies { implementation(libs.androidx.legacy.support.v4) implementation(libs.androidx.legacy.support.v13) implementation(libs.bundles.coroutines) + implementation(libs.bundles.androidx.room) implementation(libs.bundles.coil) implementation(libs.bundles.koin) implementation(libs.google.material) implementation(libs.google.protobuf.javalite) + implementation(libs.squareup.moshi.lib) implementation(libs.squareup.okio) implementation(libs.timber) - implementation(libs.bundles.dbflow) - implementation(libs.bundles.jackson) - implementation(libs.kotlin.stdlib) - implementation(libs.kotlin.reflect) - implementation(libs.rxandroid) - implementation(libs.rxjava) - implementation(libs.rxkotlin) - implementation(libs.rxrelay) + ksp(libs.androidx.room.compiler) + ksp(libs.squareup.moshi.codegen) - kapt(libs.dbflow.processor) + testImplementation(libs.androidx.arch.core.testing) + testImplementation(libs.androidx.room.testing) + testImplementation(libs.androidx.test.core) + testImplementation(libs.androidx.test.runner) + testImplementation(libs.androidx.test.junit) + testImplementation(libs.androidx.test.truth) + testImplementation(libs.bundles.androidx.test.espresso) + testImplementation(libs.truth) + testImplementation(libs.koin.test) + testImplementation(libs.kotlin.coroutines.test) + testImplementation(libs.mockk) + testImplementation(libs.robolectric) debugImplementation(libs.squareup.leakcanary) debugImplementation(libs.androidx.fragment.testing) @@ -365,7 +364,8 @@ tasks { doLast { if (!project.file("google-services.json").exists()) { throw GradleException( - "You need a google-services.json file to run this project. Please refer to the CONTRIBUTING.md file for details." + "You need a google-services.json file to run this project." + + " Please refer to the CONTRIBUTING.md file for details." ) } } @@ -379,12 +379,6 @@ tasks { } } -kotlin { - sourceSets.all { - languageSettings.enableLanguageFeature("ExplicitBackingFields") - } -} - configurations.all { resolutionStrategy { force("com.google.code.findbugs:jsr305:3.0.2") diff --git a/app/schemas/com.kelsos.mbrc.data.Database/3.json b/app/schemas/com.kelsos.mbrc.data.Database/3.json new file mode 100644 index 000000000..db36f22cb --- /dev/null +++ b/app/schemas/com.kelsos.mbrc.data.Database/3.json @@ -0,0 +1,378 @@ +{ + "formatVersion": 1, + "database": { + "version": 3, + "identityHash": "b169004076611f9b3ad422f67163745c", + "entities": [ + { + "tableName": "genre", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`genre` TEXT, `count` INTEGER, `date_added` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT)", + "fields": [ + { + "fieldPath": "genre", + "columnName": "genre", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "dateAdded", + "columnName": "date_added", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "artist", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`artist` TEXT, `count` INTEGER, `date_added` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT)", + "fields": [ + { + "fieldPath": "artist", + "columnName": "artist", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "dateAdded", + "columnName": "date_added", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "album", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`artist` TEXT, `album` TEXT, `cover` TEXT, `date_added` INTEGER, `count` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT)", + "fields": [ + { + "fieldPath": "artist", + "columnName": "artist", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "album", + "columnName": "album", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "cover", + "columnName": "cover", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateAdded", + "columnName": "date_added", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "track", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`artist` TEXT, `title` TEXT, `src` TEXT, `trackno` INTEGER, `disc` INTEGER, `album_artist` TEXT, `album` TEXT, `genre` TEXT, `date_added` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT)", + "fields": [ + { + "fieldPath": "artist", + "columnName": "artist", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "src", + "columnName": "src", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "trackno", + "columnName": "trackno", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "disc", + "columnName": "disc", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "albumArtist", + "columnName": "album_artist", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "album", + "columnName": "album", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "genre", + "columnName": "genre", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateAdded", + "columnName": "date_added", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "now_playing", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`title` TEXT, `artist` TEXT, `path` TEXT, `position` INTEGER, `date_added` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT)", + "fields": [ + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "artist", + "columnName": "artist", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "dateAdded", + "columnName": "date_added", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "playlists", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT, `url` TEXT, `date_added` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT)", + "fields": [ + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateAdded", + "columnName": "date_added", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "radio_station", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT, `url` TEXT, `date_added` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT)", + "fields": [ + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateAdded", + "columnName": "date_added", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "settings", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`address` TEXT, `port` INTEGER, `name` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT)", + "fields": [ + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "port", + "columnName": "port", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'b169004076611f9b3ad422f67163745c')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8e7ec56eb..bdb498d80 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -53,11 +53,11 @@ android:value=".features.player.PlayerActivity" /> - + - + - + () } - single { ObjectMapper().registerKotlinModule() } - + single { Moshi.Builder().build() } singleOf(::LibrarySyncUseCaseImpl) { bind() } singleOf(::ApiBase) singleOf(::RequestManagerImpl) { bind() } @@ -186,7 +152,6 @@ val appModule = singleOf(::GenreRepositoryImpl) { bind() } singleOf(::ArtistRepositoryImpl) { bind() } - singleOf(::LocalArtistDataSourceImpl) { bind() } singleOf(::AlbumRepositoryImpl) { bind() } singleOf(::TrackRepositoryImpl) { bind() } @@ -195,21 +160,6 @@ val appModule = singleOf(::RadioRepositoryImpl) { bind() } singleOf(::ConnectionRepositoryImpl) { bind() } - singleOf(::LocalGenreDataSource) - singleOf(::RemoteGenreDataSource) - singleOf(::LocalArtistDataSourceImpl) { bind() } - singleOf(::RemoteArtistDataSource) - singleOf(::LocalAlbumDataSource) - singleOf(::RemoteAlbumDataSource) - singleOf(::LocalTrackDataSource) - singleOf(::RemoteTrackDataSource) - singleOf(::LocalPlaylistDataSource) - singleOf(::RemotePlaylistDataSource) - singleOf(::LocalNowPlayingDataSource) - singleOf(::RemoteNowPlayingDataSource) - singleOf(::LocalRadioDataSource) - singleOf(::RemoteRadioDataSource) - singleOf(::GenreEntryAdapter) singleOf(::ArtistEntryAdapter) @@ -222,26 +172,28 @@ val appModule = singleOf(::RemoteBroadcastReceiver) singleOf(::SettingsManagerImpl) { bind() } singleOf(::ServiceCheckerImpl) { bind() } - singleOf(::ModelCacheImpl) { bind() } - singleOf(::MainDataModel) - singleOf(::ModelInitializer) - singleOf(::ConnectionModel) - singleOf(::LyricsModel) - singleOf(::RemoteController) - singleOf(::SocketService) + singleOf(::PlayingTrackCacheImpl) { bind() } singleOf(::SocketActivityChecker) singleOf(::CoverCache) - singleOf(::ProtocolHandler) singleOf(::NotificationModel) + singleOf(::AppNotificationManagerImpl) { bind() } + singleOf(::CommandFactoryImpl) { bind() } + singleOf(::UserActionUseCaseImpl) { bind() } + singleOf(::VolumeModifyUseCaseImpl) { bind() } + singleOf(::AppStateManager) + singleOf(::AppState) + singleOf(::ClientConnectionManagerImpl) { bind() } + singleOf(::ClientInformationStoreImpl) { bind() } + singleOf(::MessageHandlerImpl) { bind() } + singleOf(::MessageQueueImpl) { bind() } + singleOf(::UiMessageQueueImpl) { bind() } + singleOf(::ConnectionState) + singleOf(::SerializationAdapterImpl) { bind() } + singleOf(::DeserializationAdapterImpl) { bind() } factoryOf(::BasicSettingsHelper) - factoryOf(::ReduceVolumeOnRingCommand) - factoryOf(::HandshakeCompletionActions) - factoryOf(::NotifyNotAllowedCommand) - factoryOf(::ProtocolRequest) factoryOf(::VersionCheckCommand) - factoryOf(::ProcessUserAction) factoryOf(::UpdateNowPlayingTrack) factoryOf(::UpdateCover) factoryOf(::UpdateRating) @@ -260,27 +212,12 @@ val appModule = factoryOf(::UpdatePluginVersionCommand) factoryOf(::ProtocolPingHandle) factoryOf(::SimpleLogCommand) - factoryOf(::RestartConnectionCommand) - factoryOf(::CancelNotificationCommand) - factoryOf(::SessionNotificationManager) factoryOf(::RemoteSessionManager) factoryOf(::RemoteVolumeProvider) - factoryOf(::InitiateConnectionCommand) - factoryOf(::TerminateConnectionCommand) - factoryOf(::StartDiscoveryCommand) - factoryOf(::RemoteServiceDiscovery) - factoryOf(::KeyVolumeUpCommand) - factoryOf(::KeyVolumeDownCommand) - factoryOf(::SocketDataAvailableCommand) - factoryOf(::ConnectionStatusChangedCommand) - factoryOf(::HandleHandshake) - factoryOf(::TerminateServiceCommand) + factoryOf(::RemoteServiceDiscoveryImpl) { bind() } singleOf(::WidgetUpdaterImpl) { bind() } - single(named("main")) { AndroidSchedulers.mainThread() } - single(named("io")) { Schedulers.io() } - single { val database = Executors @@ -304,83 +241,94 @@ val appModule = ) } - singleOf(::ArtistAlbumsPresenterImpl) { bind() } + single { + Room + .databaseBuilder(get(), Database::class.java, Database.NAME) + .build() + } + single { get().genreDao() } + single { get().artistDao() } + single { get().albumDao() } + single { get().trackDao() } + single { get().nowPlayingDao() } + single { get().playlistDao() } + single { get().radioStationDao() } + single { get().connectionDao() } scope { - scopedOf(::MiniControlPresenterImpl) { bind() } + viewModelOf(::MiniControlViewModel) } scope { - scopedOf(::PlayerViewPresenterImpl) { bind() } - scoped { ProgressSeekerHelper(get(named("main"))) } + viewModelOf(::PlayerViewModel) } scope { - scopedOf(::LyricsPresenterImpl) { bind() } + viewModelOf(::LyricsViewModel) } scope { - scopedOf(::LibraryPresenterImpl) { bind() } scopedOf(::LibrarySearchModel) - scopedOf(::PopupActionHandler) } scope { - scopedOf(::BrowseGenrePresenterImpl) { bind() } + viewModelOf(::BrowseGenreViewModel) scopedOf(::GenreEntryAdapter) } scope { - scopedOf(::BrowseArtistPresenterImpl) { bind() } + viewModelOf(::BrowseArtistViewModel) scopedOf(::ArtistEntryAdapter) } scope { - scopedOf(::BrowseAlbumPresenterImpl) { bind() } + viewModelOf(::BrowseAlbumViewModel) scopedOf(::AlbumEntryAdapter) } scope { - scopedOf(::BrowseTrackPresenterImpl) { bind() } + viewModelOf(::BrowseTrackViewModel) scopedOf(::TrackEntryAdapter) } scope { - scopedOf(::GenreArtistsPresenterImpl) { bind() } + viewModelOf(::GenreArtistsViewModel) scopedOf(::ArtistEntryAdapter) - scopedOf(::PopupActionHandler) } scope { - scopedOf(::ArtistAlbumsPresenterImpl) { bind() } + viewModelOf(::ArtistAlbumsViewModel) scopedOf(::AlbumEntryAdapter) - scopedOf(::PopupActionHandler) } scope { - scopedOf(::AlbumTracksPresenterImpl) { bind() } + viewModelOf(::AlbumTracksViewModel) scopedOf(::TrackEntryAdapter) - scopedOf(::PopupActionHandler) } scope { - scopedOf(::NowPlayingPresenterImpl) { bind() } + viewModelOf(::NowPlayingViewModel) scopedOf(::NowPlayingAdapter) + scopedOf(::MoveManagerImpl) { bind() } } scope { - scopedOf(::PlaylistPresenterImpl) { bind() } + viewModelOf(::PlaylistViewModel) scopedOf(::PlaylistAdapter) } scope { - scopedOf(::ConnectionManagerPresenterImpl) { bind() } + viewModelOf(::ConnectionManagerViewModel) } scope { - scopedOf(::RadioPresenterImpl) { bind() } + viewModelOf(::RadioViewModel) scopedOf(::RadioAdapter) } + scope { + viewModelOf(::RatingDialogViewModel) + } + viewModelOf(::OutputSelectionViewModel) } diff --git a/app/src/main/java/com/kelsos/mbrc/BaseActivity.kt b/app/src/main/java/com/kelsos/mbrc/BaseActivity.kt index 412cb7c3c..0721603d0 100644 --- a/app/src/main/java/com/kelsos/mbrc/BaseActivity.kt +++ b/app/src/main/java/com/kelsos/mbrc/BaseActivity.kt @@ -21,12 +21,8 @@ import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.navigation.NavigationView import com.google.android.material.snackbar.Snackbar import com.kelsos.mbrc.annotations.Connection -import com.kelsos.mbrc.constants.UserInputEventType -import com.kelsos.mbrc.events.MessageEvent -import com.kelsos.mbrc.events.bus.RxBus import com.kelsos.mbrc.events.ui.ConnectionStatusChangeEvent import com.kelsos.mbrc.events.ui.NotifyUser -import com.kelsos.mbrc.events.ui.RequestConnectionStateEvent import com.kelsos.mbrc.features.help.HelpFeedbackActivity import com.kelsos.mbrc.features.library.LibraryActivity import com.kelsos.mbrc.features.lyrics.LyricsActivity @@ -47,7 +43,6 @@ private const val NAVIGATION_DELAY = 250L abstract class BaseActivity : ScopeActivity(), NavigationView.OnNavigationItemSelectedListener { - private val bus: RxBus by inject() private val serviceChecker: ServiceChecker by inject() private lateinit var toolbar: MaterialToolbar @@ -65,14 +60,12 @@ abstract class BaseActivity : private fun onConnectLongClick(): Boolean { Timber.v("Connect long pressed") serviceChecker.startServiceIfNotRunning() - bus.post(MessageEvent(UserInputEventType.RESET_CONNECTION)) return true } protected fun onConnectClick() { Timber.v("Attempting to connect") serviceChecker.startServiceIfNotRunning() - bus.post(MessageEvent(UserInputEventType.START_CONNECTION)) } override fun onDestroy() { @@ -140,12 +133,12 @@ abstract class BaseActivity : val result = when (keyCode) { KeyEvent.KEYCODE_VOLUME_UP -> { - bus.post(MessageEvent(UserInputEventType.KEY_VOLUME_UP)) + // TODO: handle true } KeyEvent.KEYCODE_VOLUME_DOWN -> { - bus.post(MessageEvent(UserInputEventType.KEY_VOLUME_DOWN)) + // TODO: Handle true } @@ -263,23 +256,6 @@ abstract class BaseActivity : serviceChecker.startServiceIfNotRunning() } - override fun onResume() { - super.onResume() - this.bus.register(this, NotifyUser::class.java, { this.handleUserNotification(it) }, true) - this.bus.register( - this, - ConnectionStatusChangeEvent::class.java, - { this.onConnection(it) }, - true, - ) - this.bus.post(RequestConnectionStateEvent()) - } - - override fun onPause() { - super.onPause() - this.bus.unregister(this) - } - companion object { const val EXIT_APP = "mbrc.exit" } diff --git a/app/src/main/java/com/kelsos/mbrc/UpdateRequiredActivity.kt b/app/src/main/java/com/kelsos/mbrc/UpdateRequiredActivity.kt index 4e73e4220..006e30806 100644 --- a/app/src/main/java/com/kelsos/mbrc/UpdateRequiredActivity.kt +++ b/app/src/main/java/com/kelsos/mbrc/UpdateRequiredActivity.kt @@ -17,12 +17,12 @@ class UpdateRequiredActivity : AppCompatActivity() { window.sharedElementEnterTransition = MaterialContainerTransform().apply { addTarget(android.R.id.content) - duration = 300L + duration = ENTER_DURATION } window.sharedElementReturnTransition = MaterialContainerTransform().apply { addTarget(android.R.id.content) - duration = 250L + duration = RETURN_DURATION } super.onCreate(savedInstanceState) setContentView(R.layout.activity_update_required) @@ -36,5 +36,7 @@ class UpdateRequiredActivity : AppCompatActivity() { companion object { const val VERSION: String = "version" + const val ENTER_DURATION = 300L + const val RETURN_DURATION = 250L } } diff --git a/app/src/main/java/com/kelsos/mbrc/annotations/PlayerState.kt b/app/src/main/java/com/kelsos/mbrc/annotations/PlayerState.kt deleted file mode 100644 index c022e4271..000000000 --- a/app/src/main/java/com/kelsos/mbrc/annotations/PlayerState.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.kelsos.mbrc.annotations - -import androidx.annotation.StringDef - -object PlayerState { - const val PLAYING = "playing" - const val PAUSED = "paused" - const val STOPPED = "stopped" - const val UNDEFINED = "undefined" - - @Retention(AnnotationRetention.SOURCE) - @StringDef(PAUSED, PLAYING, STOPPED, UNDEFINED) - annotation class State -} // no instance diff --git a/app/src/main/java/com/kelsos/mbrc/annotations/Queue.kt b/app/src/main/java/com/kelsos/mbrc/annotations/Queue.kt deleted file mode 100644 index 7cf089bc5..000000000 --- a/app/src/main/java/com/kelsos/mbrc/annotations/Queue.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.kelsos.mbrc.annotations - -import androidx.annotation.StringDef - -object Queue { - @StringDef(NEXT, LAST, NOW, ADD_ALL, PROFILE) - @Retention(AnnotationRetention.SOURCE) - annotation class Action - - const val PROFILE = "profile" - const val NEXT = "next" - const val LAST = "last" - const val NOW = "now" - const val ADD_ALL = "add-all" - const val PLAY_ALBUM = "play-album" - const val PLAY_ARTIST = "play-artist" -} diff --git a/app/src/main/java/com/kelsos/mbrc/annotations/Repeat.kt b/app/src/main/java/com/kelsos/mbrc/annotations/Repeat.kt deleted file mode 100644 index 52fbb5ff1..000000000 --- a/app/src/main/java/com/kelsos/mbrc/annotations/Repeat.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.kelsos.mbrc.annotations - -import androidx.annotation.StringDef - -object Repeat { - const val ALL = "all" - const val NONE = "none" - const val ONE = "one" - - @StringDef(ALL, NONE, ONE) - @Retention(AnnotationRetention.SOURCE) - annotation class Mode -} diff --git a/app/src/main/java/com/kelsos/mbrc/annotations/Search.kt b/app/src/main/java/com/kelsos/mbrc/annotations/Search.kt deleted file mode 100644 index 5c3f515ab..000000000 --- a/app/src/main/java/com/kelsos/mbrc/annotations/Search.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.kelsos.mbrc.annotations - -object Search { - const val SECTION_GENRE = 0 - const val SECTION_ARTIST = 1 - const val SECTION_ALBUM = 2 - const val SECTION_TRACK = 3 -} diff --git a/app/src/main/java/com/kelsos/mbrc/annotations/SocketAction.kt b/app/src/main/java/com/kelsos/mbrc/annotations/SocketAction.kt deleted file mode 100644 index 5aa21e018..000000000 --- a/app/src/main/java/com/kelsos/mbrc/annotations/SocketAction.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.kelsos.mbrc.annotations - -import androidx.annotation.IntDef - -object SocketAction { - const val RESET = 1 - const val START = 2 - const val RETRY = 3 - const val TERMINATE = 4 - const val STOP = 5 - - @Retention(AnnotationRetention.SOURCE) - @IntDef(RESET, START, RETRY, TERMINATE, STOP) - annotation class Action - - fun name( - @Action action: Int, - ): String = - when (action) { - RESET -> "Reset" - START -> "Start" - RETRY -> "Retry" - TERMINATE -> "Terminate" - STOP -> "Stop" - else -> throw IllegalArgumentException("action $action is not recognised") - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/CancelNotificationCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/CancelNotificationCommand.kt deleted file mode 100644 index 5cc5648f1..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/CancelNotificationCommand.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage -import com.kelsos.mbrc.platform.mediasession.SessionNotificationManager - -class CancelNotificationCommand( - private val sessionNotificationManager: SessionNotificationManager, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - sessionNotificationManager.cancelNotification(SessionNotificationManager.NOW_PLAYING_PLACEHOLDER) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/ConnectionStatusChangedCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/ConnectionStatusChangedCommand.kt deleted file mode 100644 index 02a9f8cdb..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/ConnectionStatusChangedCommand.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.common.state.ConnectionModel -import com.kelsos.mbrc.networking.client.SocketMessage -import com.kelsos.mbrc.networking.client.SocketService -import com.kelsos.mbrc.networking.protocol.Protocol -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage -import com.kelsos.mbrc.platform.mediasession.SessionNotificationManager - -class ConnectionStatusChangedCommand( - private val model: ConnectionModel, - private val service: SocketService, - private val sessionNotificationManager: SessionNotificationManager, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - model.setConnectionState(message.dataString) - - if (model.isConnectionActive) { - service.sendData(SocketMessage.create(Protocol.PLAYER, "Android")) - } else { - sessionNotificationManager.cancelNotification(SessionNotificationManager.NOW_PLAYING_PLACEHOLDER) - } - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/HandleHandshake.kt b/app/src/main/java/com/kelsos/mbrc/commands/HandleHandshake.kt deleted file mode 100644 index 7622dd412..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/HandleHandshake.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.common.state.ConnectionModel -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolHandler -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -class HandleHandshake( - private val handler: ProtocolHandler, - private val model: ConnectionModel, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - if (!(message.data as Boolean)) { - handler.resetHandshake() - model.setHandShakeDone(false) - } - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/InitiateConnectionCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/InitiateConnectionCommand.kt deleted file mode 100644 index 584d64b0a..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/InitiateConnectionCommand.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.annotations.SocketAction.START -import com.kelsos.mbrc.networking.client.SocketService -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -class InitiateConnectionCommand( - private val socketService: SocketService, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - socketService.socketManager(START) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/KeyVolumeDownCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/KeyVolumeDownCommand.kt deleted file mode 100644 index 5b3cc7a73..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/KeyVolumeDownCommand.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.common.state.MainDataModel -import com.kelsos.mbrc.data.UserAction -import com.kelsos.mbrc.events.MessageEvent -import com.kelsos.mbrc.events.bus.RxBus -import com.kelsos.mbrc.networking.protocol.Protocol -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -class KeyVolumeDownCommand( - private val model: MainDataModel, - private val bus: RxBus, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - if (model.volume >= 10) { - val mod = model.volume % 10 - val volume: Int - - if (mod == 0) { - volume = model.volume - 10 - } else if (mod < 5) { - volume = model.volume - (10 + mod) - } else { - volume = model.volume - mod - } - - bus.post(MessageEvent.action(UserAction(Protocol.PLAYER_VOLUME, volume))) - } - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/KeyVolumeUpCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/KeyVolumeUpCommand.kt deleted file mode 100644 index 9ec372b0c..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/KeyVolumeUpCommand.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.common.state.MainDataModel -import com.kelsos.mbrc.data.UserAction -import com.kelsos.mbrc.events.MessageEvent -import com.kelsos.mbrc.events.bus.RxBus -import com.kelsos.mbrc.networking.protocol.Protocol -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -class KeyVolumeUpCommand( - private val model: MainDataModel, - private val bus: RxBus, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - val volume: Int = - if (model.volume <= 90) { - val mod = model.volume % 10 - - when { - mod == 0 -> model.volume + 10 - mod < 5 -> model.volume + (10 - mod) - else -> model.volume + (20 - mod) - } - } else { - 100 - } - - bus.post(MessageEvent.action(UserAction(Protocol.PLAYER_VOLUME, volume))) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/ProcessUserAction.kt b/app/src/main/java/com/kelsos/mbrc/commands/ProcessUserAction.kt deleted file mode 100644 index a99117302..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/ProcessUserAction.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.data.UserAction -import com.kelsos.mbrc.networking.client.SocketMessage -import com.kelsos.mbrc.networking.client.SocketService -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -class ProcessUserAction( - private val socket: SocketService, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - socket.sendData( - SocketMessage.create( - (message.data as UserAction).context, - (message.data as UserAction).data, - ), - ) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/ProtocolRequest.kt b/app/src/main/java/com/kelsos/mbrc/commands/ProtocolRequest.kt deleted file mode 100644 index 022415a10..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/ProtocolRequest.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.networking.client.SocketMessage -import com.kelsos.mbrc.networking.client.SocketService -import com.kelsos.mbrc.networking.protocol.Protocol -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage -import com.kelsos.mbrc.networking.protocol.ProtocolPayload - -class ProtocolRequest( - private val socket: SocketService, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - val payload = ProtocolPayload() - payload.noBroadcast = false - payload.protocolVersion = Protocol.PROTOCOL_VERSION_NUMBER - socket.sendData(SocketMessage.create(Protocol.PROTOCOL_TAG, payload)) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/ReduceVolumeOnRingCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/ReduceVolumeOnRingCommand.kt deleted file mode 100644 index 087811f1b..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/ReduceVolumeOnRingCommand.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.common.state.MainDataModel -import com.kelsos.mbrc.networking.client.SocketMessage -import com.kelsos.mbrc.networking.client.SocketService -import com.kelsos.mbrc.networking.protocol.Protocol -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -class ReduceVolumeOnRingCommand( - private val model: MainDataModel, - private val service: SocketService, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - if (model.isMute || model.volume == 0) { - return - } - service.sendData(SocketMessage.create(Protocol.PLAYER_VOLUME, (model.volume * 0.2).toInt())) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/RestartConnectionCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/RestartConnectionCommand.kt deleted file mode 100644 index cfde4f318..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/RestartConnectionCommand.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.annotations.SocketAction.RESET -import com.kelsos.mbrc.networking.client.SocketService -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -class RestartConnectionCommand( - private val socket: SocketService, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - socket.socketManager(RESET) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/SocketDataAvailableCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/SocketDataAvailableCommand.kt deleted file mode 100644 index 99948733a..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/SocketDataAvailableCommand.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolHandler -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -class SocketDataAvailableCommand( - private val handler: ProtocolHandler, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - handler.preProcessIncoming(message.dataString) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/StartDiscoveryCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/StartDiscoveryCommand.kt deleted file mode 100644 index ab3625ba3..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/StartDiscoveryCommand.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.networking.discovery.RemoteServiceDiscovery -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -class StartDiscoveryCommand( - private val discovery: RemoteServiceDiscovery, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - discovery.startDiscovery() - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/TerminateConnectionCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/TerminateConnectionCommand.kt deleted file mode 100644 index 8c890c834..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/TerminateConnectionCommand.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.kelsos.mbrc.commands - -import com.kelsos.mbrc.annotations.SocketAction.TERMINATE -import com.kelsos.mbrc.common.state.ConnectionModel -import com.kelsos.mbrc.networking.client.SocketService -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -class TerminateConnectionCommand( - private val service: SocketService, - private val model: ConnectionModel, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - model.setHandShakeDone(false) - model.setConnectionState("false") - service.socketManager(TERMINATE) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/TerminateServiceCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/TerminateServiceCommand.kt deleted file mode 100644 index e0514715f..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/TerminateServiceCommand.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.kelsos.mbrc.commands - -import android.app.Application -import android.content.Intent -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage -import com.kelsos.mbrc.platform.RemoteService - -class TerminateServiceCommand( - private val application: Application, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - if (RemoteService.serviceStopping) { - return - } - application.run { - stopService(Intent(this, RemoteService::class.java)) - } - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/VersionCheckCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/VersionCheckCommand.kt index 901737299..4a49113fd 100644 --- a/app/src/main/java/com/kelsos/mbrc/commands/VersionCheckCommand.kt +++ b/app/src/main/java/com/kelsos/mbrc/commands/VersionCheckCommand.kt @@ -1,27 +1,16 @@ package com.kelsos.mbrc.commands -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import com.kelsos.mbrc.common.state.MainDataModel -import com.kelsos.mbrc.constants.ProtocolEventType -import com.kelsos.mbrc.events.MessageEvent -import com.kelsos.mbrc.events.bus.RxBus import com.kelsos.mbrc.features.settings.SettingsManager import com.kelsos.mbrc.networking.protocol.ProtocolAction import com.kelsos.mbrc.networking.protocol.ProtocolMessage import timber.log.Timber -import java.io.IOException -import java.net.URL import java.time.Instant import java.time.temporal.ChronoUnit class VersionCheckCommand( - private val model: MainDataModel, - private val mapper: ObjectMapper, private val manager: SettingsManager, - private val bus: RxBus, ) : ProtocolAction { - override fun execute(message: ProtocolMessage) { + override suspend fun execute(message: ProtocolMessage) { val now = Instant.now() if (check(MINIMUM_REQUIRED)) { @@ -30,9 +19,8 @@ class VersionCheckCommand( Timber.d("Next update required check is @ $next") return } - bus.post(MessageEvent(ProtocolEventType.PLUGIN_UPDATE_REQUIRED)) - model.minimumRequired = MINIMUM_REQUIRED - model.pluginUpdateRequired = true + // model.minimumRequired = MINIMUM_REQUIRED + // model.pluginUpdateRequired = true manager.setLastUpdated(now, true) return } @@ -47,25 +35,25 @@ class VersionCheckCommand( Timber.d("Next update check after @ $nextCheck") return } - - val jsonNode: JsonNode - try { - jsonNode = mapper.readValue(URL(CHECK_URL), JsonNode::class.java) - } catch (e1: IOException) { - Timber.d(e1, "While reading json node") - return - } - - val expected = jsonNode.path("tag_name").asText().replace("v", "") - - val found = model.pluginVersion - if (expected != found && check(expected)) { - model.pluginUpdateAvailable = true - bus.post(MessageEvent(ProtocolEventType.PLUGIN_UPDATE_AVAILABLE)) - } +// +// val jsonNode: JsonNode +// try { +// jsonNode = mapper.readValue(URL(CHECK_URL), JsonNode::class.java) +// } catch (e1: IOException) { +// Timber.d(e1, "While reading json node") +// return +// } +// +// val expected = jsonNode.path("tag_name").asText().replace("v", "") +// +// val found = model.pluginVersion +// if (expected != found && check(expected)) { +// model.pluginUpdateAvailable = true +// +// } manager.setLastUpdated(now, false) - Timber.d("Checked for plugin update @ $now. Found: $found expected: $expected") + // Timber.d("Checked for plugin update @ $now. Found: $found expected: $expected") } private fun getNextCheck(required: Boolean = false): Instant { @@ -75,20 +63,20 @@ class VersionCheckCommand( } private fun check(suggestedVersion: String): Boolean { - val currentVersion = model.pluginVersion.toVersionArray() - val latestVersion = suggestedVersion.toVersionArray() - - var i = 0 - val currentSize = currentVersion.size - val latestSize = latestVersion.size - while (i < currentSize && i < latestSize && currentVersion[i] == latestVersion[i]) { - i++ - } - - if (i < currentSize && i < latestSize) { - val diff = currentVersion[i].compareTo(latestVersion[i]) - return diff < 0 - } +// val currentVersion = model.pluginVersion.toVersionArray() +// val latestVersion = suggestedVersion.toVersionArray() +// +// var i = 0 +// val currentSize = currentVersion.size +// val latestSize = latestVersion.size +// while (i < currentSize && i < latestSize && currentVersion[i] == latestVersion[i]) { +// i++ +// } +// +// if (i < currentSize && i < latestSize) { +// val diff = currentVersion[i].compareTo(latestVersion[i]) +// return diff < 0 +// } return false } diff --git a/app/src/main/java/com/kelsos/mbrc/commands/visual/HandshakeCompletionActions.kt b/app/src/main/java/com/kelsos/mbrc/commands/visual/HandshakeCompletionActions.kt deleted file mode 100644 index f2567f4fa..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/visual/HandshakeCompletionActions.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.kelsos.mbrc.commands.visual - -import com.kelsos.mbrc.common.state.ConnectionModel -import com.kelsos.mbrc.common.state.MainDataModel -import com.kelsos.mbrc.features.library.LibrarySyncUseCase -import com.kelsos.mbrc.networking.client.SocketMessage -import com.kelsos.mbrc.networking.client.SocketService -import com.kelsos.mbrc.networking.protocol.Protocol -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage -import rx.Observable -import timber.log.Timber -import java.util.concurrent.TimeUnit - -class HandshakeCompletionActions( - private val service: SocketService, - private val model: MainDataModel, - private val connectionModel: ConnectionModel, - private val syncInteractor: LibrarySyncUseCase, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - val isComplete = message.data as Boolean - connectionModel.setHandShakeDone(isComplete) - - if (!isComplete) { - return - } - - if (model.pluginProtocol > 2) { - Timber.v("Sending init request") - service.sendData(SocketMessage.create(Protocol.INIT)) - service.sendData(SocketMessage.create(Protocol.PLUGIN_VERSION)) - } else { - Timber.v("Preparing to send requests for state") - - val messages = ArrayList() - messages.add(SocketMessage.create(Protocol.NOW_PLAYING_COVER)) - messages.add(SocketMessage.create(Protocol.PLAYER_STATUS)) - messages.add(SocketMessage.create(Protocol.NOW_PLAYING_TRACK)) - messages.add(SocketMessage.create(Protocol.NOW_PLAYING_LYRICS)) - messages.add(SocketMessage.create(Protocol.NOW_PLAYING_POSITION)) - messages.add(SocketMessage.create(Protocol.PLUGIN_VERSION)) - - val totalMessages = messages.size - Observable - .interval(150, TimeUnit.MILLISECONDS) - .take(totalMessages) - .subscribe({ service.sendData(messages.removeAt(0)) }) { - Timber.v(it, "Failure while sending the init messages") - } - } - - syncInteractor.sync(true) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/commands/visual/NotifyNotAllowedCommand.kt b/app/src/main/java/com/kelsos/mbrc/commands/visual/NotifyNotAllowedCommand.kt deleted file mode 100644 index bb771654c..000000000 --- a/app/src/main/java/com/kelsos/mbrc/commands/visual/NotifyNotAllowedCommand.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.kelsos.mbrc.commands.visual - -import com.kelsos.mbrc.R -import com.kelsos.mbrc.annotations.SocketAction.STOP -import com.kelsos.mbrc.common.state.ConnectionModel -import com.kelsos.mbrc.events.bus.RxBus -import com.kelsos.mbrc.events.ui.NotifyUser -import com.kelsos.mbrc.networking.client.SocketService -import com.kelsos.mbrc.networking.protocol.ProtocolAction -import com.kelsos.mbrc.networking.protocol.ProtocolHandler -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -class NotifyNotAllowedCommand( - private val socketService: SocketService, - private val model: ConnectionModel, - private val handler: ProtocolHandler, - private val bus: RxBus, -) : ProtocolAction { - override fun execute(message: ProtocolMessage) { - bus.post(NotifyUser(R.string.notification_not_allowed)) - socketService.socketManager(STOP) - model.setConnectionState("false") - handler.resetHandshake() - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/common/data/LocalDataSource.kt b/app/src/main/java/com/kelsos/mbrc/common/data/LocalDataSource.kt deleted file mode 100644 index ef44fb0f2..000000000 --- a/app/src/main/java/com/kelsos/mbrc/common/data/LocalDataSource.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.kelsos.mbrc.common.data - -import com.kelsos.mbrc.data.Data -import com.raizlabs.android.dbflow.list.FlowCursorList - -interface LocalDataSource { - suspend fun deleteAll() - - suspend fun saveAll(list: List) - - suspend fun loadAllCursor(): FlowCursorList - - suspend fun search(term: String): FlowCursorList - - suspend fun isEmpty(): Boolean - - suspend fun count(): Long - - suspend fun removePreviousEntries(epoch: Long) -} diff --git a/app/src/main/java/com/kelsos/mbrc/common/data/RemoteDataSource.kt b/app/src/main/java/com/kelsos/mbrc/common/data/RemoteDataSource.kt deleted file mode 100644 index 53a2473bd..000000000 --- a/app/src/main/java/com/kelsos/mbrc/common/data/RemoteDataSource.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.kelsos.mbrc.common.data - -import kotlinx.coroutines.flow.Flow - -interface RemoteDataSource { - /** - * Retrieves all the available data from a remote data source - */ - suspend fun fetch(): Flow> - - companion object { - const val LIMIT = 800 - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/common/data/Repository.kt b/app/src/main/java/com/kelsos/mbrc/common/data/Repository.kt index 03ba9084d..5fe9ad361 100644 --- a/app/src/main/java/com/kelsos/mbrc/common/data/Repository.kt +++ b/app/src/main/java/com/kelsos/mbrc/common/data/Repository.kt @@ -1,18 +1,20 @@ package com.kelsos.mbrc.common.data -import com.kelsos.mbrc.data.Data -import com.raizlabs.android.dbflow.list.FlowCursorList +import androidx.paging.PagingData +import kotlinx.coroutines.flow.Flow -interface Repository { - suspend fun getAllCursor(): FlowCursorList +typealias Progress = suspend (current: Int, total: Int) -> Unit - suspend fun getAndSaveRemote(): FlowCursorList +interface Repository { + fun getAll(): Flow> - suspend fun getRemote() + suspend fun getRemote(progress: Progress? = null) - suspend fun search(term: String): FlowCursorList - - suspend fun cacheIsEmpty(): Boolean + fun search(term: String): Flow> suspend fun count(): Long + + suspend fun getById(id: Long): T? } + +suspend fun Repository.cacheIsEmpty(): Boolean = count() == 0L diff --git a/app/src/main/java/com/kelsos/mbrc/common/mvp/BasePresenter.kt b/app/src/main/java/com/kelsos/mbrc/common/mvp/BasePresenter.kt deleted file mode 100644 index 2957284f7..000000000 --- a/app/src/main/java/com/kelsos/mbrc/common/mvp/BasePresenter.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.kelsos.mbrc.common.mvp - -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LifecycleRegistry -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancelChildren -import rx.Subscription -import rx.subscriptions.CompositeSubscription -import kotlin.coroutines.CoroutineContext - -open class BasePresenter( - private val dispatcher: CoroutineDispatcher = Dispatchers.Main, -) : Presenter, - LifecycleOwner { - var view: T? = null - private set - - private val compositeSubscription = CompositeSubscription() - private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this) - private lateinit var job: Job - protected lateinit var scope: CoroutineScope - - private val coroutineContext: CoroutineContext - get() = job + dispatcher - - override val isAttached: Boolean - get() = view != null - - override fun attach(view: T) { - this.view = view - job = SupervisorJob() - scope = CoroutineScope(coroutineContext) - lifecycleRegistry.currentState = Lifecycle.State.CREATED - lifecycleRegistry.currentState = Lifecycle.State.STARTED - } - - override fun detach() { - lifecycleRegistry.currentState = Lifecycle.State.DESTROYED - this.view = null - compositeSubscription.clear() - job.cancelChildren() - } - - protected fun addSubscription(subscription: Subscription) { - this.compositeSubscription.add(subscription) - } - - fun checkIfAttached() { - if (!isAttached) { - throw ViewNotAttachedException() - } - } - - protected class ViewNotAttachedException : - RuntimeException("Please call Presenter.attach(BaseView) before calling a method on the presenter") - - override val lifecycle: Lifecycle - get() = lifecycleRegistry -} diff --git a/app/src/main/java/com/kelsos/mbrc/common/mvp/BaseView.kt b/app/src/main/java/com/kelsos/mbrc/common/mvp/BaseView.kt deleted file mode 100644 index b8a327ebb..000000000 --- a/app/src/main/java/com/kelsos/mbrc/common/mvp/BaseView.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.kelsos.mbrc.common.mvp - -interface BaseView diff --git a/app/src/main/java/com/kelsos/mbrc/common/mvp/Presenter.kt b/app/src/main/java/com/kelsos/mbrc/common/mvp/Presenter.kt deleted file mode 100644 index 6f72a76ed..000000000 --- a/app/src/main/java/com/kelsos/mbrc/common/mvp/Presenter.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.kelsos.mbrc.common.mvp - -interface Presenter { - fun attach(view: T) - - fun detach() - - val isAttached: Boolean -} diff --git a/app/src/main/java/com/kelsos/mbrc/common/mvvm/BaseViewModel.kt b/app/src/main/java/com/kelsos/mbrc/common/mvvm/BaseViewModel.kt new file mode 100644 index 000000000..9d0c84ea6 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/mvvm/BaseViewModel.kt @@ -0,0 +1,16 @@ +package com.kelsos.mbrc.common.mvvm + +import androidx.lifecycle.ViewModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow + +interface UiMessageBase + +open class BaseViewModel : ViewModel() { + private val backingEvents = MutableSharedFlow() + val events: Flow = backingEvents + + protected suspend fun emit(uiMessage: T) { + backingEvents.emit(uiMessage) + } +} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/AppState.kt b/app/src/main/java/com/kelsos/mbrc/common/state/AppState.kt new file mode 100644 index 000000000..47f083d46 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/AppState.kt @@ -0,0 +1,11 @@ +package com.kelsos.mbrc.common.state + +import kotlinx.coroutines.flow.MutableStateFlow + +class AppState { + val playerStatus = MutableStateFlow(PlayerStatusModel()) + val playingTrack = MutableStateFlow(PlayingTrack()) + val playingTrackRating = MutableStateFlow(TrackRating()) + val playingPosition = MutableStateFlow(PlayingPosition()) + val lyrics = MutableStateFlow(emptyList()) +} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/AppStateManager.kt b/app/src/main/java/com/kelsos/mbrc/common/state/AppStateManager.kt new file mode 100644 index 000000000..fffc9cbc3 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/AppStateManager.kt @@ -0,0 +1,100 @@ +package com.kelsos.mbrc.common.state + +import com.kelsos.mbrc.common.utilities.AppCoroutineDispatchers +import com.kelsos.mbrc.platform.mediasession.AppNotificationManager +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.distinctUntilChangedBy +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import java.util.Timer +import kotlin.concurrent.fixedRateTimer + +typealias StateHandler = (Boolean) -> Unit + +class AppStateManager( + private val appState: AppState, + private val connectionState: ConnectionState, + private val notifications: AppNotificationManager, + private val trackCache: PlayingTrackCache, + private val dispatchers: AppCoroutineDispatchers, +) { + private var stateHandler: StateHandler? = null + private var job = SupervisorJob() + private var scope = CoroutineScope(job + dispatchers.io) + + init { + scope.launch { + val track = trackCache.restoreInfo() + appState.playingTrack.emit(track) + } + } + + fun start() { + if (job.isCancelled || job.isCompleted) { + job = SupervisorJob() + scope = CoroutineScope(job + dispatchers.io) + } + val playingPosition = appState.playingPosition + scope.launch { + var timer: Timer? = null + appState.playerStatus.distinctUntilChangedBy { it.state }.map { it.state }.collect { state -> + stateHandler?.invoke(state == PlayerState.Playing) + val currentPosition = playingPosition.map { it.current }.distinctUntilChanged().first() + notifications.updateState(state, currentPosition) + timer?.cancel() + if (state == PlayerState.Playing) { + timer = + fixedRateTimer("progress", period = UPDATE_PERIOD_MS) { + updatePosition() + } + } + } + } + + scope.launch { + appState.playingTrack.collect { playingTrack -> + notifications.updatePlayingTrack(playingTrack) + trackCache.persistInfo(playingTrack) + } + } + + scope.launch { + connectionState.connection.collect { connnection -> + notifications.connectionStateChanged(connnection == ConnectionStatus.Connected) + } + } + + scope.launch { + playingPosition.collect { playingPosition -> + val playerState = appState.playerStatus.map { it.state }.first() + notifications.updateState(playerState, playingPosition.current) + } + } + } + + fun stop() { + job.cancel() + notifications.cancel() + } + + private fun updatePosition() { + scope.launch { + val playingPosition = appState.playingPosition + val position = playingPosition.first() + val current = (position.current + UPDATE_PERIOD_MS).coerceAtMost(position.total) + val newPosition = position.copy(current = current) + playingPosition.emit(newPosition) + } + } + + fun setStateHandler(stateHandler: StateHandler? = null) { + this.stateHandler = stateHandler + } + + companion object { + private const val UPDATE_PERIOD_MS = 1000L + } +} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/ConnectionModel.kt b/app/src/main/java/com/kelsos/mbrc/common/state/ConnectionModel.kt deleted file mode 100644 index d62f41ca6..000000000 --- a/app/src/main/java/com/kelsos/mbrc/common/state/ConnectionModel.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.kelsos.mbrc.common.state - -import com.kelsos.mbrc.annotations.Connection -import com.kelsos.mbrc.annotations.Connection.Status -import com.kelsos.mbrc.events.bus.RxBus -import com.kelsos.mbrc.events.ui.ConnectionStatusChangeEvent -import com.kelsos.mbrc.events.ui.RequestConnectionStateEvent - -class ConnectionModel( - private val bus: RxBus, -) { - var isConnectionActive: Boolean = false - private set - private var isHandShakeDone: Boolean = false - - init { - isConnectionActive = false - isHandShakeDone = false - this.bus.register(this, RequestConnectionStateEvent::class.java) { notifyState() } - } - - val connection: Int - @Status - get() { - if (isConnectionActive && isHandShakeDone) { - return Connection.ACTIVE - } else if (isConnectionActive) { - return Connection.ON - } - - return Connection.OFF - } - - fun setConnectionState(connectionActive: String) { - this.isConnectionActive = java.lang.Boolean.parseBoolean(connectionActive) - notifyState() - } - - private fun notifyState() { - bus.post(ConnectionStatusChangeEvent.create(connection)) - } - - fun setHandShakeDone(handShakeDone: Boolean) { - this.isHandShakeDone = handShakeDone - notifyState() - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/ConnectionState.kt b/app/src/main/java/com/kelsos/mbrc/common/state/ConnectionState.kt new file mode 100644 index 000000000..811fe5fa2 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/ConnectionState.kt @@ -0,0 +1,7 @@ +package com.kelsos.mbrc.common.state + +import kotlinx.coroutines.flow.MutableStateFlow + +class ConnectionState { + val connection = MutableStateFlow(ConnectionStatus.Offline) +} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/ConnectionStatus.kt b/app/src/main/java/com/kelsos/mbrc/common/state/ConnectionStatus.kt new file mode 100644 index 000000000..9d311cbae --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/ConnectionStatus.kt @@ -0,0 +1,9 @@ +package com.kelsos.mbrc.common.state + +sealed class ConnectionStatus { + object Offline : ConnectionStatus() + + object Connecting : ConnectionStatus() + + object Connected : ConnectionStatus() +} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/LfmRating.kt b/app/src/main/java/com/kelsos/mbrc/common/state/LfmRating.kt new file mode 100644 index 000000000..3c7f7abf5 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/LfmRating.kt @@ -0,0 +1,21 @@ +package com.kelsos.mbrc.common.state + +sealed class LfmRating { + data object Loved : LfmRating() + + data object Banned : LfmRating() + + data object Normal : LfmRating() + + companion object { + private const val LOVE = "Love" + private const val BAN = "Ban" + + fun fromString(value: String?): LfmRating = + when (value) { + LOVE -> Loved + BAN -> Banned + else -> Normal + } + } +} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/MainDataModel.kt b/app/src/main/java/com/kelsos/mbrc/common/state/MainDataModel.kt deleted file mode 100644 index 9833de47c..000000000 --- a/app/src/main/java/com/kelsos/mbrc/common/state/MainDataModel.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.kelsos.mbrc.common.state - -import com.kelsos.mbrc.annotations.PlayerState -import com.kelsos.mbrc.annotations.PlayerState.State -import com.kelsos.mbrc.annotations.Repeat -import com.kelsos.mbrc.annotations.Repeat.Mode -import com.kelsos.mbrc.constants.Const -import com.kelsos.mbrc.events.ui.ShuffleChange -import com.kelsos.mbrc.events.ui.ShuffleChange.ShuffleState -import com.kelsos.mbrc.features.player.LfmStatus -import com.kelsos.mbrc.features.player.TrackInfo -import com.kelsos.mbrc.networking.protocol.Protocol - -class MainDataModel { - var pluginUpdateAvailable: Boolean = false - var pluginUpdateRequired: Boolean = false - var minimumRequired: String = "" - var position: Long = 0 - var duration: Long = 0 - var trackInfo: TrackInfo = TrackInfo() - var coverPath: String = "" - var rating: Float = 0f - var volume: Int = 0 - - @ShuffleState - var shuffle: String = ShuffleChange.OFF - var isScrobblingEnabled: Boolean = false - var isMute: Boolean = false - var lfmStatus: LfmStatus = LfmStatus.NORMAL - private set - var apiOutOfDate: Boolean = false - private set - - var pluginVersion: String = "1.0.0" - set(value) { - if (value.isEmpty()) { - return - } - field = value.substring(0, value.lastIndexOf('.')) - } - - var pluginProtocol: Int = 2 - set(value) { - field = value - if (value < Protocol.PROTOCOL_VERSION_NUMBER) { - apiOutOfDate = true - } - } - - @State - var playState: String = PlayerState.UNDEFINED - set(value) { - @State val newState: String = - when { - Const.PLAYING.equals(value, ignoreCase = true) -> PlayerState.PLAYING - Const.STOPPED.equals(value, ignoreCase = true) -> PlayerState.STOPPED - Const.PAUSED.equals(value, ignoreCase = true) -> PlayerState.PAUSED - else -> PlayerState.UNDEFINED - } - field = newState - } - - @Mode - var repeat: String - private set - - init { - repeat = Repeat.NONE - rating = 0f - - lfmStatus = LfmStatus.NORMAL - pluginVersion = Const.EMPTY - } - - fun setLfmRating(rating: String) { - lfmStatus = - when (rating) { - "Love" -> LfmStatus.LOVED - "Ban" -> LfmStatus.BANNED - else -> LfmStatus.NORMAL - } - } - - fun setRepeatState(repeat: String) { - this.repeat = - when { - Protocol.ALL.equals(repeat, ignoreCase = true) -> Repeat.ALL - Protocol.ONE.equals(repeat, ignoreCase = true) -> Repeat.ONE - else -> Repeat.NONE - } - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/NowPlayingTrack.kt b/app/src/main/java/com/kelsos/mbrc/common/state/NowPlayingTrack.kt new file mode 100644 index 000000000..a747426db --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/NowPlayingTrack.kt @@ -0,0 +1,18 @@ +package com.kelsos.mbrc.common.state + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class NowPlayingTrack( + @Json(name = "artist") + val artist: String, + @Json(name = "album") + val album: String, + @Json(name = "title") + val title: String, + @Json(name = "year") + val year: String, + @Json(name = "path") + val path: String, +) diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/PlayerState.kt b/app/src/main/java/com/kelsos/mbrc/common/state/PlayerState.kt new file mode 100644 index 000000000..19f7379e5 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/PlayerState.kt @@ -0,0 +1,28 @@ +package com.kelsos.mbrc.common.state + +sealed class PlayerState( + val state: String, +) { + object Playing : PlayerState(PLAYING) + + object Paused : PlayerState(PAUSED) + + object Stopped : PlayerState(STOPPED) + + object Undefined : PlayerState(UNDEFINED) + + companion object { + const val PLAYING = "playing" + const val PAUSED = "paused" + const val STOPPED = "stopped" + const val UNDEFINED = "undefined" + + fun fromString(state: String): PlayerState = + when (state) { + PLAYING -> Playing + PAUSED -> Paused + STOPPED -> Stopped + else -> Undefined + } + } +} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/PlayerStatus.kt b/app/src/main/java/com/kelsos/mbrc/common/state/PlayerStatus.kt new file mode 100644 index 000000000..ea0ddaf50 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/PlayerStatus.kt @@ -0,0 +1,21 @@ +package com.kelsos.mbrc.common.state + +import com.kelsos.mbrc.networking.protocol.Protocol +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class PlayerStatus( + @Json(name = Protocol.PLAYER_MUTE) + val mute: Boolean, + @Json(name = Protocol.PLAYER_STATE) + val playState: String, + @Json(name = Protocol.PLAYER_REPEAT) + val repeat: String, + @Json(name = Protocol.PLAYER_SHUFFLE) + val shuffle: String, + @Json(name = Protocol.PLAYER_SCROBBLE) + val scrobbling: Boolean, + @Json(name = Protocol.PLAYER_VOLUME) + val volume: Int, +) diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/PlayerStatusModel.kt b/app/src/main/java/com/kelsos/mbrc/common/state/PlayerStatusModel.kt new file mode 100644 index 000000000..c0eb91e95 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/PlayerStatusModel.kt @@ -0,0 +1,13 @@ +package com.kelsos.mbrc.common.state + +import androidx.annotation.IntRange + +data class PlayerStatusModel( + @get:IntRange(from = 0, to = 100) + val volume: Int = 0, + val mute: Boolean = false, + val shuffle: ShuffleMode = ShuffleMode.Off, + val scrobbling: Boolean = false, + val repeat: Repeat = Repeat.None, + val state: PlayerState = PlayerState.Undefined, +) diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/PlayingPosition.kt b/app/src/main/java/com/kelsos/mbrc/common/state/PlayingPosition.kt new file mode 100644 index 000000000..ce7f41005 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/PlayingPosition.kt @@ -0,0 +1,23 @@ +package com.kelsos.mbrc.common.state + +data class PlayingPosition( + val current: Duration = 0, + val total: Duration = 0, +) { + val totalMinutes get() = total.toMinutes() + val currentMinutes get() = current.toMinutes() + + fun progress(): String = "$currentMinutes / $totalMinutes" +} + +typealias Duration = Long + +private const val SECONDS_IN_MINUTE = 60 +private const val MILLIS_IN_SECONDS = 1000 + +fun Duration.toMinutes(): String { + val inSeconds = this / MILLIS_IN_SECONDS + val minutes = inSeconds / SECONDS_IN_MINUTE + val seconds = inSeconds % SECONDS_IN_MINUTE + return "%02d:%02d".format(minutes, seconds) +} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/PlayingTrack.kt b/app/src/main/java/com/kelsos/mbrc/common/state/PlayingTrack.kt new file mode 100644 index 000000000..f339d3bf6 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/PlayingTrack.kt @@ -0,0 +1,49 @@ +package com.kelsos.mbrc.common.state + +import android.os.Parcel +import android.os.Parcelable + +data class PlayingTrack( + val artist: String = "", + val title: String = "", + val album: String = "", + val year: String = "", + val path: String = "", + val coverUrl: String = "", + val duration: Long = 0, +) : Parcelable { + companion object { + @JvmField + val CREATOR: Parcelable.Creator = + object : Parcelable.Creator { + override fun createFromParcel(source: Parcel): PlayingTrack = PlayingTrack(source) + + override fun newArray(size: Int): Array = arrayOfNulls(size) + } + } + + constructor(source: Parcel) : this( + source.readString() ?: "", + source.readString() ?: "", + source.readString() ?: "", + source.readString() ?: "", + source.readString() ?: "", + source.readString() ?: "", + source.readLong(), + ) + + override fun describeContents() = 0 + + override fun writeToParcel( + dest: Parcel, + flags: Int, + ) { + dest.writeString(artist) + dest.writeString(title) + dest.writeString(album) + dest.writeString(year) + dest.writeString(path) + dest.writeString(coverUrl) + dest.writeLong(duration) + } +} diff --git a/app/src/main/java/com/kelsos/mbrc/features/player/ModelCache.kt b/app/src/main/java/com/kelsos/mbrc/common/state/PlayingTrackCache.kt similarity index 60% rename from app/src/main/java/com/kelsos/mbrc/features/player/ModelCache.kt rename to app/src/main/java/com/kelsos/mbrc/common/state/PlayingTrackCache.kt index 055542c86..0569740d5 100644 --- a/app/src/main/java/com/kelsos/mbrc/features/player/ModelCache.kt +++ b/app/src/main/java/com/kelsos/mbrc/common/state/PlayingTrackCache.kt @@ -1,9 +1,12 @@ -package com.kelsos.mbrc.features.player +package com.kelsos.mbrc.common.state import android.app.Application import android.content.Context +import androidx.datastore.core.CorruptionException import androidx.datastore.core.DataStore +import androidx.datastore.core.Serializer import androidx.datastore.dataStore +import com.google.protobuf.InvalidProtocolBufferException import com.kelsos.mbrc.common.utilities.AppCoroutineDispatchers import com.kelsos.mbrc.store.Store import com.kelsos.mbrc.store.Track @@ -13,16 +16,28 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext import timber.log.Timber import java.io.IOException +import java.io.InputStream +import java.io.OutputStream internal val Context.cacheDataStore: DataStore by dataStore( fileName = "cache_store.db", serializer = PlayerStateSerializer, ) -class ModelCacheImpl( +interface PlayingTrackCache { + suspend fun persistInfo(playingTrack: PlayingTrack) + + suspend fun restoreInfo(): PlayingTrack + + suspend fun persistCover(cover: String) + + suspend fun restoreCover(): String +} + +class PlayingTrackCacheImpl( private val context: Application, private val dispatchers: AppCoroutineDispatchers, -) : ModelCache { +) : PlayingTrackCache { private val storeFlow: Flow = context.cacheDataStore.data .catch { exception -> @@ -35,17 +50,17 @@ class ModelCacheImpl( } } - override suspend fun persistInfo(trackInfo: TrackInfo) = + override suspend fun persistInfo(playingTrack: PlayingTrack) = withContext(dispatchers.io) { context.cacheDataStore.updateData { store -> val track = Track .newBuilder() - .setAlbum(trackInfo.album) - .setArtist(trackInfo.artist) - .setPath(trackInfo.path) - .setTitle(trackInfo.title) - .setYear(trackInfo.year) + .setAlbum(playingTrack.album) + .setArtist(playingTrack.artist) + .setPath(playingTrack.path) + .setTitle(playingTrack.title) + .setYear(playingTrack.year) .build() store @@ -56,11 +71,11 @@ class ModelCacheImpl( return@withContext } - override suspend fun restoreInfo(): TrackInfo = + override suspend fun restoreInfo(): PlayingTrack = withContext(dispatchers.io) { val track = storeFlow.first().track - return@withContext TrackInfo( + return@withContext PlayingTrack( track.artist, track.title, track.album, @@ -78,12 +93,20 @@ class ModelCacheImpl( override suspend fun restoreCover(): String = storeFlow.first().cover } -interface ModelCache { - suspend fun persistInfo(trackInfo: TrackInfo) - - suspend fun restoreInfo(): TrackInfo +object PlayerStateSerializer : Serializer { + override suspend fun readFrom(input: InputStream): Store { + try { + return Store.parseFrom(input) + } catch (exception: InvalidProtocolBufferException) { + throw CorruptionException("Cannot read proto.", exception) + } + } - suspend fun persistCover(cover: String) + override suspend fun writeTo( + t: Store, + output: OutputStream, + ) = t.writeTo(output) - suspend fun restoreCover(): String + override val defaultValue: Store + get() = Store.getDefaultInstance() } diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/Repeat.kt b/app/src/main/java/com/kelsos/mbrc/common/state/Repeat.kt new file mode 100644 index 000000000..ee544bb13 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/Repeat.kt @@ -0,0 +1,24 @@ +package com.kelsos.mbrc.common.state + +sealed class Repeat( + val mode: String, +) { + object All : Repeat(ALL) + + object None : Repeat(NONE) + + object One : Repeat(ONE) + + companion object { + const val ALL = "all" + const val NONE = "none" + const val ONE = "one" + + fun fromString(mode: String): Repeat = + when (mode) { + ALL -> All + ONE -> One + else -> None + } + } +} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/ShuffleMode.kt b/app/src/main/java/com/kelsos/mbrc/common/state/ShuffleMode.kt new file mode 100644 index 000000000..6762d2f5f --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/ShuffleMode.kt @@ -0,0 +1,24 @@ +package com.kelsos.mbrc.common.state + +sealed class ShuffleMode( + val mode: String, +) { + data object Off : ShuffleMode(OFF) + + data object AutoDJ : ShuffleMode(AUTO_DJ) + + data object Shuffle : ShuffleMode(SHUFFLE) + + companion object { + const val OFF = "off" + const val AUTO_DJ = "autodj" + const val SHUFFLE = "shuffle" + + fun fromString(string: String): ShuffleMode = + when (string) { + AUTO_DJ -> AutoDJ + SHUFFLE -> Shuffle + else -> Off + } + } +} diff --git a/app/src/main/java/com/kelsos/mbrc/common/state/TrackRating.kt b/app/src/main/java/com/kelsos/mbrc/common/state/TrackRating.kt new file mode 100644 index 000000000..b069bfc6d --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/common/state/TrackRating.kt @@ -0,0 +1,8 @@ +package com.kelsos.mbrc.common.state + +data class TrackRating( + val lfmRating: LfmRating = LfmRating.Normal, + val rating: Float = 0f, +) { + fun isFavorite(): Boolean = lfmRating == LfmRating.Loved +} diff --git a/app/src/main/java/com/kelsos/mbrc/common/ui/CircleImageView.kt b/app/src/main/java/com/kelsos/mbrc/common/ui/CircleImageView.kt index 6d993bbd7..5dd3a216b 100644 --- a/app/src/main/java/com/kelsos/mbrc/common/ui/CircleImageView.kt +++ b/app/src/main/java/com/kelsos/mbrc/common/ui/CircleImageView.kt @@ -36,6 +36,7 @@ import androidx.annotation.DrawableRes import androidx.appcompat.widget.AppCompatImageView import androidx.core.content.ContextCompat import com.kelsos.mbrc.R +import timber.log.Timber class CircleImageView : AppCompatImageView { private val mDrawableRect = RectF() @@ -112,15 +113,11 @@ class CircleImageView : AppCompatImageView { override fun getScaleType(): ScaleType = SCALE_TYPE override fun setScaleType(scaleType: ScaleType) { - if (scaleType != SCALE_TYPE) { - throw IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)) - } + require(scaleType == SCALE_TYPE) { "ScaleType $scaleType not supported." } } override fun setAdjustViewBounds(adjustViewBounds: Boolean) { - if (adjustViewBounds) { - throw IllegalArgumentException("adjustViewBounds not supported.") - } + require(!adjustViewBounds) { "adjustViewBounds not supported." } } override fun onDraw(canvas: Canvas) { @@ -272,22 +269,19 @@ class CircleImageView : AppCompatImageView { } try { - val bitmap: Bitmap - - if (drawable is ColorDrawable) { - bitmap = - Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG) - } else { - bitmap = + val bitmap: Bitmap = + if (drawable is ColorDrawable) { + Bitmap.createBitmap(COLOR_DRAWABLE_DIMENSION, COLOR_DRAWABLE_DIMENSION, BITMAP_CONFIG) + } else { Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, BITMAP_CONFIG) - } + } val canvas = Canvas(bitmap) drawable.setBounds(0, 0, canvas.width, canvas.height) drawable.draw(canvas) return bitmap } catch (e: Exception) { - e.printStackTrace() + Timber.e(e) return null } } @@ -372,16 +366,16 @@ class CircleImageView : AppCompatImageView { if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) { scale = mDrawableRect.height() / mBitmapHeight.toFloat() - dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f + dx = (mDrawableRect.width() - mBitmapWidth * scale) * HALF } else { scale = mDrawableRect.width() / mBitmapWidth.toFloat() - dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f + dy = (mDrawableRect.height() - mBitmapHeight * scale) * HALF } mShaderMatrix.setScale(scale, scale) mShaderMatrix.postTranslate( - (dx + 0.5f).toInt() + mDrawableRect.left, - (dy + 0.5f).toInt() + mDrawableRect.top, + (dx + HALF).toInt() + mDrawableRect.left, + (dy + HALF).toInt() + mDrawableRect.top, ) mBitmapShader!!.setLocalMatrix(mShaderMatrix) @@ -391,11 +385,12 @@ class CircleImageView : AppCompatImageView { private val SCALE_TYPE = ScaleType.CENTER_CROP private val BITMAP_CONFIG = Bitmap.Config.ARGB_8888 - private val COLORDRAWABLE_DIMENSION = 2 + private const val COLOR_DRAWABLE_DIMENSION = 2 - private val DEFAULT_BORDER_WIDTH = 0 - private val DEFAULT_BORDER_COLOR = Color.BLACK - private val DEFAULT_FILL_COLOR = Color.TRANSPARENT - private val DEFAULT_BORDER_OVERLAY = false + private const val DEFAULT_BORDER_WIDTH = 0 + private const val DEFAULT_BORDER_COLOR = Color.BLACK + private const val DEFAULT_FILL_COLOR = Color.TRANSPARENT + private const val DEFAULT_BORDER_OVERLAY = false + private const val HALF = 0.5f } } diff --git a/app/src/main/java/com/kelsos/mbrc/common/utilities/Helpers.kt b/app/src/main/java/com/kelsos/mbrc/common/utilities/Helpers.kt index 7fcd5fbc1..f347432e1 100644 --- a/app/src/main/java/com/kelsos/mbrc/common/utilities/Helpers.kt +++ b/app/src/main/java/com/kelsos/mbrc/common/utilities/Helpers.kt @@ -1,5 +1,35 @@ package com.kelsos.mbrc.common.utilities +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import androidx.paging.PagingSource +import androidx.paging.map +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import java.time.Instant + +fun paged( + pagingSourceFactory: () -> PagingSource, + transform: (value: T) -> I, +): Flow> { + val config = + PagingConfig( + enablePlaceholders = true, + pageSize = 60, + maxSize = 200, + ) + return Pager( + config, + pagingSourceFactory = pagingSourceFactory, + ).flow.map { data -> data.map(transform) } +} + +/** + * [Instant.getEpochSecond] for [Instant.now] + */ +fun epoch(): Long = Instant.now().epochSecond + inline fun whenNotNull( p1: T1?, p2: T2?, diff --git a/app/src/main/java/com/kelsos/mbrc/common/utilities/RemoteUtils.kt b/app/src/main/java/com/kelsos/mbrc/common/utilities/RemoteUtils.kt index b7894eec8..48a73257c 100644 --- a/app/src/main/java/com/kelsos/mbrc/common/utilities/RemoteUtils.kt +++ b/app/src/main/java/com/kelsos/mbrc/common/utilities/RemoteUtils.kt @@ -1,48 +1,20 @@ package com.kelsos.mbrc.common.utilities -import android.content.Context -import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.BitmapFactory -import androidx.core.content.pm.PackageInfoCompat -import java.security.MessageDigest +import com.kelsos.mbrc.BuildConfig object RemoteUtils { - @Throws(PackageManager.NameNotFoundException::class) - fun Context.getVersion(): String? = packageManager.getPackageInfo(packageName, 0).versionName - - @Throws(PackageManager.NameNotFoundException::class) - fun Context.getVersionCode(): Long = PackageInfoCompat.getLongVersionCode(packageManager.getPackageInfo(packageName, 0)) - - fun coverBitmapSync(coverPath: String): Bitmap? { - return try { - val options = BitmapFactory.Options() - options.inPreferredConfig = Bitmap.Config.RGB_565 - return BitmapFactory.decodeFile(coverPath, options) - } catch (e: Exception) { - null + const val VERSION: String = BuildConfig.VERSION_NAME + const val VERSION_CODE: Int = BuildConfig.VERSION_CODE + + fun loadBitmap(path: String): Result = + runCatching { + BitmapFactory.decodeFile( + path, + BitmapFactory.Options().apply { + inPreferredConfig = Bitmap.Config.RGB_565 + }, + ) } - } - - fun sha1(input: String) = hashString("SHA-1", input) - - private fun hashString( - type: String, - input: String, - ): String { - val hexChars = "0123456789ABCDEF" - val bytes = - MessageDigest - .getInstance(type) - .digest(input.toByteArray()) - val result = StringBuilder(bytes.size * 2) - - bytes.forEach { - val i = it.toInt() - result.append(hexChars[i shr 4 and 0x0f]) - result.append(hexChars[i and 0x0f]) - } - - return result.toString() - } } diff --git a/app/src/main/java/com/kelsos/mbrc/constants/Const.kt b/app/src/main/java/com/kelsos/mbrc/constants/Const.kt index ad050faf6..de7c9ca43 100644 --- a/app/src/main/java/com/kelsos/mbrc/constants/Const.kt +++ b/app/src/main/java/com/kelsos/mbrc/constants/Const.kt @@ -2,7 +2,6 @@ package com.kelsos.mbrc.constants object Const { const val EMPTY = "" - const val LYRICS_NEWLINE = "\r\n|\n" const val DATA = "data" const val TOGGLE = "toggle" const val PLAYING = "playing" diff --git a/app/src/main/java/com/kelsos/mbrc/data/Data.kt b/app/src/main/java/com/kelsos/mbrc/data/Data.kt deleted file mode 100644 index 7979c974b..000000000 --- a/app/src/main/java/com/kelsos/mbrc/data/Data.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.kelsos.mbrc.data - -interface Data diff --git a/app/src/main/java/com/kelsos/mbrc/data/Database.kt b/app/src/main/java/com/kelsos/mbrc/data/Database.kt index 3924d8ba6..0005a79ab 100644 --- a/app/src/main/java/com/kelsos/mbrc/data/Database.kt +++ b/app/src/main/java/com/kelsos/mbrc/data/Database.kt @@ -1,73 +1,57 @@ package com.kelsos.mbrc.data -import com.kelsos.mbrc.features.library.Album -import com.kelsos.mbrc.features.library.Artist -import com.kelsos.mbrc.features.library.Genre -import com.kelsos.mbrc.features.library.Track -import com.kelsos.mbrc.features.nowplaying.NowPlaying -import com.kelsos.mbrc.features.playlists.Playlist -import com.raizlabs.android.dbflow.annotation.Migration -import com.raizlabs.android.dbflow.sql.SQLiteType -import com.raizlabs.android.dbflow.sql.migration.AlterTableMigration -import com.raizlabs.android.dbflow.annotation.Database as Db - -@Db(version = Database.VERSION, name = Database.NAME) -object Database { - const val VERSION = 3 - const val NAME = "cache" - - @Migration(version = 3, database = Database::class) - class Migration3Genre( - table: Class, - ) : AlterTableMigration(table) { - override fun onPreMigrate() { - addColumn(SQLiteType.INTEGER, "date_added") - } - } - - @Migration(version = 3, database = Database::class) - class Migration3Artist( - table: Class, - ) : AlterTableMigration(table) { - override fun onPreMigrate() { - addColumn(SQLiteType.INTEGER, "date_added") - } - } - - @Migration(version = 3, database = Database::class) - class Migration3Album( - table: Class, - ) : AlterTableMigration(table) { - override fun onPreMigrate() { - addColumn(SQLiteType.TEXT, "cover") - addColumn(SQLiteType.INTEGER, "date_added") - } - } - - @Migration(version = 3, database = Database::class) - class Migration3Track( - table: Class, - ) : AlterTableMigration(table) { - override fun onPreMigrate() { - addColumn(SQLiteType.INTEGER, "date_added") - } - } - - @Migration(version = 3, database = Database::class) - class Migration3NowPlaying( - table: Class, - ) : AlterTableMigration(table) { - override fun onPreMigrate() { - addColumn(SQLiteType.INTEGER, "date_added") - } - } - - @Migration(version = 3, database = Database::class) - class Migration3Playlist( - table: Class, - ) : AlterTableMigration(table) { - override fun onPreMigrate() { - addColumn(SQLiteType.INTEGER, "date_added") - } +import androidx.room.Database +import androidx.room.RoomDatabase +import com.kelsos.mbrc.data.Database.Companion.VERSION +import com.kelsos.mbrc.features.library.albums.AlbumDao +import com.kelsos.mbrc.features.library.albums.AlbumEntity +import com.kelsos.mbrc.features.library.artists.ArtistDao +import com.kelsos.mbrc.features.library.artists.ArtistEntity +import com.kelsos.mbrc.features.library.genres.GenreDao +import com.kelsos.mbrc.features.library.genres.GenreEntity +import com.kelsos.mbrc.features.library.tracks.TrackDao +import com.kelsos.mbrc.features.library.tracks.TrackEntity +import com.kelsos.mbrc.features.nowplaying.NowPlayingDao +import com.kelsos.mbrc.features.nowplaying.NowPlayingEntity +import com.kelsos.mbrc.features.playlists.PlaylistDao +import com.kelsos.mbrc.features.playlists.PlaylistEntity +import com.kelsos.mbrc.features.radio.RadioStationDao +import com.kelsos.mbrc.features.radio.RadioStationEntity +import com.kelsos.mbrc.features.settings.ConnectionDao +import com.kelsos.mbrc.features.settings.ConnectionSettingsEntity + +@Database( + entities = [ + GenreEntity::class, + ArtistEntity::class, + AlbumEntity::class, + TrackEntity::class, + NowPlayingEntity::class, + PlaylistEntity::class, + RadioStationEntity::class, + ConnectionSettingsEntity::class, + ], + version = VERSION, +) +abstract class Database : RoomDatabase() { + abstract fun genreDao(): GenreDao + + abstract fun artistDao(): ArtistDao + + abstract fun albumDao(): AlbumDao + + abstract fun trackDao(): TrackDao + + abstract fun nowPlayingDao(): NowPlayingDao + + abstract fun playlistDao(): PlaylistDao + + abstract fun radioStationDao(): RadioStationDao + + abstract fun connectionDao(): ConnectionDao + + companion object { + const val VERSION = 3 + const val NAME = "cache.db" } } diff --git a/app/src/main/java/com/kelsos/mbrc/data/DeserializationAdapter.kt b/app/src/main/java/com/kelsos/mbrc/data/DeserializationAdapter.kt new file mode 100644 index 000000000..70b5dd5a0 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/data/DeserializationAdapter.kt @@ -0,0 +1,50 @@ +package com.kelsos.mbrc.data + +import com.squareup.moshi.Moshi +import java.lang.reflect.ParameterizedType +import kotlin.reflect.KClass + +interface DeserializationAdapter { + fun objectify( + line: String, + kClass: KClass, + ): T where T : Any + + fun objectify( + line: String, + type: ParameterizedType, + ): T where T : Any + + fun convertValue( + data: Any?, + kClass: KClass, + ): T where T : Any +} + +class DeserializationAdapterImpl( + private val moshi: Moshi, +) : DeserializationAdapter { + override fun objectify( + line: String, + type: ParameterizedType, + ): T { + val adapter = moshi.adapter(type) + return checkNotNull(adapter.fromJson(line)) { "what?" } + } + + override fun convertValue( + data: Any?, + kClass: KClass, + ): T { + val adapter = moshi.adapter(kClass.java) + return checkNotNull(adapter.fromJsonValue(data)) { "what?" } + } + + override fun objectify( + line: String, + kClass: KClass, + ): T { + val adapter = moshi.adapter(kClass.java) + return checkNotNull(adapter.fromJson(line)) { "what? " } + } +} diff --git a/app/src/main/java/com/kelsos/mbrc/data/SerializationAdapter.kt b/app/src/main/java/com/kelsos/mbrc/data/SerializationAdapter.kt new file mode 100644 index 000000000..316714161 --- /dev/null +++ b/app/src/main/java/com/kelsos/mbrc/data/SerializationAdapter.kt @@ -0,0 +1,17 @@ +package com.kelsos.mbrc.data + +import com.kelsos.mbrc.networking.client.SocketMessage +import com.squareup.moshi.Moshi + +interface SerializationAdapter { + fun stringify(message: SocketMessage): String +} + +class SerializationAdapterImpl( + private val moshi: Moshi, +) : SerializationAdapter { + override fun stringify(message: SocketMessage): String { + val adapter = moshi.adapter(SocketMessage::class.java) + return adapter.toJson(message) + } +} diff --git a/app/src/main/java/com/kelsos/mbrc/data/UserAction.kt b/app/src/main/java/com/kelsos/mbrc/data/UserAction.kt deleted file mode 100644 index 0ec25690b..000000000 --- a/app/src/main/java/com/kelsos/mbrc/data/UserAction.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.kelsos.mbrc.data - -class UserAction( - val context: String, - val data: Any, -) { - companion object { - fun create(context: String): UserAction = UserAction(context, true) - - fun create( - context: String, - data: Any, - ): UserAction = UserAction(context, data) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/events/DefaultSettingsChangedEvent.kt b/app/src/main/java/com/kelsos/mbrc/events/DefaultSettingsChangedEvent.kt deleted file mode 100644 index 2ffd7a687..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/DefaultSettingsChangedEvent.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.kelsos.mbrc.events - -class DefaultSettingsChangedEvent { - companion object { - fun create(): DefaultSettingsChangedEvent = DefaultSettingsChangedEvent() - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/events/MessageEvent.kt b/app/src/main/java/com/kelsos/mbrc/events/MessageEvent.kt deleted file mode 100644 index bf405be54..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/MessageEvent.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.kelsos.mbrc.events - -import com.fasterxml.jackson.databind.node.TextNode -import com.kelsos.mbrc.constants.ProtocolEventType -import com.kelsos.mbrc.data.UserAction -import com.kelsos.mbrc.networking.protocol.ProtocolMessage - -data class MessageEvent( - override var type: String = "", - override var data: Any = "", -) : ProtocolMessage { - override val dataString: String - get() { - return when (data.javaClass) { - TextNode::class.java -> (data as TextNode).asText() - String::class.java -> data as String - else -> "" - } - } - - companion object { - fun action(data: UserAction): MessageEvent = MessageEvent(ProtocolEventType.USER_ACTION, data) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/events/bus/RxBus.kt b/app/src/main/java/com/kelsos/mbrc/events/bus/RxBus.kt deleted file mode 100644 index 10908c819..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/bus/RxBus.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.kelsos.mbrc.events.bus - -import rx.Subscription - -interface RxBus { - fun register( - receiver: Any, - eventClass: Class, - onNext: (T) -> Unit, - ) - - fun register( - receiver: Any, - eventClass: Class, - onNext: (T) -> Unit, - main: Boolean, - ) - - fun unregister(receiver: Any) - - fun register( - eventClass: Class, - onNext: (T) -> Unit, - main: Boolean, - ): Subscription - - fun post(event: Any) -} diff --git a/app/src/main/java/com/kelsos/mbrc/events/bus/RxBusImpl.kt b/app/src/main/java/com/kelsos/mbrc/events/bus/RxBusImpl.kt deleted file mode 100644 index 3173ca7f6..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/bus/RxBusImpl.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.kelsos.mbrc.events.bus - -import com.jakewharton.rxrelay.PublishRelay -import rx.Observable -import rx.Subscription -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers -import timber.log.Timber -import java.util.LinkedList - -class RxBusImpl : RxBus { - init { - Timber.v("Injecting RxBus instance %s", this) - } - - private val serializedRelay = PublishRelay.create().toSerialized() - private val activeSubscriptions = HashMap>() - - @Suppress("UNCHECKED_CAST") - override fun register( - receiver: Any, - eventClass: Class, - onNext: (T) -> Unit, - ) { - //noinspection unchecked - val subscription = - serializedRelay - .filter { - it.javaClass == eventClass - }.map { obj -> obj as T } - .subscribe(onNext) - - updateSubscriptions(receiver, subscription) - } - - override fun register( - receiver: Any, - eventClass: Class, - onNext: (T) -> Unit, - main: Boolean, - ) { - val subscription = register(eventClass, onNext, true) - updateSubscriptions(receiver, subscription) - } - - private fun updateSubscriptions( - receiver: Any, - subscription: Subscription, - ) { - val subscriptions: MutableList = - activeSubscriptions[receiver] ?: LinkedList() - subscriptions.add(subscription) - activeSubscriptions[receiver] = subscriptions - } - - override fun unregister(receiver: Any) { - val subscriptions = activeSubscriptions.remove(receiver) - if (subscriptions != null) { - Observable.from(subscriptions).filter { !it.isUnsubscribed }.subscribe { it.unsubscribe() } - } - } - - @Suppress("UNCHECKED_CAST") - override fun register( - eventClass: Class, - onNext: (T) -> Unit, - main: Boolean, - ): Subscription { - //noinspection unchecked - val observable = serializedRelay.filter { it.javaClass == eventClass }.map { obj -> obj as T } - val scheduler = if (main) AndroidSchedulers.mainThread() else Schedulers.immediate() - return observable.onBackpressureBuffer().observeOn(scheduler).subscribe(onNext) - } - - override fun post(event: Any) { - serializedRelay.call(event) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/ConnectionSettingsChanged.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/ConnectionSettingsChanged.kt deleted file mode 100644 index 4bf916223..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/ConnectionSettingsChanged.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.kelsos.mbrc.events.ui - -class ConnectionSettingsChanged private constructor( - val defaultId: Long, -) { - companion object { - fun newInstance(defaultId: Long): ConnectionSettingsChanged = ConnectionSettingsChanged(defaultId) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/CoverChangedEvent.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/CoverChangedEvent.kt deleted file mode 100644 index 0132c08db..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/CoverChangedEvent.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.kelsos.mbrc.events.ui - -class CoverChangedEvent( - val path: String = "", -) diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/DiscoveryStopped.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/DiscoveryStopped.kt deleted file mode 100644 index cb87decd1..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/DiscoveryStopped.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.kelsos.mbrc.events.ui - -import com.kelsos.mbrc.networking.discovery.DiscoveryStop - -class DiscoveryStopped( - val reason: DiscoveryStop, -) diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/LfmRatingChanged.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/LfmRatingChanged.kt deleted file mode 100644 index 0e32944c0..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/LfmRatingChanged.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.kelsos.mbrc.events.ui - -import com.kelsos.mbrc.features.player.LfmStatus - -class LfmRatingChanged( - val status: LfmStatus, -) diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/LyricsUpdatedEvent.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/LyricsUpdatedEvent.kt deleted file mode 100644 index aab9af1ff..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/LyricsUpdatedEvent.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.kelsos.mbrc.events.ui - -class LyricsUpdatedEvent( - val lyrics: String, -) diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/NotifyUser.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/NotifyUser.kt index fe5514461..ee363b7bc 100644 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/NotifyUser.kt +++ b/app/src/main/java/com/kelsos/mbrc/events/ui/NotifyUser.kt @@ -1,20 +1,8 @@ package com.kelsos.mbrc.events.ui -class NotifyUser { - val message: String - val resId: Int +abstract class NotifyUser { + abstract val message: String + abstract val resId: Int var isFromResource: Boolean = false private set - - constructor(message: String) { - this.message = message - this.isFromResource = false - this.resId = -1 - } - - constructor(resId: Int) { - this.resId = resId - this.isFromResource = true - this.message = "" - } } diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/PlayStateChange.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/PlayStateChange.kt deleted file mode 100644 index fe4feb90c..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/PlayStateChange.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.kelsos.mbrc.events.ui - -import com.kelsos.mbrc.annotations.PlayerState.State - -data class PlayStateChange( - @State val state: String, - val position: Long, -) diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/RatingChanged.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/RatingChanged.kt deleted file mode 100644 index a8726cefe..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/RatingChanged.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.kelsos.mbrc.events.ui - -class RatingChanged( - val rating: Float, -) diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/RemoteClientMetaData.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/RemoteClientMetaData.kt deleted file mode 100644 index 53e4bef56..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/RemoteClientMetaData.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.kelsos.mbrc.events.ui - -import com.kelsos.mbrc.features.player.TrackInfo - -data class RemoteClientMetaData( - val trackInfo: TrackInfo, - val coverPath: String = "", - val duration: Long, -) diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/RepeatChange.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/RepeatChange.kt deleted file mode 100644 index b1d5857de..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/RepeatChange.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.kelsos.mbrc.events.ui - -import com.kelsos.mbrc.annotations.Repeat.Mode - -class RepeatChange( - @Mode val mode: String, -) diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/RequestConnectionStateEvent.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/RequestConnectionStateEvent.kt deleted file mode 100644 index 0566fa5aa..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/RequestConnectionStateEvent.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.kelsos.mbrc.events.ui - -class RequestConnectionStateEvent diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/ScrobbleChange.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/ScrobbleChange.kt deleted file mode 100644 index 9573ac8ca..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/ScrobbleChange.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.kelsos.mbrc.events.ui - -class ScrobbleChange( - val isActive: Boolean, -) diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/ShuffleChange.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/ShuffleChange.kt deleted file mode 100644 index 71473edd4..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/ShuffleChange.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.kelsos.mbrc.events.ui - -import androidx.annotation.StringDef - -class ShuffleChange( - @ShuffleState val shuffleState: String, -) { - @StringDef(OFF, AUTODJ, SHUFFLE) - @Retention(AnnotationRetention.SOURCE) - annotation class ShuffleState - - companion object { - const val OFF = "off" - const val AUTODJ = "autodj" - const val SHUFFLE = "shuffle" - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/TrackInfoChangeEvent.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/TrackInfoChangeEvent.kt deleted file mode 100644 index bf489824e..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/TrackInfoChangeEvent.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.kelsos.mbrc.events.ui - -import com.kelsos.mbrc.features.player.TrackInfo - -data class TrackInfoChangeEvent( - val trackInfo: TrackInfo, -) diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/TrackMoved.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/TrackMoved.kt deleted file mode 100644 index 1a22b1f6f..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/TrackMoved.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.kelsos.mbrc.events.ui - -import com.fasterxml.jackson.databind.node.ObjectNode - -class TrackMoved( - node: ObjectNode, -) { - val isSuccess: Boolean = node.path("success").asBoolean() - val from: Int = node.path("from").asInt() - val to: Int = node.path("to").asInt() -} diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/TrackRemoval.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/TrackRemoval.kt deleted file mode 100644 index 0bbbc60ca..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/TrackRemoval.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.kelsos.mbrc.events.ui - -import com.fasterxml.jackson.databind.node.ObjectNode - -class TrackRemoval( - node: ObjectNode, -) { - val index: Int = node.path("index").asInt() - val isSuccess: Boolean = node.path("success").asBoolean() -} diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/UpdateDuration.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/UpdateDuration.kt deleted file mode 100644 index 0527cbf5f..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/UpdateDuration.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.kelsos.mbrc.events.ui - -class UpdateDuration( - val position: Int, - val duration: Int, -) diff --git a/app/src/main/java/com/kelsos/mbrc/events/ui/VolumeChange.kt b/app/src/main/java/com/kelsos/mbrc/events/ui/VolumeChange.kt deleted file mode 100644 index 18332e884..000000000 --- a/app/src/main/java/com/kelsos/mbrc/events/ui/VolumeChange.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.kelsos.mbrc.events.ui - -class VolumeChange { - var volume: Int = 0 - private set - var isMute: Boolean = false - private set - - constructor(vol: Int) { - this.volume = vol - this.isMute = false - } - - constructor() { - this.volume = 0 - this.isMute = true - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/extensions/EnableHome.kt b/app/src/main/java/com/kelsos/mbrc/extensions/EnableHome.kt deleted file mode 100644 index 6d987535a..000000000 --- a/app/src/main/java/com/kelsos/mbrc/extensions/EnableHome.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.kelsos.mbrc.extensions - -import androidx.appcompat.app.ActionBar - -fun ActionBar.enableHome(title: String?) { - this.setDisplayHomeAsUpEnabled(true) - this.setDisplayShowHomeEnabled(true) - this.title = title ?: "" -} diff --git a/app/src/main/java/com/kelsos/mbrc/extensions/FileExtensions.kt b/app/src/main/java/com/kelsos/mbrc/extensions/FileExtensions.kt deleted file mode 100644 index f22feca81..000000000 --- a/app/src/main/java/com/kelsos/mbrc/extensions/FileExtensions.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.kelsos.mbrc.extensions - -import java.io.File -import java.io.FileInputStream -import java.security.MessageDigest - -fun File.md5(): String? { - try { - val fin = FileInputStream(this) - val md5er = MessageDigest.getInstance("MD5") - val buffer = ByteArray(1024) - var read: Int - do { - read = fin.read(buffer) - if (read > 0) { - md5er.update(buffer, 0, read) - } - } while (read != -1) - fin.close() - val digest = md5er.digest() ?: return null - var str = "" - digest.indices.forEach { - str += Integer.toString((digest[it].toInt() and 0xff) + 0x100, 16).substring(1) - } - return str - } catch (e: Exception) { - return null - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/extensions/StringExtensions.kt b/app/src/main/java/com/kelsos/mbrc/extensions/StringExtensions.kt deleted file mode 100644 index b42f9bec3..000000000 --- a/app/src/main/java/com/kelsos/mbrc/extensions/StringExtensions.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.kelsos.mbrc.extensions - -fun String.escapeLike(): String = this.replace("%", "_") diff --git a/app/src/main/java/com/kelsos/mbrc/features/dragsort/OnStartDragListener.kt b/app/src/main/java/com/kelsos/mbrc/features/dragsort/OnStartDragListener.kt index cae15f921..d70123739 100644 --- a/app/src/main/java/com/kelsos/mbrc/features/dragsort/OnStartDragListener.kt +++ b/app/src/main/java/com/kelsos/mbrc/features/dragsort/OnStartDragListener.kt @@ -4,4 +4,6 @@ import androidx.recyclerview.widget.RecyclerView interface OnStartDragListener { fun onStartDrag(viewHolder: RecyclerView.ViewHolder) + + fun onDragComplete() } diff --git a/app/src/main/java/com/kelsos/mbrc/features/dragsort/SimpleItemTouchHelper.kt b/app/src/main/java/com/kelsos/mbrc/features/dragsort/SimpleItemTouchHelper.kt index 4fac4bc3a..505543ebb 100644 --- a/app/src/main/java/com/kelsos/mbrc/features/dragsort/SimpleItemTouchHelper.kt +++ b/app/src/main/java/com/kelsos/mbrc/features/dragsort/SimpleItemTouchHelper.kt @@ -64,10 +64,8 @@ class SimpleItemTouchHelper( viewHolder: RecyclerView.ViewHolder?, actionState: Int, ) { - if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { - if (viewHolder is TouchHelperViewHolder) { - viewHolder.onItemSelected() - } + if (actionState != ItemTouchHelper.ACTION_STATE_IDLE && viewHolder is TouchHelperViewHolder) { + viewHolder.onItemSelected() } super.onSelectedChanged(viewHolder, actionState) diff --git a/app/src/main/java/com/kelsos/mbrc/features/help/FeedbackFragment.kt b/app/src/main/java/com/kelsos/mbrc/features/help/FeedbackFragment.kt index 09f92fc9e..b8e52e339 100644 --- a/app/src/main/java/com/kelsos/mbrc/features/help/FeedbackFragment.kt +++ b/app/src/main/java/com/kelsos/mbrc/features/help/FeedbackFragment.kt @@ -12,12 +12,14 @@ import android.widget.CheckBox import android.widget.EditText import androidx.core.content.FileProvider import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import com.kelsos.mbrc.BuildConfig.APPLICATION_ID import com.kelsos.mbrc.R -import com.kelsos.mbrc.common.utilities.RemoteUtils.getVersion +import com.kelsos.mbrc.common.utilities.RemoteUtils.VERSION import com.kelsos.mbrc.logging.LogHelper -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.io.File class FeedbackFragment : Fragment() { @@ -26,6 +28,8 @@ class FeedbackFragment : Fragment() { private lateinit var logInfo: CheckBox private lateinit var feedbackButton: Button + val logHelper = LogHelper() + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -39,14 +43,9 @@ class FeedbackFragment : Fragment() { feedbackButton.setOnClickListener { onFeedbackButtonClicked() } - LogHelper - .logsExist(requireContext()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ - logInfo.isEnabled = true - }) { - } + lifecycleScope.launch { + logInfo.isEnabled = logHelper.logsExist(filesDir = requireContext().filesDir) + } return view } @@ -61,7 +60,7 @@ class FeedbackFragment : Fragment() { if (deviceInfo.isChecked) { val device = Build.DEVICE val manufacturer = Build.MANUFACTURER - val appVersion = requireContext().getVersion() + val appVersion = VERSION val androidVersion = Build.VERSION.RELEASE feedbackText += @@ -79,15 +78,20 @@ class FeedbackFragment : Fragment() { return } - LogHelper - .zipLogs(requireContext()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ - openChooser(feedbackText, it) - }) { - openChooser(feedbackText) + lifecycleScope.launch(Dispatchers.IO) { + val result = + runCatching { + logHelper.zipLogs(requireContext().filesDir, requireContext().externalCacheDir) + } + + withContext(Dispatchers.Main) { + if (result.isSuccess) { + openChooser(feedbackText, result.getOrNull()) + } else { + openChooser(feedbackText) + } } + } } private fun openChooser( diff --git a/app/src/main/java/com/kelsos/mbrc/features/help/HelpFragment.kt b/app/src/main/java/com/kelsos/mbrc/features/help/HelpFragment.kt index ef62b5a08..8e96f0ca9 100644 --- a/app/src/main/java/com/kelsos/mbrc/features/help/HelpFragment.kt +++ b/app/src/main/java/com/kelsos/mbrc/features/help/HelpFragment.kt @@ -1,6 +1,5 @@ package com.kelsos.mbrc.features.help -import android.content.pm.PackageManager import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -10,23 +9,14 @@ import android.webkit.WebView import android.webkit.WebViewClient import androidx.fragment.app.Fragment import com.kelsos.mbrc.R -import com.kelsos.mbrc.common.utilities.RemoteUtils.getVersion -import timber.log.Timber +import com.kelsos.mbrc.common.utilities.RemoteUtils class HelpFragment : Fragment() { private lateinit var helpView: WebView override fun onStart() { super.onStart() - val url: String = - try { - String.format("https://mbrc.kelsos.net/help?version=%s", requireContext().getVersion()) - } catch (e: PackageManager.NameNotFoundException) { - Timber.v(e, "Failed to get version") - "https://mbrc.kelsos.net/help" - } - - helpView.loadUrl(url) + helpView.loadUrl("https://mbrc.kelsos.net/help?version=${RemoteUtils.VERSION}") } override fun onCreateView( diff --git a/app/src/main/java/com/kelsos/mbrc/features/library/Album.kt b/app/src/main/java/com/kelsos/mbrc/features/library/Album.kt deleted file mode 100644 index 70d4fe246..000000000 --- a/app/src/main/java/com/kelsos/mbrc/features/library/Album.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.kelsos.mbrc.features.library - -import com.fasterxml.jackson.annotation.JsonIgnore -import com.fasterxml.jackson.annotation.JsonProperty -import com.kelsos.mbrc.common.utilities.RemoteUtils.sha1 -import com.kelsos.mbrc.data.Data -import com.kelsos.mbrc.data.Database -import com.raizlabs.android.dbflow.annotation.Column -import com.raizlabs.android.dbflow.annotation.PrimaryKey -import com.raizlabs.android.dbflow.annotation.Table - -@Table(name = "album", database = Database::class) -data class Album( - @JsonProperty("artist") - @Column - var artist: String? = null, - @JsonProperty("album") - @Column - var album: String? = null, - @JsonProperty("count") - @Column - var count: Int = 0, - @JsonIgnore - @Column - var cover: String? = null, - @JsonIgnore - @Column(name = "date_added") - var dateAdded: Long = 0, - @JsonIgnore - @Column - @PrimaryKey(autoincrement = true) - var id: Long = 0, -) : Data - -fun Album.key(): String = sha1("${artist}_$album") diff --git a/app/src/main/java/com/kelsos/mbrc/features/library/AlbumEntryAdapter.kt b/app/src/main/java/com/kelsos/mbrc/features/library/AlbumEntryAdapter.kt deleted file mode 100644 index 9aeb66b13..000000000 --- a/app/src/main/java/com/kelsos/mbrc/features/library/AlbumEntryAdapter.kt +++ /dev/null @@ -1,121 +0,0 @@ -package com.kelsos.mbrc.features.library - -import android.app.Activity -import android.view.LayoutInflater -import android.view.MenuItem -import android.view.View -import android.view.ViewGroup -import android.widget.LinearLayout -import android.widget.TextView -import androidx.appcompat.widget.PopupMenu -import androidx.core.view.isGone -import androidx.recyclerview.widget.RecyclerView -import coil3.load -import coil3.request.crossfade -import coil3.request.error -import coil3.request.placeholder -import coil3.size.Scale -import com.kelsos.mbrc.R -import com.kelsos.mbrc.common.ui.SquareImageView -import com.raizlabs.android.dbflow.list.FlowCursorList -import java.io.File - -class AlbumEntryAdapter( - context: Activity, -) : RecyclerView.Adapter() { - private val inflater: LayoutInflater = LayoutInflater.from(context) - private var data: FlowCursorList? = null - private var listener: MenuItemSelectedListener? = null - private val cache = File(context.cacheDir, "covers") - - override fun onCreateViewHolder( - parent: ViewGroup, - viewType: Int, - ): ViewHolder { - val view = inflater.inflate(R.layout.ui_list_dual, parent, false) - val holder = ViewHolder(view) - holder.indicator.setOnClickListener { - val popupMenu = PopupMenu(it.context, it) - popupMenu.inflate(R.menu.popup_album) - popupMenu.setOnMenuItemClickListener { menuItem -> - val data = this.data ?: return@setOnMenuItemClickListener false - val position = holder.bindingAdapterPosition.toLong() - val album = data.getItem(position) ?: return@setOnMenuItemClickListener false - listener?.onMenuItemSelected(menuItem, album) - true - } - popupMenu.show() - } - - holder.itemView.setOnClickListener { - val data = this.data ?: return@setOnClickListener - val position = holder.bindingAdapterPosition.toLong() - val album = data.getItem(position) ?: return@setOnClickListener - listener?.onItemClicked(album) - } - return holder - } - - override fun onBindViewHolder( - holder: ViewHolder, - position: Int, - ) { - val data = this.data ?: return - val item = data.getItem(position.toLong()) ?: return - val (artist, album) = item - holder.album.text = if (album.isNullOrBlank()) holder.emptyAlbum else album - holder.artist.text = if (artist.isNullOrBlank()) holder.unknownArtist else artist - - holder.image.load(File(cache, item.key())) { - crossfade(false) - placeholder(R.drawable.ic_image_no_cover) - error(R.drawable.ic_image_no_cover) - size( - holder.itemView.context.resources - .getDimensionPixelSize(R.dimen.list_album_size), - ) - scale(Scale.FILL) - } - } - - fun refresh() { - data?.refresh() - notifyDataSetChanged() - } - - override fun getItemCount(): Int = data?.count?.toInt() ?: 0 - - fun setMenuItemSelectedListener(listener: MenuItemSelectedListener) { - this.listener = listener - } - - interface MenuItemSelectedListener { - fun onMenuItemSelected( - menuItem: MenuItem, - album: Album, - ) - - fun onItemClicked(album: Album) - } - - class ViewHolder( - itemView: View, - ) : RecyclerView.ViewHolder(itemView) { - val artist: TextView = itemView.findViewById(R.id.line_two) - val album: TextView = itemView.findViewById(R.id.line_one) - val image: SquareImageView = itemView.findViewById(R.id.cover) - val indicator: LinearLayout = itemView.findViewById(R.id.ui_item_context_indicator) - - val unknownArtist: String = itemView.context.getString(R.string.unknown_artist) - val emptyAlbum: String = itemView.context.getString(R.string.non_album_tracks) - - init { - image.isGone = false - } - } - - fun update(albums: FlowCursorList) { - data = albums - notifyDataSetChanged() - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/features/library/AlbumRepository.kt b/app/src/main/java/com/kelsos/mbrc/features/library/AlbumRepository.kt deleted file mode 100644 index c52fcda0b..000000000 --- a/app/src/main/java/com/kelsos/mbrc/features/library/AlbumRepository.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.kelsos.mbrc.features.library - -import com.kelsos.mbrc.common.data.Repository -import com.raizlabs.android.dbflow.list.FlowCursorList - -interface AlbumRepository : Repository { - suspend fun getAlbumsByArtist(artist: String): FlowCursorList - - suspend fun updateCovers(updated: List) -} diff --git a/app/src/main/java/com/kelsos/mbrc/features/library/AlbumRepositoryImpl.kt b/app/src/main/java/com/kelsos/mbrc/features/library/AlbumRepositoryImpl.kt deleted file mode 100644 index d742bac60..000000000 --- a/app/src/main/java/com/kelsos/mbrc/features/library/AlbumRepositoryImpl.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.kelsos.mbrc.features.library - -import com.kelsos.mbrc.common.utilities.AppCoroutineDispatchers -import com.raizlabs.android.dbflow.list.FlowCursorList -import kotlinx.coroutines.flow.onCompletion -import kotlinx.coroutines.withContext -import java.time.Instant - -class AlbumRepositoryImpl( - private val localDataSource: LocalAlbumDataSource, - private val remoteDataSource: RemoteAlbumDataSource, - private val dispatchers: AppCoroutineDispatchers, -) : AlbumRepository { - override suspend fun getAlbumsByArtist(artist: String): FlowCursorList = localDataSource.getAlbumsByArtist(artist) - - override suspend fun getAllCursor(): FlowCursorList = localDataSource.loadAllCursor() - - override suspend fun getAndSaveRemote(): FlowCursorList { - getRemote() - return localDataSource.loadAllCursor() - } - - override suspend fun getRemote() { - val epoch = Instant.now().epochSecond - val default = CachedAlbumInfo(0, null) - val cached = - localDataSource.loadAllCursor().associate { - it.album + it.artist to CachedAlbumInfo(it.id, it?.cover) - } - withContext(dispatchers.io) { - remoteDataSource - .fetch() - .onCompletion { - localDataSource.removePreviousEntries(epoch) - }.collect { albums -> - val list = - albums.map { - it.apply { - dateAdded = epoch - val key = it.album + it.artist - - if (cached.containsKey(key)) { - val cachedAlbum = cached.getOrDefault(key, default) - id = cachedAlbum.id - cover = cachedAlbum.cover - } - } - } - localDataSource.saveAll(list) - } - } - } - - override suspend fun search(term: String): FlowCursorList = localDataSource.search(term) - - override suspend fun cacheIsEmpty(): Boolean = localDataSource.isEmpty() - - override suspend fun count(): Long = localDataSource.count() - - override suspend fun updateCovers(updated: List) { - localDataSource.updateCovers(updated) - } -} diff --git a/app/src/main/java/com/kelsos/mbrc/features/library/AlbumTracksActivity.kt b/app/src/main/java/com/kelsos/mbrc/features/library/AlbumTracksActivity.kt deleted file mode 100644 index 694ba474f..000000000 --- a/app/src/main/java/com/kelsos/mbrc/features/library/AlbumTracksActivity.kt +++ /dev/null @@ -1,163 +0,0 @@ -package com.kelsos.mbrc.features.library - -import android.os.Bundle -import android.view.MenuItem -import android.widget.Button -import android.widget.ImageView -import android.widget.TextView -import androidx.activity.OnBackPressedCallback -import androidx.core.os.BundleCompat -import androidx.core.view.isVisible -import androidx.recyclerview.widget.LinearLayoutManager -import coil3.load -import coil3.request.crossfade -import coil3.request.error -import coil3.request.placeholder -import coil3.size.Scale -import com.google.android.material.snackbar.Snackbar -import com.kelsos.mbrc.R -import com.kelsos.mbrc.common.ui.EmptyRecyclerView -import com.kelsos.mbrc.common.utilities.RemoteUtils.sha1 -import com.kelsos.mbrc.features.queue.PopupActionHandler -import com.raizlabs.android.dbflow.list.FlowCursorList -import org.koin.android.ext.android.inject -import org.koin.androidx.scope.ScopeActivity -import java.io.File - -class AlbumTracksActivity : - ScopeActivity(), - AlbumTracksView, - TrackEntryAdapter.MenuItemSelectedListener { - private val adapter: TrackEntryAdapter by inject() - private val actionHandler: PopupActionHandler by inject() - private val presenter: AlbumTracksPresenter by inject() - - private var album: AlbumInfo? = null - private lateinit var recyclerView: EmptyRecyclerView - - public override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_album_tracks) - onBackPressedDispatcher.addCallback( - this, - object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - finish() - } - }, - ) - - val extras = intent.extras - - if (extras != null) { - album = BundleCompat.getParcelable(extras, ALBUM, AlbumInfo::class.java) - } - - val selectedAlbum = album - if (selectedAlbum == null) { - finish() - return - } - - setSupportActionBar(findViewById(R.id.toolbar)) - val supportActionBar = supportActionBar ?: error("Actionbar should not be null") - supportActionBar.setDisplayHomeAsUpEnabled(true) - supportActionBar.setDisplayShowHomeEnabled(true) - - if (selectedAlbum.album.isEmpty()) { - supportActionBar.setTitle(R.string.non_album_tracks) - } else { - supportActionBar.title = selectedAlbum.album - } - - findViewById(R.id.album_tracks__album).text = selectedAlbum.album - findViewById(R.id.album_tracks__artist).text = selectedAlbum.artist - loadCover(selectedAlbum.artist, selectedAlbum.album) - - presenter.attach(this) - presenter.load(selectedAlbum) - adapter.setMenuItemSelectedListener(this) - recyclerView = findViewById(R.id.list_tracks) - recyclerView.layoutManager = LinearLayoutManager(baseContext) - recyclerView.adapter = adapter - recyclerView.emptyView = findViewById(R.id.empty_view) - val play = findViewById