From bff62daaecb15d7de896139e0092c952d23d926c Mon Sep 17 00:00:00 2001 From: biloute02 Date: Fri, 5 Jan 2024 13:50:20 +0100 Subject: [PATCH 01/12] Changement des listes menu et session --- app/build.gradle.kts | 16 +++-- .../java/com/example/palto/PaltoActivity.kt | 15 ++-- .../data/repository/AttendanceRepository.kt | 4 +- .../data/repository/SessionRepository.kt | 4 +- .../palto/{model => domain}/Attendance.kt | 2 +- .../example/palto/{model => domain}/Card.kt | 3 +- .../palto/{model => domain}/Session.kt | 4 +- .../java/com/example/palto/ui/NfcViewModel.kt | 14 ++++ .../attendanceList/AttendanceListFragment.kt | 69 ------------------- .../com/example/palto/ui/menu/MenuAdapter.kt | 69 +++++++++++++++++++ .../com/example/palto/ui/menu/MenuFragment.kt | 45 ++++++++++++ .../example/palto/ui/menu/MenuViewModel.kt | 21 ++++++ .../SessionAdapter.kt} | 22 +++--- .../palto/ui/session/SessionFragment.kt | 56 +++++++++++++++ .../SessionViewModel.kt} | 18 ++--- .../ui/sessionList/SessionListAdapter.kt | 44 ------------ .../ui/sessionList/SessionListFragment.kt | 31 --------- .../ui/sessionList/SessionListViewModel.kt | 14 ---- ...ndance_item.xml => fragment_menu_item.xml} | 9 ++- ...ndance_list.xml => fragment_menu_list.xml} | 8 +-- .../main/res/layout/fragment_session_item.xml | 9 +-- .../main/res/layout/fragment_session_list.xml | 6 +- app/src/main/res/navigation/nav_graph.xml | 22 ++++-- 23 files changed, 279 insertions(+), 226 deletions(-) rename app/src/main/java/com/example/palto/{model => domain}/Attendance.kt (86%) rename app/src/main/java/com/example/palto/{model => domain}/Card.kt (87%) rename app/src/main/java/com/example/palto/{model => domain}/Session.kt (77%) create mode 100644 app/src/main/java/com/example/palto/ui/NfcViewModel.kt delete mode 100644 app/src/main/java/com/example/palto/ui/attendanceList/AttendanceListFragment.kt create mode 100644 app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt create mode 100644 app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt create mode 100644 app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt rename app/src/main/java/com/example/palto/ui/{attendanceList/AttendanceListAdapter.kt => session/SessionAdapter.kt} (72%) create mode 100644 app/src/main/java/com/example/palto/ui/session/SessionFragment.kt rename app/src/main/java/com/example/palto/ui/{attendanceList/AttendanceListViewModel.kt => session/SessionViewModel.kt} (67%) delete mode 100644 app/src/main/java/com/example/palto/ui/sessionList/SessionListAdapter.kt delete mode 100644 app/src/main/java/com/example/palto/ui/sessionList/SessionListFragment.kt delete mode 100644 app/src/main/java/com/example/palto/ui/sessionList/SessionListViewModel.kt rename app/src/main/res/layout/{fragment_attendance_item.xml => fragment_menu_item.xml} (61%) rename app/src/main/res/layout/{fragment_attendance_list.xml => fragment_menu_list.xml} (67%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 39d63cb..e50f1e9 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -29,7 +29,6 @@ android { kotlinOptions { jvmTarget = "1.8" } - buildToolsVersion = "33.0.1" buildFeatures { viewBinding = true } @@ -38,16 +37,21 @@ android { dependencies { implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.appcompat:appcompat:1.6.1") - implementation("com.google.android.material:material:1.10.0") + implementation("com.google.android.material:material:1.11.0") implementation("androidx.constraintlayout:constraintlayout:2.1.4") - implementation("androidx.navigation:navigation-fragment-ktx:2.7.5") - implementation("androidx.navigation:navigation-ui-ktx:2.7.5") - implementation("androidx.annotation:annotation:1.7.0") + implementation("androidx.navigation:navigation-fragment-ktx:2.7.6") + implementation("androidx.navigation:navigation-ui-ktx:2.7.6") + implementation("androidx.annotation:annotation:1.7.1") implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2") implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2") implementation("androidx.legacy:legacy-support-v4:1.0.0") - implementation("androidx.recyclerview:recyclerview:1.3.0") + implementation("androidx.recyclerview:recyclerview:1.3.2") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + + // Retrofit and Moshi for API requests. + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-moshi:2.9.0") + implementation("com.squareup.moshi:moshi-kotlin:1.13.0") } \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/PaltoActivity.kt b/app/src/main/java/com/example/palto/PaltoActivity.kt index 8a70afa..f06d427 100644 --- a/app/src/main/java/com/example/palto/PaltoActivity.kt +++ b/app/src/main/java/com/example/palto/PaltoActivity.kt @@ -1,18 +1,20 @@ package com.example.palto import android.nfc.NfcAdapter -import android.nfc.Tag import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity import androidx.activity.viewModels +import com.example.palto.ui.NfcViewModel +import com.example.palto.ui.UserViewModel class PaltoActivity : AppCompatActivity() { private var nfcAdapter: NfcAdapter? = null - private val paltoViewModel: PaltoViewModel by viewModels() + private val nfcViewModel: NfcViewModel by viewModels() + private val userViewModel: UserViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -32,11 +34,6 @@ class PaltoActivity : AppCompatActivity() { } setContentView(R.layout.activity_palto) - /* - val url = URL("https://www.faraphel.fr/palto/api/auth/token/") - val connection = url.openConnection() - val auth_data = Json.decodeFromString(connection.content) - */ } override fun onResume() { @@ -44,7 +41,7 @@ class PaltoActivity : AppCompatActivity() { nfcAdapter?.enableReaderMode( this, - paltoViewModel.tagLiveData::postValue, + nfcViewModel.tag::postValue, NfcAdapter.FLAG_READER_NFC_A or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null ) @@ -57,8 +54,10 @@ class PaltoActivity : AppCompatActivity() { nfcAdapter?.disableReaderMode(this) } + /* @OptIn(ExperimentalStdlibApi::class) fun processTag(tag: Tag) { Log.d("NFC", "Tag ID : " + tag.id.toHexString()) } + */ } diff --git a/app/src/main/java/com/example/palto/data/repository/AttendanceRepository.kt b/app/src/main/java/com/example/palto/data/repository/AttendanceRepository.kt index 13a8631..a40f502 100644 --- a/app/src/main/java/com/example/palto/data/repository/AttendanceRepository.kt +++ b/app/src/main/java/com/example/palto/data/repository/AttendanceRepository.kt @@ -1,10 +1,10 @@ package com.example.palto.data.repository -import com.example.palto.data.network.ServerDataSource +import com.example.palto.data.network.PaltoApiService /** * */ -class AttendanceRepository(val dataSource: ServerDataSource) { +class AttendanceRepository() { // private val cards } \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/data/repository/SessionRepository.kt b/app/src/main/java/com/example/palto/data/repository/SessionRepository.kt index 3b4b4a7..177dc55 100644 --- a/app/src/main/java/com/example/palto/data/repository/SessionRepository.kt +++ b/app/src/main/java/com/example/palto/data/repository/SessionRepository.kt @@ -1,10 +1,10 @@ package com.example.palto.data.repository -import com.example.palto.data.network.ServerDataSource +import com.example.palto.data.network.PaltoApiService /** * */ -class SessionRepository(val dataSource: ServerDataSource) { +class SessionRepository(val dataSource: PaltoApiService) { // private val cards } \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/model/Attendance.kt b/app/src/main/java/com/example/palto/domain/Attendance.kt similarity index 86% rename from app/src/main/java/com/example/palto/model/Attendance.kt rename to app/src/main/java/com/example/palto/domain/Attendance.kt index 1288725..356ac19 100644 --- a/app/src/main/java/com/example/palto/model/Attendance.kt +++ b/app/src/main/java/com/example/palto/domain/Attendance.kt @@ -1,4 +1,4 @@ -package com.example.palto.model +package com.example.palto.domain import java.io.Serializable /** diff --git a/app/src/main/java/com/example/palto/model/Card.kt b/app/src/main/java/com/example/palto/domain/Card.kt similarity index 87% rename from app/src/main/java/com/example/palto/model/Card.kt rename to app/src/main/java/com/example/palto/domain/Card.kt index 8c55422..4683d05 100644 --- a/app/src/main/java/com/example/palto/model/Card.kt +++ b/app/src/main/java/com/example/palto/domain/Card.kt @@ -1,5 +1,4 @@ -package com.example.palto.model -import java.io.Serializable +package com.example.palto.domain data class Card( val id: String, diff --git a/app/src/main/java/com/example/palto/model/Session.kt b/app/src/main/java/com/example/palto/domain/Session.kt similarity index 77% rename from app/src/main/java/com/example/palto/model/Session.kt rename to app/src/main/java/com/example/palto/domain/Session.kt index 8a6827f..fef790f 100644 --- a/app/src/main/java/com/example/palto/model/Session.kt +++ b/app/src/main/java/com/example/palto/domain/Session.kt @@ -1,4 +1,4 @@ -package com.example.palto.model +package com.example.palto.domain import java.io.Serializable /** @@ -6,4 +6,4 @@ import java.io.Serializable */ data class Session( val id: String -) : Serializable \ No newline at end of file +) \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/NfcViewModel.kt b/app/src/main/java/com/example/palto/ui/NfcViewModel.kt new file mode 100644 index 0000000..058fc7b --- /dev/null +++ b/app/src/main/java/com/example/palto/ui/NfcViewModel.kt @@ -0,0 +1,14 @@ +package com.example.palto.ui + +import android.nfc.Tag +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.example.palto.domain.User + +class NfcViewModel: ViewModel() { + val tag = MutableLiveData() + + private var _user : MutableLiveData = MutableLiveData() + val user : LiveData = _user +} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/attendanceList/AttendanceListFragment.kt b/app/src/main/java/com/example/palto/ui/attendanceList/AttendanceListFragment.kt deleted file mode 100644 index 68773ab..0000000 --- a/app/src/main/java/com/example/palto/ui/attendanceList/AttendanceListFragment.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.example.palto.ui.attendanceList - -import android.nfc.NfcAdapter -import android.nfc.Tag -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import androidx.lifecycle.Observer -import androidx.navigation.navGraphViewModels -import com.example.palto.PaltoViewModel -import com.example.palto.R -import com.example.palto.databinding.FragmentAttendanceListBinding - -/** - * A fragment representing a list of attendances. - */ -class AttendanceListFragment : Fragment() { - - private val attendanceListViewModel: AttendanceListViewModel by - 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( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - - _binding = FragmentAttendanceListBinding.inflate(inflater, container, false) - 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) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt b/app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt new file mode 100644 index 0000000..79db931 --- /dev/null +++ b/app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt @@ -0,0 +1,69 @@ +package com.example.palto.ui.menu + +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.example.palto.databinding.FragmentMenuItemBinding +import com.example.palto.domain.Session + +/** + * A [ListAdapter] that can display [Session] items. + */ +class MenuAdapter : + ListAdapter(SessionDiffCallback) { + + /* + class ViewHolder(binding: FragmentSessionItemBinding) : + RecyclerView.ViewHolder(binding.root) { + + val idView: TextView = binding.itemNumber + val contentView: TextView = binding.content + + override fun toString(): String { + return super.toString() + " '" + contentView.text + "'" + } + } + */ + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + FragmentMenuItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val item = getItem(position) + holder.idView.text = position.toString() + holder.contentView.text = item.id + } + + //override fun getItemCount(): Int = values.size + + inner class ViewHolder( + binding: FragmentMenuItemBinding + ) : RecyclerView.ViewHolder(binding.root) { + + val idView: TextView = binding.itemNumber + val contentView: TextView = binding.content + override fun toString(): String { + return super.toString() + " '" + idView.text + contentView.text + "'" + } + } +} + +object SessionDiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Session, newItem: Session): Boolean { + return oldItem == newItem + } + + override fun areContentsTheSame(oldItem: Session, newItem: Session): Boolean { + return oldItem.id == newItem.id + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt b/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt new file mode 100644 index 0000000..4de1c00 --- /dev/null +++ b/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt @@ -0,0 +1,45 @@ +package com.example.palto.ui.menu + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import com.example.palto.databinding.FragmentMenuListBinding +import com.example.palto.databinding.FragmentSessionListBinding + +/** + * A fragment representing a list of Sessions. + */ +class MenuFragment : Fragment() { + + private val menuViewModel: MenuViewModel by viewModels() + + private var _binding: FragmentMenuListBinding? = null + // This property is only valid between onCreateView and onDestroyView + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentMenuListBinding.inflate(inflater, container, false) + + val adapter = MenuAdapter() + binding.menuList.adapter = MenuAdapter() + menuViewModel.sessions.observe(viewLifecycleOwner) { + Log.d("PALTO", "A session has been created") + adapter.submitList(it) + } + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + menuViewModel.createSession() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt b/app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt new file mode 100644 index 0000000..e953081 --- /dev/null +++ b/app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt @@ -0,0 +1,21 @@ +package com.example.palto.ui.menu + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.example.palto.data.repository.LoginRepository +import com.example.palto.domain.Session + +class MenuViewModel() : ViewModel() { + + private var _sessions = MutableLiveData>(emptyList()) + val sessions: LiveData> = _sessions + + fun createSession() { + val session = Session( + id = "aahh" + ) + _sessions.value = (_sessions.value ?: emptyList()) + session + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/attendanceList/AttendanceListAdapter.kt b/app/src/main/java/com/example/palto/ui/session/SessionAdapter.kt similarity index 72% rename from app/src/main/java/com/example/palto/ui/attendanceList/AttendanceListAdapter.kt rename to app/src/main/java/com/example/palto/ui/session/SessionAdapter.kt index a7788b1..00a43ef 100644 --- a/app/src/main/java/com/example/palto/ui/attendanceList/AttendanceListAdapter.kt +++ b/app/src/main/java/com/example/palto/ui/session/SessionAdapter.kt @@ -1,4 +1,4 @@ -package com.example.palto.ui.attendanceList +package com.example.palto.ui.session import android.view.LayoutInflater import android.view.ViewGroup @@ -6,22 +6,18 @@ import android.widget.TextView import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import com.example.palto.databinding.FragmentAttendanceItemBinding -import com.example.palto.model.Card +import com.example.palto.databinding.FragmentSessionItemBinding +import com.example.palto.domain.Card /** - * + * A [ListAdapter] that can display [Card] items. */ -class AttendanceListAdapter : - ListAdapter(CardDiffCallback) { - - override fun onCreateViewHolder( - parent: ViewGroup, - viewType: Int - ): ViewHolder { +class SessionAdapter : + ListAdapter(CardDiffCallback) { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return ViewHolder( - FragmentAttendanceItemBinding.inflate( + FragmentSessionItemBinding.inflate( LayoutInflater.from(parent.context), parent, false @@ -37,7 +33,7 @@ class AttendanceListAdapter : } inner class ViewHolder( - binding: FragmentAttendanceItemBinding + binding: FragmentSessionItemBinding ) : RecyclerView.ViewHolder(binding.root) { val cardId: TextView = binding.cardId diff --git a/app/src/main/java/com/example/palto/ui/session/SessionFragment.kt b/app/src/main/java/com/example/palto/ui/session/SessionFragment.kt new file mode 100644 index 0000000..d4fd9a1 --- /dev/null +++ b/app/src/main/java/com/example/palto/ui/session/SessionFragment.kt @@ -0,0 +1,56 @@ +package com.example.palto.ui.session + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.navigation.navGraphViewModels +import com.example.palto.ui.NfcViewModel +import com.example.palto.R +import com.example.palto.databinding.FragmentSessionListBinding + +/** + * A fragment representing a list of attendances. + */ +class SessionFragment : Fragment() { + + private val sessionViewModel: SessionViewModel by + navGraphViewModels(R.id.nav_graph) { SessionViewModel.Factory } + + private val nfcViewModel: NfcViewModel by + activityViewModels() + + private var _binding: FragmentSessionListBinding? = null + // This property is only valid between onCreateView and onDestroyView + private val binding get() = _binding!! + + /** + * Have the fragment instantiate the user interface. + */ + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentSessionListBinding.inflate(inflater, container, false) + + // Set the adapter of the view for managing automatically the list of items on the screen. + val adapter = SessionAdapter() + binding.sessionList.adapter = adapter + sessionViewModel.cards.observe(viewLifecycleOwner) { + Log.d("NFC", "A card has been had to the list") + adapter.submitList(it) + } + + // Set the listener for a new NFC tag. + nfcViewModel.tag.observe(viewLifecycleOwner) { + Log.d("NFC", "tag observer has been notified") + sessionViewModel.insertCard(it) + } + + return binding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/attendanceList/AttendanceListViewModel.kt b/app/src/main/java/com/example/palto/ui/session/SessionViewModel.kt similarity index 67% rename from app/src/main/java/com/example/palto/ui/attendanceList/AttendanceListViewModel.kt rename to app/src/main/java/com/example/palto/ui/session/SessionViewModel.kt index a4efa38..a64dbc8 100644 --- a/app/src/main/java/com/example/palto/ui/attendanceList/AttendanceListViewModel.kt +++ b/app/src/main/java/com/example/palto/ui/session/SessionViewModel.kt @@ -1,4 +1,4 @@ -package com.example.palto.ui.attendanceList +package com.example.palto.ui.session import android.nfc.Tag import android.util.Log @@ -6,18 +6,18 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.example.palto.data.network.ServerDataSource import com.example.palto.data.repository.AttendanceRepository -import com.example.palto.model.Card +import com.example.palto.domain.Card /** * ViewModel of a session which has a list of attendances. */ -class AttendanceListViewModel( +class SessionViewModel( private val attendanceRepository: AttendanceRepository ) : ViewModel() { - val cardsLiveData: MutableLiveData> = MutableLiveData(emptyList()) + private val _cards: MutableLiveData> = MutableLiveData(emptyList()) + val cards = _cards as LiveData> fun insertCard(tag: Tag) { val card = Card( @@ -26,12 +26,12 @@ class AttendanceListViewModel( "tmp", "tmp" ) - cardsLiveData.value = (cardsLiveData.value ?: emptyList()) + card + _cards.value = (_cards.value ?: emptyList()) + card Log.d("NFC", "view model: A card has been had to the list") } /** - * ViewModel Factory. + * ViewModel Factory. */ companion object { @@ -40,8 +40,8 @@ class AttendanceListViewModel( override fun create( modelClass: Class ): T { - return AttendanceListViewModel( - AttendanceRepository(ServerDataSource()) + return SessionViewModel( + AttendanceRepository() ) as T } } diff --git a/app/src/main/java/com/example/palto/ui/sessionList/SessionListAdapter.kt b/app/src/main/java/com/example/palto/ui/sessionList/SessionListAdapter.kt deleted file mode 100644 index 24f492f..0000000 --- a/app/src/main/java/com/example/palto/ui/sessionList/SessionListAdapter.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.example.palto.ui.sessionList - -import androidx.recyclerview.widget.RecyclerView -import android.view.LayoutInflater -import android.view.ViewGroup -import android.widget.TextView - -import com.example.palto.ui.sessionList.placeholder.PlaceholderContent.PlaceholderItem -import com.example.palto.databinding.FragmentSessionItemBinding - -/** - * [RecyclerView.Adapter] that can display a [PlaceholderItem]. - */ -class SessionListAdapter(private val values: List) : - RecyclerView.Adapter() { - - class ViewHolder(binding: FragmentSessionItemBinding) : - RecyclerView.ViewHolder(binding.root) { - - val idView: TextView = binding.itemNumber - val contentView: TextView = binding.content - - override fun toString(): String { - return super.toString() + " '" + contentView.text + "'" - } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val view = FragmentSessionItemBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false - ) - return ViewHolder(view) - } - - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val item = values[position] - holder.idView.text = item.id - holder.contentView.text = item.content - } - - override fun getItemCount(): Int = values.size -} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/sessionList/SessionListFragment.kt b/app/src/main/java/com/example/palto/ui/sessionList/SessionListFragment.kt deleted file mode 100644 index 03424e1..0000000 --- a/app/src/main/java/com/example/palto/ui/sessionList/SessionListFragment.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.example.palto.ui.sessionList - -import android.os.Bundle -import androidx.fragment.app.Fragment -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.example.palto.R -import com.example.palto.ui.sessionList.placeholder.PlaceholderContent - -/** - * A fragment representing a list of Sessions. - */ -class SessionListFragment : Fragment() { - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - val view = inflater.inflate(R.layout.fragment_session_list, container, false) - - if (view is RecyclerView) { - view.layoutManager = LinearLayoutManager(context) - view.adapter = SessionListAdapter(PlaceholderContent.ITEMS) - } - return view - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/sessionList/SessionListViewModel.kt b/app/src/main/java/com/example/palto/ui/sessionList/SessionListViewModel.kt deleted file mode 100644 index d127a36..0000000 --- a/app/src/main/java/com/example/palto/ui/sessionList/SessionListViewModel.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.example.palto.ui.sessionList - -import androidx.lifecycle.ViewModel -import com.example.palto.data.repository.LoginRepository - -class SessionListViewModel(private val loginRepository: LoginRepository) : ViewModel() { - /* - private val _loginForm = MutableLiveData() - val loginFormState: LiveData = _loginForm - - private val _loginResult = MutableLiveData() - val loginResult: LiveData = _loginResult - */ -} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_attendance_item.xml b/app/src/main/res/layout/fragment_menu_item.xml similarity index 61% rename from app/src/main/res/layout/fragment_attendance_item.xml rename to app/src/main/res/layout/fragment_menu_item.xml index b975c33..1877568 100644 --- a/app/src/main/res/layout/fragment_attendance_item.xml +++ b/app/src/main/res/layout/fragment_menu_item.xml @@ -5,7 +5,14 @@ android:orientation="horizontal"> + + \ No newline at end of file + tools:context=".ui.menu.MenuFragment" + tools:listitem="@layout/fragment_menu_item" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_session_item.xml b/app/src/main/res/layout/fragment_session_item.xml index 1877568..b975c33 100644 --- a/app/src/main/res/layout/fragment_session_item.xml +++ b/app/src/main/res/layout/fragment_session_item.xml @@ -5,14 +5,7 @@ android:orientation="horizontal"> - - \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 4b9c3fd..29dade6 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -3,20 +3,28 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/nav_graph" - app:startDestination="@id/attendanceListFragment"> + app:startDestination="@id/menuFragment"> + android:id="@+id/menuFragment" + android:name="com.example.palto.ui.menu.MenuFragment" + android:label="fragment_menu_list" + tools:layout="@layout/fragment_menu_list" > + + + + \ No newline at end of file From a79b591e903f253719c2992a4f2292accea04e73 Mon Sep 17 00:00:00 2001 From: biloute02 Date: Sat, 6 Jan 2024 11:25:31 +0100 Subject: [PATCH 02/12] =?UTF-8?q?Ajout=20de=20bouttons=20pour=20cr=C3=A9er?= =?UTF-8?q?=20des=20=C3=A9l=C3=A9ments=20dans=20les=20listes=20Menu=20et?= =?UTF-8?q?=20Session?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/palto/ui/menu/MenuAdapter.kt | 25 +++----------- .../com/example/palto/ui/menu/MenuFragment.kt | 22 ++++++------- .../example/palto/ui/menu/MenuViewModel.kt | 4 +-- .../palto/ui/session/SessionAdapter.kt | 1 - .../palto/ui/session/SessionFragment.kt | 7 ++-- .../palto/ui/session/SessionViewModel.kt | 4 +-- .../main/res/layout/fragment_menu_item.xml | 8 +---- .../main/res/layout/fragment_menu_list.xml | 33 ++++++++++++++----- .../main/res/layout/fragment_session_list.xml | 33 ++++++++++++++----- app/src/main/res/values/strings.xml | 2 ++ 10 files changed, 76 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt b/app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt index 79db931..d56a5ed 100644 --- a/app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt +++ b/app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt @@ -15,19 +15,6 @@ import com.example.palto.domain.Session class MenuAdapter : ListAdapter(SessionDiffCallback) { - /* - class ViewHolder(binding: FragmentSessionItemBinding) : - RecyclerView.ViewHolder(binding.root) { - - val idView: TextView = binding.itemNumber - val contentView: TextView = binding.content - - override fun toString(): String { - return super.toString() + " '" + contentView.text + "'" - } - } - */ - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return ViewHolder( FragmentMenuItemBinding.inflate( @@ -40,22 +27,20 @@ class MenuAdapter : override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = getItem(position) - holder.idView.text = position.toString() - holder.contentView.text = item.id + holder.sessionId.text = item.id } - //override fun getItemCount(): Int = values.size - inner class ViewHolder( binding: FragmentMenuItemBinding ) : RecyclerView.ViewHolder(binding.root) { - val idView: TextView = binding.itemNumber - val contentView: TextView = binding.content + val sessionId: TextView = binding.sessionId override fun toString(): String { - return super.toString() + " '" + idView.text + contentView.text + "'" + return super.toString() + " '" + sessionId.text + "'" } } + + //override fun getItemCount(): Int = values.size } object SessionDiffCallback : DiffUtil.ItemCallback() { diff --git a/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt b/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt index 4de1c00..f71b3ea 100644 --- a/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt +++ b/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt @@ -1,21 +1,22 @@ package com.example.palto.ui.menu import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import androidx.navigation.navGraphViewModels +import com.example.palto.R import com.example.palto.databinding.FragmentMenuListBinding -import com.example.palto.databinding.FragmentSessionListBinding /** * A fragment representing a list of Sessions. */ class MenuFragment : Fragment() { - private val menuViewModel: MenuViewModel by viewModels() + private val menuViewModel: MenuViewModel by + navGraphViewModels(R.id.nav_graph) private var _binding: FragmentMenuListBinding? = null // This property is only valid between onCreateView and onDestroyView @@ -29,17 +30,16 @@ class MenuFragment : Fragment() { _binding = FragmentMenuListBinding.inflate(inflater, container, false) val adapter = MenuAdapter() - binding.menuList.adapter = MenuAdapter() + binding.menuList.adapter = adapter menuViewModel.sessions.observe(viewLifecycleOwner) { - Log.d("PALTO", "A session has been created") adapter.submitList(it) } + binding.createSession.setOnClickListener { + menuViewModel.createSession() + findNavController().navigate(R.id.action_menuFragment_to_sessionFragment) + } + return binding.root } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - menuViewModel.createSession() - } } \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt b/app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt index e953081..859198b 100644 --- a/app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt +++ b/app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt @@ -4,18 +4,18 @@ import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.example.palto.data.repository.LoginRepository import com.example.palto.domain.Session class MenuViewModel() : ViewModel() { private var _sessions = MutableLiveData>(emptyList()) - val sessions: LiveData> = _sessions + val sessions = _sessions as LiveData> fun createSession() { val session = Session( id = "aahh" ) _sessions.value = (_sessions.value ?: emptyList()) + session + Log.d("PALTO", "MenuViewModel: a session has been added into the list.") } } \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/session/SessionAdapter.kt b/app/src/main/java/com/example/palto/ui/session/SessionAdapter.kt index 00a43ef..6a11a69 100644 --- a/app/src/main/java/com/example/palto/ui/session/SessionAdapter.kt +++ b/app/src/main/java/com/example/palto/ui/session/SessionAdapter.kt @@ -29,7 +29,6 @@ class SessionAdapter : override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = getItem(position) holder.cardId.text = item.uid.toHexString() - //holder.contentView.text = item.content } inner class ViewHolder( diff --git a/app/src/main/java/com/example/palto/ui/session/SessionFragment.kt b/app/src/main/java/com/example/palto/ui/session/SessionFragment.kt index d4fd9a1..1f19919 100644 --- a/app/src/main/java/com/example/palto/ui/session/SessionFragment.kt +++ b/app/src/main/java/com/example/palto/ui/session/SessionFragment.kt @@ -41,16 +41,19 @@ class SessionFragment : Fragment() { val adapter = SessionAdapter() binding.sessionList.adapter = adapter sessionViewModel.cards.observe(viewLifecycleOwner) { - Log.d("NFC", "A card has been had to the list") adapter.submitList(it) } // Set the listener for a new NFC tag. nfcViewModel.tag.observe(viewLifecycleOwner) { - Log.d("NFC", "tag observer has been notified") + Log.d("NFC", "The tag observers has been notified.") sessionViewModel.insertCard(it) } + binding.createCard.setOnClickListener { + //sessionViewModel. + } + return binding.root } } \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/session/SessionViewModel.kt b/app/src/main/java/com/example/palto/ui/session/SessionViewModel.kt index a64dbc8..f9e4c61 100644 --- a/app/src/main/java/com/example/palto/ui/session/SessionViewModel.kt +++ b/app/src/main/java/com/example/palto/ui/session/SessionViewModel.kt @@ -16,7 +16,7 @@ class SessionViewModel( private val attendanceRepository: AttendanceRepository ) : ViewModel() { - private val _cards: MutableLiveData> = MutableLiveData(emptyList()) + private val _cards = MutableLiveData>(emptyList()) val cards = _cards as LiveData> fun insertCard(tag: Tag) { @@ -27,7 +27,7 @@ class SessionViewModel( "tmp" ) _cards.value = (_cards.value ?: emptyList()) + card - Log.d("NFC", "view model: A card has been had to the list") + Log.d("PALTO", "SessionViewModel: a card has been added into the list.") } /** diff --git a/app/src/main/res/layout/fragment_menu_item.xml b/app/src/main/res/layout/fragment_menu_item.xml index 1877568..dd0594e 100644 --- a/app/src/main/res/layout/fragment_menu_item.xml +++ b/app/src/main/res/layout/fragment_menu_item.xml @@ -5,16 +5,10 @@ android:orientation="horizontal"> - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_menu_list.xml b/app/src/main/res/layout/fragment_menu_list.xml index e5bf724..992f5ff 100644 --- a/app/src/main/res/layout/fragment_menu_list.xml +++ b/app/src/main/res/layout/fragment_menu_list.xml @@ -1,13 +1,28 @@ - \ No newline at end of file + android:layout_height="match_parent"> + + + + + + diff --git a/app/src/main/res/layout/fragment_session_list.xml b/app/src/main/res/layout/fragment_session_list.xml index 1816dad..9e5aeae 100644 --- a/app/src/main/res/layout/fragment_session_list.xml +++ b/app/src/main/res/layout/fragment_session_list.xml @@ -1,13 +1,28 @@ - \ No newline at end of file + android:layout_height="match_parent"> + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 51b4ac6..70d74d8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -12,4 +12,6 @@ Mot de passe invalide "Erreur de connexion !" Identifiants Invalides + Créer une session + Créer une présence \ No newline at end of file From 69d1880295a185a8f080d990ef868caed0d22595 Mon Sep 17 00:00:00 2001 From: biloute02 Date: Thu, 11 Jan 2024 22:03:30 +0100 Subject: [PATCH 03/12] =?UTF-8?q?Ajout=20du=20service=20Palto=20pour=20com?= =?UTF-8?q?muniquer=20avec=20l=E2=80=99API.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 2 + .../java/com/example/palto/data/Result.kt | 18 ------ .../palto/data/network/PaltoApiService.kt | 46 ++++++++++++++ .../palto/data/network/ServerDataSource.kt | 60 ------------------- .../data/network/model/UserCredentials.kt | 6 ++ .../palto/data/repository/TokenRepository.kt | 23 +++++++ .../palto/data/repository/TokensRepository.kt | 43 ------------- .../example/palto/{model => domain}/Tokens.kt | 4 +- 8 files changed, 79 insertions(+), 123 deletions(-) delete mode 100644 app/src/main/java/com/example/palto/data/Result.kt create mode 100644 app/src/main/java/com/example/palto/data/network/PaltoApiService.kt delete mode 100644 app/src/main/java/com/example/palto/data/network/ServerDataSource.kt create mode 100644 app/src/main/java/com/example/palto/data/network/model/UserCredentials.kt create mode 100644 app/src/main/java/com/example/palto/data/repository/TokenRepository.kt delete mode 100644 app/src/main/java/com/example/palto/data/repository/TokensRepository.kt rename app/src/main/java/com/example/palto/{model => domain}/Tokens.kt (79%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fc2cb02..cf82b15 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + - */ -sealed class Result { - - data class Success(val data: T) : Result() - data class Error(val exception: Exception) : Result() - - override fun toString(): String { - return when (this) { - is Success<*> -> "Success[data=$data]" - is Error -> "Error[exception=$exception]" - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/data/network/PaltoApiService.kt b/app/src/main/java/com/example/palto/data/network/PaltoApiService.kt new file mode 100644 index 0000000..21cde23 --- /dev/null +++ b/app/src/main/java/com/example/palto/data/network/PaltoApiService.kt @@ -0,0 +1,46 @@ +package com.example.palto.data.network + +import com.example.palto.data.network.model.UserCredentials +import com.example.palto.domain.Tokens +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import retrofit2.Retrofit +import retrofit2.converter.moshi.MoshiConverterFactory +import retrofit2.http.Body +import retrofit2.http.POST + +/** + * A public Api object that exposes the lazy-initialized Retrofit service + */ +object PaltoApi { + + // Build the Moshi object that Retrofit will be using, making sure to add the Kotlin adapter for + // full Kotlin compatibility. + private val moshi = Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() + + fun createService(url: String) { + // Use the Retrofit builder to build a retrofit object using a Moshi converter + // with our Moshi object. + val retrofit = Retrofit.Builder() + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .baseUrl(url) + .build() + retrofitService = retrofit.create(PaltoApiService::class.java) + } + + // Retrofit service that Palto will use to do requests. + // Make sure to call createService once before using it. + lateinit var retrofitService: PaltoApiService +} + + +/** + * Functions to query the API. + */ +interface PaltoApiService { + + @POST("api/auth/jwt/token/") + suspend fun getTokens(@Body userCredentials: UserCredentials): Tokens +} diff --git a/app/src/main/java/com/example/palto/data/network/ServerDataSource.kt b/app/src/main/java/com/example/palto/data/network/ServerDataSource.kt deleted file mode 100644 index 8c68892..0000000 --- a/app/src/main/java/com/example/palto/data/network/ServerDataSource.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.example.palto.data.network - -import com.example.palto.data.Result -import com.example.palto.model.LoggedInUser -import com.example.palto.model.Tokens -import java.io.IOException -import java.util.UUID - -/** - * Class that handles API calls. - */ -class ServerDataSource { - - private var hostname: String? = null - - fun requestToken( - hostname: String, - username: String, - password: String - ): Result { - try { - val tokens = Tokens( - refresh = "aa", - access = "bb" - ) - return Result.Success(tokens) - } catch (e: Throwable) { - return Result.Error(IOException("Error logging in", e)) - } - } - - fun refreshToken(current_tokens: Tokens): Result { - return Result.Success(current_tokens) - } - - fun verifyToken(): Boolean { - return true - } - - fun login( - hostname: String, - username: String, - password: String - ): Result { - try { - val fakeUser = LoggedInUser( - UUID.randomUUID().toString(), - "dede", - "Lucie", - "Doe", - "aa@free.fr", - ) - return Result.Success(fakeUser) - } catch (e: Throwable) { - return Result.Error(IOException("Error logging in", e)) - } - } - - fun logout() { } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/data/network/model/UserCredentials.kt b/app/src/main/java/com/example/palto/data/network/model/UserCredentials.kt new file mode 100644 index 0000000..50b3ffd --- /dev/null +++ b/app/src/main/java/com/example/palto/data/network/model/UserCredentials.kt @@ -0,0 +1,6 @@ +package com.example.palto.data.network.model + +data class UserCredentials( + val username: String, + val password: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/data/repository/TokenRepository.kt b/app/src/main/java/com/example/palto/data/repository/TokenRepository.kt new file mode 100644 index 0000000..c1bb243 --- /dev/null +++ b/app/src/main/java/com/example/palto/data/repository/TokenRepository.kt @@ -0,0 +1,23 @@ +package com.example.palto.data.repository + +import com.example.palto.data.network.PaltoApi +import com.example.palto.data.network.model.UserCredentials +import com.example.palto.domain.Tokens + +/** + * Class that requests authentication tokens from Palto server. + */ +class TokenRepository() { + + private var tokens: Tokens? = null + + suspend fun authenticate( + hostname: String, + username: String, + password: String + ) { + PaltoApi.createService("http://$hostname:8000/") + val tokens = PaltoApi.retrofitService.getTokens((UserCredentials(username, password))) + this.tokens = tokens + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/data/repository/TokensRepository.kt b/app/src/main/java/com/example/palto/data/repository/TokensRepository.kt deleted file mode 100644 index 184f04c..0000000 --- a/app/src/main/java/com/example/palto/data/repository/TokensRepository.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.example.palto.data.repository - -import com.example.palto.data.network.ServerDataSource -import com.example.palto.model.Tokens - -/** - * Class that requests authentication and user information from the remote data source and - * maintains an in-memory cache of login status and user credentials information. - */ - -class TokensRepository(val dataSource: ServerDataSource) { - - var tokens: Tokens? = null - private set - - /* - val isLoggedIn: Boolean - get() = user != null - */ - - init { - // If user credentials will be cached in local storage, it is recommended it be encrypted - // @see https://developer.android.com/training/articles/keystore - tokens = null - } - - /* - fun login(username: String, password: String): Result { - // handle login - val result = dataSource.login(username, password) - - if (result is Result.Success) { - setLoggedInUser(result.data) - } - - return result - } - */ - - private fun setTokens(tokens: Tokens) { - this.tokens = tokens - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/model/Tokens.kt b/app/src/main/java/com/example/palto/domain/Tokens.kt similarity index 79% rename from app/src/main/java/com/example/palto/model/Tokens.kt rename to app/src/main/java/com/example/palto/domain/Tokens.kt index fa90475..4e29846 100644 --- a/app/src/main/java/com/example/palto/model/Tokens.kt +++ b/app/src/main/java/com/example/palto/domain/Tokens.kt @@ -1,4 +1,4 @@ -package com.example.palto.model +package com.example.palto.domain import java.io.Serializable /** @@ -7,4 +7,4 @@ import java.io.Serializable data class Tokens( val refresh: String, val access: String -) : Serializable \ No newline at end of file +) \ No newline at end of file From e81f70f04504b30459f44efb46cebcb31ded482b Mon Sep 17 00:00:00 2001 From: biloute02 Date: Thu, 11 Jan 2024 22:21:31 +0100 Subject: [PATCH 04/12] =?UTF-8?q?Ajout=20de=20la=20connexion=20d=E2=80=99u?= =?UTF-8?q?n=20utilisateur=20au=20serveur=20Palto=20et=20connexion=20anony?= =?UTF-8?q?me=20hors=20ligne.y?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/palto/PaltoViewModel.kt | 9 -- .../palto/data/local/LocalDataSource.kt | 24 ---- .../data/repository/AttendanceRepository.kt | 9 +- .../palto/data/repository/LoginRepository.kt | 47 -------- .../data/repository/SessionRepository.kt | 9 +- .../palto/data/repository/UserRepository.kt | 3 + .../{model/LoggedInUser.kt => domain/User.kt} | 11 +- .../com/example/palto/ui/UserViewModel.kt | 78 +++++++++++++ .../palto/ui/login/LoggedInUserView.kt | 13 --- .../example/palto/ui/login/LoginFragment.kt | 105 ++++++++++-------- .../com/example/palto/ui/login/LoginResult.kt | 7 +- .../example/palto/ui/login/LoginViewModel.kt | 63 ++--------- .../com/example/palto/ui/menu/MenuFragment.kt | 14 ++- .../placeholder/PlaceholderContent.kt | 57 ---------- app/src/main/res/layout/fragment_login.xml | 65 ++++++----- app/src/main/res/values/strings.xml | 1 + build.gradle.kts | 2 +- 17 files changed, 207 insertions(+), 310 deletions(-) delete mode 100644 app/src/main/java/com/example/palto/PaltoViewModel.kt delete mode 100644 app/src/main/java/com/example/palto/data/local/LocalDataSource.kt delete mode 100644 app/src/main/java/com/example/palto/data/repository/LoginRepository.kt create mode 100644 app/src/main/java/com/example/palto/data/repository/UserRepository.kt rename app/src/main/java/com/example/palto/{model/LoggedInUser.kt => domain/User.kt} (62%) create mode 100644 app/src/main/java/com/example/palto/ui/UserViewModel.kt delete mode 100644 app/src/main/java/com/example/palto/ui/login/LoggedInUserView.kt delete mode 100644 app/src/main/java/com/example/palto/ui/sessionList/placeholder/PlaceholderContent.kt diff --git a/app/src/main/java/com/example/palto/PaltoViewModel.kt b/app/src/main/java/com/example/palto/PaltoViewModel.kt deleted file mode 100644 index 9d69dc4..0000000 --- a/app/src/main/java/com/example/palto/PaltoViewModel.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.example.palto - -import android.nfc.Tag -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel - -class PaltoViewModel: ViewModel() { - val tagLiveData = MutableLiveData() -} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/data/local/LocalDataSource.kt b/app/src/main/java/com/example/palto/data/local/LocalDataSource.kt deleted file mode 100644 index d05487e..0000000 --- a/app/src/main/java/com/example/palto/data/local/LocalDataSource.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.example.palto.data.local - -/** - * Class that handles authentication w/ login credentials and retrieves user information. - */ -class LocalDataSource { - /* - fun login(username: String, password: String): Result { - try { - - - val fakeUser = LoggedInUser(java.util.UUID.randomUUID().toString(), "Jane Doe") - return Result.Success(fakeUser) - - } catch (e: Throwable) { - return Result.Error(IOException("Error logging in", e)) - } - } - - fun logout() { - // TODO: revoke authentication - } - */ -} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/data/repository/AttendanceRepository.kt b/app/src/main/java/com/example/palto/data/repository/AttendanceRepository.kt index a40f502..5ceb649 100644 --- a/app/src/main/java/com/example/palto/data/repository/AttendanceRepository.kt +++ b/app/src/main/java/com/example/palto/data/repository/AttendanceRepository.kt @@ -1,10 +1,3 @@ package com.example.palto.data.repository -import com.example.palto.data.network.PaltoApiService - -/** - * - */ -class AttendanceRepository() { - // private val cards -} \ No newline at end of file +class AttendanceRepository \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/data/repository/LoginRepository.kt b/app/src/main/java/com/example/palto/data/repository/LoginRepository.kt deleted file mode 100644 index ad61888..0000000 --- a/app/src/main/java/com/example/palto/data/repository/LoginRepository.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.example.palto.data.repository - -import com.example.palto.data.Result -import com.example.palto.data.network.ServerDataSource -import com.example.palto.model.LoggedInUser - -/** - * Class that requests authentication and user information from the remote data source and - * maintains an in-memory cache of login status and user credentials information. - */ - -class LoginRepository(val dataSource: ServerDataSource) { - - var user: LoggedInUser? = null - private set - - val isLoggedIn: Boolean - get() = user != null - - init { - user = null - } - - fun logout() { - user = null - dataSource.logout() - } - - fun login( - hostname: String, - username: String, - password: String - ): Result { - // handle login - val result = dataSource.login(hostname, username, password) - - if (result is Result.Success) { - setLoggedInUser(result.data) - } - - return result - } - - private fun setLoggedInUser(loggedInUser: LoggedInUser) { - this.user = loggedInUser - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/data/repository/SessionRepository.kt b/app/src/main/java/com/example/palto/data/repository/SessionRepository.kt index 177dc55..45e122c 100644 --- a/app/src/main/java/com/example/palto/data/repository/SessionRepository.kt +++ b/app/src/main/java/com/example/palto/data/repository/SessionRepository.kt @@ -1,10 +1,3 @@ package com.example.palto.data.repository -import com.example.palto.data.network.PaltoApiService - -/** - * - */ -class SessionRepository(val dataSource: PaltoApiService) { - // private val cards -} \ No newline at end of file +class SessionRepository \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/data/repository/UserRepository.kt b/app/src/main/java/com/example/palto/data/repository/UserRepository.kt new file mode 100644 index 0000000..2c58c10 --- /dev/null +++ b/app/src/main/java/com/example/palto/data/repository/UserRepository.kt @@ -0,0 +1,3 @@ +package com.example.palto.data.repository + +class UserRepository \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/model/LoggedInUser.kt b/app/src/main/java/com/example/palto/domain/User.kt similarity index 62% rename from app/src/main/java/com/example/palto/model/LoggedInUser.kt rename to app/src/main/java/com/example/palto/domain/User.kt index 6f60811..60fd4b2 100644 --- a/app/src/main/java/com/example/palto/model/LoggedInUser.kt +++ b/app/src/main/java/com/example/palto/domain/User.kt @@ -1,14 +1,13 @@ -package com.example.palto.model - -import java.io.Serializable +package com.example.palto.domain /** * Data class that captures user information for logged in users retrieved from LoginRepository */ -data class LoggedInUser( - val id: String, +data class User( + //Not in the domain layer + //val id: String, val username: String, val first_name: String, val last_name: String, val email: String -) : Serializable +) diff --git a/app/src/main/java/com/example/palto/ui/UserViewModel.kt b/app/src/main/java/com/example/palto/ui/UserViewModel.kt new file mode 100644 index 0000000..a767420 --- /dev/null +++ b/app/src/main/java/com/example/palto/ui/UserViewModel.kt @@ -0,0 +1,78 @@ +package com.example.palto.ui + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import com.example.palto.R +import com.example.palto.data.repository.TokenRepository +import com.example.palto.data.repository.UserRepository +import com.example.palto.domain.User +import com.example.palto.ui.login.LoginResult +import kotlinx.coroutines.launch + +class UserViewModel( + private val tokenRepository: TokenRepository, + private val userRepository: UserRepository +): ViewModel() { + + private var _result = MutableLiveData() + val result = _result as LiveData + + // User is initially set to null to be disconnected. + private var _user = MutableLiveData(null) + val user = _user as LiveData + + fun login( + hostname: String, + username: String, + password: String) { + + // Coroutine runs in background. + viewModelScope.launch { + try { + tokenRepository.authenticate(hostname, username, password) + _user.value = User( + username, + "", + "", + "" + ) + _result.value = LoginResult(success = true) + } catch (e: Exception) { + Log.e("Palto", "Connection error: " + e.message) + _result.value = LoginResult( + success = false, + error = R.string.login_failed, + exception = e + ) + } + } + } + + fun loginAnonymous() { + _user.value = User( + "anonymous", "", "", "" + ) + _result.value = LoginResult(success = true) + } + + fun logout() { + _user.value = null + _result.value = LoginResult(success = false) + } + + companion object { + + val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + return UserViewModel( + tokenRepository = TokenRepository(), + userRepository = UserRepository() + ) as T + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/login/LoggedInUserView.kt b/app/src/main/java/com/example/palto/ui/login/LoggedInUserView.kt deleted file mode 100644 index 8cddb61..0000000 --- a/app/src/main/java/com/example/palto/ui/login/LoggedInUserView.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.palto.ui.login - -/* Est-ce que c’est util ? - * Updater la vue dans le fragment - */ - -/** - * User details post authentication that is exposed to the UI - */ -data class LoggedInUserView( - val displayName: String - //... other data fields that may be accessible to the UI -) diff --git a/app/src/main/java/com/example/palto/ui/login/LoginFragment.kt b/app/src/main/java/com/example/palto/ui/login/LoginFragment.kt index acf12be..85530cf 100644 --- a/app/src/main/java/com/example/palto/ui/login/LoginFragment.kt +++ b/app/src/main/java/com/example/palto/ui/login/LoginFragment.kt @@ -1,42 +1,68 @@ package com.example.palto.ui.login -import androidx.lifecycle.Observer -import androidx.annotation.StringRes -import androidx.fragment.app.Fragment +import android.annotation.SuppressLint import android.os.Bundle -import android.text.Editable -import android.text.TextWatcher import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.inputmethod.EditorInfo import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController -import androidx.navigation.navGraphViewModels import com.example.palto.databinding.FragmentLoginBinding - -import com.example.palto.R +import com.example.palto.ui.UserViewModel class LoginFragment : Fragment() { - private val loginViewModel: LoginViewModel by - navGraphViewModels(R.id.nav_graph) { LoginViewModelFactory() } + // loginViewModel is used to update the login screen dynamically. + private val loginViewModel: LoginViewModel by viewModels() - private var _binding: FragmentLoginBinding? = null + // userViewModel is where the user is logged in, at the activity level. + private val userViewModel: UserViewModel by activityViewModels() { UserViewModel.Factory } - // This property is only valid between onCreateView and onDestroyView. - private val binding get() = _binding!! + private lateinit var binding: FragmentLoginBinding + @SuppressLint("SetTextI18n") override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { + binding = FragmentLoginBinding.inflate(inflater, container, false) + + val navController = findNavController() + + // Bind the login button. + binding.login.setOnClickListener { + binding.loading.visibility = View.VISIBLE + userViewModel.login( + binding.hostname.text.toString(), + binding.username.text.toString(), + binding.password.text.toString() + ) + } + + // Bind anonymous login clickable text. + binding.loginAnonymous.setOnClickListener { + userViewModel.loginAnonymous() + } + + // On result of logging. + userViewModel.result.observe(viewLifecycleOwner) { + binding.loading.visibility = View.GONE + if (it.success) { + navController.popBackStack() + } else if (it.error != null) { + binding.loginError.text = "Exception : " + it.exception.toString() + Toast.makeText(activity, it.error, Toast.LENGTH_LONG).show() + } + } - _binding = FragmentLoginBinding.inflate(inflater, container, false) return binding.root } + /* override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -46,23 +72,21 @@ class LoginFragment : Fragment() { val loginButton = binding.login val loadingProgressBar = binding.loading - // - loginViewModel.loginFormState.observe(viewLifecycleOwner, - Observer { loginFormState -> - if (loginFormState == null) { - return@Observer - } - loginButton.isEnabled = loginFormState.isDataValid - loginFormState.hostnameError?.let { - hostnameEditText.error = getString(it) - } - loginFormState.usernameError?.let { - usernameEditText.error = getString(it) - } - loginFormState.passwordError?.let { - passwordEditText.error = getString(it) - } - }) + loginViewModel.loginFormState.observe(viewLifecycleOwner) { + if (it == null) { + return@Observer + } + loginButton.isEnabled = it.isDataValid + it.hostnameError?.let { + hostnameEditText.error = getString(it) + } + it.usernameError?.let { + usernameEditText.error = getString(it) + } + it.passwordError?.let { + passwordEditText.error = getString(it) + } + } loginViewModel.loginResult.observe(viewLifecycleOwner, Observer { loginResult -> @@ -103,17 +127,8 @@ class LoginFragment : Fragment() { } false } - - // Damien : Le setOnClickListener est là ! - loginButton.setOnClickListener { - loadingProgressBar.visibility = View.VISIBLE - loginViewModel.login( - hostnameEditText.text.toString(), - usernameEditText.text.toString(), - passwordEditText.text.toString() - ) - } } + */ /* private fun updateUiWithUser(model: LoggedInUserView) { @@ -122,15 +137,11 @@ class LoginFragment : Fragment() { val appContext = context?.applicationContext ?: return Toast.makeText(appContext, welcome, Toast.LENGTH_LONG).show() } - */ private fun showLoginFailed(@StringRes errorString: Int) { val appContext = context?.applicationContext ?: return Toast.makeText(appContext, errorString, Toast.LENGTH_LONG).show() } - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + */ } \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/login/LoginResult.kt b/app/src/main/java/com/example/palto/ui/login/LoginResult.kt index 9367f89..1d748f2 100644 --- a/app/src/main/java/com/example/palto/ui/login/LoginResult.kt +++ b/app/src/main/java/com/example/palto/ui/login/LoginResult.kt @@ -1,9 +1,10 @@ package com.example.palto.ui.login /** - * Authentication result : success (user details) or error message. + * Authentication result : success is true if connected or error message with exception. */ data class LoginResult( - val success: LoggedInUserView? = null, - val error: Int? = null + val success: Boolean, + val error: Int? = null, // Id of the string resource to display to the user. + val exception: Exception? = null ) \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/login/LoginViewModel.kt b/app/src/main/java/com/example/palto/ui/login/LoginViewModel.kt index 99ea964..1e79ad5 100644 --- a/app/src/main/java/com/example/palto/ui/login/LoginViewModel.kt +++ b/app/src/main/java/com/example/palto/ui/login/LoginViewModel.kt @@ -1,40 +1,14 @@ package com.example.palto.ui.login -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import android.util.Patterns -import androidx.lifecycle.ViewModelProvider -import com.example.palto.data.repository.LoginRepository -import com.example.palto.R -import com.example.palto.data.network.ServerDataSource - -class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel() { - - private val _loginForm = MutableLiveData() - val loginFormState: LiveData = _loginForm - - private val _loginResult = MutableLiveData() - val loginResult: LiveData = _loginResult - - fun login( - hostname: String, - username: String, - password: String) { - // can be launched in a separate asynchronous job - val result = loginRepository.login(hostname, username, password) - - /* - if (result is Result.Success) { - _loginResult.value = - LoginResult(success = LoggedInUserView( - displayName = result.data.displayName)) - } else { - _loginResult.value = LoginResult(error = R.string.login_failed) - } - */ - } +/** + * View Model to check dynamically the values of the form. + */ +class LoginViewModel() : ViewModel() { + /* + private val _loginFormState = MutableLiveData() + val loginFormState: LiveData = _loginFormState fun loginDataChanged( hostname: String, @@ -50,35 +24,18 @@ class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel() _loginForm.value = LoginFormState(isDataValid = true) } } - private fun isHostNameValid(hostname: String): Boolean { return hostname.isNotBlank() } - // A placeholder username validation check private fun isUserNameValid(username: String): Boolean { - return if (username.contains("@")) { - Patterns.EMAIL_ADDRESS.matcher(username).matches() - } else { - username.isNotBlank() - } + return username.isNotBlank() } - // A placeholder password validation check private fun isPasswordValid(password: String): Boolean { return password.length > 5 } + */ } -class LoginViewModelFactory : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(LoginViewModel::class.java)) { - return LoginViewModel( - loginRepository = LoginRepository( - dataSource = ServerDataSource() - ) - ) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} + diff --git a/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt b/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt index f71b3ea..dca0377 100644 --- a/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt +++ b/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt @@ -27,8 +27,20 @@ class MenuFragment : Fragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - _binding = FragmentMenuListBinding.inflate(inflater, container, false) + binding = FragmentMenuListBinding.inflate(inflater, container, false) + val navController = findNavController() + + // Connect the user. + userViewModel.user.observe(viewLifecycleOwner) { + if (it != null) { + // Get sessions of the user from remote. + } else { + navController.navigate(R.id.loginFragment) + } + } + + // Display the list of sessions. val adapter = MenuAdapter() binding.menuList.adapter = adapter menuViewModel.sessions.observe(viewLifecycleOwner) { diff --git a/app/src/main/java/com/example/palto/ui/sessionList/placeholder/PlaceholderContent.kt b/app/src/main/java/com/example/palto/ui/sessionList/placeholder/PlaceholderContent.kt deleted file mode 100644 index b085b2c..0000000 --- a/app/src/main/java/com/example/palto/ui/sessionList/placeholder/PlaceholderContent.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.example.palto.ui.sessionList.placeholder - -import java.util.ArrayList -import java.util.HashMap - -/** - * Helper class for providing sample content for user interfaces created by - * Android template wizards. - * - * TODO: Replace all uses of this class before publishing your app. - */ -object PlaceholderContent { - - /** - * An array of sample (placeholder) items. - */ - val ITEMS: MutableList = ArrayList() - - /** - * A map of sample (placeholder) items, by ID. - */ - val ITEM_MAP: MutableMap = HashMap() - - private val COUNT = 25 - - init { - // Add some sample items. - for (i in 1..COUNT) { - addItem(createPlaceholderItem(i)) - } - } - - private fun addItem(item: PlaceholderItem) { - ITEMS.add(item) - ITEM_MAP.put(item.id, item) - } - - private fun createPlaceholderItem(position: Int): PlaceholderItem { - return PlaceholderItem(position.toString(), "Item " + position, makeDetails(position)) - } - - private fun makeDetails(position: Int): String { - val builder = StringBuilder() - builder.append("Details about Item: ").append(position) - for (i in 0..position - 1) { - builder.append("\nMore details information here.") - } - return builder.toString() - } - - /** - * A placeholder item representing a piece of content. - */ - data class PlaceholderItem(val id: String, val content: String, val details: String) { - override fun toString(): String = content - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_login.xml b/app/src/main/res/layout/fragment_login.xml index 96f7159..7e7c0c7 100644 --- a/app/src/main/res/layout/fragment_login.xml +++ b/app/src/main/res/layout/fragment_login.xml @@ -13,11 +13,8 @@ @@ -77,33 +71,38 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="start" - android:layout_marginStart="48dp" - android:layout_marginTop="8dp" - android:layout_marginEnd="48dp" - android:layout_marginBottom="64dp" - android:enabled="false" + android:enabled="true" android:text="@string/action_sign_in" + app:layout_constraintBottom_toTopOf="@+id/login_anonymous" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/login_error" /> + + + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.5" /> - + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/login" /> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 70d74d8..5cb3d0d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,6 +5,7 @@ Nom d’utilisateur Mot de passe Connexion + Connexion anonyme Sign in "Bienvenue !" Serveur inaccessible diff --git a/build.gradle.kts b/build.gradle.kts index 8e8f4ab..55ea678 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.application") version "8.2.0" apply false + id("com.android.application") version "8.2.1" apply false id("org.jetbrains.kotlin.android") version "1.9.0" apply false } \ No newline at end of file From 652b46f4c585b158e1f8d49d9b26314841f98464 Mon Sep 17 00:00:00 2001 From: biloute02 Date: Fri, 12 Jan 2024 15:05:46 +0100 Subject: [PATCH 05/12] =?UTF-8?q?Ajout=20d=E2=80=99une=20toolbar.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/palto/PaltoActivity.kt | 72 ++++++++++++++----- app/src/main/res/layout/activity_palto.xml | 17 ++++- app/src/main/res/menu/palto_menu.xml | 8 +++ 3 files changed, 76 insertions(+), 21 deletions(-) create mode 100644 app/src/main/res/menu/palto_menu.xml diff --git a/app/src/main/java/com/example/palto/PaltoActivity.kt b/app/src/main/java/com/example/palto/PaltoActivity.kt index f06d427..5fb5810 100644 --- a/app/src/main/java/com/example/palto/PaltoActivity.kt +++ b/app/src/main/java/com/example/palto/PaltoActivity.kt @@ -3,8 +3,14 @@ package com.example.palto import android.nfc.NfcAdapter import android.os.Bundle import android.util.Log -import androidx.appcompat.app.AppCompatActivity +import android.view.Menu +import android.view.MenuInflater import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.ui.AppBarConfiguration +import androidx.navigation.ui.setupWithNavController +import com.example.palto.databinding.ActivityPaltoBinding import com.example.palto.ui.NfcViewModel import com.example.palto.ui.UserViewModel @@ -14,31 +20,65 @@ class PaltoActivity : AppCompatActivity() { private var nfcAdapter: NfcAdapter? = null private val nfcViewModel: NfcViewModel by viewModels() - private val userViewModel: UserViewModel by viewModels() + + private val userViewModel: UserViewModel by viewModels() { UserViewModel.Factory } + + private lateinit var binding: ActivityPaltoBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - // get the NFC Adapter - nfcAdapter = NfcAdapter.getDefaultAdapter(this) + binding = ActivityPaltoBinding.inflate(layoutInflater) + setContentView(binding.root) - // check if NFC is supported + // + // Toolbar + // + + // Set the toolbar as the app bar for the activity. + setSupportActionBar(binding.paltoToolbar) + + // Configure the app bar + val navHostFragment = + supportFragmentManager.findFragmentById(R.id.palto_nav_host_fragment) as NavHostFragment + val navController = navHostFragment.navController + val appBarConfiguration = AppBarConfiguration( + setOf( + R.id.menuFragment, R.id.loginFragment + ) + ) + binding.paltoToolbar.setupWithNavController(navController, appBarConfiguration) + + // + // NFC Adapter + // + + nfcAdapter = NfcAdapter.getDefaultAdapter(this) + // Check if NFC is supported (already checked in the app manifest). if (nfcAdapter == null) { Log.e("NFC", "NFC is not supported") - return } - - // check if NFC is disabled if (nfcAdapter?.isEnabled == false) { Log.w("NFC", "NFC is not enabled") } - - setContentView(R.layout.activity_palto) } + /** + * Specify the options menu for the Activity. + */ + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + val inflater: MenuInflater = menuInflater + inflater.inflate(R.menu.palto_menu, menu) + return true + } + + /** + * Just before the application is displayed. + */ override fun onResume() { super.onResume() + // Begin to read NFC Cards. nfcAdapter?.enableReaderMode( this, nfcViewModel.tag::postValue, @@ -47,17 +87,13 @@ class PaltoActivity : AppCompatActivity() { ) } + /** + * Just after the application has been quit. + */ override fun onPause() { super.onPause() - // disable the NFC discovery + // Disable the NFC discovery. nfcAdapter?.disableReaderMode(this) } - - /* - @OptIn(ExperimentalStdlibApi::class) - fun processTag(tag: Tag) { - Log.d("NFC", "Tag ID : " + tag.id.toHexString()) - } - */ } diff --git a/app/src/main/res/layout/activity_palto.xml b/app/src/main/res/layout/activity_palto.xml index 3a70781..d91176c 100644 --- a/app/src/main/res/layout/activity_palto.xml +++ b/app/src/main/res/layout/activity_palto.xml @@ -1,12 +1,22 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/menu/palto_menu.xml b/app/src/main/res/menu/palto_menu.xml new file mode 100644 index 0000000..a50a1a6 --- /dev/null +++ b/app/src/main/res/menu/palto_menu.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file From 035030ca0f92c4d2fff8817fd7a59a5a0148ffdd Mon Sep 17 00:00:00 2001 From: biloute02 Date: Fri, 12 Jan 2024 15:07:43 +0100 Subject: [PATCH 06/12] =?UTF-8?q?Compl=C3=A9tion=20du=20fragment=20menu=20?= =?UTF-8?q?:=20afficher,=20cr=C3=A9er=20et=20cliquer=20une=20fiche=20d?= =?UTF-8?q?=E2=80=99=C3=A9margement.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/palto/domain/Session.kt | 4 +- .../com/example/palto/ui/menu/MenuAdapter.kt | 44 ++++++++++--------- .../com/example/palto/ui/menu/MenuFragment.kt | 26 ++++++++--- .../example/palto/ui/menu/MenuViewModel.kt | 26 ++++++++--- .../main/res/layout/fragment_menu_item.xml | 10 ++++- .../main/res/layout/fragment_menu_list.xml | 1 + .../main/res/layout/fragment_new_session.xml | 33 ++++++++++++++ app/src/main/res/navigation/nav_graph.xml | 38 ++++++++++------ app/src/main/res/values/strings.xml | 4 ++ 9 files changed, 138 insertions(+), 48 deletions(-) create mode 100644 app/src/main/res/layout/fragment_new_session.xml diff --git a/app/src/main/java/com/example/palto/domain/Session.kt b/app/src/main/java/com/example/palto/domain/Session.kt index fef790f..e574b59 100644 --- a/app/src/main/java/com/example/palto/domain/Session.kt +++ b/app/src/main/java/com/example/palto/domain/Session.kt @@ -5,5 +5,7 @@ import java.io.Serializable * Data class that captures tokens for logged in users retrieved from LoginRepository */ data class Session( - val id: String + val id: Int, + val name: String, + var attendances: List ) \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt b/app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt index d56a5ed..518c04f 100644 --- a/app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt +++ b/app/src/main/java/com/example/palto/ui/menu/MenuAdapter.kt @@ -12,35 +12,39 @@ import com.example.palto.domain.Session /** * A [ListAdapter] that can display [Session] items. */ -class MenuAdapter : +class MenuAdapter(private val onClick: (Session) -> Unit) : ListAdapter(SessionDiffCallback) { + inner class ViewHolder(binding: FragmentMenuItemBinding) : + RecyclerView.ViewHolder(binding.root) { + private val sessionNameText: TextView = binding.sessionName + private var currentSession: Session? = null + + init { + binding.root.setOnClickListener { + currentSession?.let { + onClick(it) + } + } + } + + fun bind(session: Session) { + currentSession = session + sessionNameText.text = session.name + } + } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - return ViewHolder( - FragmentMenuItemBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false - ) - ) + val binding = FragmentMenuItemBinding + .inflate(LayoutInflater.from(parent.context), parent, false) + return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = getItem(position) - holder.sessionId.text = item.id + holder.bind(item) } - inner class ViewHolder( - binding: FragmentMenuItemBinding - ) : RecyclerView.ViewHolder(binding.root) { - - val sessionId: TextView = binding.sessionId - override fun toString(): String { - return super.toString() + " '" + sessionId.text + "'" - } - } - - //override fun getItemCount(): Int = values.size + override fun getItemCount() = currentList.size } object SessionDiffCallback : DiffUtil.ItemCallback() { diff --git a/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt b/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt index dca0377..6aceecc 100644 --- a/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt +++ b/app/src/main/java/com/example/palto/ui/menu/MenuFragment.kt @@ -4,11 +4,15 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.os.bundleOf import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.navGraphViewModels import com.example.palto.R import com.example.palto.databinding.FragmentMenuListBinding +import com.example.palto.domain.Session +import com.example.palto.ui.UserViewModel /** * A fragment representing a list of Sessions. @@ -16,11 +20,13 @@ import com.example.palto.databinding.FragmentMenuListBinding class MenuFragment : Fragment() { private val menuViewModel: MenuViewModel by - navGraphViewModels(R.id.nav_graph) + navGraphViewModels(R.id.nav_graph) { MenuViewModel.Factory } + + private val userViewModel: UserViewModel by + activityViewModels() { UserViewModel.Factory } - private var _binding: FragmentMenuListBinding? = null // This property is only valid between onCreateView and onDestroyView - private val binding get() = _binding!! + private lateinit var binding: FragmentMenuListBinding override fun onCreateView( inflater: LayoutInflater, @@ -41,17 +47,25 @@ class MenuFragment : Fragment() { } // Display the list of sessions. - val adapter = MenuAdapter() + + // Create a new MenuAdapter (list) with the given function when clicking an item. + val adapter = MenuAdapter { adapterOnClick(it) } binding.menuList.adapter = adapter + // Link the adapter with the session list in the menuViewMode. menuViewModel.sessions.observe(viewLifecycleOwner) { adapter.submitList(it) } + // Bind the add button. binding.createSession.setOnClickListener { - menuViewModel.createSession() - findNavController().navigate(R.id.action_menuFragment_to_sessionFragment) + navController.navigate(R.id.action_menuFragment_to_newSessionFragment) } return binding.root } + + private fun adapterOnClick(session: Session) { + val bundle = bundleOf("session" to session.id) + findNavController().navigate(R.id.action_menuFragment_to_sessionFragment, bundle) + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt b/app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt index 859198b..b67bd65 100644 --- a/app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt +++ b/app/src/main/java/com/example/palto/ui/menu/MenuViewModel.kt @@ -4,18 +4,34 @@ import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.example.palto.data.repository.TokenRepository +import com.example.palto.data.repository.UserRepository import com.example.palto.domain.Session +import com.example.palto.ui.UserViewModel class MenuViewModel() : ViewModel() { private var _sessions = MutableLiveData>(emptyList()) - val sessions = _sessions as LiveData> + val sessions: LiveData> = _sessions - fun createSession() { + fun createSession(name: String) { + val list = _sessions.value ?: emptyList() val session = Session( - id = "aahh" + id = list.size, + name = name, + attendances = emptyList() ) - _sessions.value = (_sessions.value ?: emptyList()) + session - Log.d("PALTO", "MenuViewModel: a session has been added into the list.") + _sessions.value = list + session + Log.d("Palto", "MenuViewModel: A session has been added into the list.") + } + + companion object { + + val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + return MenuViewModel() as T + } + } } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_menu_item.xml b/app/src/main/res/layout/fragment_menu_item.xml index dd0594e..92c931f 100644 --- a/app/src/main/res/layout/fragment_menu_item.xml +++ b/app/src/main/res/layout/fragment_menu_item.xml @@ -4,11 +4,17 @@ android:layout_height="wrap_content" android:orientation="horizontal"> - + android:textAppearance="?attr/textAppearanceListItem" />--> + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_menu_list.xml b/app/src/main/res/layout/fragment_menu_list.xml index 992f5ff..645676c 100644 --- a/app/src/main/res/layout/fragment_menu_list.xml +++ b/app/src/main/res/layout/fragment_menu_list.xml @@ -21,6 +21,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" + android:layout_margin="16dp" android:clickable="true" android:contentDescription="@string/create_session" app:srcCompat="@android:drawable/ic_input_add" /> diff --git a/app/src/main/res/layout/fragment_new_session.xml b/app/src/main/res/layout/fragment_new_session.xml new file mode 100644 index 0000000..d419ed9 --- /dev/null +++ b/app/src/main/res/layout/fragment_new_session.xml @@ -0,0 +1,33 @@ + + + + + +