From 2e97eaec5eebbf80a714f7047b6e8356b321944c Mon Sep 17 00:00:00 2001 From: Jonas Lochmann Date: Mon, 26 Oct 2020 01:00:00 +0100 Subject: [PATCH] Use CategoryAppsAndRulesFragment for CategoryTimeLimitRulesFragment --- .../appsandrules/AppAndRuleAdapter.kt | 13 ++ .../category/appsandrules/AppAndRuleItem.kt | 1 + .../CategoryAppsAndRulesFragment.kt | 92 +++++++++++- .../CategoryTimeLimitRulesFragment.kt | 141 ++---------------- .../fragment_category_time_limit_rules.xml | 27 ---- 5 files changed, 113 insertions(+), 161 deletions(-) delete mode 100644 app/src/main/res/layout/fragment_category_time_limit_rules.xml diff --git a/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/AppAndRuleAdapter.kt b/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/AppAndRuleAdapter.kt index 8cd4dc4..cf86175 100644 --- a/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/AppAndRuleAdapter.kt +++ b/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/AppAndRuleAdapter.kt @@ -39,6 +39,7 @@ class AppAndRuleAdapter: RecyclerView.Adapter() { private const val RULE_ENTRY = 4 private const val EXPAND_RULES_ITEM = 5 private const val RULES_INTRO = 6 + private const val ADD_RULE_ITEM = 7 } var items: List by Delegates.observable(emptyList()) { _, _, _ -> notifyDataSetChanged() } @@ -67,6 +68,7 @@ class AppAndRuleAdapter: RecyclerView.Adapter() { is AppAndRuleItem.RuleEntry -> RULE_ENTRY AppAndRuleItem.ExpandRulesItem -> EXPAND_RULES_ITEM AppAndRuleItem.RulesIntro -> RULES_INTRO + AppAndRuleItem.AddRuleItem -> ADD_RULE_ITEM } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder = Holder( @@ -106,6 +108,16 @@ class AppAndRuleAdapter: RecyclerView.Adapter() { parent, false ).root + ADD_RULE_ITEM -> AddItemViewBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ).apply { + label = parent.context.getString(R.string.category_time_limit_rule_dialog_new) + wide = true + + root.setOnClickListener { handlers?.onAddTimeLimitRuleClicked() } + }.root else -> throw IllegalArgumentException() } ) @@ -173,6 +185,7 @@ class AppAndRuleAdapter: RecyclerView.Adapter() { } AppAndRuleItem.ExpandRulesItem -> {/* nothing to do */} AppAndRuleItem.RulesIntro -> {/* nothing to do */} + AppAndRuleItem.AddRuleItem -> {/* nothing to do */} }.let { } } diff --git a/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/AppAndRuleItem.kt b/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/AppAndRuleItem.kt index 83eed42..de94e6f 100644 --- a/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/AppAndRuleItem.kt +++ b/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/AppAndRuleItem.kt @@ -25,4 +25,5 @@ sealed class AppAndRuleItem { data class RuleEntry(val rule: TimeLimitRule): AppAndRuleItem() object ExpandRulesItem: AppAndRuleItem() object RulesIntro: AppAndRuleItem() + object AddRuleItem: AppAndRuleItem() } \ No newline at end of file diff --git a/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/CategoryAppsAndRulesFragment.kt b/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/CategoryAppsAndRulesFragment.kt index e9dd854..34b1bb0 100644 --- a/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/CategoryAppsAndRulesFragment.kt +++ b/app/src/main/java/io/timelimit/android/ui/manage/category/appsandrules/CategoryAppsAndRulesFragment.kt @@ -21,24 +21,34 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.google.android.material.snackbar.Snackbar import io.timelimit.android.R +import io.timelimit.android.async.Threads import io.timelimit.android.data.Database +import io.timelimit.android.data.extensions.getDateLive +import io.timelimit.android.data.model.HintsToShow import io.timelimit.android.data.model.TimeLimitRule +import io.timelimit.android.livedata.map +import io.timelimit.android.livedata.switchMap import io.timelimit.android.logic.DefaultAppLogic import io.timelimit.android.sync.actions.AddCategoryAppsAction +import io.timelimit.android.sync.actions.CreateTimeLimitRuleAction import io.timelimit.android.sync.actions.RemoveCategoryAppsAction +import io.timelimit.android.sync.actions.UpdateTimeLimitRuleAction import io.timelimit.android.ui.main.ActivityViewModel import io.timelimit.android.ui.main.getActivityViewModel import io.timelimit.android.ui.manage.category.apps.add.AddCategoryAppsFragment import io.timelimit.android.ui.manage.category.timelimit_rules.edit.EditTimeLimitRuleDialogFragment +import io.timelimit.android.ui.manage.category.timelimit_rules.edit.EditTimeLimitRuleDialogFragmentListener import kotlinx.android.synthetic.main.fragment_category_apps_and_rules.* -abstract class CategoryAppsAndRulesFragment: Fragment(), Handlers { +abstract class CategoryAppsAndRulesFragment: Fragment(), Handlers, EditTimeLimitRuleDialogFragmentListener { private val adapter = AppAndRuleAdapter().also { it.handlers = this } - private val database: Database by lazy { DefaultAppLogic.with(requireContext()).database } - private val auth: ActivityViewModel by lazy { getActivityViewModel(requireActivity()) } + val auth: ActivityViewModel by lazy { getActivityViewModel(requireActivity()) } + val database: Database by lazy { DefaultAppLogic.with(requireContext()).database } abstract val childId: String abstract val categoryId: String @@ -51,10 +61,86 @@ abstract class CategoryAppsAndRulesFragment: Fragment(), Handlers { recycler.layoutManager = LinearLayoutManager(requireContext()) recycler.adapter = adapter + + ItemTouchHelper(object: ItemTouchHelper.Callback() { + override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { + val index = viewHolder.adapterPosition + val item = if (index == RecyclerView.NO_POSITION) null else adapter.items[index] + + if (item == AppAndRuleItem.RulesIntro) { + return makeFlag(ItemTouchHelper.ACTION_STATE_SWIPE, ItemTouchHelper.END or ItemTouchHelper.START) or + makeFlag(ItemTouchHelper.ACTION_STATE_IDLE, ItemTouchHelper.END or ItemTouchHelper.START) + } else { + return 0 + } + } + + override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder) = throw IllegalStateException() + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val database = database + + Threads.database.submit { + database.config().setHintsShownSync(HintsToShow.TIME_LIMIT_RULE_INTRODUCTION) + } + } + }).attachToRecyclerView(recycler) + + val userDate = database.user().getUserByIdLive(childId).getDateLive(auth.logic.realTimeLogic) + + userDate.switchMap { date -> + val firstDayOfWeekAsEpochDay = date.dayOfEpoch - date.dayOfWeek + + database.usedTimes().getUsedTimesOfWeek( + categoryId = categoryId, + firstDayOfWeekAsEpochDay = firstDayOfWeekAsEpochDay + ).map { res -> + firstDayOfWeekAsEpochDay to res + } + }.observe(viewLifecycleOwner) { + adapter.epochDayOfStartOfWeek = it.first + adapter.usedTimes = it.second + } } fun setListContent(items: List) { adapter.items = items } + override fun notifyRuleCreated() { + Snackbar.make(requireView(), R.string.category_time_limit_rules_snackbar_created, Snackbar.LENGTH_SHORT) + .show() + } + + override fun notifyRuleDeleted(oldRule: TimeLimitRule) { + Snackbar.make(requireView(), R.string.category_time_limit_rules_snackbar_deleted, Snackbar.LENGTH_SHORT) + .setAction(R.string.generic_undo) { + auth.tryDispatchParentAction( + CreateTimeLimitRuleAction( + rule = oldRule + ) + ) + } + .show() + } + + override fun notifyRuleUpdated(oldRule: TimeLimitRule, newRule: TimeLimitRule) { + Snackbar.make(requireView(), R.string.category_time_limit_rules_snackbar_updated, Snackbar.LENGTH_SHORT) + .setAction(R.string.generic_undo) { + auth.tryDispatchParentAction( + UpdateTimeLimitRuleAction( + ruleId = oldRule.id, + applyToExtraTimeUsage = oldRule.applyToExtraTimeUsage, + maximumTimeInMillis = oldRule.maximumTimeInMillis, + dayMask = oldRule.dayMask, + start = oldRule.startMinuteOfDay, + end = oldRule.endMinuteOfDay, + sessionDurationMilliseconds = oldRule.sessionDurationMilliseconds, + sessionPauseMilliseconds = oldRule.sessionPauseMilliseconds + ) + ) + } + .show() + } + override fun onAppClicked(app: AppAndRuleItem.AppEntry) { if (auth.tryDispatchParentAction( RemoveCategoryAppsAction( diff --git a/app/src/main/java/io/timelimit/android/ui/manage/category/timelimit_rules/CategoryTimeLimitRulesFragment.kt b/app/src/main/java/io/timelimit/android/ui/manage/category/timelimit_rules/CategoryTimeLimitRulesFragment.kt index eec7e1d..78900c7 100644 --- a/app/src/main/java/io/timelimit/android/ui/manage/category/timelimit_rules/CategoryTimeLimitRulesFragment.kt +++ b/app/src/main/java/io/timelimit/android/ui/manage/category/timelimit_rules/CategoryTimeLimitRulesFragment.kt @@ -16,36 +16,17 @@ package io.timelimit.android.ui.manage.category.timelimit_rules import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData -import androidx.lifecycle.Observer -import androidx.recyclerview.widget.ItemTouchHelper -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.google.android.material.snackbar.Snackbar -import io.timelimit.android.R -import io.timelimit.android.async.Threads -import io.timelimit.android.data.Database -import io.timelimit.android.data.extensions.getDateLive import io.timelimit.android.data.model.HintsToShow import io.timelimit.android.data.model.TimeLimitRule import io.timelimit.android.livedata.map import io.timelimit.android.livedata.switchMap -import io.timelimit.android.logic.AppLogic -import io.timelimit.android.logic.DefaultAppLogic -import io.timelimit.android.sync.actions.CreateTimeLimitRuleAction -import io.timelimit.android.sync.actions.UpdateTimeLimitRuleAction -import io.timelimit.android.ui.main.ActivityViewModel -import io.timelimit.android.ui.main.getActivityViewModel import io.timelimit.android.ui.manage.category.ManageCategoryFragmentArgs -import io.timelimit.android.ui.manage.category.timelimit_rules.edit.EditTimeLimitRuleDialogFragment -import io.timelimit.android.ui.manage.category.timelimit_rules.edit.EditTimeLimitRuleDialogFragmentListener -import kotlinx.android.synthetic.main.fragment_category_time_limit_rules.* +import io.timelimit.android.ui.manage.category.appsandrules.AppAndRuleItem +import io.timelimit.android.ui.manage.category.appsandrules.CategoryAppsAndRulesFragment -class CategoryTimeLimitRulesFragment : Fragment(), EditTimeLimitRuleDialogFragmentListener { +class CategoryTimeLimitRulesFragment: CategoryAppsAndRulesFragment() { companion object { fun newInstance(params: ManageCategoryFragmentArgs): CategoryTimeLimitRulesFragment { val result = CategoryTimeLimitRulesFragment() @@ -54,130 +35,28 @@ class CategoryTimeLimitRulesFragment : Fragment(), EditTimeLimitRuleDialogFragme } } - private val logic: AppLogic by lazy { DefaultAppLogic.with(context!!) } - private val params: ManageCategoryFragmentArgs by lazy { ManageCategoryFragmentArgs.fromBundle(arguments!!) } - private val database: Database by lazy { logic.database } + private val params: ManageCategoryFragmentArgs by lazy { ManageCategoryFragmentArgs.fromBundle(requireArguments()) } private val rules: LiveData> by lazy { database.timeLimitRules().getTimeLimitRulesByCategory(params.categoryId) } - private val auth: ActivityViewModel by lazy { getActivityViewModel(activity!!) } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_category_time_limit_rules, container, false) - } + override val childId: String get() = params.childId + override val categoryId: String get() = params.categoryId override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val adapter = Adapter() - - recycler.layoutManager = LinearLayoutManager(context!!) - recycler.adapter = adapter - - val userDate = database.user().getUserByIdLive(params.childId).getDateLive(logic.realTimeLogic) - - userDate.switchMap { date -> - val firstDayOfWeekAsEpochDay = date.dayOfEpoch - date.dayOfWeek - - database.usedTimes().getUsedTimesOfWeek( - categoryId = params.categoryId, - firstDayOfWeekAsEpochDay = firstDayOfWeekAsEpochDay - ).map { res -> - firstDayOfWeekAsEpochDay to res - } - }.observe(viewLifecycleOwner, Observer { - adapter.epochDayOfStartOfWeek = it.first - adapter.usedTimes = it.second - }) - val hasHiddenIntro = database.config().wereHintsShown(HintsToShow.TIME_LIMIT_RULE_INTRODUCTION) rules.map { rules -> - rules.sortedBy { it.dayMask }.map { TimeLimitRuleRuleItem(it) } + rules.sortedBy { it.dayMask }.map { AppAndRuleItem.RuleEntry(it) } }.switchMap { - val baseList = it + listOf(AddTimeLimitRuleItem) + val baseList = it + listOf(AppAndRuleItem.AddRuleItem) hasHiddenIntro.map { hasHiddenIntro -> if (hasHiddenIntro) { baseList } else { - listOf(TimeLimitRuleIntroductionItem) + baseList + listOf(AppAndRuleItem.RulesIntro) + baseList } } - }.observe(viewLifecycleOwner, Observer { - adapter.data = it - }) - - adapter.handlers = object: TimeLimitRulesHandlers { - override fun onTimeLimitRuleClicked(rule: TimeLimitRule) { - if (auth.requestAuthenticationOrReturnTrue()) { - EditTimeLimitRuleDialogFragment.newInstance(rule, this@CategoryTimeLimitRulesFragment).show(fragmentManager!!) - } - } - - override fun onAddTimeLimitRuleClicked() { - if (auth.requestAuthenticationOrReturnTrueAllowChild(childId = params.childId)) { - EditTimeLimitRuleDialogFragment.newInstance(params.categoryId, this@CategoryTimeLimitRulesFragment).show(fragmentManager!!) - } - } - } - - ItemTouchHelper(object: ItemTouchHelper.Callback() { - override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { - val index = viewHolder.adapterPosition - val item = if (index == RecyclerView.NO_POSITION) null else adapter.data[index] - - if (item == TimeLimitRuleIntroductionItem) { - return makeFlag(ItemTouchHelper.ACTION_STATE_SWIPE, ItemTouchHelper.END or ItemTouchHelper.START) or - makeFlag(ItemTouchHelper.ACTION_STATE_IDLE, ItemTouchHelper.END or ItemTouchHelper.START) - } else { - return 0 - } - } - - override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder) = throw IllegalStateException() - - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - val database = logic.database - - Threads.database.submit { - database.config().setHintsShownSync(HintsToShow.TIME_LIMIT_RULE_INTRODUCTION) - } - } - }).attachToRecyclerView(recycler) - } - - override fun notifyRuleCreated() { - Snackbar.make(view!!, R.string.category_time_limit_rules_snackbar_created, Snackbar.LENGTH_SHORT) - .show() - } - - override fun notifyRuleDeleted(oldRule: TimeLimitRule) { - Snackbar.make(view!!, R.string.category_time_limit_rules_snackbar_deleted, Snackbar.LENGTH_SHORT) - .setAction(R.string.generic_undo) { - auth.tryDispatchParentAction( - CreateTimeLimitRuleAction( - rule = oldRule - ) - ) - } - .show() - } - - override fun notifyRuleUpdated(oldRule: TimeLimitRule, newRule: TimeLimitRule) { - Snackbar.make(view!!, R.string.category_time_limit_rules_snackbar_updated, Snackbar.LENGTH_SHORT) - .setAction(R.string.generic_undo) { - auth.tryDispatchParentAction( - UpdateTimeLimitRuleAction( - ruleId = oldRule.id, - applyToExtraTimeUsage = oldRule.applyToExtraTimeUsage, - maximumTimeInMillis = oldRule.maximumTimeInMillis, - dayMask = oldRule.dayMask, - start = oldRule.startMinuteOfDay, - end = oldRule.endMinuteOfDay, - sessionDurationMilliseconds = oldRule.sessionDurationMilliseconds, - sessionPauseMilliseconds = oldRule.sessionPauseMilliseconds - ) - ) - } - .show() + }.observe(viewLifecycleOwner) { setListContent(it) } } } diff --git a/app/src/main/res/layout/fragment_category_time_limit_rules.xml b/app/src/main/res/layout/fragment_category_time_limit_rules.xml deleted file mode 100644 index cac53c7..0000000 --- a/app/src/main/res/layout/fragment_category_time_limit_rules.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - -