Replaced fragment switching functionality in MainActivity.kt with Navigation component, simplifying logic significantly; upgraded to AGP 8.0.1

This commit is contained in:
denizk0461
2023-05-02 20:52:56 +02:00
parent 51c4c9120b
commit 36a7ae0035
12 changed files with 73 additions and 119 deletions
@@ -3,15 +3,10 @@ package com.denizk0461.studip.activity
import android.os.Bundle
import androidx.core.view.WindowCompat
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.Lifecycle
import com.denizk0461.studip.R
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.setupWithNavController
import com.denizk0461.studip.databinding.ActivityMainBinding
import com.denizk0461.studip.db.AppRepository
import com.denizk0461.studip.fragment.EventFragment
import com.denizk0461.studip.fragment.CanteenFragment
import com.denizk0461.studip.fragment.SettingsFragment
import com.denizk0461.studip.model.SettingsPreferences
/**
* Main activity that handles all common fragments. This is opened on app launch.
@@ -21,91 +16,17 @@ class MainActivity : FragmentActivity() {
// View binding
private lateinit var binding: ActivityMainBinding
/*
* Tag for the currently active fragment; set on activity launch to the fragment that will be
* shown first.
*/
private var currentFragment: String = "event"
override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
/*
* Instantiate repository object that is accessed by the fragments' view models to retrieve
* data.
*/
// Dependencies.repo = AppRepository(application)
// Inflate view binding and bind to this activity
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// Set up navigation view bar to launch fragments
binding.navView.setOnItemSelectedListener { item ->
// Launch fragment based on the item that has been clicked
loadFragment(when (item.itemId) {
R.id.food -> "canteen"
R.id.settings -> "settings"
else -> "event"
})
}
// Set up bottom nav bar and the initial fragment when the app launches
if (savedInstanceState == null) {
// Open the fragment that the user specified to open on app start
if (AppRepository.getRepositoryInstance(application)
.getBooleanPreference(SettingsPreferences.LAUNCH_CANTEEN_ON_START)
) {
// Open canteen fragment
binding.navView.selectedItemId = R.id.food
currentFragment = "canteen"
} else {
// Open event fragment
binding.navView.selectedItemId = R.id.plan
currentFragment = "event"
}
// Launch the fragment defined in currentFragment
loadFragment(currentFragment)
}
}
/**
* Loads a given fragment.
*
* @param type tag for the fragment that is to be opened
* @return true on success, false if another fragment is currently instantiating
*/
private fun loadFragment(type: String): Boolean {
// Find the fragment that is to be opened, or create it if it hasn't been instantiated yet
val fragment = supportFragmentManager.findFragmentByTag(type) ?: getFragment(type)
// Don't interrupt the current fragment's lifecycle if it isn't fully initialised
if (fragment.lifecycle.currentState != Lifecycle.State.INITIALIZED) {
return false
}
// Start the transaction to show the new fragment
supportFragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment_content_main, fragment, type)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commit()
// Success
return true
}
/**
* Retrieve fragment by its tag.
*
* @param type tag for the corresponding fragment
* @return the corresponding fragment
*/
private fun getFragment(type: String) = when (type) {
"canteen" -> CanteenFragment() // CanteenFragment.kt
"settings" -> SettingsFragment() // SettingsFragment.kt
else -> EventFragment() // on unknown value or "event", launch EventFragment.kt
// Set up bottom navigation view to navigate between fragments
binding.navView.setupWithNavController(
binding.navHostFragmentContentMain.getFragment<NavHostFragment>().findNavController()
)
}
}
@@ -24,6 +24,7 @@ import java.util.*
*/
class StudIPEventItemAdapter(
private val currentDay: Int,
private val highlightNextCourse: Boolean,
private val onClickListener: OnClickListener,
) : RecyclerView.Adapter<StudIPEventItemAdapter.EventViewHolder>() {
@@ -80,10 +81,11 @@ class StudIPEventItemAdapter(
val theme = holder.binding.root.context.theme
/*
* Highlight the next upcoming course of the day if the day of the adapter matches the
* current day, and if no other course has been highlighted, to avoid double highlighting.
* Highlight the next upcoming course of the day if the user selected the option, if the day
* of the adapter matches the current day, and if no other course has been highlighted, to
* avoid double highlighting.
*/
if (!isAnyCourseHighlighted && currentItem.isCurrentCourse(currentCalendar)) {
if (highlightNextCourse && !isAnyCourseHighlighted && currentItem.isCurrentCourse(currentCalendar)) {
// Ensure that no other course will be highlighted
isAnyCourseHighlighted = true
@@ -124,17 +124,6 @@ class CanteenFragment : AppFragment() {
chip.setOnCheckedChangeListener { buttonView, newValue ->
// Save the preference change to persistent storage
setPreference(pref, newValue)
/*
* Force an animation on click. This is a subpar method from StackOverflow. Since
* it removes the view before immediately adding it back, this method causes a
* flicker.
* TODO implement a more efficient / better-looking method
* TODO order the chips alphabetically?
*/
// val index = binding.chipsPreference.indexOfChild(buttonView)
// binding.chipsPreference.removeView(buttonView)
// binding.chipsPreference.addView(buttonView, index)
}
}
@@ -152,6 +141,8 @@ class CanteenFragment : AppFragment() {
// Let the adapter know of the new amount of dates (pages) to display
viewPagerAdapter.itemCount = dates.size
openingHours = viewModel.getCanteenOpeningHours()
}
// Assign the adapter to the view pager
@@ -48,7 +48,11 @@ class EventPageFragment : AppFragment(), StudIPEventItemAdapter.OnClickListener
currentDay = arguments?.getInt("currentDay") ?: -1
// Instantiate event adapter with the current day
eventAdapter = StudIPEventItemAdapter(currentDay, this)
eventAdapter = StudIPEventItemAdapter(
currentDay,
viewModel.preferenceCourseHighlighting,
this,
)
// Inflate view binding
_binding = RecyclerViewBinding.inflate(inflater, container, false)
@@ -43,7 +43,6 @@ class CanteenPageViewModel(app: Application) : AppViewModel(app) {
/**
* This value determines which canteen the user has selected.
*/
var preferenceColour: Boolean
get() = repo.getBooleanPreference(SettingsPreferences.COLOUR_PREFS)
set(newValue) { repo.setPreference(SettingsPreferences.COLOUR_PREFS, newValue) }
val preferenceColour: Boolean
get() = repo.getBooleanPreference(SettingsPreferences.COLOUR_PREFS, defaultValue = true)
}
@@ -2,6 +2,7 @@ package com.denizk0461.studip.viewmodel
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizk0461.studip.model.SettingsPreferences
import com.denizk0461.studip.model.StudIPEvent
/**
@@ -17,4 +18,14 @@ class EventPageViewModel(app: Application) : AppViewModel(app) {
* @return Stud.IP events for a certain day exposed through a LiveData object
*/
fun getEventsForDay(day: Int): LiveData<List<StudIPEvent>> = repo.getEventsForDay(day)
/**
* This value determines whether the user wants to have the next course in their schedule
* highlighted.
*/
val preferenceCourseHighlighting: Boolean
get() = repo.getBooleanPreference(
SettingsPreferences.COURSE_HIGHLIGHTING,
defaultValue = true
)
}
@@ -15,7 +15,10 @@ class SettingsViewModel(app: Application) : AppViewModel(app) {
* highlighted.
*/
var preferenceCourseHighlighting: Boolean
get() = repo.getBooleanPreference(SettingsPreferences.COURSE_HIGHLIGHTING)
get() = repo.getBooleanPreference(
SettingsPreferences.COURSE_HIGHLIGHTING,
defaultValue = true
)
set(newValue) { repo.setPreference(SettingsPreferences.COURSE_HIGHLIGHTING, newValue) }
/**
@@ -36,7 +39,7 @@ class SettingsViewModel(app: Application) : AppViewModel(app) {
* This value determines which canteen the user has selected.
*/
var preferenceColour: Boolean
get() = repo.getBooleanPreference(SettingsPreferences.COLOUR_PREFS)
get() = repo.getBooleanPreference(SettingsPreferences.COLOUR_PREFS, defaultValue = true)
set(newValue) { repo.setPreference(SettingsPreferences.COLOUR_PREFS, newValue) }
/**
@@ -13,6 +13,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="@navigation/main_nav_graph"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/nav_view"
app:layout_constraintStart_toStartOf="parent"
+9 -9
View File
@@ -44,6 +44,15 @@
</androidx.appcompat.widget.LinearLayoutCompat>
<TextView
android:id="@+id/app_title_bar"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="@string/title_food"
android:textSize="32sp"
android:fontFamily="@font/lato_bolditalic"
android:layout_marginHorizontal="16dp"/>
<HorizontalScrollView
android:id="@+id/scroll_view_chip"
android:layout_width="match_parent"
@@ -181,15 +190,6 @@
</HorizontalScrollView>
<TextView
android:id="@+id/app_title_bar"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="@string/title_food"
android:textSize="32sp"
android:fontFamily="@font/lato_bolditalic"
android:layout_marginHorizontal="16dp"/>
</androidx.appcompat.widget.LinearLayoutCompat>
<com.google.android.material.tabs.TabLayout
+2 -2
View File
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/plan"
android:id="@+id/schedule"
android:icon="@drawable/design"
android:title="@string/nav_schedule"
android:enabled="true"/>
<item
android:id="@+id/food"
android:id="@+id/canteen"
android:icon="@drawable/restaurant"
android:title="@string/nav_food"
android:enabled="true"/>
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation 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/main_nav_graph"
app:startDestination="@id/schedule">
<fragment
android:id="@+id/schedule"
android:name="com.denizk0461.studip.fragment.EventFragment"
android:label="EventFragment"
tools:layout="@layout/fragment_event"/>
<fragment
android:id="@+id/canteen"
android:name="com.denizk0461.studip.fragment.CanteenFragment"
android:label="CanteenFragment"/>
<fragment
android:id="@+id/settings"
android:name="com.denizk0461.studip.fragment.SettingsFragment"
android:label="SettingsFragment"
tools:layout="@layout/fragment_settings"/>
</navigation>