Compare commits

...

3 Commits
main ... lab4

Author SHA1 Message Date
cf2d21d2eb Загрузка отчета по лабораторной 4. 2023-12-23 10:26:59 +04:00
ksenianeva
cb425c227b 3nd lab 2023-11-22 09:10:15 +04:00
ksenianeva
86be093a35 2nd lab 2023-11-21 23:50:31 +04:00
19 changed files with 752 additions and 9 deletions

View File

@ -1,6 +1,7 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.devtools.ksp")
}
android {
@ -9,7 +10,7 @@ android {
defaultConfig {
applicationId = "com.example.myapplication"
minSdk = 24
minSdk = 26
targetSdk = 33
versionCode = 1
versionName = "1.0"
@ -27,17 +28,17 @@ android {
}
}
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"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.3"
kotlinCompilerExtensionVersion = "1.4.5"
}
packaging {
resources {
@ -46,16 +47,34 @@ android {
}
}
dependencies {
kotlin {
jvmToolchain(17)
}
dependencies {
//Core
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")
//UI
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")
implementation("androidx.compose.material3:material3")
// Room
val room_version = "2.5.2"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")
ksp("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version")
implementation("androidx.room:room-paging:$room_version")
//Tests
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")

View File

@ -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()
}
}
}

View File

@ -0,0 +1,65 @@
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.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
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.navigation.NavController
import com.example.myapplication.category.model.Category
import com.example.myapplication.database.AppDatabase
import com.example.myapplication.ui.theme.MyApplicationTheme
import com.example.myapplication.user.model.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun CategoriesList(navController: NavController?) {
val context = LocalContext.current;
val categories = remember { mutableStateListOf<Category>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
AppDatabase.getInstance(context).categoryDao().getAll().collect { data ->
categories.clear()
categories.addAll(data)
}
}
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.padding(all = 10.dp)
.verticalScroll(rememberScrollState())) {
categories.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)
}
}
}

View File

@ -0,0 +1,27 @@
package com.example.myapplication.category.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Delete
import androidx.room.Update
import com.example.myapplication.category.model.Category
import kotlinx.coroutines.flow.Flow
@Dao
interface CategoryDao {
@Query("select * from categories order by category_name collate nocase asc")
fun getAll(): Flow<List<Category>>
@Query("select * from categories where categories.uid = :uid")
suspend fun getByUid(uid: Int): Category
@Insert
suspend fun insert(category: Category)
@Update
suspend fun update(category: Category)
@Delete
suspend fun delete(category: Category)
}

View File

@ -0,0 +1,11 @@
package com.example.myapplication.category.model
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "categories")
data class Category(
@PrimaryKey val uid: Int,
val category_name: String,
)

View File

@ -0,0 +1,27 @@
package com.example.myapplication.challenge.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Delete
import androidx.room.Update
import com.example.myapplication.challenge.model.Challenge
import kotlinx.coroutines.flow.Flow
@Dao
interface ChallengeDao {
@Query("select * from challenges order by challenge_name asc")
fun getAll(): Flow<List<Challenge>>
@Query("select * from challenges where challenges.challenge_id = :uid")
suspend fun getByUid(uid: Int): Challenge
@Insert
suspend fun insert(challenge: Challenge)
@Update
suspend fun update(challenge: Challenge)
@Delete
suspend fun delete(challenge: Challenge)
}

View File

@ -0,0 +1,33 @@
package com.example.myapplication.challenge.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import com.example.myapplication.category.model.Category
import com.example.myapplication.user.model.User
@Entity(tableName = "challenges", foreignKeys = [
ForeignKey(
entity = User::class,
parentColumns = ["uid"],
childColumns = ["user_id"],
onDelete = ForeignKey.RESTRICT,
onUpdate = ForeignKey.RESTRICT,
),
ForeignKey(
entity = Category::class,
parentColumns = ["uid"],
childColumns = ["category_id"],
onDelete = ForeignKey.RESTRICT,
onUpdate = ForeignKey.RESTRICT,
),
])
data class Challenge(
@PrimaryKey val challenge_id: Int,
val challenge_name: String,
val challenge_status: Boolean,
val category_id: Int,
@ColumnInfo(index = true)
val user_id: Int,
)

View File

@ -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()
}
}
}

View File

@ -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()
}
}
}

View File

@ -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) }
}
}
}

View File

@ -0,0 +1,79 @@
package com.example.myapplication.database
import java.util.concurrent.Flow
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.myapplication.category.dao.CategoryDao
import com.example.myapplication.category.model.Category
import com.example.myapplication.user.model.UserWithChallenges
import com.example.myapplication.challenge.dao.ChallengeDao
import com.example.myapplication.challenge.model.Challenge
import com.example.myapplication.user.dao.UserDao
import com.example.myapplication.user.model.User
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.time.LocalDate
@Database(entities = [User::class, Challenge::class, Category::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun challengeDao(): ChallengeDao
abstract fun categoryDao(): CategoryDao
abstract fun userDao(): UserDao
companion object {
private const val DB_NAME: String = "sport-app-db"
@Volatile
private var INSTANCE: AppDatabase? = null
private suspend fun populateDatabase() {
INSTANCE?.let { database ->
val categoryDao = database.categoryDao()
val category1 = Category(3, "Кардио")
val category2 = Category(4, "Силовые тренировки")
categoryDao.insert(category1)
categoryDao.insert(category2)
val userDao = database.userDao()
val user1 = User(3, "test1", "1234", "John")
val user2 = User(4, "test2", "1234", "Ivan")
userDao.insert(user1)
userDao.insert(user2)
val challengeDao = database.challengeDao()
val challenge1 = Challenge(3, "Сделать 10 отжиманий", false, category2.uid, user1.uid)
val challenge2 = Challenge(4, "Пробежать 1 км", true, category1.uid, user2.uid)
challengeDao.insert(challenge1)
challengeDao.insert(challenge2)
}
}
fun getInstance(appContext: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
Room.databaseBuilder(
appContext,
AppDatabase::class.java,
DB_NAME
)
.addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch {
populateDatabase()
}
}
})
.build()
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,91 @@
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.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.myapplication.ui.theme.MyApplicationTheme
import com.example.myapplication.R
import com.example.myapplication.database.AppDatabase
import com.example.myapplication.user.model.UserWithChallenges
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun UserView(id: Int) {
val context = LocalContext.current
val (userWithChallanges, setUserWithChallanges) = remember { mutableStateOf<UserWithChallenges?>(null) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
setUserWithChallanges(AppDatabase.getInstance(context).userDao().getByUid(id))
}
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.padding(all = 10.dp)
.verticalScroll(rememberScrollState())
) {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = userWithChallanges?.user?.login.toString(),
onValueChange = {},
readOnly = true,
label = {
Text(stringResource(id = R.string.user_login))
}
)
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = userWithChallanges?.user?.fio.toString(),
onValueChange = {},
readOnly = true,
label = {
Text(stringResource(id = R.string.user_fio))
}
)
userWithChallanges?.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)
}
}
}

View File

@ -0,0 +1,75 @@
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.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
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.navigation.NavController
import com.example.myapplication.composeui.navigation.Screen
import com.example.myapplication.database.AppDatabase
import com.example.myapplication.ui.theme.MyApplicationTheme
import com.example.myapplication.user.model.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.withContext
@Composable
fun UsersList(navController: NavController?) {
val context = LocalContext.current;
val users = remember { mutableStateListOf<User>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
AppDatabase.getInstance(context).userDao().getAll().collect { data ->
users.clear()
users.addAll(data)
}
}
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.padding(all = 10.dp)
.verticalScroll(rememberScrollState())) {
users.forEachIndexed() { _, user ->
val userId = Screen.UserView.route.replace("{id}", (user.uid).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)
}
}
}

View File

@ -0,0 +1,28 @@
package com.example.myapplication.user.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.example.myapplication.user.model.User
import com.example.myapplication.user.model.UserWithChallenges
import kotlinx.coroutines.flow.Flow
@Dao
interface UserDao {
@Query("select * from users order by fio asc")
fun getAll(): Flow<List<User>>
@Query("select * from users where users.uid = :uid")
suspend fun getByUid(uid: Int): UserWithChallenges
@Insert
suspend fun insert(user: User)
@Update
suspend fun update(user: User)
@Delete
suspend fun delete(user: User)
}

View File

@ -0,0 +1,13 @@
package com.example.myapplication.user.model
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.example.myapplication.challenge.model.Challenge
@Entity(tableName = "users")
data class User(
@PrimaryKey val uid: Int,
val login: String,
val password: String,
val fio: String,
)

View File

@ -0,0 +1,15 @@
package com.example.myapplication.user.model
import androidx.room.Embedded
import androidx.room.Relation
import com.example.myapplication.challenge.model.Challenge
import com.example.myapplication.user.model.User
data class UserWithChallenges(
@Embedded val user: User,
@Relation(
parentColumn = "uid",
entityColumn = "user_id"
)
val challenges: List<Challenge>
)

View File

@ -1,3 +1,18 @@
<resources>
<string name="app_name">My Application</string>
<string name="about_main_title">О нас</string>
<string name="user_list">Пользователи</string>
<string name="categories_list">Категории</string>
<string name="about_text">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.</string>
<string name="user_login">Логин</string>
<string name="user_fio">ФИО</string>
<string name="user_view_title">Пользователь</string>
</resources>

View File

@ -2,4 +2,5 @@
plugins {
id("com.android.application") version "8.1.1" apply false
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
id("com.google.devtools.ksp") version "1.8.20-1.0.11" apply false
}

BIN
Лаб4_Отчет.docx Normal file

Binary file not shown.