mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 09:49:25 +02:00
Add option to restrict viewing child users
This commit is contained in:
parent
7139c87fec
commit
a0a1c20e10
15 changed files with 1274 additions and 13 deletions
1012
app/schemas/io.timelimit.android.data.RoomDatabase/30.json
Normal file
1012
app/schemas/io.timelimit.android.data.RoomDatabase/30.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -218,4 +218,10 @@ object DatabaseMigrations {
|
||||||
database.execSQL("CREATE INDEX IF NOT EXISTS `session_duration_index_category_id` ON `session_duration` (`category_id`)")
|
database.execSQL("CREATE INDEX IF NOT EXISTS `session_duration_index_category_id` ON `session_duration` (`category_id`)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val MIGRATE_TO_V30 = object: Migration(29, 30) {
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL("ALTER TABLE `user` ADD COLUMN `flags` INTEGER NOT NULL DEFAULT 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ import io.timelimit.android.data.model.*
|
||||||
AllowedContact::class,
|
AllowedContact::class,
|
||||||
UserKey::class,
|
UserKey::class,
|
||||||
SessionDuration::class
|
SessionDuration::class
|
||||||
], version = 29)
|
], version = 30)
|
||||||
abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database {
|
abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database {
|
||||||
companion object {
|
companion object {
|
||||||
private val lock = Object()
|
private val lock = Object()
|
||||||
|
@ -100,7 +100,8 @@ abstract class RoomDatabase: RoomDatabase(), io.timelimit.android.data.Database
|
||||||
DatabaseMigrations.MIGRATE_TO_V26,
|
DatabaseMigrations.MIGRATE_TO_V26,
|
||||||
DatabaseMigrations.MIGRATE_TO_V27,
|
DatabaseMigrations.MIGRATE_TO_V27,
|
||||||
DatabaseMigrations.MIGRATE_TO_V28,
|
DatabaseMigrations.MIGRATE_TO_V28,
|
||||||
DatabaseMigrations.MIGRATE_TO_V29
|
DatabaseMigrations.MIGRATE_TO_V29,
|
||||||
|
DatabaseMigrations.MIGRATE_TO_V30
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
@ -62,7 +62,9 @@ data class User(
|
||||||
@ColumnInfo(name = "mail_notification_flags")
|
@ColumnInfo(name = "mail_notification_flags")
|
||||||
val mailNotificationFlags: Int,
|
val mailNotificationFlags: Int,
|
||||||
@ColumnInfo(name = "blocked_times")
|
@ColumnInfo(name = "blocked_times")
|
||||||
val blockedTimes: ImmutableBitmask
|
val blockedTimes: ImmutableBitmask,
|
||||||
|
@ColumnInfo(name = "flags")
|
||||||
|
val flags: Long
|
||||||
): JsonSerializable {
|
): JsonSerializable {
|
||||||
companion object {
|
companion object {
|
||||||
private const val ID = "id"
|
private const val ID = "id"
|
||||||
|
@ -78,6 +80,7 @@ data class User(
|
||||||
private const val RELAX_PRIMARY_DEVICE = "relaxPrimaryDevice"
|
private const val RELAX_PRIMARY_DEVICE = "relaxPrimaryDevice"
|
||||||
private const val MAIL_NOTIFICATION_FLAGS = "mailNotificationFlags"
|
private const val MAIL_NOTIFICATION_FLAGS = "mailNotificationFlags"
|
||||||
private const val BLOCKED_TIMES = "blockedTimes"
|
private const val BLOCKED_TIMES = "blockedTimes"
|
||||||
|
private const val FLAGS = "flags"
|
||||||
|
|
||||||
fun parse(reader: JsonReader): User {
|
fun parse(reader: JsonReader): User {
|
||||||
var id: String? = null
|
var id: String? = null
|
||||||
|
@ -93,6 +96,7 @@ data class User(
|
||||||
var relaxPrimaryDevice = false
|
var relaxPrimaryDevice = false
|
||||||
var mailNotificationFlags = 0
|
var mailNotificationFlags = 0
|
||||||
var blockedTimes = ImmutableBitmask(BitSet())
|
var blockedTimes = ImmutableBitmask(BitSet())
|
||||||
|
var flags = 0L
|
||||||
|
|
||||||
reader.beginObject()
|
reader.beginObject()
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
|
@ -110,6 +114,7 @@ data class User(
|
||||||
RELAX_PRIMARY_DEVICE -> relaxPrimaryDevice = reader.nextBoolean()
|
RELAX_PRIMARY_DEVICE -> relaxPrimaryDevice = reader.nextBoolean()
|
||||||
MAIL_NOTIFICATION_FLAGS -> mailNotificationFlags = reader.nextInt()
|
MAIL_NOTIFICATION_FLAGS -> mailNotificationFlags = reader.nextInt()
|
||||||
BLOCKED_TIMES -> blockedTimes = ImmutableBitmaskJson.parse(reader.nextString(), Category.BLOCKED_MINUTES_IN_WEEK_LENGTH)
|
BLOCKED_TIMES -> blockedTimes = ImmutableBitmaskJson.parse(reader.nextString(), Category.BLOCKED_MINUTES_IN_WEEK_LENGTH)
|
||||||
|
FLAGS -> flags = reader.nextLong()
|
||||||
else -> reader.skipValue()
|
else -> reader.skipValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +133,8 @@ data class User(
|
||||||
categoryForNotAssignedApps = categoryForNotAssignedApps,
|
categoryForNotAssignedApps = categoryForNotAssignedApps,
|
||||||
relaxPrimaryDevice = relaxPrimaryDevice,
|
relaxPrimaryDevice = relaxPrimaryDevice,
|
||||||
mailNotificationFlags = mailNotificationFlags,
|
mailNotificationFlags = mailNotificationFlags,
|
||||||
blockedTimes = blockedTimes
|
blockedTimes = blockedTimes,
|
||||||
|
flags = flags
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +165,9 @@ data class User(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val restrictViewingToParents: Boolean
|
||||||
|
get() = flags and UserFlags.RESTRICT_VIEWING_TO_PARENTS == UserFlags.RESTRICT_VIEWING_TO_PARENTS
|
||||||
|
|
||||||
override fun serialize(writer: JsonWriter) {
|
override fun serialize(writer: JsonWriter) {
|
||||||
writer.beginObject()
|
writer.beginObject()
|
||||||
|
|
||||||
|
@ -175,6 +184,7 @@ data class User(
|
||||||
writer.name(RELAX_PRIMARY_DEVICE).value(relaxPrimaryDevice)
|
writer.name(RELAX_PRIMARY_DEVICE).value(relaxPrimaryDevice)
|
||||||
writer.name(MAIL_NOTIFICATION_FLAGS).value(mailNotificationFlags)
|
writer.name(MAIL_NOTIFICATION_FLAGS).value(mailNotificationFlags)
|
||||||
writer.name(BLOCKED_TIMES).value(ImmutableBitmaskJson.serialize(blockedTimes))
|
writer.name(BLOCKED_TIMES).value(ImmutableBitmaskJson.serialize(blockedTimes))
|
||||||
|
writer.name(FLAGS).value(flags)
|
||||||
|
|
||||||
writer.endObject()
|
writer.endObject()
|
||||||
}
|
}
|
||||||
|
@ -207,3 +217,8 @@ class UserTypeConverter {
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun toString(value: UserType) = UserTypeJson.serialize(value)
|
fun toString(value: UserType) = UserTypeJson.serialize(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object UserFlags {
|
||||||
|
const val RESTRICT_VIEWING_TO_PARENTS = 1L
|
||||||
|
const val ALL_FLAGS = RESTRICT_VIEWING_TO_PARENTS
|
||||||
|
}
|
|
@ -128,7 +128,8 @@ class AppSetupLogic(private val appLogic: AppLogic) {
|
||||||
categoryForNotAssignedApps = "",
|
categoryForNotAssignedApps = "",
|
||||||
relaxPrimaryDevice = false,
|
relaxPrimaryDevice = false,
|
||||||
mailNotificationFlags = 0,
|
mailNotificationFlags = 0,
|
||||||
blockedTimes = ImmutableBitmask(BitSet())
|
blockedTimes = ImmutableBitmask(BitSet()),
|
||||||
|
flags = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
appLogic.database.user().addUserSync(child)
|
appLogic.database.user().addUserSync(child)
|
||||||
|
@ -150,7 +151,8 @@ class AppSetupLogic(private val appLogic: AppLogic) {
|
||||||
categoryForNotAssignedApps = "",
|
categoryForNotAssignedApps = "",
|
||||||
relaxPrimaryDevice = false,
|
relaxPrimaryDevice = false,
|
||||||
mailNotificationFlags = 0,
|
mailNotificationFlags = 0,
|
||||||
blockedTimes = ImmutableBitmask(BitSet())
|
blockedTimes = ImmutableBitmask(BitSet()),
|
||||||
|
flags = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
appLogic.database.user().addUserSync(parent)
|
appLogic.database.user().addUserSync(parent)
|
||||||
|
|
|
@ -1826,6 +1826,34 @@ data class ResetParentBlockedTimesAction(val parentId: String): ParentAction() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class UpdateUserFlagsAction(val userId: String, val modifiedBits: Long, val newValues: Long): ParentAction() {
|
||||||
|
companion object {
|
||||||
|
private const val TYPE_VALUE = "UPDATE_USER_FLAGS"
|
||||||
|
private const val USER_ID = "userId"
|
||||||
|
private const val MODIFIED_BITS = "modified"
|
||||||
|
private const val NEW_VALUES = "values"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
IdGenerator.assertIdValid(userId)
|
||||||
|
|
||||||
|
if (modifiedBits or UserFlags.ALL_FLAGS != UserFlags.ALL_FLAGS || modifiedBits or newValues != modifiedBits) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(writer: JsonWriter) {
|
||||||
|
writer.beginObject()
|
||||||
|
|
||||||
|
writer.name(TYPE).value(TYPE_VALUE)
|
||||||
|
writer.name(USER_ID).value(userId)
|
||||||
|
writer.name(MODIFIED_BITS).value(modifiedBits)
|
||||||
|
writer.name(NEW_VALUES).value(newValues)
|
||||||
|
|
||||||
|
writer.endObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// child actions
|
// child actions
|
||||||
object ChildSignInAction: ChildAction() {
|
object ChildSignInAction: ChildAction() {
|
||||||
private const val TYPE_VALUE = "CHILD_SIGN_IN"
|
private const val TYPE_VALUE = "CHILD_SIGN_IN"
|
||||||
|
|
|
@ -68,6 +68,7 @@ object ActionParser {
|
||||||
// UpdateCategoryTimeWarningsAction
|
// UpdateCategoryTimeWarningsAction
|
||||||
// UpdateCategoryBatteryLimit
|
// UpdateCategoryBatteryLimit
|
||||||
// UpdateCategorySorting
|
// UpdateCategorySorting
|
||||||
|
// UpdateUserFlagsAction
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,7 +176,8 @@ object LocalDatabaseParentActionDispatcher {
|
||||||
categoryForNotAssignedApps = "",
|
categoryForNotAssignedApps = "",
|
||||||
relaxPrimaryDevice = false,
|
relaxPrimaryDevice = false,
|
||||||
mailNotificationFlags = 0,
|
mailNotificationFlags = 0,
|
||||||
blockedTimes = ImmutableBitmask(BitSet())
|
blockedTimes = ImmutableBitmask(BitSet()),
|
||||||
|
flags = 0
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
is UpdateCategoryBlockedTimesAction -> {
|
is UpdateCategoryBlockedTimesAction -> {
|
||||||
|
@ -586,6 +587,15 @@ object LocalDatabaseParentActionDispatcher {
|
||||||
database.category().updateCategorySorting(categoryId, index)
|
database.category().updateCategorySorting(categoryId, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is UpdateUserFlagsAction -> {
|
||||||
|
val user = database.user().getUserByIdSync(action.userId)!!
|
||||||
|
|
||||||
|
val updatedUser = user.copy(
|
||||||
|
flags = (user.flags and action.modifiedBits.inv()) or action.newValues
|
||||||
|
)
|
||||||
|
|
||||||
|
database.user().updateUserSync(updatedUser)
|
||||||
|
}
|
||||||
}.let { }
|
}.let { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,11 +34,13 @@ import io.timelimit.android.ui.help.HelpDialogFragment
|
||||||
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
|
||||||
import io.timelimit.android.ui.manage.child.ManageChildFragmentArgs
|
import io.timelimit.android.ui.manage.child.ManageChildFragmentArgs
|
||||||
|
import io.timelimit.android.ui.manage.child.advanced.limituserviewing.LimitUserViewingView
|
||||||
import io.timelimit.android.ui.manage.child.advanced.manageblocktemporarily.ManageBlockTemporarilyView
|
import io.timelimit.android.ui.manage.child.advanced.manageblocktemporarily.ManageBlockTemporarilyView
|
||||||
import io.timelimit.android.ui.manage.child.advanced.managedisabletimelimits.ManageDisableTimelimitsViewHelper
|
import io.timelimit.android.ui.manage.child.advanced.managedisabletimelimits.ManageDisableTimelimitsViewHelper
|
||||||
import io.timelimit.android.ui.manage.child.advanced.password.ManageChildPassword
|
import io.timelimit.android.ui.manage.child.advanced.password.ManageChildPassword
|
||||||
import io.timelimit.android.ui.manage.child.advanced.timezone.UserTimezoneView
|
import io.timelimit.android.ui.manage.child.advanced.timezone.UserTimezoneView
|
||||||
import io.timelimit.android.ui.manage.child.primarydevice.PrimaryDeviceView
|
import io.timelimit.android.ui.manage.child.primarydevice.PrimaryDeviceView
|
||||||
|
import kotlin.concurrent.fixedRateTimer
|
||||||
|
|
||||||
class ManageChildAdvancedFragment : Fragment() {
|
class ManageChildAdvancedFragment : Fragment() {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -149,6 +151,15 @@ class ManageChildAdvancedFragment : Fragment() {
|
||||||
fragmentManager = fragmentManager!!
|
fragmentManager = fragmentManager!!
|
||||||
)
|
)
|
||||||
|
|
||||||
|
LimitUserViewingView.bind(
|
||||||
|
view = binding.limitViewing,
|
||||||
|
auth = auth,
|
||||||
|
lifecycleOwner = viewLifecycleOwner,
|
||||||
|
fragmentManager = parentFragmentManager,
|
||||||
|
userEntry = childEntry,
|
||||||
|
userId = params.childId
|
||||||
|
)
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 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.child.advanced.limituserviewing
|
||||||
|
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import io.timelimit.android.R
|
||||||
|
import io.timelimit.android.data.model.User
|
||||||
|
import io.timelimit.android.data.model.UserFlags
|
||||||
|
import io.timelimit.android.databinding.LimitUserViewingViewBinding
|
||||||
|
import io.timelimit.android.livedata.ignoreUnchanged
|
||||||
|
import io.timelimit.android.livedata.map
|
||||||
|
import io.timelimit.android.sync.actions.UpdateUserFlagsAction
|
||||||
|
import io.timelimit.android.ui.help.HelpDialogFragment
|
||||||
|
import io.timelimit.android.ui.main.ActivityViewModel
|
||||||
|
|
||||||
|
object LimitUserViewingView {
|
||||||
|
fun bind(
|
||||||
|
view: LimitUserViewingViewBinding,
|
||||||
|
auth: ActivityViewModel,
|
||||||
|
lifecycleOwner: LifecycleOwner,
|
||||||
|
fragmentManager: FragmentManager,
|
||||||
|
userEntry: LiveData<User?>,
|
||||||
|
userId: String
|
||||||
|
) {
|
||||||
|
view.titleView.setOnClickListener {
|
||||||
|
HelpDialogFragment.newInstance(
|
||||||
|
title = R.string.limit_user_viewing_title,
|
||||||
|
text = R.string.limit_user_viewing_help
|
||||||
|
).show(fragmentManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
userEntry.map { it?.restrictViewingToParents ?: false }.ignoreUnchanged().observe(lifecycleOwner, Observer { checked ->
|
||||||
|
view.enableSwitch.setOnCheckedChangeListener { buttonView, isChecked -> /* ignore */ }
|
||||||
|
view.enableSwitch.isChecked = checked
|
||||||
|
view.enableSwitch.setOnCheckedChangeListener { buttonView, isChecked ->
|
||||||
|
if (isChecked != checked) {
|
||||||
|
if (
|
||||||
|
!auth.tryDispatchParentAction(
|
||||||
|
UpdateUserFlagsAction(
|
||||||
|
userId = userId,
|
||||||
|
modifiedBits = UserFlags.RESTRICT_VIEWING_TO_PARENTS,
|
||||||
|
newValues = if (isChecked) UserFlags.RESTRICT_VIEWING_TO_PARENTS else 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
view.enableSwitch.isChecked = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
@ -69,10 +69,18 @@ class OverviewFragment : CoroutineFragment(), CanNotAddDevicesInLocalModeDialogF
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUserClicked(user: User) {
|
override fun onUserClicked(user: User) {
|
||||||
when (user.type) {
|
if (
|
||||||
UserType.Child -> handlers.openManageChildScreen(childId = user.id)
|
user.restrictViewingToParents &&
|
||||||
UserType.Parent -> handlers.openManageParentScreen(parentId = user.id)
|
logic.deviceUserId.value != user.id &&
|
||||||
}.let { }
|
!auth.requestAuthenticationOrReturnTrue()
|
||||||
|
) {
|
||||||
|
// do "nothing"/ request authentication
|
||||||
|
} else {
|
||||||
|
when (user.type) {
|
||||||
|
UserType.Child -> handlers.openManageChildScreen(childId = user.id)
|
||||||
|
UserType.Parent -> handlers.openManageParentScreen(parentId = user.id)
|
||||||
|
}.let { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAddDeviceClicked() {
|
override fun onAddDeviceClicked() {
|
||||||
|
|
|
@ -98,6 +98,9 @@
|
||||||
<include android:id="@+id/password"
|
<include android:id="@+id/password"
|
||||||
layout="@layout/manage_child_password" />
|
layout="@layout/manage_child_password" />
|
||||||
|
|
||||||
|
<include android:id="@+id/limit_viewing"
|
||||||
|
layout="@layout/limit_user_viewing_view" />
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
app:cardUseCompatPadding="true"
|
app:cardUseCompatPadding="true"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
48
app/src/main/res/layout/limit_user_viewing_view.xml
Normal file
48
app/src/main/res/layout/limit_user_viewing_view.xml
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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/>.
|
||||||
|
-->
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:cardUseCompatPadding="true">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
tools:ignore="UnusedAttribute"
|
||||||
|
android:drawableTint="?colorOnSurface"
|
||||||
|
android:id="@+id/title_view"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:drawableEnd="@drawable/ic_info_outline_black_24dp"
|
||||||
|
android:textAppearance="?android:textAppearanceLarge"
|
||||||
|
android:text="@string/limit_user_viewing_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
android:id="@+id/enable_switch"
|
||||||
|
android:text="@string/limit_user_viewing_checkbox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
</layout>
|
24
app/src/main/res/values-de/strings-limit-user-viewing.xml
Normal file
24
app/src/main/res/values-de/strings-limit-user-viewing.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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/>.
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
<string name="limit_user_viewing_title">Nutzersichtbarkeit einschränken</string>
|
||||||
|
<string name="limit_user_viewing_checkbox">Nur dem Benutzer selbst und den Eltern erlauben, die Benutzerdetails anzuzeigen</string>
|
||||||
|
<string name="limit_user_viewing_help">Damit kann verhindert werden, dass andere Kinder der Familie
|
||||||
|
die Einstellungen und Nutzungsdauern dieses Kindes sehen können. Das ist nicht als
|
||||||
|
Sicherheitsfunktion gedacht und leicht umgehbar, z.B. mit der Nutzung einer älteren TimeLimit-
|
||||||
|
Version.
|
||||||
|
</string>
|
||||||
|
</resources>
|
23
app/src/main/res/values/strings-limit-user-viewing.xml
Normal file
23
app/src/main/res/values/strings-limit-user-viewing.xml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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/>.
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
<string name="limit_user_viewing_title">Restrict viewing the user</string>
|
||||||
|
<string name="limit_user_viewing_checkbox">Only allow parents and the user itself to view its details</string>
|
||||||
|
<string name="limit_user_viewing_help">This allows preventing other child users to
|
||||||
|
view the configuration and used times of this child user. This is not intended as security feature
|
||||||
|
and it is not one - using an older version is enough to circumvent this.
|
||||||
|
</string>
|
||||||
|
</resources>
|
Loading…
Add table
Add a link
Reference in a new issue