From 2ba00bdbf00bf444486ca73ef6311103fab46b90 Mon Sep 17 00:00:00 2001 From: Ben Trengrove Date: Wed, 11 Dec 2024 09:08:45 +1100 Subject: [PATCH] Convert sample app activity to Compose --- .../com/google/accompanist/KotlinAndroid.kt | 2 +- sample/build.gradle.kts | 2 +- sample/src/main/AndroidManifest.xml | 3 +- .../google/accompanist/sample/MainActivity.kt | 113 ++++++++---------- .../google/accompanist/sample/MainScreen.kt | 97 +++++++++++++++ 5 files changed, 153 insertions(+), 64 deletions(-) create mode 100644 sample/src/main/java/com/google/accompanist/sample/MainScreen.kt diff --git a/build-logic/convention/src/main/kotlin/com/google/accompanist/KotlinAndroid.kt b/build-logic/convention/src/main/kotlin/com/google/accompanist/KotlinAndroid.kt index 07cdfbcd3..e9d9d7e23 100644 --- a/build-logic/convention/src/main/kotlin/com/google/accompanist/KotlinAndroid.kt +++ b/build-logic/convention/src/main/kotlin/com/google/accompanist/KotlinAndroid.kt @@ -36,7 +36,7 @@ internal fun Project.configureKotlinAndroid( commonExtension: CommonExtension<*, *, *, *, *, *>, ) { commonExtension.apply { - compileSdk = 34 + compileSdk = 35 defaultConfig { minSdk = 21 diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index e0835e5d4..cf654240d 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -25,7 +25,7 @@ plugins { } android { - compileSdk = 34 + compileSdk = 35 defaultConfig { applicationId = "com.google.accompanist.sample" diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 15144a1b7..2b94c2318 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -42,7 +42,8 @@ diff --git a/sample/src/main/java/com/google/accompanist/sample/MainActivity.kt b/sample/src/main/java/com/google/accompanist/sample/MainActivity.kt index 951ef8193..34da9494f 100644 --- a/sample/src/main/java/com/google/accompanist/sample/MainActivity.kt +++ b/sample/src/main/java/com/google/accompanist/sample/MainActivity.kt @@ -14,44 +14,43 @@ * limitations under the License. */ -@file:Suppress("DEPRECATION") // ListActivity - package com.google.accompanist.sample import android.annotation.SuppressLint -import android.app.ListActivity import android.content.Intent import android.os.Bundle -import android.view.View -import android.widget.ListView -import android.widget.SimpleAdapter -import java.text.Collator -import java.util.ArrayList -import java.util.Collections -import java.util.Comparator -import java.util.HashMap +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable /** - * A [ListActivity] which automatically populates the list of sample activities in this app + * A list which automatically populates the list of sample activities in this app * with the category `com.google.accompanist.sample.SAMPLE_CODE`. */ -class MainActivity : ListActivity() { +class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - listAdapter = SimpleAdapter( - this, - getData(intent.getStringExtra(EXTRA_PATH)), - android.R.layout.simple_list_item_1, - arrayOf("title"), - intArrayOf(android.R.id.text1) - ) + enableEdgeToEdge() + val data = getData(intent.getStringExtra(EXTRA_PATH)) - listView.isTextFilterEnabled = true + setContent { + AccompanistM3SampleTheme { + MainScreen( + listData = data, + onItemClick = { startActivity(it) } + ) + } + } } - private fun getData(prefix: String?): List> { - val myData = ArrayList>() + private fun getData(prefix: String?): List { + val myData = mutableListOf() val mainIntent = Intent(Intent.ACTION_MAIN, null) mainIntent.addCategory("com.google.accompanist.sample.SAMPLE_CODE") @@ -69,7 +68,7 @@ class MainActivity : ListActivity() { prefixWithSlash = "$prefix/" } - val entries = HashMap() + val entries = mutableMapOf() list.forEach { info -> val labelSeq = info.loadLabel(packageManager) @@ -78,22 +77,24 @@ class MainActivity : ListActivity() { if (prefixWithSlash.isNullOrEmpty() || label.startsWith(prefixWithSlash)) { val labelPath = label.split("/".toRegex()).toTypedArray() val nextLabel = if (prefixPath == null) labelPath[0] else labelPath[prefixPath.size] - if (prefixPath?.size ?: 0 == labelPath.size - 1) { - addItem( - data = myData, - name = nextLabel, - intent = activityIntent( - info.activityInfo.applicationInfo.packageName, - info.activityInfo.name + if ((prefixPath?.size ?: 0) == labelPath.size - 1) { + myData.add( + AccompanistSample( + title = nextLabel, + intent = activityIntent( + info.activityInfo.applicationInfo.packageName, + info.activityInfo.name + ) ) ) } else { if (entries[nextLabel] == null) { - addItem( - data = myData, - name = nextLabel, - intent = browseIntent( - if (prefix == "") nextLabel else "$prefix/$nextLabel" + myData.add( + AccompanistSample( + title = nextLabel, + intent = browseIntent( + if (prefix == "") nextLabel else "$prefix/$nextLabel" + ) ) ) entries[nextLabel] = true @@ -102,7 +103,7 @@ class MainActivity : ListActivity() { } } - Collections.sort(myData, sDisplayNameComparator) + myData.sortBy { it.title } return myData } @@ -119,30 +120,20 @@ class MainActivity : ListActivity() { result.putExtra(EXTRA_PATH, path) return result } +} - private fun addItem(data: MutableList>, name: String, intent: Intent) { - val temp = mutableMapOf() - temp["title"] = name - temp["intent"] = intent - data += temp - } - - @Deprecated("Deprecated in Java") - override fun onListItemClick(l: ListView, v: View, position: Int, id: Long) { - val map = l.getItemAtPosition(position) as Map<*, *> - val intent = map["intent"] as Intent? - startActivity(intent) - } - - companion object { - private const val EXTRA_PATH = "com.example.android.apis.Path" - - private val sDisplayNameComparator = object : Comparator> { - private val collator = Collator.getInstance() +private const val EXTRA_PATH = "com.example.android.apis.Path" - override fun compare(map1: Map, map2: Map): Int { - return collator.compare(map1["title"], map2["title"]) - } - } - } +/** + * TODO Migrate whole sample app to m3 and move to Theme.kt + */ +@Composable +fun AccompanistM3SampleTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + MaterialTheme( + colorScheme = if (darkTheme) darkColorScheme() else lightColorScheme(), + content = content + ) } diff --git a/sample/src/main/java/com/google/accompanist/sample/MainScreen.kt b/sample/src/main/java/com/google/accompanist/sample/MainScreen.kt new file mode 100644 index 000000000..5c18c12d2 --- /dev/null +++ b/sample/src/main/java/com/google/accompanist/sample/MainScreen.kt @@ -0,0 +1,97 @@ +/* + * Copyright 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 + * + * https://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. + */ + +package com.google.accompanist.sample + +import android.content.Intent +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.windowInsetsBottomHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ListItem +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberTopAppBarState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.res.stringResource + +data class AccompanistSample( + val title: String, + val intent: Intent +) + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MainScreen( + listData: List, + onItemClick: (Intent) -> Unit, + modifier: Modifier = Modifier +) { + Surface(modifier) { + Column { + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) + TopAppBar( + title = { Text(stringResource(R.string.app_name)) }, + scrollBehavior = scrollBehavior + ) + + ContentList( + listData, + onItemClick, + modifier = Modifier + .fillMaxSize() + .nestedScroll(scrollBehavior.nestedScrollConnection) + ) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun ContentList( + listData: List, + onItemClick: (Intent) -> Unit, + modifier: Modifier = Modifier +) { + LazyColumn( + modifier = modifier + ) { + items(listData) { + ListItem( + headlineText = { Text(it.title) }, + modifier = Modifier.clickable { onItemClick(it.intent) } + ) + } + + item { + Spacer( + Modifier.windowInsetsBottomHeight( + WindowInsets.systemBars + ) + ) + } + } +}