Compare commits

...

6 Commits
design ... main

Author SHA1 Message Date
3190a26884 / 2025-02-20 13:59:15 +00:00
2118e137b2 / 2025-02-20 13:58:49 +00:00
bbc19ecd48 refactoring 2025-02-20 16:52:13 +03:00
69ddacabcf minor refactoring 2025-02-20 16:32:08 +03:00
901fb22198 Merge branch 'main' of https://gitnto.innovationcampus.ru/pedro/minipigs-front 2025-02-20 16:28:13 +03:00
46414f93bb base functionality fully implemented 2025-02-20 16:24:46 +03:00
15 changed files with 125 additions and 59 deletions

BIN
app-debug.apk Normal file

Binary file not shown.

View File

@ -33,6 +33,7 @@ import kotlinx.coroutines.runBlocking
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.datastore.preferences.core.booleanPreferencesKey
import com.example.nto_minipigs.ui.screens.QR.QRResultScreen import com.example.nto_minipigs.ui.screens.QR.QRResultScreen
import com.example.nto_minipigs.ui.screens.QR.QRScreen import com.example.nto_minipigs.ui.screens.QR.QRScreen
import com.example.nto_minipigs.ui.screens.QR.QRViewModel import com.example.nto_minipigs.ui.screens.QR.QRViewModel
@ -54,9 +55,7 @@ class MainActivity : ComponentActivity() {
val mainViewModel = ViewModelProvider(this)[MainViewModel::class.java] val mainViewModel = ViewModelProvider(this)[MainViewModel::class.java]
val qrViewModel = ViewModelProvider(this)[QRViewModel::class.java] val qrViewModel = ViewModelProvider(this)[QRViewModel::class.java]
val token = dataStore.getToken() val token = dataStore.getLogin()
Log.d("token", token.toString())
NavHost( NavHost(
navController = navController, navController = navController,
@ -64,7 +63,7 @@ class MainActivity : ComponentActivity() {
) { ) {
composable<Login> { LoginScreen( onNavigateToMain = { navController.popBackStack(); navController.navigate(route = Main) }, viewModel = loginViewModel, dataStore = dataStore ) } composable<Login> { LoginScreen( onNavigateToMain = { navController.popBackStack(); navController.navigate(route = Main) }, viewModel = loginViewModel, dataStore = dataStore ) }
composable<Main> { MainScreen( viewModel = mainViewModel, dataStore = dataStore, navController = navController ) } composable<Main> { MainScreen( viewModel = mainViewModel, dataStore = dataStore, navController = navController ) }
composable<QR> { QRScreen( navController = navController, viewModel = qrViewModel) } composable<QR> { QRScreen( navController = navController, viewModel = qrViewModel, dataStore = dataStore) }
composable<QRResult> { QRResultScreen( navController = navController, viewModel = qrViewModel ) } composable<QRResult> { QRResultScreen( navController = navController, viewModel = qrViewModel ) }
} }
} }
@ -86,8 +85,46 @@ class UserData(private val context: Context) {
settings[tokenKey] = data settings[tokenKey] = data
} }
fun getLogin():String {
return runBlocking { context.dataStore.data.map { preferences ->
preferences[loginKey]
}.first().toString()}
}
suspend fun updateLogin(data:String) =
context.dataStore.edit { settings ->
settings[loginKey] = data
}
fun getPassword():String {
return runBlocking { context.dataStore.data.map { preferences ->
preferences[passwordKey]
}.first().toString()}
}
suspend fun updatePassword(data:String) =
context.dataStore.edit { settings ->
settings[passwordKey] = data
}
fun getAdmin():Boolean {
return runBlocking {
context.dataStore.data.map { preferences ->
preferences[adminKey]
}.first() == true
}
}
suspend fun updateAdmin(data:Boolean) =
context.dataStore.edit { settings ->
settings[adminKey] = data
}
companion object { companion object {
val tokenKey = stringPreferencesKey("Bearer") val tokenKey = stringPreferencesKey("Bearer")
val loginKey = stringPreferencesKey("Login")
val passwordKey = stringPreferencesKey("Password")
val adminKey = booleanPreferencesKey("IsAdmin")
} }
} }

View File

@ -1,7 +1,7 @@
package com.example.nto_minipigs.Retrofit package com.example.nto_minipigs.Retrofit
import com.example.nto_minipigs.Retrofit.Models.Auth import com.example.nto_minipigs.Retrofit.Models.Auth
import com.example.nto_minipigs.Retrofit.Models.Data import com.example.nto_minipigs.Retrofit.Models.AuthResponse
import com.example.nto_minipigs.Retrofit.Models.Door import com.example.nto_minipigs.Retrofit.Models.Door
import com.example.nto_minipigs.Retrofit.Models.DoorResponse import com.example.nto_minipigs.Retrofit.Models.DoorResponse
import com.example.nto_minipigs.Retrofit.Models.User import com.example.nto_minipigs.Retrofit.Models.User
@ -18,12 +18,12 @@ public interface ApiService {
@GET("/api/{LOGIN}/auth") @GET("/api/{LOGIN}/auth")
suspend fun auth(@Path("LOGIN") login: String): ResponseBody suspend fun auth(@Path("LOGIN") login: String): ResponseBody
@GET("/api/info") @GET("/api/info/")
suspend fun info(@Header("Authorization") token: String): Response<User> suspend fun info(@Header("Authorization") token: String): Response<User>
@PATCH("/api/open") @PATCH("/api/open/")
suspend fun open(@Body data: Door): Response<DoorResponse> suspend fun open(@Header("Authorization") token: String, @Body data: Long): Response<DoorResponse>
@POST("/api/login") @POST("/api/login/")
suspend fun login(@Body data: Auth): Response<Data> suspend fun login(@Body data: Auth): Response<AuthResponse>
} }

View File

@ -1,5 +1,5 @@
package com.example.nto_minipigs.Retrofit.Models package com.example.nto_minipigs.Retrofit.Models
data class Data( data class AuthResponse(
val token: String val admin: Boolean
) )

View File

@ -1,5 +1,5 @@
package com.example.nto_minipigs.Retrofit.Models package com.example.nto_minipigs.Retrofit.Models
data class Door( data class Door(
val id: String val id: Long
) )

View File

@ -0,0 +1,8 @@
package com.example.nto_minipigs.Retrofit.Models
data class Entry(
val id: Long,
val employee: Long,
val time: String,
val place: Place,
)

View File

@ -0,0 +1,7 @@
package com.example.nto_minipigs.Retrofit.Models
data class Place(
val id: Long,
val value: Long,
val name: String,
)

View File

@ -7,5 +7,6 @@ data class User(
val password: String, val password: String,
val name: String, val name: String,
val photo: String, val photo: String,
val position: String val position: String,
val entries: ArrayList<Entry>
) )

View File

@ -1,7 +1,5 @@
package com.example.nto_minipigs.core package com.example.nto_minipigs.core
object Constants { object Constants {
const val SHARED_PREFS = "shared_prefs" const val SERVER_ADDRESS = "http://79.137.192.19:8080/"
const val EMAIL_KEY = "email_key"
const val SERVER_ADDRESS = "http:///192.168.99.212:5000"
} }

View File

@ -1,5 +1,6 @@
package com.example.nto_minipigs.ui.screens.Login package com.example.nto_minipigs.ui.screens.Login
import androidx.annotation.FontRes
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -19,6 +20,9 @@ import com.example.nto_minipigs.ui.theme.Nto_minipigsTheme
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.example.nto_minipigs.UserData import com.example.nto_minipigs.UserData
@ -35,6 +39,9 @@ fun LoginScreen(onNavigateToMain: () -> Unit, viewModel: LoginViewModel, dataSto
Text( Text(
text = "MiniPigs", text = "MiniPigs",
style = MaterialTheme.typography.displayMedium, style = MaterialTheme.typography.displayMedium,
fontWeight = FontWeight.ExtraBold,
fontStyle = FontStyle.Italic,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(bottom = 36.dp) modifier = Modifier.padding(bottom = 36.dp)
) )
@ -53,7 +60,7 @@ fun LoginScreen(onNavigateToMain: () -> Unit, viewModel: LoginViewModel, dataSto
value = password, value = password,
onValueChange = { password = it }, onValueChange = { password = it },
label = { Text("Password") }, label = { Text("Password") },
modifier = Modifier.padding(bottom = 12.dp), modifier = Modifier.padding(bottom = 16.dp),
shape = RoundedCornerShape(12.dp), shape = RoundedCornerShape(12.dp),
) )

View File

@ -17,7 +17,11 @@ class LoginViewModel :ViewModel() {
val auth = Auth(login, password) val auth = Auth(login, password)
val response = serviceApi.login(auth) val response = serviceApi.login(auth)
if(response.isSuccessful) { if(response.isSuccessful) {
dataStore.updateToken(response.body()?.token.toString()) // dataStore.updateToken(response.body()?.token.toString())
dataStore.updateLogin(login)
dataStore.updatePassword(password)
Log.d("yenis", (response.body()?.admin == true).toString())
dataStore.updateAdmin(response.body()?.admin == true)
// dataStore.updateToken("") // dataStore.updateToken("")
func() func()
} }

View File

@ -1,8 +1,8 @@
package com.example.nto_minipigs.ui.screens.Main package com.example.nto_minipigs.ui.screens.Main
import android.util.Log
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -15,43 +15,30 @@ import androidx.compose.foundation.layout.offset
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.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.Logout import androidx.compose.material.icons.automirrored.outlined.Logout
import androidx.compose.material.icons.filled.BookmarkRemove
import androidx.compose.material.icons.outlined.Logout
import androidx.compose.material.icons.outlined.QrCode import androidx.compose.material.icons.outlined.QrCode
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard import androidx.compose.material3.OutlinedCard
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.material3.rememberDateRangePickerState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect 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 com.example.nto_minipigs.ui.theme.Nto_minipigsTheme
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -60,7 +47,7 @@ import coil.compose.rememberAsyncImagePainter
import com.example.nto_minipigs.Login import com.example.nto_minipigs.Login
import com.example.nto_minipigs.QR import com.example.nto_minipigs.QR
import com.example.nto_minipigs.UserData import com.example.nto_minipigs.UserData
import kotlinx.coroutines.coroutineScope import com.example.nto_minipigs.ui.theme.Nto_minipigsTheme
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -69,6 +56,8 @@ fun MainScreen( viewModel: MainViewModel, dataStore: UserData, navController: Na
Nto_minipigsTheme { Nto_minipigsTheme {
val data = viewModel.data.observeAsState() val data = viewModel.data.observeAsState()
val token = dataStore.getToken() val token = dataStore.getToken()
val login = dataStore.getLogin()
val password = dataStore.getPassword()
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
Surface { Surface {
when(val result = data.value){ when(val result = data.value){
@ -85,6 +74,7 @@ fun MainScreen( viewModel: MainViewModel, dataStore: UserData, navController: Na
} }
} }
is NetworkResponse.Success -> { is NetworkResponse.Success -> {
Log.d("yenis", result.data.entries.toString())
Column ( Column (
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {
@ -95,7 +85,13 @@ fun MainScreen( viewModel: MainViewModel, dataStore: UserData, navController: Na
.height(200.dp), .height(200.dp),
) { ) {
IconButton( IconButton(
onClick = { coroutineScope.launch { dataStore.updateToken("") }; navController.popBackStack(); navController.navigate(Login) }, onClick = { coroutineScope.launch {
dataStore.updateToken("");
dataStore.updateLogin("");
dataStore.updateAdmin(false);
dataStore.updatePassword("") };
navController.popBackStack();
navController.navigate(Login) },
modifier = Modifier modifier = Modifier
.align(Alignment.TopEnd) .align(Alignment.TopEnd)
.size(20.dp) .size(20.dp)
@ -161,21 +157,23 @@ fun MainScreen( viewModel: MainViewModel, dataStore: UserData, navController: Na
.fillMaxSize() .fillMaxSize()
.background(MaterialTheme.colorScheme.surfaceContainerLow, RoundedCornerShape(topEnd = 24.dp , topStart = 24.dp)) .background(MaterialTheme.colorScheme.surfaceContainerLow, RoundedCornerShape(topEnd = 24.dp , topStart = 24.dp))
) { ) {
Column( LazyColumn(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxWidth()
.padding(horizontal = 20.dp) .padding(horizontal = 20.dp)
.padding(top = 8.dp) .padding(top = 8.dp)
.verticalScroll(rememberScrollState())
) { ) {
for(i in 1..24) { items(
items = result.data.entries,
key = { item -> item.id }
) { entry ->
OutlinedCard( OutlinedCard(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(top = 12.dp) .padding(top = 12.dp)
) { ) {
Text( Text(
text = "4am 141", text = entry.time,
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Light,
modifier = Modifier modifier = Modifier
@ -183,7 +181,7 @@ fun MainScreen( viewModel: MainViewModel, dataStore: UserData, navController: Na
.padding(top = 12.dp) .padding(top = 12.dp)
) )
Text( Text(
text = "Dildos factory", text = entry.place.name,
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
modifier = Modifier modifier = Modifier
@ -194,7 +192,7 @@ fun MainScreen( viewModel: MainViewModel, dataStore: UserData, navController: Na
} }
} }
Button( Button(
onClick = {navController.navigate(QR) }, onClick = { navController.navigate(QR) },
shape = CircleShape, shape = CircleShape,
modifier = Modifier modifier = Modifier
.align(Alignment.BottomEnd) .align(Alignment.BottomEnd)
@ -213,7 +211,7 @@ fun MainScreen( viewModel: MainViewModel, dataStore: UserData, navController: Na
} }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
viewModel.Fetch(token) viewModel.Fetch(login, password)
} }
} }
} }

View File

@ -1,14 +1,13 @@
package com.example.nto_minipigs.ui.screens.Main package com.example.nto_minipigs.ui.screens.Main
import android.util.Log import RetrofitClient
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.nto_minipigs.Retrofit.Models.Auth
import com.example.nto_minipigs.Retrofit.Models.User import com.example.nto_minipigs.Retrofit.Models.User
import com.example.nto_minipigs.UserData
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.Credentials
class MainViewModel: ViewModel() { class MainViewModel: ViewModel() {
private val serviceApi = RetrofitClient.apiService private val serviceApi = RetrofitClient.apiService
@ -16,13 +15,14 @@ class MainViewModel: ViewModel() {
private val _data = MutableLiveData<NetworkResponse<User>>() private val _data = MutableLiveData<NetworkResponse<User>>()
val data : LiveData<NetworkResponse<User>> = _data val data : LiveData<NetworkResponse<User>> = _data
fun Fetch(token: String?) { fun Fetch(login: String?, password: String?) {
_data.value = NetworkResponse.Loading _data.value = NetworkResponse.Loading
var basic = Credentials.basic(login.toString(), password.toString())
viewModelScope.launch { viewModelScope.launch {
if(token != null) { if(basic != "") {
try { try {
val response = serviceApi.info(token) val response = serviceApi.info(basic)
if(response.isSuccessful) { if(response.isSuccessful) {
response.body()?.let { response.body()?.let {
_data.value = NetworkResponse.Success(it) _data.value = NetworkResponse.Success(it)

View File

@ -14,15 +14,20 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.datastore.core.DataStore
import androidx.navigation.NavController import androidx.navigation.NavController
import com.example.nto_minipigs.QRResult import com.example.nto_minipigs.QRResult
import com.example.nto_minipigs.UserData
@Composable @Composable
fun QRScreen(navController: NavController, viewModel: QRViewModel) { fun QRScreen(navController: NavController, viewModel: QRViewModel, dataStore: UserData) {
var scanFlag by remember { var scanFlag by remember {
mutableStateOf(false) mutableStateOf(false)
} }
val login = dataStore.getLogin()
val password = dataStore.getPassword()
AndroidView( AndroidView(
factory = { context -> factory = { context ->
CompoundBarcodeView(context).apply { CompoundBarcodeView(context).apply {
@ -40,7 +45,8 @@ fun QRScreen(navController: NavController, viewModel: QRViewModel) {
Log.d("penis", barCodeOrQr) Log.d("penis", barCodeOrQr)
scanFlag = true scanFlag = true
this.pause() this.pause()
viewModel.Fetch(barCodeOrQr)
viewModel.Fetch(barCodeOrQr.toLong(), login, password)
navController.navigate(QRResult) navController.navigate(QRResult)
} }
//If you don't put this scanFlag = false, it will never work again. //If you don't put this scanFlag = false, it will never work again.

View File

@ -4,11 +4,11 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.nto_minipigs.Retrofit.Models.Data import com.example.nto_minipigs.Retrofit.Models.Auth
import com.example.nto_minipigs.Retrofit.Models.Door import com.example.nto_minipigs.Retrofit.Models.Door
import com.example.nto_minipigs.Retrofit.Models.DoorResponse import com.example.nto_minipigs.Retrofit.Models.DoorResponse
import com.example.nto_minipigs.Retrofit.Models.User
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.Credentials
class QRViewModel: ViewModel() { class QRViewModel: ViewModel() {
private val serviceApi = RetrofitClient.apiService private val serviceApi = RetrofitClient.apiService
@ -16,14 +16,14 @@ class QRViewModel: ViewModel() {
private val _data = MutableLiveData<NetworkResponse<DoorResponse>>() private val _data = MutableLiveData<NetworkResponse<DoorResponse>>()
val data : LiveData<NetworkResponse<DoorResponse>> = _data val data : LiveData<NetworkResponse<DoorResponse>> = _data
fun Fetch(id: String) { fun Fetch(id: Long, login:String, password:String) {
_data.value = NetworkResponse.Loading _data.value = NetworkResponse.Loading
viewModelScope.launch { viewModelScope.launch {
if(id != null) { if(id != null) {
try { try {
val request = Door(id) var basic = Credentials.basic(login.toString(), password.toString())
val response = serviceApi.open(request) val response = serviceApi.open(basic, id)
if(response.isSuccessful) { if(response.isSuccessful) {
response.body()?.let { response.body()?.let {
_data.value = NetworkResponse.Success(it) _data.value = NetworkResponse.Success(it)