Course work: implement login
This commit is contained in:
parent
d79f6982fe
commit
a687ff002f
@ -94,4 +94,7 @@ dependencies {
|
||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
||||
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
||||
|
||||
implementation("javax.inject:javax.inject:1")
|
||||
implementation("androidx.compose.runtime:runtime-livedata")
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
package com.example.mobile_labs.api
|
||||
|
||||
import android.util.Log
|
||||
import com.example.mobile_labs.api.models.Credentials
|
||||
import com.example.mobile_labs.api.models.EventRemote
|
||||
import com.example.mobile_labs.api.models.PerformanceRemote
|
||||
import com.example.mobile_labs.api.models.PersonRemote
|
||||
import com.example.mobile_labs.api.models.Token
|
||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
@ -52,6 +55,11 @@ interface MyServerService {
|
||||
@Path("id") id: Int,
|
||||
): EventRemote
|
||||
|
||||
@POST("api/login")
|
||||
suspend fun login(
|
||||
@Body credentials: Credentials
|
||||
): Token
|
||||
|
||||
companion object {
|
||||
private const val BASE_URL = "http://10.0.2.2:8000/"
|
||||
|
||||
@ -96,6 +104,10 @@ interface MyServerService {
|
||||
}
|
||||
}
|
||||
|
||||
fun getToken(): String {
|
||||
return _token
|
||||
}
|
||||
|
||||
fun setToken(token: String) {
|
||||
_token = token
|
||||
}
|
||||
|
@ -4,6 +4,6 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Credentials(
|
||||
val login: String = "",
|
||||
val email: String = "",
|
||||
val password: String = "",
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
package com.example.mobile_labs.api.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Token(
|
||||
val token: String
|
||||
)
|
@ -72,8 +72,8 @@ class PeopleRemoteMediator(
|
||||
)
|
||||
}
|
||||
|
||||
// dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.PERSON)
|
||||
// dbPersonRepository.clearPeople()
|
||||
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.PERSON)
|
||||
dbPersonRepository.clearPeople()
|
||||
dbRemoteKeyRepository.createRemoteKeys(keys)
|
||||
dbPersonRepository.insertPeople(people)
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.example.mobile_labs.TheatreApplication
|
||||
import com.example.mobile_labs.ui.event.list.EventListViewModel
|
||||
import com.example.mobile_labs.ui.login.LoginViewModel
|
||||
import com.example.mobile_labs.ui.performance.list.PerformanceListViewModel
|
||||
import com.example.mobile_labs.ui.performance.view.PerformanceViewModel
|
||||
import com.example.mobile_labs.ui.person.list.PeopleListViewModel
|
||||
@ -25,6 +26,9 @@ object AppViewModelProvider {
|
||||
initializer {
|
||||
PerformanceViewModel(this.createSavedStateHandle(), theatreApplication().container.performanceRestRepository)
|
||||
}
|
||||
initializer {
|
||||
LoginViewModel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
116
app/src/main/java/com/example/mobile_labs/ui/login/Login.kt
Normal file
116
app/src/main/java/com/example/mobile_labs/ui/login/Login.kt
Normal file
@ -0,0 +1,116 @@
|
||||
package com.example.mobile_labs.ui.login
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.*
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.unit.*
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import com.example.mobile_labs.R
|
||||
import com.example.mobile_labs.common.AppViewModelProvider
|
||||
import com.example.mobile_labs.ui.navigation.Screen
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
fun Login(
|
||||
navController: NavHostController,
|
||||
viewModel: LoginViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val success = viewModel.successState.observeAsState().value
|
||||
|
||||
val login = remember { mutableStateOf(TextFieldValue(""))}
|
||||
val password = remember { mutableStateOf(TextFieldValue(""))}
|
||||
|
||||
if (success == false) {
|
||||
AlertDialog(
|
||||
title = {
|
||||
Text(
|
||||
text = "Ошибка авторизации",
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 20.sp
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
text = "Неверный логин или пароль",
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp
|
||||
)
|
||||
},
|
||||
onDismissRequest = {
|
||||
viewModel.calmSuccessState()
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
viewModel.calmSuccessState()
|
||||
}
|
||||
) {
|
||||
Text("OK")
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxWidth(0.7f).fillMaxHeight().padding(vertical=100.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Вход",
|
||||
style = TextStyle(
|
||||
fontSize = 40.sp,
|
||||
fontWeight = FontWeight(400),
|
||||
),
|
||||
modifier = Modifier.fillMaxHeight(0.3f)
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom=30.dp),
|
||||
value = login.value,
|
||||
onValueChange = { login.value = it },
|
||||
label = { Text(stringResource(id = R.string.login)) },
|
||||
singleLine = true
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom=30.dp),
|
||||
value = password.value,
|
||||
onValueChange = { password.value = it },
|
||||
label = { Text(stringResource(id = R.string.password)) },
|
||||
singleLine = true
|
||||
)
|
||||
Button(
|
||||
{
|
||||
viewModel.login(login.value.text, password.value.text, navController)
|
||||
},
|
||||
modifier = Modifier.padding(bottom=20.dp).fillMaxWidth(0.5f)
|
||||
) {
|
||||
Text(
|
||||
text = "Войти",
|
||||
style = TextStyle(
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight(400),
|
||||
color = Color(0xFFFFFFFF),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.example.mobile_labs.ui.login
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.navigation.NavHostController
|
||||
import com.example.mobile_labs.api.MyServerService
|
||||
import com.example.mobile_labs.api.models.Credentials
|
||||
import com.example.mobile_labs.ui.navigation.Screen
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoginViewModel : ViewModel() {
|
||||
private val _successState = MutableLiveData<Boolean?>()
|
||||
val successState: LiveData<Boolean?>
|
||||
get() = _successState
|
||||
|
||||
fun calmSuccessState() {
|
||||
_successState.postValue(null)
|
||||
}
|
||||
|
||||
fun login(login: String, password: String, navController: NavHostController) {
|
||||
viewModelScope.launch {
|
||||
val token = MyServerService.getInstance().login(Credentials(login, password))
|
||||
|
||||
if (token.token.isEmpty()) {
|
||||
_successState.postValue(false)
|
||||
return@launch
|
||||
}
|
||||
|
||||
MyServerService.setToken(token.token)
|
||||
|
||||
_successState.setValue(true)
|
||||
|
||||
navigate(navController)
|
||||
}
|
||||
}
|
||||
fun navigate(navController: NavHostController) {
|
||||
Screen.About.route.let {
|
||||
navController.navigate(it) {
|
||||
popUpTo(it) {
|
||||
inclusive = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -33,8 +33,10 @@ import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import com.example.mobile_labs.ui.theme.Mobile_LabsTheme
|
||||
import com.example.mobile_labs.R
|
||||
import com.example.mobile_labs.api.MyServerService
|
||||
import com.example.mobile_labs.ui.about.About
|
||||
import com.example.mobile_labs.ui.event.list.EventList
|
||||
import com.example.mobile_labs.ui.login.Login
|
||||
import com.example.mobile_labs.ui.performance.list.PerformanceList
|
||||
import com.example.mobile_labs.ui.performance.view.PerformanceView
|
||||
import com.example.mobile_labs.ui.person.list.PeopleList
|
||||
@ -78,6 +80,7 @@ fun Navbar(
|
||||
) {
|
||||
NavigationBar(modifier) {
|
||||
Screen.bottomBarItems.forEach { screen ->
|
||||
if (MyServerService.getToken().isBlank() || screen.route !== "login") {
|
||||
NavigationBarItem(
|
||||
icon = { Icon(screen.icon, contentDescription = null) },
|
||||
label = { Text(stringResource(screen.resourceId)) },
|
||||
@ -85,16 +88,17 @@ fun Navbar(
|
||||
onClick = {
|
||||
navController.navigate(screen.route) {
|
||||
popUpTo(navController.graph.findStartDestination().id) {
|
||||
saveState = true
|
||||
saveState = false
|
||||
}
|
||||
launchSingleTop = true
|
||||
restoreState = true
|
||||
restoreState = false
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Navhost(
|
||||
@ -108,9 +112,14 @@ fun Navhost(
|
||||
modifier.padding(innerPadding)
|
||||
) {
|
||||
composable(Screen.Schedule.route) { EventList(navController) }
|
||||
composable(Screen.Repertoire.route) { PerformanceList(navController) }
|
||||
composable(Screen.Repertoire.route) {
|
||||
PerformanceList(navController)
|
||||
}
|
||||
composable(Screen.PeopleList.route) { PeopleList() }
|
||||
composable(Screen.About.route) { About() }
|
||||
if (MyServerService.getToken().isBlank()) {
|
||||
composable(Screen.Login.route) { Login(navController) }
|
||||
}
|
||||
composable(
|
||||
Screen.PerformanceView.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||
|
@ -3,12 +3,14 @@ package com.example.mobile_labs.ui.navigation
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.DateRange
|
||||
import androidx.compose.material.icons.filled.Face
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
import androidx.compose.material.icons.filled.List
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.example.mobile_labs.R
|
||||
import com.example.mobile_labs.api.MyServerService
|
||||
|
||||
enum class Screen(
|
||||
val route: String,
|
||||
@ -30,10 +32,19 @@ enum class Screen(
|
||||
),
|
||||
About(
|
||||
"about", R.string.about_main_title, Icons.Filled.Info
|
||||
),
|
||||
Login(
|
||||
"login", R.string.login_main_title, Icons.Filled.Face
|
||||
);
|
||||
|
||||
companion object {
|
||||
val bottomBarItems = listOf(
|
||||
val bottomBarItems = if (MyServerService.getToken().isBlank()) listOf(
|
||||
Schedule,
|
||||
Repertoire,
|
||||
PeopleList,
|
||||
About,
|
||||
Login
|
||||
) else listOf(
|
||||
Schedule,
|
||||
Repertoire,
|
||||
PeopleList,
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.example.mobile_labs.ui.performance.list
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@ -28,6 +29,7 @@ import androidx.paging.compose.itemContentType
|
||||
import androidx.paging.compose.itemKey
|
||||
import coil.compose.AsyncImage
|
||||
import com.example.mobile_labs.R
|
||||
import com.example.mobile_labs.api.MyServerService
|
||||
import com.example.mobile_labs.database.performance.model.Performance
|
||||
import com.example.mobile_labs.common.AppViewModelProvider
|
||||
import com.example.mobile_labs.ui.navigation.Screen
|
||||
|
@ -6,12 +6,15 @@
|
||||
<string name="performance_author">Автор</string>
|
||||
<string name="performance_director">Режиссёр</string>
|
||||
<string name="performance_actors">Актёры</string>
|
||||
<string name="people_main_title">Люди театра</string>
|
||||
<string name="people_main_title">Труппа</string>
|
||||
<string name="about_main_title">О нас</string>
|
||||
<string name="login_main_title">Вход</string>
|
||||
<string name="performance_view_main_title">Представление</string>
|
||||
<string name="people_missing_description">Данные о людях отсутствуют</string>
|
||||
<string name="events_missing_description">Данные о событиях отсутствуют</string>
|
||||
<string name="performance_missing_description">Данные о представлениях отсутствуют</string>
|
||||
<string name="login">Логин</string>
|
||||
<string name="password">Пароль</string>
|
||||
<string name="about_text">
|
||||
<p>
|
||||
Netus quis congue nascetur ullamcorper nibh, nostra iaculis turpis! Facilisi pretium vehicula purus porttitor vitae aliquet dignissim. Donec diam molestie litora magnis dolor aptent scelerisque mus. Sit mi, venenatis interdum. Commodo vel malesuada tincidunt eget. Aenean laoreet lacinia platea sem? Libero urna odio diam? Nisl, sodales nisi gravida. Interdum elementum libero turpis dapibus tristique per sed maecenas ante integer massa? Tortor molestie sapien himenaeos condimentum. Facilisis accumsan ullamcorper semper fermentum elementum quisque. Curae;, vivamus ante hac elit fringilla odio ornare curabitur quisque magna commodo. Placerat proin!
|
||||
|
Loading…
Reference in New Issue
Block a user