empty app

This commit is contained in:
Kirill 2025-02-20 15:06:29 +03:00
parent 65440d8feb
commit 155b1a0d7c
30 changed files with 408 additions and 106 deletions

View File

@ -40,6 +40,8 @@ android {
}
dependencies {
implementation(libs.lifecycle.view.model)
implementation(libs.fragment.navigation)
implementation(libs.ktor.client.core)
implementation(libs.zbar.code)
implementation(libs.ktor.serialization.json)

View File

@ -9,6 +9,8 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.navigation.fragment.NavHostFragment
import com.example.nto_2024_client.login.LoginFragment
import com.example.nto_2024_client.qr.QrFragment
class MainActivity : AppCompatActivity() {
@ -21,6 +23,8 @@ class MainActivity : AppCompatActivity() {
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
// val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment
// val navController = navHostFragment.navController
checkPermissions()
}
@ -29,7 +33,7 @@ class MainActivity : AppCompatActivity() {
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.CAMERA),12)
}
else{
supportFragmentManager.beginTransaction().replace(R.id.fragment_login,QrFragment()).commit()
supportFragmentManager.beginTransaction().replace(R.id.fragment_login,LoginFragment()).commit()
}
}
@ -43,7 +47,7 @@ class MainActivity : AppCompatActivity() {
if(requestCode == 12){
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
supportFragmentManager.beginTransaction().replace(R.id.fragment_login,QrFragment()).commit()
supportFragmentManager.beginTransaction().replace(R.id.fragment_login,LoginFragment()).commit()
Log.d("MyResp","GOOOL")
}

View File

@ -0,0 +1,26 @@
package com.example.nto_2024_client.list
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
import com.example.nto_2024_client.R
import com.example.nto_2024_client.databinding.FragmentListBinding
import com.example.nto_2024_client.list.adapter.ListAdapter
class ListFragment:Fragment(R.layout.fragment_list) {
private lateinit var binding:FragmentListBinding
private val listViewModel:ListViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val adapter = ListAdapter()
binding.rvView.adapter=adapter
binding = FragmentListBinding.bind(view)
listViewModel.entry.observe(viewLifecycleOwner, Observer { it->
for (listEnterEntity in it){
adapter.addEnter(listEnterEntity)
}
})
}
}

View File

@ -0,0 +1,33 @@
package com.example.nto_2024_client.list
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.nto_2024_client.list.models.ListEnterEntity
import com.example.nto_2024_client.list.network.ListEnterRepoImpl
import com.example.nto_2024_client.list.network.ListNetworkEnter
import kotlinx.coroutines.launch
class ListViewModel:ViewModel() {
private val listNetworkEnter:ListNetworkEnter = ListNetworkEnter()
private val listEnterRepoImpl:ListEnterRepoImpl = ListEnterRepoImpl(listNetworkEnter)
val entry:MutableLiveData<List<ListEnterEntity>> by lazy {
MutableLiveData<List<ListEnterEntity>>()
}
fun getEntry(username:String,password:String){
viewModelScope.launch {
val result = listEnterRepoImpl.lastEntry(username,password)
result.onSuccess { listEntry->
entry.value = listEntry
Log.d("MyListEntry",entry.value.toString())
}
result.onFailure {
Log.d("MyListEntry","Mda")
}
}
}
}

View File

@ -0,0 +1,44 @@
package com.example.nto_2024_client.list.adapter
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.nto_2024_client.R
import com.example.nto_2024_client.databinding.EntryItemBinding
import com.example.nto_2024_client.list.models.ListEnterEntity
class ListAdapter:RecyclerView.Adapter<com.example.nto_2024_client.list.adapter.ListAdapter.EntryHolder>() {
val entryItem=ArrayList<ListEnterEntity>()
inner class EntryHolder(item: View):RecyclerView.ViewHolder(item){
val binding=EntryItemBinding.bind(item)
fun bind(item: ListEnterEntity){
binding.textView.text = item.lastEntry
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EntryHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.entry_item,parent,false)
return EntryHolder(view)
}
override fun getItemCount(): Int {
return entryItem.size
}
override fun onBindViewHolder(holder: EntryHolder, position: Int) {
holder.bind(entryItem[position])
}
@SuppressLint("NotifyDataSetChanged")
fun addEnter(lastEnterEntity: ListEnterEntity){
entryItem.add(lastEnterEntity)
notifyDataSetChanged()
}
}

View File

@ -0,0 +1,10 @@
package com.example.nto_2024_client.list.models
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
class ListEnterDTO (
@SerialName("lastEntry")
val lastEntry:String
)

View File

@ -0,0 +1,5 @@
package com.example.nto_2024_client.list.models
class ListEnterEntity (
val lastEntry:String
)

View File

@ -0,0 +1,7 @@
package com.example.nto_2024_client.list.network
import com.example.nto_2024_client.list.models.ListEnterEntity
interface ListEnterRepo {
suspend fun lastEntry(login:String,password:String):Result<List<ListEnterEntity>>
}

View File

@ -0,0 +1,16 @@
package com.example.nto_2024_client.list.network
import com.example.nto_2024_client.list.models.ListEnterEntity
class ListEnterRepoImpl (val listNetworkEnter: ListNetworkEnter):ListEnterRepo{
override suspend fun lastEntry(login: String, password: String): Result<List<ListEnterEntity>> {
return listNetworkEnter.findLastEntry(login,password).map { listDTO->
listDTO.mapNotNull { dto->
ListEnterEntity(
lastEntry = dto.lastEntry
)
}
}
}
}

View File

@ -0,0 +1,36 @@
package com.example.nto_2024_client.list.network
import com.example.nto_2024_client.list.models.ListEnterDTO
import com.example.nto_2024_client.login.models.UserDTO
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.basicAuth
import io.ktor.client.request.get
import io.ktor.client.request.setBody
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import kotlin.math.log
class ListNetworkEnter {
val client = HttpClient(CIO){
install(ContentNegotiation){
json(Json {
isLenient = true
ignoreUnknownKeys = true
})
}
}
suspend fun findLastEntry(login:String,password:String):Result<List<ListEnterDTO>> = withContext(Dispatchers.IO){
runCatching {
val result = client.get("http://10.6.66.81:8080/api/enter/${login}")
result.body()
}
}
}

View File

@ -1,6 +1,41 @@
package com.example.nto_2024_client.login
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
import com.example.nto_2024_client.R
import com.example.nto_2024_client.databinding.FragmentLoginBinding
import com.example.nto_2024_client.list.ListViewModel
import com.example.nto_2024_client.login.network.LoginNetwork
import com.example.nto_2024_client.login.network.LoginRepoImpl
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class LoginFragment:Fragment(R.layout.fragment_login) {
private lateinit var binding:FragmentLoginBinding
private val loginNetwork: LoginNetwork = LoginNetwork()
private val loginRepoImpl: LoginRepoImpl = LoginRepoImpl(loginNetwork)
private val loginViewModel:LoginViewModel by activityViewModels()
private val listViewModel:ListViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentLoginBinding.bind(view)
binding.button2.setOnClickListener{
CoroutineScope(Dispatchers.Main).launch{
val result = loginNetwork.login("gnazarov","admin")
result.onSuccess {
Log.d("MyLog","Good")
}
result.onFailure {
Log.d("MyLog","Fail")
}
}
}
}
class LoginFragment:Fragment() {
}

View File

@ -1,6 +1,33 @@
package com.example.nto_2024_client.login
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.nto_2024_client.login.network.LoginNetwork
import com.example.nto_2024_client.login.network.LoginRepoImpl
import kotlinx.coroutines.launch
class LoginViewModel:ViewModel() {
private val loginNetwork:LoginNetwork = LoginNetwork()
private val loginRepoImpl:LoginRepoImpl = LoginRepoImpl(loginNetwork)
val message:MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
fun login(login:String,password:String){
viewModelScope.launch {
val result = loginNetwork.login("gnazarov","admin")
result.onSuccess {
message.value = "cool"
Log.d("MyLogin","True")
}
result.onFailure {
Log.d("MyLogin","Fail")
}
}
}
}

View File

@ -1,18 +1,18 @@
package com.example.nto_2024_client.register.models
package com.example.nto_2024_client.login.models
import android.icu.text.Transliterator.Position
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
@Serializable
data class RegisterDTO (
data class UserDTO(
@SerialName("name")
val name:String,
@SerialName("username")
val username:String,
@SerialName("password")
val password:String,
@SerialName("position")
val position: String
)
@SerialName("photo")
val photo:String,
@SerialName("jobPos")
val jobPos:String
)

View File

@ -0,0 +1,9 @@
package com.example.nto_2024_client.login.models
class UserEntity(
val name:String,
val username:String,
val password:String,
val photo:String,
val jobPos:String
)

View File

@ -0,0 +1,52 @@
package com.example.nto_2024_client.login.network
import android.net.Credentials
import android.util.Log
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.auth.Auth
import io.ktor.client.plugins.auth.providers.BasicAuthCredentials
import io.ktor.client.plugins.auth.providers.basic
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.basicAuth
import io.ktor.client.request.get
import io.ktor.client.request.headers
import io.ktor.client.utils.EmptyContent.headers
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpStatusCode
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
class LoginNetwork {
val client = HttpClient(CIO) {
install(ContentNegotiation) {
json(Json {
isLenient = true
ignoreUnknownKeys = true
})
}
install(Auth) {
basic {
sendWithoutRequest { true }
credentials {
BasicAuthCredentials(username = "gnazarov", password = "admin")
}
}
}
}
suspend fun login(login: String, password: String): Result<Unit> = withContext(Dispatchers.IO) {
runCatching {
val result = client.get("http://10.6.66.81:8080/api/employee/login")
if (result.status!= HttpStatusCode.OK){
error("jopa")
}
Unit
}
}
}

View File

@ -0,0 +1,4 @@
package com.example.nto_2024_client.login.network
interface LoginRepo {
suspend fun login(login:String,password:String):Result<Unit>
}

View File

@ -0,0 +1,7 @@
package com.example.nto_2024_client.login.network
class LoginRepoImpl(val loginNetwork: LoginNetwork):LoginRepo {
override suspend fun login(login: String, password: String): Result<Unit> {
return loginNetwork.login(login,password)
}
}

View File

@ -1,16 +1,18 @@
package com.example.nto_2024_client.login
package com.example.nto_2024_client.qr.network
import com.example.nto_2024_client.login.models.UserDTO
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.basicAuth
import io.ktor.client.request.get
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
class LoginNetwork {
class QrNetwork {
val client = HttpClient(CIO){
install(ContentNegotiation){
json(Json {
@ -21,9 +23,12 @@ class LoginNetwork {
}
}
suspend fun login(login:String,password:String):Result<Unit> = withContext(Dispatchers.IO){
suspend fun findQrCode(qrCode:String):Result<UserDTO> = withContext(Dispatchers.IO){
runCatching {
val result = client.get("")
val result = client.get("http://10.6.66.81:8080/api/registration")
result.body()
}
}
}

View File

@ -1,7 +0,0 @@
package com.example.nto_2024_client.register
import androidx.fragment.app.Fragment
class RegisterFragment:Fragment() {
}

View File

@ -1,43 +0,0 @@
package com.example.nto_2024_client.register
import android.icu.text.Transliterator.Position
import com.example.nto_2024_client.register.models.RegisterDTO
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.basicAuth
import io.ktor.client.request.get
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
class RegisterNetwork {
val client = HttpClient(CIO){
install(ContentNegotiation){
json(Json {
isLenient = true
ignoreUnknownKeys = true
})
}
}
suspend fun register(name:String,password:String,login:String,position:String,):Result<Unit> = withContext(Dispatchers.IO){
runCatching {
val result = client.post("http://10.6.66.81:8080/api/registration"){
basicAuth(login,password)
setBody(RegisterDTO(
name = name,
password = password,
username = login,
position = position
))
}
}
}
}

View File

@ -1,8 +0,0 @@
package com.example.nto_2024_client.register
import androidx.lifecycle.ViewModel
class RegisterViewModel: ViewModel() {
}

View File

@ -1,12 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app = "http://schemas.android.com/apk/res-auto"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- <androidx.fragment.app.FragmentContainerView-->
<!-- android:id="@+id/fragmentContainerView"-->
<!-- android:name="androidx.navigation.fragment.NavHostFragment"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent"/>-->
<FrameLayout
android:id="@+id/fragment_login"
android:layout_width="0dp"

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -5,7 +5,7 @@
android:background="@color/background"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".ListActivity">
>
<androidx.appcompat.widget.Toolbar
@ -26,14 +26,23 @@
android:layout_height="75dp"
app:srcCompat="@drawable/history"
tools:ignore="RtlHardcoded" />
<ImageButton
android:background="@android:color/transparent"
android:id="@+id/profile"
android:layout_width="75dp"
android:layout_gravity="bottom|left"
android:layout_height="75dp"
android:layout_gravity="bottom|left"
android:background="@android:color/transparent"
app:srcCompat="@drawable/profile"
tools:ignore="RtlHardcoded" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvView"
android:layout_width="match_parent"
android:layout_height="561dp"
android:layout_gravity="center"
tools:listitem="@layout/entry_item"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -30,7 +30,7 @@
android:background="@drawable/shape_rectangle3"
android:gravity="center"
android:inputType="text"
android:text="Логин"
android:hint="Логин"
android:textColor="@color/dark_grey"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -44,8 +44,8 @@
android:layout_marginBottom="16dp"
android:background="@drawable/shape_rectangle3"
android:gravity="center"
android:inputType="text"
android:text="Пароль"
android:inputType="textPassword"
android:hint="Пароль"
android:textColor="@color/dark_grey"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@ -54,6 +54,7 @@
app:layout_constraintVertical_bias="0.076" />
<android.widget.Button
android:visibility="gone"
android:id="@+id/button"
android:layout_width="250dp"
android:layout_height="50dp"

View File

@ -31,7 +31,7 @@
android:background="@drawable/shape_rectangle3"
android:gravity="center"
android:inputType="text"
android:text="Имя"
android:hint="Имя"
android:textColor="@color/dark_grey"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -45,7 +45,7 @@
android:layout_marginTop="24dp"
android:background="@drawable/shape_rectangle3"
android:gravity="center"
android:inputType="text"
android:inputType="textPassword"
android:text="Фамилия"
android:textColor="@color/dark_grey"
app:layout_constraintEnd_toEndOf="parent"

View File

@ -1,12 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="800dp"
android:height="800dp"
android:viewportWidth="325"
android:viewportHeight="325">
<path
android:pathData="M233.73,325h5.46c1.71,0 3.34,-0.73 4.47,-2l36.1,-40.39c0.98,-1.1 1.53,-2.52 1.53,-4v-4.69h-47.56V325z"
android:fillColor="#000000"/>
<path
android:pathData="M275.29,0H49.71c-3.31,0 -6,2.69 -6,6v313c0,3.31 2.69,6 6,6h168.02v-59.08c0,-4.42 3.58,-8 8,-8h55.56V6C281.29,2.69 278.6,0 275.29,0zM130.92,261.37H76.78c-4.42,0 -8,-3.58 -8,-8c0,-4.42 3.58,-8 8,-8h54.14c4.42,0 8,3.58 8,8C138.92,257.79 135.34,261.37 130.92,261.37zM248.22,200.79H76.78c-4.42,0 -8,-3.58 -8,-8c0,-4.42 3.58,-8 8,-8h171.44c4.42,0 8,3.58 8,8C256.22,197.21 252.64,200.79 248.22,200.79zM248.22,140.21H76.78c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8h171.44c4.42,0 8,3.58 8,8S252.64,140.21 248.22,140.21zM248.22,79.63H76.78c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8h171.44c4.42,0 8,3.58 8,8S252.64,79.63 248.22,79.63z"
android:fillColor="#000000"/>
</vector>

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/topbar_menu"
android:icon="@drawable/ic_navigation"
app:showAsAction="ifRoom"
android:title="@string/Profile"/>
</menu>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_host"
app:startDestination="@id/loginFragment">
<fragment
android:id="@+id/loginFragment"
android:name="com.example.nto_2024_client.login.LoginFragment"
android:label="LoginFragment" >
<action
android:id="@+id/action_loginFragment_to_listFragment"
app:destination="@id/listFragment" />
</fragment>
<fragment
android:id="@+id/listFragment"
android:name="com.example.nto_2024_client.list.ListFragment"
android:label="ListFragment" />
</navigation>

View File

@ -1,5 +1,5 @@
[versions]
agp = "8.7.3"
agp = "8.8.0"
kotlin = "2.0.0-RC1"
coreKtx = "1.15.0"
junit = "4.13.2"
@ -9,7 +9,9 @@ appcompat = "1.6.1"
material = "1.10.0"
activity = "1.10.0"
constraintlayout = "2.1.4"
lifecycleView = "2.8.7"
ktor ="3.0.3"
navFrag = "2.8.7"
zbar = "1.9.7"
kotlinSerialization="1.8.0"
@ -23,6 +25,8 @@ material = { group = "com.google.android.material", name = "material", version.r
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
ktor-client-core = {module = "io.ktor:ktor-client-core",version.ref="ktor"}
ktor-client-auth = {group="io.ktor",name="ktor-client-auth",version.ref="ktor"}
lifecycle-view-model={group="androidx.lifecycle",name="lifecycle-viewmodel-ktx",version.ref="lifecycleView"}
fragment-navigation = {group="androidx.navigation",name="navigation-fragment-ktx",version.ref="navFrag"}
zbar-code = {group="me.dm7.barcodescanner",name="zbar",version.ref="zbar"}
ktor-client-cio = {module="io.ktor:ktor-client-cio",version.ref="ktor"}
ktor-client-content-negotiation={module="io.ktor:ktor-client-content-negotiation",version.ref="ktor"}