Use CategoryAppsAndRulesFragment for CategoryTimeLimitRulesFragment

This commit is contained in:
Jonas Lochmann 2020-10-26 01:00:00 +01:00
parent 2c30b648e6
commit 2e97eaec5e
No known key found for this signature in database
GPG key ID: 8B8C9AEE10FA5B36
5 changed files with 113 additions and 161 deletions

View file

@ -39,6 +39,7 @@ class AppAndRuleAdapter: RecyclerView.Adapter<AppAndRuleAdapter.Holder>() {
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<AppAndRuleItem> by Delegates.observable(emptyList()) { _, _, _ -> notifyDataSetChanged() }
@ -67,6 +68,7 @@ class AppAndRuleAdapter: RecyclerView.Adapter<AppAndRuleAdapter.Holder>() {
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<AppAndRuleAdapter.Holder>() {
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<AppAndRuleAdapter.Holder>() {
}
AppAndRuleItem.ExpandRulesItem -> {/* nothing to do */}
AppAndRuleItem.RulesIntro -> {/* nothing to do */}
AppAndRuleItem.AddRuleItem -> {/* nothing to do */}
}.let { }
}

View file

@ -25,4 +25,5 @@ sealed class AppAndRuleItem {
data class RuleEntry(val rule: TimeLimitRule): AppAndRuleItem()
object ExpandRulesItem: AppAndRuleItem()
object RulesIntro: AppAndRuleItem()
object AddRuleItem: AppAndRuleItem()
}

View file

@ -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<AppAndRuleItem>) { 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(

View file

@ -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<List<TimeLimitRule>> 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) }
}
}

View file

@ -1,27 +0,0 @@
<!--
TimeLimit Copyright <C> 2019 Jonas Lochmann
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="io.timelimit.android.ui.manage.category.timelimit_rules.CategoryTimeLimitRulesFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>