From 5097f11c5981d2ced92ffb3bd11592601901fea3 Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Mon, 9 Jan 2023 23:02:17 +0100 Subject: [PATCH] :dog: --- .../main/java/fr/uca/iut/myouafff/data/Dog.kt | 2 +- .../myouafff/ui/activity/DogListActivity.kt | 69 +++++++- .../myouafff/ui/activity/DogPagerActivity.kt | 50 +++++- .../iut/myouafff/ui/fragment/DogFragment.kt | 2 +- .../myouafff/ui/fragment/DogListFragment.kt | 133 ++++++++++++++++ .../iut/myouafff/ui/utils/DogPagerAdapter.kt | 16 ++ .../ui/utils/DogRecyclerViewAdapter.kt | 63 ++++++++ .../toolbar_md_activity_content.xml | 22 +++ app/src/main/res/layout/activity_pager.xml | 19 +++ app/src/main/res/layout/dialog_date.xml | 1 - app/src/main/res/layout/fragment_dog.xml | 149 ++++++++++++++++++ app/src/main/res/layout/fragment_list_dog.xml | 67 ++++++++ app/src/main/res/layout/item_list_dog.xml | 35 ++++ app/src/main/res/layout/toolbar_activity.xml | 25 +++ .../main/res/layout/toolbar_md_activity.xml | 22 +++ .../layout/toolbar_md_activity_content.xml | 4 + app/src/main/res/menu/fragment_dog.xml | 15 ++ app/src/main/res/menu/fragment_list_dog.xml | 11 ++ app/src/main/res/values-fr/strings.xml | 42 +++++ app/src/main/res/values/arrays.xml | 16 ++ app/src/main/res/values/ids.xml | 4 + app/src/main/res/values/strings.xml | 40 ++++- 22 files changed, 800 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/fr/uca/iut/myouafff/ui/fragment/DogListFragment.kt create mode 100644 app/src/main/java/fr/uca/iut/myouafff/ui/utils/DogPagerAdapter.kt create mode 100644 app/src/main/java/fr/uca/iut/myouafff/ui/utils/DogRecyclerViewAdapter.kt create mode 100644 app/src/main/res/layout-land/toolbar_md_activity_content.xml create mode 100644 app/src/main/res/layout/activity_pager.xml create mode 100644 app/src/main/res/layout/fragment_dog.xml create mode 100644 app/src/main/res/layout/fragment_list_dog.xml create mode 100644 app/src/main/res/layout/item_list_dog.xml create mode 100644 app/src/main/res/layout/toolbar_activity.xml create mode 100644 app/src/main/res/layout/toolbar_md_activity.xml create mode 100644 app/src/main/res/layout/toolbar_md_activity_content.xml create mode 100644 app/src/main/res/menu/fragment_dog.xml create mode 100644 app/src/main/res/menu/fragment_list_dog.xml create mode 100644 app/src/main/res/values-fr/strings.xml create mode 100644 app/src/main/res/values/arrays.xml create mode 100644 app/src/main/res/values/ids.xml diff --git a/app/src/main/java/fr/uca/iut/myouafff/data/Dog.kt b/app/src/main/java/fr/uca/iut/myouafff/data/Dog.kt index c3f02a8..31aa3f7 100644 --- a/app/src/main/java/fr/uca/iut/myouafff/data/Dog.kt +++ b/app/src/main/java/fr/uca/iut/myouafff/data/Dog.kt @@ -4,7 +4,7 @@ import androidx.room.Entity import androidx.room.PrimaryKey import java.util.* -const val NEW_DOG_ID = 1337L +const val NEW_DOG_ID = 0L @Entity(tableName = "dogs") class Dog( diff --git a/app/src/main/java/fr/uca/iut/myouafff/ui/activity/DogListActivity.kt b/app/src/main/java/fr/uca/iut/myouafff/ui/activity/DogListActivity.kt index 2ee4aac..a25c52d 100644 --- a/app/src/main/java/fr/uca/iut/myouafff/ui/activity/DogListActivity.kt +++ b/app/src/main/java/fr/uca/iut/myouafff/ui/activity/DogListActivity.kt @@ -1,4 +1,71 @@ package fr.uca.iut.myouafff.ui.activity -class DogListActivity { +import android.os.Bundle +import android.widget.FrameLayout +import fr.uca.iut.myouafff.R +import fr.uca.iut.myouafff.data.NEW_DOG_ID +import fr.uca.iut.myouafff.ui.fragment.DogFragment +import fr.uca.iut.myouafff.ui.fragment.DogListFragment + +class DogListActivity : SimpleFragmentActivity(), + DogListFragment.OnInteractionListener, DogFragment.OnInteractionListener { + + private var isTwoPane: Boolean = false + private lateinit var masterFragment: DogListFragment + + override fun createFragment() = DogListFragment().also { masterFragment = it } + override fun getLayoutResId() = R.layout.toolbar_md_activity + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + supportActionBar?.setIcon(R.mipmap.ic_launcher) + isTwoPane = findViewById(R.id.container_fragment_detail) != null + if (savedInstanceState != null) + masterFragment = + supportFragmentManager.findFragmentById(R.id.container_fragment) as DogListFragment + + if (!isTwoPane) { + removeDisplayedFragment() + } + } + + override fun onDogSelected(dogId: Long) { + if (isTwoPane) { + supportFragmentManager.beginTransaction() + .replace(R.id.container_fragment_detail, DogFragment.newInstance(dogId)) + .commit() + } else { + startActivity(DogPagerActivity.getIntent(this, dogId)) + } + } + + override fun onAddNewDog() = startActivity(DogActivity.getIntent(this, NEW_DOG_ID)) + + override fun onDogSaved() { + if (isTwoPane) { + masterFragment.updateList() + } + } + + private fun removeDisplayedFragment() { + supportFragmentManager.findFragmentById(R.id.container_fragment_detail)?.let { + supportFragmentManager.beginTransaction().remove(it).commit() + } + } + + override fun onDogDeleted() { + if (isTwoPane) { + removeDisplayedFragment() + } else { + finish() + } + } + + override fun onDogSwiped() { + if (isTwoPane) { + removeDisplayedFragment() + } + } + } \ No newline at end of file diff --git a/app/src/main/java/fr/uca/iut/myouafff/ui/activity/DogPagerActivity.kt b/app/src/main/java/fr/uca/iut/myouafff/ui/activity/DogPagerActivity.kt index 0a77a05..be5d1c1 100644 --- a/app/src/main/java/fr/uca/iut/myouafff/ui/activity/DogPagerActivity.kt +++ b/app/src/main/java/fr/uca/iut/myouafff/ui/activity/DogPagerActivity.kt @@ -1,4 +1,52 @@ package fr.uca.iut.myouafff.ui.activity -class DogPagerActivity { +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.widget.LinearLayout +import androidx.appcompat.app.AppCompatActivity +import androidx.viewpager2.widget.ViewPager2 +import fr.uca.iut.myouafff.R +import fr.uca.iut.myouafff.ui.fragment.DogFragment +import fr.uca.iut.myouafff.ui.utils.DogPagerAdapter + +class DogPagerActivity : AppCompatActivity(), DogFragment.OnInteractionListener { + + companion object { + private const val EXTRA_DOG_ID = "fr.uca.iut.myouafff.extra_dog_id" + + fun getIntent(context: Context, dogId: Long) = + Intent(context, DogPagerActivity::class.java).apply { + putExtra(EXTRA_DOG_ID, dogId) + } + } + + private lateinit var viewPager: ViewPager2 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_pager) + + setSupportActionBar(findViewById(R.id.toolbar_activity)) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + + viewPager = ViewPager2(this) + viewPager.id = R.id.view_pager + findViewById(R.id.pager_layout).addView(viewPager) + + val adapter = DogPagerAdapter(this) + viewPager.adapter = adapter + val initialPosition = adapter.positionFromId(intent.getLongExtra(EXTRA_DOG_ID, 1)) + viewPager.currentItem = initialPosition + supportActionBar?.subtitle = getString(R.string.dogs_subtitle_format, initialPosition + 1) + + viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + supportActionBar?.subtitle = getString(R.string.dogs_subtitle_format, position + 1) + } + }) + } + + override fun onDogSaved() = finish() + override fun onDogDeleted() = finish() } \ No newline at end of file diff --git a/app/src/main/java/fr/uca/iut/myouafff/ui/fragment/DogFragment.kt b/app/src/main/java/fr/uca/iut/myouafff/ui/fragment/DogFragment.kt index 94a4652..900d32f 100644 --- a/app/src/main/java/fr/uca/iut/myouafff/ui/fragment/DogFragment.kt +++ b/app/src/main/java/fr/uca/iut/myouafff/ui/fragment/DogFragment.kt @@ -104,7 +104,7 @@ class DogFragment : Fragment() { val view = inflater.inflate(R.layout.fragment_dog, container, false) dogNameEditor = view.findViewById(R.id.dog_name_editor) dogBreedEditor = view.findViewById(R.id.dog_breed_editor) - genderSpinner = view.findViewById(R.id.dog_breed_editor) + genderSpinner = view.findViewById(R.id.gender_spinner) dogWeightEditor = view.findViewById(R.id.dog_weight_editor) aggressivenessRatingBar = view.findViewById(R.id.aggressiveness_rating_bar) dogOwnerText = view.findViewById(R.id.dog_owner_text) diff --git a/app/src/main/java/fr/uca/iut/myouafff/ui/fragment/DogListFragment.kt b/app/src/main/java/fr/uca/iut/myouafff/ui/fragment/DogListFragment.kt new file mode 100644 index 0000000..2bc34e8 --- /dev/null +++ b/app/src/main/java/fr/uca/iut/myouafff/ui/fragment/DogListFragment.kt @@ -0,0 +1,133 @@ +package fr.uca.iut.myouafff.ui.fragment + +import android.content.Context +import android.os.Bundle +import android.view.* +import androidx.constraintlayout.widget.Group +import androidx.core.view.MenuProvider +import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.floatingactionbutton.FloatingActionButton +import fr.uca.iut.myouafff.R +import fr.uca.iut.myouafff.data.Dog +import fr.uca.iut.myouafff.data.persistence.DogDatabase +import fr.uca.iut.myouafff.ui.utils.DogRecyclerViewAdapter + +class DogListFragment : Fragment(), DogRecyclerViewAdapter.Callbacks { + private var dogList = DogDatabase.getInstance().dogDAO().getAll() + private var dogListAdapter = DogRecyclerViewAdapter(dogList, this) + + private lateinit var groupEmptyView: Group + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.fragment_list_dog, container, false) + groupEmptyView = view.findViewById(R.id.group_empty_view) + groupEmptyView.visibility = if (dogList.isEmpty()) View.VISIBLE else View.GONE + val recyclerView = view.findViewById(R.id.recycler_view) + recyclerView.adapter = dogListAdapter + ItemTouchHelper(DogListItemTouchHelper()).attachToRecyclerView(recyclerView) + view.findViewById(R.id.fab_add_dog).setOnClickListener { addNewDog() } + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupMenu() + } + + private fun setupMenu() { + requireActivity().addMenuProvider(object : MenuProvider { + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + menuInflater.inflate(R.menu.fragment_list_dog, menu) + } + + override fun onMenuItemSelected(menuItem: MenuItem): Boolean { + return when (menuItem.itemId) { + R.id.menu_item_new_dog -> { + addNewDog() + true + } + else -> false + } + } + }, viewLifecycleOwner, Lifecycle.State.RESUMED) + } + + override fun onResume() { + super.onResume() + updateList() + } + + fun updateList() { + dogList = DogDatabase.getInstance().dogDAO().getAll() + dogListAdapter.updateList(dogList) + groupEmptyView.visibility = if (dogList.isEmpty()) View.VISIBLE else View.GONE + } + + private var listener: OnInteractionListener? = null + + private fun addNewDog() { + listener?.onAddNewDog() + } + + override fun onDogSelected(dogId: Long) { + listener?.onDogSelected(dogId) + } + + private inner class DogListItemTouchHelper : ItemTouchHelper.Callback() { + override fun getMovementFlags( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder + ) = + makeMovementFlags( + ItemTouchHelper.UP or ItemTouchHelper.DOWN, + ItemTouchHelper.START or ItemTouchHelper.END + ) + + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ) = false + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + (viewHolder as DogRecyclerViewAdapter.DogViewHolder).dog?.also { + removeDog(it) + listener?.onDogSwiped() + } + } + } + + private fun removeDog(dog: Dog) { + val dao = DogDatabase.getInstance().dogDAO() + dao.delete(dog) + updateList() + } + + interface OnInteractionListener { + fun onDogSelected(dogId: Long) + fun onAddNewDog() + fun onDogSwiped() + } + + override fun onAttach(context: Context) { + super.onAttach(context) + if (context is OnInteractionListener) { + listener = context + } else { + throw RuntimeException("$context must implement OnInteractionListener") + } + } + + override fun onDetach() { + super.onDetach() + listener = null + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/uca/iut/myouafff/ui/utils/DogPagerAdapter.kt b/app/src/main/java/fr/uca/iut/myouafff/ui/utils/DogPagerAdapter.kt new file mode 100644 index 0000000..82500db --- /dev/null +++ b/app/src/main/java/fr/uca/iut/myouafff/ui/utils/DogPagerAdapter.kt @@ -0,0 +1,16 @@ +package fr.uca.iut.myouafff.ui.utils + +import androidx.fragment.app.FragmentActivity +import androidx.viewpager2.adapter.FragmentStateAdapter +import fr.uca.iut.myouafff.data.persistence.DogDatabase +import fr.uca.iut.myouafff.ui.fragment.DogFragment + +class DogPagerAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) { + private var dogList = DogDatabase.getInstance().dogDAO().getAll() + + override fun getItemCount() = dogList.size + + override fun createFragment(position: Int) = DogFragment.newInstance(dogList[position].id) + + fun positionFromId(dogId: Long) = dogList.indexOfFirst { it.id == dogId } +} \ No newline at end of file diff --git a/app/src/main/java/fr/uca/iut/myouafff/ui/utils/DogRecyclerViewAdapter.kt b/app/src/main/java/fr/uca/iut/myouafff/ui/utils/DogRecyclerViewAdapter.kt new file mode 100644 index 0000000..779e1ad --- /dev/null +++ b/app/src/main/java/fr/uca/iut/myouafff/ui/utils/DogRecyclerViewAdapter.kt @@ -0,0 +1,63 @@ +package fr.uca.iut.myouafff.ui.utils + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.cardview.widget.CardView +import androidx.recyclerview.widget.RecyclerView +import fr.uca.iut.myouafff.R +import fr.uca.iut.myouafff.data.Dog + +class DogRecyclerViewAdapter(private var dogList: List, private val listener: Callbacks) : + RecyclerView.Adapter() { + override fun getItemCount() = dogList.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = + DogViewHolder( + LayoutInflater.from(parent.context).inflate( + R.layout.item_list_dog, + parent, + false + ), listener + ) + + override fun onBindViewHolder(holder: DogViewHolder, position: Int) = + holder.bind(dogList[position]) + + class DogViewHolder(itemView: View, listener: Callbacks) : + RecyclerView.ViewHolder(itemView) { + + private val viewName = itemView.findViewById(R.id.view_name) + private val viewBreed = itemView.findViewById(R.id.view_breed) + private val dogCardview = itemView.findViewById(R.id.dog_cardview) + + var dog: Dog? = null + private set + + init { + itemView.setOnClickListener { dog?.let { listener.onDogSelected(it.id) } } + } + + fun bind(dog: Dog) { + this.dog = dog + viewName.text = dog.name + val context = itemView.context + val breed = dog.breed + viewBreed.text = breed.ifEmpty { context.getString(R.string.unknown_breed) } + val color = + context.resources.getIntArray(R.array.aggressiveness_color)[dog.aggressiveness] + dogCardview.setCardBackgroundColor(color) + } + } + + fun updateList(dogList: List) { + this.dogList = dogList + notifyDataSetChanged() + } + + interface Callbacks { + fun onDogSelected(dogId: Long) + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout-land/toolbar_md_activity_content.xml b/app/src/main/res/layout-land/toolbar_md_activity_content.xml new file mode 100644 index 0000000..db8cb86 --- /dev/null +++ b/app/src/main/res/layout-land/toolbar_md_activity_content.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/app/src/main/res/layout/activity_pager.xml b/app/src/main/res/layout/activity_pager.xml new file mode 100644 index 0000000..72672a4 --- /dev/null +++ b/app/src/main/res/layout/activity_pager.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_date.xml b/app/src/main/res/layout/dialog_date.xml index 4a43693..6d93cab 100644 --- a/app/src/main/res/layout/dialog_date.xml +++ b/app/src/main/res/layout/dialog_date.xml @@ -2,4 +2,3 @@ - diff --git a/app/src/main/res/layout/fragment_dog.xml b/app/src/main/res/layout/fragment_dog.xml new file mode 100644 index 0000000..8bc96f0 --- /dev/null +++ b/app/src/main/res/layout/fragment_dog.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_list_dog.xml b/app/src/main/res/layout/fragment_list_dog.xml new file mode 100644 index 0000000..391af63 --- /dev/null +++ b/app/src/main/res/layout/fragment_list_dog.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_list_dog.xml b/app/src/main/res/layout/item_list_dog.xml new file mode 100644 index 0000000..c3bb6a8 --- /dev/null +++ b/app/src/main/res/layout/item_list_dog.xml @@ -0,0 +1,35 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/toolbar_activity.xml b/app/src/main/res/layout/toolbar_activity.xml new file mode 100644 index 0000000..39ecbb7 --- /dev/null +++ b/app/src/main/res/layout/toolbar_activity.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/app/src/main/res/layout/toolbar_md_activity.xml b/app/src/main/res/layout/toolbar_md_activity.xml new file mode 100644 index 0000000..5d18921 --- /dev/null +++ b/app/src/main/res/layout/toolbar_md_activity.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/app/src/main/res/layout/toolbar_md_activity_content.xml b/app/src/main/res/layout/toolbar_md_activity_content.xml new file mode 100644 index 0000000..59d3295 --- /dev/null +++ b/app/src/main/res/layout/toolbar_md_activity_content.xml @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/app/src/main/res/menu/fragment_dog.xml b/app/src/main/res/menu/fragment_dog.xml new file mode 100644 index 0000000..ac9a7ae --- /dev/null +++ b/app/src/main/res/menu/fragment_dog.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/fragment_list_dog.xml b/app/src/main/res/menu/fragment_list_dog.xml new file mode 100644 index 0000000..4dd4b9e --- /dev/null +++ b/app/src/main/res/menu/fragment_list_dog.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml new file mode 100644 index 0000000..a7ab8be --- /dev/null +++ b/app/src/main/res/values-fr/strings.xml @@ -0,0 +1,42 @@ + + + MyOuafff + Détail du chien + Nouveau chien + Chien %d + Date d\'admission + Chien supprimé + Impossible de supprimer le chien + Sauvegarder + Supprimer + "URL inconnue : " + "Insertion non autorisée dans : " + "Mise à jour non autorisée dans : " + "Suppression non autorisée dans : " + Ajouter un chien + + Genre + Identité + Mesure + Agressivité + Divers + + Nom + Race + Poids + kg + Propriétaire + Date d\'admission + + Inconnu + Mâle + Femelle + + Race inconnue + + C\'est un peu vide par ici… + Commençons par ajouter un chien + Impossible de créer le chien + Le nom du chien et son poids ne peuvent pas être vides. + Un bouton de raccourci pour ajouter un nouveau chien + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml new file mode 100644 index 0000000..ebc6ddd --- /dev/null +++ b/app/src/main/res/values/arrays.xml @@ -0,0 +1,16 @@ + + + + + @string/gender_unknown + @string/gender_male + @string/gender_female + + + + @color/colorNice + @color/colorNormal + @color/colorBad + @color/colorDevil + + \ No newline at end of file diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml new file mode 100644 index 0000000..3241b29 --- /dev/null +++ b/app/src/main/res/values/ids.xml @@ -0,0 +1,4 @@ + + + + \ 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 d486efd..8557367 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,6 +1,42 @@ + MyOuafff + Dog detail + New dog + Dog %d + Admission date of the dog: + Dog deleted + Failed to delete dog + Save + Delete + "Unknown URL: " + "Insertion not allowed: " + "Update not allowed: " + "Delete not allowed: " Add a dog + + Overview + Gender + Measurement + Aggressiveness + Miscellaneous + + Name + Breed + Weight + kg + Owner + Admission date + + Unknown + Male + Female + + Unknown breed + + It\'s a bit lonely here… + Get started by adding a pet Cannot create the dog - Dog\'s name or weight cannot be empty - \ No newline at end of file + Dog\'s name and weight cannot be empty. + A shortcut button to add a new dog +