mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 09:49:25 +02:00
Add option to assign all system apps without category
This commit is contained in:
parent
c40b2298d4
commit
1821e697cf
22 changed files with 119 additions and 30 deletions
|
@ -31,6 +31,7 @@ abstract class PlatformIntegration(
|
||||||
abstract fun getLocalAppActivities(deviceId: String): Collection<AppActivity>
|
abstract fun getLocalAppActivities(deviceId: String): Collection<AppActivity>
|
||||||
abstract fun getLocalAppTitle(packageName: String): String?
|
abstract fun getLocalAppTitle(packageName: String): String?
|
||||||
abstract fun getAppIcon(packageName: String): Drawable?
|
abstract fun getAppIcon(packageName: String): Drawable?
|
||||||
|
abstract fun isSystemImageApp(packageName: String): Boolean
|
||||||
abstract fun getLauncherAppPackageName(): String?
|
abstract fun getLauncherAppPackageName(): String?
|
||||||
abstract fun getCurrentProtectionLevel(): ProtectionLevel
|
abstract fun getCurrentProtectionLevel(): ProtectionLevel
|
||||||
abstract fun getForegroundAppPermissionStatus(): RuntimePermissionStatus
|
abstract fun getForegroundAppPermissionStatus(): RuntimePermissionStatus
|
||||||
|
|
|
@ -34,6 +34,7 @@ import android.provider.Settings
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.collection.LruCache
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
@ -116,6 +117,18 @@ class AndroidIntegration(context: Context): PlatformIntegration(maximumProtectio
|
||||||
return AndroidIntegrationApps.getAppIcon(packageName, context)
|
return AndroidIntegrationApps.getAppIcon(packageName, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val isSystemImageAppCache = object: LruCache<String, Boolean>(8) {
|
||||||
|
override fun create(key: String): Boolean? = try {
|
||||||
|
val appInfo: ApplicationInfo = context.packageManager.getApplicationInfo(key, 0)
|
||||||
|
|
||||||
|
appInfo.flags and ApplicationInfo.FLAG_SYSTEM == ApplicationInfo.FLAG_SYSTEM
|
||||||
|
} catch (ex: PackageManager.NameNotFoundException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isSystemImageApp(packageName: String): Boolean = isSystemImageAppCache.get(packageName) ?: false
|
||||||
|
|
||||||
override fun getLauncherAppPackageName(): String? {
|
override fun getLauncherAppPackageName(): String? {
|
||||||
return Intent(Intent.ACTION_MAIN)
|
return Intent(Intent.ACTION_MAIN)
|
||||||
.addCategory(Intent.CATEGORY_HOME)
|
.addCategory(Intent.CATEGORY_HOME)
|
||||||
|
|
|
@ -18,8 +18,6 @@ package io.timelimit.android.integration.platform.android
|
||||||
import android.annotation.TargetApi
|
import android.annotation.TargetApi
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.ApplicationInfo
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.service.notification.NotificationListenerService
|
import android.service.notification.NotificationListenerService
|
||||||
import android.service.notification.StatusBarNotification
|
import android.service.notification.StatusBarNotification
|
||||||
|
@ -153,16 +151,19 @@ class NotificationListener: NotificationListenerService() {
|
||||||
return if (deviceAndUserRelatedData?.userRelatedData?.user?.type != UserType.Child) {
|
return if (deviceAndUserRelatedData?.userRelatedData?.user?.type != UserType.Child) {
|
||||||
BlockingReason.None
|
BlockingReason.None
|
||||||
} else {
|
} else {
|
||||||
|
val isSystemImageApp = appLogic.platformIntegration.isSystemImageApp(sbn.packageName)
|
||||||
|
|
||||||
val appHandling = AppBaseHandling.calculate(
|
val appHandling = AppBaseHandling.calculate(
|
||||||
foregroundAppPackageName = sbn.packageName,
|
foregroundAppPackageName = sbn.packageName,
|
||||||
foregroundAppActivityName = null,
|
foregroundAppActivityName = null,
|
||||||
pauseCounting = false,
|
pauseCounting = false,
|
||||||
pauseForegroundAppBackgroundLoop = false,
|
pauseForegroundAppBackgroundLoop = false,
|
||||||
userRelatedData = deviceAndUserRelatedData.userRelatedData,
|
userRelatedData = deviceAndUserRelatedData.userRelatedData,
|
||||||
deviceRelatedData = deviceAndUserRelatedData.deviceRelatedData
|
deviceRelatedData = deviceAndUserRelatedData.deviceRelatedData,
|
||||||
|
isSystemImageApp = isSystemImageApp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (appHandling is AppBaseHandling.BlockDueToNoCategory && !isSystemApp(sbn.packageName)) {
|
if (appHandling is AppBaseHandling.BlockDueToNoCategory && !isSystemImageApp) {
|
||||||
BlockingReason.NotPartOfAnCategory
|
BlockingReason.NotPartOfAnCategory
|
||||||
} else if (appHandling is AppBaseHandling.UseCategories) {
|
} else if (appHandling is AppBaseHandling.UseCategories) {
|
||||||
val time = RealTime.newInstance()
|
val time = RealTime.newInstance()
|
||||||
|
@ -201,14 +202,4 @@ class NotificationListener: NotificationListenerService() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isSystemApp(packageName: String): Boolean {
|
|
||||||
try {
|
|
||||||
val appInfo = packageManager.getApplicationInfo(packageName, 0)
|
|
||||||
|
|
||||||
return appInfo.flags and ApplicationInfo.FLAG_SYSTEM == ApplicationInfo.FLAG_SYSTEM
|
|
||||||
} catch (ex: PackageManager.NameNotFoundException) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -55,6 +55,8 @@ class DummyIntegration(
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isSystemImageApp(packageName: String): Boolean = false
|
||||||
|
|
||||||
override fun getLauncherAppPackageName(): String? = null
|
override fun getLauncherAppPackageName(): String? = null
|
||||||
|
|
||||||
override fun getCurrentProtectionLevel(): ProtectionLevel {
|
override fun getCurrentProtectionLevel(): ProtectionLevel {
|
||||||
|
|
|
@ -55,7 +55,8 @@ object AppAffectedByPrimaryDeviceUtil {
|
||||||
deviceRelatedData = deviceAndUserRelatedData.deviceRelatedData,
|
deviceRelatedData = deviceAndUserRelatedData.deviceRelatedData,
|
||||||
userRelatedData = deviceAndUserRelatedData.userRelatedData,
|
userRelatedData = deviceAndUserRelatedData.userRelatedData,
|
||||||
pauseCounting = false,
|
pauseCounting = false,
|
||||||
pauseForegroundAppBackgroundLoop = false
|
pauseForegroundAppBackgroundLoop = false,
|
||||||
|
isSystemImageApp = logic.platformIntegration.isSystemImageApp(currentApp.packageName)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!(handling is AppBaseHandling.UseCategories)) {
|
if (!(handling is AppBaseHandling.UseCategories)) {
|
||||||
|
|
|
@ -294,7 +294,8 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
pauseForegroundAppBackgroundLoop = pauseForegroundAppBackgroundLoop,
|
pauseForegroundAppBackgroundLoop = pauseForegroundAppBackgroundLoop,
|
||||||
userRelatedData = userRelatedData,
|
userRelatedData = userRelatedData,
|
||||||
deviceRelatedData = deviceRelatedData,
|
deviceRelatedData = deviceRelatedData,
|
||||||
pauseCounting = !isScreenOn
|
pauseCounting = !isScreenOn,
|
||||||
|
isSystemImageApp = appLogic.platformIntegration.isSystemImageApp(app.packageName)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +305,8 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
||||||
pauseForegroundAppBackgroundLoop = false,
|
pauseForegroundAppBackgroundLoop = false,
|
||||||
userRelatedData = userRelatedData,
|
userRelatedData = userRelatedData,
|
||||||
deviceRelatedData = deviceRelatedData,
|
deviceRelatedData = deviceRelatedData,
|
||||||
pauseCounting = false
|
pauseCounting = false,
|
||||||
|
isSystemImageApp = audioPlaybackPackageName?.let { appLogic.platformIntegration.isSystemImageApp(it) } ?: false
|
||||||
)
|
)
|
||||||
|
|
||||||
val allAppsBaseHandlings = foregroundAppWithBaseHandlings.map { it.second } + listOf(backgroundAppBaseHandling)
|
val allAppsBaseHandlings = foregroundAppWithBaseHandlings.map { it.second } + listOf(backgroundAppBaseHandling)
|
||||||
|
|
47
app/src/main/java/io/timelimit/android/logic/DummyApps.kt
Normal file
47
app/src/main/java/io/timelimit/android/logic/DummyApps.kt
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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.logic
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import io.timelimit.android.R
|
||||||
|
import io.timelimit.android.data.model.App
|
||||||
|
import io.timelimit.android.data.model.AppRecommendation
|
||||||
|
|
||||||
|
object DummyApps {
|
||||||
|
const val NOT_ASSIGNED_SYSTEM_IMAGE_APP = ".dummy.system_image"
|
||||||
|
|
||||||
|
fun getTitle(packageName: String, context: Context): String? = when (packageName) {
|
||||||
|
NOT_ASSIGNED_SYSTEM_IMAGE_APP -> context.getString(R.string.dummy_app_unassigned_system_image_app)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getIcon(packageName: String, context: Context): Drawable? = when (packageName) {
|
||||||
|
NOT_ASSIGNED_SYSTEM_IMAGE_APP -> ContextCompat.getDrawable(context, R.mipmap.ic_system_app)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getApps(deviceId: String, context: Context): List<App> = listOf(
|
||||||
|
App(
|
||||||
|
deviceId = deviceId,
|
||||||
|
packageName = NOT_ASSIGNED_SYSTEM_IMAGE_APP,
|
||||||
|
title = getTitle(NOT_ASSIGNED_SYSTEM_IMAGE_APP, context)!!,
|
||||||
|
isLaunchable = false,
|
||||||
|
recommendation = AppRecommendation.None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
|
@ -171,6 +171,7 @@ class SuspendAppsLogic(private val appLogic: AppLogic): Observer {
|
||||||
|
|
||||||
private fun getAppsWithCategories(packageNames: List<String>, data: UserRelatedData, blockingAtActivityLevel: Boolean): Map<String, Set<String>> {
|
private fun getAppsWithCategories(packageNames: List<String>, data: UserRelatedData, blockingAtActivityLevel: Boolean): Map<String, Set<String>> {
|
||||||
val categoryForUnassignedApps = data.categoryById[data.user.categoryForNotAssignedApps]
|
val categoryForUnassignedApps = data.categoryById[data.user.categoryForNotAssignedApps]
|
||||||
|
val categoryForOtherSystemApps = data.findCategoryApp(DummyApps.NOT_ASSIGNED_SYSTEM_IMAGE_APP)?.categoryId?.let { data.categoryById[it] }
|
||||||
|
|
||||||
if (blockingAtActivityLevel) {
|
if (blockingAtActivityLevel) {
|
||||||
val categoriesByPackageName = data.categoryApps.groupBy { it.packageNameWithoutActivityName }
|
val categoriesByPackageName = data.categoryApps.groupBy { it.packageNameWithoutActivityName }
|
||||||
|
@ -183,7 +184,9 @@ class SuspendAppsLogic(private val appLogic: AppLogic): Observer {
|
||||||
val isMainAppIncluded = categoriesItems?.find { !it.specifiesActivity } != null
|
val isMainAppIncluded = categoriesItems?.find { !it.specifiesActivity } != null
|
||||||
|
|
||||||
if (!isMainAppIncluded) {
|
if (!isMainAppIncluded) {
|
||||||
if (categoryForUnassignedApps != null) {
|
if (categoryForOtherSystemApps != null && appLogic.platformIntegration.isSystemImageApp(packageName)) {
|
||||||
|
categories.add(categoryForOtherSystemApps.category.id)
|
||||||
|
} else if (categoryForUnassignedApps != null) {
|
||||||
categories.add(categoryForUnassignedApps.category.id)
|
categories.add(categoryForUnassignedApps.category.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,7 +201,10 @@ class SuspendAppsLogic(private val appLogic: AppLogic): Observer {
|
||||||
val result = mutableMapOf<String, Set<String>>()
|
val result = mutableMapOf<String, Set<String>>()
|
||||||
|
|
||||||
packageNames.forEach { packageName ->
|
packageNames.forEach { packageName ->
|
||||||
val category = categoryByPackageName[packageName]?.categoryId ?: categoryForUnassignedApps?.category?.id
|
val category = categoryByPackageName[packageName]?.categoryId ?: run {
|
||||||
|
if (categoryForOtherSystemApps != null && appLogic.platformIntegration.isSystemImageApp(packageName))
|
||||||
|
categoryForOtherSystemApps.category.id else categoryForUnassignedApps?.category?.id
|
||||||
|
}
|
||||||
|
|
||||||
result[packageName] = if (category != null) setOf(category) else emptySet()
|
result[packageName] = if (category != null) setOf(category) else emptySet()
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import io.timelimit.android.data.model.derived.DeviceRelatedData
|
||||||
import io.timelimit.android.data.model.derived.UserRelatedData
|
import io.timelimit.android.data.model.derived.UserRelatedData
|
||||||
import io.timelimit.android.integration.platform.android.AndroidIntegrationApps
|
import io.timelimit.android.integration.platform.android.AndroidIntegrationApps
|
||||||
import io.timelimit.android.logic.BlockingLevel
|
import io.timelimit.android.logic.BlockingLevel
|
||||||
|
import io.timelimit.android.logic.DummyApps
|
||||||
|
|
||||||
sealed class AppBaseHandling {
|
sealed class AppBaseHandling {
|
||||||
object Idle: AppBaseHandling()
|
object Idle: AppBaseHandling()
|
||||||
|
@ -49,7 +50,8 @@ sealed class AppBaseHandling {
|
||||||
pauseForegroundAppBackgroundLoop: Boolean,
|
pauseForegroundAppBackgroundLoop: Boolean,
|
||||||
pauseCounting: Boolean,
|
pauseCounting: Boolean,
|
||||||
userRelatedData: UserRelatedData,
|
userRelatedData: UserRelatedData,
|
||||||
deviceRelatedData: DeviceRelatedData
|
deviceRelatedData: DeviceRelatedData,
|
||||||
|
isSystemImageApp: Boolean
|
||||||
): AppBaseHandling {
|
): AppBaseHandling {
|
||||||
if (pauseForegroundAppBackgroundLoop) {
|
if (pauseForegroundAppBackgroundLoop) {
|
||||||
return PauseLogic
|
return PauseLogic
|
||||||
|
@ -71,7 +73,9 @@ sealed class AppBaseHandling {
|
||||||
} else if (foregroundAppPackageName != null) {
|
} else if (foregroundAppPackageName != null) {
|
||||||
val appCategory = run {
|
val appCategory = run {
|
||||||
val tryActivityLevelBlocking = deviceRelatedData.deviceEntry.enableActivityLevelBlocking && foregroundAppActivityName != null
|
val tryActivityLevelBlocking = deviceRelatedData.deviceEntry.enableActivityLevelBlocking && foregroundAppActivityName != null
|
||||||
val appLevelCategory = userRelatedData.findCategoryApp(foregroundAppPackageName)
|
val appLevelCategory = userRelatedData.findCategoryApp(foregroundAppPackageName) ?: run {
|
||||||
|
if (isSystemImageApp) userRelatedData.findCategoryApp(DummyApps.NOT_ASSIGNED_SYSTEM_IMAGE_APP) else null
|
||||||
|
}
|
||||||
|
|
||||||
(if (tryActivityLevelBlocking) {
|
(if (tryActivityLevelBlocking) {
|
||||||
userRelatedData.findCategoryApp("$foregroundAppPackageName:$foregroundAppActivityName")
|
userRelatedData.findCategoryApp("$foregroundAppPackageName:$foregroundAppActivityName")
|
||||||
|
|
|
@ -96,7 +96,8 @@ class LockModel(application: Application): AndroidViewModel(application) {
|
||||||
deviceRelatedData = deviceAndUserRelatedData.deviceRelatedData,
|
deviceRelatedData = deviceAndUserRelatedData.deviceRelatedData,
|
||||||
userRelatedData = deviceAndUserRelatedData.userRelatedData,
|
userRelatedData = deviceAndUserRelatedData.userRelatedData,
|
||||||
pauseForegroundAppBackgroundLoop = false,
|
pauseForegroundAppBackgroundLoop = false,
|
||||||
pauseCounting = false
|
pauseCounting = false,
|
||||||
|
isSystemImageApp = logic.platformIntegration.isSystemImageApp(packageName)
|
||||||
)
|
)
|
||||||
|
|
||||||
val needsNetworkId = appBaseHandling.needsNetworkId()
|
val needsNetworkId = appBaseHandling.needsNetworkId()
|
||||||
|
|
|
@ -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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,6 +21,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.timelimit.android.data.model.App
|
import io.timelimit.android.data.model.App
|
||||||
import io.timelimit.android.databinding.FragmentAddCategoryAppsItemBinding
|
import io.timelimit.android.databinding.FragmentAddCategoryAppsItemBinding
|
||||||
import io.timelimit.android.logic.DefaultAppLogic
|
import io.timelimit.android.logic.DefaultAppLogic
|
||||||
|
import io.timelimit.android.logic.DummyApps
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
class AddAppAdapter: RecyclerView.Adapter<ViewHolder>() {
|
class AddAppAdapter: RecyclerView.Adapter<ViewHolder>() {
|
||||||
|
@ -61,6 +62,7 @@ class AddAppAdapter: RecyclerView.Adapter<ViewHolder>() {
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val item = getItem(position)
|
val item = getItem(position)
|
||||||
|
val context = holder.itemView.context
|
||||||
|
|
||||||
holder.apply {
|
holder.apply {
|
||||||
binding.item = item
|
binding.item = item
|
||||||
|
@ -70,7 +72,8 @@ class AddAppAdapter: RecyclerView.Adapter<ViewHolder>() {
|
||||||
binding.executePendingBindings()
|
binding.executePendingBindings()
|
||||||
|
|
||||||
binding.icon.setImageDrawable(
|
binding.icon.setImageDrawable(
|
||||||
DefaultAppLogic.with(holder.itemView.context)
|
DummyApps.getIcon(item.packageName, context) ?:
|
||||||
|
DefaultAppLogic.with(context)
|
||||||
.platformIntegration.getAppIcon(item.packageName)
|
.platformIntegration.getAppIcon(item.packageName)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ import io.timelimit.android.livedata.liveDataFromValue
|
||||||
import io.timelimit.android.livedata.map
|
import io.timelimit.android.livedata.map
|
||||||
import io.timelimit.android.livedata.switchMap
|
import io.timelimit.android.livedata.switchMap
|
||||||
import io.timelimit.android.logic.DefaultAppLogic
|
import io.timelimit.android.logic.DefaultAppLogic
|
||||||
|
import io.timelimit.android.logic.DummyApps
|
||||||
import io.timelimit.android.sync.actions.AddCategoryAppsAction
|
import io.timelimit.android.sync.actions.AddCategoryAppsAction
|
||||||
import io.timelimit.android.ui.main.ActivityViewModel
|
import io.timelimit.android.ui.main.ActivityViewModel
|
||||||
import io.timelimit.android.ui.main.getActivityViewModel
|
import io.timelimit.android.ui.main.getActivityViewModel
|
||||||
|
@ -147,6 +148,8 @@ class AddCategoryAppsFragment : DialogFragment() {
|
||||||
|
|
||||||
val installedApps = realShowAppsFromAllDevices.switchMap { appsFromAllDevices ->
|
val installedApps = realShowAppsFromAllDevices.switchMap { appsFromAllDevices ->
|
||||||
if (appsFromAllDevices) appsAtAllDevices else appsAtAssignedDevices
|
if (appsFromAllDevices) appsAtAllDevices else appsAtAssignedDevices
|
||||||
|
}.map { list ->
|
||||||
|
if (list.isEmpty()) list else list + DummyApps.getApps(deviceId = list.first().deviceId, context = requireContext())
|
||||||
}.map { apps -> apps.distinctBy { app -> app.packageName } }
|
}.map { apps -> apps.distinctBy { app -> app.packageName } }
|
||||||
|
|
||||||
val userRelatedDataLive = database.derivedDataDao().getUserRelatedDataLive(childId)
|
val userRelatedDataLive = database.derivedDataDao().getUserRelatedDataLive(childId)
|
||||||
|
|
|
@ -25,6 +25,7 @@ import io.timelimit.android.data.model.UsedTimeItem
|
||||||
import io.timelimit.android.databinding.*
|
import io.timelimit.android.databinding.*
|
||||||
import io.timelimit.android.extensions.MinuteOfDay
|
import io.timelimit.android.extensions.MinuteOfDay
|
||||||
import io.timelimit.android.logic.DefaultAppLogic
|
import io.timelimit.android.logic.DefaultAppLogic
|
||||||
|
import io.timelimit.android.logic.DummyApps
|
||||||
import io.timelimit.android.ui.manage.category.apps.AppAdapterHandlers
|
import io.timelimit.android.ui.manage.category.apps.AppAdapterHandlers
|
||||||
import io.timelimit.android.ui.manage.category.timelimit_rules.TimeLimitRulesHandlers
|
import io.timelimit.android.ui.manage.category.timelimit_rules.TimeLimitRulesHandlers
|
||||||
import io.timelimit.android.util.JoinUtil
|
import io.timelimit.android.util.JoinUtil
|
||||||
|
@ -133,13 +134,15 @@ class AppAndRuleAdapter: RecyclerView.Adapter<AppAndRuleAdapter.Holder>() {
|
||||||
when (item) {
|
when (item) {
|
||||||
is AppAndRuleItem.AppEntry -> {
|
is AppAndRuleItem.AppEntry -> {
|
||||||
val binding = holder.itemView.tag as FragmentCategoryAppsItemBinding
|
val binding = holder.itemView.tag as FragmentCategoryAppsItemBinding
|
||||||
|
val context = binding.root.context
|
||||||
|
|
||||||
binding.item = item
|
binding.item = item
|
||||||
binding.handlers = handlers
|
binding.handlers = handlers
|
||||||
binding.executePendingBindings()
|
binding.executePendingBindings()
|
||||||
|
|
||||||
binding.icon.setImageDrawable(
|
binding.icon.setImageDrawable(
|
||||||
DefaultAppLogic.with(binding.root.context)
|
DummyApps.getIcon(item.packageNameWithoutActivityName, context) ?:
|
||||||
|
DefaultAppLogic.with(context)
|
||||||
.platformIntegration.getAppIcon(item.packageNameWithoutActivityName)
|
.platformIntegration.getAppIcon(item.packageNameWithoutActivityName)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import io.timelimit.android.extensions.takeDistributedElements
|
||||||
import io.timelimit.android.livedata.map
|
import io.timelimit.android.livedata.map
|
||||||
import io.timelimit.android.livedata.switchMap
|
import io.timelimit.android.livedata.switchMap
|
||||||
import io.timelimit.android.logic.DefaultAppLogic
|
import io.timelimit.android.logic.DefaultAppLogic
|
||||||
|
import io.timelimit.android.logic.DummyApps
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class AppsAndRulesModel(application: Application): AndroidViewModel(application) {
|
class AppsAndRulesModel(application: Application): AndroidViewModel(application) {
|
||||||
|
@ -114,15 +115,18 @@ class AppsAndRulesModel(application: Application): AndroidViewModel(application)
|
||||||
private val appsOfCategoryWithNames = installedApps.switchMap { allApps ->
|
private val appsOfCategoryWithNames = installedApps.switchMap { allApps ->
|
||||||
appsOfThisCategory.map { apps ->
|
appsOfThisCategory.map { apps ->
|
||||||
apps.map { categoryApp ->
|
apps.map { categoryApp ->
|
||||||
categoryApp to allApps.find { app -> app.packageName == categoryApp.packageNameWithoutActivityName }
|
val title = DummyApps.getTitle(categoryApp.packageNameWithoutActivityName, getApplication()) ?:
|
||||||
|
allApps.find { app -> app.packageName == categoryApp.packageNameWithoutActivityName }?.title
|
||||||
|
|
||||||
|
categoryApp to title
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val appEntries = appsOfCategoryWithNames.map { apps ->
|
private val appEntries = appsOfCategoryWithNames.map { apps ->
|
||||||
apps.map { (app, appEntry) ->
|
apps.map { (app, title) ->
|
||||||
if (appEntry != null) {
|
if (title != null) {
|
||||||
AppAndRuleItem.AppEntry(appEntry.title, app.packageName, app.packageNameWithoutActivityName)
|
AppAndRuleItem.AppEntry(title, app.packageName, app.packageNameWithoutActivityName)
|
||||||
} else {
|
} else {
|
||||||
AppAndRuleItem.AppEntry("app not found", app.packageName, app.packageNameWithoutActivityName)
|
AppAndRuleItem.AppEntry("app not found", app.packageName, app.packageNameWithoutActivityName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import io.timelimit.android.databinding.FragmentChildAppsItemBinding
|
||||||
import io.timelimit.android.databinding.GenericBigListHeaderBinding
|
import io.timelimit.android.databinding.GenericBigListHeaderBinding
|
||||||
import io.timelimit.android.databinding.GenericListHeaderBinding
|
import io.timelimit.android.databinding.GenericListHeaderBinding
|
||||||
import io.timelimit.android.logic.DefaultAppLogic
|
import io.timelimit.android.logic.DefaultAppLogic
|
||||||
|
import io.timelimit.android.logic.DummyApps
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
class ChildAppsAdapter: RecyclerView.Adapter<ChildAppsHolder>() {
|
class ChildAppsAdapter: RecyclerView.Adapter<ChildAppsHolder>() {
|
||||||
|
@ -101,10 +102,13 @@ class ChildAppsAdapter: RecyclerView.Adapter<ChildAppsHolder>() {
|
||||||
is ChildAppsApp -> {
|
is ChildAppsApp -> {
|
||||||
holder as AppHolder
|
holder as AppHolder
|
||||||
|
|
||||||
|
val context = holder.binding.root.context
|
||||||
|
|
||||||
holder.binding.item = item.app
|
holder.binding.item = item.app
|
||||||
holder.binding.currentCategoryTitle = item.shownCategoryName
|
holder.binding.currentCategoryTitle = item.shownCategoryName
|
||||||
holder.binding.icon.setImageDrawable(
|
holder.binding.icon.setImageDrawable(
|
||||||
DefaultAppLogic.with(holder.binding.root.context).platformIntegration.getAppIcon(item.app.packageName)
|
DummyApps.getIcon(item.app.packageName, context) ?:
|
||||||
|
DefaultAppLogic.with(context).platformIntegration.getAppIcon(item.app.packageName)
|
||||||
)
|
)
|
||||||
holder.binding.handlers = handlers
|
holder.binding.handlers = handlers
|
||||||
holder.binding.executePendingBindings()
|
holder.binding.executePendingBindings()
|
||||||
|
|
BIN
app/src/main/res/mipmap-hdpi/ic_system_app.png
Normal file
BIN
app/src/main/res/mipmap-hdpi/ic_system_app.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_system_app.png
Normal file
BIN
app/src/main/res/mipmap-mdpi/ic_system_app.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_system_app.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/ic_system_app.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_system_app.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/ic_system_app.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_system_app.png
Normal file
BIN
app/src/main/res/mipmap-xxxhdpi/ic_system_app.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
|
@ -1514,4 +1514,6 @@
|
||||||
<string name="task_review_text">%1$s hat angegeben, %2$s erledigt zu haben. Ist das richtig?</string>
|
<string name="task_review_text">%1$s hat angegeben, %2$s erledigt zu haben. Ist das richtig?</string>
|
||||||
<string name="task_review_category">Dafür wird es %1$s Extrazeit für %2$s geben</string>
|
<string name="task_review_category">Dafür wird es %1$s Extrazeit für %2$s geben</string>
|
||||||
<string name="task_review_last_grant">Diese Aufgabe wurde zuletzt bestätigt am %s</string>
|
<string name="task_review_last_grant">Diese Aufgabe wurde zuletzt bestätigt am %s</string>
|
||||||
|
|
||||||
|
<string name="dummy_app_unassigned_system_image_app">nicht zugeordnete Apps von der Systempartition</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1567,4 +1567,6 @@
|
||||||
<string name="task_review_text">%1$s said that %2$s was finished. Is this correct?</string>
|
<string name="task_review_text">%1$s said that %2$s was finished. Is this correct?</string>
|
||||||
<string name="task_review_category">This will grant %1$s extra time for %2$s</string>
|
<string name="task_review_category">This will grant %1$s extra time for %2$s</string>
|
||||||
<string name="task_review_last_grant">This task was confirmed last time at %s</string>
|
<string name="task_review_last_grant">This task was confirmed last time at %s</string>
|
||||||
|
|
||||||
|
<string name="dummy_app_unassigned_system_image_app">not assigned Apps from the system image</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue