diff --git a/.github/ci-gradle.properties b/.github/ci-gradle.properties index 2962a6399..dbafa68cd 100644 --- a/.github/ci-gradle.properties +++ b/.github/ci-gradle.properties @@ -15,9 +15,13 @@ # org.gradle.daemon=false -org.gradle.parallel=false -org.gradle.jvmargs=-Xmx5120m +org.gradle.parallel=true org.gradle.workers.max=2 kotlin.incremental=false -kotlin.compiler.execution.strategy=in-process \ No newline at end of file + +# Controls KotlinOptions.allWarningsAsErrors. +# This value used in CI and is currently set to false. +# If you want to treat warnings as errors locally, set this property to true +# in your ~/.gradle/gradle.properties file. +warningsAsErrors=false diff --git a/.github/workflows/build_test.yaml b/.github/workflows/build_test.yaml index 8e52b225a..026425148 100644 --- a/.github/workflows/build_test.yaml +++ b/.github/workflows/build_test.yaml @@ -48,7 +48,7 @@ jobs: api-level: ${{ matrix.api-level }} arch: x86 disable-animations: true - script: ./gradlew connectedCheck --stacktrace + script: ./gradlew :app:connectedCheck --stacktrace - name: Upload test reports if: always() diff --git a/.github/workflows/copy-branch.yml b/.github/workflows/copy-branch.yml index f8f8572d9..46a0f90d3 100644 --- a/.github/workflows/copy-branch.yml +++ b/.github/workflows/copy-branch.yml @@ -19,7 +19,7 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it, # but specifies master branch (old default). - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 ref: master diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 457602507..454e37d0a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -17,12 +17,13 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) - alias(libs.plugins.kapt) alias(libs.plugins.ksp) alias(libs.plugins.hilt) + alias(libs.plugins.compose.compiler) } android { + namespace = "com.example.android.architecture.blueprints.todoapp" compileSdk = libs.versions.compileSdk.get().toInt() defaultConfig { @@ -78,26 +79,23 @@ android { buildFeatures { compose = true + buildConfig = true } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = "17" } - packagingOptions { + packaging { excludes += "META-INF/AL2.0" excludes += "META-INF/LGPL2.1" } - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.androidxComposeCompiler.get() - } - tasks.withType().configureEach { kotlinOptions { freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn" @@ -128,7 +126,7 @@ dependencies { // Hilt implementation(libs.hilt.android.core) implementation(libs.androidx.hilt.navigation.compose) - kapt(libs.hilt.compiler) + ksp(libs.hilt.compiler) // Jetpack Compose val composeBom = platform(libs.androidx.compose.bom) @@ -139,7 +137,8 @@ dependencies { implementation(libs.androidx.compose.foundation.core) implementation(libs.androidx.compose.foundation.layout) implementation(libs.androidx.compose.animation) - implementation(libs.androidx.compose.material.core) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.material.iconsExtended) implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.navigation.compose) implementation(libs.androidx.lifecycle.runtimeCompose) @@ -166,7 +165,7 @@ dependencies { // JVM tests - Hilt testImplementation(libs.hilt.android.testing) - kaptTest(libs.hilt.compiler) + kspTest(libs.hilt.compiler) // Dependencies for Android unit tests androidTestImplementation(composeBom) @@ -196,5 +195,5 @@ dependencies { // AndroidX Test - Hilt testing androidTestImplementation(libs.hilt.android.testing) - kaptAndroidTest(libs.hilt.compiler) + kspAndroidTest(libs.hilt.compiler) } diff --git a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskScreenTest.kt b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskScreenTest.kt index f7b68a521..4c68d9df8 100644 --- a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskScreenTest.kt +++ b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskScreenTest.kt @@ -16,7 +16,7 @@ package com.example.android.architecture.blueprints.todoapp.addedittask -import androidx.compose.material.Surface +import androidx.compose.material3.Surface import androidx.compose.ui.test.SemanticsNodeInteraction import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.hasSetTextAction @@ -32,11 +32,10 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import com.example.android.architecture.blueprints.todoapp.HiltTestActivity import com.example.android.architecture.blueprints.todoapp.R +import com.example.android.architecture.blueprints.todoapp.TodoTheme import com.example.android.architecture.blueprints.todoapp.data.TaskRepository -import com.google.accompanist.appcompattheme.AppCompatTheme import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest -import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals @@ -44,6 +43,7 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import javax.inject.Inject /** * Integration test for the Add Task screen. @@ -70,7 +70,7 @@ class AddEditTaskScreenTest { // GIVEN - On the "Add Task" screen. composeTestRule.setContent { - AppCompatTheme { + TodoTheme { Surface { AddEditTaskScreen( viewModel = AddEditTaskViewModel(repository, SavedStateHandle()), diff --git a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsScreenTest.kt b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsScreenTest.kt index ac28599c4..7d0fe181d 100644 --- a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsScreenTest.kt +++ b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsScreenTest.kt @@ -16,7 +16,7 @@ package com.example.android.architecture.blueprints.todoapp.statistics -import androidx.compose.material.Surface +import androidx.compose.material3.Surface import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onNodeWithText @@ -24,17 +24,17 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import com.example.android.architecture.blueprints.todoapp.HiltTestActivity import com.example.android.architecture.blueprints.todoapp.R +import com.example.android.architecture.blueprints.todoapp.TodoTheme import com.example.android.architecture.blueprints.todoapp.data.TaskRepository -import com.google.accompanist.appcompattheme.AppCompatTheme import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest -import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import javax.inject.Inject /** * Integration test for the statistics screen. @@ -71,7 +71,7 @@ class StatisticsScreenTest { } composeTestRule.setContent { - AppCompatTheme { + TodoTheme { Surface { StatisticsScreen( openDrawer = { }, diff --git a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailScreenTest.kt b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailScreenTest.kt index 666f76747..625447fb7 100644 --- a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailScreenTest.kt +++ b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailScreenTest.kt @@ -16,7 +16,7 @@ package com.example.android.architecture.blueprints.todoapp.taskdetail -import androidx.compose.material.Surface +import androidx.compose.material3.Surface import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsOff import androidx.compose.ui.test.assertIsOn @@ -27,17 +27,17 @@ import androidx.lifecycle.SavedStateHandle import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import com.example.android.architecture.blueprints.todoapp.HiltTestActivity +import com.example.android.architecture.blueprints.todoapp.TodoTheme import com.example.android.architecture.blueprints.todoapp.data.TaskRepository -import com.google.accompanist.appcompattheme.AppCompatTheme import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest -import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import javax.inject.Inject /** * Integration test for the Task Details screen. @@ -100,7 +100,7 @@ class TaskDetailScreenTest { private fun setContent(activeTaskId: String) { composeTestRule.setContent { - AppCompatTheme { + TodoTheme { Surface { TaskDetailScreen( viewModel = TaskDetailViewModel( diff --git a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/AppNavigationTest.kt b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/AppNavigationTest.kt index 2d9014eb9..6496abdea 100644 --- a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/AppNavigationTest.kt +++ b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/AppNavigationTest.kt @@ -30,17 +30,17 @@ import androidx.test.filters.LargeTest import com.example.android.architecture.blueprints.todoapp.HiltTestActivity import com.example.android.architecture.blueprints.todoapp.R import com.example.android.architecture.blueprints.todoapp.TodoNavGraph +import com.example.android.architecture.blueprints.todoapp.TodoTheme import com.example.android.architecture.blueprints.todoapp.data.TaskRepository -import com.google.accompanist.appcompattheme.AppCompatTheme import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest -import javax.inject.Inject import kotlinx.coroutines.test.runTest import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import javax.inject.Inject /** * Tests for scenarios that requires navigating within the app. @@ -181,7 +181,7 @@ class AppNavigationTest { private fun setContent() { composeTestRule.setContent { - AppCompatTheme { + TodoTheme { TodoNavGraph() } } diff --git a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreenTest.kt b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreenTest.kt index a91ad574c..8ec1e65c4 100644 --- a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreenTest.kt +++ b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreenTest.kt @@ -17,7 +17,7 @@ package com.example.android.architecture.blueprints.todoapp.tasks import androidx.annotation.StringRes -import androidx.compose.material.Surface +import androidx.compose.material3.Surface import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.isToggleable import androidx.compose.ui.test.junit4.createAndroidComposeRule @@ -29,17 +29,17 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import com.example.android.architecture.blueprints.todoapp.HiltTestActivity import com.example.android.architecture.blueprints.todoapp.R +import com.example.android.architecture.blueprints.todoapp.TodoTheme import com.example.android.architecture.blueprints.todoapp.data.TaskRepository -import com.google.accompanist.appcompattheme.AppCompatTheme import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest -import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import javax.inject.Inject /** * Integration test for the Task List screen. @@ -255,7 +255,7 @@ class TasksScreenTest { private fun setContent() { composeTestRule.setContent { - AppCompatTheme { + TodoTheme { Surface { TasksScreen( viewModel = TasksViewModel(repository, SavedStateHandle()), diff --git a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksTest.kt b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksTest.kt index 8d3097e87..f84f649ed 100644 --- a/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksTest.kt +++ b/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksTest.kt @@ -35,17 +35,17 @@ import androidx.test.filters.LargeTest import com.example.android.architecture.blueprints.todoapp.HiltTestActivity import com.example.android.architecture.blueprints.todoapp.R import com.example.android.architecture.blueprints.todoapp.TodoNavGraph +import com.example.android.architecture.blueprints.todoapp.TodoTheme import com.example.android.architecture.blueprints.todoapp.data.TaskRepository -import com.google.accompanist.appcompattheme.AppCompatTheme import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest -import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import javax.inject.Inject /** * Large End-to-End test for the tasks module. @@ -291,7 +291,7 @@ class TasksTest { private fun setContent() { composeTestRule.setContent { - AppCompatTheme { + TodoTheme { TodoNavGraph() } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 79bb88f91..2ea63d37f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. --> - + + android:exported="true"> diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoActivity.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoActivity.kt index 90ad33d03..241ce065b 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoActivity.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoActivity.kt @@ -19,7 +19,7 @@ package com.example.android.architecture.blueprints.todoapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import com.google.accompanist.appcompattheme.AppCompatTheme +import androidx.activity.enableEdgeToEdge import dagger.hilt.android.AndroidEntryPoint /** @@ -30,8 +30,9 @@ class TodoActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + enableEdgeToEdge() setContent { - AppCompatTheme { + TodoTheme { TodoNavGraph() } } diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoNavGraph.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoNavGraph.kt index c488d87d5..852256c65 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoNavGraph.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoNavGraph.kt @@ -17,9 +17,9 @@ package com.example.android.architecture.blueprints.todoapp import android.app.Activity -import androidx.compose.material.DrawerState -import androidx.compose.material.DrawerValue -import androidx.compose.material.rememberDrawerState +import androidx.compose.material3.DrawerState +import androidx.compose.material3.DrawerValue +import androidx.compose.material3.rememberDrawerState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoTheme.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoTheme.kt new file mode 100644 index 000000000..e461d959a --- /dev/null +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/TodoTheme.kt @@ -0,0 +1,19 @@ +package com.example.android.architecture.blueprints.todoapp + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + +@Composable +fun TodoTheme(content: @Composable () -> Unit) { + MaterialTheme( + colorScheme = lightColorScheme( + primary = Color(0xFF263238), + secondary = Color(0xFF2E7D32), + tertiary = Color(0xFFCCCCCC), + ) + ) { + content() + } +} diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskScreen.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskScreen.kt index 26e381546..ef50627b6 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskScreen.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskScreen.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:OptIn(ExperimentalMaterial3Api::class) + package com.example.android.architecture.blueprints.todoapp.addedittask import androidx.annotation.StringRes @@ -24,21 +26,26 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.ContentAlpha -import androidx.compose.material.FloatingActionButton -import androidx.compose.material.Icon -import androidx.compose.material.MaterialTheme -import androidx.compose.material.OutlinedTextField -import androidx.compose.material.Scaffold -import androidx.compose.material.ScaffoldState -import androidx.compose.material.Text -import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Done -import androidx.compose.material.rememberScaffoldState +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.OutlinedTextFieldDefaults +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SmallFloatingActionButton +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.pulltorefresh.PullToRefreshBox +import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.dimensionResource @@ -46,29 +53,25 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.example.android.architecture.blueprints.todoapp.R import com.example.android.architecture.blueprints.todoapp.util.AddEditTaskTopAppBar -import com.google.accompanist.swiperefresh.SwipeRefresh -import com.google.accompanist.swiperefresh.rememberSwipeRefreshState -@OptIn(ExperimentalLifecycleComposeApi::class) @Composable fun AddEditTaskScreen( @StringRes topBarTitle: Int, onTaskUpdate: () -> Unit, onBack: () -> Unit, modifier: Modifier = Modifier, - scaffoldState: ScaffoldState = rememberScaffoldState(), - viewModel: AddEditTaskViewModel = hiltViewModel() + viewModel: AddEditTaskViewModel = hiltViewModel(), + snackbarHostState: SnackbarHostState = remember { SnackbarHostState() } ) { Scaffold( modifier = modifier.fillMaxSize(), - scaffoldState = scaffoldState, + snackbarHost = { SnackbarHost(snackbarHostState) }, topBar = { AddEditTaskTopAppBar(topBarTitle, onBack) }, floatingActionButton = { - FloatingActionButton(onClick = viewModel::saveTask) { + SmallFloatingActionButton(onClick = viewModel::saveTask) { Icon(Icons.Filled.Done, stringResource(id = R.string.cd_save_task)) } } @@ -94,8 +97,8 @@ fun AddEditTaskScreen( // Check for user messages to display on the screen uiState.userMessage?.let { userMessage -> val snackbarText = stringResource(userMessage) - LaunchedEffect(scaffoldState, viewModel, userMessage, snackbarText) { - scaffoldState.snackbarHostState.showSnackbar(snackbarText) + LaunchedEffect(snackbarHostState, viewModel, userMessage, snackbarText) { + snackbarHostState.showSnackbar(snackbarText) viewModel.snackbarMessageShown() } } @@ -111,12 +114,14 @@ private fun AddEditTaskContent( onDescriptionChanged: (String) -> Unit, modifier: Modifier = Modifier ) { + var isRefreshing by remember { mutableStateOf(false) } + val refreshingState = rememberPullToRefreshState() if (loading) { - SwipeRefresh( - // Show the loading spinner—`loading` is `true` in this code path - state = rememberSwipeRefreshState(true), + PullToRefreshBox( + isRefreshing = isRefreshing, + state = refreshingState, onRefresh = { /* DO NOTHING */ }, - content = { }, + content = { } ) } else { Column( @@ -125,10 +130,10 @@ private fun AddEditTaskContent( .padding(all = dimensionResource(id = R.dimen.horizontal_margin)) .verticalScroll(rememberScrollState()) ) { - val textFieldColors = TextFieldDefaults.outlinedTextFieldColors( + val textFieldColors = OutlinedTextFieldDefaults.colors( focusedBorderColor = Color.Transparent, unfocusedBorderColor = Color.Transparent, - cursorColor = MaterialTheme.colors.secondary.copy(alpha = ContentAlpha.high) + cursorColor = MaterialTheme.colorScheme.onSecondary ) OutlinedTextField( value = title, @@ -137,10 +142,11 @@ private fun AddEditTaskContent( placeholder = { Text( text = stringResource(id = R.string.title_hint), - style = MaterialTheme.typography.h6 + style = MaterialTheme.typography.headlineSmall ) }, - textStyle = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Bold), + textStyle = MaterialTheme.typography.headlineSmall + .copy(fontWeight = FontWeight.Bold), maxLines = 1, colors = textFieldColors ) diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskViewModel.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskViewModel.kt index 247573042..30c90f822 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskViewModel.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskViewModel.kt @@ -23,12 +23,12 @@ import com.example.android.architecture.blueprints.todoapp.R import com.example.android.architecture.blueprints.todoapp.TodoDestinationsArgs import com.example.android.architecture.blueprints.todoapp.data.TaskRepository import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import javax.inject.Inject /** * UiState for the Add/Edit screen diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/DefaultTaskRepository.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/DefaultTaskRepository.kt index 9fa32de87..7d61755a6 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/DefaultTaskRepository.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/DefaultTaskRepository.kt @@ -20,15 +20,15 @@ import com.example.android.architecture.blueprints.todoapp.data.source.local.Tas import com.example.android.architecture.blueprints.todoapp.data.source.network.NetworkDataSource import com.example.android.architecture.blueprints.todoapp.di.ApplicationScope import com.example.android.architecture.blueprints.todoapp.di.DefaultDispatcher -import java.util.UUID -import javax.inject.Inject -import javax.inject.Singleton import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import java.util.UUID +import javax.inject.Inject +import javax.inject.Singleton /** * Default implementation of [TaskRepository]. Single entry point for managing tasks' data. diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/network/TaskNetworkDataSource.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/network/TaskNetworkDataSource.kt index 3f248fc3a..8103d65fb 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/network/TaskNetworkDataSource.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/network/TaskNetworkDataSource.kt @@ -16,10 +16,10 @@ package com.example.android.architecture.blueprints.todoapp.data.source.network -import javax.inject.Inject import kotlinx.coroutines.delay import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import javax.inject.Inject class TaskNetworkDataSource @Inject constructor() : NetworkDataSource { diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/di/CoroutinesModule.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/di/CoroutinesModule.kt index 262d52e39..4c38330b3 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/di/CoroutinesModule.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/di/CoroutinesModule.kt @@ -20,12 +20,12 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import javax.inject.Qualifier -import javax.inject.Singleton import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob +import javax.inject.Qualifier +import javax.inject.Singleton @Qualifier @Retention(AnnotationRetention.RUNTIME) diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsScreen.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsScreen.kt index cd5b24d71..4bb2c4ba0 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsScreen.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsScreen.kt @@ -22,36 +22,35 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Scaffold -import androidx.compose.material.ScaffoldState -import androidx.compose.material.Surface -import androidx.compose.material.Text -import androidx.compose.material.rememberScaffoldState +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.example.android.architecture.blueprints.todoapp.R import com.example.android.architecture.blueprints.todoapp.util.LoadingContent import com.example.android.architecture.blueprints.todoapp.util.StatisticsTopAppBar -import com.google.accompanist.appcompattheme.AppCompatTheme -@OptIn(ExperimentalLifecycleComposeApi::class) @Composable fun StatisticsScreen( openDrawer: () -> Unit, modifier: Modifier = Modifier, viewModel: StatisticsViewModel = hiltViewModel(), - scaffoldState: ScaffoldState = rememberScaffoldState() + snackbarHostState: SnackbarHostState = remember { SnackbarHostState() } ) { Scaffold( - scaffoldState = scaffoldState, - topBar = { StatisticsTopAppBar(openDrawer) } + modifier = modifier.fillMaxSize(), + snackbarHost = { SnackbarHost(snackbarHostState) }, + topBar = { StatisticsTopAppBar(openDrawer) }, ) { paddingValues -> val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -76,7 +75,7 @@ private fun StatisticsContent( modifier: Modifier = Modifier ) { val commonModifier = modifier - .fillMaxWidth() + .fillMaxSize() .padding(all = dimensionResource(id = R.dimen.horizontal_margin)) LoadingContent( @@ -112,31 +111,21 @@ private fun StatisticsContent( @Preview @Composable fun StatisticsContentPreview() { - AppCompatTheme { - Surface { - StatisticsContent( - loading = false, - empty = false, - activeTasksPercent = 80f, - completedTasksPercent = 20f, - onRefresh = { } - ) - } + Surface { + StatisticsContent( + loading = false, + empty = false, + activeTasksPercent = 80f, + completedTasksPercent = 20f, + onRefresh = { } + ) } } @Preview @Composable fun StatisticsContentEmptyPreview() { - AppCompatTheme { - Surface { - StatisticsContent( - loading = false, - empty = true, - activeTasksPercent = 0f, - completedTasksPercent = 0f, - onRefresh = { } - ) - } + Surface { + StatisticsScreen({}) } } diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsViewModel.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsViewModel.kt index 4db5c1f22..ac575e629 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsViewModel.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/statistics/StatisticsViewModel.kt @@ -24,12 +24,12 @@ import com.example.android.architecture.blueprints.todoapp.data.TaskRepository import com.example.android.architecture.blueprints.todoapp.util.Async import com.example.android.architecture.blueprints.todoapp.util.WhileUiSubscribed import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject /** * UiState for the statistics screen. diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailScreen.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailScreen.kt index 814377da3..7720815a9 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailScreen.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailScreen.kt @@ -23,34 +23,32 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Checkbox -import androidx.compose.material.FloatingActionButton -import androidx.compose.material.Icon -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Scaffold -import androidx.compose.material.ScaffoldState -import androidx.compose.material.Surface -import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Edit -import androidx.compose.material.rememberScaffoldState +import androidx.compose.material3.Checkbox +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SmallFloatingActionButton +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.example.android.architecture.blueprints.todoapp.R import com.example.android.architecture.blueprints.todoapp.data.Task import com.example.android.architecture.blueprints.todoapp.util.LoadingContent import com.example.android.architecture.blueprints.todoapp.util.TaskDetailTopAppBar -import com.google.accompanist.appcompattheme.AppCompatTheme -@OptIn(ExperimentalLifecycleComposeApi::class) @Composable fun TaskDetailScreen( onEditTask: (String) -> Unit, @@ -58,16 +56,15 @@ fun TaskDetailScreen( onDeleteTask: () -> Unit, modifier: Modifier = Modifier, viewModel: TaskDetailViewModel = hiltViewModel(), - scaffoldState: ScaffoldState = rememberScaffoldState() + snackbarHostState: SnackbarHostState = remember { SnackbarHostState() } + ) { Scaffold( - scaffoldState = scaffoldState, modifier = modifier.fillMaxSize(), - topBar = { - TaskDetailTopAppBar(onBack = onBack, onDelete = viewModel::deleteTask) - }, + snackbarHost = { SnackbarHost(snackbarHostState) }, + topBar = { TaskDetailTopAppBar(onBack = onBack, onDelete = viewModel::deleteTask) }, floatingActionButton = { - FloatingActionButton(onClick = { onEditTask(viewModel.taskId) }) { + SmallFloatingActionButton(onClick = { onEditTask(viewModel.taskId) }) { Icon(Icons.Filled.Edit, stringResource(id = R.string.edit_task)) } } @@ -86,8 +83,8 @@ fun TaskDetailScreen( // Check for user messages to display on the screen uiState.userMessage?.let { userMessage -> val snackbarText = stringResource(userMessage) - LaunchedEffect(scaffoldState, viewModel, userMessage, snackbarText) { - scaffoldState.snackbarHostState.showSnackbar(snackbarText) + LaunchedEffect(snackbarHostState, viewModel, userMessage, snackbarText) { + snackbarHostState.showSnackbar(snackbarText) viewModel.snackbarMessageShown() } } @@ -139,8 +136,8 @@ private fun EditTaskContent( if (task != null) { Checkbox(task.isCompleted, onTaskCheck) Column { - Text(text = task.title, style = MaterialTheme.typography.h6) - Text(text = task.description, style = MaterialTheme.typography.body1) + Text(text = task.title, style = MaterialTheme.typography.headlineSmall) + Text(text = task.description, style = MaterialTheme.typography.bodySmall) } } } @@ -151,62 +148,57 @@ private fun EditTaskContent( @Preview @Composable private fun EditTaskContentPreview() { - AppCompatTheme { - Surface { - EditTaskContent( - loading = false, - empty = false, - Task( - title = "Title", - description = "Description", - isCompleted = false, - id = "ID" - ), - onTaskCheck = { }, - onRefresh = { } - ) - } + Surface { + EditTaskContent( + loading = false, + empty = false, + Task( + title = "Title", + description = "Description", + isCompleted = false, + id = "ID" + ), + onTaskCheck = { }, + onRefresh = { } + ) } + } @Preview @Composable private fun EditTaskContentTaskCompletedPreview() { - AppCompatTheme { - Surface { - EditTaskContent( - loading = false, - empty = false, - Task( - title = "Title", - description = "Description", - isCompleted = false, - id = "ID" - ), - onTaskCheck = { }, - onRefresh = { } - ) - } + Surface { + EditTaskContent( + loading = false, + empty = false, + Task( + title = "Title", + description = "Description", + isCompleted = false, + id = "ID" + ), + onTaskCheck = { }, + onRefresh = { } + ) } } @Preview @Composable private fun EditTaskContentEmptyPreview() { - AppCompatTheme { - Surface { - EditTaskContent( - loading = false, - empty = true, - Task( - title = "Title", - description = "Description", - isCompleted = false, - id = "ID" - ), - onTaskCheck = { }, - onRefresh = { } - ) - } + Surface { + EditTaskContent( + loading = false, + empty = true, + Task( + title = "Title", + description = "Description", + isCompleted = false, + id = "ID" + ), + onTaskCheck = { }, + onRefresh = { } + ) } } diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailViewModel.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailViewModel.kt index 080b22c04..6297ecf1b 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailViewModel.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/taskdetail/TaskDetailViewModel.kt @@ -26,7 +26,6 @@ import com.example.android.architecture.blueprints.todoapp.data.TaskRepository import com.example.android.architecture.blueprints.todoapp.util.Async import com.example.android.architecture.blueprints.todoapp.util.WhileUiSubscribed import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch @@ -34,6 +33,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject /** * UiState for the Details screen. diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreen.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreen.kt index 16cf81e86..395865d0a 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreen.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksScreen.kt @@ -29,20 +29,21 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material.Checkbox -import androidx.compose.material.FloatingActionButton -import androidx.compose.material.Icon -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Scaffold -import androidx.compose.material.ScaffoldState -import androidx.compose.material.Surface -import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add -import androidx.compose.material.rememberScaffoldState +import androidx.compose.material3.Checkbox +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SmallFloatingActionButton +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -53,18 +54,16 @@ import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.example.android.architecture.blueprints.todoapp.R +import com.example.android.architecture.blueprints.todoapp.TodoTheme import com.example.android.architecture.blueprints.todoapp.data.Task import com.example.android.architecture.blueprints.todoapp.tasks.TasksFilterType.ACTIVE_TASKS import com.example.android.architecture.blueprints.todoapp.tasks.TasksFilterType.ALL_TASKS import com.example.android.architecture.blueprints.todoapp.tasks.TasksFilterType.COMPLETED_TASKS import com.example.android.architecture.blueprints.todoapp.util.LoadingContent import com.example.android.architecture.blueprints.todoapp.util.TasksTopAppBar -import com.google.accompanist.appcompattheme.AppCompatTheme -@OptIn(ExperimentalLifecycleComposeApi::class) @Composable fun TasksScreen( @StringRes userMessage: Int, @@ -74,10 +73,11 @@ fun TasksScreen( openDrawer: () -> Unit, modifier: Modifier = Modifier, viewModel: TasksViewModel = hiltViewModel(), - scaffoldState: ScaffoldState = rememberScaffoldState() + snackbarHostState: SnackbarHostState = remember { SnackbarHostState() } ) { Scaffold( - scaffoldState = scaffoldState, + modifier = modifier.fillMaxSize(), + snackbarHost = { SnackbarHost(snackbarHostState) }, topBar = { TasksTopAppBar( openDrawer = openDrawer, @@ -88,9 +88,8 @@ fun TasksScreen( onRefresh = { viewModel.refresh() } ) }, - modifier = modifier.fillMaxSize(), floatingActionButton = { - FloatingActionButton(onClick = onAddTask) { + SmallFloatingActionButton(onClick = onAddTask) { Icon(Icons.Filled.Add, stringResource(id = R.string.add_task)) } } @@ -112,8 +111,8 @@ fun TasksScreen( // Check for user messages to display on the screen uiState.userMessage?.let { message -> val snackbarText = stringResource(message) - LaunchedEffect(scaffoldState, viewModel, message, snackbarText) { - scaffoldState.snackbarHostState.showSnackbar(snackbarText) + LaunchedEffect(snackbarHostState, viewModel, message, snackbarText) { + snackbarHostState.showSnackbar(snackbarText) viewModel.snackbarMessageShown() } } @@ -158,7 +157,7 @@ private fun TasksContent( horizontal = dimensionResource(id = R.dimen.list_item_padding), vertical = dimensionResource(id = R.dimen.vertical_margin) ), - style = MaterialTheme.typography.h6 + style = MaterialTheme.typography.headlineSmall ) LazyColumn { items(tasks) { task -> @@ -195,7 +194,7 @@ private fun TaskItem( ) Text( text = task.titleForList, - style = MaterialTheme.typography.h6, + style = MaterialTheme.typography.headlineSmall, modifier = Modifier.padding( start = dimensionResource(id = R.dimen.horizontal_margin) ), @@ -231,7 +230,7 @@ private fun TasksEmptyContent( @Preview @Composable private fun TasksContentPreview() { - AppCompatTheme { + MaterialTheme { Surface { TasksContent( loading = false, @@ -281,7 +280,7 @@ private fun TasksContentPreview() { @Preview @Composable private fun TasksContentEmptyPreview() { - AppCompatTheme { + MaterialTheme { Surface { TasksContent( loading = false, @@ -300,7 +299,7 @@ private fun TasksContentEmptyPreview() { @Preview @Composable private fun TasksEmptyContentPreview() { - AppCompatTheme { + TodoTheme { Surface { TasksEmptyContent( noTasksLabel = R.string.no_tasks_all, @@ -313,7 +312,7 @@ private fun TasksEmptyContentPreview() { @Preview @Composable private fun TaskItemPreview() { - AppCompatTheme { + MaterialTheme { Surface { TaskItem( task = Task( @@ -331,7 +330,7 @@ private fun TaskItemPreview() { @Preview @Composable private fun TaskItemCompletedPreview() { - AppCompatTheme { + MaterialTheme { Surface { TaskItem( task = Task( diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModel.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModel.kt index 9868f80a7..f95b2d273 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModel.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModel.kt @@ -31,7 +31,6 @@ import com.example.android.architecture.blueprints.todoapp.tasks.TasksFilterType import com.example.android.architecture.blueprints.todoapp.util.Async import com.example.android.architecture.blueprints.todoapp.util.WhileUiSubscribed import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch @@ -40,6 +39,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject /** * UiState for the task list screen. diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/util/TodoDrawer.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/util/TodoDrawer.kt index 8e5ed06af..16e8fc154 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/util/TodoDrawer.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/util/TodoDrawer.kt @@ -27,13 +27,13 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width -import androidx.compose.material.DrawerState -import androidx.compose.material.Icon -import androidx.compose.material.MaterialTheme -import androidx.compose.material.ModalDrawer -import androidx.compose.material.Surface -import androidx.compose.material.Text -import androidx.compose.material.TextButton +import androidx.compose.material3.DrawerState +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalNavigationDrawer +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment @@ -47,7 +47,7 @@ import androidx.compose.ui.unit.dp import com.example.android.architecture.blueprints.todoapp.R import com.example.android.architecture.blueprints.todoapp.TodoDestinations import com.example.android.architecture.blueprints.todoapp.TodoNavigationActions -import com.google.accompanist.appcompattheme.AppCompatTheme +import com.example.android.architecture.blueprints.todoapp.TodoTheme import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -59,7 +59,7 @@ fun AppModalDrawer( coroutineScope: CoroutineScope = rememberCoroutineScope(), content: @Composable () -> Unit ) { - ModalDrawer( + ModalNavigationDrawer( drawerState = drawerState, drawerContent = { AppDrawer( @@ -82,26 +82,28 @@ private fun AppDrawer( closeDrawer: () -> Unit, modifier: Modifier = Modifier ) { - Column(modifier = modifier.fillMaxSize()) { - DrawerHeader() - DrawerButton( - painter = painterResource(id = R.drawable.ic_list), - label = stringResource(id = R.string.list_title), - isSelected = currentRoute == TodoDestinations.TASKS_ROUTE, - action = { - navigateToTasks() - closeDrawer() - } - ) - DrawerButton( - painter = painterResource(id = R.drawable.ic_statistics), - label = stringResource(id = R.string.statistics_title), - isSelected = currentRoute == TodoDestinations.STATISTICS_ROUTE, - action = { - navigateToStatistics() - closeDrawer() - } - ) + Surface(color = MaterialTheme.colorScheme.background) { + Column(modifier = modifier.fillMaxSize()) { + DrawerHeader() + DrawerButton( + painter = painterResource(id = R.drawable.ic_list), + label = stringResource(id = R.string.list_title), + isSelected = currentRoute == TodoDestinations.TASKS_ROUTE, + action = { + navigateToTasks() + closeDrawer() + } + ) + DrawerButton( + painter = painterResource(id = R.drawable.ic_statistics), + label = stringResource(id = R.string.statistics_title), + isSelected = currentRoute == TodoDestinations.STATISTICS_ROUTE, + action = { + navigateToStatistics() + closeDrawer() + } + ) + } } } @@ -126,7 +128,7 @@ private fun DrawerHeader( ) Text( text = stringResource(id = R.string.navigation_view_header_title), - color = MaterialTheme.colors.surface + color = MaterialTheme.colorScheme.surface ) } } @@ -140,9 +142,9 @@ private fun DrawerButton( modifier: Modifier = Modifier ) { val tintColor = if (isSelected) { - MaterialTheme.colors.secondary + MaterialTheme.colorScheme.secondary } else { - MaterialTheme.colors.onSurface.copy(alpha = 0.6f) + MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) } TextButton( @@ -164,7 +166,7 @@ private fun DrawerButton( Spacer(Modifier.width(16.dp)) Text( text = label, - style = MaterialTheme.typography.body2, + style = MaterialTheme.typography.bodySmall, color = tintColor ) } @@ -174,7 +176,7 @@ private fun DrawerButton( @Preview("Drawer contents") @Composable fun PreviewAppDrawer() { - AppCompatTheme { + TodoTheme { Surface { AppDrawer( currentRoute = TodoDestinations.TASKS_ROUTE, diff --git a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/util/TopAppBars.kt b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/util/TopAppBars.kt index abf26cc2e..9e3b11cc0 100644 --- a/app/src/main/java/com/example/android/architecture/blueprints/todoapp/util/TopAppBars.kt +++ b/app/src/main/java/com/example/android/architecture/blueprints/todoapp/util/TopAppBars.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:OptIn(ExperimentalMaterial3Api::class) + package com.example.android.architecture.blueprints.todoapp.util import androidx.annotation.StringRes @@ -21,18 +23,20 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.material.DropdownMenu -import androidx.compose.material.DropdownMenuItem -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.Surface -import androidx.compose.material.Text -import androidx.compose.material.TopAppBar import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -44,7 +48,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.example.android.architecture.blueprints.todoapp.R -import com.google.accompanist.appcompattheme.AppCompatTheme +import com.example.android.architecture.blueprints.todoapp.TodoTheme @Composable fun TasksTopAppBar( @@ -84,15 +88,15 @@ private fun FilterTasksMenu( ) } ) { closeMenu -> - DropdownMenuItem(onClick = { onFilterAllTasks(); closeMenu() }) { - Text(text = stringResource(id = R.string.nav_all)) - } - DropdownMenuItem(onClick = { onFilterActiveTasks(); closeMenu() }) { - Text(text = stringResource(id = R.string.nav_active)) - } - DropdownMenuItem(onClick = { onFilterCompletedTasks(); closeMenu() }) { - Text(text = stringResource(id = R.string.nav_completed)) - } + DropdownMenuItem(onClick = { onFilterAllTasks(); closeMenu() }, + text = { Text(text = stringResource(id = R.string.nav_all)) } + ) + DropdownMenuItem(onClick = { onFilterActiveTasks(); closeMenu() }, + text = { Text(text = stringResource(id = R.string.nav_active)) } + ) + DropdownMenuItem(onClick = { onFilterCompletedTasks(); closeMenu() }, + text = { Text(text = stringResource(id = R.string.nav_completed)) } + ) } } @@ -106,12 +110,14 @@ private fun MoreTasksMenu( Icon(Icons.Filled.MoreVert, stringResource(id = R.string.menu_more)) } ) { closeMenu -> - DropdownMenuItem(onClick = { onClearCompletedTasks(); closeMenu() }) { - Text(text = stringResource(id = R.string.menu_clear)) - } - DropdownMenuItem(onClick = { onRefresh(); closeMenu() }) { - Text(text = stringResource(id = R.string.refresh)) - } + DropdownMenuItem( + text = { Text(text = stringResource(id = R.string.menu_clear)) }, + onClick = { onClearCompletedTasks(); closeMenu() } + ) + DropdownMenuItem( + text = { Text(text = stringResource(id = R.string.refresh)) }, + onClick = { onRefresh(); closeMenu() } + ) } } @@ -175,7 +181,7 @@ fun AddEditTaskTopAppBar(@StringRes title: Int, onBack: () -> Unit) { title = { Text(text = stringResource(title)) }, navigationIcon = { IconButton(onClick = onBack) { - Icon(Icons.Filled.ArrowBack, stringResource(id = R.string.menu_back)) + Icon(Icons.AutoMirrored.Filled.ArrowBack, stringResource(id = R.string.menu_back)) } }, modifier = Modifier.fillMaxWidth() @@ -185,7 +191,7 @@ fun AddEditTaskTopAppBar(@StringRes title: Int, onBack: () -> Unit) { @Preview @Composable private fun TasksTopAppBarPreview() { - AppCompatTheme { + TodoTheme { Surface { TasksTopAppBar({}, {}, {}, {}, {}, {}) } @@ -195,7 +201,7 @@ private fun TasksTopAppBarPreview() { @Preview @Composable private fun StatisticsTopAppBarPreview() { - AppCompatTheme { + TodoTheme { Surface { StatisticsTopAppBar { } } @@ -205,7 +211,7 @@ private fun StatisticsTopAppBarPreview() { @Preview @Composable private fun TaskDetailTopAppBarPreview() { - AppCompatTheme { + TodoTheme { Surface { TaskDetailTopAppBar({ }, { }) } @@ -215,7 +221,7 @@ private fun TaskDetailTopAppBarPreview() { @Preview @Composable private fun AddEditTaskTopAppBarPreview() { - AppCompatTheme { + TodoTheme { Surface { AddEditTaskTopAppBar(R.string.add_task) { } } diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml deleted file mode 100644 index e42c06cbf..000000000 --- a/app/src/main/res/values-v21/styles.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index cfa6d2bfb..103997705 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -14,28 +14,24 @@ See the License for the specific language governing permissions and limitations under the License. --> - + - - - - -