Archived
Replaced fragment switching functionality in MainActivity.kt with Navigation component, simplifying logic significantly; upgraded to AGP 8.0.1
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id 'com.android.application' version '8.0.0' apply false
|
||||
id 'com.android.library' version '8.0.0' apply false
|
||||
id 'com.android.application' version '8.0.1' apply false
|
||||
id 'com.android.library' version '8.0.1' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
|
||||
}
|
||||
Reference in New Issue
Block a user