mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-05 19:42:20 +02:00
Create AppAndRuleAdapter
This commit is contained in:
parent
770b5cdf11
commit
8b4e8432f7
9 changed files with 236 additions and 22 deletions
|
@ -23,6 +23,7 @@ import io.timelimit.android.R
|
|||
import io.timelimit.android.databinding.AddItemViewBinding
|
||||
import io.timelimit.android.databinding.FragmentCategoryAppsItemBinding
|
||||
import io.timelimit.android.logic.DefaultAppLogic
|
||||
import io.timelimit.android.ui.manage.category.appsandrules.AppAndRuleItem
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
class AppAdapter: RecyclerView.Adapter<ViewHolder>() {
|
||||
|
@ -31,14 +32,14 @@ class AppAdapter: RecyclerView.Adapter<ViewHolder>() {
|
|||
private const val TYPE_ADD = 2
|
||||
}
|
||||
|
||||
var data: List<AppEntry>? by Delegates.observable(null as List<AppEntry>?) { _, _, _ -> notifyDataSetChanged() }
|
||||
var handlers: Handlers? by Delegates.observable(null as Handlers?) { _, _, _ -> notifyDataSetChanged() }
|
||||
var data: List<AppAndRuleItem.AppEntry>? by Delegates.observable(null as List<AppAndRuleItem.AppEntry>?) { _, _, _ -> notifyDataSetChanged() }
|
||||
var handlers: AppAdapterHandlers? by Delegates.observable(null as AppAdapterHandlers?) { _, _, _ -> notifyDataSetChanged() }
|
||||
|
||||
init {
|
||||
setHasStableIds(true)
|
||||
}
|
||||
|
||||
private fun getItem(position: Int): AppEntry {
|
||||
private fun getItem(position: Int): AppAndRuleItem.AppEntry {
|
||||
return data!![position]
|
||||
}
|
||||
|
||||
|
@ -112,9 +113,7 @@ class AppAdapter: RecyclerView.Adapter<ViewHolder>() {
|
|||
open class ViewHolder(view: View): RecyclerView.ViewHolder(view)
|
||||
class AppViewHolder(val binding: FragmentCategoryAppsItemBinding): ViewHolder(binding.root)
|
||||
|
||||
data class AppEntry(val title: String, val packageName: String, val packageNameWithoutActivityName: String)
|
||||
|
||||
interface Handlers {
|
||||
fun onAppClicked(app: AppEntry)
|
||||
interface AppAdapterHandlers {
|
||||
fun onAppClicked(app: AppAndRuleItem.AppEntry)
|
||||
fun onAddAppsClicked()
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ 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.apps.add.AddCategoryAppsFragment
|
||||
import io.timelimit.android.ui.manage.category.appsandrules.AppAndRuleItem
|
||||
import kotlinx.android.synthetic.main.fragment_category_apps.*
|
||||
|
||||
class CategoryAppsFragment : Fragment() {
|
||||
|
@ -42,9 +43,9 @@ class CategoryAppsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private val params: ManageCategoryFragmentArgs by lazy { ManageCategoryFragmentArgs.fromBundle(arguments!!) }
|
||||
private val database: Database by lazy { DefaultAppLogic.with(context!!).database }
|
||||
private val auth: ActivityViewModel by lazy { getActivityViewModel(activity!!) }
|
||||
private val params: ManageCategoryFragmentArgs by lazy { ManageCategoryFragmentArgs.fromBundle(requireArguments()) }
|
||||
private val database: Database by lazy { DefaultAppLogic.with(requireContext()).database }
|
||||
private val auth: ActivityViewModel by lazy { getActivityViewModel(requireActivity()) }
|
||||
private val model: CategoryAppsModel by lazy {
|
||||
ViewModelProviders.of(this).get(CategoryAppsModel::class.java)
|
||||
}
|
||||
|
@ -58,8 +59,8 @@ class CategoryAppsFragment : Fragment() {
|
|||
|
||||
val adapter = AppAdapter()
|
||||
|
||||
adapter.handlers = object: Handlers {
|
||||
override fun onAppClicked(app: AppEntry) {
|
||||
adapter.handlers = object: AppAdapterHandlers {
|
||||
override fun onAppClicked(app: AppAndRuleItem.AppEntry) {
|
||||
if (auth.tryDispatchParentAction(
|
||||
RemoveCategoryAppsAction(
|
||||
categoryId = params.categoryId,
|
||||
|
@ -90,7 +91,7 @@ class CategoryAppsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
recycler.layoutManager = LinearLayoutManager(context!!)
|
||||
recycler.layoutManager = LinearLayoutManager(requireContext())
|
||||
recycler.adapter = adapter
|
||||
|
||||
model.init(params)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2020 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
|
||||
|
@ -22,6 +22,7 @@ import io.timelimit.android.livedata.map
|
|||
import io.timelimit.android.livedata.switchMap
|
||||
import io.timelimit.android.logic.DefaultAppLogic
|
||||
import io.timelimit.android.ui.manage.category.ManageCategoryFragmentArgs
|
||||
import io.timelimit.android.ui.manage.category.appsandrules.AppAndRuleItem
|
||||
import java.util.*
|
||||
|
||||
class CategoryAppsModel(application: Application): AndroidViewModel(application) {
|
||||
|
@ -50,9 +51,9 @@ class CategoryAppsModel(application: Application): AndroidViewModel(application)
|
|||
val appEntries = appsOfCategoryWithNames.map { apps ->
|
||||
apps.map { (app, appEntry) ->
|
||||
if (appEntry != null) {
|
||||
AppEntry(appEntry.title, app.packageName, app.packageNameWithoutActivityName)
|
||||
AppAndRuleItem.AppEntry(appEntry.title, app.packageName, app.packageNameWithoutActivityName)
|
||||
} else {
|
||||
AppEntry("app not found", app.packageName, app.packageNameWithoutActivityName)
|
||||
AppAndRuleItem.AppEntry("app not found", app.packageName, app.packageNameWithoutActivityName)
|
||||
}
|
||||
}.sortedBy { it.title.toLowerCase(Locale.US) }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2020 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/>.
|
||||
*/
|
||||
|
||||
package io.timelimit.android.ui.manage.category.appsandrules
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.timelimit.android.R
|
||||
import io.timelimit.android.data.model.UsedTimeItem
|
||||
import io.timelimit.android.databinding.*
|
||||
import io.timelimit.android.extensions.MinuteOfDay
|
||||
import io.timelimit.android.logic.DefaultAppLogic
|
||||
import io.timelimit.android.ui.manage.category.apps.AppAdapterHandlers
|
||||
import io.timelimit.android.ui.manage.category.timelimit_rules.TimeLimitRulesHandlers
|
||||
import io.timelimit.android.util.JoinUtil
|
||||
import io.timelimit.android.util.TimeTextUtil
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
class AppAndRuleAdapter: RecyclerView.Adapter<AppAndRuleAdapter.Holder>() {
|
||||
companion object {
|
||||
private const val APP_ENTRY = 1
|
||||
private const val ADD_APP_ITEM = 2
|
||||
private const val EXPAND_APPS_ITEM = 3
|
||||
private const val RULE_ENTRY = 4
|
||||
private const val EXPAND_RULES_ITEM = 5
|
||||
private const val RULES_INTRO = 6
|
||||
}
|
||||
|
||||
var items: List<AppAndRuleItem> by Delegates.observable(emptyList()) { _, _, _ -> notifyDataSetChanged() }
|
||||
var usedTimes: List<UsedTimeItem> by Delegates.observable(emptyList()) { _, _, _ -> notifyDataSetChanged() }
|
||||
var epochDayOfStartOfWeek: Int by Delegates.observable(0) { _, _, _ -> notifyDataSetChanged() }
|
||||
var handlers: Handlers? = null
|
||||
|
||||
init {
|
||||
setHasStableIds(true)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = items.size
|
||||
|
||||
override fun getItemId(position: Int): Long = items[position].let { item ->
|
||||
when (item) {
|
||||
is AppAndRuleItem.AppEntry -> item.packageName.hashCode()
|
||||
is AppAndRuleItem.RuleEntry -> item.rule.id.hashCode()
|
||||
else -> item.hashCode()
|
||||
}
|
||||
}.toLong()
|
||||
|
||||
override fun getItemViewType(position: Int): Int = when (items[position]) {
|
||||
is AppAndRuleItem.AppEntry -> APP_ENTRY
|
||||
AppAndRuleItem.AddAppItem -> ADD_APP_ITEM
|
||||
AppAndRuleItem.ExpandAppsItem -> EXPAND_APPS_ITEM
|
||||
is AppAndRuleItem.RuleEntry -> RULE_ENTRY
|
||||
AppAndRuleItem.ExpandRulesItem -> EXPAND_RULES_ITEM
|
||||
AppAndRuleItem.RulesIntro -> RULES_INTRO
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder = Holder(
|
||||
when (viewType) {
|
||||
APP_ENTRY -> FragmentCategoryAppsItemBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
).also { it.root.tag = it }.root
|
||||
ADD_APP_ITEM -> AddItemViewBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
).apply {
|
||||
label = parent.context.getString(R.string.category_apps_add_dialog_btn_positive)
|
||||
wide = true
|
||||
|
||||
root.setOnClickListener { handlers?.onAddAppsClicked() }
|
||||
}.root
|
||||
EXPAND_APPS_ITEM -> ShowMoreListItemBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
).root.also { it.setOnClickListener { handlers?.onShowAllApps() } }
|
||||
RULE_ENTRY -> FragmentCategoryTimeLimitRuleItemBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
).also { it.root.tag = it }.root
|
||||
EXPAND_RULES_ITEM -> ShowMoreListItemBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
).root.also { it.setOnClickListener { handlers?.onShowAllRules() } }
|
||||
RULES_INTRO -> TimeLimitRuleIntroductionBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
).root
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
)
|
||||
|
||||
override fun onBindViewHolder(holder: Holder, position: Int) {
|
||||
val item = items[position]
|
||||
|
||||
when (item) {
|
||||
is AppAndRuleItem.AppEntry -> {
|
||||
val binding = holder.itemView.tag as FragmentCategoryAppsItemBinding
|
||||
|
||||
binding.item = item
|
||||
binding.handlers = handlers
|
||||
binding.executePendingBindings()
|
||||
|
||||
binding.icon.setImageDrawable(
|
||||
DefaultAppLogic.with(binding.root.context)
|
||||
.platformIntegration.getAppIcon(item.packageNameWithoutActivityName)
|
||||
)
|
||||
}
|
||||
AppAndRuleItem.AddAppItem -> {/* nothing to do */}
|
||||
AppAndRuleItem.ExpandAppsItem -> {/* nothing to do */}
|
||||
is AppAndRuleItem.RuleEntry -> {
|
||||
val rule = item.rule
|
||||
val binding = holder.itemView.tag as FragmentCategoryTimeLimitRuleItemBinding
|
||||
val context = binding.root.context
|
||||
val dayNames = binding.root.resources.getStringArray(R.array.days_of_week_array)
|
||||
val usedTime = usedTimes.filter { usedTime ->
|
||||
val dayOfWeek = usedTime.dayOfEpoch - epochDayOfStartOfWeek
|
||||
usedTime.startTimeOfDay == rule.startMinuteOfDay && usedTime.endTimeOfDay == rule.endMinuteOfDay &&
|
||||
(rule.dayMask.toInt() and (1 shl dayOfWeek) != 0)
|
||||
}.map { it.usedMillis }.sum().toInt()
|
||||
|
||||
binding.maxTimeString = TimeTextUtil.time(rule.maximumTimeInMillis, context)
|
||||
binding.usageAsText = TimeTextUtil.used(usedTime, context)
|
||||
binding.usageProgressInPercent = if (rule.maximumTimeInMillis > 0)
|
||||
(usedTime * 100 / rule.maximumTimeInMillis)
|
||||
else
|
||||
100
|
||||
binding.daysString = JoinUtil.join(
|
||||
dayNames.filterIndexed { index, _ -> (rule.dayMask.toInt() and (1 shl index)) != 0 },
|
||||
context
|
||||
)
|
||||
binding.timeAreaString = if (rule.appliesToWholeDay)
|
||||
null
|
||||
else
|
||||
context.getString(
|
||||
R.string.category_time_limit_rules_time_area,
|
||||
MinuteOfDay.format(rule.startMinuteOfDay),
|
||||
MinuteOfDay.format(rule.endMinuteOfDay)
|
||||
)
|
||||
binding.appliesToExtraTime = rule.applyToExtraTimeUsage
|
||||
binding.sessionLimitString = if (rule.sessionDurationLimitEnabled)
|
||||
context.getString(
|
||||
R.string.category_time_limit_rules_session_limit,
|
||||
TimeTextUtil.time(rule.sessionPauseMilliseconds, context),
|
||||
TimeTextUtil.time(rule.sessionDurationMilliseconds, context)
|
||||
)
|
||||
else
|
||||
null
|
||||
|
||||
binding.card.setOnClickListener { handlers?.onTimeLimitRuleClicked(rule) }
|
||||
|
||||
binding.executePendingBindings()
|
||||
}
|
||||
AppAndRuleItem.ExpandRulesItem -> {/* nothing to do */}
|
||||
AppAndRuleItem.RulesIntro -> {/* nothing to do */}
|
||||
}.let { }
|
||||
}
|
||||
|
||||
class Holder(view: View): RecyclerView.ViewHolder(view)
|
||||
}
|
||||
|
||||
interface Handlers: AppAdapterHandlers, TimeLimitRulesHandlers {
|
||||
fun onShowAllApps()
|
||||
fun onShowAllRules()
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2020 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/>.
|
||||
*/
|
||||
|
||||
package io.timelimit.android.ui.manage.category.appsandrules
|
||||
|
||||
import io.timelimit.android.data.model.TimeLimitRule
|
||||
|
||||
sealed class AppAndRuleItem {
|
||||
data class AppEntry(val title: String, val packageName: String, val packageNameWithoutActivityName: String): AppAndRuleItem()
|
||||
object AddAppItem: AppAndRuleItem()
|
||||
object ExpandAppsItem: AppAndRuleItem()
|
||||
data class RuleEntry(val rule: TimeLimitRule): AppAndRuleItem()
|
||||
object ExpandRulesItem: AppAndRuleItem()
|
||||
object RulesIntro: AppAndRuleItem()
|
||||
}
|
|
@ -40,7 +40,7 @@ class Adapter: RecyclerView.Adapter<ViewHolder>() {
|
|||
var data: List<TimeLimitRuleItem> by Delegates.observable(emptyList()) { _, _, _ -> notifyDataSetChanged() }
|
||||
var usedTimes: List<UsedTimeItem> by Delegates.observable(emptyList()) { _, _, _ -> notifyDataSetChanged() }
|
||||
var epochDayOfStartOfWeek: Int by Delegates.observable(0) { _, _, _ -> notifyDataSetChanged() }
|
||||
var handlers: Handlers? = null
|
||||
var handlers: TimeLimitRulesHandlers? = null
|
||||
|
||||
init {
|
||||
setHasStableIds(true)
|
||||
|
@ -160,7 +160,7 @@ class Adapter: RecyclerView.Adapter<ViewHolder>() {
|
|||
open class ViewHolder(view: View): RecyclerView.ViewHolder(view)
|
||||
class ItemViewHolder(val view: FragmentCategoryTimeLimitRuleItemBinding): ViewHolder(view.root)
|
||||
|
||||
interface Handlers {
|
||||
interface TimeLimitRulesHandlers {
|
||||
fun onTimeLimitRuleClicked(rule: TimeLimitRule)
|
||||
fun onAddTimeLimitRuleClicked()
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ class CategoryTimeLimitRulesFragment : Fragment(), EditTimeLimitRuleDialogFragme
|
|||
adapter.data = it
|
||||
})
|
||||
|
||||
adapter.handlers = object: Handlers {
|
||||
adapter.handlers = object: TimeLimitRulesHandlers {
|
||||
override fun onTimeLimitRuleClicked(rule: TimeLimitRule) {
|
||||
if (auth.requestAuthenticationOrReturnTrue()) {
|
||||
EditTimeLimitRuleDialogFragment.newInstance(rule, this@CategoryTimeLimitRulesFragment).show(fragmentManager!!)
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
<data>
|
||||
<variable
|
||||
name="item"
|
||||
type="io.timelimit.android.ui.manage.category.apps.AppEntry" />
|
||||
type="io.timelimit.android.ui.manage.category.appsandrules.AppAndRuleItem.AppEntry" />
|
||||
|
||||
<variable
|
||||
name="handlers"
|
||||
type="io.timelimit.android.ui.manage.category.apps.Handlers" />
|
||||
type="io.timelimit.android.ui.manage.category.apps.AppAdapterHandlers" />
|
||||
|
||||
<import type="android.view.View" />
|
||||
</data>
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
|
||||
<variable
|
||||
name="handlers"
|
||||
type="io.timelimit.android.ui.manage.category.timelimit_rules.Handlers" />
|
||||
type="io.timelimit.android.ui.manage.category.timelimit_rules.TimeLimitRulesHandlers" />
|
||||
|
||||
<import type="android.view.View" />
|
||||
<import type="android.text.TextUtils" />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue