From 53a54dcc348aeec637f371836dec69b5ef37b4e4 Mon Sep 17 00:00:00 2001 From: Ryan <102423466+50t0r25@users.noreply.github.com> Date: Sat, 14 May 2022 05:42:51 +0100 Subject: [PATCH] Mfw 5am commits: Added delay report system Users can report bus delays or cancel their reported delay Reports automatically get cleared everyday Bumped version --- app/build.gradle | 4 +- .../dz/notacompany/el_cous/DetailsFragment.kt | 140 +++++++++++++++++- .../dz/notacompany/el_cous/MainActivity.kt | 2 +- .../dz/notacompany/el_cous/ScheduleItem.kt | 4 +- .../notacompany/el_cous/SchedulesAdapter.kt | 13 +- app/src/main/res/layout/item_schedule.xml | 24 ++- app/src/main/res/values/strings.xml | 4 + 7 files changed, 176 insertions(+), 15 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7ea07a6..8d2b5ef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "dz.notacompany.el_cous" minSdk 21 targetSdk 32 - versionCode 1 - versionName '0.1' + versionCode 2 + versionName '0.9' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/dz/notacompany/el_cous/DetailsFragment.kt b/app/src/main/java/dz/notacompany/el_cous/DetailsFragment.kt index 37e037c..3a8a2ce 100644 --- a/app/src/main/java/dz/notacompany/el_cous/DetailsFragment.kt +++ b/app/src/main/java/dz/notacompany/el_cous/DetailsFragment.kt @@ -2,18 +2,26 @@ package dz.notacompany.el_cous import android.os.Bundle import android.view.View +import android.widget.TextView import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.auth.ktx.auth import com.google.firebase.firestore.QueryDocumentSnapshot +import com.google.firebase.firestore.SetOptions import com.google.firebase.firestore.Source import com.google.firebase.firestore.ktx.firestore import com.google.firebase.ktx.Firebase import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.fragment_details.* +import java.util.* +import kotlin.collections.ArrayList class DetailsFragment(private val documentID : String) : Fragment(R.layout.fragment_details) { private val db = Firebase.firestore + private lateinit var auth: FirebaseAuth private lateinit var mainAct : MainActivity private lateinit var source: Source @@ -21,6 +29,8 @@ class DetailsFragment(private val documentID : String) : Fragment(R.layout.fragm override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + auth = Firebase.auth + mainAct = activity as MainActivity // Reference to MainActivity mainAct.currentDocument = documentID // Used to delete Routes if admin is user @@ -34,6 +44,98 @@ class DetailsFragment(private val documentID : String) : Fragment(R.layout.fragm val schedulesList = mutableListOf() + // Function will be passed to the adapter to run stuff that can't be run inside it otherwise + fun onScheduleClick(position : Int, textView : TextView) { + + var dialogMessage = getString(R.string.add_report) + var isRemoving = false + if (schedulesList[position].userHasReported) { + dialogMessage = getString(R.string.remove_report) + isRemoving = true + } + + MaterialAlertDialogBuilder(requireContext()) + .setTitle(getString(R.string.confirm)) + .setMessage(dialogMessage) + .setNeutralButton(getString(R.string.cancel)) { dialog, _ -> + dialog.dismiss() + } + .setPositiveButton(getString(R.string.confirm)) { dialog, _ -> + dialog.dismiss() + + val scheduleRef = db.collection("trajets").document(documentID).collection("horaires").document(schedulesList[position].itemID) + var reportsSize = 0 + + if (isRemoving) { + + db.runTransaction { transaction -> + val thisSchedule = transaction.get(scheduleRef) + var newReports : ArrayList? = arrayListOf() + + val reports = thisSchedule.data?.get("retards") as ArrayList? + + reports?.let { newReports!!.addAll(it) } + newReports!!.remove(auth.uid.toString()) + + reportsSize = newReports.size + + val cal = Calendar.getInstance() + var newDate : String? = "${cal.get(Calendar.MONTH)}/${cal.get(Calendar.DAY_OF_MONTH)}" + + if (newReports.size == 0) { + newReports = null + newDate = null + } + + val newData = hashMapOf( + "retards" to newReports, + "lastReport" to newDate + ) + + transaction.set(scheduleRef, newData, SetOptions.merge()) + + null + }.addOnSuccessListener { + textView.visibility = View.VISIBLE + schedulesList[position].userHasReported = false + textView.text = "${getString(R.string.reported_delays0)} $reportsSize ${getString(R.string.reported_delays1)}" + if (reportsSize == 0) textView.visibility = View.GONE + } + + } else { + + db.runTransaction { transaction -> + val thisSchedule = transaction.get(scheduleRef) + val newReports : ArrayList = arrayListOf() + + val reports = thisSchedule.data?.get("retards") as ArrayList? + + reports?.let { newReports.addAll(it) } + newReports.add(auth.uid.toString()) + + reportsSize = newReports.size + + val cal = Calendar.getInstance() + + val newData = hashMapOf( + "retards" to newReports, + "lastReport" to "${cal.get(Calendar.MONTH)}/${cal.get(Calendar.DAY_OF_MONTH)}" + ) + + transaction.set(scheduleRef, newData, SetOptions.merge()) + + null + }.addOnSuccessListener { + textView.visibility = View.VISIBLE + schedulesList[position].userHasReported = true + textView.text = "${getString(R.string.reported_delays0)} $reportsSize ${getString(R.string.reported_delays1)}" + } + + } + } + .show() + } + mainAct.createLoadingDialog() // If user doesn't have internet access, fetch data from cache @@ -50,14 +152,34 @@ class DetailsFragment(private val documentID : String) : Fragment(R.layout.fragm db.collection("trajets").document(documentID).collection("horaires").get(source) .addOnSuccessListener { horaires -> - // Adds each Schudule object from the DB to our list + // Adds each schedule object from the DB to our list for (horaire in horaires) { - addScheduleToList(horaire,schedulesList) + + val cal = Calendar.getInstance() + val currentDate = "${cal.get(Calendar.MONTH)}/${cal.get(Calendar.DAY_OF_MONTH)}" + + if (horaire.data["lastReport"] != null && horaire.data["lastReport"].toString() != currentDate) { + db.runBatch { batch -> + + val horaireRef = db.collection("trajets").document(documentID).collection("horaires").document(horaire.id) + val newData = hashMapOf( + "lastReport" to null, + "retards" to null + ) + batch.set(horaireRef, newData, SetOptions.merge()) + + addScheduleToList(horaire,schedulesList,true) + } + } else { + addScheduleToList(horaire,schedulesList,false) + } + + } schedulesList.sortBy { it.itemOrder } // Sorts the list by the itemOrder variable // Initializes the RecyclerView with the adapter - schedulesRecyclerView.adapter = SchedulesAdapter(schedulesList) + schedulesRecyclerView.adapter = SchedulesAdapter(requireContext(), schedulesList, { position, textView -> onScheduleClick(position, textView)}) schedulesRecyclerView.layoutManager = LinearLayoutManager(context) mainAct.dismissLoadingDialog() @@ -67,12 +189,20 @@ class DetailsFragment(private val documentID : String) : Fragment(R.layout.fragm } // Function adds a schedule from the received object from the DB to a list of ScheduleItem - private fun addScheduleToList(horaire: QueryDocumentSnapshot, list: MutableList) { + private fun addScheduleToList(horaire: QueryDocumentSnapshot, list: MutableList, gotCleared : Boolean) { val id = horaire.id val order = horaire.data["ordre"].toString().toInt() val departure = horaire.data["depart"].toString() val arrival = horaire.data["arrive"].toString() - list.add(ScheduleItem(id,order,departure,arrival)) + val retards = horaire.data["retards"] as ArrayList? + var delays = 0 + var userHasReported = false + if (retards != null && !gotCleared) { + delays = retards.size + if (retards.contains(auth.uid.toString())) userHasReported = true + } + + list.add(ScheduleItem(id,order,departure,arrival,delays,userHasReported)) } } \ No newline at end of file diff --git a/app/src/main/java/dz/notacompany/el_cous/MainActivity.kt b/app/src/main/java/dz/notacompany/el_cous/MainActivity.kt index 5535850..88ea3d2 100644 --- a/app/src/main/java/dz/notacompany/el_cous/MainActivity.kt +++ b/app/src/main/java/dz/notacompany/el_cous/MainActivity.kt @@ -77,7 +77,7 @@ class MainActivity : AppCompatActivity() { MaterialAlertDialogBuilder(this) .setTitle(getString(R.string.caution)) .setMessage(getString(R.string.delete_route)) - .setNeutralButton("Cancel") { dialog, _ -> + .setNeutralButton(getString(R.string.cancel)) { dialog, _ -> dialog.dismiss() } .setPositiveButton(getString(R.string.confirm)) { dialog, _ -> diff --git a/app/src/main/java/dz/notacompany/el_cous/ScheduleItem.kt b/app/src/main/java/dz/notacompany/el_cous/ScheduleItem.kt index 5992fb0..3be731e 100644 --- a/app/src/main/java/dz/notacompany/el_cous/ScheduleItem.kt +++ b/app/src/main/java/dz/notacompany/el_cous/ScheduleItem.kt @@ -4,5 +4,7 @@ data class ScheduleItem( val itemID : String, val itemOrder : Int, val scheduleDepartureTime : String, - val scheduleArrivalTime : String + val scheduleArrivalTime : String, + val delays : Int, + var userHasReported : Boolean ) \ No newline at end of file diff --git a/app/src/main/java/dz/notacompany/el_cous/SchedulesAdapter.kt b/app/src/main/java/dz/notacompany/el_cous/SchedulesAdapter.kt index fb4584f..fee4638 100644 --- a/app/src/main/java/dz/notacompany/el_cous/SchedulesAdapter.kt +++ b/app/src/main/java/dz/notacompany/el_cous/SchedulesAdapter.kt @@ -1,11 +1,14 @@ package dz.notacompany.el_cous +import android.content.Context import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup +import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import dz.notacompany.el_cous.databinding.ItemScheduleBinding -class SchedulesAdapter(var schedulesList: List) : RecyclerView.Adapter() { +class SchedulesAdapter(private val context : Context, private var schedulesList: List, private val onScheduleClick : (position : Int, textView : TextView) -> Unit) : RecyclerView.Adapter() { inner class SchedulesViewHolder(val binding: ItemScheduleBinding) : RecyclerView.ViewHolder(binding.root) @@ -19,6 +22,14 @@ class SchedulesAdapter(var schedulesList: List) : RecyclerView.Ada override fun onBindViewHolder(holder: SchedulesViewHolder, position: Int) { holder.binding.apply { + itemTripCard.setOnClickListener { + onScheduleClick(position, delaysTextView) + } + + if (schedulesList[position].delays != 0) { + delaysTextView.visibility = View.VISIBLE //${schedulesList[position].delays} + delaysTextView.text = "${context.getString(R.string.reported_delays0)} ${schedulesList[position].delays} ${context.getString(R.string.reported_delays1)}" + } cousNumberTextView.text = "Cous N°".plus(schedulesList[position].itemOrder) departureTimeTextView.text = schedulesList[position].scheduleDepartureTime arrivalTimeTextView.text = schedulesList[position].scheduleArrivalTime diff --git a/app/src/main/res/layout/item_schedule.xml b/app/src/main/res/layout/item_schedule.xml index 2a0a0b2..096c68f 100644 --- a/app/src/main/res/layout/item_schedule.xml +++ b/app/src/main/res/layout/item_schedule.xml @@ -12,7 +12,6 @@ android:clickable="true" android:focusable="true" app:cardCornerRadius="20dp" - app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -39,24 +38,24 @@ android:layout_height="match_parent" android:layout_marginStart="10dp" android:layout_marginEnd="5dp" - app:layout_constraintHorizontal_weight="1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/cousNumberTextView" + app:layout_constraintHorizontal_weight="1" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:srcCompat="@drawable/bus"/> + app:srcCompat="@drawable/bus" /> @@ -131,4 +130,19 @@ + + \ 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 78786a6..96b619b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -25,4 +25,8 @@ Annuler Avertissement Êtes-vous sûr de vouloir definitivement supprimer ce trajet? + Retard signalé par + étudiant(s) aujourdhui + Êtes-vous sûr de vouloir signaler un retard pour cet horaire? + Êtes-vous sûr de vouloir annuler votre signalement de retard pour cet horaire? \ No newline at end of file