Skip to content

Commit

Permalink
TodoSettingsFragment: Rewrite to Jetpack Compose (#368, #581)
Browse files Browse the repository at this point in the history
* Add ViewModel for fragment
  • Loading branch information
EdricChan03 committed Dec 14, 2024
1 parent 9a83ee0 commit 8f390f1
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
package com.edricchan.studybuddy.ui.modules.settings.fragment

import android.os.Bundle
import com.edricchan.studybuddy.R
import com.edricchan.studybuddy.ui.preference.MaterialPreferenceFragment
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.fragment.app.viewModels
import androidx.fragment.compose.content
import com.edricchan.studybuddy.features.settings.task.ui.TaskSettingsScreen
import com.edricchan.studybuddy.features.settings.task.vm.TaskSettingsViewModel
import com.edricchan.studybuddy.ui.common.fragment.BaseFragment
import com.edricchan.studybuddy.ui.theming.compose.StudyBuddyTheme
import dagger.hilt.android.AndroidEntryPoint

class TodoSettingsFragment : MaterialPreferenceFragment() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.pref_todos, rootKey)
@AndroidEntryPoint
class TodoSettingsFragment : BaseFragment() {
private val viewModel by viewModels<TaskSettingsViewModel>()

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
) = content {
val nestedScrollInterop = rememberNestedScrollInteropConnection()
StudyBuddyTheme {
TaskSettingsScreen(
modifier = Modifier
.nestedScroll(nestedScrollInterop)
.windowInsetsPadding(WindowInsets.navigationBars),
viewModel = viewModel
)
}
}
}
11 changes: 0 additions & 11 deletions app/src/main/res/xml/pref_todos.xml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.edricchan.studybuddy.features.settings.task.model

import androidx.annotation.StringRes
import com.edricchan.studybuddy.features.settings.R
import com.edricchan.studybuddy.features.settings.task.model.TaskSortOptionCompat.entries

enum class TaskSortOptionCompat(
@StringRes val stringResource: Int,
val value: String
) {
None(
stringResource = R.string.pref_task_default_sort_entry_none,
value = "none"
),
TitleAsc(
stringResource = R.string.pref_task_default_sort_entry_title_asc,
value = "title_asc"
),
TitleDesc(
stringResource = R.string.pref_task_default_sort_entry_title_desc,
value = "title_desc"
),
DueDateNewToOld(
stringResource = R.string.pref_task_default_sort_entry_due_date_new_to_old,
value = "due_date_new_to_old"
),
DueDateOldToNew(
stringResource = R.string.pref_task_default_sort_entry_due_date_old_to_new,
value = "due_date_old_to_new"
);

companion object {
fun fromValue(value: String): TaskSortOptionCompat = entries.first { it.value == value }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.edricchan.studybuddy.features.settings.task.ui

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.edricchan.studybuddy.features.settings.R
import com.edricchan.studybuddy.features.settings.task.model.TaskSortOptionCompat
import com.edricchan.studybuddy.features.settings.task.vm.TaskSettingsViewModel
import com.edricchan.studybuddy.ui.preference.compose.ListDialogPreference
import com.edricchan.studybuddy.ui.theming.compose.StudyBuddyTheme

@Composable
private fun TaskDefaultSortPreference(
modifier: Modifier = Modifier,
defaultSort: TaskSortOptionCompat,
onDefaultSortChange: (TaskSortOptionCompat) -> Unit
) {
ListDialogPreference(
modifier = modifier,
icon = { Icon(painterResource(R.drawable.ic_sort_24dp), contentDescription = null) },
title = { Text(text = stringResource(R.string.pref_task_default_sort_title)) },
subtitle = { Text(text = stringResource(defaultSort.stringResource)) },
values = TaskSortOptionCompat.entries,
value = defaultSort,
onValueChanged = onDefaultSortChange,
valueLabel = { Text(text = stringResource(it.stringResource)) }
)
}

@Composable
fun TaskSettingsScreen(
modifier: Modifier = Modifier,
defaultSort: TaskSortOptionCompat,
onDefaultSortChange: (TaskSortOptionCompat) -> Unit
) = Column(
modifier = modifier.verticalScroll(rememberScrollState())
) {
TaskDefaultSortPreference(
defaultSort = defaultSort,
onDefaultSortChange = onDefaultSortChange
)
}

@Composable
fun TaskSettingsScreen(
modifier: Modifier = Modifier,
viewModel: TaskSettingsViewModel
) {
val defaultSort by viewModel.prefDefaultSort.asFlow().collectAsStateWithLifecycle(
TaskSortOptionCompat.None
)

TaskSettingsScreen(
modifier = modifier,
defaultSort = defaultSort,
onDefaultSortChange = viewModel.prefDefaultSort::set
)
}

@Preview
@Composable
private fun TaskSettingsScreenPreview() {
var defaultSort by remember { mutableStateOf(TaskSortOptionCompat.None) }

StudyBuddyTheme {
TaskSettingsScreen(
defaultSort = defaultSort,
onDefaultSortChange = { defaultSort = it }
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.edricchan.studybuddy.features.settings.task.vm

import android.content.Context
import androidx.lifecycle.ViewModel
import com.edricchan.studybuddy.core.settings.tasks.keyPrefTaskDefaultSort
import com.edricchan.studybuddy.exts.androidx.preference.defaultSharedPreferences
import com.edricchan.studybuddy.features.settings.task.model.TaskSortOptionCompat
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
import com.fredporciuncula.flow.preferences.Preference
import com.fredporciuncula.flow.preferences.map
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject

@HiltViewModel
class TaskSettingsViewModel @Inject constructor(
@ApplicationContext context: Context
) : ViewModel() {
private val appPreferences = FlowSharedPreferences(
context.defaultSharedPreferences
)

val prefDefaultSort: Preference<TaskSortOptionCompat> = appPreferences.getString(
keyPrefTaskDefaultSort
).map(
mapper = TaskSortOptionCompat::fromValue,
reverse = TaskSortOptionCompat::value
)
}
14 changes: 14 additions & 0 deletions features/settings/src/main/res/values/task_strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- TODO: Add a better UI for the default sort -->
<eat-comment />

<!-- Title for the default sort mode setting. -->
<string name="pref_task_default_sort_title">Default sorting mode</string>

<string name="pref_task_default_sort_entry_none">None (Default)</string>
<string name="pref_task_default_sort_entry_title_asc">Title (A to Z)</string>
<string name="pref_task_default_sort_entry_title_desc">Title (Z to A)</string>
<string name="pref_task_default_sort_entry_due_date_new_to_old">Due Date (Newest to Oldest)</string>
<string name="pref_task_default_sort_entry_due_date_old_to_new">Due Date (Oldest to Newest)</string>
</resources>

0 comments on commit 8f390f1

Please sign in to comment.