Ajout de deux packages pour une liste de Sessions et une liste d’Attendances.

Pourra changer dans le futur
Correction du code pour qu’il puisse compiler.
This commit is contained in:
biloute02 2023-12-22 11:01:03 +01:00
parent a856513920
commit 1c04f18ec8
24 changed files with 368 additions and 144 deletions

View file

@ -8,7 +8,7 @@ import java.io.IOException
* Class that handles authentication w/ login credentials and retrieves user information. * Class that handles authentication w/ login credentials and retrieves user information.
*/ */
class LocalDataSource { class LocalDataSource {
/*
fun login(username: String, password: String): Result<LoggedInUser> { fun login(username: String, password: String): Result<LoggedInUser> {
try { try {
@ -24,4 +24,5 @@ class LocalDataSource {
fun logout() { fun logout() {
// TODO: revoke authentication // TODO: revoke authentication
} }
*/
} }

View file

@ -0,0 +1,10 @@
package com.example.palto.data.model
import java.io.Serializable
/**
* Data class that captures tokens for logged in users retrieved from LoginRepository
*/
data class Attendance(
val date: String,
val access: String
) : Serializable

View file

@ -0,0 +1,9 @@
package com.example.palto.data.model
import java.io.Serializable
/**
* Data class that captures tokens for logged in users retrieved from LoginRepository
*/
data class StudentCard(
val id: String
) : Serializable

View file

@ -12,36 +12,48 @@ class ServerDataSource {
private var hostname: String? = null private var hostname: String? = null
fun requestToken(hostname: String, username: String, password: String): Result<Tokens> { fun requestToken(
hostname: String,
username: String,
password: String
): Result<Tokens> {
try { try {
val tokens = Tokens() val tokens = Tokens(
return Result.Success() refresh = "aa",
} catch () { access = "bb"
return Result.Error() )
} return Result.Success(tokens)
}
fun refreshToken(): Result<Tokens> {
}
fun verifyToken(): Boolean {
}
fun login(hostname: String, username: String, password: String): Result<LoggedInUser> {
try {
/*
val fakeUser = LoggedInUser(java.util.UUID.randomUUID().toString(), "Jane Doe")
return Result.Success(fakeUser)
*/
return
} catch (e: Throwable) { } catch (e: Throwable) {
return Result.Error(IOException("Error logging in", e)) return Result.Error(IOException("Error logging in", e))
} }
} }
fun logout() { fun refreshToken(current_tokens: Tokens): Result<Tokens> {
// TODO: revoke authentication return Result.Success(current_tokens)
} }
fun verifyToken(): Boolean {
return true
}
fun login(
hostname: String,
username: String,
password: String
): Result<LoggedInUser> {
try {
val fakeUser = LoggedInUser(
java.util.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() { }
} }

View file

@ -0,0 +1,13 @@
package com.example.palto.data.repository
import com.example.palto.data.Result
import com.example.palto.data.network.ServerDataSource
import com.example.palto.data.model.LoggedInUser
import com.example.palto.data.model.Tokens
/**
*
*/
class AttendanceRepository(val dataSource: ServerDataSource) {
// private val cards
}

View file

@ -19,8 +19,6 @@ class LoginRepository(val dataSource: ServerDataSource) {
get() = user != null get() = user != null
init { init {
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
user = null user = null
} }
@ -38,7 +36,7 @@ class LoginRepository(val dataSource: ServerDataSource) {
val result = dataSource.login(hostname, username, password) val result = dataSource.login(hostname, username, password)
if (result is Result.Success) { if (result is Result.Success) {
setTokens(result.data) setLoggedInUser(result.data)
} }
return result return result
@ -46,7 +44,5 @@ class LoginRepository(val dataSource: ServerDataSource) {
private fun setLoggedInUser(loggedInUser: LoggedInUser) { private fun setLoggedInUser(loggedInUser: LoggedInUser) {
this.user = loggedInUser this.user = loggedInUser
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
} }
} }

View file

@ -1,33 +1,30 @@
package com.example.palto.ui.session package com.example.palto.ui.attendanceList
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import com.example.palto.R
import com.example.palto.ui.session.placeholder.PlaceholderContent.PlaceholderItem import com.example.palto.ui.attendanceList.placeholder.PlaceholderContent.PlaceholderItem
import com.example.palto.databinding.FragmentAttendanceBinding import com.example.palto.databinding.FragmentAttendanceItemBinding
/** /**
* [RecyclerView.Adapter] that can display a [PlaceholderItem]. * [RecyclerView.Adapter] that can display a [PlaceholderItem].
* TODO: Replace the implementation with code for your data type. * TODO: Replace the implementation with code for your data type.
*/ */
class MyAttendanceRecyclerViewAdapter( class AttendanceListAdapter(
private val values: List<PlaceholderItem> private val values: List<PlaceholderItem>
) : RecyclerView.Adapter<MyAttendanceRecyclerViewAdapter.ViewHolder>() { ) : RecyclerView.Adapter<AttendanceListAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder( return ViewHolder(
FragmentAttendanceBinding.inflate( FragmentAttendanceItemBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
) )
) )
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@ -38,7 +35,7 @@ class MyAttendanceRecyclerViewAdapter(
override fun getItemCount(): Int = values.size override fun getItemCount(): Int = values.size
inner class ViewHolder(binding: FragmentAttendanceBinding) : inner class ViewHolder(binding: FragmentAttendanceItemBinding) :
RecyclerView.ViewHolder(binding.root) { RecyclerView.ViewHolder(binding.root) {
val idView: TextView = binding.itemNumber val idView: TextView = binding.itemNumber
val contentView: TextView = binding.content val contentView: TextView = binding.content
@ -47,5 +44,4 @@ class MyAttendanceRecyclerViewAdapter(
return super.toString() + " '" + contentView.text + "'" return super.toString() + " '" + contentView.text + "'"
} }
} }
} }

View file

@ -0,0 +1,33 @@
package com.example.palto.ui.attendanceList
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 androidx.navigation.navGraphViewModels
import com.example.palto.R
import com.example.palto.ui.attendanceList.placeholder.PlaceholderContent
/**
* A fragment representing a list of attendances.
*/
class AttendanceListFragment : Fragment() {
private val attendanceListViewModel: AttendanceListViewModel by
navGraphViewModels(R.id.nav_graph)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_attendance_list, container, false)
if (view is RecyclerView) {
view.layoutManager = LinearLayoutManager(context)
view.adapter = AttendanceListAdapter(PlaceholderContent.ITEMS)
}
return view
}
}

View file

@ -0,0 +1,34 @@
package com.example.palto.ui.attendanceList
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.data.repository.LoginRepository
class AttendanceListViewModel(
private val attendanceRepository: AttendanceRepository
) : ViewModel() {
/*
private val _loginForm = MutableLiveData<LoginFormState>()
val loginFormState: LiveData<LoginFormState> = _loginForm
private val _loginResult = MutableLiveData<LoginResult>()
val loginResult: LiveData<LoginResult> = _loginResult
*/
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()
)
) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
}

View file

@ -0,0 +1,57 @@
package com.example.palto.ui.attendanceList.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<PlaceholderItem> = ArrayList()
/**
* A map of sample (placeholder) items, by ID.
*/
val ITEM_MAP: MutableMap<String, PlaceholderItem> = 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
}
}

View file

@ -1,9 +1,13 @@
package com.example.palto.ui.login package com.example.palto.ui.login
/* Est-ce que cest util ?
* Updater la vue dans le fragment
*/
/** /**
* User details post authentication that is exposed to the UI * User details post authentication that is exposed to the UI
*/ */
data class LoggedInUserView( data class LoggedInUserView(
val displayName: String val displayName: String
//... other data fields that may be accessible to the UI //... other data fields that may be accessible to the UI
) )

View file

@ -1,7 +1,6 @@
package com.example.palto.ui.login package com.example.palto.ui.login
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import android.os.Bundle import android.os.Bundle
@ -11,9 +10,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.Button
import android.widget.EditText
import android.widget.ProgressBar
import android.widget.Toast import android.widget.Toast
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.navGraphViewModels import androidx.navigation.navGraphViewModels
@ -24,7 +20,7 @@ import com.example.palto.R
class LoginFragment : Fragment() { class LoginFragment : Fragment() {
private val loginViewModel: LoginViewModel by private val loginViewModel: LoginViewModel by
navGraphViewModels (R.id.nav_graph) { LoginViewModelFactory() } navGraphViewModels(R.id.nav_graph) { LoginViewModelFactory() }
private var _binding: FragmentLoginBinding? = null private var _binding: FragmentLoginBinding? = null

View file

@ -4,10 +4,12 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import android.util.Patterns import android.util.Patterns
import androidx.lifecycle.ViewModelProvider
import com.example.palto.data.repository.LoginRepository import com.example.palto.data.repository.LoginRepository
import com.example.palto.data.Result import com.example.palto.data.Result
import com.example.palto.R import com.example.palto.R
import com.example.palto.data.network.ServerDataSource
class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel() { class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel() {
@ -22,14 +24,17 @@ class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel()
username: String, username: String,
password: String) { password: String) {
// can be launched in a separate asynchronous job // can be launched in a separate asynchronous job
val result = loginRepository.login(username, password) val result = loginRepository.login(hostname, username, password)
/*
if (result is Result.Success) { if (result is Result.Success) {
_loginResult.value = _loginResult.value =
LoginResult(success = LoggedInUserView(displayName = result.data.displayName)) LoginResult(success = LoggedInUserView(
displayName = result.data.displayName))
} else { } else {
_loginResult.value = LoginResult(error = R.string.login_failed) _loginResult.value = LoginResult(error = R.string.login_failed)
} }
*/
} }
fun loginDataChanged( fun loginDataChanged(
@ -64,4 +69,17 @@ class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel()
private fun isPasswordValid(password: String): Boolean { private fun isPasswordValid(password: String): Boolean {
return password.length > 5 return password.length > 5
} }
} }
class LoginViewModelFactory : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
return LoginViewModel(
loginRepository = LoginRepository(
dataSource = ServerDataSource()
)
) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}

View file

@ -1,25 +0,0 @@
package com.example.palto.ui.login
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.palto.data.network.ServerDataSource
import com.example.palto.data.repository.LoginRepository
/**
* ViewModel provider factory to instantiate LoginViewModel.
* Required given LoginViewModel has a non-empty constructor
*/
class LoginViewModelFactory : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
return LoginViewModel(
loginRepository = LoginRepository(
dataSource = ServerDataSource()
)
) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}

View file

@ -1,63 +0,0 @@
package com.example.palto.ui.session
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
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.session.placeholder.PlaceholderContent
/**
* A fragment representing a list of Items.
*/
class AttendanceListFragment : Fragment() {
private var columnCount = 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
columnCount = it.getInt(ARG_COLUMN_COUNT)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_attendance_list, container, false)
// Set the adapter
if (view is RecyclerView) {
with(view) {
layoutManager = when {
columnCount <= 1 -> LinearLayoutManager(context)
else -> GridLayoutManager(context, columnCount)
}
adapter = MyAttendanceRecyclerViewAdapter(PlaceholderContent.ITEMS)
}
}
return view
}
companion object {
// TODO: Customize parameter argument names
const val ARG_COLUMN_COUNT = "column-count"
// TODO: Customize parameter initialization
@JvmStatic
fun newInstance(columnCount: Int) =
AttendanceListFragment().apply {
arguments = Bundle().apply {
putInt(ARG_COLUMN_COUNT, columnCount)
}
}
}
}

View file

@ -0,0 +1,44 @@
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<PlaceholderItem>) :
RecyclerView.Adapter<SessionListAdapter.ViewHolder>() {
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
}

View file

@ -0,0 +1,31 @@
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
}
}

View file

@ -0,0 +1,20 @@
package com.example.palto.ui.sessionList
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import android.util.Patterns
import com.example.palto.data.repository.LoginRepository
import com.example.palto.data.Result
import com.example.palto.R
class SessionListViewModel(private val loginRepository: LoginRepository) : ViewModel() {
/*
private val _loginForm = MutableLiveData<LoginFormState>()
val loginFormState: LiveData<LoginFormState> = _loginForm
private val _loginResult = MutableLiveData<LoginResult>()
val loginResult: LiveData<LoginResult> = _loginResult
*/
}

View file

@ -1,4 +1,4 @@
package com.example.palto.ui.session.placeholder package com.example.palto.ui.sessionList.placeholder
import java.util.ArrayList import java.util.ArrayList
import java.util.HashMap import java.util.HashMap

View file

@ -3,11 +3,11 @@
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/list" android:id="@+id/list"
android:name="com.example.palto.ui.session.AttendanceFragment" android:name="com.example.palto.ui.attendanceList.AttendanceFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager" app:layoutManager="LinearLayoutManager"
tools:context=".ui.session.AttendanceListFragment" tools:context=".ui.attendanceList.AttendanceListFragment"
tools:listitem="@layout/fragment_attendance" /> tools:listitem="@layout/fragment_attendance_item" />

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/item_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
</LinearLayout>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list"
android:name="com.example.palto.ui.session.SessionListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context=".ui.sessionList.SessionListFragment"
tools:listitem="@layout/fragment_session_item" />

View file

@ -13,9 +13,14 @@
android:id="@+id/action_loginFragment_to_attendanceFragment" android:id="@+id/action_loginFragment_to_attendanceFragment"
app:destination="@id/attendanceFragment" /> app:destination="@id/attendanceFragment" />
</fragment> </fragment>
<fragment
android:id="@+id/sessionListFragment"
android:name="com.example.palto.ui.sessionList.SessionListFragment"
android:label="fragment_session_list"
tools:layout="@layout/fragment_session_list" />
<fragment <fragment
android:id="@+id/attendanceFragment" android:id="@+id/attendanceFragment"
android:name="com.example.palto.ui.session.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" />
</navigation> </navigation>