3 lab
This commit is contained in:
parent
895ee0fe2b
commit
02a36d1a92
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.8.10" />
|
||||
<option name="version" value="1.8.20" />
|
||||
</component>
|
||||
</project>
|
@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("com.google.devtools.ksp")
|
||||
}
|
||||
|
||||
android {
|
||||
@ -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 {
|
||||
@ -57,6 +58,14 @@ dependencies {
|
||||
implementation("androidx.compose.ui:ui-graphics")
|
||||
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||
implementation("androidx.compose.material3:material3")
|
||||
|
||||
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")
|
||||
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
|
@ -1,18 +0,0 @@
|
||||
package com.example.myapplication.book.model
|
||||
|
||||
import java.io.Serializable
|
||||
import com.example.myapplication.R
|
||||
|
||||
data class Book(
|
||||
val title: String,
|
||||
val author: String,
|
||||
val content: String
|
||||
) : Serializable
|
||||
|
||||
fun getBooks(): List<Book> {
|
||||
return listOf(
|
||||
Book("1984", "Дж. Оруэлл", "Был холодный ясный апрельский день, и часы пробили тринадцать."),
|
||||
Book("Собачье сердце", "М.А. Булгаков", "У‑у-у-у-у-гу-гуг-гуу! О, гляньте на меня, я погибаю."),
|
||||
Book("Вельд", "Р. Брэдбери", "— Джорджи, пожалуйста, посмотри детскую комнату. — А что с ней?")
|
||||
)
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.example.myapplication.composeui
|
||||
|
||||
import android.content.res.Configuration
|
||||
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.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import com.example.myapplication.db.database.AppDatabase
|
||||
import com.example.myapplication.db.model.BookWithAuthor
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun BookRead(id: Int) {
|
||||
val context = LocalContext.current
|
||||
val (bookWithAuthor, setBookWithAuthor) = remember { mutableStateOf<BookWithAuthor?>(null) }
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
setBookWithAuthor(AppDatabase.getInstance(context).bookDao().getByUid(id))
|
||||
}
|
||||
}
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp)
|
||||
){
|
||||
Text(text = bookWithAuthor?.book?.content ?: "", fontSize=22.sp)
|
||||
}
|
||||
}
|
||||
|
||||
@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 BookReadPreview() {
|
||||
MyApplicationTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
BookRead(id = 0)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package com.example.myapplication.composeui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
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.key
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.composeui.navigation.Screen
|
||||
import com.example.myapplication.db.database.AppDatabase
|
||||
import com.example.myapplication.db.model.Book
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun BookSearch(navController: NavController?, text: String) {
|
||||
val context = LocalContext.current
|
||||
val books = remember { mutableStateListOf<Book>() }
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
AppDatabase.getInstance(context).bookDao().getBySearch(text).collect { data ->
|
||||
books.clear()
|
||||
books.addAll(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
Column(Modifier.padding(all = 10.dp)) {
|
||||
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 180.dp)) {
|
||||
items (books){ book ->
|
||||
key(book.uid) {
|
||||
val bookId = Screen.BookView.route.replace("{id}", book.uid.toString())
|
||||
Image(
|
||||
painter = painterResource(id = book.cover!!),
|
||||
contentDescription = book.title,
|
||||
modifier = Modifier
|
||||
.height(300.dp)
|
||||
.padding(horizontal = 5.dp)
|
||||
.clickable(
|
||||
enabled = true,
|
||||
onClick = { navController?.navigate(bookId) }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp),
|
||||
onClick = { navController?.navigate(Screen.Loader.route) }) {
|
||||
Text(stringResource(id = R.string.add_book))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 BookSearchPreview() {
|
||||
MyApplicationTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
BookSearch(navController = null, "")
|
||||
}
|
||||
}
|
||||
}
|
@ -2,49 +2,76 @@ package com.example.myapplication.composeui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
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.key
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
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 androidx.compose.ui.platform.LocalContext
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import com.example.myapplication.db.database.AppDatabase;
|
||||
import com.example.myapplication.db.model.BookWithAuthor;
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.book.model.getBooks
|
||||
import com.example.myapplication.composeui.navigation.Screen
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun BookView(id: Int) {
|
||||
val book = getBooks()[id]
|
||||
fun BookView(navController: NavController?, id: Int) {
|
||||
val context = LocalContext.current
|
||||
val (bookWithAuthor, setBookWithAuthor) = remember { mutableStateOf<BookWithAuthor?>(null) }
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
setBookWithAuthor(AppDatabase.getInstance(context).bookDao().getByUid(id))
|
||||
}
|
||||
}
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp)
|
||||
) {
|
||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||
value = book.title, onValueChange = {}, readOnly = true,
|
||||
value = bookWithAuthor?.book?.title ?: "", onValueChange = {}, readOnly = true,
|
||||
label = {
|
||||
Text(stringResource(id = R.string.book_title))
|
||||
}
|
||||
)
|
||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||
value = book.author, onValueChange = {}, readOnly = true,
|
||||
value = bookWithAuthor?.authorName ?: "", onValueChange = {}, readOnly = true,
|
||||
label = {
|
||||
Text(stringResource(id = R.string.author_name))
|
||||
}
|
||||
)
|
||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||
value = book.content, onValueChange = {}, readOnly = true,
|
||||
value = bookWithAuthor?.book?.description ?: "", onValueChange = {}, readOnly = true,
|
||||
label = {
|
||||
Text(stringResource(id = R.string.all_content))
|
||||
Text(stringResource(id = R.string.description))
|
||||
}
|
||||
)
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp),
|
||||
onClick = { navController?.navigate(Screen.BookRead.route.replace("{id}", id.toString())) }) {
|
||||
Text(stringResource(id = R.string.read_book))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +83,7 @@ fun BookViewPreview() {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
BookView(id = 0)
|
||||
BookView(navController = null, id = 0)
|
||||
}
|
||||
}
|
||||
}
|
@ -5,35 +5,68 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.ui.res.painterResource
|
||||
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.key
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
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 androidx.compose.runtime.remember
|
||||
import androidx.navigation.NavController
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import kotlinx.coroutines.withContext
|
||||
import com.example.myapplication.db.database.AppDatabase;
|
||||
import com.example.myapplication.db.model.Book;
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.book.model.getBooks
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import com.example.myapplication.composeui.navigation.Screen
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
|
||||
@Composable
|
||||
fun Catalog(navController: NavController?) {
|
||||
val context = LocalContext.current
|
||||
val books = remember { mutableStateListOf<Book>() }
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
AppDatabase.getInstance(context).bookDao().getAll().collect { data ->
|
||||
books.clear()
|
||||
books.addAll(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
Column(Modifier.padding(all = 10.dp)) {
|
||||
getBooks().forEachIndexed() { index, book ->
|
||||
val bookId = Screen.BookView.route.replace("{id}", index.toString())
|
||||
Button(
|
||||
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 180.dp)) {
|
||||
items (books){ book ->
|
||||
key(book.uid) {
|
||||
val bookId = Screen.BookView.route.replace("{id}", book.uid.toString())
|
||||
Image(
|
||||
painter = painterResource(id = book.cover!!),
|
||||
contentDescription = book.title,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp),
|
||||
onClick = { navController?.navigate(bookId) }) {
|
||||
Text("${book.title}")
|
||||
.height(300.dp)
|
||||
.padding(horizontal = 5.dp)
|
||||
.clickable(
|
||||
enabled = true,
|
||||
onClick = { navController?.navigate(bookId) }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.padding(bottom = 40.dp))
|
||||
}
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
@ -12,6 +12,7 @@ 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.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
@ -20,30 +21,57 @@ import androidx.navigation.NavController
|
||||
import com.example.myapplication.R
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.example.myapplication.composeui.navigation.Screen
|
||||
import com.example.myapplication.db.database.AppDatabase
|
||||
import com.example.myapplication.db.model.User
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Enter(navController: NavController?) {
|
||||
var login by remember{mutableStateOf("")}
|
||||
var password by remember{mutableStateOf("")}
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
AppDatabase.getInstance(context).userDao().getAll()
|
||||
}
|
||||
}
|
||||
Column(Modifier.fillMaxWidth().padding(all = 40.dp)) {
|
||||
val loginStr = remember{mutableStateOf("")}
|
||||
Text(stringResource(id = R.string.login))
|
||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||
value = loginStr.value, onValueChange = { newText -> loginStr.value = newText },
|
||||
value = login, onValueChange = { login = it },
|
||||
)
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
val passwordStr = remember{mutableStateOf("")}
|
||||
Text(stringResource(id = R.string.password))
|
||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||
value = passwordStr.value, onValueChange = { newText -> passwordStr.value = newText },
|
||||
value = password, onValueChange = { password = it },
|
||||
)
|
||||
Spacer(Modifier.padding(bottom = 20.dp))
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp),
|
||||
onClick = { navController?.navigate(Screen.Profile.route) }) {
|
||||
onClick = {
|
||||
var user: User?
|
||||
GlobalScope.launch (Dispatchers.Main) {
|
||||
user = AppDatabase.getInstance(context).userDao().tryLogin(login, password)
|
||||
if (user != null) {
|
||||
//AppDatabase.getInstance(context).userDao().setLogined(user!!.uid!!)
|
||||
navController?.navigate(Screen.Profile.route)
|
||||
} else {
|
||||
password = ""
|
||||
login = "Неверный логин или пароль"
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(id = R.string.enter))
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
package com.example.myapplication.composeui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
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.key
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.remember
|
||||
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 androidx.compose.ui.unit.sp
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.composeui.navigation.Screen
|
||||
import com.example.myapplication.db.database.AppDatabase
|
||||
import com.example.myapplication.db.model.Author
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun ListAuthors() {
|
||||
val context = LocalContext.current
|
||||
val authors = remember { mutableStateListOf<Author>() }
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
AppDatabase.getInstance(context).authorDao().getAll().collect { data ->
|
||||
authors.clear()
|
||||
authors.addAll(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
Column(Modifier.padding(all = 10.dp)) {
|
||||
authors.forEach{ author ->
|
||||
Text(author.name, fontSize = 20.sp)
|
||||
}
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp),
|
||||
onClick = {}) {
|
||||
Text(stringResource(id = R.string.add_book))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 ListAuthorsPreview() {
|
||||
MyApplicationTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
ListAuthors()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +1,254 @@
|
||||
package com.example.myapplication.composeui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Create
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.outlined.Clear
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
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.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
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.db.database.AppDatabase
|
||||
import com.example.myapplication.db.model.User
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Profile() {
|
||||
Column(Modifier.padding(all = 40.dp)) {
|
||||
Text(stringResource(id = R.string.stats))
|
||||
fun Profile(navController: NavController?) {
|
||||
val openDialogEdit = remember { mutableStateOf(false) }
|
||||
val openDialogExit = remember { mutableStateOf(false) }
|
||||
val openDialogDelete = remember { mutableStateOf(false) }
|
||||
val context = LocalContext.current
|
||||
val user = remember { mutableStateOf<User>(User("", "", "", "USER")) }
|
||||
val userOldPsswd = remember { mutableStateOf("") }
|
||||
val userNewPsswd = remember { mutableStateOf("") }
|
||||
val userNewPsswdConf = remember { mutableStateOf("") }
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
user.value = AppDatabase.getInstance(context).userDao().getByUid(2)
|
||||
}
|
||||
}
|
||||
Column(Modifier.padding(all = 10.dp), horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||
value = user.value.login, onValueChange = {user.value.login = it},
|
||||
label = {
|
||||
Text(stringResource(id = R.string.login))
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
|
||||
)
|
||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||
value = user.value.password, onValueChange = {user.value.password = it},
|
||||
label = {
|
||||
Text(stringResource(id = R.string.password))
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
|
||||
)
|
||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||
value = user.value.email, onValueChange = {user.value.email = it},
|
||||
label = {
|
||||
Text(stringResource(id = R.string.email))
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(all = 20.dp))
|
||||
Button(
|
||||
onClick = { openDialogEdit.value = true },
|
||||
shape = CircleShape,
|
||||
modifier = Modifier.fillMaxWidth(fraction = 0.75f),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
) {
|
||||
// Inner content including an icon and a text label
|
||||
Icon(
|
||||
imageVector = Icons.Default.Create,
|
||||
contentDescription = "Favorite",
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
|
||||
Text(text = "Редактировать")
|
||||
}
|
||||
Button(
|
||||
onClick = { openDialogExit.value = true },
|
||||
shape = CircleShape,
|
||||
modifier = Modifier.fillMaxWidth(fraction = 0.75f),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = MaterialTheme.colorScheme.errorContainer,
|
||||
contentColor = MaterialTheme.colorScheme.error
|
||||
)
|
||||
) {
|
||||
// Inner content including an icon and a text label
|
||||
Icon(
|
||||
imageVector = Icons.Default.Close,
|
||||
contentDescription = "Favorite",
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
|
||||
Text(text = "Выход")
|
||||
}
|
||||
OutlinedButton(
|
||||
onClick = { openDialogDelete.value = true },
|
||||
shape = CircleShape,
|
||||
modifier = Modifier.fillMaxWidth(fraction = 0.75f),
|
||||
border= BorderStroke(1.dp, MaterialTheme.colorScheme.error),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = MaterialTheme.colorScheme.error
|
||||
)
|
||||
) {
|
||||
// Inner content including an icon and a text label
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Clear,
|
||||
contentDescription = "Удалить",
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
|
||||
Text(text = "Удалить аккаунт")
|
||||
}
|
||||
}
|
||||
if (openDialogEdit.value) {
|
||||
AlertDialog(
|
||||
icon = {
|
||||
Icon(Icons.Default.Edit, contentDescription = "Example Icon")
|
||||
},
|
||||
title = {
|
||||
Text(text = "Подтверждение")
|
||||
},
|
||||
text = {
|
||||
Text(text = "Вы хотите применить изменения?")
|
||||
},
|
||||
onDismissRequest = {
|
||||
openDialogEdit.value = false
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
openDialogEdit.value = false
|
||||
/* TODO */
|
||||
}
|
||||
) {
|
||||
Text("Да")
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
openDialogEdit.value = false
|
||||
}
|
||||
) {
|
||||
Text("Нет")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
if (openDialogExit.value) {
|
||||
AlertDialog(
|
||||
icon = {
|
||||
Icon(Icons.Default.Close, contentDescription = "Example Icon")
|
||||
},
|
||||
title = {
|
||||
Text(text = "Подтверждение")
|
||||
},
|
||||
text = {
|
||||
Text(text = "Вы хотите выйти из аккаунта?")
|
||||
},
|
||||
onDismissRequest = {
|
||||
openDialogExit.value = false
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
openDialogExit.value = false
|
||||
navController?.navigate(Screen.Enter.route)
|
||||
}
|
||||
) {
|
||||
Text("Да")
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
openDialogExit.value = false
|
||||
}
|
||||
) {
|
||||
Text("Нет")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
if (openDialogDelete.value) {
|
||||
AlertDialog(
|
||||
icon = {
|
||||
Icon(Icons.Default.Close, contentDescription = "Example Icon")
|
||||
},
|
||||
title = {
|
||||
Text(text = "Подтверждение")
|
||||
},
|
||||
text = {
|
||||
Text(text = "Вы хотите удалить аккаунт?")
|
||||
},
|
||||
onDismissRequest = {
|
||||
openDialogDelete.value = false
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
openDialogDelete.value = false
|
||||
/* TODO */
|
||||
}
|
||||
) {
|
||||
Text("Да")
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
openDialogDelete.value = false
|
||||
}
|
||||
) {
|
||||
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)
|
||||
@ -29,7 +258,7 @@ fun ProfilePreview() {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
Profile()
|
||||
Profile(navController = null)
|
||||
}
|
||||
}
|
||||
}
|
@ -10,10 +10,13 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
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.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
@ -22,12 +25,16 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import com.example.myapplication.composeui.navigation.Screen
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Search() {
|
||||
fun Search(navController: NavController?) {
|
||||
var searchStr by remember { mutableStateOf("") }
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
@ -37,16 +44,25 @@ fun Search() {
|
||||
Text(stringResource(id = R.string.book_world), color = Color.White)
|
||||
}
|
||||
Spacer(Modifier.padding(bottom = 20.dp))
|
||||
val searchStr = remember{ mutableStateOf("") }
|
||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||
value = searchStr.value, onValueChange = { newText -> searchStr.value = newText },
|
||||
TextField(modifier = Modifier.fillMaxWidth(),
|
||||
value = searchStr, onValueChange = { searchStr = it }, singleLine = true,
|
||||
placeholder = { Text("Поиск", fontSize = 22.sp) }
|
||||
)
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp),
|
||||
onClick = {}) {
|
||||
onClick = {
|
||||
if(!searchStr.isEmpty()){
|
||||
navController?.navigate(
|
||||
Screen.BookSearch.route.replace(
|
||||
"{text}",
|
||||
searchStr
|
||||
)
|
||||
)
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(id = R.string.search_book))
|
||||
}
|
||||
}
|
||||
@ -60,7 +76,7 @@ fun SearchPreview() {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
Search()
|
||||
Search(navController=null)
|
||||
}
|
||||
}
|
||||
}
|
@ -41,6 +41,9 @@ import com.example.myapplication.composeui.Search
|
||||
import com.example.myapplication.composeui.Loader
|
||||
import com.example.myapplication.composeui.Catalog
|
||||
import com.example.myapplication.composeui.BookView
|
||||
import com.example.myapplication.composeui.BookRead
|
||||
import com.example.myapplication.composeui.BookSearch
|
||||
import com.example.myapplication.composeui.ListAuthors
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@ -113,15 +116,28 @@ fun Navhost(
|
||||
composable(Screen.Main.route) { Main(navController) }
|
||||
composable(Screen.Registration.route) { Registration(navController) }
|
||||
composable(Screen.Enter.route) { Enter(navController) }
|
||||
composable(Screen.Profile.route) { Profile() }
|
||||
composable(Screen.Search.route) { Search() }
|
||||
composable(Screen.Profile.route) { Profile(navController) }
|
||||
composable(Screen.Search.route) { Search(navController) }
|
||||
composable(Screen.Loader.route) { Loader() }
|
||||
composable(Screen.Catalog.route) { Catalog(navController) }
|
||||
composable(Screen.ListAuthors.route) { ListAuthors() }
|
||||
composable(
|
||||
Screen.BookView.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||
) { backStackEntry ->
|
||||
backStackEntry.arguments?.let { BookView(it.getInt("id")) }
|
||||
backStackEntry.arguments?.let { BookView(navController, it.getInt("id")) }
|
||||
}
|
||||
composable(
|
||||
Screen.BookRead.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||
) { backStackEntry ->
|
||||
backStackEntry.arguments?.let { BookRead(it.getInt("id")) }
|
||||
}
|
||||
composable(
|
||||
Screen.BookSearch.route,
|
||||
arguments = listOf(navArgument("text") { type = NavType.StringType })
|
||||
) { backStackEntry ->
|
||||
backStackEntry.arguments?.let { BookSearch(navController = navController ,it.getString ("text", "")) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.example.myapplication.composeui.navigation
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.AccountCircle
|
||||
import androidx.compose.material.icons.filled.Face
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.List
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
@ -33,11 +34,20 @@ enum class Screen(
|
||||
Catalog(
|
||||
"catalog", R.string.catalog, Icons.Filled.List
|
||||
),
|
||||
ListAuthors(
|
||||
"listauthors", R.string.listauthors, Icons.Filled.Face
|
||||
),
|
||||
Loader(
|
||||
"loader", R.string.loader, showInBottomBar = false
|
||||
),
|
||||
BookSearch(
|
||||
"book-search/{text}", R.string.search, showInBottomBar = false
|
||||
),
|
||||
BookView(
|
||||
"book-view/{id}", R.string.book_view_title, showInBottomBar = false
|
||||
),
|
||||
BookRead(
|
||||
"book-read/{id}", R.string.book_view_title, showInBottomBar = false
|
||||
);
|
||||
|
||||
companion object {
|
||||
@ -45,6 +55,7 @@ enum class Screen(
|
||||
Profile,
|
||||
Search,
|
||||
Catalog,
|
||||
ListAuthors
|
||||
)
|
||||
fun getItem(route: String): Screen? {
|
||||
val findRoute = route.split("/").first()
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.example.myapplication.db.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.db.model.Author;
|
||||
import com.example.myapplication.db.model.Book
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface AuthorDao {
|
||||
@Query("select * from authors order by author_name collate nocase asc")
|
||||
fun getAll(): Flow<List<Author>>
|
||||
|
||||
@Insert
|
||||
suspend fun insert(author: Author)
|
||||
|
||||
@Update
|
||||
suspend fun update(author: Author)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(author: Author)
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.example.myapplication.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import com.example.myapplication.db.model.Book;
|
||||
import com.example.myapplication.db.model.BookWithAuthor;
|
||||
|
||||
@Dao
|
||||
interface BookDao {
|
||||
@Query("select * from books order by title collate nocase asc")
|
||||
fun getAll(): Flow<List<Book>>
|
||||
|
||||
@Query("select * from books left join authors on books.author_id = authors.uid where books.uid = :uid")
|
||||
suspend fun getByUid(uid: Int): BookWithAuthor
|
||||
|
||||
@Query("select * from books where books.title LIKE '%' || :searchStr || '%'")
|
||||
fun getBySearch(searchStr: String): Flow<List<Book>>
|
||||
|
||||
@Query("select * from books where books.user_id = :userId")
|
||||
fun getByUserId(userId: Int): Flow<List<Book>>
|
||||
|
||||
@Query("select * from books where books.author_id = :authorId")
|
||||
fun getByAuthorId(authorId: Int): Flow<List<Book>>
|
||||
|
||||
@Insert
|
||||
suspend fun insert(book: Book)
|
||||
|
||||
@Update
|
||||
suspend fun update(book: Book)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(book: Book)
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.example.myapplication.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import com.example.myapplication.db.model.User;
|
||||
|
||||
@Dao
|
||||
interface UserDao {
|
||||
@Query("select * from users")
|
||||
fun getAll(): Flow<List<User>>
|
||||
|
||||
@Query("select * from users where login = :login and password = :password")
|
||||
suspend fun tryLogin(login: String, password: String): User?
|
||||
|
||||
@Query("select * from users where users.uid = :uid")
|
||||
suspend fun getByUid(uid: Int): User
|
||||
|
||||
@Insert
|
||||
suspend fun insert(user: User)
|
||||
|
||||
@Update
|
||||
suspend fun update(user: User)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(user: User)
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package com.example.myapplication.db.database
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import com.example.myapplication.db.dao.UserDao;
|
||||
import com.example.myapplication.db.dao.BookDao;
|
||||
import com.example.myapplication.db.dao.AuthorDao;
|
||||
import com.example.myapplication.db.model.User;
|
||||
import com.example.myapplication.db.model.Book;
|
||||
import com.example.myapplication.db.model.Author;
|
||||
import com.example.myapplication.R
|
||||
|
||||
@Database(entities = [Book::class, Author::class, User::class], version = 1, exportSchema = false)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun bookDao(): BookDao
|
||||
abstract fun authorDao(): AuthorDao
|
||||
abstract fun userDao(): UserDao
|
||||
|
||||
companion object {
|
||||
private const val DB_NAME: String = "PMU"
|
||||
|
||||
@Volatile
|
||||
private var INSTANCE: AppDatabase? = null
|
||||
|
||||
private suspend fun populateDatabase() {
|
||||
INSTANCE?.let { database ->
|
||||
//Users
|
||||
val userDao = database.userDao()
|
||||
val user1 = User(1, "Admin", "Admin", "admin@mail.ru", "ADMIN")
|
||||
val user2 = User(2, "User1", "123", "u1@mail.ru", "USER")
|
||||
userDao.insert(user1)
|
||||
userDao.insert(user2)
|
||||
// Authors
|
||||
val authorDao = database.authorDao()
|
||||
val author1 = Author(1, "Дж. Оруэлл")
|
||||
val author2 = Author(2, "М.А. Булгаков")
|
||||
val author3 = Author(3, "Р. Брэдбери")
|
||||
authorDao.insert(author1)
|
||||
authorDao.insert(author2)
|
||||
authorDao.insert(author3)
|
||||
// Books
|
||||
val bookDao = database.bookDao()
|
||||
val book1 = Book(1,"1984", "Роман о том, как репрессивная машина тоталитарного государства может уничтожить любую личность.", "Был холодный ясный апрельский день, и часы пробили тринадцать.\n" + "Уинстон Смит, прижав подбородок к груди и ежась от омерзительного ветра, быстро скользнул в стеклянные двери Дома Победы, но все же вихрь песка и пыли успел ворваться вместе с ним.", R.drawable.or1984, 1, 1)
|
||||
val book2 = Book(2,"Собачье сердце", "Роман о бродячем псе Шарике, превращенном в человека.", "У‑у-у-у-у-гу-гуг-гуу! О, гляньте на меня, я погибаю.\n" + "Вьюга в подворотне ревёт мне отходную, и я вою с ней.\n" + "Пропал я, пропал.", R.drawable.dogsheart, 2, 1)
|
||||
val book3 = Book(3,"Вельд", "Рассказ о зависимости от технических устройств, потере человечности.", "— Джорджи, пожалуйста, посмотри детскую комнату.\n" + "— А что с ней?\n" + "— Не знаю.\n" + "— Так в чем же дело?", R.drawable.veld, 3, 1)
|
||||
val book4 = Book(4,"Роковые яйца", "Рассказ, критикующий стремление к прогрессу без учета последствий.","16 апреля 1928 года, вечером, профессор зоологии IV государственного университета и директор зооинститута в Москве Персиков вошел в свой кабинет, помещающийся в зооинституте, что на улице Герцена.\n" + "Профессор зажег верхний матовый шар и огляделся.", R.drawable.eggs, 2, 2)
|
||||
bookDao.insert(book1)
|
||||
bookDao.insert(book2)
|
||||
bookDao.insert(book3)
|
||||
bookDao.insert(book4)
|
||||
}
|
||||
}
|
||||
|
||||
fun getInstance(appContext: Context): AppDatabase {
|
||||
return INSTANCE ?: synchronized(this) {
|
||||
Room.databaseBuilder(
|
||||
appContext,
|
||||
AppDatabase::class.java,
|
||||
DB_NAME
|
||||
)
|
||||
.addCallback(object : Callback() {
|
||||
override fun onCreate(db: SupportSQLiteDatabase) {
|
||||
super.onCreate(db)
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
populateDatabase()
|
||||
}
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.also { INSTANCE = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.example.myapplication.db.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "authors")
|
||||
data class Author(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val uid: Int?,
|
||||
@ColumnInfo(name = "author_name")
|
||||
val name: String
|
||||
) {
|
||||
@Ignore
|
||||
constructor(
|
||||
name: String
|
||||
) : this(null, name)
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as Author
|
||||
if (uid != other.uid) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return uid ?: -1
|
||||
}
|
||||
}
|
65
app/src/main/java/com/example/myapplication/db/model/Book.kt
Normal file
65
app/src/main/java/com/example/myapplication/db/model/Book.kt
Normal file
@ -0,0 +1,65 @@
|
||||
package com.example.myapplication.db.model
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.PrimaryKey
|
||||
import androidx.room.Ignore
|
||||
|
||||
@Entity(
|
||||
tableName = "books", foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Author::class,
|
||||
parentColumns = ["uid"],
|
||||
childColumns = ["author_id"],
|
||||
onDelete = ForeignKey.RESTRICT,
|
||||
onUpdate = ForeignKey.RESTRICT
|
||||
),
|
||||
ForeignKey(
|
||||
entity = User::class,
|
||||
parentColumns = ["uid"],
|
||||
childColumns = ["user_id"],
|
||||
onDelete = ForeignKey.RESTRICT,
|
||||
onUpdate = ForeignKey.RESTRICT
|
||||
)
|
||||
]
|
||||
)
|
||||
data class Book(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val uid: Int?,
|
||||
@ColumnInfo(name = "title")
|
||||
val title: String,
|
||||
@ColumnInfo(name = "description")
|
||||
val description: String,
|
||||
@ColumnInfo(name = "content")
|
||||
val content: String,
|
||||
@ColumnInfo(name = "cover")
|
||||
@DrawableRes val cover: Int?,
|
||||
@ColumnInfo(name = "author_id", index = true)
|
||||
val authorId: Int?,
|
||||
@ColumnInfo(name = "user_id", index = true)
|
||||
val userId: Int?
|
||||
) {
|
||||
@Ignore
|
||||
constructor(
|
||||
title: String,
|
||||
description: String,
|
||||
content: String,
|
||||
cover: Int?,
|
||||
authorId: Int?,
|
||||
userId: Int?
|
||||
) : this(null, title, description, content, cover, authorId, userId)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as Book
|
||||
if (uid != other.uid) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return uid ?: -1
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.example.myapplication.db.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Embedded
|
||||
|
||||
data class BookWithAuthor(
|
||||
@Embedded
|
||||
val book: Book,
|
||||
@ColumnInfo(name = "author_name")
|
||||
val authorName: String
|
||||
)
|
41
app/src/main/java/com/example/myapplication/db/model/User.kt
Normal file
41
app/src/main/java/com/example/myapplication/db/model/User.kt
Normal file
@ -0,0 +1,41 @@
|
||||
package com.example.myapplication.db.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.Index
|
||||
|
||||
@Entity(tableName = "users", indices = [(Index(value = ["login"], unique = true))])
|
||||
data class User(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val uid: Int?,
|
||||
@ColumnInfo(name = "login")
|
||||
var login: String,
|
||||
@ColumnInfo(name = "password")
|
||||
var password: String,
|
||||
@ColumnInfo(name = "email")
|
||||
var email: String,
|
||||
@ColumnInfo(name = "admin")
|
||||
var role: String,
|
||||
) {
|
||||
@Ignore
|
||||
constructor(
|
||||
login: String,
|
||||
password: String,
|
||||
email: String,
|
||||
role: String
|
||||
) : this(null, login, password, email, role)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as User
|
||||
if (uid != other.uid) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return uid ?: -1
|
||||
}
|
||||
}
|
BIN
app/src/main/res/drawable/dogsheart.jpg
Normal file
BIN
app/src/main/res/drawable/dogsheart.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
app/src/main/res/drawable/eggs.jpg
Normal file
BIN
app/src/main/res/drawable/eggs.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
app/src/main/res/drawable/or1984.jpg
Normal file
BIN
app/src/main/res/drawable/or1984.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
app/src/main/res/drawable/veld.jpg
Normal file
BIN
app/src/main/res/drawable/veld.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
@ -9,6 +9,7 @@
|
||||
<string name="search">Поиск</string>
|
||||
<string name="loader">Загрузка</string>
|
||||
<string name="catalog">Каталог</string>
|
||||
<string name="listauthors">Писатели</string>
|
||||
<string name="book_view_title">Книга</string>
|
||||
<string name="enter">Войти</string>
|
||||
<string name="create_acc">Создать аккаунт</string>
|
||||
@ -27,11 +28,13 @@
|
||||
</string>
|
||||
<string name="book_title">Название</string>
|
||||
<string name="author_name">Автор</string>
|
||||
<string name="description">Содержание</string>
|
||||
<string name="all_content">Содержание</string>
|
||||
<string name="welcome">Добро пожаловать</string>
|
||||
<string name="book_world">в мир книг!</string>
|
||||
<string name="search_book">Найти</string>
|
||||
<string name="load_book">Загрузить</string>
|
||||
<string name="add_book">Добавить</string>
|
||||
<string name="read_book">Читать</string>
|
||||
<string name="help_me_pls">Вы можете помочь нашей библиотеке, загрузив свою книгу.</string>
|
||||
</resources>
|
@ -1,5 +1,6 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id("com.android.application") version "8.1.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
|
||||
id("com.android.application") version "8.1.2" apply false
|
||||
id("org.jetbrains.kotlin.android") version "1.8.20" apply false
|
||||
id("com.google.devtools.ksp") version "1.8.20-1.0.11" apply false
|
||||
}
|
BIN
Отчеты и макеты/Тюрнер_ЛР3.docx
Normal file
BIN
Отчеты и макеты/Тюрнер_ЛР3.docx
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user