diff --git a/appdistribution/app/build.gradle b/appdistribution/app/build.gradle index cb4c85c26..2f2ee4090 100644 --- a/appdistribution/app/build.gradle +++ b/appdistribution/app/build.gradle @@ -6,11 +6,11 @@ plugins { android { namespace 'com.google.firebase.appdistributionquickstart' - compileSdk 33 + compileSdk 34 defaultConfig { applicationId "com.google.firebase.appdistributionquickstart" minSdk 21 // minSdk would be 19 without compose - targetSdk 33 + targetSdk 34 versionCode 1 versionName "1.0" @@ -66,7 +66,7 @@ dependencies { implementation platform('com.google.firebase:firebase-bom:31.0.2') // ADD the SDK to the "prerelease" variant only (example) - implementation 'com.google.firebase:firebase-appdistribution-ktx:16.0.0-beta01' + implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta12' // For an optimal experience using App Distribution, add the Firebase SDK // for Google Analytics. This is recommended, but not required. @@ -77,6 +77,7 @@ dependencies { implementation "androidx.compose.material:material:$compose_version" implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation 'androidx.activity:activity-compose:1.5.1' + implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1' androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/appdistribution/app/src/main/AndroidManifest.xml b/appdistribution/app/src/main/AndroidManifest.xml index a29b19adf..f261af635 100644 --- a/appdistribution/app/src/main/AndroidManifest.xml +++ b/appdistribution/app/src/main/AndroidManifest.xml @@ -21,6 +21,12 @@ android:theme="@style/AppTheme"> + + + diff --git a/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/EntryChoiceActivity.kt b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/EntryChoiceActivity.kt index b8e0666f8..6fe85d44a 100644 --- a/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/EntryChoiceActivity.kt +++ b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/EntryChoiceActivity.kt @@ -4,20 +4,29 @@ import android.content.Intent import com.firebase.example.internal.BaseEntryChoiceActivity import com.firebase.example.internal.Choice import com.google.firebase.appdistributionquickstart.java.MainActivity +import com.google.firebase.appdistributionquickstart.kotlin.ComposeMainActivity import com.google.firebase.appdistributionquickstart.kotlin.KotlinMainActivity class EntryChoiceActivity : BaseEntryChoiceActivity() { override fun getChoices(): List { return listOf( - Choice( - "Java", - "Run the Firebase App Distribution quickstart written in Java.", - Intent(this, MainActivity::class.java)), - Choice( - "Kotlin", - "Run the Firebase App Distribution quickstart written in Kotlin.", - Intent(this, KotlinMainActivity::class.java)) - ) + Choice( + "Java", + "Run the Firebase App Distribution quickstart written in Java.", + Intent(this, MainActivity::class.java) + ), + Choice( + "Kotlin", + "Run the Firebase App Distribution quickstart written in Kotlin.", + Intent(this, KotlinMainActivity::class.java) + ), + Choice( + "Compose", + "Run the Firebase App Distribution quickstart written in Compose.", + Intent(this, ComposeMainActivity::class.java), + ), + + ) } } diff --git a/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/kotlin/AppDistributionViewModel.kt b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/kotlin/AppDistributionViewModel.kt new file mode 100644 index 000000000..3aa373dd0 --- /dev/null +++ b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/kotlin/AppDistributionViewModel.kt @@ -0,0 +1,45 @@ +package com.google.firebase.appdistributionquickstart.kotlin + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewmodel.CreationExtras +import com.google.firebase.Firebase +import com.google.firebase.appdistribution.FirebaseAppDistribution +import com.google.firebase.appdistribution.FirebaseAppDistributionException +import com.google.firebase.appdistribution.appDistribution + +class AppDistributionViewModel( + val appDistribution: FirebaseAppDistribution +) : ViewModel() { + + companion object { + const val TAG = "AppDistribution-Quickstart" + + // Used to inject this ViewModel's dependencies + // See also: https://developer.android.com/topic/libraries/architecture/viewmodel/viewmodel-factories + val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create( + modelClass: Class, + extras: CreationExtras + ): T { + // Get instance. + val appDistribution = Firebase.appDistribution + return AppDistributionViewModel(appDistribution) as T + } + } + } + + fun updateIfNewRelease() { + appDistribution.updateIfNewReleaseAvailable() + .addOnProgressListener { updateProgress -> + // (Optional) Implement custom progress updates in addition to + // automatic NotificationManager updates. + } + .addOnFailureListener { e -> + if (e is FirebaseAppDistributionException) { + // Handle exception. + } + } + } +} \ No newline at end of file diff --git a/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/kotlin/ComposeMainActivity.kt b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/kotlin/ComposeMainActivity.kt new file mode 100644 index 000000000..5977d5a17 --- /dev/null +++ b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/kotlin/ComposeMainActivity.kt @@ -0,0 +1,114 @@ +package com.google.firebase.appdistributionquickstart.kotlin + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.viewmodel.compose.viewModel +import com.google.firebase.appdistributionquickstart.R +import com.google.firebase.appdistributionquickstart.ui.theme.AppDistributionTheme + + +class ComposeMainActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + AppDistributionTheme { + Surface( + modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background + ) { + MainAppView() + } + } + } + } +} + +@Composable +fun MainAppView( + appDistributionViewModel: AppDistributionViewModel = viewModel(factory = AppDistributionViewModel.Factory) +) { + + ComposableLifecycle { source, event -> + if (event == Lifecycle.Event.ON_RESUME) { + appDistributionViewModel.updateIfNewRelease() + } + } + + + Scaffold(topBar = { + TopAppBar( + backgroundColor = colorResource(R.color.colorPrimary) + ) { + Text( + text = stringResource(R.string.app_name), + style = MaterialTheme.typography.h6, + textAlign = TextAlign.Center, + modifier = Modifier.padding(8.dp), + color = Color.White + ) + } + }, content = { it -> + Column( + horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier + .fillMaxSize() + .padding(it) + ) { + Spacer(modifier = Modifier.height(30.dp)) + Image( + painterResource(R.drawable.firebase_lockup_400), + contentDescription = "Firebase logo", + contentScale = ContentScale.Crop, + ) + Text( + text = stringResource(R.string.textview_text), modifier = Modifier.padding(8.dp) + ) + } + }) +} + +@Composable +fun ComposableLifecycle( + lifeCycleOwner: LifecycleOwner = LocalLifecycleOwner.current, + onEvent: (LifecycleOwner, Lifecycle.Event) -> Unit +) { + DisposableEffect(lifeCycleOwner) { + val observer = LifecycleEventObserver { source, event -> + onEvent(source, event) + } + lifeCycleOwner.lifecycle.addObserver(observer) + onDispose { + lifeCycleOwner.lifecycle.removeObserver(observer) + } + } +} \ No newline at end of file diff --git a/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Color.kt b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Color.kt new file mode 100644 index 000000000..3e95f9409 --- /dev/null +++ b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.google.firebase.appdistributionquickstart.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val FirebaseBlue = Color(0xFF0288D1) // copied from colors.xml +val FirebaseBannerBlue = Color(0xFF039BE5) // copied from colors.xml +val FirebaseOrange = Color(0xFFFFA000) // copied from colors.xml \ No newline at end of file diff --git a/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Shape.kt b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Shape.kt new file mode 100644 index 000000000..cb3013c77 --- /dev/null +++ b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Shape.kt @@ -0,0 +1,11 @@ +package com.google.firebase.appdistributionquickstart.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + small = RoundedCornerShape(16.dp), + medium = RoundedCornerShape(2.dp), + large = RoundedCornerShape(0.dp) +) \ No newline at end of file diff --git a/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Theme.kt b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Theme.kt new file mode 100644 index 000000000..23c43e59d --- /dev/null +++ b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Theme.kt @@ -0,0 +1,39 @@ +package com.google.firebase.appdistributionquickstart.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors + +import androidx.compose.runtime.Composable + +private val DarkColorPalette = darkColors( + primary = Purple80, + primaryVariant = PurpleGrey80, + secondary = Pink80 +) + +private val LightColorPalette = lightColors( + primary = FirebaseBlue, + primaryVariant = FirebaseBannerBlue, + secondary = FirebaseOrange +) + +@Composable +fun AppDistributionTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + val colors = if (darkTheme) { + DarkColorPalette + } else { + LightColorPalette + } + + MaterialTheme( + colors = colors, + typography = Typography, + shapes = Shapes, + content = content + ) +} \ No newline at end of file diff --git a/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Type.kt b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Type.kt new file mode 100644 index 000000000..d64c4bb93 --- /dev/null +++ b/appdistribution/app/src/main/java/com/google/firebase/appdistributionquickstart/ui/theme/Type.kt @@ -0,0 +1,18 @@ +package com.google.firebase.appdistributionquickstart.ui.theme + +import androidx.compose.material.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + body1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) +) \ No newline at end of file diff --git a/appdistribution/build.gradle b/appdistribution/build.gradle index 64c31555c..0421ce3df 100644 --- a/appdistribution/build.gradle +++ b/appdistribution/build.gradle @@ -2,6 +2,10 @@ buildscript { + ext { + compose_version = '1.2.1' + } + repositories { mavenLocal() google() diff --git a/appdistribution/gradle.properties b/appdistribution/gradle.properties index aac7c9b46..c79c84715 100644 --- a/appdistribution/gradle.properties +++ b/appdistribution/gradle.properties @@ -15,3 +15,4 @@ org.gradle.jvmargs=-Xmx1536m # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true +android.useAndroidX=true \ No newline at end of file