From 86be093a351cfc9112ed25de121885a82c65c03d Mon Sep 17 00:00:00 2001 From: ksenianeva <95441235+ksenianeva@users.noreply.github.com> Date: Tue, 21 Nov 2023 23:50:31 +0400 Subject: [PATCH] 2nd lab --- app/build.gradle.kts | 7 +- .../com/example/myapplication/MainActivity.kt | 3 +- .../category/composeui/CategotyList.kt | 47 ++++++ .../myapplication/category/model/Category.kt | 15 ++ .../challenge/model/Challenge.kt | 19 +++ .../example/myapplication/composeui/About.kt | 46 ++++++ .../composeui/navigation/MainNavbar.kt | 154 ++++++++++++++++++ .../composeui/navigation/Screen.kt | 43 +++++ .../myapplication/user/composeui/UserView.kt | 69 ++++++++ .../myapplication/user/composeui/UsersList.kt | 57 +++++++ .../example/myapplication/user/model/User.kt | 22 +++ app/src/main/res/values/strings.xml | 15 ++ 12 files changed, 493 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/com/example/myapplication/category/composeui/CategotyList.kt create mode 100644 app/src/main/java/com/example/myapplication/category/model/Category.kt create mode 100644 app/src/main/java/com/example/myapplication/challenge/model/Challenge.kt create mode 100644 app/src/main/java/com/example/myapplication/composeui/About.kt create mode 100644 app/src/main/java/com/example/myapplication/composeui/navigation/MainNavbar.kt create mode 100644 app/src/main/java/com/example/myapplication/composeui/navigation/Screen.kt create mode 100644 app/src/main/java/com/example/myapplication/user/composeui/UserView.kt create mode 100644 app/src/main/java/com/example/myapplication/user/composeui/UsersList.kt create mode 100644 app/src/main/java/com/example/myapplication/user/model/User.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b2ff921..fd90055 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -47,11 +47,12 @@ android { } dependencies { - implementation("androidx.core:core-ktx:1.9.0") - implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1") - implementation("androidx.activity:activity-compose:1.7.0") + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") + implementation("androidx.activity:activity-compose:1.7.2") implementation(platform("androidx.compose:compose-bom:2023.03.00")) + implementation("androidx.navigation:navigation-compose:2.6.0") + implementation("io.coil-kt:coil-compose:2.4.0") implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-graphics") implementation("androidx.compose.ui:ui-tooling-preview") diff --git a/app/src/main/java/com/example/myapplication/MainActivity.kt b/app/src/main/java/com/example/myapplication/MainActivity.kt index 1abe739..3a21706 100644 --- a/app/src/main/java/com/example/myapplication/MainActivity.kt +++ b/app/src/main/java/com/example/myapplication/MainActivity.kt @@ -10,6 +10,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview +import com.example.myapplication.composeui.navigation.MainNavbar import com.example.myapplication.ui.theme.MyApplicationTheme class MainActivity : ComponentActivity() { @@ -19,7 +20,7 @@ class MainActivity : ComponentActivity() { MyApplicationTheme { // A surface container using the 'background' color from the theme Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { - Greeting("World") + MainNavbar() } } } diff --git a/app/src/main/java/com/example/myapplication/category/composeui/CategotyList.kt b/app/src/main/java/com/example/myapplication/category/composeui/CategotyList.kt new file mode 100644 index 0000000..6a41ffd --- /dev/null +++ b/app/src/main/java/com/example/myapplication/category/composeui/CategotyList.kt @@ -0,0 +1,47 @@ +package com.example.myapplication.category.composeui + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.example.myapplication.category.model.getTestCategory +import com.example.myapplication.ui.theme.MyApplicationTheme + +@Composable +fun CategoriesList(navController: NavController?) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .padding(all = 10.dp) + .verticalScroll(rememberScrollState())) { + getTestCategory().forEachIndexed() { _, category -> + Row(Modifier.padding(all = 20.dp)) { + Text(category.category_name) + } + } + } +} + +@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +fun CategoryPreview() { + MyApplicationTheme { + Surface( + color = MaterialTheme.colorScheme.background + ) { + CategoriesList(navController = null) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/category/model/Category.kt b/app/src/main/java/com/example/myapplication/category/model/Category.kt new file mode 100644 index 0000000..5e69fa7 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/category/model/Category.kt @@ -0,0 +1,15 @@ +package com.example.myapplication.category.model + +import java.io.Serializable + +data class Category( + val category_name: String, +) : Serializable + +fun getTestCategory(): List { + return listOf( + Category("Отжимания"), + Category("Кардио"), + Category("Силовые") + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/challenge/model/Challenge.kt b/app/src/main/java/com/example/myapplication/challenge/model/Challenge.kt new file mode 100644 index 0000000..071a672 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/challenge/model/Challenge.kt @@ -0,0 +1,19 @@ +package com.example.myapplication.challenge.model + +import com.example.myapplication.category.model.Category +import java.io.Serializable + +data class Challenge( + val challenge_name: String, + val challenge_status: Boolean, + val category: Category, +) : Serializable + +fun getTestChallenge(): List { + val сategory = Category("Отжимания") + return listOf( + Challenge("Сделать 20 отжиманий", false, сategory), + Challenge("Сделать 10 отжиманий", false, сategory), + Challenge("Сделать 5 отжиманий", false, сategory), + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/composeui/About.kt b/app/src/main/java/com/example/myapplication/composeui/About.kt new file mode 100644 index 0000000..0a94da5 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/composeui/About.kt @@ -0,0 +1,46 @@ +package com.example.myapplication.composeui + +import android.content.res.Configuration +import android.widget.TextView +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView +import com.example.myapplication.ui.theme.MyApplicationTheme +import com.example.myapplication.R; + +@Composable +fun About() { + val localContext = LocalContext.current + val aboutText = localContext.resources.getText(R.string.about_text) + + Column(Modifier.padding(all = 10.dp)) { + AndroidView( + modifier = Modifier + .fillMaxWidth(), + factory = { context -> TextView(context) }, + update = { it.text = aboutText } + ) + } +} + +@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +fun AboutPreview() { + MyApplicationTheme { + Surface( + color = MaterialTheme.colorScheme.background + ) { + About() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/composeui/navigation/MainNavbar.kt b/app/src/main/java/com/example/myapplication/composeui/navigation/MainNavbar.kt new file mode 100644 index 0000000..6ee7d1f --- /dev/null +++ b/app/src/main/java/com/example/myapplication/composeui/navigation/MainNavbar.kt @@ -0,0 +1,154 @@ +package com.example.myapplication.composeui.navigation +import android.content.res.Configuration +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.navigation.NavDestination +import androidx.navigation.NavDestination.Companion.hierarchy +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.NavHostController +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument +import com.example.myapplication.R +import com.example.myapplication.category.composeui.CategoriesList +import com.example.myapplication.composeui.About +import com.example.myapplication.ui.theme.MyApplicationTheme +import com.example.myapplication.user.composeui.UserView +import com.example.myapplication.user.composeui.UsersList + + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun Topbar( + navController: NavHostController, + currentScreen: Screen? +) { + TopAppBar( + colors = TopAppBarDefaults.smallTopAppBarColors( + containerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + ), + title = { + Text(stringResource(currentScreen?.resourceId ?: R.string.app_name)) + }, + navigationIcon = { + if ( + navController.previousBackStackEntry != null + && (currentScreen == null || !currentScreen.showInBottomBar) + ) { + IconButton(onClick = { navController.navigateUp() }) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = null, + tint = MaterialTheme.colorScheme.onPrimary + ) + } + } + } + ) +} + +@Composable +fun Navbar( + navController: NavHostController, + currentDestination: NavDestination?, + modifier: Modifier = Modifier +) { + NavigationBar(modifier) { + Screen.bottomBarItems.forEach { screen -> + NavigationBarItem( + icon = { Icon(screen.icon, contentDescription = null) }, + label = { Text(stringResource(screen.resourceId)) }, + selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true, + onClick = { + navController.navigate(screen.route) { + popUpTo(navController.graph.findStartDestination().id) { + saveState = true + } + launchSingleTop = true + restoreState = true + } + } + ) + } + } +} + +@Composable +fun Navhost( + navController: NavHostController, + innerPadding: PaddingValues, modifier: + Modifier = Modifier +) { + NavHost( + navController, + startDestination = Screen.About.route, + modifier.padding(innerPadding) + ) { + composable(Screen.CategoryList.route) { CategoriesList(navController)} + composable(Screen.About.route) { About() } + composable(Screen.UserList.route) { UsersList(navController)} + composable( + Screen.UserView.route, + arguments = listOf(navArgument("id") { type = NavType.IntType }) + ) { backStackEntry -> + backStackEntry.arguments?.let { UserView(it.getInt("id")) } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MainNavbar() { + val navController = rememberNavController() + val navBackStackEntry by navController.currentBackStackEntryAsState() + val currentDestination = navBackStackEntry?.destination + val currentScreen = currentDestination?.route?.let { Screen.getItem(it) } + + Scaffold( + topBar = { + Topbar(navController, currentScreen) + }, + bottomBar = { + if (currentScreen == null || currentScreen.showInBottomBar) { + Navbar(navController, currentDestination) + } + } + ) { innerPadding -> + Navhost(navController, innerPadding) + } +} + +@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +fun MainNavbarPreview() { + MyApplicationTheme { + Surface( + color = MaterialTheme.colorScheme.background + ) { + MainNavbar() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/composeui/navigation/Screen.kt b/app/src/main/java/com/example/myapplication/composeui/navigation/Screen.kt new file mode 100644 index 0000000..568a83a --- /dev/null +++ b/app/src/main/java/com/example/myapplication/composeui/navigation/Screen.kt @@ -0,0 +1,43 @@ +package com.example.myapplication.composeui.navigation + +import androidx.annotation.StringRes +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.material.icons.filled.Info +import androidx.compose.material.icons.filled.List +import androidx.compose.material.icons.filled.Person +import androidx.compose.ui.graphics.vector.ImageVector +import com.example.myapplication.R + +enum class Screen( + val route: String, + @StringRes val resourceId: Int, + val icon: ImageVector = Icons.Filled.Favorite, + val showInBottomBar: Boolean = true +) { + CategoryList( + "categories-list", R.string.categories_list, Icons.Filled.List + ), + UserList( + "users-list", R.string.user_list, Icons.Filled.Person + ), + About( + "about", R.string.about_main_title, Icons.Filled.Info + ), + UserView( + "user-view/{id}", R.string.user_view_title, showInBottomBar = false + ); + + companion object { + val bottomBarItems = listOf( + CategoryList, + UserList, + About, + ) + + fun getItem(route: String): Screen? { + val findRoute = route.split("/").first() + return values().find { value -> value.route.startsWith(findRoute) } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/user/composeui/UserView.kt b/app/src/main/java/com/example/myapplication/user/composeui/UserView.kt new file mode 100644 index 0000000..6738f69 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/user/composeui/UserView.kt @@ -0,0 +1,69 @@ +package com.example.myapplication.user.composeui + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +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.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.example.myapplication.user.model.getTestUser +import com.example.myapplication.ui.theme.MyApplicationTheme +import com.example.myapplication.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun UserView(id: Int) { + var user = getTestUser()[id] + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .padding(all = 10.dp) + .verticalScroll(rememberScrollState())) { + OutlinedTextField(modifier = Modifier.fillMaxWidth(), value = user.login, onValueChange = {}, readOnly = true, + label = { + Text(stringResource(id = R.string.user_login)) + } + ) + OutlinedTextField(modifier = Modifier.fillMaxWidth(), value = user.fio, onValueChange = {}, readOnly = true, + label = { + Text(stringResource(id = R.string.user_fio)) + } + ) + user.challenges.forEachIndexed() { _, challenge -> + Row { + Text(text = challenge.challenge_name) + if (challenge.challenge_status) { + Text(text = " - Выполнено") + } + else { + Text(text = " - В процессе") + } + } + } + } +} + +@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +fun PerformanceViewPreview() { + MyApplicationTheme { + Surface( + color = MaterialTheme.colorScheme.background + ) { + UserView(id = 0) + } + } +} diff --git a/app/src/main/java/com/example/myapplication/user/composeui/UsersList.kt b/app/src/main/java/com/example/myapplication/user/composeui/UsersList.kt new file mode 100644 index 0000000..114dd28 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/user/composeui/UsersList.kt @@ -0,0 +1,57 @@ +package com.example.myapplication.user.composeui + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +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.material3.Button +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.example.myapplication.composeui.navigation.Screen +import com.example.myapplication.user.model.getTestUser +import com.example.myapplication.ui.theme.MyApplicationTheme + +@Composable +fun UsersList(navController: NavController?) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .padding(all = 10.dp) + .verticalScroll(rememberScrollState())) { + getTestUser().forEachIndexed() { _, user -> + val userId = Screen.UserView.route.replace("{id}", (user.id).toString()) + Row(Modifier.padding(all = 10.dp)) { + Button( + modifier = Modifier + .fillMaxWidth() + .padding(all = 10.dp), + onClick = { navController?.navigate(userId) }) { + Text(user.fio) + } + } + } + } +} + +@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +fun UserPreview() { + MyApplicationTheme { + Surface( + color = MaterialTheme.colorScheme.background + ) { + UsersList(navController = null) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/user/model/User.kt b/app/src/main/java/com/example/myapplication/user/model/User.kt new file mode 100644 index 0000000..5c69529 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/user/model/User.kt @@ -0,0 +1,22 @@ +package com.example.myapplication.user.model + +import com.example.myapplication.challenge.model.Challenge +import com.example.myapplication.challenge.model.getTestChallenge +import java.io.Serializable + +data class User( + val id: Int, + val login: String, + val password: String, + val fio: String, + val challenges: List, +) : Serializable + +fun getTestUser(): List { + val challenges = getTestChallenge() + return listOf( + User(0,"user1", "1234", "ivanov ivan", challenges), + User(1,"user2", "1234", "vasiliev ivan", challenges), + User(2,"user3", "1234", "listov ivan", challenges), + ) +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3de1a39..19c8459 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,18 @@ My Application + О нас + Пользователи + Категории + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Volutpat odio facilisis + mauris sit amet massa vitae. Arcu dui vivamus arcu felis bibendum ut tristique. + Leo in vitae turpis massa sed elementum. Tristique sollicitudin nibh sit amet commodo. + Donec ultrices tincidunt arcu non sodales neque sodales. Convallis aenean et tortor at. + Nisi est sit amet facilisis magna etiam tempor orci. Dignissim diam quis enim lobortis. + Lacus laoreet non curabitur gravida. Netus et malesuada fames ac turpis egestas maecenas. + Ornare aenean euismod elementum nisi quis eleifend. Elit sed vulputate mi sit. Sit amet + justo donec enim diam vulputate ut. Laoreet non curabitur gravida arcu. + Логин + ФИО + Пользователь \ No newline at end of file