This commit is contained in:
ksenianeva 2023-11-22 09:10:15 +04:00
parent 86be093a35
commit cb425c227b
13 changed files with 324 additions and 70 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,9 +47,16 @@ android {
}
}
kotlin {
jvmToolchain(17)
}
dependencies {
//Core
implementation("androidx.core:core-ktx:1.9.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")
@ -57,6 +65,16 @@ dependencies {
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,22 +10,40 @@ 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.getTestCategory
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())) {
getTestCategory().forEachIndexed() { _, category ->
categories.forEachIndexed() { _, category ->
Row(Modifier.padding(all = 20.dp)) {
Text(category.category_name)
}

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

@ -1,15 +1,11 @@
package com.example.myapplication.category.model
import java.io.Serializable
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "categories")
data class Category(
@PrimaryKey val uid: Int,
val category_name: String,
) : Serializable
)
fun getTestCategory(): List<Category> {
return listOf(
Category("Отжимания"),
Category("Кардио"),
Category("Силовые")
)
}

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

@ -1,19 +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 java.io.Serializable
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: Category,
) : Serializable
fun getTestChallenge(): List<Challenge> {
val сategory = Category("Отжимания")
return listOf(
Challenge("Сделать 20 отжиманий", false, сategory),
Challenge("Сделать 10 отжиманий", false, сategory),
Challenge("Сделать 5 отжиманий", false, сategory),
)
}
val category_id: Int,
@ColumnInfo(index = true)
val user_id: Int,
)

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

@ -13,47 +13,69 @@ 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.user.model.getTestUser
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) {
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))
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))
}
)
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 = " - Выполнено")
}
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))
}
else {
Text(text = " - В процессе")
)
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)

View File

@ -12,24 +12,42 @@ 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.user.model.getTestUser
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())) {
getTestUser().forEachIndexed() { _, user ->
val userId = Screen.UserView.route.replace("{id}", (user.id).toString())
users.forEachIndexed() { _, user ->
val userId = Screen.UserView.route.replace("{id}", (user.uid).toString())
Row(Modifier.padding(all = 10.dp)) {
Button(
modifier = Modifier

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

@ -1,22 +1,13 @@
package com.example.myapplication.user.model
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.example.myapplication.challenge.model.Challenge
import com.example.myapplication.challenge.model.getTestChallenge
import java.io.Serializable
@Entity(tableName = "users")
data class User(
val id: Int,
@PrimaryKey val uid: Int,
val login: String,
val password: String,
val fio: String,
val challenges: List<Challenge>,
) : Serializable
fun getTestUser(): List<User> {
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),
)
}
)

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

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