base functionality implemented for test api

This commit is contained in:
pedro 2025-02-20 14:51:41 +03:00
parent 39a60043d2
commit 02385d86d5
11 changed files with 213 additions and 10 deletions

View File

@ -70,4 +70,10 @@ dependencies {
implementation("androidx.datastore:datastore:1.1.2")
implementation("androidx.compose.runtime:runtime-livedata:1.7.8")
implementation("io.coil-kt:coil-compose:2.0.0-rc01")
implementation("com.google.accompanist:accompanist-permissions:0.34.0")
implementation("androidx.camera:camera-camera2:1.4.1")
implementation("androidx.camera:camera-lifecycle:1.4.1")
implementation("androidx.camera:camera-view:1.4.1")
implementation("com.journeyapps:zxing-android-embedded:4.3.0")
implementation("com.google.zxing:core:3.4.0")
}

View File

@ -3,7 +3,11 @@
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.CAMERA"/>
<application
android:hardwareAccelerated="true"
android:allowBackup="true"
android:usesCleartextTraffic="true"
android:dataExtractionRules="@xml/data_extraction_rules"
@ -15,10 +19,13 @@
android:theme="@style/Theme.Nto_minipigs"
tools:targetApi="31">
<activity
android:screenOrientation="portrait"
tools:replace="screenOrientation"
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Nto_minipigs">
android:theme="@style/Theme.Nto_minipigs"
tools:ignore="DiscouragedApi">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@ -3,6 +3,7 @@ package com.example.nto_minipigs
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
@ -11,7 +12,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
@ -33,6 +33,9 @@ import kotlinx.coroutines.runBlocking
import kotlinx.serialization.Serializable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
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.QRViewModel
class MainActivity : ComponentActivity() {
@ -49,6 +52,7 @@ class MainActivity : ComponentActivity() {
val navController = rememberNavController()
val loginViewModel = ViewModelProvider(this)[LoginViewModel::class.java]
val mainViewModel = ViewModelProvider(this)[MainViewModel::class.java]
val qrViewModel = ViewModelProvider(this)[QRViewModel::class.java]
val token = dataStore.getToken()
@ -57,10 +61,11 @@ class MainActivity : ComponentActivity() {
NavHost(
navController = navController,
startDestination = if(token == "") Login else Main
// startDestination = Login
) {
composable<Login> { LoginScreen( onNavigateToMain = { navController.popBackStack(); navController.navigate(route = Main) }, viewModel = loginViewModel, dataStore = dataStore ) }
composable<Main> { MainScreen( viewModel = mainViewModel, dataStore = dataStore, navController = navController ) }
composable<QR> { QRScreen( navController = navController, viewModel = qrViewModel) }
composable<QRResult> { QRResultScreen( navController = navController, viewModel = qrViewModel ) }
}
}
}
@ -91,3 +96,9 @@ object Login
@Serializable
object Main
@Serializable
object QR
@Serializable
object QRResult

View File

@ -2,6 +2,8 @@ package com.example.nto_minipigs.Retrofit
import com.example.nto_minipigs.Retrofit.Models.Auth
import com.example.nto_minipigs.Retrofit.Models.Data
import com.example.nto_minipigs.Retrofit.Models.Door
import com.example.nto_minipigs.Retrofit.Models.DoorResponse
import com.example.nto_minipigs.Retrofit.Models.User
import okhttp3.ResponseBody
import retrofit2.Response
@ -19,8 +21,8 @@ public interface ApiService {
@GET("/api/info")
suspend fun info(@Header("Authorization") token: String): Response<User>
@PATCH("/api/{LOGIN}/open")
suspend fun open(@Body data: Data, @Path("LOGIN") login: String): ResponseBody
@PATCH("/api/open")
suspend fun open(@Body data: Door): Response<DoorResponse>
@POST("/api/login")
suspend fun login(@Body data: Auth): Response<Data>

View File

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

View File

@ -0,0 +1,5 @@
package com.example.nto_minipigs.Retrofit.Models
data class DoorResponse(
val name: String
)

View File

@ -58,6 +58,7 @@ import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import coil.compose.rememberAsyncImagePainter
import com.example.nto_minipigs.Login
import com.example.nto_minipigs.QR
import com.example.nto_minipigs.UserData
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
@ -193,7 +194,7 @@ fun MainScreen( viewModel: MainViewModel, dataStore: UserData, navController: Na
}
}
Button(
onClick = { },
onClick = {navController.navigate(QR) },
shape = CircleShape,
modifier = Modifier
.align(Alignment.BottomEnd)

View File

@ -36,10 +36,6 @@ class MainViewModel: ViewModel() {
}
}
}
fun Logout() {
}
}
sealed class NetworkResponse<out T> {

View File

@ -0,0 +1,70 @@
package com.example.nto_minipigs.ui.screens.QR
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Cancel
import androidx.compose.material.icons.outlined.Check
import androidx.compose.material.icons.outlined.CheckCircle
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.example.nto_minipigs.QRResult
import com.example.nto_minipigs.ui.screens.Main.NetworkResponse
import com.example.nto_minipigs.ui.screens.QR.QRViewModel
@Composable
fun QRResultScreen(navController: NavController, viewModel: QRViewModel) {
val data = viewModel.data.observeAsState()
Surface {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
when(val result = data.value){
is com.example.nto_minipigs.ui.screens.QR.NetworkResponse.Error -> {
Icon(
Icons.Outlined.Cancel,
contentDescription = null,
tint = MaterialTheme.colorScheme.error,
modifier = Modifier
.size(100.dp)
)
}
com.example.nto_minipigs.ui.screens.QR.NetworkResponse.Loading -> {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
CircularProgressIndicator()
}
}
is com.example.nto_minipigs.ui.screens.QR.NetworkResponse.Success -> {
Icon(
Icons.Outlined.CheckCircle,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier
.size(100.dp)
)
}
null -> {}
}
}
}
}

View File

@ -0,0 +1,54 @@
package com.example.nto_minipigs.ui.screens.QR
import android.app.Activity
import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import com.journeyapps.barcodescanner.CaptureManager
import com.journeyapps.barcodescanner.CompoundBarcodeView
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView
import androidx.navigation.NavController
import com.example.nto_minipigs.QRResult
@Composable
fun QRScreen(navController: NavController, viewModel: QRViewModel) {
var scanFlag by remember {
mutableStateOf(false)
}
AndroidView(
factory = { context ->
CompoundBarcodeView(context).apply {
val capture = CaptureManager(context as Activity, this)
capture.initializeFromIntent(context.intent, null)
this.setStatusText("")
capture.decode()
this.decodeContinuous { result ->
if (scanFlag) {
return@decodeContinuous
}
println("scanFlag true")
scanFlag = true
result.text?.let { barCodeOrQr ->
Log.d("penis", barCodeOrQr)
scanFlag = true
this.pause()
viewModel.Fetch(barCodeOrQr)
navController.navigate(QRResult)
}
//If you don't put this scanFlag = false, it will never work again.
//you can put a delay over 2 seconds and then scanFlag = false to prevent multiple scanning
}
this.resume()
}
},
modifier = Modifier
)
}

View File

@ -0,0 +1,46 @@
package com.example.nto_minipigs.ui.screens.QR
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.nto_minipigs.Retrofit.Models.Data
import com.example.nto_minipigs.Retrofit.Models.Door
import com.example.nto_minipigs.Retrofit.Models.DoorResponse
import com.example.nto_minipigs.Retrofit.Models.User
import kotlinx.coroutines.launch
class QRViewModel: ViewModel() {
private val serviceApi = RetrofitClient.apiService
private val _data = MutableLiveData<NetworkResponse<DoorResponse>>()
val data : LiveData<NetworkResponse<DoorResponse>> = _data
fun Fetch(id: String) {
_data.value = NetworkResponse.Loading
viewModelScope.launch {
if(id != null) {
try {
val request = Door(id)
val response = serviceApi.open(request)
if(response.isSuccessful) {
response.body()?.let {
_data.value = NetworkResponse.Success(it)
}
} else {
_data.value = NetworkResponse.Error(response.message())
}
} catch(e: Exception) {
_data.value = NetworkResponse.Error(e.toString())
}
}
}
}
}
sealed class NetworkResponse<out T> {
data class Success<out T>(val data: T) : NetworkResponse<T>()
data class Error(val message: String) : NetworkResponse<Nothing>()
object Loading : NetworkResponse<Nothing>()
}