Регистрация, аутентификация, вывод книг по автору и по пользователю
This commit is contained in:
parent
3b17a15278
commit
ef72894515
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"users": [
|
"users": [
|
||||||
{
|
{
|
||||||
|
"id": 1,
|
||||||
"login": "Admin",
|
"login": "Admin",
|
||||||
"password": "Admin",
|
"password": "Admin",
|
||||||
"email": "admin@mail.ru",
|
"email": "admin@mail.ru",
|
||||||
"role": "ADMIN",
|
"role": "ADMIN"
|
||||||
"id": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
@ -13,6 +13,13 @@
|
|||||||
"password": "123",
|
"password": "123",
|
||||||
"email": "user1@mail.ru",
|
"email": "user1@mail.ru",
|
||||||
"role": "USER"
|
"role": "USER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"login": "User2",
|
||||||
|
"password": "123",
|
||||||
|
"email": "user2@gmail.ru",
|
||||||
|
"role": "USER"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
@ -3957,7 +3964,7 @@
|
|||||||
-39
|
-39
|
||||||
],
|
],
|
||||||
"authorId": 2,
|
"authorId": 2,
|
||||||
"userId": 2
|
"userId": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Вельд",
|
"title": "Вельд",
|
||||||
@ -7316,7 +7323,7 @@
|
|||||||
-39
|
-39
|
||||||
],
|
],
|
||||||
"authorId": 2,
|
"authorId": 2,
|
||||||
"userId": 2,
|
"userId": 1,
|
||||||
"id": 4
|
"id": 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -89,6 +89,7 @@ dependencies {
|
|||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||||
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
|
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
|
||||||
|
|
||||||
// LiveData | +
|
// LiveData | DataStore
|
||||||
implementation("androidx.compose.runtime:runtime-livedata:1.5.4")
|
implementation("androidx.compose.runtime:runtime-livedata:1.5.4")
|
||||||
|
implementation("androidx.datastore:datastore-preferences:1.0.0")
|
||||||
}
|
}
|
@ -11,6 +11,7 @@ import androidx.compose.material3.Surface
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import com.example.myapplication.composeui.authenticator.Authenticator
|
||||||
import com.example.myapplication.composeui.navigation.MainNavbar
|
import com.example.myapplication.composeui.navigation.MainNavbar
|
||||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||||
|
|
||||||
@ -24,7 +25,8 @@ class MainActivity : ComponentActivity() {
|
|||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
color = MaterialTheme.colorScheme.background
|
color = MaterialTheme.colorScheme.background
|
||||||
) {
|
) {
|
||||||
MainNavbar()
|
Authenticator()
|
||||||
|
MainNavbar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
package com.example.myapplication
|
|
||||||
|
|
||||||
class SingletonClass{
|
|
||||||
var _userId = 2
|
|
||||||
var _role = "USER"
|
|
||||||
fun getUserId(): Int{ return _userId }
|
|
||||||
fun setUserId(userId: Int){
|
|
||||||
_userId = userId
|
|
||||||
}
|
|
||||||
fun getRole(): String{ return _role }
|
|
||||||
fun setRole(role: String){
|
|
||||||
_role = role
|
|
||||||
}
|
|
||||||
}
|
|
@ -100,7 +100,7 @@ interface ServerService{
|
|||||||
suspend fun getUserByLoginPass(
|
suspend fun getUserByLoginPass(
|
||||||
@Query("login") login: String,
|
@Query("login") login: String,
|
||||||
@Query("password") password: String
|
@Query("password") password: String
|
||||||
): UserRemote
|
): List<UserRemote>
|
||||||
@POST("users")
|
@POST("users")
|
||||||
suspend fun createUser(
|
suspend fun createUser(
|
||||||
@Body user: UserRemote,
|
@Body user: UserRemote,
|
||||||
@ -117,7 +117,7 @@ interface ServerService{
|
|||||||
@Path("id") id: Int,
|
@Path("id") id: Int,
|
||||||
): UserRemote
|
): UserRemote
|
||||||
companion object {
|
companion object {
|
||||||
private const val BASE_URL = "http://89.239.172.45:8079/"
|
private const val BASE_URL = "http://89.239.174.67:8079/"
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
private var INSTANCE: ServerService? = null
|
private var INSTANCE: ServerService? = null
|
||||||
|
@ -28,7 +28,7 @@ class RestUserRepository(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun tryLogin(login: String, password: String): User? {
|
override suspend fun tryLogin(login: String, password: String): User? {
|
||||||
return service.getUserByLoginPass(login, password).toUser()
|
return service.getUserByLoginPass(login, password).firstOrNull()?.toUser()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun insert(user: User) {
|
override suspend fun insert(user: User) {
|
||||||
|
@ -6,15 +6,19 @@ import androidx.lifecycle.viewmodel.CreationExtras
|
|||||||
import androidx.lifecycle.viewmodel.initializer
|
import androidx.lifecycle.viewmodel.initializer
|
||||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
import com.example.myapplication.MyApplication
|
import com.example.myapplication.MyApplication
|
||||||
|
import com.example.myapplication.composeui.ViewModel.AuthorBooksViewModel
|
||||||
import com.example.myapplication.composeui.ViewModel.AuthorDropDownViewModel
|
import com.example.myapplication.composeui.ViewModel.AuthorDropDownViewModel
|
||||||
import com.example.myapplication.composeui.ViewModel.AuthorEditViewModel
|
import com.example.myapplication.composeui.ViewModel.AuthorEditViewModel
|
||||||
import com.example.myapplication.composeui.ViewModel.AuthorListViewModel
|
import com.example.myapplication.composeui.ViewModel.AuthorListViewModel
|
||||||
import com.example.myapplication.composeui.ViewModel.BookEditViewModel
|
import com.example.myapplication.composeui.ViewModel.BookEditViewModel
|
||||||
import com.example.myapplication.composeui.ViewModel.BookListViewModel
|
import com.example.myapplication.composeui.ViewModel.BookListViewModel
|
||||||
import com.example.myapplication.composeui.ViewModel.BookPageViewModel
|
import com.example.myapplication.composeui.ViewModel.BookPageViewModel
|
||||||
|
import com.example.myapplication.composeui.ViewModel.LoginViewModel
|
||||||
import com.example.myapplication.composeui.ViewModel.SearchPageViewModel
|
import com.example.myapplication.composeui.ViewModel.SearchPageViewModel
|
||||||
|
import com.example.myapplication.composeui.ViewModel.UserBooksViewModel
|
||||||
import com.example.myapplication.composeui.ViewModel.UserEditViewModel
|
import com.example.myapplication.composeui.ViewModel.UserEditViewModel
|
||||||
import com.example.myapplication.composeui.ViewModel.UserPageViewModel
|
import com.example.myapplication.composeui.ViewModel.UserPageViewModel
|
||||||
|
import com.example.myapplication.composeui.authenticator.AuthenticatorViewModel
|
||||||
|
|
||||||
object AppViewModelProvider {
|
object AppViewModelProvider {
|
||||||
val Factory = viewModelFactory {
|
val Factory = viewModelFactory {
|
||||||
@ -69,6 +73,21 @@ object AppViewModelProvider {
|
|||||||
myApplication().container.authorRestRepository
|
myApplication().container.authorRestRepository
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
initializer {
|
||||||
|
AuthorBooksViewModel(
|
||||||
|
this.createSavedStateHandle(),
|
||||||
|
myApplication().container.bookRestRepository
|
||||||
|
)
|
||||||
|
}
|
||||||
|
initializer {
|
||||||
|
UserBooksViewModel(myApplication().container.bookRestRepository)
|
||||||
|
}
|
||||||
|
initializer {
|
||||||
|
AuthenticatorViewModel(myApplication().container.userRestRepository)
|
||||||
|
}
|
||||||
|
initializer {
|
||||||
|
LoginViewModel(myApplication().container.userRestRepository)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.example.myapplication.composeui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import androidx.paging.compose.LazyPagingItems
|
||||||
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
|
import com.example.myapplication.composeui.ViewModel.AuthorBooksViewModel
|
||||||
|
import com.example.myapplication.db.model.Book
|
||||||
|
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AuthorBooks(navController: NavController, authorId: Int, viewModel: AuthorBooksViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val authorBooksUiState = viewModel.authorBooksUiState
|
||||||
|
val pagingBook: LazyPagingItems<Book> = viewModel.bookPagedData.collectAsLazyPagingItems()
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
viewModel.refreshState()
|
||||||
|
}
|
||||||
|
fun refresh(){
|
||||||
|
coroutineScope.launch { viewModel.refreshState() }
|
||||||
|
}
|
||||||
|
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 180.dp)){
|
||||||
|
items (pagingBook.itemCount){
|
||||||
|
index -> BookCell(navController = navController, book = pagingBook[index]!!.copy())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 AuthorBooksPreview() {
|
||||||
|
MyApplicationTheme {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
AuthorBooks(navController = rememberNavController(), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,14 +27,17 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.example.myapplication.MainActivity
|
import com.example.myapplication.MainActivity
|
||||||
|
import com.example.myapplication.R
|
||||||
import com.example.myapplication.composeui.ViewModel.AuthorListViewModel
|
import com.example.myapplication.composeui.ViewModel.AuthorListViewModel
|
||||||
import com.example.myapplication.composeui.navigation.Screen
|
import com.example.myapplication.composeui.navigation.Screen
|
||||||
import com.example.myapplication.db.database.AppDatabase
|
import com.example.myapplication.db.database.AppDatabase
|
||||||
import com.example.myapplication.db.model.Author
|
import com.example.myapplication.db.model.Author
|
||||||
|
import com.example.myapplication.store.LiveStore
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -46,7 +49,7 @@ fun AuthorCell(navController: NavController?, author: Author, viewModel: AuthorL
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Column(modifier = Modifier
|
Column(modifier = Modifier
|
||||||
.padding(all = 5.dp)
|
.padding(all = 5.dp)
|
||||||
.requiredSize(170.dp, 100.dp)
|
.requiredSize(170.dp, 150.dp)
|
||||||
.clip(RoundedCornerShape(10.dp))
|
.clip(RoundedCornerShape(10.dp))
|
||||||
.border(1.dp, Color.LightGray, shape = RoundedCornerShape(10.dp))
|
.border(1.dp, Color.LightGray, shape = RoundedCornerShape(10.dp))
|
||||||
) {
|
) {
|
||||||
@ -83,6 +86,14 @@ fun AuthorCell(navController: NavController?, author: Author, viewModel: AuthorL
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Button(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(all = 10.dp),
|
||||||
|
onClick = {
|
||||||
|
navController?.navigate(Screen.AuthorBooks.route.replace("{id}", author.id.toString()))
|
||||||
|
}) {
|
||||||
|
Text(stringResource(id = R.string.books))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -33,7 +33,6 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.example.myapplication.R
|
import com.example.myapplication.R
|
||||||
import com.example.myapplication.SingletonClass
|
|
||||||
import com.example.myapplication.composeui.ViewModel.AuthorsListUiState
|
import com.example.myapplication.composeui.ViewModel.AuthorsListUiState
|
||||||
import com.example.myapplication.composeui.ViewModel.AuthorsUiState
|
import com.example.myapplication.composeui.ViewModel.AuthorsUiState
|
||||||
import com.example.myapplication.composeui.ViewModel.AuthorDetails
|
import com.example.myapplication.composeui.ViewModel.AuthorDetails
|
||||||
|
@ -8,15 +8,12 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.DropdownMenu
|
import androidx.compose.material3.DropdownMenu
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextField
|
import androidx.compose.material3.TextField
|
||||||
@ -33,7 +30,6 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.example.myapplication.R
|
import com.example.myapplication.R
|
||||||
import com.example.myapplication.SingletonClass
|
|
||||||
import com.example.myapplication.composeui.ViewModel.AuthorDropDownViewModel
|
import com.example.myapplication.composeui.ViewModel.AuthorDropDownViewModel
|
||||||
import com.example.myapplication.composeui.ViewModel.AuthorsListUiState
|
import com.example.myapplication.composeui.ViewModel.AuthorsListUiState
|
||||||
import com.example.myapplication.composeui.ViewModel.AuthorsUiState
|
import com.example.myapplication.composeui.ViewModel.AuthorsUiState
|
||||||
@ -42,6 +38,7 @@ import com.example.myapplication.composeui.ViewModel.BookEditViewModel
|
|||||||
import com.example.myapplication.composeui.ViewModel.BookUiState
|
import com.example.myapplication.composeui.ViewModel.BookUiState
|
||||||
import com.example.myapplication.composeui.ViewModel.ImageUploader
|
import com.example.myapplication.composeui.ViewModel.ImageUploader
|
||||||
import com.example.myapplication.db.model.Author
|
import com.example.myapplication.db.model.Author
|
||||||
|
import com.example.myapplication.store.LiveStore
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -124,8 +121,7 @@ private fun BookEdit(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
var SingletonClass = SingletonClass()
|
onUpdate(bookUiState.bookDetails.copy(userId = LiveStore.getUserId()))
|
||||||
onUpdate(bookUiState.bookDetails.copy(userId = SingletonClass.getUserId()))
|
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
@ -6,14 +6,19 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
@ -25,41 +30,52 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.example.myapplication.MainActivity
|
import com.example.myapplication.MainActivity
|
||||||
import com.example.myapplication.SingletonClass
|
import com.example.myapplication.composeui.ViewModel.LoginViewModel
|
||||||
import com.example.myapplication.api.ServerService
|
|
||||||
import com.example.myapplication.composeui.navigation.Screen
|
import com.example.myapplication.composeui.navigation.Screen
|
||||||
import com.example.myapplication.db.database.AppDatabase
|
import com.example.myapplication.store.PreferencesStore
|
||||||
import com.example.myapplication.db.model.User
|
|
||||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun Enter(navController: NavController) {
|
fun Enter(navController: NavController, viewModel: LoginViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
||||||
var SingletonClass = SingletonClass()
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val service: ServerService
|
val user = viewModel.signInUserState
|
||||||
var login by remember{mutableStateOf("")}
|
|
||||||
var password by remember{mutableStateOf("")}
|
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(all = 40.dp)) {
|
.padding(all = 40.dp)) {
|
||||||
Text(stringResource(id = R.string.login))
|
Text(stringResource(id = R.string.login))
|
||||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||||
value = login, onValueChange = { login = it },
|
value = user.details.login, onValueChange = { viewModel.updateState(user.details.copy(login = it)) },
|
||||||
)
|
)
|
||||||
Spacer(Modifier.padding(bottom = 10.dp))
|
Spacer(Modifier.padding(bottom = 10.dp))
|
||||||
Text(stringResource(id = R.string.password))
|
Text(stringResource(id = R.string.password))
|
||||||
|
var passwordVisible by rememberSaveable { mutableStateOf(false) }
|
||||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||||
value = password, onValueChange = { password = it },
|
value = user.details.password, onValueChange = { viewModel.updateState(user.details.copy(password = it)) },
|
||||||
|
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
||||||
|
trailingIcon = {
|
||||||
|
val image = if (passwordVisible)
|
||||||
|
Icons.Filled.Close
|
||||||
|
else Icons.Filled.Check
|
||||||
|
|
||||||
|
val description = if (passwordVisible) "Hide password" else "Show password"
|
||||||
|
|
||||||
|
IconButton(onClick = { passwordVisible = !passwordVisible }) {
|
||||||
|
Icon(imageVector = image, description)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
Spacer(Modifier.padding(bottom = 20.dp))
|
Spacer(Modifier.padding(bottom = 20.dp))
|
||||||
Button(
|
Button(
|
||||||
@ -68,15 +84,13 @@ fun Enter(navController: NavController) {
|
|||||||
.padding(all = 10.dp),
|
.padding(all = 10.dp),
|
||||||
onClick = {
|
onClick = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
//if( AppDatabase.getInstance(context).userDao().tryLogin(login.toString(), password.toString()) != null){
|
if(viewModel.signIn(context) != null) {
|
||||||
// SingletonClass.setUserId(AppDatabase.getInstance(context).userDao().tryLogin(login.toString(), password.toString())?.uid!!)
|
navController?.navigate(Screen.Profile.route)
|
||||||
//SingletonClass.setRole(AppDatabase.getInstance(context).userDao().tryLogin(login.toString(), password.toString())?.role!!)
|
}
|
||||||
navController?.navigate(Screen.Profile.route)
|
else{
|
||||||
//}
|
val toast = Toast.makeText(MainActivity.appContext, "Неверный логин или пароль", Toast.LENGTH_SHORT)
|
||||||
//else{
|
toast.show()
|
||||||
// val toast = Toast.makeText(MainActivity.appContext, "Неверный логин или пароль", Toast.LENGTH_SHORT)
|
}
|
||||||
// toast.show()
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Text(stringResource(id = R.string.enter))
|
Text(stringResource(id = R.string.enter))
|
||||||
|
@ -1,66 +1,33 @@
|
|||||||
package com.example.myapplication.composeui
|
package com.example.myapplication.composeui
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.BorderStroke
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
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.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.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedButton
|
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
|
||||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.example.myapplication.composeui.navigation.Screen
|
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.R
|
||||||
import com.example.myapplication.SingletonClass
|
import com.example.myapplication.store.LiveStore
|
||||||
import com.example.myapplication.composeui.ViewModel.UserPageViewModel
|
|
||||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Profile(navController: NavController) {
|
fun Profile(navController: NavController) {
|
||||||
var SingletonClass = SingletonClass()
|
|
||||||
Column(Modifier.padding(all = 40.dp)) {
|
Column(Modifier.padding(all = 40.dp)) {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(id = R.drawable.user),
|
painter = painterResource(id = R.drawable.user),
|
||||||
@ -70,17 +37,22 @@ fun Profile(navController: NavController) {
|
|||||||
.clickable(
|
.clickable(
|
||||||
enabled = true,
|
enabled = true,
|
||||||
onClick = {
|
onClick = {
|
||||||
navController?.navigate(
|
navController?.navigate(Screen.ProfileEdit.route.replace("{id}", LiveStore.getUserId().toString()))
|
||||||
Screen.ProfileEdit.route.replace(
|
|
||||||
"{id}",
|
|
||||||
SingletonClass.getUserId().toString()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
Spacer (Modifier.padding(bottom = 10.dp))
|
Spacer (Modifier.padding(bottom = 10.dp))
|
||||||
Text("Открыть профиль", modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
|
Text("Открыть профиль", modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
|
||||||
|
Spacer(Modifier.padding(bottom = 20.dp))
|
||||||
|
Button(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(all = 10.dp),
|
||||||
|
onClick = {
|
||||||
|
navController?.navigate(Screen.UserBooks.route.replace("{id}", LiveStore.getUserId().toString()))
|
||||||
|
}) {
|
||||||
|
Text(stringResource(id = R.string.my_books))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,14 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
@ -22,49 +28,83 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.example.myapplication.composeui.navigation.Screen
|
import com.example.myapplication.composeui.navigation.Screen
|
||||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||||
import com.example.myapplication.R
|
import com.example.myapplication.R
|
||||||
import com.example.myapplication.db.database.AppDatabase
|
import com.example.myapplication.composeui.ViewModel.UserDetails
|
||||||
import com.example.myapplication.db.model.User
|
import com.example.myapplication.composeui.ViewModel.UserEditViewModel
|
||||||
|
import com.example.myapplication.composeui.ViewModel.UserUiState
|
||||||
|
import com.example.myapplication.store.LiveStore
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Registration(navController: NavController, viewModel: UserEditViewModel = viewModel(factory = AppViewModelProvider.Factory)){
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
Registration(
|
||||||
|
navController = navController,
|
||||||
|
userUiState = viewModel.userUiState,
|
||||||
|
onClick = {
|
||||||
|
scope.launch {
|
||||||
|
viewModel.saveUser()
|
||||||
|
navController?.navigate(Screen.Enter.route)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onUpdate = viewModel::updateUiState
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun Registration(navController: NavController) {
|
private fun Registration(
|
||||||
val scope = rememberCoroutineScope()
|
navController: NavController,
|
||||||
val context = LocalContext.current
|
userUiState: UserUiState,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
onUpdate: (UserDetails) -> Unit
|
||||||
|
) {
|
||||||
|
onUpdate(userUiState.userDetails.copy(role = "USER"))
|
||||||
Column(Modifier.fillMaxWidth().padding(all = 40.dp)) {
|
Column(Modifier.fillMaxWidth().padding(all = 40.dp)) {
|
||||||
var mail by remember{mutableStateOf("")}
|
|
||||||
Text(stringResource(id = R.string.email))
|
Text(stringResource(id = R.string.email))
|
||||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||||
value = mail, onValueChange = { mail = it },
|
value = userUiState.userDetails.email, onValueChange = { onUpdate(userUiState.userDetails.copy(email = it)) },
|
||||||
)
|
)
|
||||||
Spacer(Modifier.padding(bottom = 10.dp))
|
Spacer(Modifier.padding(bottom = 10.dp))
|
||||||
var login by remember{mutableStateOf("")}
|
|
||||||
Text(stringResource(id = R.string.login))
|
Text(stringResource(id = R.string.login))
|
||||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||||
value = login, onValueChange = { login = it },
|
value = userUiState.userDetails.login, onValueChange = { onUpdate(userUiState.userDetails.copy(login = it)) },
|
||||||
)
|
)
|
||||||
Spacer(Modifier.padding(bottom = 10.dp))
|
Spacer(Modifier.padding(bottom = 10.dp))
|
||||||
var password by remember{mutableStateOf("")}
|
var passwordVisible by rememberSaveable { mutableStateOf(false) }
|
||||||
Text(stringResource(id = R.string.password))
|
Text(stringResource(id = R.string.password))
|
||||||
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
|
||||||
value = password, onValueChange = { password = it },
|
value = userUiState.userDetails.password, onValueChange = { onUpdate(userUiState.userDetails.copy(password = it)) },
|
||||||
|
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
||||||
|
trailingIcon = {
|
||||||
|
val image = if (passwordVisible)
|
||||||
|
Icons.Filled.Close
|
||||||
|
else Icons.Filled.Check
|
||||||
|
|
||||||
|
val description = if (passwordVisible) "Hide password" else "Show password"
|
||||||
|
|
||||||
|
IconButton(onClick = { passwordVisible = !passwordVisible }) {
|
||||||
|
Icon(imageVector = image, description)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
Spacer(Modifier.padding(bottom = 20.dp))
|
Spacer(Modifier.padding(bottom = 20.dp))
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(all = 10.dp),
|
.padding(all = 10.dp),
|
||||||
onClick = {
|
onClick = onClick
|
||||||
scope.launch{
|
) {
|
||||||
//AppDatabase.getInstance(context).userDao().insert(User(0, login.toString(), password.toString(), mail.toString(), "USER"))
|
|
||||||
}
|
|
||||||
navController?.navigate(Screen.Enter.route)
|
|
||||||
}) {
|
|
||||||
Text(stringResource(id = R.string.create_acc))
|
Text(stringResource(id = R.string.create_acc))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.example.myapplication.composeui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import androidx.paging.compose.LazyPagingItems
|
||||||
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
|
import com.example.myapplication.composeui.ViewModel.UserBooksViewModel
|
||||||
|
import com.example.myapplication.db.model.Book
|
||||||
|
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun UserBooks(navController: NavController, userId: Int, viewModel: UserBooksViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val userBooksUiState = viewModel.userBooksUiState
|
||||||
|
val pagingBook: LazyPagingItems<Book> = viewModel.bookPagedData.collectAsLazyPagingItems()
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
viewModel.refreshState()
|
||||||
|
}
|
||||||
|
fun refresh(){
|
||||||
|
coroutineScope.launch { viewModel.refreshState() }
|
||||||
|
}
|
||||||
|
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 180.dp)){
|
||||||
|
items (pagingBook.itemCount){
|
||||||
|
index -> BookCell(navController = navController, book = pagingBook[index]!!.copy())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 UserBooksPreview() {
|
||||||
|
MyApplicationTheme {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
UserBooks(navController = rememberNavController(), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.example.myapplication.composeui.ViewModel
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import androidx.paging.filter
|
||||||
|
import com.example.myapplication.db.model.Book
|
||||||
|
import com.example.myapplication.db.respository.BookRepository
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class AuthorBooksViewModel(savedStateHandle: SavedStateHandle, private val bookRepository: BookRepository) : ViewModel(){
|
||||||
|
private val authorUid: Int = checkNotNull(savedStateHandle["id"])
|
||||||
|
var authorBooksUiState by mutableStateOf(AuthorBooksUiState())
|
||||||
|
private set
|
||||||
|
init {
|
||||||
|
viewModelScope.launch {
|
||||||
|
refreshState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
suspend fun refreshState() {
|
||||||
|
authorBooksUiState = AuthorBooksUiState(bookRepository.getByUserId(authorUid))
|
||||||
|
}
|
||||||
|
|
||||||
|
val bookPagedData: Flow<PagingData<Book>> = bookRepository.loadAllBooksPaged().map{
|
||||||
|
x -> x.filter{
|
||||||
|
y-> (y.authorId == authorUid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AuthorBooksUiState(val bookList: List<Book> = listOf())
|
@ -0,0 +1,51 @@
|
|||||||
|
package com.example.myapplication.composeui.ViewModel
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.example.myapplication.db.model.User
|
||||||
|
import com.example.myapplication.db.respository.UserRepository
|
||||||
|
import com.example.myapplication.store.LiveStore
|
||||||
|
import com.example.myapplication.store.PreferencesStore
|
||||||
|
|
||||||
|
class LoginViewModel (
|
||||||
|
private val userRepository: UserRepository
|
||||||
|
) : ViewModel() {
|
||||||
|
var signInUserState by mutableStateOf(SignInUserState())
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun updateState(signInUserDetails: SignInUserDetails) {
|
||||||
|
signInUserState = SignInUserState(
|
||||||
|
details = signInUserDetails
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SuspiciousIndentation")
|
||||||
|
suspend fun signIn(context: Context): User? {
|
||||||
|
val user: User? = userRepository.tryLogin(signInUserState.details.login, signInUserState.details.password)
|
||||||
|
if(user != null) {
|
||||||
|
val store = PreferencesStore(context)
|
||||||
|
store.setUid(user.uid.toString())
|
||||||
|
LiveStore.user.value = user.copy()
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
signInUserState = SignInUserState(
|
||||||
|
details = signInUserState.details,
|
||||||
|
)
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class SignInUserDetails(
|
||||||
|
val login: String = "",
|
||||||
|
val password: String = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
data class SignInUserState(
|
||||||
|
val details: SignInUserDetails = SignInUserDetails(),
|
||||||
|
)
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.example.myapplication.composeui.ViewModel
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import androidx.paging.filter
|
||||||
|
import com.example.myapplication.db.model.Book
|
||||||
|
import com.example.myapplication.db.respository.BookRepository
|
||||||
|
import com.example.myapplication.store.LiveStore
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class UserBooksViewModel(private val bookRepository: BookRepository) : ViewModel(){
|
||||||
|
private val userUid: Int = LiveStore.user.value?.uid ?: 0
|
||||||
|
var userBooksUiState by mutableStateOf(UserBooksUiState())
|
||||||
|
private set
|
||||||
|
init {
|
||||||
|
viewModelScope.launch {
|
||||||
|
refreshState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
suspend fun refreshState() {
|
||||||
|
userBooksUiState = UserBooksUiState(bookRepository.getByUserId(userUid))
|
||||||
|
}
|
||||||
|
|
||||||
|
val bookPagedData: Flow<PagingData<Book>> = bookRepository.loadAllBooksPaged().map{
|
||||||
|
x -> x.filter{
|
||||||
|
y-> (y.userId == userUid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class UserBooksUiState(val bookList: List<Book> = listOf())
|
@ -9,6 +9,7 @@ import androidx.lifecycle.ViewModel
|
|||||||
import com.example.myapplication.db.respository.UserRepository
|
import com.example.myapplication.db.respository.UserRepository
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.example.myapplication.db.model.User
|
import com.example.myapplication.db.model.User
|
||||||
|
import com.example.myapplication.store.LiveStore
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class UserEditViewModel(savedStateHandle: SavedStateHandle,
|
class UserEditViewModel(savedStateHandle: SavedStateHandle,
|
||||||
@ -17,7 +18,7 @@ class UserEditViewModel(savedStateHandle: SavedStateHandle,
|
|||||||
var userUiState by mutableStateOf(UserUiState())
|
var userUiState by mutableStateOf(UserUiState())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private val userUid: Int = checkNotNull(savedStateHandle["id"])
|
private val userUid: Int = LiveStore.user.value?.uid ?: 0
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (userUid > 0) {
|
if (userUid > 0) {
|
||||||
|
@ -9,21 +9,21 @@ import androidx.lifecycle.SavedStateHandle
|
|||||||
import com.example.myapplication.db.model.User
|
import com.example.myapplication.db.model.User
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import com.example.myapplication.db.respository.UserRepository
|
import com.example.myapplication.db.respository.UserRepository
|
||||||
|
import com.example.myapplication.store.LiveStore
|
||||||
|
|
||||||
|
|
||||||
class UserPageViewModel(savedStateHandle: SavedStateHandle, private val userRepository: UserRepository) : ViewModel(){
|
class UserPageViewModel(savedStateHandle: SavedStateHandle, private val userRepository: UserRepository) : ViewModel(){
|
||||||
private val userId: Int = checkNotNull(savedStateHandle["id"])
|
|
||||||
var userPageUiState by mutableStateOf(UserPageUiState())
|
var userPageUiState by mutableStateOf(UserPageUiState())
|
||||||
private set
|
private set
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (userId > 0) {
|
if (LiveStore.user.value != null) {
|
||||||
refreshState()
|
refreshState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
suspend fun refreshState() {
|
suspend fun refreshState() {
|
||||||
userPageUiState = UserPageUiState(userRepository.getByUid(userId))
|
userPageUiState = UserPageUiState(LiveStore.user.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.example.myapplication.composeui.authenticator
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.example.myapplication.store.LiveStore
|
||||||
|
import com.example.myapplication.store.PreferencesStore
|
||||||
|
import com.example.myapplication.composeui.AppViewModelProvider
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Authenticator(
|
||||||
|
viewModel: AuthenticatorViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val store = PreferencesStore(context)
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val uid = store.getUid().collectAsState(initial = "").value
|
||||||
|
|
||||||
|
fun synchronize() {
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
if (uid == "") {
|
||||||
|
LiveStore.user.value = null
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
viewModel.findUserByUid(uid.toInt())
|
||||||
|
}
|
||||||
|
catch (_: Exception){}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronize()
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.example.myapplication.composeui.authenticator
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.example.myapplication.db.model.User
|
||||||
|
import com.example.myapplication.db.respository.UserRepository
|
||||||
|
|
||||||
|
class AuthenticatorViewModel(
|
||||||
|
private val userRepository: UserRepository
|
||||||
|
) : ViewModel() {
|
||||||
|
var authUiState by mutableStateOf(AuthenticatorUiState())
|
||||||
|
private set
|
||||||
|
|
||||||
|
suspend fun findUserByUid(uid: Int) {
|
||||||
|
authUiState = AuthenticatorUiState(userRepository.getByUid(uid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class AuthenticatorUiState(val user: User? = null)
|
@ -36,6 +36,7 @@ import androidx.navigation.compose.rememberNavController
|
|||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||||
import com.example.myapplication.R
|
import com.example.myapplication.R
|
||||||
|
import com.example.myapplication.composeui.AuthorBooks
|
||||||
import com.example.myapplication.composeui.Main
|
import com.example.myapplication.composeui.Main
|
||||||
import com.example.myapplication.composeui.Registration
|
import com.example.myapplication.composeui.Registration
|
||||||
import com.example.myapplication.composeui.Enter
|
import com.example.myapplication.composeui.Enter
|
||||||
@ -49,6 +50,7 @@ import com.example.myapplication.composeui.BookEdit
|
|||||||
import com.example.myapplication.composeui.BookSearch
|
import com.example.myapplication.composeui.BookSearch
|
||||||
import com.example.myapplication.composeui.ListAuthors
|
import com.example.myapplication.composeui.ListAuthors
|
||||||
import com.example.myapplication.composeui.AuthorEdit
|
import com.example.myapplication.composeui.AuthorEdit
|
||||||
|
import com.example.myapplication.composeui.UserBooks
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
@ -163,6 +165,18 @@ fun Navhost(
|
|||||||
) { backStackEntry ->
|
) { backStackEntry ->
|
||||||
backStackEntry.arguments?.let { BookSearch(navController = navController ,it.getString ("searchStr", "")) }
|
backStackEntry.arguments?.let { BookSearch(navController = navController ,it.getString ("searchStr", "")) }
|
||||||
}
|
}
|
||||||
|
composable(
|
||||||
|
Screen.AuthorBooks.route,
|
||||||
|
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||||
|
) { backStackEntry ->
|
||||||
|
backStackEntry.arguments?.let { AuthorBooks(navController = navController, it.getInt("id")) }
|
||||||
|
}
|
||||||
|
composable(
|
||||||
|
Screen.UserBooks.route,
|
||||||
|
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||||
|
) { backStackEntry ->
|
||||||
|
backStackEntry.arguments?.let { UserBooks(navController = navController, it.getInt("id")) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,12 @@ enum class Screen(
|
|||||||
BookSearch(
|
BookSearch(
|
||||||
"book-search/{searchStr}", R.string.search, showInBottomBar = false
|
"book-search/{searchStr}", R.string.search, showInBottomBar = false
|
||||||
),
|
),
|
||||||
|
AuthorBooks(
|
||||||
|
"author-books/{id}", R.string.authors_books, showInBottomBar = false
|
||||||
|
),
|
||||||
|
UserBooks(
|
||||||
|
"user-books/{id}", R.string.my_books, showInBottomBar = false
|
||||||
|
),
|
||||||
BookView(
|
BookView(
|
||||||
"book-view/{id}", R.string.book_view_title, showInBottomBar = false
|
"book-view/{id}", R.string.book_view_title, showInBottomBar = false
|
||||||
),
|
),
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.example.myapplication.store
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.example.myapplication.db.model.User
|
||||||
|
|
||||||
|
class LiveStore{
|
||||||
|
companion object{
|
||||||
|
val user = MutableLiveData<User?>(null)
|
||||||
|
fun getUserId(): Int{
|
||||||
|
return user.value?.uid ?: 0
|
||||||
|
}
|
||||||
|
fun getRole(): String{
|
||||||
|
return user.value?.role ?: "USER"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.example.myapplication.store
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.preferences.core.Preferences
|
||||||
|
import androidx.datastore.preferences.core.edit
|
||||||
|
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||||
|
import androidx.datastore.preferences.preferencesDataStore
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
class PreferencesStore(private val context: Context) {
|
||||||
|
companion object {
|
||||||
|
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore("Store")
|
||||||
|
val UID = stringPreferencesKey("uid")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUid(): Flow<String> {
|
||||||
|
return context.dataStore.data
|
||||||
|
.map { preferences ->
|
||||||
|
preferences[UID] ?: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun saveStringValue(key: Preferences.Key<String>, value: String) {
|
||||||
|
context.dataStore.edit { preferences ->
|
||||||
|
preferences[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun setUid(uid: String) {
|
||||||
|
saveStringValue(UID, uid)
|
||||||
|
}
|
||||||
|
}
|
@ -12,21 +12,14 @@
|
|||||||
<string name="listauthors">Писатели</string>
|
<string name="listauthors">Писатели</string>
|
||||||
<string name="author">Писатель</string>
|
<string name="author">Писатель</string>
|
||||||
<string name="book_view_title">Книга</string>
|
<string name="book_view_title">Книга</string>
|
||||||
|
<string name="books">Книги</string>
|
||||||
|
<string name="my_books">Мои книги</string>
|
||||||
|
<string name="authors_books">Книги автора</string>
|
||||||
<string name="enter">Войти</string>
|
<string name="enter">Войти</string>
|
||||||
<string name="create_acc">Создать аккаунт</string>
|
<string name="create_acc">Создать аккаунт</string>
|
||||||
<string name="email">Почта</string>
|
<string name="email">Почта</string>
|
||||||
<string name="login">Логин</string>
|
<string name="login">Логин</string>
|
||||||
<string name="password">Пароль</string>
|
<string name="password">Пароль</string>
|
||||||
<string name="stats">
|
|
||||||
<p>Пользователь</p>\n
|
|
||||||
<p>User1</p>\n\n
|
|
||||||
<p>Дата регистрации</p>\n
|
|
||||||
<p>20.09.2023</p>\n\n
|
|
||||||
<p>Прочитано книг</p>\n
|
|
||||||
<p>7</p>\n\n
|
|
||||||
<p>Загружено книг</p>\n
|
|
||||||
<p>0</p>
|
|
||||||
</string>
|
|
||||||
<string name="book_title">Название</string>
|
<string name="book_title">Название</string>
|
||||||
<string name="author_name">Автор</string>
|
<string name="author_name">Автор</string>
|
||||||
<string name="description">Содержание</string>
|
<string name="description">Содержание</string>
|
||||||
@ -37,5 +30,4 @@
|
|||||||
<string name="load_book">Загрузить</string>
|
<string name="load_book">Загрузить</string>
|
||||||
<string name="add_book">Добавить</string>
|
<string name="add_book">Добавить</string>
|
||||||
<string name="read_book">Читать</string>
|
<string name="read_book">Читать</string>
|
||||||
<string name="help_me_pls">Вы можете помочь нашей библиотеке, загрузив свою книгу.</string>
|
|
||||||
</resources>
|
</resources>
|
@ -3,6 +3,6 @@
|
|||||||
<domain-config cleartextTrafficPermitted="true">
|
<domain-config cleartextTrafficPermitted="true">
|
||||||
<domain includeSubdomains="true">100.87.48.148</domain>
|
<domain includeSubdomains="true">100.87.48.148</domain>
|
||||||
<domain includeSubdomains="true">192.168.43.198</domain>
|
<domain includeSubdomains="true">192.168.43.198</domain>
|
||||||
<domain includeSubdomains="true">89.239.172.45</domain>
|
<domain includeSubdomains="true">89.239.174.67</domain>
|
||||||
</domain-config>
|
</domain-config>
|
||||||
</network-security-config>
|
</network-security-config>
|
Loading…
Reference in New Issue
Block a user