AttendanceList fonctionnelle avec lecture des cartes NFC
This commit is contained in:
parent
0775eb13da
commit
d7bade2287
10 changed files with 135 additions and 62 deletions
|
@ -18,13 +18,19 @@
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
<activity
|
||||||
android:name=".PaltoActivity"
|
android:name=".PaltoActivity"
|
||||||
android:exported="true" >
|
android:exported="true"
|
||||||
|
android:launchMode="singleTop">
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
|
|
@ -5,42 +5,46 @@ import android.nfc.Tag
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
|
||||||
|
|
||||||
class PaltoActivity : AppCompatActivity() {
|
class PaltoActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private var nfcAdapter: NfcAdapter? = null
|
private var nfcAdapter: NfcAdapter? = null
|
||||||
|
|
||||||
|
private val paltoViewModel: PaltoViewModel by viewModels()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_palto)
|
|
||||||
|
|
||||||
// get the NFC Adapter
|
// get the NFC Adapter
|
||||||
this.nfcAdapter = NfcAdapter.getDefaultAdapter(this)
|
nfcAdapter = NfcAdapter.getDefaultAdapter(this)
|
||||||
|
|
||||||
// check if NFC is supported
|
// check if NFC is supported
|
||||||
if (this.nfcAdapter == null) {
|
if (nfcAdapter == null) {
|
||||||
Log.e("NFC", "NFC is not supported")
|
Log.e("NFC", "NFC is not supported")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if NFC is disabled
|
// check if NFC is disabled
|
||||||
if (!(this.nfcAdapter!!.isEnabled)) {
|
if (nfcAdapter?.isEnabled == false) {
|
||||||
Log.w("NFC", "NFC is not enabled")
|
Log.w("NFC", "NFC is not enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST
|
setContentView(R.layout.activity_palto)
|
||||||
/*
|
/*
|
||||||
val url = URL("https://www.faraphel.fr/palto/api/auth/token/")
|
val url = URL("https://www.faraphel.fr/palto/api/auth/token/")
|
||||||
val connection = url.openConnection()
|
val connection = url.openConnection()
|
||||||
val auth_data = Json.decodeFromString(connection.content)*/
|
val auth_data = Json.decodeFromString(connection.content)
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
nfcAdapter!!.enableReaderMode(
|
nfcAdapter?.enableReaderMode(
|
||||||
this,
|
this,
|
||||||
this::processTag,
|
paltoViewModel.tagLiveData::postValue,
|
||||||
NfcAdapter.FLAG_READER_NFC_A or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK,
|
NfcAdapter.FLAG_READER_NFC_A or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK,
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
@ -50,11 +54,11 @@ class PaltoActivity : AppCompatActivity() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
|
||||||
// disable the NFC discovery
|
// disable the NFC discovery
|
||||||
this.nfcAdapter!!.disableReaderMode(this)
|
nfcAdapter?.disableReaderMode(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
fun processTag(tag: Tag) {
|
fun processTag(tag: Tag) {
|
||||||
Log.d("NFC", "Tag ID : ${tag.id.toHexString()}")
|
Log.d("NFC", "Tag ID : " + tag.id.toHexString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
9
app/src/main/java/com/example/palto/PaltoViewModel.kt
Normal file
9
app/src/main/java/com/example/palto/PaltoViewModel.kt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package com.example.palto
|
||||||
|
|
||||||
|
import android.nfc.Tag
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
class PaltoViewModel: ViewModel() {
|
||||||
|
val tagLiveData = MutableLiveData<Tag>()
|
||||||
|
}
|
|
@ -2,5 +2,22 @@ package com.example.palto.model
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
data class Card(
|
data class Card(
|
||||||
val id: String
|
val id: String,
|
||||||
) : Serializable
|
val uid: ByteArray,
|
||||||
|
val department: String,
|
||||||
|
val owner: String
|
||||||
|
) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as Card
|
||||||
|
|
||||||
|
return uid.contentEquals(other.uid)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return uid.contentHashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,14 +1,13 @@
|
||||||
package com.example.palto.ui.attendanceList
|
package com.example.palto.ui.attendanceList
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import com.example.palto.model.Card
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
||||||
import com.example.palto.databinding.FragmentAttendanceItemBinding
|
import com.example.palto.databinding.FragmentAttendanceItemBinding
|
||||||
|
import com.example.palto.model.Card
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -30,9 +29,10 @@ class AttendanceListAdapter :
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val item = getItem(position)
|
val item = getItem(position)
|
||||||
holder.cardId.text = item.id
|
holder.cardId.text = item.uid.toHexString()
|
||||||
//holder.contentView.text = item.content
|
//holder.contentView.text = item.content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
package com.example.palto.ui.attendanceList
|
package com.example.palto.ui.attendanceList
|
||||||
|
|
||||||
|
import android.nfc.NfcAdapter
|
||||||
|
import android.nfc.Tag
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.fragment.app.Fragment
|
import android.util.Log
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
import androidx.navigation.navGraphViewModels
|
import androidx.navigation.navGraphViewModels
|
||||||
|
import com.example.palto.PaltoViewModel
|
||||||
import com.example.palto.R
|
import com.example.palto.R
|
||||||
import com.example.palto.databinding.FragmentAttendanceListBinding
|
import com.example.palto.databinding.FragmentAttendanceListBinding
|
||||||
|
|
||||||
|
@ -17,22 +21,49 @@ import com.example.palto.databinding.FragmentAttendanceListBinding
|
||||||
class AttendanceListFragment : Fragment() {
|
class AttendanceListFragment : Fragment() {
|
||||||
|
|
||||||
private val attendanceListViewModel: AttendanceListViewModel by
|
private val attendanceListViewModel: AttendanceListViewModel by
|
||||||
navGraphViewModels(R.id.nav_graph)
|
navGraphViewModels(R.id.nav_graph) { AttendanceListViewModel.Factory }
|
||||||
|
|
||||||
|
private val paltoViewModel: PaltoViewModel by
|
||||||
|
activityViewModels()
|
||||||
|
|
||||||
|
private var _binding: FragmentAttendanceListBinding? = null
|
||||||
|
// This property is only valid between onCreateView and onDestroyView
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only inflate the view.
|
||||||
|
*/
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
val binding = FragmentAttendanceListBinding.inflate(inflater, container, false)
|
|
||||||
|
|
||||||
val adapter = AttendanceListAdapter()
|
|
||||||
binding.list.adapter = adapter
|
|
||||||
|
|
||||||
attendanceListViewModel.cardsLiveData.observe(viewLifecycleOwner) {
|
|
||||||
it -> adapter.submitList(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
_binding = FragmentAttendanceListBinding.inflate(inflater, container, false)
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logic on the returned view of onCreateView.
|
||||||
|
*/
|
||||||
|
override fun onViewCreated(
|
||||||
|
view: View,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
// Set the adapter of the view for managing automatically the list of items on the screen.
|
||||||
|
val adapter = AttendanceListAdapter()
|
||||||
|
binding.list.adapter = adapter
|
||||||
|
attendanceListViewModel.cardsLiveData.observe(viewLifecycleOwner) {
|
||||||
|
Log.d("NFC", "A card has been had to the list")
|
||||||
|
adapter.submitList(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the listener for a new NFC tag.
|
||||||
|
paltoViewModel.tagLiveData.observe(viewLifecycleOwner) {
|
||||||
|
Log.d("NFC", "tag observer has been notified")
|
||||||
|
attendanceListViewModel.insertCard(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package com.example.palto.ui.attendanceList
|
package com.example.palto.ui.attendanceList
|
||||||
|
|
||||||
|
import android.nfc.Tag
|
||||||
|
import android.util.Log
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
@ -7,32 +9,41 @@ import androidx.lifecycle.ViewModelProvider
|
||||||
import com.example.palto.data.network.ServerDataSource
|
import com.example.palto.data.network.ServerDataSource
|
||||||
import com.example.palto.data.repository.AttendanceRepository
|
import com.example.palto.data.repository.AttendanceRepository
|
||||||
import com.example.palto.model.Card
|
import com.example.palto.model.Card
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewModel of a session which has a list of attendances.
|
||||||
|
*/
|
||||||
class AttendanceListViewModel(
|
class AttendanceListViewModel(
|
||||||
private val attendanceRepository: AttendanceRepository
|
private val attendanceRepository: AttendanceRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val cardsList: MutableList<Card> = mutableListOf()
|
val cardsLiveData: MutableLiveData<List<Card>> = MutableLiveData(emptyList())
|
||||||
val cardsLiveData: LiveData<List<Card>> = MutableLiveData(cardsList)
|
|
||||||
|
|
||||||
fun insertCard(cardId: String) {
|
fun insertCard(tag: Tag) {
|
||||||
val card = Card(cardId)
|
val card = Card(
|
||||||
cardsList.add(card)
|
"0",
|
||||||
}
|
tag.id,
|
||||||
}
|
"tmp",
|
||||||
|
"tmp"
|
||||||
class AttendanceListViewModelFactory : ViewModelProvider.Factory {
|
|
||||||
|
|
||||||
//@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
|
||||||
if (modelClass.isAssignableFrom(AttendanceListViewModel::class.java)) {
|
|
||||||
return AttendanceListViewModel(
|
|
||||||
attendanceRepository = AttendanceRepository(
|
|
||||||
dataSource = ServerDataSource()
|
|
||||||
)
|
)
|
||||||
|
cardsLiveData.value = (cardsLiveData.value ?: emptyList()) + card
|
||||||
|
Log.d("NFC", "view model: A card has been had to the list")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewModel Factory.
|
||||||
|
*/
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(
|
||||||
|
modelClass: Class<T>
|
||||||
|
): T {
|
||||||
|
return AttendanceListViewModel(
|
||||||
|
AttendanceRepository(ServerDataSource())
|
||||||
) as T
|
) as T
|
||||||
}
|
}
|
||||||
throw IllegalArgumentException("Unknown ViewModel class")
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,8 +24,7 @@ class LoginFragment : Fragment() {
|
||||||
|
|
||||||
private var _binding: FragmentLoginBinding? = null
|
private var _binding: FragmentLoginBinding? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and
|
// This property is only valid between onCreateView and onDestroyView.
|
||||||
// onDestroyView.
|
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
|
@ -73,7 +72,7 @@ class LoginFragment : Fragment() {
|
||||||
showLoginFailed(it)
|
showLoginFailed(it)
|
||||||
}
|
}
|
||||||
loginResult.success?.let {
|
loginResult.success?.let {
|
||||||
findNavController().navigate(R.id.action_loginFragment_to_attendanceFragment)
|
//findNavController().navigate(R.id.action_loginFragment_to_attendanceFragment)
|
||||||
//updateUiWithUser(it)
|
//updateUiWithUser(it)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,23 +3,19 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/nav_graph"
|
android:id="@+id/nav_graph"
|
||||||
app:startDestination="@id/loginFragment">
|
app:startDestination="@id/attendanceListFragment">
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/loginFragment"
|
android:id="@+id/loginFragment"
|
||||||
android:name="com.example.palto.ui.login.LoginFragment"
|
android:name="com.example.palto.ui.login.LoginFragment"
|
||||||
android:label="fragment._login"
|
android:label="fragment._login"
|
||||||
tools:layout="@layout/fragment_login" >
|
tools:layout="@layout/fragment_login" />
|
||||||
<action
|
|
||||||
android:id="@+id/action_loginFragment_to_attendanceFragment"
|
|
||||||
app:destination="@id/attendanceFragment" />
|
|
||||||
</fragment>
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/sessionListFragment"
|
android:id="@+id/sessionListFragment"
|
||||||
android:name="com.example.palto.ui.sessionList.SessionListFragment"
|
android:name="com.example.palto.ui.sessionList.SessionListFragment"
|
||||||
android:label="fragment_session_list"
|
android:label="fragment_session_list"
|
||||||
tools:layout="@layout/fragment_session_list" />
|
tools:layout="@layout/fragment_session_list" />
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/attendanceFragment"
|
android:id="@+id/attendanceListFragment"
|
||||||
android:name="com.example.palto.ui.attendanceList.AttendanceListFragment"
|
android:name="com.example.palto.ui.attendanceList.AttendanceListFragment"
|
||||||
android:label="fragment_attendance_list"
|
android:label="fragment_attendance_list"
|
||||||
tools:layout="@layout/fragment_attendance_list" />
|
tools:layout="@layout/fragment_attendance_list" />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application") version "8.1.4" apply false
|
id("com.android.application") version "8.2.0" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "1.9.0" apply false
|
id("org.jetbrains.kotlin.android") version "1.9.0" apply false
|
||||||
}
|
}
|
Loading…
Reference in a new issue