diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a3bf80e..df65987 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -47,6 +47,7 @@ kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", geekdroid = { module = "com.geekorum.geekdroid:geekdroid", version.ref = "geekdroid" } androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref="androidx-lifecycle" } +androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } androidx-activity = { module = "androidx.activity:activity-ktx", version.ref="androidx-activity" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref="androidx-activity" } @@ -67,6 +68,7 @@ androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-te com-android-application = { id = "com.android.application", version.ref = "com-android-application" } com-android-library = { id = "com.android.library", version.ref = "com-android-library" } org-jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "org-jetbrains-kotlin-android" } +google-gms-oss-license = { id = "com.google.android.gms.oss-licenses-plugin", version = "0.10.6" } [bundles] diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 16cd423..941de4c 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -24,6 +24,14 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id("com.geekorum.build.source-license-checker") + alias(libs.plugins.google.gms.oss.license) +} + +// workaround bug https://issuetracker.google.com/issues/275534543 +buildscript { + dependencies { + classpath("com.android.tools.build:gradle:8.0.0") + } } android { @@ -61,6 +69,7 @@ android { } buildFeatures { compose = true + buildConfig = true } composeOptions { kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() @@ -73,9 +82,19 @@ android { } dependencies { + implementation(project(":core")) + implementation(project(":ui:common")) implementation(project(":ui:material2")) implementation(project(":ui:material3")) + implementation(libs.geekdroid) { + //TODO get rid of dagger platform in geekdroid + exclude("com.google.dagger", "dagger-platform") + } + + + implementation(libs.androidx.lifecycle.viewmodel) + implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.compose.ui) diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 8fc0143..d8340b3 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -42,6 +42,15 @@ + + + + + \ No newline at end of file diff --git a/sample/src/main/java/com/geekorum/aboutoss/sampleapp/CustomViewer.kt b/sample/src/main/java/com/geekorum/aboutoss/sampleapp/CustomViewer.kt new file mode 100644 index 0000000..43227db --- /dev/null +++ b/sample/src/main/java/com/geekorum/aboutoss/sampleapp/CustomViewer.kt @@ -0,0 +1,113 @@ +/* + * AboutOss is an utility library to retrieve and display + * opensource licenses in Android applications. + * + * Copyright (C) 2023 by Frederic-Charles Barthelery. + * + * This file is part of AboutOss. + * + * AboutOss is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AboutOss is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AboutOss. If not, see . + */ +package com.geekorum.aboutoss.sampleapp + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.itemsIndexed +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.geekorum.aboutoss.ui.common.OpenSourceLicensesViewModel + +@Composable +fun CustomViewer( + viewModel: OpenSourceLicensesViewModel = viewModel( + initializer = { + createPrebuildOpenSourceLicensesViewModel() + } + ), + modifier: Modifier = Modifier +) { + Column(modifier = modifier) { + Text("This section shows our you can use a custom ui to display licenses") + DependenciesGrid(viewModel, Modifier.padding(top = 16.dp)) + } +} + +@Composable +private fun DependenciesGrid( + viewModel: OpenSourceLicensesViewModel, + modifier: Modifier = Modifier +) { + val dependencies by viewModel.dependenciesList.collectAsState(initial = emptyList()) + var selected by remember { mutableStateOf(-1) } + LazyVerticalGrid( + GridCells.Adaptive(150.dp), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = modifier + ) { + itemsIndexed(dependencies) { idx, dependency -> + if (idx == selected) { + val license by viewModel.getLicenseDependency(dependency) + .collectAsState(initial = "") + LicenseCard(license, onClick = { + selected = -1 + }) + } else { + DependencyCard(dependency, onClick = { + selected = idx + }) + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun LicenseCard(license: String, onClick: () -> Unit) { + Card(modifier = Modifier.size(150.dp), onClick = onClick, + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primary) + ) { + Text( + license, style = MaterialTheme.typography.bodyMedium, + modifier = Modifier + .padding(16.dp) + .fillMaxSize() + .wrapContentSize( + Alignment.Center + ) + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun DependencyCard(dependency: String, onClick: () -> Unit) { + Card(modifier = Modifier.size(150.dp), onClick = onClick) { + Text( + dependency, + style = MaterialTheme.typography.titleLarge, + modifier = Modifier + .padding(16.dp) + .fillMaxSize() + .wrapContentSize( + Alignment.Center + ) + ) + } +} diff --git a/sample/src/main/java/com/geekorum/aboutoss/sampleapp/MainActivity.kt b/sample/src/main/java/com/geekorum/aboutoss/sampleapp/MainActivity.kt index c891536..345ee3e 100644 --- a/sample/src/main/java/com/geekorum/aboutoss/sampleapp/MainActivity.kt +++ b/sample/src/main/java/com/geekorum/aboutoss/sampleapp/MainActivity.kt @@ -21,47 +21,132 @@ */ package com.geekorum.aboutoss.sampleapp +import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import com.geekorum.aboutoss.sampleapp.ui.theme.AboutOssTheme +import com.geekorum.aboutoss.sampleapp.ui.theme.OpenSourceLicenseTheme +import com.geekorum.aboutoss.ui.material3.OpenSourceLicensesActivity +import com.geekorum.aboutoss.ui.material.OpenSourceLicensesActivity as Material2OpenSourceLicensesActivity class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { AboutOssTheme { - // A surface container using the 'background' color from the theme - Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background - ) { - Greeting("Android") - } + Sample( + onMaterial2Click = { + startMaterial2LicenseActivity() + }, + onMaterial3Click = { + startMaterial3LicenseActivity() + } + ) } } } + + private fun startMaterial2LicenseActivity() { + val intent = if (BuildConfig.DEBUG) { + // we launch a custom activity in debug to display some fake licenses + // see Material2AcPrebuiltLicencesMaterial2Activitytivity for more info + Intent(this, PrebuiltLicencesMaterial2Activity::class.java) + } else { + Intent(this, Material2OpenSourceLicensesActivity::class.java) + } + startActivity(intent) + } + + private fun startMaterial3LicenseActivity() { + // Don't use default MaterialTheme but supply our own + OpenSourceLicensesActivity.themeProvider = { content -> + OpenSourceLicenseTheme(content) + } + val intent = if (BuildConfig.DEBUG) { + // we launch a custom activity in debug to display some fake licenses + // see PrebuiltLicencesMaterial3Activity for more info + Intent(this, PrebuiltLicencesMaterial3Activity::class.java) + } else { + Intent(this, OpenSourceLicensesActivity::class.java) + } + startActivity(intent) + } +} + +@Composable +private fun Sample( + onMaterial2Click: () -> Unit, + onMaterial3Click: () -> Unit, +) { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + Column(Modifier.fillMaxSize()) { + LaunchActivitySection(onMaterial2Click, onMaterial3Click) + CustomViewer(modifier = Modifier.padding(horizontal = 16.dp)) + } + } +} + +@Composable +private fun LaunchActivitySection( + onMaterial2Click: () -> Unit, + onMaterial3Click: () -> Unit, + modifier: Modifier = Modifier +) { + Column(modifier.padding(16.dp)) { + Text("This section launch a new activity to display licences information") + Row( + horizontalArrangement = Arrangement.SpaceAround, modifier = Modifier + .fillMaxWidth() + .padding(32.dp) + ) { + Material2Card(onClick = onMaterial2Click) + Material3Card(onClick = onMaterial3Click) + } + } } + @Composable -fun Greeting(name: String, modifier: Modifier = Modifier) { - Text( - text = "Hello $name!", - modifier = modifier - ) +@OptIn(ExperimentalMaterial3Api::class) +private fun Material2Card( + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Card(modifier = modifier, onClick = onClick) { + Column(Modifier.padding(16.dp)) { + Text("Material2 UI", style = MaterialTheme.typography.labelLarge) + } + } } +@Composable +@OptIn(ExperimentalMaterial3Api::class) +private fun Material3Card( + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Card(modifier = modifier, onClick = onClick) { + Column(Modifier.padding(16.dp)) { + Text("Material3 UI", style = MaterialTheme.typography.labelLarge) + } + } +} + + @Preview(showBackground = true) @Composable -fun GreetingPreview() { +fun LauncherActivitySectionPreview() { AboutOssTheme { - Greeting("Android") + LaunchActivitySection(onMaterial2Click = {}, onMaterial3Click = {}) } } \ No newline at end of file diff --git a/sample/src/main/java/com/geekorum/aboutoss/sampleapp/PrebuiltLicencesActivities.kt b/sample/src/main/java/com/geekorum/aboutoss/sampleapp/PrebuiltLicencesActivities.kt new file mode 100644 index 0000000..579ef7b --- /dev/null +++ b/sample/src/main/java/com/geekorum/aboutoss/sampleapp/PrebuiltLicencesActivities.kt @@ -0,0 +1,88 @@ +/* + * AboutOss is an utility library to retrieve and display + * opensource licenses in Android applications. + * + * Copyright (C) 2023 by Frederic-Charles Barthelery. + * + * This file is part of AboutOss. + * + * AboutOss is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AboutOss is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AboutOss. If not, see . + */ +package com.geekorum.aboutoss.sampleapp + +import androidx.activity.viewModels +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewmodel.CreationExtras +import androidx.lifecycle.viewmodel.initializer +import androidx.lifecycle.viewmodel.viewModelFactory +import com.geekorum.aboutoss.core.LicenseInfoRepository +import com.geekorum.aboutoss.ui.common.OpenSourceLicensesViewModel +import com.geekorum.aboutoss.ui.material3.OpenSourceLicensesActivity +import com.geekorum.geekdroid.network.BrowserLauncher +import kotlinx.coroutines.Dispatchers +import com.geekorum.aboutoss.ui.material.OpenSourceLicensesActivity as Material2OpenSourceLicensesActivity + +/** + * Custom activity needed to load resources from another set of files than default generated by + * OSS Licenses Gradle Plugin. + * + * This is necessary because OSS License gradle plugin generates stub resources on debug builds. + */ +class PrebuiltLicencesMaterial2Activity : Material2OpenSourceLicensesActivity() { + override val viewModel: OpenSourceLicensesViewModel by viewModels( + factoryProducer = { + viewModelFactory { + initializer { + createPrebuildOpenSourceLicensesViewModel() + } + } + } + ) +} + + +/** + * Custom activity needed to load resources from another set of files than default generated by + * OSS Licenses Gradle Plugin. + * + * This is necessary because OSS License gradle plugin generates stub resources on debug builds. + */ +class PrebuiltLicencesMaterial3Activity : OpenSourceLicensesActivity() { + override val viewModel: OpenSourceLicensesViewModel by viewModels( + factoryProducer = { + viewModelFactory { + initializer { + createPrebuildOpenSourceLicensesViewModel() + } + } + } + ) +} + +fun CreationExtras.createPrebuildOpenSourceLicensesViewModel(): OpenSourceLicensesViewModel { + val application = + this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY]!! + val licenseInfoRepository = LicenseInfoRepository( + appContext = application, + mainCoroutineDispatcher = Dispatchers.Main, + ioCoroutineDispatcher = Dispatchers.IO, + thirdPartyLicensesResourceName = "prebuilt_third_party_licenses", + thirdPartyLicenseMetadataResourceName = "prebuilt_third_party_license_metadata" + ) + val browserLauncher = BrowserLauncher(application, application.packageManager) + return OpenSourceLicensesViewModel( + licenseInfoRepository, + browserLauncher + ) +} diff --git a/sample/src/main/java/com/geekorum/aboutoss/sampleapp/ui/theme/Theme.kt b/sample/src/main/java/com/geekorum/aboutoss/sampleapp/ui/theme/Theme.kt index a10e0ea..ea734f5 100644 --- a/sample/src/main/java/com/geekorum/aboutoss/sampleapp/ui/theme/Theme.kt +++ b/sample/src/main/java/com/geekorum/aboutoss/sampleapp/ui/theme/Theme.kt @@ -31,6 +31,7 @@ import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView @@ -88,4 +89,20 @@ fun AboutOssTheme( typography = Typography, content = content ) -} \ No newline at end of file +} + +private val OpenSourcesLightColorScheme = lightColorScheme( + primary = Color.Cyan, + secondary = PurpleGrey40, + tertiary = Pink40 +) + +@Composable +fun OpenSourceLicenseTheme( + content: @Composable () -> Unit +) { + MaterialTheme( + colorScheme = OpenSourcesLightColorScheme, + content = content + ) +} diff --git a/sample/src/main/res/raw/prebuilt_third_party_license_metadata b/sample/src/main/res/raw/prebuilt_third_party_license_metadata new file mode 100644 index 0000000..96194fd --- /dev/null +++ b/sample/src/main/res/raw/prebuilt_third_party_license_metadata @@ -0,0 +1,118 @@ +0:46 Material Components for Android +0:46 Compose Navigation +0:46 Android Navigation Runtime Kotlin Extensions +0:46 androidx.databinding:databinding-adapters +0:46 Kotlin Stdlib Jdk7 +0:46 Kotlin Stdlib Jdk8 +0:46 Fragment Kotlin Extensions +0:46 Android Lifecycle ViewModel +0:46 Android Support Library fragment +0:46 Android Transition Support Library +0:46 Compose Geometry +0:46 okio +0:46 Kotlin Stdlib +0:46 AndroidX Autofill +0:46 Compose Runtime +0:46 Compose Foundation +0:46 androidx.databinding:viewbinding +0:46 Compose Graphics +0:46 Compose Material Icons Core +0:46 Compose Unit +0:46 Android Support RecyclerView +0:46 IntelliJ IDEA Annotations +0:46 Android Support Library Local Broadcast Manager +0:46 Jetpack Compose Libraries BOM +0:46 Android Support Library Annotations +0:46 javax.inject +0:46 Android Support AnimatedVectorDrawable +0:46 Android Room-Runtime +0:46 Android Arch-Runtime +0:46 Android App Startup Runtime +0:46 Android Support Library Sliding Pane Layout +0:46 Android Emoji2 Compat view helpers +0:46 androidx.databinding:databinding-ktx +47:47 kotlinx-coroutines-bom +0:46 Android Support Library Document File +0:46 Saved State +0:46 Android Support Library Annotations +0:46 Compose Animation Core +0:46 okio +0:46 Android Support Library Interpolators +0:46 Lifecycle ViewModel Compose +0:46 Android Navigation Fragment +0:46 Core Kotlin Extensions +0:46 Compose Layouts +0:46 Android ConstraintLayout Core +0:46 okhttp +0:46 androidx.profileinstaller:profileinstaller +0:46 Compose Material3 Components +0:46 AndroidX Futures +0:46 Android Lifecycle Service +0:46 Android AppCompat Library +0:46 SavedState Kotlin Extensions +0:46 Android Emoji2 Compat +0:46 Android Lifecycle LiveData Core +0:46 Android Support Library loader +0:46 Android Room-Common +0:46 Android Support Library Drawer Layout +0:46 Compose Material Ripple +0:46 androidx.databinding.databinding-common +95:41 Geekdroid +0:46 Android Lifecycle Kotlin Extensions +0:46 Android Arch-Common +0:46 androidx.customview:poolingcontainer +0:46 Android Support Library Cursor Adapter +0:46 Activity +0:46 Android Navigation Runtime +0:46 Android WorkManager Runtime +0:46 Android Support CardView v7 +0:46 Android Tracing +0:46 Kotlin Stdlib Common +0:46 Android Lifecycle Runtime +0:46 error-prone annotations +0:46 androidx.databinding:databinding-runtime +0:46 Compose Util +0:46 Android Support Library Custom View +0:46 Jetpack WindowManager Library +0:46 Android Lifecycle LiveData +0:46 Android Navigation Common +47:47 kotlinx-coroutines-core +0:46 Android Support VectorDrawable +0:46 Android Lifecycle-Common for Java 8 Language +0:46 Compose Material3 Components +0:46 Activity Kotlin Extensions +0:46 VersionedParcelable +0:46 Android Lifecycle ViewModel with SavedState +0:46 Android Support Library collections +0:46 Compose Saveable +0:46 Compose UI primitives +0:46 Android Navigation Common Kotlin Extensions +0:46 Android Support DynamicAnimation +0:46 LiveData Core Kotlin Extensions +0:46 Android Support Custom Tabs +47:47 Dagger +0:46 Compose Animation +0:46 Android Support Library View Pager +0:46 Compose Material Components +0:46 Kotlin Libraries bill-of-materials +0:46 Android Support Library Print +0:46 AndroidX Widget ViewPager2 +0:46 Collections Kotlin Extensions +0:46 Android Support Library Coordinator Layout +0:46 Android Support Library core utils +47:47 kotlinx-coroutines-android +0:46 Android Resources Library +0:46 Android DB +47:47 kotlinx-coroutines-core +0:46 AndroidX Preference +0:46 Android Lifecycle ViewModel Kotlin Extensions +0:46 Android Support SQLite - Framework Implementation +0:46 Experimental annotation +0:46 Compose Tooling API +0:46 Android Support Library compat +0:46 Android Resource Inspection - Annotations +0:46 Android Lifecycle-Common +0:46 Android ConstraintLayout +0:46 Android Lifecycle Process +0:46 Activity Compose +0:46 Compose UI Text diff --git a/sample/src/main/res/raw/prebuilt_third_party_licenses b/sample/src/main/res/raw/prebuilt_third_party_licenses new file mode 100644 index 0000000..ef6ff69 --- /dev/null +++ b/sample/src/main/res/raw/prebuilt_third_party_licenses @@ -0,0 +1,3 @@ +http://www.apache.org/licenses/LICENSE-2.0.txt +https://www.apache.org/licenses/LICENSE-2.0.txt +https://www.gnu.org/licenses/gpl-3.0.html diff --git a/settings.gradle.kts b/settings.gradle.kts index 451bee7..b8b27a3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,7 +4,16 @@ pluginManagement { mavenCentral() gradlePluginPortal() } + + resolutionStrategy { + eachPlugin { + when (requested.id.id) { + "com.google.android.gms.oss-licenses-plugin" -> useModule("com.google.android.gms:oss-licenses-plugin:${requested.version}") + } + } + } } + dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { @@ -22,3 +31,4 @@ include(":core") include(":ui:common") include(":ui:material2") include(":ui:material3") +include(":sample")