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