From 76bb6e3e42f6093ba92a3c9a69a61f890afdcbf4 Mon Sep 17 00:00:00 2001 From: renhaoting <370797079@qq.com> Date: Tue, 18 Nov 2025 13:30:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/.gitignore | 1 + app/build.gradle | 91 +++ app/proguard-rules.pro | 21 + app/src/main/AndroidManifest.xml | 39 ++ app/src/main/java/com/gamedog/vididin/App.kt | 8 + .../java/com/gamedog/vididin/Constants.kt | 16 + .../vididin/adapter/MainTabsAdapter.kt | 174 +++++ .../vididin/adapter/MainViewPagerAdapter.kt | 21 + .../com/gamedog/vididin/api/YoutubeApi.kt | 48 ++ .../com/gamedog/vididin/beans/MainTabsItem.kt | 24 + .../java/com/gamedog/vididin/beans/User.kt | 9 + .../com/gamedog/vididin/beans/UserData.kt | 9 + .../com/gamedog/vididin/beans/YoutubeBeans.kt | 122 ++++ .../com/gamedog/vididin/di/AppDispatchers.kt | 13 + .../vididin/di/CoroutineScopesModule.kt | 29 + .../java/com/gamedog/vididin/di/DataModule.kt | 18 + .../gamedog/vididin/di/GlobalInterceptor.kt | 100 +++ .../java/com/gamedog/vididin/di/HomeModule.kt | 71 ++ .../com/gamedog/vididin/di/NetworkModule.kt | 60 ++ .../gamedog/vididin/di/RouterEntryPoints.kt | 20 + .../gamedog/vididin/login/LoginActivity.kt | 60 ++ .../com/gamedog/vididin/login/LoginManager.kt | 7 + .../com/gamedog/vididin/main/MainActivity.kt | 122 ++++ .../com/gamedog/vididin/main/MainViewModel.kt | 59 ++ .../vididin/main/fragments/HomeFragment.kt | 125 ++++ .../vididin/main/fragments/MineFragment.kt | 61 ++ .../vididin/main/fragments/TasksFragment.kt | 47 ++ .../home/DefaultYoutubeDatasource.kt | 22 + .../home/DefaultYoutubeRepository.kt | 39 ++ .../home/HomeFragmentStateAdapter.kt | 16 + .../OnRepositoryRefreshLoadMoreListeners.kt | 14 + .../fragments/home/RefreshRepositoryOwner.kt | 8 + .../main/fragments/home/YoutubeDataSource.kt | 10 + .../main/fragments/home/YoutubeRepository.kt | 12 + .../main/fragments/home/YoutubeViewModel.kt | 32 + .../home/fragment/HomeItemFragment.kt | 216 ++++++ .../main/fragments/mine/MineViewModel.kt | 33 + .../main/interfaces/OnSwitchTabListener.kt | 6 + .../interfaces/OnTabClickAgainListener.kt | 17 + .../main/interfaces/OnTabStyleListener.kt | 6 + .../repository/DefaultMainRepository.kt | 25 + .../vididin/repository/MainRepository.kt | 14 + .../vididin/router/DefaultHomeRouter.kt | 10 + .../vididin/router/DefaultLoginRouter.kt | 12 + .../vididin/router/DefaultMineRouter.kt | 11 + .../vididin/router/DefaultTaskRouter.kt | 11 + .../com/gamedog/vididin/router/HomeRouter.kt | 7 + .../com/gamedog/vididin/router/LoginRouter.kt | 7 + .../com/gamedog/vididin/router/MineRouter.kt | 7 + .../java/com/gamedog/vididin/router/Router.kt | 27 + .../gamedog/vididin/router/RouterContract.kt | 15 + .../vididin/router/RouterInitializer.kt | 15 + .../com/gamedog/vididin/router/TaskRouter.kt | 8 + .../vididin/sp/AppPreferencesDataSource.kt | 11 + .../vididin/sp/UserPreferencesSerializer.kt | 10 + .../gamedog/vididin/sp/datastore/user.proto | 26 + .../sp/datastore/user_preferences.proto | 32 + .../vididin/widget/HomeDragIconView.kt | 30 + .../vididin/widget/MyPlayerControlView.kt | 294 +++++++++ .../gamedog/vididin/widget/MyPlayerMenu.kt | 67 ++ .../com/gamedog/vididin/widget/YTParams.java | 125 ++++ .../res/drawable/ic_launcher_background.xml | 170 +++++ .../res/drawable/ic_launcher_foreground.xml | 30 + ...inapp_feature_message_bg_task_activity.xml | 9 + ...didinapp_feature_message_bg_task_ativi.xml | 9 + ...ididinapp_feature_message_bg_task_cash.xml | 7 + ...ididinapp_feature_message_bg_task_coin.xml | 7 + ...didinapp_feature_message_bg_task_fazer.xml | 9 + ...didinapp_feature_message_bg_task_inici.xml | 9 + ...didinapp_feature_message_bg_task_login.xml | 9 + .../vididinapp_feature_mine_bg_top.xml | 7 + .../vididinapp_feature_mine_option_bg.xml | 5 + app/src/main/res/layout/activity_main.xml | 29 + .../res/layout/item_activity_main_tab.xml | 24 + .../main/res/layout/layout_drag_icon_view.xml | 65 ++ .../res/layout/layout_player_controller.xml | 204 ++++++ .../vididinapp_feature_home_fragment_home.xml | 20 + .../vididinapp_feature_home_item_layout.xml | 159 +++++ ...ididinapp_feature_login_activity_login.xml | 13 + ...inapp_feature_message_fragment_message.xml | 433 ++++++++++++ .../vididinapp_feature_mine_fragment_mine.xml | 200 ++++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 6 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 6 + .../douyin_feature_mine_bg_top.jpg | Bin 0 -> 11061 bytes app/src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes app/src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/home_menu_1.webp | Bin 0 -> 23724 bytes .../main/res/mipmap-xxhdpi/home_menu_2.webp | Bin 0 -> 20160 bytes .../main/res/mipmap-xxhdpi/home_menu_3.webp | Bin 0 -> 21774 bytes .../main/res/mipmap-xxhdpi/home_menu_4.webp | Bin 0 -> 18180 bytes .../main/res/mipmap-xxhdpi/home_share.webp | Bin 0 -> 3600 bytes app/src/main/res/mipmap-xxhdpi/home_star.webp | Bin 0 -> 10288 bytes .../res/mipmap-xxhdpi/home_star_undo.webp | Bin 0 -> 4152 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes app/src/main/res/mipmap-xxhdpi/tab_home.webp | Bin 0 -> 1778 bytes .../res/mipmap-xxhdpi/tab_home_selected.webp | Bin 0 -> 5470 bytes app/src/main/res/mipmap-xxhdpi/tab_my.webp | Bin 0 -> 1788 bytes .../res/mipmap-xxhdpi/tab_my_selected.webp | Bin 0 -> 5466 bytes app/src/main/res/mipmap-xxhdpi/tab_tasks.webp | Bin 0 -> 1818 bytes .../res/mipmap-xxhdpi/tab_tasks_selected.webp | Bin 0 -> 5458 bytes app/src/main/res/mipmap-xxhdpi/temp.png | Bin 0 -> 3692 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes app/src/main/res/raw/players.qualson | 177 +++++ app/src/main/res/raw/players111.html | 177 +++++ app/src/main/res/values-night/colors.xml | 49 ++ app/src/main/res/values-night/themes.xml | 6 + app/src/main/res/values/colors.xml | 60 ++ app/src/main/res/values/dimens.xml | 9 + app/src/main/res/values/strings.xml | 10 + app/src/main/res/values/themes.xml | 61 ++ app/src/main/res/xml/backup_rules.xml | 13 + .../main/res/xml/data_extraction_rules.xml | 19 + .../main/res/xml/network_security_config.xml | 8 + build.gradle | 62 ++ core.build.gradle | 39 ++ core/architecture-reflect/.gitignore | 1 + core/architecture-reflect/build.gradle | 10 + core/architecture-reflect/consumer-rules.pro | 0 core/architecture-reflect/proguard-rules.pro | 21 + .../src/main/AndroidManifest.xml | 4 + .../reflect/ReflectViewBindings.kt | 52 ++ .../architecture/reflect/ReflectViewModels.kt | 89 +++ core/architecture/.gitignore | 1 + core/architecture/build.gradle | 33 + core/architecture/consumer-rules.pro | 0 core/architecture/proguard-rules.pro | 21 + .../architecture/src/main/AndroidManifest.xml | 16 + .../architecture/appBase/AppViewsActivity.kt | 37 ++ .../appBase/AppViewsDialogFragment.kt | 24 + .../appBase/AppViewsEmptyViewModelActivity.kt | 15 + .../AppViewsEmptyViewModelDialogFragment.kt | 15 + .../appBase/AppViewsEmptyViewModelFragment.kt | 15 + .../architecture/appBase/AppViewsFragment.kt | 39 ++ .../appBase/OnFragmentBackgroundListener.kt | 7 + .../appBase/adapter/AppAdapter.kt | 13 + .../appBase/adapter/AppDifferAdapter.kt | 97 +++ .../adapter/AppFragmentStateAdapter.kt | 24 + .../appBase/adapter/AppNavigatorAdapter.kt | 31 + .../adapter/AppViewBindingViewHolder.kt | 12 + .../architecture/appBase/vm/AppViewModel.kt | 6 + .../core/architecture/base/BaseActivity.kt | 6 + .../core/architecture/base/BaseFragment.kt | 6 + .../core/architecture/base/BaseViewModel.kt | 34 + .../base/compose/BaseComposeActivity.kt | 5 + .../base/views/BaseViewsActivity.kt | 92 +++ .../base/views/BaseViewsDialogFragment.kt | 155 +++++ .../base/views/BaseViewsFragment.kt | 145 ++++ .../views/adapter/BaseDiffItemCallback.kt | 22 + .../views/adapter/BaseFragmentStateAdapter.kt | 72 ++ .../adapter/BaseViewBindingViewHolder.kt | 28 + .../architecture/basebean/ResponseData.kt | 10 + .../core/architecture/basebean/ResponseNew.kt | 85 +++ .../core/architecture/empty/EmptyViewModel.kt | 13 + .../architecture/interfaces/DialogInit.kt | 11 + .../interfaces/FragmentIsLazyInit.kt | 6 + .../interfaces/LoadStateUiStateOwner.kt | 9 + .../architecture/interfaces/UiStateOwner.kt | 13 + .../interfaces/ViewBindingsInit.kt | 35 + .../architecture/interfaces/ViewModelOwner.kt | 8 + .../ama/core/architecture/message/Message.kt | 4 + .../architecture/message/MessageCollector.kt | 16 + .../message/MessageCollectorOwner.kt | 6 + .../architecture/message/MessageController.kt | 17 + .../message/MessageDisplayManager.kt | 20 + .../architecture/message/MessageManager.kt | 32 + .../collector/SnakbarViewMessageCollector.kt | 142 ++++ .../collector/ToastMessageCollector.kt | 157 +++++ .../controller/DefaultMessageController.kt | 51 ++ .../BaseMemoryRefreshLoadMoreRepository.kt | 133 ++++ .../OnRepositoryRefreshLoadMoreListeners.kt | 14 + ...ageKeyedMemoryRefreshLoadMoreRepository.kt | 10 + .../architecture/page/RefreshRepository.kt | 19 + .../repository/BaseRepositoryNew.kt | 85 +++ .../startup/BaseGlobalMessageInitializer.kt | 30 + .../stateview/LoadStateUiState.kt | 56 ++ .../interfaces/DefaultStateViewManager.kt | 129 ++++ .../stateview/interfaces/StateViewManager.kt | 36 + .../architecture/stateview/util/StateView.kt | 34 + .../stateview/util/StateViewManager.kt | 49 ++ .../ama/core/architecture/util/Fragment.kt | 22 + .../ama/core/architecture/util/LoadState.kt | 33 + .../core/architecture/util/MagicIndicator.kt | 99 +++ .../ama/core/architecture/util/Throwable.kt | 33 + .../util/UiStateMapChangedCollect.kt | 38 ++ .../ama/core/architecture/util/ViewPager2.kt | 54 ++ .../util/WindowInsetsController.kt | 20 + .../ConstraintLayoutMergeStateBaseView.kt | 15 + .../util/state/DefaultStateEmptyView.kt | 18 + .../util/state/DefaultStateErrorView.kt | 26 + .../util/state/DefaultStateLoadingView.kt | 17 + .../util/state/DefaultStateView.kt | 75 +++ .../core/architecture/util/state/StateView.kt | 7 + .../util/state/interfaces/StateBaseView.kt | 13 + .../util/state/interfaces/StateEmptyView.kt | 4 + .../util/state/interfaces/StateErrorView.kt | 8 + .../util/state/interfaces/StateLoadingView.kt | 4 + .../src/main/res/anim/slide_in_bottom.xml | 8 + .../src/main/res/anim/slide_in_left.xml | 7 + .../src/main/res/anim/slide_in_right.xml | 7 + .../src/main/res/anim/slide_out_bottom.xml | 8 + .../src/main/res/anim/slide_out_left.xml | 7 + .../src/main/res/anim/slide_out_right.xml | 7 + ...yin_core_designsystem_view_state_empty.xml | 42 ++ ...yin_core_designsystem_view_state_error.xml | 103 +++ ...n_core_designsystem_view_state_loading.xml | 16 + .../main/res/mipmap-nodpi/ic_state_empty.png | Bin 0 -> 10707 bytes .../main/res/mipmap-nodpi/ic_state_error.png | Bin 0 -> 9302 bytes .../src/main/res/values/colors.xml | 49 ++ .../src/main/res/values/dimens.xml | 10 + .../src/main/res/values/strings.xml | 9 + .../src/main/res/values/styles.xml | 28 + .../src/main/res/values/themes.xml | 61 ++ core/common/.gitignore | 1 + core/common/build.gradle | 15 + core/common/consumer-rules.pro | 0 core/common/proguard-rules.pro | 21 + core/common/src/main/AndroidManifest.xml | 16 + .../core/common/exception/RuleException.kt | 4 + .../DefaultActivityLifecycleCallbacks.kt | 29 + .../common/startup/BaseCommonInitializer.kt | 18 + .../main/java/com/ama/core/common/util/Any.kt | 6 + .../com/ama/core/common/util/AppProvider.kt | 18 + .../java/com/ama/core/common/util/Context.kt | 13 + .../com/ama/core/common/util/DisplaySize.kt | 48 ++ .../main/java/com/ama/core/common/util/Dp.kt | 18 + .../main/java/com/ama/core/common/util/Sp.kt | 18 + .../java/com/ama/core/common/util/View.kt | 42 ++ .../ama/core/common/widget/DragIconView.kt | 240 +++++++ .../com/ama/core/common/widget/DragLayout.kt | 205 ++++++ .../ama/core/common/widget/PopMenuIconView.kt | 161 +++++ .../widget/roundedimageview/Corner.java | 18 + .../roundedimageview/RoundedDrawable.java | 618 ++++++++++++++++++ .../roundedimageview/RoundedImageView.java | 588 +++++++++++++++++ .../res/layout/layout_pop_icon_menu_view.xml | 33 + .../main/res/mipmap-xxhdpi/home_collapse.webp | Bin 0 -> 1664 bytes .../main/res/mipmap-xxhdpi/home_envelope.webp | Bin 0 -> 10182 bytes .../main/res/mipmap-xxhdpi/home_expand.webp | Bin 0 -> 1702 bytes .../src/main/res/mipmap-xxhdpi/home_gold.webp | Bin 0 -> 4884 bytes core/common/src/main/res/values/attrs.xml | 50 ++ core/common/src/main/res/values/colors.xml | 4 + core/core.includes.gradle | 6 + core/designsystem/.gitignore | 1 + core/designsystem/build.gradle | 10 + core/designsystem/consumer-rules.pro | 0 core/designsystem/proguard-rules.pro | 21 + .../designsystem/src/main/AndroidManifest.xml | 4 + .../widget/DefaultLoadingDialog.kt | 36 + .../ama/core/designsystem/widget/TitleBar.kt | 389 +++++++++++ .../widget/interfaces/LoadingDialog.kt | 12 + .../widget/interfaces/StateView.kt | 12 + .../src/main/res/values/titlebar_values.xml | 51 ++ core/model/.gitignore | 1 + core/model/build.gradle | 9 + core/model/consumer-rules.pro | 0 core/model/proguard-rules.pro | 21 + core/model/src/main/AndroidManifest.xml | 4 + .../java/com/ama/core/model/BaseDiffItem.kt | 23 + .../core/model/BaseFragmentStateDiffItem.kt | 6 + core/network/.gitignore | 1 + core/network/build.gradle | 10 + core/network/consumer-rules.pro | 0 core/network/proguard-rules.pro | 21 + core/network/src/main/AndroidManifest.xml | 6 + .../core/network/model/BaseNetworkModel.kt | 24 + .../ama/core/network/util/BaseNetworkModel.kt | 36 + generateModuleGraphs.sh | 109 +++ gradle.properties | 34 + gradle/libs.versions.toml | 136 ++++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 ++++++ gradlew.bat | 89 +++ settings.gradle | 23 + 279 files changed, 11386 insertions(+) create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/com/gamedog/vididin/App.kt create mode 100644 app/src/main/java/com/gamedog/vididin/Constants.kt create mode 100644 app/src/main/java/com/gamedog/vididin/adapter/MainTabsAdapter.kt create mode 100644 app/src/main/java/com/gamedog/vididin/adapter/MainViewPagerAdapter.kt create mode 100644 app/src/main/java/com/gamedog/vididin/api/YoutubeApi.kt create mode 100644 app/src/main/java/com/gamedog/vididin/beans/MainTabsItem.kt create mode 100644 app/src/main/java/com/gamedog/vididin/beans/User.kt create mode 100644 app/src/main/java/com/gamedog/vididin/beans/UserData.kt create mode 100644 app/src/main/java/com/gamedog/vididin/beans/YoutubeBeans.kt create mode 100644 app/src/main/java/com/gamedog/vididin/di/AppDispatchers.kt create mode 100644 app/src/main/java/com/gamedog/vididin/di/CoroutineScopesModule.kt create mode 100644 app/src/main/java/com/gamedog/vididin/di/DataModule.kt create mode 100644 app/src/main/java/com/gamedog/vididin/di/GlobalInterceptor.kt create mode 100644 app/src/main/java/com/gamedog/vididin/di/HomeModule.kt create mode 100644 app/src/main/java/com/gamedog/vididin/di/NetworkModule.kt create mode 100644 app/src/main/java/com/gamedog/vididin/di/RouterEntryPoints.kt create mode 100644 app/src/main/java/com/gamedog/vididin/login/LoginActivity.kt create mode 100644 app/src/main/java/com/gamedog/vididin/login/LoginManager.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/MainActivity.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/MainViewModel.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/HomeFragment.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/MineFragment.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/TasksFragment.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/home/DefaultYoutubeDatasource.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/home/DefaultYoutubeRepository.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/home/HomeFragmentStateAdapter.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/home/OnRepositoryRefreshLoadMoreListeners.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/home/RefreshRepositoryOwner.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeDataSource.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeRepository.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeViewModel.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/home/fragment/HomeItemFragment.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/fragments/mine/MineViewModel.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/interfaces/OnSwitchTabListener.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/interfaces/OnTabClickAgainListener.kt create mode 100644 app/src/main/java/com/gamedog/vididin/main/interfaces/OnTabStyleListener.kt create mode 100644 app/src/main/java/com/gamedog/vididin/repository/DefaultMainRepository.kt create mode 100644 app/src/main/java/com/gamedog/vididin/repository/MainRepository.kt create mode 100644 app/src/main/java/com/gamedog/vididin/router/DefaultHomeRouter.kt create mode 100644 app/src/main/java/com/gamedog/vididin/router/DefaultLoginRouter.kt create mode 100644 app/src/main/java/com/gamedog/vididin/router/DefaultMineRouter.kt create mode 100644 app/src/main/java/com/gamedog/vididin/router/DefaultTaskRouter.kt create mode 100644 app/src/main/java/com/gamedog/vididin/router/HomeRouter.kt create mode 100644 app/src/main/java/com/gamedog/vididin/router/LoginRouter.kt create mode 100644 app/src/main/java/com/gamedog/vididin/router/MineRouter.kt create mode 100644 app/src/main/java/com/gamedog/vididin/router/Router.kt create mode 100644 app/src/main/java/com/gamedog/vididin/router/RouterContract.kt create mode 100644 app/src/main/java/com/gamedog/vididin/router/RouterInitializer.kt create mode 100644 app/src/main/java/com/gamedog/vididin/router/TaskRouter.kt create mode 100644 app/src/main/java/com/gamedog/vididin/sp/AppPreferencesDataSource.kt create mode 100644 app/src/main/java/com/gamedog/vididin/sp/UserPreferencesSerializer.kt create mode 100644 app/src/main/java/com/gamedog/vididin/sp/datastore/user.proto create mode 100644 app/src/main/java/com/gamedog/vididin/sp/datastore/user_preferences.proto create mode 100644 app/src/main/java/com/gamedog/vididin/widget/HomeDragIconView.kt create mode 100644 app/src/main/java/com/gamedog/vididin/widget/MyPlayerControlView.kt create mode 100644 app/src/main/java/com/gamedog/vididin/widget/MyPlayerMenu.kt create mode 100644 app/src/main/java/com/gamedog/vididin/widget/YTParams.java create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/vididinapp_feature_message_bg_task_activity.xml create mode 100644 app/src/main/res/drawable/vididinapp_feature_message_bg_task_ativi.xml create mode 100644 app/src/main/res/drawable/vididinapp_feature_message_bg_task_cash.xml create mode 100644 app/src/main/res/drawable/vididinapp_feature_message_bg_task_coin.xml create mode 100644 app/src/main/res/drawable/vididinapp_feature_message_bg_task_fazer.xml create mode 100644 app/src/main/res/drawable/vididinapp_feature_message_bg_task_inici.xml create mode 100644 app/src/main/res/drawable/vididinapp_feature_message_bg_task_login.xml create mode 100644 app/src/main/res/drawable/vididinapp_feature_mine_bg_top.xml create mode 100644 app/src/main/res/drawable/vididinapp_feature_mine_option_bg.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/item_activity_main_tab.xml create mode 100644 app/src/main/res/layout/layout_drag_icon_view.xml create mode 100644 app/src/main/res/layout/layout_player_controller.xml create mode 100644 app/src/main/res/layout/vididinapp_feature_home_fragment_home.xml create mode 100644 app/src/main/res/layout/vididinapp_feature_home_item_layout.xml create mode 100644 app/src/main/res/layout/vididinapp_feature_login_activity_login.xml create mode 100644 app/src/main/res/layout/vididinapp_feature_message_fragment_message.xml create mode 100644 app/src/main/res/layout/vididinapp_feature_mine_fragment_mine.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/douyin_feature_mine_bg_top.jpg create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/home_menu_1.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/home_menu_2.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/home_menu_3.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/home_menu_4.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/home_share.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/home_star.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/home_star_undo.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/tab_home.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/tab_home_selected.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/tab_my.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/tab_my_selected.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/tab_tasks.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/tab_tasks_selected.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/temp.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/raw/players.qualson create mode 100644 app/src/main/res/raw/players111.html create mode 100644 app/src/main/res/values-night/colors.xml create mode 100644 app/src/main/res/values-night/themes.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/main/res/xml/backup_rules.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/main/res/xml/network_security_config.xml create mode 100644 build.gradle create mode 100644 core.build.gradle create mode 100644 core/architecture-reflect/.gitignore create mode 100644 core/architecture-reflect/build.gradle create mode 100644 core/architecture-reflect/consumer-rules.pro create mode 100644 core/architecture-reflect/proguard-rules.pro create mode 100644 core/architecture-reflect/src/main/AndroidManifest.xml create mode 100644 core/architecture-reflect/src/main/java/com/ama/core/architecture/reflect/ReflectViewBindings.kt create mode 100644 core/architecture-reflect/src/main/java/com/ama/core/architecture/reflect/ReflectViewModels.kt create mode 100644 core/architecture/.gitignore create mode 100644 core/architecture/build.gradle create mode 100644 core/architecture/consumer-rules.pro create mode 100644 core/architecture/proguard-rules.pro create mode 100644 core/architecture/src/main/AndroidManifest.xml create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/AppViewsActivity.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/AppViewsDialogFragment.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/AppViewsEmptyViewModelActivity.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/AppViewsEmptyViewModelDialogFragment.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/AppViewsEmptyViewModelFragment.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/AppViewsFragment.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/OnFragmentBackgroundListener.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/adapter/AppAdapter.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/adapter/AppDifferAdapter.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/adapter/AppFragmentStateAdapter.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/adapter/AppNavigatorAdapter.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/adapter/AppViewBindingViewHolder.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/appBase/vm/AppViewModel.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/base/BaseActivity.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/base/BaseFragment.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/base/BaseViewModel.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/base/compose/BaseComposeActivity.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/base/views/BaseViewsActivity.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/base/views/BaseViewsDialogFragment.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/base/views/BaseViewsFragment.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/base/views/adapter/BaseDiffItemCallback.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/base/views/adapter/BaseFragmentStateAdapter.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/base/views/adapter/BaseViewBindingViewHolder.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/basebean/ResponseData.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/basebean/ResponseNew.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/empty/EmptyViewModel.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/interfaces/DialogInit.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/interfaces/FragmentIsLazyInit.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/interfaces/LoadStateUiStateOwner.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/interfaces/UiStateOwner.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/interfaces/ViewBindingsInit.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/interfaces/ViewModelOwner.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/message/Message.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/message/MessageCollector.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/message/MessageCollectorOwner.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/message/MessageController.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/message/MessageDisplayManager.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/message/MessageManager.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/message/collector/SnakbarViewMessageCollector.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/message/collector/ToastMessageCollector.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/message/controller/DefaultMessageController.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/page/BaseMemoryRefreshLoadMoreRepository.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/page/OnRepositoryRefreshLoadMoreListeners.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/page/PageKeyedMemoryRefreshLoadMoreRepository.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/page/RefreshRepository.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/repository/BaseRepositoryNew.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/startup/BaseGlobalMessageInitializer.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/stateview/LoadStateUiState.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/stateview/interfaces/DefaultStateViewManager.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/stateview/interfaces/StateViewManager.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/stateview/util/StateView.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/stateview/util/StateViewManager.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/Fragment.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/LoadState.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/MagicIndicator.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/Throwable.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/UiStateMapChangedCollect.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/ViewPager2.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/WindowInsetsController.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/state/ConstraintLayoutMergeStateBaseView.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/state/DefaultStateEmptyView.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/state/DefaultStateErrorView.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/state/DefaultStateLoadingView.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/state/DefaultStateView.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/state/StateView.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/state/interfaces/StateBaseView.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/state/interfaces/StateEmptyView.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/state/interfaces/StateErrorView.kt create mode 100644 core/architecture/src/main/java/com/ama/core/architecture/util/state/interfaces/StateLoadingView.kt create mode 100644 core/architecture/src/main/res/anim/slide_in_bottom.xml create mode 100644 core/architecture/src/main/res/anim/slide_in_left.xml create mode 100644 core/architecture/src/main/res/anim/slide_in_right.xml create mode 100644 core/architecture/src/main/res/anim/slide_out_bottom.xml create mode 100644 core/architecture/src/main/res/anim/slide_out_left.xml create mode 100644 core/architecture/src/main/res/anim/slide_out_right.xml create mode 100644 core/architecture/src/main/res/layout/douyin_core_designsystem_view_state_empty.xml create mode 100644 core/architecture/src/main/res/layout/douyin_core_designsystem_view_state_error.xml create mode 100644 core/architecture/src/main/res/layout/douyin_core_designsystem_view_state_loading.xml create mode 100644 core/architecture/src/main/res/mipmap-nodpi/ic_state_empty.png create mode 100644 core/architecture/src/main/res/mipmap-nodpi/ic_state_error.png create mode 100644 core/architecture/src/main/res/values/colors.xml create mode 100644 core/architecture/src/main/res/values/dimens.xml create mode 100644 core/architecture/src/main/res/values/strings.xml create mode 100644 core/architecture/src/main/res/values/styles.xml create mode 100644 core/architecture/src/main/res/values/themes.xml create mode 100644 core/common/.gitignore create mode 100644 core/common/build.gradle create mode 100644 core/common/consumer-rules.pro create mode 100644 core/common/proguard-rules.pro create mode 100644 core/common/src/main/AndroidManifest.xml create mode 100644 core/common/src/main/java/com/ama/core/common/exception/RuleException.kt create mode 100644 core/common/src/main/java/com/ama/core/common/interfaces/empty/DefaultActivityLifecycleCallbacks.kt create mode 100644 core/common/src/main/java/com/ama/core/common/startup/BaseCommonInitializer.kt create mode 100644 core/common/src/main/java/com/ama/core/common/util/Any.kt create mode 100644 core/common/src/main/java/com/ama/core/common/util/AppProvider.kt create mode 100644 core/common/src/main/java/com/ama/core/common/util/Context.kt create mode 100644 core/common/src/main/java/com/ama/core/common/util/DisplaySize.kt create mode 100644 core/common/src/main/java/com/ama/core/common/util/Dp.kt create mode 100644 core/common/src/main/java/com/ama/core/common/util/Sp.kt create mode 100644 core/common/src/main/java/com/ama/core/common/util/View.kt create mode 100644 core/common/src/main/java/com/ama/core/common/widget/DragIconView.kt create mode 100644 core/common/src/main/java/com/ama/core/common/widget/DragLayout.kt create mode 100644 core/common/src/main/java/com/ama/core/common/widget/PopMenuIconView.kt create mode 100644 core/common/src/main/java/com/ama/core/common/widget/roundedimageview/Corner.java create mode 100644 core/common/src/main/java/com/ama/core/common/widget/roundedimageview/RoundedDrawable.java create mode 100644 core/common/src/main/java/com/ama/core/common/widget/roundedimageview/RoundedImageView.java create mode 100644 core/common/src/main/res/layout/layout_pop_icon_menu_view.xml create mode 100644 core/common/src/main/res/mipmap-xxhdpi/home_collapse.webp create mode 100644 core/common/src/main/res/mipmap-xxhdpi/home_envelope.webp create mode 100644 core/common/src/main/res/mipmap-xxhdpi/home_expand.webp create mode 100644 core/common/src/main/res/mipmap-xxhdpi/home_gold.webp create mode 100644 core/common/src/main/res/values/attrs.xml create mode 100644 core/common/src/main/res/values/colors.xml create mode 100644 core/core.includes.gradle create mode 100644 core/designsystem/.gitignore create mode 100644 core/designsystem/build.gradle create mode 100644 core/designsystem/consumer-rules.pro create mode 100644 core/designsystem/proguard-rules.pro create mode 100644 core/designsystem/src/main/AndroidManifest.xml create mode 100644 core/designsystem/src/main/java/com/ama/core/designsystem/widget/DefaultLoadingDialog.kt create mode 100644 core/designsystem/src/main/java/com/ama/core/designsystem/widget/TitleBar.kt create mode 100644 core/designsystem/src/main/java/com/ama/core/designsystem/widget/interfaces/LoadingDialog.kt create mode 100644 core/designsystem/src/main/java/com/ama/core/designsystem/widget/interfaces/StateView.kt create mode 100644 core/designsystem/src/main/res/values/titlebar_values.xml create mode 100644 core/model/.gitignore create mode 100644 core/model/build.gradle create mode 100644 core/model/consumer-rules.pro create mode 100644 core/model/proguard-rules.pro create mode 100644 core/model/src/main/AndroidManifest.xml create mode 100644 core/model/src/main/java/com/ama/core/model/BaseDiffItem.kt create mode 100644 core/model/src/main/java/com/ama/core/model/BaseFragmentStateDiffItem.kt create mode 100644 core/network/.gitignore create mode 100644 core/network/build.gradle create mode 100644 core/network/consumer-rules.pro create mode 100644 core/network/proguard-rules.pro create mode 100644 core/network/src/main/AndroidManifest.xml create mode 100644 core/network/src/main/java/com/ama/core/network/model/BaseNetworkModel.kt create mode 100644 core/network/src/main/java/com/ama/core/network/util/BaseNetworkModel.kt create mode 100644 generateModuleGraphs.sh create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..15acb8e --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,91 @@ +plugins { + alias(libs.plugins.androidApplication) + alias(libs.plugins.kotlinAndroid) + alias(libs.plugins.hilt) +// alias(libs.plugins.ksp) + alias(libs.plugins.protobuf) + id 'kotlin-kapt' +} + +android { + namespace = "com.gamedog.vididin" + compileSdk libs.versions.compileSdk.get().toInteger() + + defaultConfig { + applicationId "com.gamedog.vididin" + minSdk libs.versions.minSdk.get().toInteger() + targetSdk libs.versions.targetSdk.get().toInteger() + versionCode libs.versions.versionCode.get().toInteger() + versionName libs.versions.versionName.get().toString() + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility libs.versions.javaVersion.get().toInteger() + targetCompatibility libs.versions.javaVersion.get().toInteger() + } + kotlinOptions { + jvmTarget = libs.versions.javaVersion.get().toInteger() + } + buildFeatures { + viewBinding = true + } +} + + +protobuf { + protoc { + artifact = libs.protobuf.protoc.get().toString() + } + generateProtoTasks { + all().forEach { task -> + task.builtins { + register("java") { + option("lite") + } + register("kotlin") { + option("lite") + } + } + } + } +} + + + +dependencies { + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.test.ext.junit) + androidTestImplementation(libs.espresso.core) + + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation(project(":core:network")) + implementation(project(":core:architecture")) + //api(project(":core:architecture-reflect")) + implementation(project(":core:network")) + implementation libs.androidx.navigation.fragment.ktx + implementation(libs.startup) + implementation(libs.hilt.android) + kapt(libs.hilt.compiler) + //ksp(libs.hilt.compiler) + implementation(libs.material) + implementation(libs.datastore) + implementation(libs.protobuf.kotlin.lite) + implementation(libs.kotlinx.serialization.json) + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:core:13.0.0' + implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:custom-ui:13.0.0' + implementation(libs.glide) // ImageLoader在用 + implementation(libs.okhttp.logging) + implementation(libs.retrofit) + implementation(libs.retrofit.kotlin.serialization) + + +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..1133de5 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/App.kt b/app/src/main/java/com/gamedog/vididin/App.kt new file mode 100644 index 0000000..08560ae --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/App.kt @@ -0,0 +1,8 @@ +package com.gamedog.vididin + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + + +@HiltAndroidApp +class App : Application() \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/Constants.kt b/app/src/main/java/com/gamedog/vididin/Constants.kt new file mode 100644 index 0000000..223b4db --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/Constants.kt @@ -0,0 +1,16 @@ +package com.gamedog.vididin + +/** + * 描述:网络常量 + * + */ +const val URL_YOUTUBE_API = "https://www.googleapis.com" + + + + +/** + * 描述:其他常量 + * + */ +const val XXXX = "xxx" \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/adapter/MainTabsAdapter.kt b/app/src/main/java/com/gamedog/vididin/adapter/MainTabsAdapter.kt new file mode 100644 index 0000000..7a5f821 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/adapter/MainTabsAdapter.kt @@ -0,0 +1,174 @@ +package com.gamedog.vididin.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.widget.ImageView +import android.widget.TextView +import androidx.core.view.isVisible +import androidx.fragment.app.FragmentActivity +import androidx.viewpager2.widget.ViewPager2 +import com.ama.core.architecture.appBase.adapter.AppNavigatorAdapter +import com.ama.core.common.util.asSafe +import com.ama.core.common.util.getDataFromThemeAttr +import com.gamedog.vididin.R +import com.gamedog.vididin.beans.MainTabsItem +import com.gamedog.vididin.main.interfaces.OnTabClickAgainListener +import com.gamedog.vididin.main.interfaces.OnTabClickRefreshFinishListener +import com.gamedog.vididin.main.interfaces.OnTabClickRefreshListener +import net.lucode.hackware.magicindicator.MagicIndicator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.CommonNavigator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator +import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerTitleView +import net.lucode.hackware.magicindicator.buildins.commonnavigator.titles.CommonPagerTitleView +import kotlin.ranges.until +import com.gamedog.vididin.databinding.ItemActivityMainTabBinding as ViewBinding +import com.google.android.material.R as materialR + + + +class MainTabsAdapter( + private val activity: FragmentActivity, + private val viewPager2: ViewPager2, + private val mainFragmentStateAdapter: MainViewPagerAdapter, + private val magicIndicator: MagicIndicator, +) : AppNavigatorAdapter() { + + companion object { + val TEXT_TAB = 1 + val IMAGE_TAB = 2 + } + + + private var isDarkFont: Boolean = true + + override fun getTabView(context: Context, index: Int, item: MainTabsItem): IPagerTitleView { + val tabView = CommonPagerTitleView(context) + + val binding = ViewBinding.inflate(LayoutInflater.from(context)) + binding.setTabStyle(IMAGE_TAB) + tabView.setContentView(binding.root) + tabView.setColor(isDarkFont, index == viewPager2.currentItem) + tabView.updateImageSrc(false, item) + + + tabView.setOnClickListener { + binding.onTabClickHandle(index, item) + } + tabView.onPagerTitleChangeListener = object: CommonPagerTitleView.OnPagerTitleChangeListener { + override fun onSelected(index: Int, totalCount: Int) { + tabView.updateImageSrc(true, item) + } + + override fun onDeselected(index: Int, totalCount: Int) { + tabView.updateImageSrc(false, item) + } + + override fun onLeave( + index: Int, + totalCount: Int, + leavePercent: Float, + leftToRight: Boolean + ) { + + } + + override fun onEnter( + index: Int, + totalCount: Int, + enterPercent: Float, + leftToRight: Boolean + ) { + + } + } + + return tabView + } + + + override fun getIndicator(context: Context): IPagerIndicator? = null + + private fun ViewBinding.onTabClickHandle(index: Int, item: MainTabsItem) { + if (viewPager2.currentItem == index) { + onTabClickAgainHandle(index) + } else { + val isNeedLogin = false + if (!isNeedLogin) { + viewPager2.setCurrentItem(index, false) + } else { + /*LoginManager.checkLogin(activity) { + viewPager2.setCurrentItem(index, false) + }*/ + } + } + } + + private fun ViewBinding.onTabClickAgainHandle(index: Int) { + val currentFragment = mainFragmentStateAdapter.getFragmentByIndex(index) + if (currentFragment is OnTabClickRefreshListener) { + // 刷新 - 展示Loading + currentFragment.onTabClickRefresh(object : OnTabClickRefreshFinishListener { + override fun onTabClickRefreshFinish() { + setTabStyle(1) + } + }) + } else if (currentFragment is OnTabClickAgainListener) { + currentFragment.onTabClickAgain() + } + } + + + private fun ViewBinding.setTabStyle(type: Int) { + when (type) { + TEXT_TAB -> { + title.isVisible = true + image.isVisible = false + } + + IMAGE_TAB -> { + title.isVisible = false + image.isVisible = true + } + } + } + + fun setIsDarkFont(isDarkFont: Boolean) { + this.isDarkFont = isDarkFont + setTitleColor(isDarkFont) + setBackgroundColor(isDarkFont) + } + + private fun setTitleColor(isDarkFont: Boolean) { + val titleContainer = + magicIndicator.navigator.asSafe()?.titleContainer ?: return + for (i in 0 until titleContainer.childCount) { + titleContainer.getChildAt(i).asSafe() + ?.setColor(isDarkFont, i == viewPager2.currentItem) + } + } + + private fun CommonPagerTitleView.setColor( + isDarkFont: Boolean, + selected: Boolean, + ) { + val title = findViewById(R.id.title) + title.alpha = if (selected) 1f else 0.7f + title.setTextColor(context.getDataFromThemeAttr(if (isDarkFont) materialR.attr.colorOnSurface else materialR.attr.colorOnSurfaceInverse)) + } + + private fun CommonPagerTitleView.updateImageSrc( + selected: Boolean, + tabItem: MainTabsItem + ) { + val image = findViewById(R.id.image) + image.setImageResource(if (selected) tabItem.tabIconSelected else tabItem.tabIconNormal) + } + + private fun setBackgroundColor( + isDarkFont: Boolean, + ) { + val selectedBackgroundColor = + magicIndicator.context.getDataFromThemeAttr(if (isDarkFont) materialR.attr.colorSurface else materialR.attr.colorSurfaceInverse) + magicIndicator.setBackgroundColor(selectedBackgroundColor) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/adapter/MainViewPagerAdapter.kt b/app/src/main/java/com/gamedog/vididin/adapter/MainViewPagerAdapter.kt new file mode 100644 index 0000000..1df61e3 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/adapter/MainViewPagerAdapter.kt @@ -0,0 +1,21 @@ +package com.gamedog.vididin.adapter + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import com.ama.core.architecture.appBase.adapter.AppFragmentStateAdapter +import com.gamedog.vididin.beans.MainTabsItem +import com.gamedog.vididin.repository.MainTabType +import com.gamedog.vididin.router.Router + + +class MainViewPagerAdapter(activity: FragmentActivity) : + AppFragmentStateAdapter(activity, true) { + + override fun createFragment(position: Int, item: MainTabsItem): Fragment { + return when (item.type) { + MainTabType.HOME -> Router.Home.createHomeFragment() + MainTabType.TASKS -> Router.Task.createTaskFragment() + MainTabType.MINE -> Router.Mine.createMineFragment() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/api/YoutubeApi.kt b/app/src/main/java/com/gamedog/vididin/api/YoutubeApi.kt new file mode 100644 index 0000000..af701b0 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/api/YoutubeApi.kt @@ -0,0 +1,48 @@ +package com.gamedog.vididin.feature.home.api + + + +import com.gamedog.vididin.beans.ResYoutubeChannel +import com.gamedog.vididin.beans.ResYoutubePlayList +import retrofit2.http.GET +import retrofit2.http.Query +import java.net.URLEncoder + + +interface YoutubeApi { + + /** + * Youtube channel list + */ + @GET("/youtube/v3/channels") + suspend fun getChannelList( + @Query("part") part: String="snippet", + @Query("key") key: String="AIzaSyBm9k2lS_j7Fdd43NEPkcfikJRotup5DMY", + @Query("channelId") channelId: String="UCbTLwN10NoCU4WDzLf1JMOA", + ): ResYoutubeChannel + + + /** + * Youtube play list + */ + @GET("/youtube/v3/playlists") + suspend fun getPlayList( + @Query("part") part: String="snippet", + @Query("key") key: String="AIzaSyBm9k2lS_j7Fdd43NEPkcfikJRotup5DMY", + @Query("channelId") channelId: String="UCbTLwN10NoCU4WDzLf1JMOA", + ): ResYoutubePlayList + + + @GET("/youtube/v3/playlistItems") + suspend fun getVideoList( + @Query("part") part: String= URLEncoder.encode("id", "UTF-8"), + @Query("key") key: String="AIzaSyBm9k2lS_j7Fdd43NEPkcfikJRotup5DMY", + @Query("playlistId") channelId: String="PLcVfz1-_0rj_KFKlQeW2ZJnWTSjgc-9Jp", + //@Query("pageToken") pageToken: String="" + ): ResYoutubePlayList + + + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/beans/MainTabsItem.kt b/app/src/main/java/com/gamedog/vididin/beans/MainTabsItem.kt new file mode 100644 index 0000000..f682fda --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/beans/MainTabsItem.kt @@ -0,0 +1,24 @@ +package com.gamedog.vididin.beans + +import com.ama.core.common.util.asUnsafe +import com.ama.core.model.BaseFragmentStateDiffItem +import com.gamedog.vididin.repository.MainTabType + + +data class MainTabsItem( + val titleResId: Int, + val type: MainTabType, + val tabIconNormal: Int, + val tabIconSelected: Int, + val updateMainTabShopOrFriend: (Boolean) -> Unit, +) : BaseFragmentStateDiffItem { + + override fun getPrimaryKey() = type + + override fun areContentsTheSame(newItem: T): Boolean { + val mainTabsItem = newItem.asUnsafe() + return titleResId == mainTabsItem.titleResId && type == mainTabsItem.type + } + + override fun getItemId() = type.ordinal.toLong() +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/beans/User.kt b/app/src/main/java/com/gamedog/vididin/beans/User.kt new file mode 100644 index 0000000..40746fa --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/beans/User.kt @@ -0,0 +1,9 @@ +package com.gamedog.vididin.beans + + +data class User( + val id: Int, + val token: String, + val account: String, + val createdAt: String, +) diff --git a/app/src/main/java/com/gamedog/vididin/beans/UserData.kt b/app/src/main/java/com/gamedog/vididin/beans/UserData.kt new file mode 100644 index 0000000..5f9840c --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/beans/UserData.kt @@ -0,0 +1,9 @@ +package com.gamedog.vididin.beans + + +data class UserData( + val user: User, + val mainTabs: List, + val homeTabs: List, + val useDynamicColor: Boolean, +) \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/beans/YoutubeBeans.kt b/app/src/main/java/com/gamedog/vididin/beans/YoutubeBeans.kt new file mode 100644 index 0000000..e333f63 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/beans/YoutubeBeans.kt @@ -0,0 +1,122 @@ +package com.gamedog.vididin.beans + + +import com.ama.core.model.BaseFragmentStateDiffItem +import kotlinx.serialization.Serializable + + +@Serializable +data class ResYoutubeChannel( + val id: String, + val name: String, +) : BaseFragmentStateDiffItem { + override fun getPrimaryKey() = id + override fun getItemId() = id.hashCode().toLong() +} + + + +@Serializable +data class ResYoutubePlayList ( + val kind: String, + val etag: String, // TODO - this is Etag type + val nextPageToken: String, + val prevPageToken: String, + val pageInfo: PageInfo, + val items: List, +) /*: BaseFragmentStateDiffItem { + override fun getPrimaryKey() = pageInfo + override fun getItemId() = pageInfo.hashCode().toLong() +}*/ + + +@Serializable +data class PageInfo( + val totalResults: Int, + val resultsPerPage: Int, +) : BaseFragmentStateDiffItem { + override fun getPrimaryKey() = totalResults + override fun getItemId() = totalResults.hashCode().toLong() +} + +@Serializable +data class YoutubeVideo( + val kind: String, + val etag: String, + val id: String, + val snippet: Snippet, + val status: Status, + + val contentDetails: ContentDetails, + val player: Player, + val localizations: Localizations, +) : BaseFragmentStateDiffItem { + override fun getPrimaryKey() = id + override fun getItemId() = id.hashCode().toLong() +} + + + +@Serializable +data class ContentDetails( + val itemCount: Int, +): BaseFragmentStateDiffItem { + override fun getPrimaryKey() = itemCount + override fun getItemId() = itemCount.hashCode().toLong() +} + +@Serializable +data class Player( + val embedHtml: String, +): BaseFragmentStateDiffItem { + override fun getPrimaryKey() = embedHtml + override fun getItemId() = embedHtml.hashCode().toLong() +} + +@Serializable +data class Localizations( + val title: String, + val description: String, +): BaseFragmentStateDiffItem { + override fun getPrimaryKey() = title + override fun getItemId() = title.hashCode().toLong() +} + + + +@Serializable +data class Snippet( + val publishedAt: String, + val channelId: String, + val title: String, + val description: String, + val thumbnails: String, // + + val channelTitle: String, + val defaultLanguage: String, + val localized: Localized, +) : BaseFragmentStateDiffItem { + override fun getPrimaryKey() = channelId + override fun getItemId() = channelId.hashCode().toLong() +} + +@Serializable +data class Localized( + val title: String, + val description: String, +) : BaseFragmentStateDiffItem { + override fun getPrimaryKey() = title + override fun getItemId() = title.hashCode().toLong() +} + +@Serializable +data class Status( + val privacyStatus: String, + val podcastStatus: Int, +): BaseFragmentStateDiffItem { + override fun getPrimaryKey() = podcastStatus + override fun getItemId() = privacyStatus.hashCode().toLong() +} + + + diff --git a/app/src/main/java/com/gamedog/vididin/di/AppDispatchers.kt b/app/src/main/java/com/gamedog/vididin/di/AppDispatchers.kt new file mode 100644 index 0000000..a2dd13e --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/di/AppDispatchers.kt @@ -0,0 +1,13 @@ +package com.gamedog.vididin.di + +import javax.inject.Qualifier + + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +annotation class Dispatcher(val appDispatcher: AppDispatchers) + +enum class AppDispatchers { + Default, + IO, +} diff --git a/app/src/main/java/com/gamedog/vididin/di/CoroutineScopesModule.kt b/app/src/main/java/com/gamedog/vididin/di/CoroutineScopesModule.kt new file mode 100644 index 0000000..5f96d55 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/di/CoroutineScopesModule.kt @@ -0,0 +1,29 @@ +package com.gamedog.vididin.di + + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import javax.inject.Qualifier +import javax.inject.Singleton + + +@Retention(AnnotationRetention.RUNTIME) +@Qualifier +annotation class ApplicationScope + +@Module +@InstallIn(SingletonComponent::class) +internal object CoroutineScopesModule { + @Provides + @Singleton + @ApplicationScope + // 提供全局协程作用域 + fun providesCoroutineScope( + @Dispatcher(AppDispatchers.Default) dispatcher: CoroutineDispatcher, + ): CoroutineScope = CoroutineScope(SupervisorJob() + dispatcher) +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/di/DataModule.kt b/app/src/main/java/com/gamedog/vididin/di/DataModule.kt new file mode 100644 index 0000000..726dbc1 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/di/DataModule.kt @@ -0,0 +1,18 @@ +package com.gamedog.vididin.di + + +import com.gamedog.vididin.repository.DefaultMainRepository +import com.gamedog.vididin.repository.MainRepository +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + + +@Module +@InstallIn(SingletonComponent::class) +interface DataModule { + + @Binds + fun bindsMainRepository(repository: DefaultMainRepository): MainRepository +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/di/GlobalInterceptor.kt b/app/src/main/java/com/gamedog/vididin/di/GlobalInterceptor.kt new file mode 100644 index 0000000..e4368ec --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/di/GlobalInterceptor.kt @@ -0,0 +1,100 @@ +package com.gamedog.vididin.core.network.di + + +import android.util.Log +import okhttp3.Headers +import okhttp3.Interceptor +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.Request +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.Response +import okhttp3.ResponseBody +import okhttp3.ResponseBody.Companion.asResponseBody +import okio.Buffer +import java.io.IOException +import java.util.Locale + + +class GlobalInterceptor : Interceptor { + + override fun intercept(chain: Interceptor.Chain): Response { + var request = chain.request() + val bodyStr = readBody(chain.request().body) + val emptyBody = "{}".toRequestBody("application/json;charset=utf-8".toMediaType()) + val requestBody = if (bodyStr.isNotBlank()) request.body else emptyBody + + + val headersBuilder = Headers.Builder() + /* + .add("authorazation", "Bearer xxxxx") + .add("AUTH_DID", AppUtils.getAndroidID()) + .add("platform", AppConstant.APP_CLIENT) + .add("Authorization", "Bearer xxx") + .add("versionNum", "100") + */ + .add("User-Agent", "Android") + .add("Accept-Language", Locale.getDefault().toLanguageTag()) + .add("Content-Type", "application/json") + .add("Accept", "application/json") + .add("Accept-Charset", "utf-8") + + + val headers = headersBuilder.build() + request = chain.request().newBuilder() + .headers(headers) + .build() + val response = chain.proceed(request) + + + if (true) { + try { + Log.d("RetroLog" , + """ + ———————————————— 发起请求 我是开始分割线 —————————————————————————————— + ${request.url} + ******** 请求头 ${request.method} ********: + ${getRequestHeadersString(request)} + ******** 请求体(当post等时) ********: + ${readBody(requestBody)} + ******** 请求响应 ********: + ${clone(response.body)?.string()} + ———————————————— 我是结束分割线 ——————————————————————————————— + """.trimIndent() + ) + } catch (e: Exception) { + Log.d("RetroLog" , "GlobalInterceptor request.exception : ${e.localizedMessage}}") + } + } + + return response + } + + + fun getRequestHeadersString(request: Request): String { + val headers = request.headers + val headerCount = headers.size + + val sb = StringBuilder() + for (i in 0 until headerCount) { + val key = headers.name(i) + val value = headers.value(i) + sb.append("$key=$value\n") + } + return sb.toString() + } + + private fun readBody(body: RequestBody?): String { + val buffer = Buffer() + body?.writeTo(buffer) + return buffer.readUtf8() + } + + @Throws(IOException::class) + private fun clone(body: ResponseBody?): ResponseBody? { + val source = body?.source() + if (source?.request(Long.MAX_VALUE) == true) throw IOException("body too long!") + val bufferedCopy = source?.buffer?.clone() + return bufferedCopy?.asResponseBody(body.contentType(), body.contentLength()) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/di/HomeModule.kt b/app/src/main/java/com/gamedog/vididin/di/HomeModule.kt new file mode 100644 index 0000000..4ed77db --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/di/HomeModule.kt @@ -0,0 +1,71 @@ +package com.gamedog.vididin.di + +import com.gamedog.vididin.core.router.interfaces.HomeRouter +import com.gamedog.vididin.core.router.interfaces.LoginRouter +import com.gamedog.vididin.core.router.interfaces.MineRouter +import com.gamedog.vididin.core.router.interfaces.TaskRouter +import com.gamedog.vididin.feature.home.repository.DefaultYoutubeDatasource +import com.gamedog.vididin.feature.home.repository.DefaultYoutubeRepository +import com.gamedog.vididin.main.fragments.home.YoutubeDataSource +import com.gamedog.vididin.main.fragments.home.YoutubeRepository +import com.gamedog.vididin.router.DefaultHomeRouter +import com.gamedog.vididin.router.DefaultLoginRouter +import com.gamedog.vididin.router.DefaultMineRouter +import com.gamedog.vididin.router.DefaultTaskRouter +import dagger.Binds +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + + +@Module +@InstallIn(SingletonComponent::class) +object HomeModule { + @Provides + @Singleton + fun providesHomeRouter(): HomeRouter = DefaultHomeRouter() +} + +@Module +@InstallIn(SingletonComponent::class) +object TaskModule { + @Provides + @Singleton + fun providesTaskRouter(): TaskRouter = DefaultTaskRouter() +} + +@Module +@InstallIn(SingletonComponent::class) +object MineModule { + @Provides + @Singleton + fun providesMineRouter(): MineRouter = DefaultMineRouter() +} + + +@Module +@InstallIn(SingletonComponent::class) +internal interface YoutubeDataSourceModule { + @Binds + fun binds(impl: DefaultYoutubeDatasource): YoutubeDataSource +} + + +@Module +@InstallIn(SingletonComponent::class) +interface YoutubeRepositoryModule { + @Binds + fun bindsYoutubeRepository(repository: DefaultYoutubeRepository): YoutubeRepository +} + + +@Module +@InstallIn(SingletonComponent::class) +object LoginModule { + + @Provides + @Singleton + fun providesLoginRouter(): LoginRouter = DefaultLoginRouter() +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/di/NetworkModule.kt b/app/src/main/java/com/gamedog/vididin/di/NetworkModule.kt new file mode 100644 index 0000000..75c6aea --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/di/NetworkModule.kt @@ -0,0 +1,60 @@ +package com.gamedog.vididin.di + + +import com.gamedog.vididin.URL_YOUTUBE_API +import com.gamedog.vididin.core.network.di.GlobalInterceptor +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.serialization.json.Json +import okhttp3.Call +import okhttp3.OkHttpClient +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import javax.inject.Singleton + + +@Module +@InstallIn(SingletonComponent::class) +internal object NetworkModule { + + @Provides + @Singleton + fun providesNetworkJson(): Json = Json { + ignoreUnknownKeys = true + isLenient = true + } + + @Provides + @Singleton + fun okHttpCallFactory(): Call.Factory = + OkHttpClient.Builder() + .addInterceptor(GlobalInterceptor()) + /*.addInterceptor( + HttpLoggingInterceptor() + .apply { + if (BuildConfig.DEBUG) { + setLevel(HttpLoggingInterceptor.Level.BODY) + } + }, + )*/ + .build() + + @Provides + @Singleton + fun providesRetrofit( + networkJson: Json, + okhttpCallFactory: dagger.Lazy, + ): Retrofit { + return Retrofit.Builder() + .baseUrl(URL_YOUTUBE_API) + .callFactory { okhttpCallFactory.get().newCall(it) } + .addConverterFactory( + GsonConverterFactory.create() + //networkJson.asConverterFactory("application/json".toMediaType()), + ) + .build() + } +} + diff --git a/app/src/main/java/com/gamedog/vididin/di/RouterEntryPoints.kt b/app/src/main/java/com/gamedog/vididin/di/RouterEntryPoints.kt new file mode 100644 index 0000000..5fd22ca --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/di/RouterEntryPoints.kt @@ -0,0 +1,20 @@ +package com.gamedog.vididin.di + +import com.gamedog.vididin.core.router.interfaces.HomeRouter +import com.gamedog.vididin.core.router.interfaces.LoginRouter +import com.gamedog.vididin.core.router.interfaces.MineRouter +import com.gamedog.vididin.core.router.interfaces.TaskRouter +import dagger.hilt.EntryPoint +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + + +@EntryPoint +@InstallIn(SingletonComponent::class) +interface RouterEntryPoint { + fun homeRouter(): HomeRouter + fun taskRouter(): TaskRouter + fun mineRouter(): MineRouter + fun loginRouter(): LoginRouter +} + diff --git a/app/src/main/java/com/gamedog/vididin/login/LoginActivity.kt b/app/src/main/java/com/gamedog/vididin/login/LoginActivity.kt new file mode 100644 index 0000000..d297990 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/login/LoginActivity.kt @@ -0,0 +1,60 @@ +package com.gamedog.vididin.login + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import com.ama.core.architecture.appBase.AppViewsEmptyViewModelActivity +import com.gamedog.vididin.databinding.VididinappFeatureLoginActivityLoginBinding as ViewBinding +import dagger.hilt.android.AndroidEntryPoint +import kotlin.jvm.java + + + +@AndroidEntryPoint +@Suppress("DEPRECATION") +class LoginActivity : AppViewsEmptyViewModelActivity() { + + + override fun onCreate(savedInstanceState: Bundle?) { + /*Activity.overridePendingTransition( + designSystemR.anim.slide_in_bottom, + 0 + )*/ + super.onCreate(savedInstanceState) + } + + override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater) + + override fun ViewBinding.initWindowInsets() { + // 由于登录页面的子Fragment没有背景,所以在此统一设置内间距即可实现,子Fragment不需要实现。 + ViewCompat.setOnApplyWindowInsetsListener(root) { v, insets -> + val systemBars = insets.getInsets( + WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() or WindowInsetsCompat.Type.ime() + ) + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) + insets + } + } + + override fun ViewBinding.initViews() { + } + + override fun ViewBinding.initListeners() { + } + + override fun ViewBinding.initObservers() { + } + + override fun finish() { + super.finish() + } + + companion object { + internal fun startActivity(activity: Activity) { + activity.startActivity(Intent(activity.applicationContext, LoginActivity::class.java)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/login/LoginManager.kt b/app/src/main/java/com/gamedog/vididin/login/LoginManager.kt new file mode 100644 index 0000000..2007ddd --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/login/LoginManager.kt @@ -0,0 +1,7 @@ +package com.gamedog.vididin.core.login.login + + +object LoginManager { + +} + diff --git a/app/src/main/java/com/gamedog/vididin/main/MainActivity.kt b/app/src/main/java/com/gamedog/vididin/main/MainActivity.kt new file mode 100644 index 0000000..8e21d31 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/MainActivity.kt @@ -0,0 +1,122 @@ +package com.gamedog.vididin.main + + +import com.ama.core.common.util.asSafe +import androidx.activity.OnBackPressedCallback +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks +import androidx.viewpager2.widget.ViewPager2 +import android.view.LayoutInflater +import androidx.activity.viewModels +import com.ama.core.architecture.appBase.AppViewsActivity +import com.ama.core.architecture.appBase.OnFragmentBackgroundListener +import com.ama.core.architecture.util.bindViewPager2 +import com.ama.core.architecture.util.setCommonNavigator +import com.ama.core.architecture.util.setDataOrAdapter +import com.gamedog.vididin.adapter.MainTabsAdapter +import com.gamedog.vididin.adapter.MainViewPagerAdapter +import com.gamedog.vididin.main.interfaces.OnSwitchTabListener +import com.gamedog.vididin.main.interfaces.OnTabStyleListener +import dagger.hilt.android.AndroidEntryPoint +import kotlin.getValue +import com.gamedog.vididin.databinding.ActivityMainBinding as ViewBinding +import com.gamedog.vididin.main.MainUiState as UiState +import com.gamedog.vididin.main.MainViewModel as ViewModel + + + + +@AndroidEntryPoint +class MainActivity : AppViewsActivity(), OnTabStyleListener { + + override val viewModel: ViewModel by viewModels() + private lateinit var navigatorAdapter: MainTabsAdapter + private val fragmentStateAdapter by lazy { MainViewPagerAdapter(this) } + + + + private val onBackPressedCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + fragmentStateAdapter.getFragmentByIndex(0).asSafe() + ?.onSwitchTab(-1) + + binding.viewPager2.setCurrentItem(0, false) + } + } + + override fun inflateViewBinding(inflater: LayoutInflater) = ViewBinding.inflate(inflater) + + override fun ViewBinding.initWindowInsets() { + ViewCompat.setOnApplyWindowInsetsListener(magicIndicator) { v, insets -> + val systemBars = + insets.getInsets(WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.displayCutout()) + v.setPadding( + systemBars.left, + 36, + systemBars.right, + systemBars.bottom + 36 + ) + insets + } + } + + override fun ViewBinding.initViews() { + content.foreground.alpha = 0 + navigatorAdapter = MainTabsAdapter( + this@MainActivity, viewPager2, fragmentStateAdapter, magicIndicator + ) + magicIndicator.setCommonNavigator { isAdjustMode = true } + magicIndicator.bindViewPager2(viewPager2) + + viewPager2.isUserInputEnabled = false + viewPager2.setPageTransformer { _, _ -> } + } + + override fun ViewBinding.initListeners() { + onBackPressedDispatcher.addCallback(this@MainActivity, onBackPressedCallback) + + viewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + setOnBackPressedCallbackIsEnabled() + } + }) + + supportFragmentManager.registerFragmentLifecycleCallbacks(object : + FragmentLifecycleCallbacks() { + override fun onFragmentResumed(fm: FragmentManager, f: Fragment) { + super.onFragmentResumed(fm, f) + val isBackgroundBright = + f.asSafe()?.isBackgroundBright + ?: return + + onTabIsDarkFont(isBackgroundBright) + } + }, false) + } + + override fun ViewBinding.initObservers() { + + } + + override fun ViewBinding.onUiStateCollect(uiState: UiState) { + magicIndicator.setDataOrAdapter(uiState.tabs) { navigatorAdapter } + viewPager2.setDataOrAdapter(uiState.tabs, Int.MAX_VALUE) { fragmentStateAdapter } + } + + + private fun setOnBackPressedCallbackIsEnabled() { + onBackPressedCallback.isEnabled = binding.viewPager2.currentItem != 0 + } + + override fun onResume() { + super.onResume() + } + + override fun onTabIsDarkFont(isDarkFont: Boolean) { + navigatorAdapter.setIsDarkFont(isDarkFont) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/MainViewModel.kt b/app/src/main/java/com/gamedog/vididin/main/MainViewModel.kt new file mode 100644 index 0000000..f5cd565 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/MainViewModel.kt @@ -0,0 +1,59 @@ +package com.gamedog.vididin.main + + +import androidx.lifecycle.viewModelScope +import com.ama.core.architecture.appBase.vm.AppViewModel +import com.gamedog.vididin.R +import com.gamedog.vididin.beans.MainTabsItem +import com.gamedog.vididin.repository.MainRepository +import com.gamedog.vididin.repository.MainTabType +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import javax.inject.Inject +import com.gamedog.vididin.main.MainUiState as UiState + + +@HiltViewModel +class MainViewModel @Inject constructor( + mainRepository: MainRepository, +) : AppViewModel() { + + override val uiStateInitialValue: UiState = UiState() + + override val uiStateFlow: Flow = mainRepository.getMainTabsStream().map { + it.map { type -> + val title = when (type) { + MainTabType.HOME -> R.string.main_tabs_home + MainTabType.TASKS -> R.string.main_tabs_tasks + MainTabType.MINE -> R.string.main_tabs_mine + } + + val normalIcon = when (type) { + MainTabType.HOME -> R.mipmap.tab_home + MainTabType.TASKS -> R.mipmap.tab_tasks + MainTabType.MINE -> R.mipmap.tab_my + } + + val selectedIcon = when (type) { + MainTabType.HOME -> R.mipmap.tab_home_selected + MainTabType.TASKS -> R.mipmap.tab_tasks_selected + MainTabType.MINE -> R.mipmap.tab_my_selected + } + + MainTabsItem(title, type, normalIcon, selectedIcon) { + viewModelScope.launch { + // TODO any other action you need + } + } + } + }.map { + UiState(tabs = it) + } +} + + +data class MainUiState( + val tabs: List? = null, +) \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/HomeFragment.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/HomeFragment.kt new file mode 100644 index 0000000..079bde2 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/HomeFragment.kt @@ -0,0 +1,125 @@ +package com.gamedog.vididin.main.fragments + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.activity.OnBackPressedCallback +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks +import androidx.fragment.app.viewModels +import androidx.viewpager2.widget.ViewPager2 +import com.ama.core.architecture.appBase.AppViewsFragment +import com.ama.core.architecture.appBase.OnFragmentBackgroundListener +import com.ama.core.architecture.util.setDataOrAdapter +import com.ama.core.common.util.asSafe +import com.gamedog.vididin.main.fragments.home.HomeFragmentStateAdapter +import com.gamedog.vididin.main.interfaces.OnSwitchTabListener +import com.gamedog.vididin.main.interfaces.OnTabStyleListener +import dagger.hilt.android.AndroidEntryPoint +import kotlin.getValue +import com.gamedog.vididin.databinding.VididinappFeatureHomeFragmentHomeBinding as ViewBinding +import com.gamedog.vididin.main.fragments.home.YoutubeViewModel as ViewModel +import com.gamedog.vididin.main.fragments.home.YoutubeUiState as UiState + + + +@AndroidEntryPoint +class HomeFragment : AppViewsFragment(), OnSwitchTabListener, + OnFragmentBackgroundListener { + override val viewModel: ViewModel by viewModels() + override var isBackgroundBright: Boolean = true + + + private val onBackPressedCallback = object : OnBackPressedCallback(false) { + override fun handleOnBackPressed() { + } + } + private val mViewPagerAdapter by lazy { HomeFragmentStateAdapter(this) } + + override fun inflateViewBinding( + inflater: LayoutInflater, + container: ViewGroup?, + ) = ViewBinding.inflate(inflater, container, false) + + override fun ViewBinding.initWindowInsets() { + ViewCompat.setOnApplyWindowInsetsListener(viewPager2) { v, insets -> + val systemBars = + insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()) + v.updatePadding(top = systemBars.top) + insets + } + } + + override fun ViewBinding.initViews() { + viewPager2.setPageTransformer { _, _ -> } + viewPager2.offscreenPageLimit = 1 + } + + override fun ViewBinding.initListeners() { + requireActivity().onBackPressedDispatcher.addCallback( + this@HomeFragment, + onBackPressedCallback + ) + + viewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + setHomeTabStyle(mViewPagerAdapter.getFragmentByIndex(position)) + setOnBackPressedCallbackIsEnabled() + } + }) + + childFragmentManager.registerFragmentLifecycleCallbacks(object : + FragmentLifecycleCallbacks() { + override fun onFragmentResumed(fm: FragmentManager, f: Fragment) { + super.onFragmentResumed(fm, f) + setHomeTabStyle(f) + } + }, false) + } + + override fun ViewBinding.initObservers() { + + } + + override fun ViewBinding.onUiStateCollect(uiState: UiState) { + viewPager2.setDataOrAdapter(uiState.playLists, 1) { mViewPagerAdapter } + } + + override fun onResume() { + super.onResume() + setOnBackPressedCallbackIsEnabled() + } + + override fun onPause() { + super.onPause() + setOnBackPressedCallbackIsEnabled() + } + + override fun onSwitchTab(index: Int, smoothScroll: Boolean) { + var item = index + if (index < 0 || index >= mViewPagerAdapter.itemCount) { + item = mViewPagerAdapter.itemCount - 1 + } + binding?.viewPager2?.setCurrentItem(item, smoothScroll) + } + + + private fun setOnBackPressedCallbackIsEnabled() { + onBackPressedCallback.isEnabled = + isResumed && binding?.viewPager2?.currentItem != mViewPagerAdapter.itemCount - 1 + } + + private fun setHomeTabStyle(f: Fragment?) { + isBackgroundBright = f.asSafe()?.isBackgroundBright ?: return + activity.asSafe()?.onTabIsDarkFont(isBackgroundBright) + } + + companion object { + internal fun newInstance() = HomeFragment() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/MineFragment.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/MineFragment.kt new file mode 100644 index 0000000..601bdcb --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/MineFragment.kt @@ -0,0 +1,61 @@ +package com.gamedog.vididin.main.fragments + + + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.fragment.app.viewModels +import com.ama.core.architecture.appBase.AppViewsFragment +import com.ama.core.architecture.appBase.OnFragmentBackgroundListener +import com.ama.core.architecture.util.setStatusBarDarkFont +import dagger.hilt.android.AndroidEntryPoint +import kotlin.getValue +import com.gamedog.vididin.databinding.VididinappFeatureMineFragmentMineBinding as ViewBinding +import com.gamedog.vididin.main.fragments.mine.MineUiState as UiState +import com.gamedog.vididin.main.fragments.mine.MineViewModel as ViewModel + + + + +@AndroidEntryPoint +class MineFragment : AppViewsFragment(), + OnFragmentBackgroundListener { + override val viewModel: ViewModel by viewModels() + override var isBackgroundBright: Boolean = true + + + + private var isStatusBarDarkFont = false + + override fun inflateViewBinding( + inflater: LayoutInflater, + container: ViewGroup?, + ) = ViewBinding.inflate(inflater, container, false) + + override fun ViewBinding.initViews() { + + } + + override fun ViewBinding.initListeners() { + nestedScrollView.setOnScrollChangeListener { _, _, scrollY, _, _ -> + isStatusBarDarkFont = scrollY > topBackground.height + setStatusBarDarkFont(isStatusBarDarkFont) + } + } + + override fun ViewBinding.initObservers() { + } + + override fun ViewBinding.onUiStateCollect(uiState: UiState) { + //dynamicColorsSwitch.isChecked = uiState.useDynamicColor + } + + override fun onResume() { + super.onResume() + setStatusBarDarkFont(isDarkFont = isStatusBarDarkFont) + } + + companion object { + internal fun newInstance() = MineFragment() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/TasksFragment.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/TasksFragment.kt new file mode 100644 index 0000000..49fcecf --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/TasksFragment.kt @@ -0,0 +1,47 @@ +package com.gamedog.vididin.main.fragments + +import android.view.LayoutInflater +import android.view.ViewGroup +import com.ama.core.architecture.appBase.AppViewsEmptyViewModelFragment +import com.ama.core.architecture.appBase.OnFragmentBackgroundListener +import com.ama.core.architecture.util.setStatusBarDarkFont +import com.gamedog.vididin.databinding.VididinappFeatureMessageFragmentMessageBinding as ViewBinding +import com.gamedog.vididin.main.interfaces.OnTabClickAgainListener +import dagger.hilt.android.AndroidEntryPoint + + + + +@AndroidEntryPoint +class TasksFragment : AppViewsEmptyViewModelFragment(), OnTabClickAgainListener, + OnFragmentBackgroundListener { + override var isBackgroundBright: Boolean = true + + + override fun inflateViewBinding( + inflater: LayoutInflater, + container: ViewGroup?, + ) = ViewBinding.inflate(inflater, container, false) + + override fun ViewBinding.initViews() { + + } + + override fun ViewBinding.initListeners() { + } + + override fun ViewBinding.initObservers() { + } + + override fun onResume() { + super.onResume() + setStatusBarDarkFont(isDarkFont = isBackgroundBright) + } + + override fun onTabClickAgain() { + } + + companion object { + internal fun newInstance() = TasksFragment() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/home/DefaultYoutubeDatasource.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/home/DefaultYoutubeDatasource.kt new file mode 100644 index 0000000..37abeb1 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/home/DefaultYoutubeDatasource.kt @@ -0,0 +1,22 @@ +package com.gamedog.vididin.feature.home.repository + + +import com.gamedog.vididin.feature.home.api.YoutubeApi +import com.gamedog.vididin.main.fragments.home.YoutubeDataSource +import retrofit2.Retrofit +import javax.inject.Inject +import javax.inject.Singleton + + +@Singleton +class DefaultYoutubeDatasource @Inject constructor(retrofit: Retrofit) : YoutubeDataSource { + private val shopApi = retrofit.create(YoutubeApi::class.java) + + + override suspend fun getChannels( + ) = shopApi.getChannelList() + + override suspend fun getPlayList( + ) = shopApi.getVideoList() + +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/home/DefaultYoutubeRepository.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/home/DefaultYoutubeRepository.kt new file mode 100644 index 0000000..d8b8c0b --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/home/DefaultYoutubeRepository.kt @@ -0,0 +1,39 @@ +package com.gamedog.vididin.feature.home.repository + + +import com.gamedog.vididin.beans.ResYoutubeChannel +import com.gamedog.vididin.beans.ResYoutubePlayList +import com.gamedog.vididin.beans.YoutubeVideo +import com.gamedog.vididin.core.data.repository.refreshloadmore.PageKeyedMemoryRefreshLoadMoreRepository +import com.gamedog.vididin.main.fragments.home.YoutubeDataSource +import com.gamedog.vididin.main.fragments.home.YoutubeRepository +import javax.inject.Inject + + +class DefaultYoutubeRepository @Inject constructor( + private val network: YoutubeDataSource, +) : PageKeyedMemoryRefreshLoadMoreRepository(), YoutubeRepository { + + override suspend fun getVideoList( + page: Int, + size: Int + ): ResYoutubePlayList { + return network.getPlayList() + } + + override suspend fun getChannelList( + page: Int, + size: Int + ): ResYoutubeChannel { + return network.getChannels() + } + + override suspend fun getListDataByKey( + key: Int, + pageSize: Int + ): List? { + return getVideoList(key, pageSize).items + } + + +} diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/home/HomeFragmentStateAdapter.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/home/HomeFragmentStateAdapter.kt new file mode 100644 index 0000000..1e60acd --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/home/HomeFragmentStateAdapter.kt @@ -0,0 +1,16 @@ +package com.gamedog.vididin.main.fragments.home + + +import androidx.fragment.app.Fragment +import com.ama.core.architecture.appBase.adapter.AppFragmentStateAdapter +import com.gamedog.vididin.beans.YoutubeVideo +import com.gamedog.vididin.main.fragments.home.fragment.HomeItemFragment + + +class HomeFragmentStateAdapter(fragment: Fragment) : + AppFragmentStateAdapter(fragment, true) { + + override fun createFragment(position: Int, item: YoutubeVideo): Fragment { + return HomeItemFragment.newInstance(item.getItemId(), item) + } +} diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/home/OnRepositoryRefreshLoadMoreListeners.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/home/OnRepositoryRefreshLoadMoreListeners.kt new file mode 100644 index 0000000..40110ad --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/home/OnRepositoryRefreshLoadMoreListeners.kt @@ -0,0 +1,14 @@ +package com.gamedog.vididin.main.fragments.home + + +interface OnRepositoryRefreshListener { + + fun refresh(finish: (() -> Unit)? = null) +} + +interface OnRepositoryLoadMoreListener { + + fun load() + + fun loadRetry() +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/home/RefreshRepositoryOwner.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/home/RefreshRepositoryOwner.kt new file mode 100644 index 0000000..016ce83 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/home/RefreshRepositoryOwner.kt @@ -0,0 +1,8 @@ +package com.gamedog.vididin.main.fragments.home + +import com.ama.core.architecture.page.RefreshRepository + + +interface RefreshRepositoryOwner { + fun onRefreshRepository(): RefreshRepository<*> +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeDataSource.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeDataSource.kt new file mode 100644 index 0000000..185333d --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeDataSource.kt @@ -0,0 +1,10 @@ +package com.gamedog.vididin.main.fragments.home + +import com.gamedog.vididin.beans.ResYoutubeChannel +import com.gamedog.vididin.beans.ResYoutubePlayList + + +interface YoutubeDataSource { + suspend fun getChannels(): ResYoutubeChannel + suspend fun getPlayList(): ResYoutubePlayList +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeRepository.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeRepository.kt new file mode 100644 index 0000000..8ab8916 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeRepository.kt @@ -0,0 +1,12 @@ +package com.gamedog.vididin.main.fragments.home + +import com.ama.core.architecture.page.RefreshLoadMoreRepository +import com.gamedog.vididin.beans.ResYoutubeChannel +import com.gamedog.vididin.beans.ResYoutubePlayList +import com.gamedog.vididin.beans.YoutubeVideo + + +interface YoutubeRepository : RefreshLoadMoreRepository { + suspend fun getVideoList(page: Int, size: Int): ResYoutubePlayList + suspend fun getChannelList(page: Int, size: Int): ResYoutubeChannel +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeViewModel.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeViewModel.kt new file mode 100644 index 0000000..4ca6e84 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/home/YoutubeViewModel.kt @@ -0,0 +1,32 @@ +package com.gamedog.vididin.main.fragments.home + + + +import com.ama.core.architecture.appBase.vm.AppViewModel +import com.ama.core.architecture.page.RefreshRepository +import com.gamedog.vididin.beans.YoutubeVideo +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + + +@HiltViewModel +class YoutubeViewModel @Inject constructor( + private val mRepository: YoutubeRepository, +) : AppViewModel(), RefreshRepositoryOwner { + + override val uiStateInitialValue: YoutubeUiState = YoutubeUiState() + override val uiStateFlow: Flow = mRepository.result.map { listData -> + YoutubeUiState(playLists = listData) + } + + override fun onRefreshRepository(): RefreshRepository<*> { + TODO("Not yet implemented") + } +} + +data class YoutubeUiState( + val playLists: List? = null, +) + diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/home/fragment/HomeItemFragment.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/home/fragment/HomeItemFragment.kt new file mode 100644 index 0000000..86e8564 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/home/fragment/HomeItemFragment.kt @@ -0,0 +1,216 @@ +package com.gamedog.vididin.main.fragments.home.fragment + + +import android.os.Bundle +import android.provider.MediaStore.Audio.Playlists.Members.PLAYLIST_ID +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.annotation.NonNull +import com.ama.core.architecture.appBase.AppViewsEmptyViewModelFragment +import com.ama.core.common.widget.PopMenuIconView +import com.gamedog.vididin.R +import com.gamedog.vididin.beans.YoutubeVideo +import com.gamedog.vididin.widget.MyPlayerControlView +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerListener +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.options.IFramePlayerOptions +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView +import kotlin.apply +import kotlin.toString +import com.gamedog.vididin.databinding.VididinappFeatureHomeItemLayoutBinding as ViewBinding + + +class HomeItemFragment : AppViewsEmptyViewModelFragment() { + private var mIsStared = false + private var mPlayer: YouTubePlayer? = null + private var mVideoData: YoutubeVideo? = null + + + override fun inflateViewBinding( + inflater: LayoutInflater, + container: ViewGroup?, + ) = ViewBinding.inflate(inflater, container, false) + + override fun ViewBinding.initViews() { + + tvPlay.setOnClickListener { + mPlayer?.play() + } + + tvPause.setOnClickListener { + mPlayer?.pause() + //mPlayer.seekTo() + mPlayer?.setPlaybackRate(PlayerConstants.PlaybackRate.RATE_2) + } + + + + + + tvVideoFrom.text = "@From-" + arguments?.getLong(KEY_ID).toString() + tvVideoIntro.text = "Introduce-" + arguments?.getLong(KEY_ID).toString() + + popMenu.setMenuList( + mutableListOf( + PopMenuIconView.MenuItem(R.mipmap.home_menu_1) { + + }, + PopMenuIconView.MenuItem(R.mipmap.home_menu_2) { + + }, + PopMenuIconView.MenuItem(R.mipmap.home_menu_3) { + + }, + PopMenuIconView.MenuItem(R.mipmap.home_menu_4) { + + } + )) + + lifecycle.addObserver(youtubePlayerView) + youtubePlayerView.enableBackgroundPlayback(false) + youtubePlayerView.enableAutomaticInitialization = false + } + + fun initAndStartPlay() { + val youtubePlayerView: YouTubePlayerView = binding?.youtubePlayerView!! + + val iFramePlayerOptions = IFramePlayerOptions.Builder(requireContext()) + .rel(1) + .ccLoadPolicy(1) + .controls(0) + .listType("playlist") + .list(PLAYLIST_ID) + .fullscreen(0) + .build() + youtubePlayerView.initialize(object : YouTubePlayerListener { + override fun onReady(youTubePlayer: YouTubePlayer) { + + } + + override fun onStateChange( + youTubePlayer: YouTubePlayer, + state: PlayerConstants.PlayerState + ) { + + } + + override fun onPlaybackQualityChange( + youTubePlayer: YouTubePlayer, + playbackQuality: PlayerConstants.PlaybackQuality + ) { + + } + + override fun onPlaybackRateChange( + youTubePlayer: YouTubePlayer, + playbackRate: PlayerConstants.PlaybackRate + ) { + + } + + override fun onError( + youTubePlayer: YouTubePlayer, + error: PlayerConstants.PlayerError + ) { + + } + + override fun onCurrentSecond( + youTubePlayer: YouTubePlayer, + second: Float + ) { + + } + + override fun onVideoDuration( + youTubePlayer: YouTubePlayer, + duration: Float + ) { + + } + + override fun onVideoLoadedFraction( + youTubePlayer: YouTubePlayer, + loadedFraction: Float + ) { + + } + + override fun onVideoId( + youTubePlayer: YouTubePlayer, + videoId: String + ) { + + } + + override fun onApiChange(youTubePlayer: YouTubePlayer) { + + } + + + }, iFramePlayerOptions) + + + + youtubePlayerView.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() { + + override fun onReady(@NonNull youTubePlayer: YouTubePlayer) { + mPlayer = youTubePlayer + + //val playerUiController = DefaultPlayerUiController(youtubePlayerView, youTubePlayer) + val playerUiController = MyPlayerControlView(youtubePlayerView, youTubePlayer) + youtubePlayerView.setCustomPlayerUi(playerUiController.rootView) + + if (mVideoData != null && !mVideoData?.id.isNullOrEmpty()) { + youTubePlayer.loadVideo(mVideoData!!.id, 0f) + } + } + + override fun onStateChange( + youTubePlayer: YouTubePlayer, + state: PlayerConstants.PlayerState + ) { + when (state) { + PlayerConstants.PlayerState.UNKNOWN -> { } + PlayerConstants.PlayerState.UNSTARTED -> { } + PlayerConstants.PlayerState.ENDED -> { } + PlayerConstants.PlayerState.PLAYING -> { } + PlayerConstants.PlayerState.PAUSED -> { } + PlayerConstants.PlayerState.BUFFERING -> { } + PlayerConstants.PlayerState.VIDEO_CUED -> { } + } + } + }) + } + + override fun ViewBinding.initListeners() { + ivStar.setOnClickListener { + mIsStared = !mIsStared + ivStar.setImageResource(if (mIsStared) R.mipmap.home_star else R.mipmap.home_star_undo) + } + + } + + override fun ViewBinding.initObservers() { + try { + initAndStartPlay() + } catch (e: Exception) { + e.printStackTrace() + } + } + + + + + companion object { + private const val KEY_ID = "id" + internal fun newInstance(id: Long, videoData: YoutubeVideo) = HomeItemFragment().apply { + mVideoData = videoData + arguments = Bundle().apply { + putLong(KEY_ID, id) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/fragments/mine/MineViewModel.kt b/app/src/main/java/com/gamedog/vididin/main/fragments/mine/MineViewModel.kt new file mode 100644 index 0000000..15c6381 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/fragments/mine/MineViewModel.kt @@ -0,0 +1,33 @@ +package com.gamedog.vididin.main.fragments.mine + +import androidx.lifecycle.viewModelScope +import com.ama.core.architecture.appBase.vm.AppViewModel +import com.gamedog.vididin.core.datastore.AppPreferencesDataSource +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.launch +import javax.inject.Inject +import com.gamedog.vididin.main.fragments.mine.MineUiState as UiState + + +@HiltViewModel +class MineViewModel @Inject constructor( + private val preferencesDataSource: AppPreferencesDataSource, +) : AppViewModel() { + override val uiStateInitialValue: UiState = UiState() + + override val uiStateFlow: Flow = flowOf() + fun updateDynamicColorPreference(useDynamicColor: Boolean, finish: () -> Unit) { + if (useDynamicColor == uiState.value.useDynamicColor) return + viewModelScope.launch { + delay(250) + finish() + } + } +} + +data class MineUiState( + val useDynamicColor: Boolean = false, +) \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/interfaces/OnSwitchTabListener.kt b/app/src/main/java/com/gamedog/vididin/main/interfaces/OnSwitchTabListener.kt new file mode 100644 index 0000000..6257f2d --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/interfaces/OnSwitchTabListener.kt @@ -0,0 +1,6 @@ +package com.gamedog.vididin.main.interfaces + + +interface OnSwitchTabListener { + fun onSwitchTab(index: Int, smoothScroll: Boolean = false) +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/interfaces/OnTabClickAgainListener.kt b/app/src/main/java/com/gamedog/vididin/main/interfaces/OnTabClickAgainListener.kt new file mode 100644 index 0000000..c071bbf --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/interfaces/OnTabClickAgainListener.kt @@ -0,0 +1,17 @@ +package com.gamedog.vididin.main.interfaces + + + +interface OnTabClickRefreshListener { + fun onTabClickRefresh(listener: OnTabClickRefreshFinishListener) +} + +interface OnTabClickRefreshFinishListener { + fun onTabClickRefreshFinish() +} + + +@Suppress("EmptyMethod") +interface OnTabClickAgainListener { + fun onTabClickAgain() +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/main/interfaces/OnTabStyleListener.kt b/app/src/main/java/com/gamedog/vididin/main/interfaces/OnTabStyleListener.kt new file mode 100644 index 0000000..4b1fbb2 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/main/interfaces/OnTabStyleListener.kt @@ -0,0 +1,6 @@ +package com.gamedog.vididin.main.interfaces + + +interface OnTabStyleListener { + fun onTabIsDarkFont(isDarkFont: Boolean) +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/repository/DefaultMainRepository.kt b/app/src/main/java/com/gamedog/vididin/repository/DefaultMainRepository.kt new file mode 100644 index 0000000..86f7d0e --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/repository/DefaultMainRepository.kt @@ -0,0 +1,25 @@ +package com.gamedog.vididin.repository + + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import javax.inject.Inject + + +class DefaultMainRepository @Inject constructor( +) : MainRepository { + + override fun getMainTabsStream(): Flow> { + return flowOf(listOf(MainTabType.HOME, MainTabType.TASKS, MainTabType.MINE)) + } + + private suspend fun setDefaultMainTabs() { + val arrayListOf = arrayListOf( + MainTabType.HOME, + MainTabType.TASKS, + MainTabType.MINE + ) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/repository/MainRepository.kt b/app/src/main/java/com/gamedog/vididin/repository/MainRepository.kt new file mode 100644 index 0000000..9474e1f --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/repository/MainRepository.kt @@ -0,0 +1,14 @@ +package com.gamedog.vididin.repository + +import kotlinx.coroutines.flow.Flow + + +interface MainRepository { + fun getMainTabsStream(): Flow> +} + +enum class MainTabType { + HOME, + TASKS, + MINE, +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/router/DefaultHomeRouter.kt b/app/src/main/java/com/gamedog/vididin/router/DefaultHomeRouter.kt new file mode 100644 index 0000000..e05de53 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/router/DefaultHomeRouter.kt @@ -0,0 +1,10 @@ +package com.gamedog.vididin.router + +import androidx.fragment.app.Fragment +import com.gamedog.vididin.core.router.interfaces.HomeRouter +import com.gamedog.vididin.main.fragments.HomeFragment + + +class DefaultHomeRouter : HomeRouter { + override fun createHomeFragment(): Fragment = HomeFragment.newInstance() +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/router/DefaultLoginRouter.kt b/app/src/main/java/com/gamedog/vididin/router/DefaultLoginRouter.kt new file mode 100644 index 0000000..9a284a5 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/router/DefaultLoginRouter.kt @@ -0,0 +1,12 @@ +package com.gamedog.vididin.router + +import android.app.Activity +import com.gamedog.vididin.core.router.interfaces.LoginRouter +import com.gamedog.vididin.login.LoginActivity + + +class DefaultLoginRouter : LoginRouter { + override fun startLoginActivity(activity: Activity) { + LoginActivity.startActivity(activity) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/router/DefaultMineRouter.kt b/app/src/main/java/com/gamedog/vididin/router/DefaultMineRouter.kt new file mode 100644 index 0000000..65a94d7 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/router/DefaultMineRouter.kt @@ -0,0 +1,11 @@ +package com.gamedog.vididin.router + +import androidx.fragment.app.Fragment +import com.gamedog.vididin.core.router.interfaces.MineRouter +import com.gamedog.vididin.main.fragments.MineFragment + + + +class DefaultMineRouter : MineRouter { + override fun createMineFragment(): Fragment = MineFragment.newInstance() +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/router/DefaultTaskRouter.kt b/app/src/main/java/com/gamedog/vididin/router/DefaultTaskRouter.kt new file mode 100644 index 0000000..b6e487d --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/router/DefaultTaskRouter.kt @@ -0,0 +1,11 @@ +package com.gamedog.vididin.router + +import androidx.fragment.app.Fragment +import com.gamedog.vididin.core.router.interfaces.TaskRouter +import com.gamedog.vididin.main.fragments.TasksFragment + + + +class DefaultTaskRouter : TaskRouter { + override fun createTaskFragment(): Fragment = TasksFragment.newInstance() +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/router/HomeRouter.kt b/app/src/main/java/com/gamedog/vididin/router/HomeRouter.kt new file mode 100644 index 0000000..81d9d5a --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/router/HomeRouter.kt @@ -0,0 +1,7 @@ +package com.gamedog.vididin.core.router.interfaces + +import androidx.fragment.app.Fragment + +interface HomeRouter { + fun createHomeFragment(): Fragment +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/router/LoginRouter.kt b/app/src/main/java/com/gamedog/vididin/router/LoginRouter.kt new file mode 100644 index 0000000..eba1039 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/router/LoginRouter.kt @@ -0,0 +1,7 @@ +package com.gamedog.vididin.core.router.interfaces + +import android.app.Activity + +interface LoginRouter { + fun startLoginActivity(activity: Activity) +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/router/MineRouter.kt b/app/src/main/java/com/gamedog/vididin/router/MineRouter.kt new file mode 100644 index 0000000..700c843 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/router/MineRouter.kt @@ -0,0 +1,7 @@ +package com.gamedog.vididin.core.router.interfaces + +import androidx.fragment.app.Fragment + +interface MineRouter { + fun createMineFragment(): Fragment +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/router/Router.kt b/app/src/main/java/com/gamedog/vididin/router/Router.kt new file mode 100644 index 0000000..249cc54 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/router/Router.kt @@ -0,0 +1,27 @@ +package com.gamedog.vididin.router + +import android.content.Context +import com.gamedog.vididin.core.router.interfaces.HomeRouter +import com.gamedog.vididin.core.router.interfaces.LoginRouter +import com.gamedog.vididin.core.router.interfaces.MineRouter +import com.gamedog.vididin.core.router.interfaces.TaskRouter +import com.gamedog.vididin.di.RouterEntryPoint +import dagger.hilt.android.EntryPointAccessors +import kotlin.getValue +import kotlin.jvm.java + + +object Router : RouterContract { + private lateinit var routerEntryPoint: RouterEntryPoint + + fun init(context: Context) { + routerEntryPoint = EntryPointAccessors.fromApplication(context, RouterEntryPoint::class.java) + } + + override val Home: HomeRouter by lazy { routerEntryPoint.homeRouter() } + override val Task: TaskRouter by lazy { routerEntryPoint.taskRouter() } + override val Mine: MineRouter by lazy { routerEntryPoint.mineRouter() } + override val Login: LoginRouter by lazy { routerEntryPoint.loginRouter() } + +} + diff --git a/app/src/main/java/com/gamedog/vididin/router/RouterContract.kt b/app/src/main/java/com/gamedog/vididin/router/RouterContract.kt new file mode 100644 index 0000000..faba990 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/router/RouterContract.kt @@ -0,0 +1,15 @@ +package com.gamedog.vididin.router + +import com.gamedog.vididin.core.router.interfaces.HomeRouter +import com.gamedog.vididin.core.router.interfaces.LoginRouter +import com.gamedog.vididin.core.router.interfaces.TaskRouter +import com.gamedog.vididin.core.router.interfaces.MineRouter + + +@Suppress("PropertyName") +interface RouterContract { + val Home: HomeRouter + val Task: TaskRouter + val Mine: MineRouter + val Login: LoginRouter +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/router/RouterInitializer.kt b/app/src/main/java/com/gamedog/vididin/router/RouterInitializer.kt new file mode 100644 index 0000000..4a774c9 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/router/RouterInitializer.kt @@ -0,0 +1,15 @@ +package com.gamedog.vididin.router + +import android.content.Context +import androidx.startup.Initializer + + +class RouterInitializer : Initializer { + override fun create(context: Context) { + Router.init(context) + } + + override fun dependencies(): MutableList>> { + return mutableListOf() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/router/TaskRouter.kt b/app/src/main/java/com/gamedog/vididin/router/TaskRouter.kt new file mode 100644 index 0000000..5e3d62c --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/router/TaskRouter.kt @@ -0,0 +1,8 @@ +package com.gamedog.vididin.core.router.interfaces + +import androidx.fragment.app.Fragment + + +interface TaskRouter { + fun createTaskFragment(): Fragment +} \ No newline at end of file diff --git a/app/src/main/java/com/gamedog/vididin/sp/AppPreferencesDataSource.kt b/app/src/main/java/com/gamedog/vididin/sp/AppPreferencesDataSource.kt new file mode 100644 index 0000000..14c1825 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/sp/AppPreferencesDataSource.kt @@ -0,0 +1,11 @@ +package com.gamedog.vididin.core.datastore + + +import javax.inject.Inject + + +class AppPreferencesDataSource @Inject constructor( +) { + +} + diff --git a/app/src/main/java/com/gamedog/vididin/sp/UserPreferencesSerializer.kt b/app/src/main/java/com/gamedog/vididin/sp/UserPreferencesSerializer.kt new file mode 100644 index 0000000..94c662a --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/sp/UserPreferencesSerializer.kt @@ -0,0 +1,10 @@ +package com.gamedog.vididin.core.datastore + +import javax.inject.Inject + + +class UserPreferencesSerializer @Inject constructor() { + +} + + diff --git a/app/src/main/java/com/gamedog/vididin/sp/datastore/user.proto b/app/src/main/java/com/gamedog/vididin/sp/datastore/user.proto new file mode 100644 index 0000000..11f01a1 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/sp/datastore/user.proto @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto3"; +option java_package = "com.gamedog.vididin.sp.datastore"; +option java_multiple_files = true; + +message User { + int32 id = 1; + string token = 2; + string account = 3; + string createdAt = 4; +} diff --git a/app/src/main/java/com/gamedog/vididin/sp/datastore/user_preferences.proto b/app/src/main/java/com/gamedog/vididin/sp/datastore/user_preferences.proto new file mode 100644 index 0000000..7108fbc --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/sp/datastore/user_preferences.proto @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto3"; +import "com/gamedog/vididin/sp/datastore/user.proto"; + +option java_package = "com.gamedog.vididin.sp.datastore"; +option java_multiple_files = true; + +message UserPreferences { + // User,user。 + User user = 1; + // List,主页Tabs。 + repeated int32 main_tabs = 2; + // List,首页Tabs。 + repeated int32 home_tabs = 3; + // boolean,是否用动态颜色,UseDynamicColor。 + bool use_dynamic_color = 4; +} diff --git a/app/src/main/java/com/gamedog/vididin/widget/HomeDragIconView.kt b/app/src/main/java/com/gamedog/vididin/widget/HomeDragIconView.kt new file mode 100644 index 0000000..93c42a8 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/widget/HomeDragIconView.kt @@ -0,0 +1,30 @@ +package com.gamedog.vididin.widget + + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.LinearLayout +import com.gamedog.vididin.databinding.LayoutDragIconViewBinding +import kotlin.run + +class HomeDragIconView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + private var mBinding: LayoutDragIconViewBinding? = null + + + init { + mBinding = LayoutDragIconViewBinding.inflate(LayoutInflater.from(context), this, true) + mBinding?.run { + + } + } + +} + + + diff --git a/app/src/main/java/com/gamedog/vididin/widget/MyPlayerControlView.kt b/app/src/main/java/com/gamedog/vididin/widget/MyPlayerControlView.kt new file mode 100644 index 0000000..73a80c0 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/widget/MyPlayerControlView.kt @@ -0,0 +1,294 @@ +package com.gamedog.vididin.widget + + +import android.content.Intent +import android.graphics.drawable.Drawable +import android.net.Uri +import android.util.Log +import android.view.View +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.ProgressBar +import android.widget.TextView +import androidx.core.content.ContextCompat +import com.gamedog.vididin.R +import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.PlayerUiController +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView +import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.menu.YouTubePlayerMenu +import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.utils.FadeViewHelper +import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.views.YouTubePlayerSeekBar +import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.views.YouTubePlayerSeekBarListener +import kotlin.jvm.javaClass + + +class MyPlayerControlView( + private val youTubePlayerView: YouTubePlayerView, + private val youTubePlayer: YouTubePlayer +) : PlayerUiController { + + val rootView: View = View.inflate(youTubePlayerView.context, R.layout.layout_player_controller, null) + + private var youTubePlayerMenu: YouTubePlayerMenu = MyPlayerMenu( + youTubePlayerView.context + ) + + /** + * View used for for intercepting clicks and for drawing a black background. + * Could have used controlsContainer, but in this way I'm able to hide all the control at once by hiding controlsContainer + */ + private val panel: View = rootView.findViewById(R.id.panel) + + private val controlsContainer: View = rootView.findViewById(R.id.controls_container) + private val extraViewsContainer: LinearLayout = rootView.findViewById(R.id.extra_views_container) + + private val videoTitle: TextView = rootView.findViewById(R.id.video_title) + private val liveVideoIndicator: TextView = rootView.findViewById(R.id.live_video_indicator) + + private val progressBar: ProgressBar = rootView.findViewById(R.id.progress) + private val menuButton: ImageView = rootView.findViewById(R.id.menu_button) + private val playPauseButton: ImageView = rootView.findViewById(R.id.play_pause_button) + private val youTubeButton: ImageView = rootView.findViewById(R.id.youtube_button) + private val fullscreenButton: ImageView = rootView.findViewById(R.id.fullscreen_button) + + private val customActionLeft: ImageView = rootView.findViewById(R.id.custom_action_left_button) + private val customActionRight: ImageView = rootView.findViewById(R.id.custom_action_right_button) + + private val youtubePlayerSeekBar: YouTubePlayerSeekBar = rootView.findViewById(R.id.youtube_player_seekbar) + private val fadeControlsContainer: FadeViewHelper = FadeViewHelper(controlsContainer) + + private var onFullscreenButtonListener: View.OnClickListener + private var onMenuButtonClickListener: View.OnClickListener + + private var isPlaying = false + private var isPlayPauseButtonEnabled = true + private var isCustomActionLeftEnabled = false + private var isCustomActionRightEnabled = false + + private var isMatchParent = false + + private val youTubePlayerStateListener = object : AbstractYouTubePlayerListener() { + override fun onStateChange(youTubePlayer: YouTubePlayer, state: PlayerConstants.PlayerState) { + updateState(state) + + if (state === PlayerConstants.PlayerState.PLAYING || state === PlayerConstants.PlayerState.PAUSED || state === PlayerConstants.PlayerState.VIDEO_CUED) { + panel.setBackgroundColor(ContextCompat.getColor(panel.context, R.color.transparent)) + progressBar.visibility = View.GONE + + if (isPlayPauseButtonEnabled) playPauseButton.visibility = View.VISIBLE + if (isCustomActionLeftEnabled) customActionLeft.visibility = View.VISIBLE + if (isCustomActionRightEnabled) customActionRight.visibility = View.VISIBLE + + updatePlayPauseButtonIcon(state === PlayerConstants.PlayerState.PLAYING) + + } else { + updatePlayPauseButtonIcon(false) + + if (state === PlayerConstants.PlayerState.BUFFERING) { + progressBar.visibility = View.VISIBLE + panel.setBackgroundColor( + ContextCompat.getColor( + panel.context, + R.color.transparent + ) + ) + if (isPlayPauseButtonEnabled) playPauseButton.visibility = View.INVISIBLE + + customActionLeft.visibility = View.GONE + customActionRight.visibility = View.GONE + } + + if (state === PlayerConstants.PlayerState.UNSTARTED) { + progressBar.visibility = View.GONE + if (isPlayPauseButtonEnabled) playPauseButton.visibility = View.VISIBLE + } + } + } + + override fun onVideoId(youTubePlayer: YouTubePlayer, videoId: String) { + youTubeButton.setOnClickListener { + val intent = Intent( + Intent.ACTION_VIEW, + Uri.parse("https://www.youtube.com/watch?v=" + videoId + "#t=" + youtubePlayerSeekBar.seekBar.progress) + ) + try { + youTubeButton.context.startActivity(intent) + } catch (e: Exception) { + Log.e(javaClass.simpleName, e.message ?: "Can't open url to YouTube") + } + } + } + } + + init { + onFullscreenButtonListener = View.OnClickListener { + isMatchParent = !isMatchParent + when (isMatchParent) { + true -> youTubePlayerView.matchParent() + false -> youTubePlayerView.wrapContent() + } + } + + onMenuButtonClickListener = View.OnClickListener { youTubePlayerMenu.show(menuButton) } + + initClickListeners() + } + + private fun initClickListeners() { + youTubePlayer.addListener(youtubePlayerSeekBar) + youTubePlayer.addListener(fadeControlsContainer) + youTubePlayer.addListener(youTubePlayerStateListener) + + youtubePlayerSeekBar.youtubePlayerSeekBarListener = object : YouTubePlayerSeekBarListener { + override fun seekTo(time: Float) = youTubePlayer.seekTo(time) + } + panel.setOnClickListener { fadeControlsContainer.toggleVisibility() } + playPauseButton.setOnClickListener { onPlayButtonPressed() } + fullscreenButton.setOnClickListener { onFullscreenButtonListener.onClick(fullscreenButton) } + menuButton.setOnClickListener { onMenuButtonClickListener.onClick(menuButton) } + } + + override fun showVideoTitle(show: Boolean): PlayerUiController { + videoTitle.visibility = if (show) View.VISIBLE else View.GONE + return this + } + + override fun setVideoTitle(videoTitle: String): PlayerUiController { + this.videoTitle.text = videoTitle + return this + } + + override fun showUi(show: Boolean): PlayerUiController { + fadeControlsContainer.isDisabled = !show + controlsContainer.visibility = if (show) View.VISIBLE else View.INVISIBLE + return this + } + + override fun showPlayPauseButton(show: Boolean): PlayerUiController { + playPauseButton.visibility = if (show) View.VISIBLE else View.GONE + + isPlayPauseButtonEnabled = show + return this + } + + override fun enableLiveVideoUi(enable: Boolean): PlayerUiController { + youtubePlayerSeekBar.visibility = if (enable) View.INVISIBLE else View.VISIBLE + liveVideoIndicator.visibility = if (enable) View.VISIBLE else View.GONE + return this + } + + override fun setCustomAction1( + icon: Drawable, + clickListener: View.OnClickListener? + ): PlayerUiController { + customActionLeft.setImageDrawable(icon) + customActionLeft.setOnClickListener(clickListener) + showCustomAction1(true) + return this + } + + override fun setCustomAction2( + icon: Drawable, + clickListener: View.OnClickListener? + ): PlayerUiController { + customActionRight.setImageDrawable(icon) + customActionRight.setOnClickListener(clickListener) + showCustomAction2(true) + return this + } + + override fun showCustomAction1(show: Boolean): PlayerUiController { + isCustomActionLeftEnabled = show + customActionLeft.visibility = if (show) View.VISIBLE else View.GONE + return this + } + + override fun showCustomAction2(show: Boolean): PlayerUiController { + isCustomActionRightEnabled = show + customActionRight.visibility = if (show) View.VISIBLE else View.GONE + return this + } + + override fun showMenuButton(show: Boolean): PlayerUiController { + menuButton.visibility = if (show) View.VISIBLE else View.GONE + return this + } + + override fun setMenuButtonClickListener(customMenuButtonClickListener: View.OnClickListener): PlayerUiController { + onMenuButtonClickListener = customMenuButtonClickListener + return this + } + + override fun showCurrentTime(show: Boolean): PlayerUiController { + youtubePlayerSeekBar.videoCurrentTimeTextView.visibility = if (show) View.VISIBLE else View.GONE + return this + } + + override fun showDuration(show: Boolean): PlayerUiController { + youtubePlayerSeekBar.videoDurationTextView.visibility = if (show) View.VISIBLE else View.GONE + return this + } + + override fun showSeekBar(show: Boolean): PlayerUiController { + youtubePlayerSeekBar.seekBar.visibility = if (show) View.VISIBLE else View.INVISIBLE + return this + } + + override fun showBufferingProgress(show: Boolean): PlayerUiController { + youtubePlayerSeekBar.showBufferingProgress = show + return this + } + + override fun showYouTubeButton(show: Boolean): PlayerUiController { + youTubeButton.visibility = if (show) View.VISIBLE else View.GONE + return this + } + + override fun addView(view: View): PlayerUiController { + extraViewsContainer.addView(view, 0) + return this + } + + override fun removeView(view: View): PlayerUiController { + extraViewsContainer.removeView(view) + return this + } + + override fun getMenu(): YouTubePlayerMenu = youTubePlayerMenu + + override fun showFullscreenButton(show: Boolean): PlayerUiController { + fullscreenButton.visibility = if (show) View.VISIBLE else View.GONE + return this + } + + override fun setFullscreenButtonClickListener(customFullscreenButtonClickListener: View.OnClickListener): PlayerUiController { + onFullscreenButtonListener = customFullscreenButtonClickListener + return this + } + + private fun onPlayButtonPressed() { + if (isPlaying) + youTubePlayer.pause() + else + youTubePlayer.play() + } + + private fun updateState(state: PlayerConstants.PlayerState) { + when (state) { + PlayerConstants.PlayerState.ENDED -> isPlaying = false + PlayerConstants.PlayerState.PAUSED -> isPlaying = false + PlayerConstants.PlayerState.PLAYING -> isPlaying = true + else -> {} + } + + updatePlayPauseButtonIcon(!isPlaying) + } + + private fun updatePlayPauseButtonIcon(playing: Boolean) { + /*val drawable = if (playing) R.drawable.ayp_ic_pause_36dp else R.drawable.ayp_ic_play_36dp + playPauseButton.setImageResource(drawable)*/ + } +} + diff --git a/app/src/main/java/com/gamedog/vididin/widget/MyPlayerMenu.kt b/app/src/main/java/com/gamedog/vididin/widget/MyPlayerMenu.kt new file mode 100644 index 0000000..23003d1 --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/widget/MyPlayerMenu.kt @@ -0,0 +1,67 @@ +package com.gamedog.vididin.widget + + +import android.content.Context +import android.util.Log +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import android.widget.FrameLayout +import android.widget.PopupWindow +import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.R +import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.menu.MenuItem +import com.pierfrancescosoffritti.androidyoutubeplayer.core.customui.menu.YouTubePlayerMenu +import kotlin.jvm.java + + +internal class MyPlayerMenu(private val context: Context) : YouTubePlayerMenu { + private val menuItems = kotlin.collections.ArrayList() + private var popupWindow: PopupWindow? = null + + override val itemCount: Int + get() = menuItems.size + + override fun show(anchorView: View) { + popupWindow = createPopupWindow() + popupWindow?.showAsDropDown( + anchorView, + -context.resources.getDimensionPixelSize(R.dimen.ayp_8dp) * 12, + -context.resources.getDimensionPixelSize(R.dimen.ayp_8dp) * 12 + ) + + if (menuItems.size == 0) + Log.e(YouTubePlayerMenu::class.java.name, "The menu is empty") + } + + override fun dismiss() { + popupWindow?.dismiss() + } + + override fun addItem(menuItem: MenuItem): YouTubePlayerMenu { + menuItems.add(menuItem) + return this + } + + override fun removeItem(itemIndex: Int): YouTubePlayerMenu { + menuItems.removeAt(itemIndex) + return this + } + + override fun removeItem(menuItem: MenuItem): YouTubePlayerMenu { + menuItems.remove(menuItem) + return this + } + + private fun createPopupWindow(): PopupWindow { + val view = FrameLayout(context) + val popupWindow = PopupWindow( + view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT + ) + popupWindow.contentView = view + popupWindow.isFocusable = true + popupWindow.width = WindowManager.LayoutParams.WRAP_CONTENT + popupWindow.height = WindowManager.LayoutParams.WRAP_CONTENT + + return popupWindow + } +} diff --git a/app/src/main/java/com/gamedog/vididin/widget/YTParams.java b/app/src/main/java/com/gamedog/vididin/widget/YTParams.java new file mode 100644 index 0000000..8897dcf --- /dev/null +++ b/app/src/main/java/com/gamedog/vididin/widget/YTParams.java @@ -0,0 +1,125 @@ +package com.gamedog.vididin.widget; + + +public class YTParams { + /** + * 0或1。默认值为0。用于设置初始视频是否在加载播放器时自动播放。 + */ + private int autoplay = 0; + /** + * 2(默认值)、1和0。此参数会指明视频控件是否会在视频开始播放之后自动隐藏。默认行为(autohide=2)表示,当播放器控件(播放按钮和音量控件等)处于可见状态时,视频进度条将淡出。 + 如果将此参数设为1,则视频进度条和播放器控件将会在视频开始播放几秒钟后退出播放界面。仅在用户将鼠标移动到视频播放器上方或按键盘上的某个键时,进度条和控件才会重新显示。 + 如果将此参数设为0,则视频进度条和视频播放器控件在视频播放全程和全屏状态下均会显示。 + */ + private int autohide = 1; + /** + * 0或1。默认值为1。此参数将表明初始视频播放结束时,播放器是否应显示相关视频。 + */ + private int rel = 0; + /** + * 0或1。此参数的默认值为1。如果您将此参数的值设为0,则在视频开始播放之前,播放器不会显示视频标题和上传者等信息。 + */ + private int showinfo = 1; + /** + * 0或1。默认值为0。将此值设为1将会停用Javascript API. + */ + private int enablejsapi = 0; + /** + * 0或1。默认值为0。将此值设为1将会停用播放器键盘控件。键盘控件如下: + 空格键:播放/暂停 + 向左箭头:当前视频后退10% + 向右箭头:当前视频前进10% + 向上箭头:调高音量 + 向下箭头:降低音量 + */ + private int disablekb = 1; + /** + * 0、1或2。默认值为1。此参数会指明视频播放器控件是否会显示。对于加载Flash播放器的iframe嵌入, + * 此参数还会定义控件何时在播放器中显示,以及播放器加载时间: + controls=0 - 播放器控件不会在播放器中显示。对于iframe嵌入,Flash播放器会立即加载。 + controls=1 - 播放器控件会在播放器中显示。对于iframe嵌入,控件会立即显示,而且Flash播放器也会立即加载。 + controls=2 - 播放器控件会在播放器中显示。对于iframe嵌入,控件会显示,而且Flash播放器会在用户启动视频播放时加载。 + 注意:参数值1和2用于提供一致的用户体验,但是,对于iframe嵌入而言,controls=2提供的性能较之controls=1已得到改进。 + 目前,这两个参数值仍会在播放器中产生一些视觉方面的差异(例如,视频标题的字体大小)。 + 但是,当两个参数值之间的差异对用户而言变得完全透明时,默认参数值可能会从1更改为2。 + */ + private int controls = 1; + /** + * 0或1。默认值为1,该值会使全屏按钮显示。将此参数设为0会阻止全屏按钮显示。 + */ + private int fs = 1; + + private String cc_lang_pref = "en"; + + public int getFs() { + return fs; + } + + public void setFs(int fs) { + this.fs = fs; + } + + public int getAutoplay() { + return autoplay; + } + + public void setAutoplay(int autoplay) { + this.autoplay = autoplay; + } + + public int getAutohide() { + return autohide; + } + + public void setAutohide(int autohide) { + this.autohide = autohide; + } + + public int getRel() { + return rel; + } + + public void setRel(int rel) { + this.rel = rel; + } + + public int getShowinfo() { + return showinfo; + } + + public void setShowinfo(int showinfo) { + this.showinfo = showinfo; + } + + public int getEnablejsapi() { + return enablejsapi; + } + + public void setEnablejsapi(int enablejsapi) { + this.enablejsapi = enablejsapi; + } + + public int getDisablekb() { + return disablekb; + } + + public void setDisablekb(int disablekb) { + this.disablekb = disablekb; + } + + public String getCc_lang_pref() { + return cc_lang_pref; + } + + public void setCc_lang_pref(String cc_lang_pref) { + this.cc_lang_pref = cc_lang_pref; + } + + public int getControls() { + return controls; + } + + public void setControls(int controls) { + this.controls = controls; + } +} diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/vididinapp_feature_message_bg_task_activity.xml b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_activity.xml new file mode 100644 index 0000000..2420857 --- /dev/null +++ b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_activity.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/app/src/main/res/drawable/vididinapp_feature_message_bg_task_ativi.xml b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_ativi.xml new file mode 100644 index 0000000..6c342ea --- /dev/null +++ b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_ativi.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/app/src/main/res/drawable/vididinapp_feature_message_bg_task_cash.xml b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_cash.xml new file mode 100644 index 0000000..096053e --- /dev/null +++ b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_cash.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/app/src/main/res/drawable/vididinapp_feature_message_bg_task_coin.xml b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_coin.xml new file mode 100644 index 0000000..ae5a162 --- /dev/null +++ b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_coin.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/app/src/main/res/drawable/vididinapp_feature_message_bg_task_fazer.xml b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_fazer.xml new file mode 100644 index 0000000..3670d5c --- /dev/null +++ b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_fazer.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/app/src/main/res/drawable/vididinapp_feature_message_bg_task_inici.xml b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_inici.xml new file mode 100644 index 0000000..e333eb6 --- /dev/null +++ b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_inici.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/app/src/main/res/drawable/vididinapp_feature_message_bg_task_login.xml b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_login.xml new file mode 100644 index 0000000..0e237ac --- /dev/null +++ b/app/src/main/res/drawable/vididinapp_feature_message_bg_task_login.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/app/src/main/res/drawable/vididinapp_feature_mine_bg_top.xml b/app/src/main/res/drawable/vididinapp_feature_mine_bg_top.xml new file mode 100644 index 0000000..90d49ec --- /dev/null +++ b/app/src/main/res/drawable/vididinapp_feature_mine_bg_top.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/src/main/res/drawable/vididinapp_feature_mine_option_bg.xml b/app/src/main/res/drawable/vididinapp_feature_mine_option_bg.xml new file mode 100644 index 0000000..881f0d3 --- /dev/null +++ b/app/src/main/res/drawable/vididinapp_feature_mine_option_bg.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..a761f4e --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,29 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_activity_main_tab.xml b/app/src/main/res/layout/item_activity_main_tab.xml new file mode 100644 index 0000000..6ba08d8 --- /dev/null +++ b/app/src/main/res/layout/item_activity_main_tab.xml @@ -0,0 +1,24 @@ + + + + + +