Просмотр исходного кода

theme dynamic & payments preimplementation

Milan Jurkulak 3 лет назад
Родитель
Сommit
09a1caf4d1

+ 20 - 0
app/debug/output-metadata.json

@@ -0,0 +1,20 @@
+{
+  "version": 3,
+  "artifactType": {
+    "type": "APK",
+    "kind": "Directory"
+  },
+  "applicationId": "org.mjdev.tvapp.debug",
+  "variantName": "debug",
+  "elements": [
+    {
+      "type": "SINGLE",
+      "filters": [],
+      "attributes": [],
+      "versionCode": 10100,
+      "versionName": "1.1.0",
+      "outputFile": "app-debug.apk"
+    }
+  ],
+  "elementType": "File"
+}

+ 4 - 0
app/src/main/AndroidManifest.xml

@@ -57,6 +57,10 @@
         android:usesCleartextTraffic="true"
         tools:ignore="UnusedAttribute">
 
+        <meta-data
+            android:name="com.google.android.gms.wallet.api.enabled"
+            android:value="true" />
+
         <activity
             android:name=".activity.MainActivity"
             android:clearTaskOnLaunch="true"

+ 9 - 5
tvlib/build.gradle.kts

@@ -112,16 +112,16 @@ dependencies {
     // compose base libs
     implementation(platform("androidx.compose:compose-bom:2023.09.01"))
     implementation("androidx.compose.ui:ui-tooling")
-    implementation("androidx.activity:activity-compose:1.7.2")
+    implementation("androidx.activity:activity-compose:1.8.0")
     // more icons
-    implementation("androidx.compose.material:material-icons-extended:1.5.2")
+    implementation("androidx.compose.material:material-icons-extended:1.5.3")
     // tv compose
     implementation("androidx.tv:tv-foundation:1.0.0-alpha09")
     implementation("androidx.tv:tv-material:1.0.0-alpha09")
     // view model
     implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
     // navigation
-    implementation("androidx.navigation:navigation-compose:2.7.3")
+    implementation("androidx.navigation:navigation-compose:2.7.4")
     // okhttp
     implementation(platform("com.squareup.okhttp3:okhttp-bom:5.0.0-alpha.11"))
     implementation("com.squareup.okhttp3:okhttp")
@@ -155,7 +155,7 @@ dependencies {
     kapt("com.google.dagger:dagger-android-processor:2.48")
     // dagger - hilt
     implementation("com.google.dagger:hilt-android:2.48")
-    implementation("androidx.hilt:hilt-navigation-compose:1.1.0-alpha01")
+    implementation("androidx.hilt:hilt-navigation-compose:1.1.0-beta01")
     kapt("com.google.dagger:hilt-compiler:2.48")
     // encrypt data
     implementation("com.scottyab:aescrypt:0.0.1")
@@ -196,7 +196,11 @@ dependencies {
     // dm
     implementation("com.dailymotion.dailymotion-sdk-android:sdk:0.2.12")
     // dynamic theme
-//    implementation("com.google.android.material:material:1.9.0")
+    implementation("com.google.android.material:material:1.10.0")
+    // stripe payments
+    implementation ("com.stripe:stripe-android:20.32.1")
+    implementation ("com.stripe:stripecardscan:20.32.1")
+    implementation ("com.stripe:financial-connections:20.32.1")
     // yt
     // ...
     // constraints

+ 10 - 5
tvlib/src/main/kotlin/org/mjdev/tvlib/activity/ComposableActivity.kt

@@ -10,6 +10,7 @@ package org.mjdev.tvlib.activity
 
 import android.content.Intent
 import android.content.res.Configuration
+import android.os.Build
 import android.os.Bundle
 import android.view.WindowManager
 import androidx.activity.ComponentActivity
@@ -82,11 +83,15 @@ open class ComposableActivity : ComponentActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {
         Timber.d("Activity ${this::class.simpleName} created.")
         super.onCreate(savedInstanceState)
-        setDecorFitsSystemWindows(window, false)
-        window.setFlags(
-            WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
-            WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-        )
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            setDecorFitsSystemWindows(window, false)
+            window.setFlags(
+                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
+                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+            )
+        } else {
+            setDecorFitsSystemWindows(window, true)
+        }
         if (BuildConfig.DEBUG) {
             anrWatchDog.start()
         }

+ 2 - 1
tvlib/src/main/kotlin/org/mjdev/tvlib/application/TvApplication.kt

@@ -12,11 +12,12 @@ package org.mjdev.tvlib.application
 
 import android.app.Application
 import coil.ImageLoader
+import com.google.android.material.color.DynamicColors
 
 open class TvApplication : Application() {
     override fun onCreate() {
         super.onCreate()
-//        DynamicColors.applyToActivitiesIfAvailable(this)
+        DynamicColors.applyToActivitiesIfAvailable(this)
     }
 
     open fun createImageLoader(): ImageLoader? = null

+ 49 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/payments/Settings.kt

@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.payments
+
+import android.content.Context
+import android.content.pm.PackageManager
+
+class Settings(context: Context) {
+    private val appContext = context.applicationContext
+    private val backendMetadata = getMetadata(METADATA_KEY_BACKEND_URL_KEY)
+    private val googlePlacesMetadata = getMetadata(METADATA_KEY_GOOGLE_PLACES_API_KEY)
+
+    val playgroundBackendUrl: String
+        get() {
+            return backendMetadata ?: BASE_URL
+        }
+
+    val googlePlacesApiKey: String?
+        get() {
+            return googlePlacesMetadata
+        }
+
+    private fun getMetadata(key: String): String? {
+        return appContext.packageManager
+            .getApplicationInfo(appContext.packageName, PackageManager.GET_META_DATA)
+            .metaData
+            .getString(key)
+            .takeIf { it?.isNotBlank() == true }
+    }
+
+    internal companion object {
+
+        private const val BASE_URL = "https://stp-mobile-playground-backend-v7.stripedemos.com/"
+
+        private const val METADATA_KEY_BACKEND_URL_KEY =
+            "com.stripe.android.paymentsheet.example.metadata.backend_url"
+
+        private const val METADATA_KEY_GOOGLE_PLACES_API_KEY =
+            "com.stripe.android.paymentsheet.example.metadata.google_places_api_key"
+
+    }
+
+}

+ 0 - 1
tvlib/src/main/kotlin/org/mjdev/tvlib/screen/Screen.kt

@@ -80,7 +80,6 @@ open class Screen {
             modifier = Modifier
                 .fillMaxSize()
                 .onlyPortrait {
-                    // todo not working on lollipop
                     navigationBarsPadding().statusBarsPadding()
                 }
         ) {

+ 3 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/media/MediaPlayerContainer.kt

@@ -11,11 +11,13 @@
 package org.mjdev.tvlib.ui.components.media
 
 import android.annotation.SuppressLint
+import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
 import org.mjdev.tvlib.annotations.Previews
 import org.mjdev.tvlib.extensions.ModifierExt.recomposeHighlighter
 import org.mjdev.tvlib.extensions.ModifierExt.swipeGestures
@@ -39,6 +41,7 @@ fun MediaPlayerContainer(
                 onSwipeUp = { nextItem() },
                 onSwipeDown = { prevItem() },
             )
+            .background(Color.Black)
             .recomposeHighlighter()
     ) {
         state.player.GetPlayerView()

+ 4 - 2
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/tv/Tabs.kt

@@ -74,12 +74,14 @@ fun Tabs(
             Spacer(modifier = Modifier.width(itemsSpacing))
         },
         indicator = { tabPositions, isActivated ->
-            tabPositions.getOrNull(selectedTabIndex.value)?.let { tab ->
+            tabPositions.getOrNull(
+                selectedTabIndex.value
+            )?.let { tab ->
                 TabRowDefaults.PillIndicator(
                     currentTabPosition = tab,
                     isActivated = isActivated,
                     activeColor = activeContentColor,
-                    inactiveColor = activeContentColor.copy(alpha = 0.4f)
+                    inactiveColor = activeContentColor.copy(alpha = 0.4f),
                 )
             }
         },

+ 1 - 2
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/theme/Theme.kt

@@ -8,13 +8,12 @@
 
 package org.mjdev.tvlib.ui.theme
 
-import android.os.Build
 import androidx.compose.foundation.isSystemInDarkTheme
 import androidx.compose.runtime.Composable
 
 @Composable
 fun TVAppTheme(
     useDarkTheme: Boolean = isSystemInDarkTheme(),
-    dynamicColor: Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S,
+    dynamicColor: Boolean = true,
     content: @Composable () -> Unit,
 ) = ThemeHelper (useDarkTheme, dynamicColor, content)

+ 220 - 15
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/theme/ThemeHelper.kt

@@ -11,7 +11,10 @@
 package org.mjdev.tvlib.ui.theme
 
 import android.app.Activity
+import android.content.Context
 import android.os.Build
+import androidx.annotation.ColorRes
+import androidx.annotation.RequiresApi
 import androidx.compose.foundation.Indication
 import androidx.compose.foundation.IndicationInstance
 import androidx.compose.foundation.LocalIndication
@@ -42,12 +45,11 @@ import androidx.tv.material3.MaterialTheme
 import androidx.tv.material3.darkColorScheme
 import androidx.tv.material3.lightColorScheme
 
-@Suppress("UNUSED_PARAMETER")
 @OptIn(ExperimentalTvMaterial3Api::class)
 @Composable
 fun ThemeHelper(
     useDarkTheme: Boolean = isSystemInDarkTheme(),
-    dynamicColor: Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S,
+    dynamicColors: Boolean = true,
     content: @Composable () -> Unit,
 ) {
     val context = LocalContext.current
@@ -56,21 +58,20 @@ fun ThemeHelper(
     val window = activity?.window
     val isEditMode = view.isInEditMode
 
-    val colorScheme: ColorScheme = when {
-//        dynamicColor -> {
-//            if (useDarkTheme)
-//                dynamicDarkColorScheme(context)
-//            else
-//                dynamicLightColorScheme(context)
-//        }
-
-        else -> {
-            if (useDarkTheme)
+    val colorScheme: ColorScheme =
+        if (useDarkTheme) {
+            if (dynamicColors && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)) {
+                dynamicDarkColorScheme(context)
+            } else {
                 darkColorScheme()
-            else
+            }
+        } else {
+            if (dynamicColors && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)) {
+                dynamicLightColorScheme(context)
+            } else {
                 lightColorScheme()
+            }
         }
-    }
 
     if (!isEditMode) {
         SideEffect {
@@ -158,4 +159,208 @@ object ThemeHelper {
         @ReadOnlyComposable
         get() = LocalThemeProvider.current
 
-}
+}
+
+@RequiresApi(Build.VERSION_CODES.S)
+@OptIn(ExperimentalTvMaterial3Api::class)
+fun dynamicDarkColorScheme(context: Context): ColorScheme {
+    val tonalPalette = dynamicTonalPalette(context)
+    return darkColorScheme(
+        primary = tonalPalette.primary80,
+        onPrimary = tonalPalette.primary20,
+        primaryContainer = tonalPalette.primary30,
+        onPrimaryContainer = tonalPalette.primary90,
+        inversePrimary = tonalPalette.primary40,
+        secondary = tonalPalette.secondary80,
+        onSecondary = tonalPalette.secondary20,
+        secondaryContainer = tonalPalette.secondary30,
+        onSecondaryContainer = tonalPalette.secondary90,
+        tertiary = tonalPalette.tertiary80,
+        onTertiary = tonalPalette.tertiary20,
+        tertiaryContainer = tonalPalette.tertiary30,
+        onTertiaryContainer = tonalPalette.tertiary90,
+        background = tonalPalette.neutral10,
+        onBackground = tonalPalette.neutral90,
+        surface = tonalPalette.neutral10,
+        onSurface = tonalPalette.neutral90,
+        surfaceVariant = tonalPalette.neutralVariant30,
+        onSurfaceVariant = tonalPalette.neutralVariant80,
+        inverseSurface = tonalPalette.neutral90,
+        inverseOnSurface = tonalPalette.neutral20,
+//        outline = tonalPalette.neutralVariant60,
+    )
+}
+
+@RequiresApi(Build.VERSION_CODES.S)
+@OptIn(ExperimentalTvMaterial3Api::class)
+fun dynamicLightColorScheme(context: Context): ColorScheme {
+    val tonalPalette = dynamicTonalPalette(context)
+    return lightColorScheme(
+        primary = tonalPalette.primary40,
+        onPrimary = tonalPalette.primary100,
+        primaryContainer = tonalPalette.primary90,
+        onPrimaryContainer = tonalPalette.primary10,
+        inversePrimary = tonalPalette.primary80,
+        secondary = tonalPalette.secondary40,
+        onSecondary = tonalPalette.secondary100,
+        secondaryContainer = tonalPalette.secondary90,
+        onSecondaryContainer = tonalPalette.secondary10,
+        tertiary = tonalPalette.tertiary40,
+        onTertiary = tonalPalette.tertiary100,
+        tertiaryContainer = tonalPalette.tertiary90,
+        onTertiaryContainer = tonalPalette.tertiary10,
+        background = tonalPalette.neutral99,
+        onBackground = tonalPalette.neutral10,
+        surface = tonalPalette.neutral99,
+        onSurface = tonalPalette.neutral10,
+        surfaceVariant = tonalPalette.neutralVariant90,
+        onSurfaceVariant = tonalPalette.neutralVariant30,
+        inverseSurface = tonalPalette.neutral20,
+        inverseOnSurface = tonalPalette.neutral95,
+//        outline = tonalPalette.neutralVariant50,
+    )
+}
+
+object ColorResourceHelper {
+    @RequiresApi(Build.VERSION_CODES.S)
+    fun getColor(context: Context, @ColorRes id: Int): Color {
+        return Color(context.resources.getColor(id, context.theme))
+    }
+}
+
+class TonalPalette(
+    val neutral100: Color,
+    val neutral99: Color,
+    val neutral95: Color,
+    val neutral90: Color,
+    val neutral80: Color,
+    val neutral70: Color,
+    val neutral60: Color,
+    val neutral50: Color,
+    val neutral40: Color,
+    val neutral30: Color,
+    val neutral20: Color,
+    val neutral10: Color,
+    val neutral0: Color,
+    val neutralVariant100: Color,
+    val neutralVariant99: Color,
+    val neutralVariant95: Color,
+    val neutralVariant90: Color,
+    val neutralVariant80: Color,
+    val neutralVariant70: Color,
+    val neutralVariant60: Color,
+    val neutralVariant50: Color,
+    val neutralVariant40: Color,
+    val neutralVariant30: Color,
+    val neutralVariant20: Color,
+    val neutralVariant10: Color,
+    val neutralVariant0: Color,
+    val primary100: Color,
+    val primary99: Color,
+    val primary95: Color,
+    val primary90: Color,
+    val primary80: Color,
+    val primary70: Color,
+    val primary60: Color,
+    val primary50: Color,
+    val primary40: Color,
+    val primary30: Color,
+    val primary20: Color,
+    val primary10: Color,
+    val primary0: Color,
+    val secondary100: Color,
+    val secondary99: Color,
+    val secondary95: Color,
+    val secondary90: Color,
+    val secondary80: Color,
+    val secondary70: Color,
+    val secondary60: Color,
+    val secondary50: Color,
+    val secondary40: Color,
+    val secondary30: Color,
+    val secondary20: Color,
+    val secondary10: Color,
+    val secondary0: Color,
+    val tertiary100: Color,
+    val tertiary99: Color,
+    val tertiary95: Color,
+    val tertiary90: Color,
+    val tertiary80: Color,
+    val tertiary70: Color,
+    val tertiary60: Color,
+    val tertiary50: Color,
+    val tertiary40: Color,
+    val tertiary30: Color,
+    val tertiary20: Color,
+    val tertiary10: Color,
+    val tertiary0: Color,
+)
+
+@RequiresApi(Build.VERSION_CODES.S)
+fun dynamicTonalPalette(context: Context): TonalPalette = TonalPalette(
+    neutral100 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_0),
+    neutral99 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_10),
+    neutral95 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_50),
+    neutral90 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_100),
+    neutral80 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_200),
+    neutral70 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_300),
+    neutral60 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_400),
+    neutral50 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_500),
+    neutral40 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_600),
+    neutral30 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_700),
+    neutral20 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_800),
+    neutral10 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_900),
+    neutral0 = ColorResourceHelper.getColor(context, android.R.color.system_neutral1_1000),
+    neutralVariant100 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_0),
+    neutralVariant99 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_10),
+    neutralVariant95 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_50),
+    neutralVariant90 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_100),
+    neutralVariant80 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_200),
+    neutralVariant70 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_300),
+    neutralVariant60 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_400),
+    neutralVariant50 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_500),
+    neutralVariant40 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_600),
+    neutralVariant30 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_700),
+    neutralVariant20 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_800),
+    neutralVariant10 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_900),
+    neutralVariant0 = ColorResourceHelper.getColor(context, android.R.color.system_neutral2_1000),
+    primary100 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_0),
+    primary99 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_10),
+    primary95 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_50),
+    primary90 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_100),
+    primary80 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_200),
+    primary70 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_300),
+    primary60 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_400),
+    primary50 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_500),
+    primary40 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_600),
+    primary30 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_700),
+    primary20 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_800),
+    primary10 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_900),
+    primary0 = ColorResourceHelper.getColor(context, android.R.color.system_accent1_1000),
+    secondary100 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_0),
+    secondary99 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_10),
+    secondary95 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_50),
+    secondary90 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_100),
+    secondary80 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_200),
+    secondary70 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_300),
+    secondary60 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_400),
+    secondary50 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_500),
+    secondary40 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_600),
+    secondary30 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_700),
+    secondary20 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_800),
+    secondary10 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_900),
+    secondary0 = ColorResourceHelper.getColor(context, android.R.color.system_accent2_1000),
+    tertiary100 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_0),
+    tertiary99 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_10),
+    tertiary95 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_50),
+    tertiary90 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_100),
+    tertiary80 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_200),
+    tertiary70 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_300),
+    tertiary60 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_400),
+    tertiary50 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_500),
+    tertiary40 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_600),
+    tertiary30 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_700),
+    tertiary20 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_800),
+    tertiary10 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_900),
+    tertiary0 = ColorResourceHelper.getColor(context, android.R.color.system_accent3_1000),
+)