├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml └── workflows │ ├── nightly.yml │ ├── pr.yml │ └── stable.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── google-services.json └── src │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── java │ │ └── dev │ │ │ └── brahmkshatriya │ │ │ └── echo │ │ │ ├── MainActivity.kt │ │ │ ├── MainApplication.kt │ │ │ ├── di │ │ │ ├── App.kt │ │ │ └── DI.kt │ │ │ ├── download │ │ │ ├── Downloader.kt │ │ │ ├── db │ │ │ │ ├── DownloadDao.kt │ │ │ │ ├── DownloadDatabase.kt │ │ │ │ └── models │ │ │ │ │ ├── ContextEntity.kt │ │ │ │ │ ├── DownloadEntity.kt │ │ │ │ │ ├── TaskStatus.kt │ │ │ │ │ └── TaskType.kt │ │ │ ├── exceptions │ │ │ │ ├── DownloadException.kt │ │ │ │ └── DownloaderExtensionNotFoundException.kt │ │ │ └── workers │ │ │ │ ├── BaseWorker.kt │ │ │ │ ├── DownloadingWorker.kt │ │ │ │ ├── LoadingWorker.kt │ │ │ │ ├── MergingWorker.kt │ │ │ │ └── TaggingWorker.kt │ │ │ ├── extensions │ │ │ ├── ExtensionLoader.kt │ │ │ ├── ExtensionUtils.kt │ │ │ ├── Extensions.kt │ │ │ ├── InjectedRepo.kt │ │ │ ├── InstallationUtils.kt │ │ │ ├── SettingsUtils.kt │ │ │ ├── Updater.kt │ │ │ ├── WebViewClientImpl.kt │ │ │ ├── builtin │ │ │ │ ├── offline │ │ │ │ │ ├── Convertors.kt │ │ │ │ │ ├── MediaStoreUtils.kt │ │ │ │ │ └── OfflineExtension.kt │ │ │ │ ├── test │ │ │ │ │ ├── DownloadExtension.kt │ │ │ │ │ ├── TestExtension.kt │ │ │ │ │ └── TrackerTestExtension.kt │ │ │ │ └── unified │ │ │ │ │ ├── UnifiedDatabase.kt │ │ │ │ │ └── UnifiedExtension.kt │ │ │ ├── db │ │ │ │ ├── ExtensionDao.kt │ │ │ │ ├── ExtensionDatabase.kt │ │ │ │ ├── UserDao.kt │ │ │ │ └── models │ │ │ │ │ ├── CurrentUser.kt │ │ │ │ │ ├── ExtensionEntity.kt │ │ │ │ │ └── UserEntity.kt │ │ │ ├── exceptions │ │ │ │ ├── AppException.kt │ │ │ │ ├── ExtensionLoaderException.kt │ │ │ │ ├── ExtensionNotFoundException.kt │ │ │ │ ├── InvalidExtensionListException.kt │ │ │ │ ├── RequiredExtensionsMissingException.kt │ │ │ │ └── UpdateException.kt │ │ │ └── plugger │ │ │ │ ├── ExtensionsRepo.kt │ │ │ │ ├── impl │ │ │ │ ├── AppInfo.kt │ │ │ │ ├── BuiltInRepo.kt │ │ │ │ ├── DexLoader.kt │ │ │ │ ├── InjectablePluginRepo.kt │ │ │ │ ├── app │ │ │ │ │ ├── ApkManifestParser.kt │ │ │ │ │ └── InstalledAppSource.kt │ │ │ │ └── file │ │ │ │ │ ├── ApkLinkParser.kt │ │ │ │ │ ├── FileParser.kt │ │ │ │ │ └── FilePluginSource.kt │ │ │ │ └── interfaces │ │ │ │ ├── ManifestParser.kt │ │ │ │ ├── PluginLoader.kt │ │ │ │ ├── PluginRepo.kt │ │ │ │ └── PluginSource.kt │ │ │ ├── playback │ │ │ ├── AndroidAutoCallback.kt │ │ │ ├── MediaItemUtils.kt │ │ │ ├── PlayerCallback.kt │ │ │ ├── PlayerCommands.kt │ │ │ ├── PlayerService.kt │ │ │ ├── PlayerState.kt │ │ │ ├── ResumptionUtils.kt │ │ │ ├── ShufflePlayer.kt │ │ │ ├── exceptions │ │ │ │ ├── NoServersException.kt │ │ │ │ ├── NoSourceException.kt │ │ │ │ └── PlayerException.kt │ │ │ ├── listener │ │ │ │ ├── AudioFocusListener.kt │ │ │ │ ├── EffectsListener.kt │ │ │ │ ├── MediaSessionServiceListener.kt │ │ │ │ ├── PlayerEventListener.kt │ │ │ │ ├── PlayerRadio.kt │ │ │ │ └── TrackingListener.kt │ │ │ ├── renderer │ │ │ │ ├── PlayerBitmapLoader.kt │ │ │ │ └── RenderersFactory.kt │ │ │ └── source │ │ │ │ ├── ByteStreamDataSource.kt │ │ │ │ ├── CustomCacheDataSource.kt │ │ │ │ ├── StreamableDataSource.kt │ │ │ │ ├── StreamableLoader.kt │ │ │ │ ├── StreamableMediaSource.kt │ │ │ │ └── StreamableResolver.kt │ │ │ ├── ui │ │ │ ├── UiViewModel.kt │ │ │ ├── common │ │ │ │ ├── ExceptionFragment.kt │ │ │ │ ├── ExceptionUtils.kt │ │ │ │ ├── FragmentUtils.kt │ │ │ │ ├── PagingUtils.kt │ │ │ │ └── SnackBarHandler.kt │ │ │ ├── download │ │ │ │ ├── DownloadFragment.kt │ │ │ │ ├── DownloadViewModel.kt │ │ │ │ └── DownloadsAdapter.kt │ │ │ ├── extensions │ │ │ │ ├── ExtensionInfoFragment.kt │ │ │ │ ├── ExtensionInfoPreference.kt │ │ │ │ ├── ExtensionOpenerActivity.kt │ │ │ │ ├── ExtensionsViewModel.kt │ │ │ │ ├── WebViewFragment.kt │ │ │ │ ├── add │ │ │ │ │ ├── ExtensionInstallerBottomSheet.kt │ │ │ │ │ ├── ExtensionsAddListAdapter.kt │ │ │ │ │ └── ExtensionsAddListBottomSheet.kt │ │ │ │ ├── list │ │ │ │ │ ├── ExtensionListViewModel.kt │ │ │ │ │ └── ExtensionsListBottomSheet.kt │ │ │ │ ├── login │ │ │ │ │ ├── LoginFragment.kt │ │ │ │ │ ├── LoginUserBottomSheet.kt │ │ │ │ │ ├── LoginUserListBottomSheet.kt │ │ │ │ │ ├── LoginUserListViewModel.kt │ │ │ │ │ └── LoginViewModel.kt │ │ │ │ └── manage │ │ │ │ │ ├── ExtensionAdapter.kt │ │ │ │ │ └── ManageExtensionsFragment.kt │ │ │ ├── main │ │ │ │ ├── FeedViewModel.kt │ │ │ │ ├── MainFragment.kt │ │ │ │ ├── home │ │ │ │ │ ├── HomeFeedViewModel.kt │ │ │ │ │ └── HomeFragment.kt │ │ │ │ ├── library │ │ │ │ │ ├── LibraryFragment.kt │ │ │ │ │ └── LibraryViewModel.kt │ │ │ │ └── search │ │ │ │ │ ├── QuickSearchAdapter.kt │ │ │ │ │ ├── QuickSearchViewHolder.kt │ │ │ │ │ ├── SearchFragment.kt │ │ │ │ │ └── SearchViewModel.kt │ │ │ ├── media │ │ │ │ ├── MediaFragment.kt │ │ │ │ ├── MediaViewModel.kt │ │ │ │ ├── SortBottomSheet.kt │ │ │ │ ├── adapter │ │ │ │ │ ├── GenericItemAdapter.kt │ │ │ │ │ ├── MediaHeaderAdapter.kt │ │ │ │ │ ├── MediaItemSelectableAdapter.kt │ │ │ │ │ ├── SearchHeaderAdapter.kt │ │ │ │ │ ├── TrackAdapter.kt │ │ │ │ │ └── TrackSort.kt │ │ │ │ └── more │ │ │ │ │ ├── Action.kt │ │ │ │ │ ├── LoadingAdapter.kt │ │ │ │ │ └── MediaMoreBottomSheet.kt │ │ │ ├── player │ │ │ │ ├── PlayerColors.kt │ │ │ │ ├── PlayerFragment.kt │ │ │ │ ├── PlayerMoreFragment.kt │ │ │ │ ├── PlayerTrackAdapter.kt │ │ │ │ ├── PlayerUiListener.kt │ │ │ │ ├── PlayerViewModel.kt │ │ │ │ ├── audiofx │ │ │ │ │ └── AudioEffectsBottomSheet.kt │ │ │ │ ├── info │ │ │ │ │ ├── InfoFragment.kt │ │ │ │ │ ├── TrackInfoAdapter.kt │ │ │ │ │ └── TrackInfoViewModel.kt │ │ │ │ ├── lyrics │ │ │ │ │ ├── LyricAdapter.kt │ │ │ │ │ ├── LyricsFragment.kt │ │ │ │ │ ├── LyricsItemAdapter.kt │ │ │ │ │ └── LyricsViewModel.kt │ │ │ │ ├── quality │ │ │ │ │ ├── FormatUtils.kt │ │ │ │ │ └── QualitySelectionBottomSheet.kt │ │ │ │ ├── sleep │ │ │ │ │ └── SleepTimerBottomSheet.kt │ │ │ │ └── upnext │ │ │ │ │ ├── QueueAdapter.kt │ │ │ │ │ └── QueueFragment.kt │ │ │ ├── playlist │ │ │ │ ├── CreatePlaylistBottomSheet.kt │ │ │ │ ├── edit │ │ │ │ │ ├── EditPlaylistFragment.kt │ │ │ │ │ ├── EditPlaylistHeaderAdapter.kt │ │ │ │ │ ├── EditPlaylistViewModel.kt │ │ │ │ │ ├── PlaylistAdapter.kt │ │ │ │ │ └── search │ │ │ │ │ │ ├── EditPlaylistSearchClickListener.kt │ │ │ │ │ │ ├── EditPlaylistSearchFragment.kt │ │ │ │ │ │ └── EditPlaylistSearchViewModel.kt │ │ │ │ └── save │ │ │ │ │ ├── SaveButtonAdapter.kt │ │ │ │ │ ├── SaveToPlaylistBottomSheet.kt │ │ │ │ │ ├── SaveToPlaylistViewModel.kt │ │ │ │ │ └── TopAppBarAdapter.kt │ │ │ ├── settings │ │ │ │ ├── AudioEffectsFragment.kt │ │ │ │ ├── AudioFragment.kt │ │ │ │ ├── BaseSettingsFragment.kt │ │ │ │ ├── LookFragment.kt │ │ │ │ ├── MiscFragment.kt │ │ │ │ └── SettingsFragment.kt │ │ │ └── shelf │ │ │ │ ├── ShelfFragment.kt │ │ │ │ ├── ShelfViewModel.kt │ │ │ │ └── adapter │ │ │ │ ├── CategoryShelfViewHolder.kt │ │ │ │ ├── ListsShelfViewHolder.kt │ │ │ │ ├── MediaItemViewHolder.kt │ │ │ │ ├── ShelfAdapter.kt │ │ │ │ ├── ShelfClickListener.kt │ │ │ │ ├── lists │ │ │ │ ├── CategoryShelfListsViewHolder.kt │ │ │ │ ├── GridMediaShelfListsViewHolder.kt │ │ │ │ ├── MediaItemShelfListsViewHolder.kt │ │ │ │ ├── ShelfListsAdapter.kt │ │ │ │ └── ThreeTrackShelfListsViewHolder.kt │ │ │ │ └── other │ │ │ │ ├── ShelfEmptyAdapter.kt │ │ │ │ ├── ShelfLoadingAdapter.kt │ │ │ │ ├── ShelfSearchHeaderAdapter.kt │ │ │ │ ├── ShelfSort.kt │ │ │ │ └── ShelfSortBottomSheet.kt │ │ │ ├── utils │ │ │ ├── AdjustableSemaphore.kt │ │ │ ├── AppShortcuts.kt │ │ │ ├── AppUpdater.kt │ │ │ ├── CacheUtils.kt │ │ │ ├── ContextUtils.kt │ │ │ ├── CoroutineUtils.kt │ │ │ ├── PauseTimer.kt │ │ │ ├── PermsUtils.kt │ │ │ ├── Serializer.kt │ │ │ ├── Sticky.kt │ │ │ ├── image │ │ │ │ ├── BlurTransformation.kt │ │ │ │ ├── ImageUtils.kt │ │ │ │ └── SquareCropTransformation.kt │ │ │ └── ui │ │ │ │ ├── AnimationUtils.kt │ │ │ │ ├── AutoClearedValue.kt │ │ │ │ ├── CheckBoxListener.kt │ │ │ │ ├── FastScrollerHelper.kt │ │ │ │ ├── GestureListener.kt │ │ │ │ ├── GradientDrawable.kt │ │ │ │ ├── RulerAdapter.kt │ │ │ │ ├── ShimmerLayoutSelf.kt │ │ │ │ ├── SimpleItemSpan.kt │ │ │ │ ├── UiUtils.kt │ │ │ │ ├── ViewPager2Utils.kt │ │ │ │ └── prefs │ │ │ │ ├── ColorListPreference.kt │ │ │ │ ├── ColorPickerDialog.kt │ │ │ │ ├── LongClickPreference.kt │ │ │ │ ├── MaterialListPreference.kt │ │ │ │ ├── MaterialMultipleChoicePreference.kt │ │ │ │ ├── MaterialSliderPreference.kt │ │ │ │ ├── MaterialTextInputPreference.kt │ │ │ │ ├── SwitchLongClickPreference.kt │ │ │ │ └── TransitionPreference.kt │ │ │ └── widget │ │ │ ├── AppWidget.kt │ │ │ └── WidgetPlayerListener.kt │ └── res │ │ ├── color │ │ ├── button_player.xml │ │ ├── button_player_more.xml │ │ ├── button_player_ripple.xml │ │ └── nav_bar_icon.xml │ │ ├── drawable-land │ │ └── gradient_track.xml │ │ ├── drawable-nodpi │ │ └── example_appwidget_preview.png │ │ ├── drawable │ │ ├── anim_bookmark.xml │ │ ├── anim_heart_40dp.xml │ │ ├── anim_home.xml │ │ ├── anim_now_playing.xml │ │ ├── anim_play_pause.xml │ │ ├── anim_play_pause_48dp.xml │ │ ├── anim_search.xml │ │ ├── anim_shuffle.xml │ │ ├── app_widget_gradient_background.xml │ │ ├── app_widget_image_background.xml │ │ ├── app_widget_inner_view_background.xml │ │ ├── art_album.xml │ │ ├── art_artist.xml │ │ ├── art_brand.xml │ │ ├── art_download_for_offline.xml │ │ ├── art_downloading.xml │ │ ├── art_edit_note.xml │ │ ├── art_library_music.xml │ │ ├── art_music.xml │ │ ├── art_person.xml │ │ ├── art_problem.xml │ │ ├── art_sensors.xml │ │ ├── art_shivam.xml │ │ ├── art_splash_anim.xml │ │ ├── dialog_bg.xml │ │ ├── gradient_track.xml │ │ ├── ic_account_circle.xml │ │ ├── ic_account_circle_48dp.xml │ │ ├── ic_add_20dp.xml │ │ ├── ic_add_circle.xml │ │ ├── ic_add_photo_alternate.xml │ │ ├── ic_album.xml │ │ ├── ic_article.xml │ │ ├── ic_artist.xml │ │ ├── ic_back.xml │ │ ├── ic_bookmark_anim.xml │ │ ├── ic_bookmark_filled.xml │ │ ├── ic_bookmark_outline.xml │ │ ├── ic_check_20dp.xml │ │ ├── ic_close.xml │ │ ├── ic_close_small.xml │ │ ├── ic_copy.xml │ │ ├── ic_delete.xml │ │ ├── ic_download_for_offline.xml │ │ ├── ic_downloading.xml │ │ ├── ic_drag_20dp.xml │ │ ├── ic_edit_note.xml │ │ ├── ic_email.xml │ │ ├── ic_equalizer.xml │ │ ├── ic_expand_more.xml │ │ ├── ic_extension.xml │ │ ├── ic_extension_48dp.xml │ │ ├── ic_favorite_20dp.xml │ │ ├── ic_favorite_filled_20dp.xml │ │ ├── ic_files.xml │ │ ├── ic_forward.xml │ │ ├── ic_heart_filled_40dp.xml │ │ ├── ic_heart_filled_to_outline_40dp.xml │ │ ├── ic_heart_outline_40dp.xml │ │ ├── ic_heart_outline_to_filled_40dp.xml │ │ ├── ic_hide_filled.xml │ │ ├── ic_hide_outline.xml │ │ ├── ic_high_quality.xml │ │ ├── ic_history.xml │ │ ├── ic_home_anim.xml │ │ ├── ic_home_filled.xml │ │ ├── ic_home_outline.xml │ │ ├── ic_incognito.xml │ │ ├── ic_info.xml │ │ ├── ic_input.xml │ │ ├── ic_language.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_launcher_monochrome.xml │ │ ├── ic_library_music.xml │ │ ├── ic_login.xml │ │ ├── ic_logout.xml │ │ ├── ic_mono.xml │ │ ├── ic_more_horiz.xml │ │ ├── ic_music.xml │ │ ├── ic_numbers.xml │ │ ├── ic_offline.xml │ │ ├── ic_palette.xml │ │ ├── ic_password.xml │ │ ├── ic_pause.xml │ │ ├── ic_pause_48dp.xml │ │ ├── ic_pause_to_play_48dp_anim.xml │ │ ├── ic_pause_to_play_anim.xml │ │ ├── ic_person.xml │ │ ├── ic_play.xml │ │ ├── ic_play_48dp.xml │ │ ├── ic_play_to_pause_48dp_anim.xml │ │ ├── ic_play_to_pause_anim.xml │ │ ├── ic_playlist_add.xml │ │ ├── ic_playlist_play.xml │ │ ├── ic_queue_music.xml │ │ ├── ic_refresh.xml │ │ ├── ic_repeat_20dp.xml │ │ ├── ic_repeat_40dp.xml │ │ ├── ic_repeat_off_40dp.xml │ │ ├── ic_repeat_off_to_repeat_40dp.xml │ │ ├── ic_repeat_on_20dp.xml │ │ ├── ic_repeat_one_20dp.xml │ │ ├── ic_repeat_one_40dp.xml │ │ ├── ic_repeat_one_to_repeat_off_40dp.xml │ │ ├── ic_repeat_to_repeat_one_40dp.xml │ │ ├── ic_save.xml │ │ ├── ic_schedule.xml │ │ ├── ic_search_anim.xml │ │ ├── ic_search_filled.xml │ │ ├── ic_search_outline.xml │ │ ├── ic_sensors.xml │ │ ├── ic_settings_outline.xml │ │ ├── ic_shuffle.xml │ │ ├── ic_shuffle_40dp.xml │ │ ├── ic_shuffle_on_40dp.xml │ │ ├── ic_skip_next_40dp.xml │ │ ├── ic_skip_previous_40dp.xml │ │ ├── ic_snooze.xml │ │ ├── ic_sort.xml │ │ ├── ripple_44dp.xml │ │ ├── ripple_60dp.xml │ │ ├── ripple_68dp.xml │ │ ├── ripple_item_container.xml │ │ ├── rounded_rectangle_24dp.xml │ │ ├── rounded_rectangle_cover.xml │ │ ├── rounded_rectangle_cover_profile.xml │ │ ├── shape_rounded_4dp.xml │ │ ├── shape_rounded_item_corner.xml │ │ └── tab_indicator.xml │ │ ├── layout-land │ │ ├── activity_main.xml │ │ ├── fragment_player.xml │ │ └── item_player_track.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── app_widget_large.xml │ │ ├── app_widget_medium.xml │ │ ├── app_widget_small.xml │ │ ├── button_extension.xml │ │ ├── dialog_color_picker.xml │ │ ├── dialog_extension_add.xml │ │ ├── dialog_extension_installer.xml │ │ ├── dialog_extensions_add_list.xml │ │ ├── dialog_extensions_list.xml │ │ ├── dialog_login_user.xml │ │ ├── dialog_login_user_list.xml │ │ ├── dialog_media_more.xml │ │ ├── dialog_player_audio_fx.xml │ │ ├── dialog_player_quality_selection.xml │ │ ├── dialog_player_sleep_timer.xml │ │ ├── dialog_playlist_create.xml │ │ ├── dialog_playlist_save.xml │ │ ├── dialog_sort.xml │ │ ├── fragment_audio_fx.xml │ │ ├── fragment_download.xml │ │ ├── fragment_exception.xml │ │ ├── fragment_extension_login_custom_input.xml │ │ ├── fragment_extension_login_selector.xml │ │ ├── fragment_generic_collapsable.xml │ │ ├── fragment_home.xml │ │ ├── fragment_library.xml │ │ ├── fragment_main.xml │ │ ├── fragment_manage_extensions.xml │ │ ├── fragment_media.xml │ │ ├── fragment_player.xml │ │ ├── fragment_player_info.xml │ │ ├── fragment_player_lyrics.xml │ │ ├── fragment_player_more.xml │ │ ├── fragment_player_queue.xml │ │ ├── fragment_playlist_edit.xml │ │ ├── fragment_playlist_search.xml │ │ ├── fragment_search.xml │ │ ├── fragment_shelf.xml │ │ ├── fragment_webview.xml │ │ ├── item_click_panels.xml │ │ ├── item_color_card.xml │ │ ├── item_download.xml │ │ ├── item_download_task.xml │ │ ├── item_edit_playlist_header.xml │ │ ├── item_edit_text.xml │ │ ├── item_extension.xml │ │ ├── item_extension_add.xml │ │ ├── item_extension_add_footer.xml │ │ ├── item_extension_add_header.xml │ │ ├── item_input.xml │ │ ├── item_loading.xml │ │ ├── item_login_user.xml │ │ ├── item_lyric.xml │ │ ├── item_lyrics_item.xml │ │ ├── item_media_header.xml │ │ ├── item_media_selectable.xml │ │ ├── item_player_collapsed.xml │ │ ├── item_player_collapsed_controls.xml │ │ ├── item_player_controls.xml │ │ ├── item_player_track.xml │ │ ├── item_playlist_save_footer.xml │ │ ├── item_playlist_save_header.xml │ │ ├── item_playlist_track.xml │ │ ├── item_quick_search_media.xml │ │ ├── item_quick_search_query.xml │ │ ├── item_ruler.xml │ │ ├── item_selectable_header.xml │ │ ├── item_shelf_category.xml │ │ ├── item_shelf_empty.xml │ │ ├── item_shelf_error.xml │ │ ├── item_shelf_lists.xml │ │ ├── item_shelf_lists_four_tracks.xml │ │ ├── item_shelf_lists_media.xml │ │ ├── item_shelf_lists_media_grid.xml │ │ ├── item_shelf_login_required.xml │ │ ├── item_shelf_media.xml │ │ ├── item_shelf_media_cover.xml │ │ ├── item_shelf_not_loading.xml │ │ ├── item_shelf_track_card.xml │ │ ├── item_text_button.xml │ │ ├── item_track_info.xml │ │ ├── item_track_list_header.xml │ │ ├── preference.xml │ │ ├── preference_category.xml │ │ ├── preference_color_list.xml │ │ ├── preference_common.xml │ │ ├── preference_extension_info.xml │ │ ├── preference_slider.xml │ │ ├── preference_switch.xml │ │ ├── skeleton_shelf.xml │ │ ├── skeleton_shelf_lists.xml │ │ ├── skeleton_shelf_lists_media_item.xml │ │ ├── skeleton_track.xml │ │ └── skeleton_track_list.xml │ │ ├── menu │ │ ├── create_playlist_menu.xml │ │ ├── delete_menu.xml │ │ ├── exception_menu.xml │ │ ├── extensions_menu.xml │ │ ├── lyrics_menu.xml │ │ ├── more_menu.xml │ │ ├── nav_menu.xml │ │ ├── refresh_menu.xml │ │ ├── settings_menu.xml │ │ ├── sleep_timer_menu.xml │ │ └── top_bar_menu.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── resources.properties │ │ ├── values-land │ │ ├── dimens.xml │ │ ├── integers.xml │ │ └── styles.xml │ │ ├── values-night │ │ ├── colors.xml │ │ └── themes.xml │ │ ├── values │ │ ├── attributes.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── integers.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ └── themes.xml │ │ └── xml │ │ ├── app_widget_info.xml │ │ ├── automotive_app_desc.xml │ │ └── provider_paths.xml │ └── nightly │ ├── ic_launcher-playstore.png │ └── res │ ├── drawable │ └── ic_launcher_foreground.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-mdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ └── values │ └── ic_launcher_background.xml ├── build.gradle.kts ├── common ├── .gitignore ├── build.gradle.kts └── src │ └── main │ ├── java │ └── dev │ │ └── brahmkshatriya │ │ └── echo │ │ └── common │ │ ├── Extension.kt │ │ ├── README.md │ │ ├── clients │ │ ├── AlbumClient.kt │ │ ├── ArtistClient.kt │ │ ├── ArtistFollowClient.kt │ │ ├── DownloadClient.kt │ │ ├── ExtensionClient.kt │ │ ├── HomeFeedClient.kt │ │ ├── LibraryFeedClient.kt │ │ ├── LoginClient.kt │ │ ├── LyricsClient.kt │ │ ├── LyricsSearchClient.kt │ │ ├── PlaylistClient.kt │ │ ├── PlaylistEditClient.kt │ │ ├── PlaylistEditCoverClient.kt │ │ ├── PlaylistEditPrivacyClient.kt │ │ ├── PlaylistEditorListenerClient.kt │ │ ├── RadioClient.kt │ │ ├── SaveToLibraryClient.kt │ │ ├── SearchFeedClient.kt │ │ ├── SettingsChangeListenerClient.kt │ │ ├── ShareClient.kt │ │ ├── TrackClient.kt │ │ ├── TrackHideClient.kt │ │ ├── TrackLikeClient.kt │ │ ├── TrackerClient.kt │ │ └── UserClient.kt │ │ ├── helpers │ │ ├── ClientException.kt │ │ ├── ContinuationCallback.kt │ │ ├── ExtensionType.kt │ │ ├── ImportType.kt │ │ ├── Injectable.kt │ │ ├── Page.kt │ │ ├── PagedData.kt │ │ ├── WebViewClient.kt │ │ └── WebViewRequest.kt │ │ ├── models │ │ ├── Album.kt │ │ ├── Artist.kt │ │ ├── Date.kt │ │ ├── DownloadContext.kt │ │ ├── EchoMediaItem.kt │ │ ├── ImageHolder.kt │ │ ├── Lyrics.kt │ │ ├── Message.kt │ │ ├── Metadata.kt │ │ ├── Playlist.kt │ │ ├── Progress.kt │ │ ├── QuickSearchItem.kt │ │ ├── Radio.kt │ │ ├── Request.kt │ │ ├── Shelf.kt │ │ ├── Streamable.kt │ │ ├── Tab.kt │ │ ├── Track.kt │ │ ├── TrackDetails.kt │ │ └── User.kt │ │ ├── providers │ │ ├── LyricsExtensionsProvider.kt │ │ ├── MessageFlowProvider.kt │ │ ├── MetadataProvider.kt │ │ ├── MiscExtensionsProvider.kt │ │ ├── MusicExtensionsProvider.kt │ │ ├── SettingsProvider.kt │ │ ├── TrackerExtensionsProvider.kt │ │ └── WebViewClientProvider.kt │ │ └── settings │ │ ├── Setting.kt │ │ ├── SettingCategory.kt │ │ ├── SettingItem.kt │ │ ├── SettingList.kt │ │ ├── SettingMultipleChoice.kt │ │ ├── SettingOnClick.kt │ │ ├── SettingSlider.kt │ │ ├── SettingSwitch.kt │ │ ├── SettingTextInput.kt │ │ └── Settings.kt │ └── resources │ └── META-INF │ └── proguard │ └── consumer-proguard-rules.pro ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.yml └── settings.gradle.kts /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [brahmkshatriya] 2 | ko_fi: brahmkshatriya 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Discord Server 4 | url: https://discord.gg/J3WvbBUU8Z 5 | about: Join our Discord server for support and updates. 6 | - name: Telegram group 7 | url: https://t.me/echo_extension 8 | about: Join our Telegram discussion group for support and updates. -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: pr build 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | workflow_dispatch: { } 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout repo 13 | uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 0 16 | 17 | - name: Setup JDK 17 18 | uses: actions/setup-java@v4 19 | with: 20 | distribution: 'zulu' 21 | java-version: 17 22 | cache: 'gradle' 23 | 24 | - name: Make gradlew executable 25 | run: chmod +x ./gradlew 26 | 27 | - name: Build with Gradle 28 | run: ./gradlew assembleRelease 29 | 30 | - name: Upload APK 31 | uses: actions/upload-artifact@v4 32 | with: 33 | path: app/build/outputs/apk/release/app-release-unsigned.apk 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | local.properties 11 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /release -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/di/App.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.di 2 | 3 | import android.app.Application 4 | import android.content.SharedPreferences 5 | import dev.brahmkshatriya.echo.common.models.Message 6 | import kotlinx.coroutines.GlobalScope 7 | import kotlinx.coroutines.flow.MutableSharedFlow 8 | import kotlinx.coroutines.flow.collectLatest 9 | import kotlinx.coroutines.launch 10 | 11 | data class App( 12 | val context: Application, 13 | val settings: SharedPreferences, 14 | ) { 15 | val throwFlow = MutableSharedFlow() 16 | val messageFlow = MutableSharedFlow() 17 | 18 | init { 19 | @Suppress("OPT_IN_USAGE") 20 | GlobalScope.launch { 21 | throwFlow.collectLatest { 22 | it.printStackTrace() 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/download/db/DownloadDatabase.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.download.db 2 | 3 | import android.app.Application 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import dev.brahmkshatriya.echo.download.db.models.ContextEntity 8 | import dev.brahmkshatriya.echo.download.db.models.DownloadEntity 9 | 10 | @Database( 11 | entities = [ 12 | ContextEntity::class, 13 | DownloadEntity::class 14 | ], 15 | version = 4, 16 | exportSchema = false 17 | ) 18 | abstract class DownloadDatabase : RoomDatabase() { 19 | abstract fun downloadDao(): DownloadDao 20 | 21 | companion object { 22 | private const val DATABASE_NAME = "download_db" 23 | fun create(app: Application) = Room.databaseBuilder( 24 | app, DownloadDatabase::class.java, DATABASE_NAME 25 | ).fallbackToDestructiveMigration(true).build() 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/download/db/models/ContextEntity.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.download.db.models 2 | 3 | import androidx.room.Entity 4 | import androidx.room.PrimaryKey 5 | import dev.brahmkshatriya.echo.common.models.EchoMediaItem 6 | import dev.brahmkshatriya.echo.utils.Serializer.toData 7 | 8 | @Entity 9 | data class ContextEntity( 10 | @PrimaryKey(true) 11 | val id: Long, 12 | val itemId: String, 13 | val data: String, 14 | ) { 15 | val mediaItem by lazy { data.toData() } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/download/db/models/DownloadEntity.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.download.db.models 2 | 3 | import androidx.room.Entity 4 | import androidx.room.PrimaryKey 5 | import dev.brahmkshatriya.echo.common.models.Track 6 | import dev.brahmkshatriya.echo.ui.common.ExceptionUtils 7 | import dev.brahmkshatriya.echo.utils.Serializer.toData 8 | import kotlinx.serialization.Serializable 9 | 10 | @Entity 11 | @Serializable 12 | data class DownloadEntity( 13 | @PrimaryKey(true) 14 | val id: Long, 15 | val extensionId: String, 16 | val trackId: String, 17 | val contextId: Long?, 18 | val data: String, 19 | val sortOrder: Int? = null, 20 | val loaded: Boolean = false, 21 | val folderPath: String? = null, 22 | val streamableId: String? = null, 23 | val indexesData: String? = null, 24 | val toMergeFilesData: String? = null, 25 | val toTagFile: String? = null, 26 | val finalFile: String? = null, 27 | val exceptionData : String? = null, 28 | ) { 29 | val track by lazy { data.toData() } 30 | val indexes by lazy { indexesData?.toData>().orEmpty() } 31 | val toMergeFiles by lazy { toMergeFilesData?.toData>().orEmpty() } 32 | val exception by lazy { exceptionData?.toData() } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/download/db/models/TaskStatus.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.download.db.models 2 | 3 | enum class TaskStatus { 4 | Initialized, Progressing, Paused, Completed, Failed 5 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/download/db/models/TaskType.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.download.db.models 2 | 3 | enum class TaskType { 4 | Loading, Downloading, Merging, Tagging 5 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/download/exceptions/DownloadException.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.download.exceptions 2 | 3 | import dev.brahmkshatriya.echo.download.db.models.DownloadEntity 4 | import dev.brahmkshatriya.echo.download.db.models.TaskType 5 | 6 | data class DownloadException( 7 | val type: TaskType, 8 | val downloadEntity: DownloadEntity, 9 | override val cause: Throwable 10 | ) : Exception() -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/download/exceptions/DownloaderExtensionNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.download.exceptions 2 | 3 | class DownloaderExtensionNotFoundException : Exception() -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/download/workers/MergingWorker.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.download.workers 2 | 3 | import android.content.Context 4 | import androidx.work.WorkerParameters 5 | import dev.brahmkshatriya.echo.download.Downloader 6 | import dev.brahmkshatriya.echo.download.db.models.TaskType 7 | import java.io.File 8 | 9 | class MergingWorker( 10 | context: Context, 11 | workerParams: WorkerParameters, 12 | downloader: Downloader, 13 | ) : BaseWorker(context, workerParams, downloader) { 14 | override val type = TaskType.Merging 15 | 16 | override suspend fun work(trackId: Long) { 17 | val downloadContext = getDownloadContext() 18 | val download = getDownload() 19 | val file = withDownloadExtension { 20 | merge(progressFlow, downloadContext, download.toMergeFiles.map { File(it) }) 21 | } 22 | dao.insertDownloadEntity(download.copy(toTagFile = file.toString())) 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/db/ExtensionDao.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.db 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Insert 5 | import androidx.room.OnConflictStrategy 6 | import androidx.room.Query 7 | import dev.brahmkshatriya.echo.extensions.db.models.ExtensionEntity 8 | import kotlinx.coroutines.flow.Flow 9 | 10 | @Dao 11 | interface ExtensionDao { 12 | 13 | @Query("SELECT * FROM ExtensionEntity") 14 | fun getExtensionFlow(): Flow> 15 | 16 | @Insert(onConflict = OnConflictStrategy.REPLACE) 17 | suspend fun setExtension(extensionEntity: ExtensionEntity) 18 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/db/models/CurrentUser.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.db.models 2 | 3 | import androidx.room.Entity 4 | import dev.brahmkshatriya.echo.common.helpers.ExtensionType 5 | 6 | @Entity(primaryKeys = ["type", "extId"]) 7 | data class CurrentUser( 8 | val type : ExtensionType, 9 | val extId: String, 10 | val userId: String? 11 | ) -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/db/models/ExtensionEntity.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.db.models 2 | 3 | import androidx.room.Entity 4 | import dev.brahmkshatriya.echo.common.helpers.ExtensionType 5 | 6 | @Entity(primaryKeys = ["id", "type"]) 7 | data class ExtensionEntity( 8 | val id: String, 9 | val type : ExtensionType, 10 | val enabled : Boolean 11 | ) -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/db/models/UserEntity.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.db.models 2 | 3 | import androidx.room.Entity 4 | import dev.brahmkshatriya.echo.common.helpers.ExtensionType 5 | import dev.brahmkshatriya.echo.common.models.User 6 | import dev.brahmkshatriya.echo.utils.Serializer.toData 7 | import dev.brahmkshatriya.echo.utils.Serializer.toJson 8 | 9 | @Entity(primaryKeys = ["id", "type", "extId"]) 10 | data class UserEntity( 11 | val type: ExtensionType, 12 | val extId: String, 13 | val id: String, 14 | val data: String 15 | ) { 16 | val user by lazy { data.toData() } 17 | 18 | companion object { 19 | fun User.toEntity(type: ExtensionType, clientId: String) = 20 | UserEntity(type, clientId, id, toJson()) 21 | 22 | fun UserEntity.toCurrentUser() = 23 | CurrentUser(type, extId, id) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/exceptions/ExtensionLoaderException.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.exceptions 2 | 3 | class ExtensionLoaderException( 4 | val clazz: String, 5 | val source: String, 6 | override val cause: Throwable 7 | ) : Exception() -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/exceptions/ExtensionNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.exceptions 2 | 3 | class ExtensionNotFoundException(val id: String?) : Exception("Extension not found: $id") -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/exceptions/InvalidExtensionListException.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.exceptions 2 | 3 | class InvalidExtensionListException( 4 | val link: String, override val cause: Throwable 5 | ) : Exception() -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/exceptions/RequiredExtensionsMissingException.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.exceptions 2 | 3 | class RequiredExtensionsMissingException(val required: List) : 4 | Exception("Missing required extensions: ${required.joinToString(", ")}") -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/exceptions/UpdateException.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.exceptions 2 | 3 | class UpdateException(override val cause: Throwable) : Exception(cause) { 4 | override val message: String 5 | get() = "Update failed: ${cause.message}" 6 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/plugger/impl/AppInfo.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.plugger.impl 2 | 3 | import android.content.pm.ApplicationInfo 4 | import android.content.pm.FeatureInfo 5 | import android.content.pm.PackageInfo 6 | import dev.brahmkshatriya.echo.common.helpers.ExtensionType 7 | import dev.brahmkshatriya.echo.extensions.plugger.ExtensionsRepo.Companion.FEATURE 8 | 9 | data class AppInfo( 10 | val path: String, 11 | val appInfo: ApplicationInfo, 12 | val type: ExtensionType 13 | ) { 14 | 15 | constructor(path: String, packageInfo: PackageInfo) : this( 16 | path, 17 | packageInfo.applicationInfo!!, 18 | packageInfo.reqFeatures!!.toExtensionType() 19 | ) 20 | 21 | constructor(packageInfo: PackageInfo) : this( 22 | packageInfo.applicationInfo!!.sourceDir, 23 | packageInfo 24 | ) 25 | 26 | companion object { 27 | private fun Array.toExtensionType(): ExtensionType { 28 | val feature = first { it.name.startsWith(FEATURE) } 29 | val type = feature.name.substringAfter(FEATURE) 30 | return ExtensionType.entries.first { it.feature == type } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/plugger/impl/BuiltInRepo.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.plugger.impl 2 | 3 | import dev.brahmkshatriya.echo.common.clients.ExtensionClient 4 | import dev.brahmkshatriya.echo.common.helpers.Injectable 5 | import dev.brahmkshatriya.echo.common.models.Metadata 6 | import dev.brahmkshatriya.echo.extensions.plugger.interfaces.PluginRepo 7 | import kotlinx.coroutines.flow.MutableStateFlow 8 | 9 | class BuiltInRepo( 10 | private val list: List>> 11 | ) : PluginRepo { 12 | override fun getAllPlugins() = MutableStateFlow(list.map { Result.success(it) }) 13 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/plugger/impl/file/FileParser.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.plugger.impl.file 2 | 3 | import android.content.pm.PackageManager 4 | import dev.brahmkshatriya.echo.common.models.Metadata 5 | import dev.brahmkshatriya.echo.extensions.plugger.ExtensionsRepo.Companion.PACKAGE_FLAGS 6 | import dev.brahmkshatriya.echo.extensions.plugger.impl.AppInfo 7 | import dev.brahmkshatriya.echo.extensions.plugger.interfaces.ManifestParser 8 | import java.io.File 9 | 10 | class FileParser( 11 | private val packageManager: PackageManager, 12 | private val apkManifestParser: ManifestParser 13 | ) : ManifestParser { 14 | override fun parseManifest(data: File): Metadata { 15 | val info = runCatching { 16 | AppInfo( 17 | data.path, 18 | packageManager.getPackageArchiveInfo(data.path, PACKAGE_FLAGS)!! 19 | ) 20 | }.getOrElse { 21 | throw Exception("Failed to parse APK file: ${data.path}", it) 22 | } 23 | return apkManifestParser.parseManifest(info) 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/plugger/interfaces/ManifestParser.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.plugger.interfaces 2 | 3 | interface ManifestParser { 4 | fun parseManifest(data: TInputData): TMetadata 5 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/plugger/interfaces/PluginLoader.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.plugger.interfaces 2 | 3 | interface PluginLoader { 4 | fun loadPlugin(pluginMetadata: TMetadata): TPlugin 5 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/plugger/interfaces/PluginRepo.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.plugger.interfaces 2 | 3 | import dev.brahmkshatriya.echo.common.helpers.Injectable 4 | import kotlinx.coroutines.flow.Flow 5 | 6 | interface PluginRepo { 7 | fun getAllPlugins(): Flow>>>> 8 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/extensions/plugger/interfaces/PluginSource.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.extensions.plugger.interfaces 2 | 3 | import kotlinx.coroutines.flow.StateFlow 4 | 5 | interface PluginSource { 6 | fun getSourceFiles() : StateFlow> 7 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/playback/exceptions/NoServersException.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.playback.exceptions 2 | 3 | class NoServersException : Exception() -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/playback/exceptions/NoSourceException.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.playback.exceptions 2 | 3 | class NoSourceException : Exception() -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/playback/exceptions/PlayerException.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.playback.exceptions 2 | 3 | import androidx.media3.common.MediaItem 4 | 5 | class PlayerException( 6 | val mediaItem: MediaItem?, 7 | override val cause: Throwable 8 | ) : Exception() -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/ui/extensions/list/ExtensionListViewModel.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.ui.extensions.list 2 | 3 | import androidx.lifecycle.ViewModel 4 | import dev.brahmkshatriya.echo.common.Extension 5 | import kotlinx.coroutines.flow.MutableStateFlow 6 | import kotlinx.coroutines.flow.StateFlow 7 | 8 | abstract class ExtensionListViewModel> : ViewModel() { 9 | abstract val extensionsFlow: StateFlow?> 10 | abstract val currentSelectionFlow: MutableStateFlow 11 | fun selectExtension(index: Int) { 12 | val extension = extensionsFlow.value?.get(index) ?: return 13 | currentSelectionFlow.value = extension 14 | onExtensionSelected(extension) 15 | } 16 | 17 | open fun onExtensionSelected(extension: T) {} 18 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/ui/main/home/HomeFeedViewModel.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.ui.main.home 2 | 3 | import dev.brahmkshatriya.echo.common.Extension 4 | import dev.brahmkshatriya.echo.common.clients.HomeFeedClient 5 | import dev.brahmkshatriya.echo.common.helpers.PagedData 6 | import dev.brahmkshatriya.echo.common.models.Shelf 7 | import dev.brahmkshatriya.echo.common.models.Tab 8 | import dev.brahmkshatriya.echo.di.App 9 | import dev.brahmkshatriya.echo.extensions.ExtensionLoader 10 | import dev.brahmkshatriya.echo.extensions.ExtensionUtils.get 11 | import dev.brahmkshatriya.echo.ui.main.FeedViewModel 12 | 13 | class HomeFeedViewModel( 14 | app: App, 15 | extensionLoader: ExtensionLoader, 16 | ) : FeedViewModel(app.throwFlow, extensionLoader) { 17 | 18 | override suspend fun getTabs(extension: Extension<*>) = 19 | extension.get> { 20 | getHomeTabs() 21 | } 22 | 23 | override suspend fun getFeed(extension: Extension<*>) = 24 | extension.get> { 25 | getHomeFeed(tab) 26 | } 27 | 28 | init { init() } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/ui/media/more/LoadingAdapter.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.ui.media.more 2 | 3 | import android.annotation.SuppressLint 4 | import android.view.LayoutInflater 5 | import android.view.ViewGroup 6 | import android.view.ViewGroup.LayoutParams.WRAP_CONTENT 7 | import androidx.core.view.updateLayoutParams 8 | import androidx.recyclerview.widget.RecyclerView 9 | import dev.brahmkshatriya.echo.databinding.ItemLoadingBinding 10 | 11 | class LoadingAdapter : RecyclerView.Adapter() { 12 | class ViewHolder(val binding: ItemLoadingBinding) : RecyclerView.ViewHolder(binding.root) 13 | 14 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 15 | val binding = ItemLoadingBinding.inflate( 16 | LayoutInflater.from(parent.context), parent, false 17 | ) 18 | binding.root.updateLayoutParams { height = WRAP_CONTENT } 19 | return ViewHolder(binding) 20 | } 21 | 22 | private var loading = false 23 | 24 | @SuppressLint("NotifyDataSetChanged") 25 | fun setLoading(loading: Boolean) { 26 | this.loading = loading 27 | notifyDataSetChanged() 28 | } 29 | 30 | override fun getItemCount() = if (loading) 1 else 0 31 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {} 32 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/ui/playlist/edit/search/EditPlaylistSearchViewModel.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.ui.playlist.edit.search 2 | 3 | import androidx.lifecycle.ViewModel 4 | import dev.brahmkshatriya.echo.common.models.Track 5 | import kotlinx.coroutines.flow.MutableStateFlow 6 | 7 | class EditPlaylistSearchViewModel : ViewModel() { 8 | 9 | val selectedTracks = MutableStateFlow>(listOf()) 10 | fun toggleTrack(track: Track) = with(selectedTracks) { 11 | val mutable = selectedTracks.value.toMutableList() 12 | with(mutable) { if (contains(track)) remove(track) else add(track) } 13 | value = mutable 14 | } 15 | 16 | fun addTrack(track: Track) = with(selectedTracks) { 17 | if(value.contains(track)) return@with 18 | val mutable = selectedTracks.value.toMutableList() 19 | mutable.add(track) 20 | value = mutable 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/ui/playlist/save/TopAppBarAdapter.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.ui.playlist.save 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import dev.brahmkshatriya.echo.databinding.ItemPlaylistSaveHeaderBinding 7 | 8 | class TopAppBarAdapter( 9 | private val onClose: () -> Unit, 10 | private val onCreateClicked: () -> Unit 11 | ) : RecyclerView.Adapter() { 12 | inner class ViewHolder( 13 | val binding: ItemPlaylistSaveHeaderBinding 14 | ) : RecyclerView.ViewHolder(binding.root) { 15 | init { 16 | binding.root.setNavigationOnClickListener { 17 | onClose() 18 | } 19 | 20 | binding.root.setOnMenuItemClickListener { 21 | onCreateClicked() 22 | true 23 | } 24 | } 25 | } 26 | 27 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 28 | val inflater = LayoutInflater.from(parent.context) 29 | return ViewHolder(ItemPlaylistSaveHeaderBinding.inflate(inflater, parent, false)) 30 | 31 | } 32 | 33 | override fun getItemCount() = 1 34 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {} 35 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/ui/shelf/adapter/other/ShelfEmptyAdapter.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.ui.shelf.adapter.other 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.paging.LoadState 6 | import androidx.paging.LoadStateAdapter 7 | import androidx.recyclerview.widget.RecyclerView 8 | import dev.brahmkshatriya.echo.databinding.ItemShelfEmptyBinding 9 | 10 | class ShelfEmptyAdapter : LoadStateAdapter() { 11 | class ViewHolder(val binding: ItemShelfEmptyBinding) : RecyclerView.ViewHolder(binding.root) 12 | override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): ViewHolder { 13 | val inflater = LayoutInflater.from(parent.context) 14 | val binding = ItemShelfEmptyBinding.inflate(inflater, parent, false) 15 | return ViewHolder(binding) 16 | } 17 | 18 | override fun onBindViewHolder(holder: ViewHolder, loadState: LoadState) {} 19 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/utils/PauseTimer.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.utils 2 | 3 | import kotlinx.coroutines.CoroutineScope 4 | import kotlinx.coroutines.Job 5 | import kotlinx.coroutines.delay 6 | import kotlinx.coroutines.launch 7 | 8 | class PauseTimer( 9 | private val scope: CoroutineScope, 10 | private var millisInFuture: Long, 11 | private val onTimerFinish: () -> Unit, 12 | ) { 13 | private var job: Job? = null 14 | private var lastPauseTime: Long = System.currentTimeMillis() 15 | private var isTimerPaused: Boolean = true 16 | 17 | fun resume() { 18 | if (isTimerPaused) { 19 | val diff = System.currentTimeMillis() - lastPauseTime 20 | val remainingTime = millisInFuture - diff 21 | if (remainingTime < 0) return 22 | job = scope.launch { 23 | delay(remainingTime) 24 | onTimerFinish() 25 | } 26 | isTimerPaused = false 27 | } 28 | } 29 | 30 | fun pause() { 31 | job?.cancel() 32 | lastPauseTime = System.currentTimeMillis() 33 | isTimerPaused = true 34 | } 35 | 36 | init { 37 | resume() 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/utils/Sticky.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.utils 2 | 3 | import java.util.WeakHashMap 4 | import kotlin.reflect.KProperty 5 | 6 | class Sticky(private val initializer: R.() -> T) { 7 | 8 | private val map = WeakHashMap>() 9 | operator fun getValue(thisRef: R, property: KProperty<*>): T { 10 | return map.getOrPut(thisRef) { 11 | runCatching { initializer(thisRef) } 12 | }.getOrThrow() 13 | } 14 | 15 | operator fun setValue(thisRef: R, property: KProperty<*>, value: T) { 16 | map[thisRef] = Result.success(value) 17 | } 18 | 19 | companion object { 20 | fun sticky(initializer: R.() -> T) = Sticky(initializer) 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/utils/image/SquareCropTransformation.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.utils.image 2 | 3 | import android.graphics.Bitmap 4 | import coil3.size.Size 5 | import coil3.transform.Transformation 6 | 7 | class SquareCropTransformation : Transformation() { 8 | val version = 1 9 | override val cacheKey = "${javaClass.simpleName}.$version" 10 | override suspend fun transform(input: Bitmap, size: Size): Bitmap { 11 | val max = input.width.coerceAtMost(input.height) 12 | val x = (input.width - max) / 2 13 | val y = (input.height - max) / 2 14 | return Bitmap.createBitmap(input, x, y, max, max) 15 | } 16 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/utils/ui/CheckBoxListener.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.utils.ui 2 | 3 | import com.google.android.material.checkbox.MaterialCheckBox 4 | 5 | class CheckBoxListener(private val block: (Boolean) -> Unit) : 6 | MaterialCheckBox.OnCheckedStateChangedListener { 7 | var enabled = true 8 | private var checked = false 9 | private fun check(isChecked: Boolean) { 10 | if (checked == isChecked) return 11 | block(isChecked) 12 | } 13 | 14 | override fun onCheckedStateChangedListener(checkBox: MaterialCheckBox, state: Int) { 15 | val isChecked = checkBox.isChecked 16 | if (enabled) check(isChecked) 17 | checked = isChecked 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/utils/ui/ShimmerLayoutSelf.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.utils.ui 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.animation.AlphaAnimation 6 | import android.view.animation.Animation 7 | import android.widget.FrameLayout 8 | import com.google.android.material.R 9 | import com.google.android.material.motion.MotionUtils 10 | 11 | class ShimmerLayoutSelf @JvmOverloads constructor( 12 | context: Context, attrs: AttributeSet? = null 13 | ) : FrameLayout(context, attrs) { 14 | 15 | private val timeDuration = MotionUtils.resolveThemeDuration( 16 | context, 17 | R.attr.motionDurationMedium1, 18 | 350 19 | ).toLong() 20 | 21 | private val animation = AlphaAnimation(1.0f, 0.25f).apply { 22 | duration = timeDuration * 2 23 | fillAfter = true 24 | repeatMode = AlphaAnimation.REVERSE 25 | repeatCount = Animation.INFINITE 26 | } 27 | 28 | init { 29 | startAnimation(animation) 30 | } 31 | 32 | override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { 33 | super.onLayout(changed, left, top, right, bottom) 34 | startAnimation(animation) 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/utils/ui/SimpleItemSpan.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.utils.ui 2 | 3 | import android.content.Context 4 | import android.text.TextPaint 5 | import android.text.style.ClickableSpan 6 | import android.view.View 7 | import dev.brahmkshatriya.echo.R 8 | 9 | class SimpleItemSpan( 10 | val context: Context, 11 | private val onItemClicked: () -> Unit 12 | ) : ClickableSpan() { 13 | 14 | override fun onClick(widget: View) { 15 | onItemClicked() 16 | } 17 | 18 | override fun updateDrawState(ds: TextPaint) { 19 | super.updateDrawState(ds) 20 | ds.isUnderlineText = false 21 | context.run { 22 | ds.color = resources.getColor(R.color.button_player, theme) 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/utils/ui/prefs/LongClickPreference.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.utils.ui.prefs 2 | 3 | import android.content.Context 4 | import androidx.preference.Preference 5 | import androidx.preference.PreferenceViewHolder 6 | 7 | open class LongClickPreference(context:Context) : Preference(context) { 8 | private var onLongClickListener: (() -> Unit)? = null 9 | 10 | fun setOnLongClickListener(listener: () -> Unit) { 11 | onLongClickListener = listener 12 | } 13 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 14 | super.onBindViewHolder(holder) 15 | 16 | val listener = onLongClickListener ?: return 17 | holder.itemView.setOnLongClickListener { 18 | listener.invoke() 19 | true 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/utils/ui/prefs/SwitchLongClickPreference.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.utils.ui.prefs 2 | 3 | import android.content.Context 4 | import androidx.preference.PreferenceViewHolder 5 | import androidx.preference.SwitchPreferenceCompat 6 | 7 | class SwitchLongClickPreference(context: Context) : SwitchPreferenceCompat(context) { 8 | private var onLongClickListener: (() -> Unit)? = null 9 | 10 | fun setOnLongClickListener(listener: () -> Unit) { 11 | onLongClickListener = listener 12 | } 13 | 14 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 15 | super.onBindViewHolder(holder) 16 | 17 | val listener = onLongClickListener ?: return 18 | holder.itemView.setOnLongClickListener { 19 | listener.invoke() 20 | true 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/dev/brahmkshatriya/echo/utils/ui/prefs/TransitionPreference.kt: -------------------------------------------------------------------------------- 1 | package dev.brahmkshatriya.echo.utils.ui.prefs 2 | 3 | import android.content.Context 4 | import androidx.preference.Preference 5 | import androidx.preference.PreferenceViewHolder 6 | 7 | class TransitionPreference( 8 | context: Context 9 | ) : Preference(context) { 10 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 11 | super.onBindViewHolder(holder) 12 | holder.itemView.id = key.hashCode() 13 | holder.itemView.transitionName = key 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/res/color/button_player.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/color/button_player_more.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/color/button_player_ripple.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/color/nav_bar_icon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-land/gradient_track.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/example_appwidget_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/res/drawable-nodpi/example_appwidget_preview.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/anim_bookmark.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 12 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/anim_heart_40dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 12 | 17 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/anim_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 12 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/anim_play_pause.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 12 | 17 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/anim_play_pause_48dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 12 | 13 | 18 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/anim_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 12 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/anim_shuffle.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/app_widget_gradient_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/app_widget_image_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/app_widget_inner_view_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/art_album.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/art_brand.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/art_download_for_offline.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/art_downloading.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/art_edit_note.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/art_music.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/art_person.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/art_problem.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/art_shivam.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gradient_track.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_account_circle.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_account_circle_48dp.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_circle.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_photo_alternate.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_album.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_article.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_artist.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_back.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_bookmark_filled.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_bookmark_outline.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close_small.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_copy.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_download_for_offline.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_downloading.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_drag_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_edit_note.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_email.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_equalizer.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_expand_more.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_extension_48dp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_favorite_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_favorite_filled_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_files.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_forward.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_heart_filled_40dp.xml: -------------------------------------------------------------------------------- 1 | 8 | 12 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_hide_filled.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_hide_outline.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_high_quality.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_history.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_home_filled.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_home_outline.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_incognito.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_input.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_language.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_monochrome.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_library_music.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_login.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_logout.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mono.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_more_horiz.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_music.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_numbers.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_offline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_palette.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_pause.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_pause_48dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_person.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_play.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_play_48dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_playlist_add.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_playlist_play.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_queue_music.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_refresh.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_repeat_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_repeat_on_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_save.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_schedule.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search_filled.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search_outline.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sensors.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_shuffle.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_shuffle_40dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_shuffle_on_40dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_snooze.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sort.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ripple_44dp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ripple_60dp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ripple_68dp.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ripple_item_container.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/rounded_rectangle_24dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/rounded_rectangle_cover.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/rounded_rectangle_cover_profile.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_rounded_4dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_rounded_item_corner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_indicator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 8 | 9 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/button_extension.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_extensions_add_list.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_media_more.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_playlist_save.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 20 | 21 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_extension_login_selector.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_main.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_player_info.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_player_queue.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_webview.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_click_panels.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_color_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 22 | 23 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_edit_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_extension_add_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_extension_add_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_input.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_lyric.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_lyrics_item.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_playlist_save_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_playlist_save_header.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_ruler.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 20 | 21 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_selectable_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_shelf_empty.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 18 | 19 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_shelf_lists_four_tracks.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 14 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_shelf_login_required.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 21 | 22 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_shelf_not_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 21 | 22 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_text_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 21 | 22 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_track_info.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/preference.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/preference_category.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/preference_slider.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | 17 | 18 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/preference_switch.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/skeleton_shelf_lists_media_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 22 | 23 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/menu/create_playlist_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/menu/delete_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/menu/exception_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/menu/extensions_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/menu/lyrics_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/menu/more_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/menu/nav_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 12 | 13 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/menu/refresh_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/menu/settings_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/menu/sleep_timer_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/menu/top_bar_menu.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brahmkshatriya/echo/62edf5cec0a5db43511e06c8ee1ce580e3340e3b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/resources.properties: -------------------------------------------------------------------------------- 1 | unqualifiedResLocale=en-US -------------------------------------------------------------------------------- /app/src/main/res/values-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 80dp 4 | 8dp 5 | -------------------------------------------------------------------------------- /app/src/main/res/values-land/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 180 4 | -------------------------------------------------------------------------------- /app/src/main/res/values-land/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 14 | 15 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | @color/black 4 | @color/white 5 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 |