Skip to content

Commit

Permalink
Migrate "Schedule Changes" screen to Compose UI.
Browse files Browse the repository at this point in the history
+ Replace XML-based screen with Compose UI setup.
+ Detach from AbstractListFragment.
+ Introduce SessionChangeParametersFactory to encapsulate screen logic. Add unit tests.
+ Let video recording icon color represent change state similar as text changes.
+ Remove now unused code from SessionsAdapter which is still used by "Favorites" screen.
+ Vertical scroll bar is missing.
  • Loading branch information
johnjohndoe committed Jul 8, 2024
1 parent 05bc75f commit f3e5308
Show file tree
Hide file tree
Showing 26 changed files with 1,439 additions and 398 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ abstract class SessionsAdapter protected constructor(
time = rowView.requireViewByIdCompat(R.id.session_list_item_time_view),
room = rowView.requireViewByIdCompat(R.id.session_list_item_room_view),
duration = rowView.requireViewByIdCompat(R.id.session_list_item_duration_view),
video = rowView.requireViewByIdCompat(R.id.session_list_item_video_view),
noVideo = rowView.requireViewByIdCompat(R.id.session_list_item_no_video_view),
withoutVideoRecording = rowView.requireViewByIdCompat(R.id.session_list_item_without_video_recording_view),
)
rowView.tag = viewHolder
Expand Down Expand Up @@ -187,8 +185,6 @@ abstract class SessionsAdapter protected constructor(
var time: TextView,
var room: TextView,
var duration: TextView,
var noVideo: ImageView,
var video: ImageView,
var withoutVideoRecording: ImageView
)

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,37 @@ import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.HeaderViewListAdapter
import android.widget.ListView
import androidx.annotation.CallSuper
import androidx.annotation.IdRes
import androidx.annotation.MainThread
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.viewModels
import info.metadude.android.eventfahrplan.commons.flow.observe
import nerd.tuxmobil.fahrplan.congress.R
import nerd.tuxmobil.fahrplan.congress.base.AbstractListFragment
import nerd.tuxmobil.fahrplan.congress.base.AbstractListFragment.OnSessionListClick
import nerd.tuxmobil.fahrplan.congress.commons.ResourceResolver
import nerd.tuxmobil.fahrplan.congress.commons.ScreenNavigation
import nerd.tuxmobil.fahrplan.congress.contract.BundleKeys
import nerd.tuxmobil.fahrplan.congress.extensions.replaceFragment
import nerd.tuxmobil.fahrplan.congress.extensions.requireViewByIdCompat
import nerd.tuxmobil.fahrplan.congress.extensions.withArguments
import nerd.tuxmobil.fahrplan.congress.notifications.NotificationHelper
import nerd.tuxmobil.fahrplan.congress.repositories.AppRepository
import nerd.tuxmobil.fahrplan.congress.utils.ContentDescriptionFormatter
import nerd.tuxmobil.fahrplan.congress.utils.SessionPropertiesFormatter

/**
* A fragment representing a list of Items.
*
* Large screen devices (such as tablets) are supported by replacing the ListView with a GridView.
*
* Activities containing this fragment MUST implement the [OnSessionListClick] interface.
*
* Mandatory empty constructor for the fragment manager to instantiate the fragment (e.g. upon
* screen orientation changes).
*/
class ChangeListFragment : AbstractListFragment() {
class ChangeListFragment : Fragment() {

companion object {

Expand All @@ -55,8 +56,16 @@ class ChangeListFragment : AbstractListFragment() {
}

private var onSessionListClickListener: OnSessionListClick? = null
private lateinit var currentListView: ListView
private val viewModelFactory by lazy { ChangeListViewModelFactory(appRepository) }
private lateinit var screenNavigation: ScreenNavigation
private val viewModelFactory by lazy {
ChangeListViewModelFactory(
AppRepository,
ResourceResolver(requireContext()),
screenNavigation,
SessionPropertiesFormatter(),
ContentDescriptionFormatter(requireContext()),
)
}
private val viewModel: ChangeListViewModel by viewModels { viewModelFactory }

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
Expand All @@ -65,16 +74,18 @@ class ChangeListFragment : AbstractListFragment() {

val contextThemeWrapper = ContextThemeWrapper(requireContext(), R.style.Theme_Congress_NoActionBar)
val localInflater = inflater.cloneInContext(contextThemeWrapper)
val (fragmentLayout, headerLayout) = when {
sidePane -> R.layout.fragment_session_list_narrow to R.layout.changes_header
else -> R.layout.fragment_session_list to R.layout.header_empty
val fragmentView = localInflater.inflate(R.layout.fragment_session_list, container, false)
fragmentView.findViewById<ComposeView>(R.id.session_changes_view).apply {
setViewCompositionStrategy(DisposeOnViewTreeLifecycleDestroyed)
setContent {
SessionChangesScreen(
state = viewModel.sessionChangesState.collectAsState().value,
showInSidePane = sidePane,
onViewEvent = viewModel::onViewEvent,
)
}
isClickable = true
}

val fragmentView = localInflater.inflate(fragmentLayout, container, false)
val headerView = localInflater.inflate(headerLayout, null, false)
currentListView = fragmentView.requireViewByIdCompat(android.R.id.list)
currentListView.addHeaderView(headerView, null, false)
currentListView.setHeaderDividersEnabled(false)
return fragmentView
}

Expand All @@ -84,17 +95,6 @@ class ChangeListFragment : AbstractListFragment() {
}

private fun observeViewModel() {
viewModel.changeListParameter.observe(this) { (sessions, numDays, useDeviceTimeZone) ->
val adapter = ChangeListAdapter(
context = requireContext(),
list = sessions,
numDays = numDays,
useDeviceTimeZone = useDeviceTimeZone,
sessionPropertiesFormatter = SessionPropertiesFormatter(),
contentDescriptionFormatter = ContentDescriptionFormatter(requireContext())
)
currentListView.adapter = adapter
}
viewModel.scheduleChangesSeen.observe(viewLifecycleOwner) {
NotificationHelper(requireContext()).cancelScheduleUpdateNotification()
}
Expand All @@ -111,6 +111,9 @@ class ChangeListFragment : AbstractListFragment() {
super.onAttach(context)
if (context is OnSessionListClick) {
onSessionListClickListener = context
screenNavigation = ScreenNavigation { sessionId ->
onSessionListClickListener?.onSessionListClick(sessionId)
}
} else {
error("$context must implement OnSessionListClick")
}
Expand All @@ -123,17 +126,4 @@ class ChangeListFragment : AbstractListFragment() {
onSessionListClickListener = null
}

override fun onListItemClick(listView: ListView, view: View, listPosition: Int, rowId: Long) {
val headerViewListAdapter = currentListView.adapter as HeaderViewListAdapter
val adapter = headerViewListAdapter.wrappedAdapter as ChangeListAdapter
onSessionListClickListener?.let { listener ->
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
val clicked = adapter.getSession(listPosition - 1)
if (!clicked.changedIsCanceled) {
listener.onSessionListClick(clicked.sessionId)
}
}
}

}

This file was deleted.

Loading

0 comments on commit f3e5308

Please sign in to comment.