diff --git a/app/src/main/java/io/timelimit/android/ui/lock/LockActivity.kt b/app/src/main/java/io/timelimit/android/ui/lock/LockActivity.kt index 9521bc4..fa5344f 100644 --- a/app/src/main/java/io/timelimit/android/ui/lock/LockActivity.kt +++ b/app/src/main/java/io/timelimit/android/ui/lock/LockActivity.kt @@ -23,15 +23,18 @@ import android.os.Bundle import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import io.timelimit.android.R import io.timelimit.android.extensions.showSafe +import io.timelimit.android.logic.BlockingReason import io.timelimit.android.logic.DefaultAppLogic +import io.timelimit.android.sync.network.UpdatePrimaryDeviceRequestType import io.timelimit.android.ui.IsAppInForeground import io.timelimit.android.ui.login.NewLoginFragment import io.timelimit.android.ui.main.ActivityViewModel import io.timelimit.android.ui.main.ActivityViewModelHolder +import io.timelimit.android.ui.manage.child.primarydevice.UpdatePrimaryDeviceDialogFragment import io.timelimit.android.ui.util.SyncStatusModel +import kotlinx.android.synthetic.main.lock_activity.* class LockActivity : AppCompatActivity(), ActivityViewModelHolder { companion object { @@ -58,6 +61,9 @@ class LockActivity : AppCompatActivity(), ActivityViewModelHolder { } private val model: LockModel by viewModels() + private val syncModel: SyncStatusModel by viewModels() + private val activityModel: ActivityViewModel by viewModels() + private var isResumed = false override var ignoreStop: Boolean = false @@ -74,27 +80,30 @@ class LockActivity : AppCompatActivity(), ActivityViewModelHolder { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.lock_activity) - if (savedInstanceState == null) { - supportFragmentManager.beginTransaction() - .replace(R.id.container, LockFragment.newInstance(blockedPackageName, blockedActivityName)) - .commitNow() - } + setContentView(R.layout.lock_activity) if (savedInstanceState == null) { stopMediaPlayback() } - val syncModel = ViewModelProviders.of(this).get(SyncStatusModel::class.java) - - syncModel.statusText.observe(this, Observer { - supportActionBar?.subtitle = it - }) + syncModel.statusText.observe(this) { supportActionBar?.subtitle = it } currentInstances.add(this) model.init(blockedPackageName, blockedActivityName) + + pager.adapter = LockActivityAdapter(supportFragmentManager) + + model.content.observe(this) { + if (isResumed && it is LockscreenContent.Blocked.BlockedCategory && it.reason == BlockingReason.RequiresCurrentDevice && !model.didOpenSetCurrentDeviceScreen) { + model.didOpenSetCurrentDeviceScreen = true + + UpdatePrimaryDeviceDialogFragment + .newInstance(UpdatePrimaryDeviceRequestType.SetThisDevice) + .show(supportFragmentManager) + } + } } override fun onDestroy() { @@ -103,9 +112,7 @@ class LockActivity : AppCompatActivity(), ActivityViewModelHolder { currentInstances.remove(this) } - override fun getActivityViewModel(): ActivityViewModel { - return ViewModelProviders.of(this).get(ActivityViewModel::class.java) - } + override fun getActivityViewModel(): ActivityViewModel = activityModel override fun showAuthenticationScreen() { NewLoginFragment().showSafe(supportFragmentManager, LOGIN_DIALOG_TAG) @@ -115,12 +122,14 @@ class LockActivity : AppCompatActivity(), ActivityViewModelHolder { super.onResume() lockTaskModeWorkaround() + isResumed = true } override fun onPause() { super.onPause() lockTaskModeWorkaround() + isResumed = false } override fun onStart() { diff --git a/app/src/main/java/io/timelimit/android/ui/lock/LockActivityAdapter.kt b/app/src/main/java/io/timelimit/android/ui/lock/LockActivityAdapter.kt new file mode 100644 index 0000000..a0d648b --- /dev/null +++ b/app/src/main/java/io/timelimit/android/ui/lock/LockActivityAdapter.kt @@ -0,0 +1,30 @@ +/* + * TimeLimit Copyright 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 . + */ + +package io.timelimit.android.ui.lock + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter + +class LockActivityAdapter(fragmentManager: FragmentManager): FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + override fun getCount(): Int = 1 + + override fun getItem(position: Int): Fragment = when (position) { + 0 -> LockReasonFragment() + else -> throw IllegalArgumentException() + } +} \ No newline at end of file diff --git a/app/src/main/java/io/timelimit/android/ui/lock/LockModel.kt b/app/src/main/java/io/timelimit/android/ui/lock/LockModel.kt index e248ff5..36d30ea 100644 --- a/app/src/main/java/io/timelimit/android/ui/lock/LockModel.kt +++ b/app/src/main/java/io/timelimit/android/ui/lock/LockModel.kt @@ -54,6 +54,8 @@ class LockModel(application: Application): AndroidViewModel(application) { val title: String? get() = logic.platformIntegration.getLocalAppTitle(packageAndActivityNameLiveInternal.value!!.first) val icon: Drawable? get() = logic.platformIntegration.getAppIcon(packageAndActivityNameLiveInternal.value!!.first) + val packageAndActivityNameLive: LiveData> = packageAndActivityNameLiveInternal + var didOpenSetCurrentDeviceScreen = false fun init(packageName: String, activityName: String?) { if (didInit) return @@ -119,18 +121,21 @@ class LockModel(application: Application): AndroidViewModel(application) { val categoryHandlings = appBaseHandling.categoryIds.map { handlingCache.get(it) } val blockingHandling = categoryHandlings.find { it.shouldBlockActivities } - value = if (blockingHandling == null) LockscreenContent.Close else LockscreenContent.BlockedCategory( + value = if (blockingHandling == null) LockscreenContent.Close else LockscreenContent.Blocked.BlockedCategory( deviceAndUserRelatedData = deviceAndUserRelatedData, blockingHandling = blockingHandling, level = appBaseHandling.level, userRelatedData = deviceAndUserRelatedData.userRelatedData, - appBaseHandling = appBaseHandling + appPackageName = packageName, + appActivityName = activityName ).also { scheduleUpdate((blockingHandling.dependsOnMaxTime - realTime.timeInMillis)) } } else if (appBaseHandling is AppBaseHandling.BlockDueToNoCategory) { - value = LockscreenContent.BlockDueToNoCategory( + value = LockscreenContent.Blocked.BlockDueToNoCategory( userRelatedData = deviceAndUserRelatedData.userRelatedData, deviceId = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.id, - enableActivityLevelBlocking = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.enableActivityLevelBlocking + enableActivityLevelBlocking = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.enableActivityLevelBlocking, + appPackageName = packageName, + appActivityName = activityName ) } else { value = LockscreenContent.Close; return @@ -201,27 +206,37 @@ class LockModel(application: Application): AndroidViewModel(application) { sealed class LockscreenContent { object Close: LockscreenContent() - data class BlockedCategory( - val deviceAndUserRelatedData: DeviceAndUserRelatedData, - val blockingHandling: CategoryItselfHandling, - val appBaseHandling: AppBaseHandling, - val level: BlockingLevel, - val userRelatedData: UserRelatedData - ): LockscreenContent() { - val appCategoryTitle = blockingHandling.createdWithCategoryRelatedData.category.title - val reason = blockingHandling.activityBlockingReason - val deviceId = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.id - val userId = userRelatedData.user.id - val timeZone = userRelatedData.user.timeZone - val blockedCategoryId = blockingHandling.createdWithCategoryRelatedData.category.id - val deviceRelatedData = deviceAndUserRelatedData.deviceRelatedData - val hasFullVersion = deviceRelatedData.isConnectedAndHasPremium || deviceRelatedData.isLocalMode - val enableActivityLevelBlocking = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.enableActivityLevelBlocking - } + sealed class Blocked: LockscreenContent() { + abstract val userRelatedData: UserRelatedData + abstract val appPackageName: String + abstract val appActivityName: String? + abstract val enableActivityLevelBlocking: Boolean - data class BlockDueToNoCategory( - val userRelatedData: UserRelatedData, - val deviceId: String, - val enableActivityLevelBlocking: Boolean - ): LockscreenContent() + class BlockedCategory( + val deviceAndUserRelatedData: DeviceAndUserRelatedData, + val blockingHandling: CategoryItselfHandling, + val level: BlockingLevel, + override val userRelatedData: UserRelatedData, + override val appPackageName: String, + override val appActivityName: String? + ): Blocked() { + val appCategoryTitle = blockingHandling.createdWithCategoryRelatedData.category.title + val reason = blockingHandling.activityBlockingReason + val deviceId = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.id + val userId = userRelatedData.user.id + val timeZone = userRelatedData.user.timeZone + val blockedCategoryId = blockingHandling.createdWithCategoryRelatedData.category.id + val deviceRelatedData = deviceAndUserRelatedData.deviceRelatedData + val hasFullVersion = deviceRelatedData.isConnectedAndHasPremium || deviceRelatedData.isLocalMode + override val enableActivityLevelBlocking = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.enableActivityLevelBlocking + } + + class BlockDueToNoCategory( + override val userRelatedData: UserRelatedData, + val deviceId: String, + override val enableActivityLevelBlocking: Boolean, + override val appPackageName: String, + override val appActivityName: String? + ): Blocked() + } } \ No newline at end of file diff --git a/app/src/main/java/io/timelimit/android/ui/lock/LockFragment.kt b/app/src/main/java/io/timelimit/android/ui/lock/LockReasonFragment.kt similarity index 72% rename from app/src/main/java/io/timelimit/android/ui/lock/LockFragment.kt rename to app/src/main/java/io/timelimit/android/ui/lock/LockReasonFragment.kt index 6c0c2c4..cd6d7d4 100644 --- a/app/src/main/java/io/timelimit/android/ui/lock/LockFragment.kt +++ b/app/src/main/java/io/timelimit/android/ui/lock/LockReasonFragment.kt @@ -30,8 +30,8 @@ import io.timelimit.android.data.extensions.sortedCategories import io.timelimit.android.data.model.* import io.timelimit.android.data.model.derived.DeviceRelatedData import io.timelimit.android.data.model.derived.UserRelatedData -import io.timelimit.android.databinding.LockFragmentBinding import io.timelimit.android.databinding.LockFragmentCategoryButtonBinding +import io.timelimit.android.databinding.LockReasonFragmentBinding import io.timelimit.android.date.DateInTimezone import io.timelimit.android.livedata.* import io.timelimit.android.logic.* @@ -53,38 +53,13 @@ import io.timelimit.android.ui.payment.RequiresPurchaseDialogFragment import io.timelimit.android.ui.view.SelectTimeSpanViewListener import java.util.* -class LockFragment : Fragment() { +class LockReasonFragment : Fragment() { companion object { - private const val EXTRA_PACKAGE_NAME = "pkg" - private const val EXTRA_ACTIVITY = "activitiy" - private const val STATUS_DID_OPEN_SET_CURRENT_DEVICE_SCREEN = "didOpenSetCurrentDeviceScreen" private const val LOCATION_REQUEST_CODE = 1 - - fun newInstance(packageName: String, activity: String?): LockFragment { - val result = LockFragment() - val arguments = Bundle() - - arguments.putString(EXTRA_PACKAGE_NAME, packageName) - - if (activity != null) { - arguments.putString(EXTRA_ACTIVITY, activity) - } - - result.arguments = arguments - return result - } } - private var didOpenSetCurrentDeviceScreen = false - private val packageName: String by lazy { requireArguments().getString(EXTRA_PACKAGE_NAME)!! } - private val activityName: String? by lazy { - if (requireArguments().containsKey(EXTRA_ACTIVITY)) - requireArguments().getString(EXTRA_ACTIVITY) - else - null - } private val auth: ActivityViewModel by lazy { getActivityViewModel(requireActivity()) } - private lateinit var binding: LockFragmentBinding + private lateinit var binding: LockReasonFragmentBinding private val model: LockModel by activityViewModels() private fun setupHandlers(deviceId: String, userRelatedData: UserRelatedData, blockedCategoryId: String?) { @@ -140,23 +115,23 @@ class LockFragment : Fragment() { (activity as LockActivity).showAuthenticationScreen() } - override fun setThisDeviceAsCurrentDevice() = this@LockFragment.setThisDeviceAsCurrentDevice() + override fun setThisDeviceAsCurrentDevice() = this@LockReasonFragment.setThisDeviceAsCurrentDevice() override fun requestLocationPermission() { - RequestWifiPermission.doRequest(this@LockFragment, LOCATION_REQUEST_CODE) + RequestWifiPermission.doRequest(this@LockReasonFragment, LOCATION_REQUEST_CODE) } } } private fun setThisDeviceAsCurrentDevice() { - didOpenSetCurrentDeviceScreen = true + model.didOpenSetCurrentDeviceScreen = true UpdatePrimaryDeviceDialogFragment .newInstance(UpdatePrimaryDeviceRequestType.SetThisDevice) .show(parentFragmentManager) } - private fun bindAddToCategoryOptions(userRelatedData: UserRelatedData) { + private fun bindAddToCategoryOptions(userRelatedData: UserRelatedData, blockedPackageName: String) { binding.addToCategoryOptions.removeAllViews() userRelatedData.sortedCategories().forEach { (_, category) -> @@ -166,7 +141,7 @@ class LockFragment : Fragment() { auth.tryDispatchParentAction( AddCategoryAppsAction( categoryId = category.category.id, - packageNames = listOf(packageName) + packageNames = listOf(blockedPackageName) ) ) } @@ -238,22 +213,8 @@ class LockFragment : Fragment() { model.missingNetworkIdPermission.observe(viewLifecycleOwner) { binding.missingNetworkIdPermission = it } } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - if (savedInstanceState != null) { - didOpenSetCurrentDeviceScreen = savedInstanceState.getBoolean(STATUS_DID_OPEN_SET_CURRENT_DEVICE_SCREEN) - } - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - - outState.putBoolean(STATUS_DID_OPEN_SET_CURRENT_DEVICE_SCREEN, didOpenSetCurrentDeviceScreen) - } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - binding = LockFragmentBinding.inflate(layoutInflater, container, false) + binding = LockReasonFragmentBinding.inflate(layoutInflater, container, false) AuthenticationFab.manageAuthenticationFab( fab = binding.fab, @@ -272,7 +233,7 @@ class LockFragment : Fragment() { ) } - binding.packageName = packageName + model.packageAndActivityNameLive.observe(viewLifecycleOwner) { binding.packageName = it.first } binding.appTitle = model.title ?: "???" binding.appIcon.setImageDrawable(model.icon) @@ -288,50 +249,51 @@ class LockFragment : Fragment() { requireActivity().finish() } - is LockscreenContent.BlockedCategory -> { - binding.activityName = if (content.enableActivityLevelBlocking) activityName?.removePrefix(packageName) else null + is LockscreenContent.Blocked -> { + binding.activityName = if (content.enableActivityLevelBlocking) content.appActivityName?.removePrefix(content.appPackageName) else null - binding.appCategoryTitle = content.appCategoryTitle - binding.reason = content.reason - binding.blockedKindLabel = when (content.level) { - BlockingLevel.Activity -> "Activity" - BlockingLevel.App -> "App" - } - setupHandlers( - deviceId = content.deviceId, - blockedCategoryId = content.blockedCategoryId, - userRelatedData = content.userRelatedData - ) - bindExtraTimeView( - deviceRelatedData = content.deviceRelatedData, - categoryId = content.blockedCategoryId, - timeZone = content.userRelatedData.timeZone - ) - binding.manageDisableTimeLimits.handlers = ManageDisableTimelimitsViewHelper.createHandlers( - childId = content.userId, - childTimezone = content.timeZone, - activity = requireActivity(), - hasFullVersion = content.hasFullVersion - ) + when (content) { + is LockscreenContent.Blocked.BlockedCategory -> { + binding.appCategoryTitle = content.appCategoryTitle + binding.reason = content.reason + binding.blockedKindLabel = when (content.level) { + BlockingLevel.Activity -> "Activity" + BlockingLevel.App -> "App" + } + setupHandlers( + deviceId = content.deviceId, + blockedCategoryId = content.blockedCategoryId, + userRelatedData = content.userRelatedData + ) + bindExtraTimeView( + deviceRelatedData = content.deviceRelatedData, + categoryId = content.blockedCategoryId, + timeZone = content.userRelatedData.timeZone + ) + binding.manageDisableTimeLimits.handlers = ManageDisableTimelimitsViewHelper.createHandlers( + childId = content.userId, + childTimezone = content.timeZone, + activity = requireActivity(), + hasFullVersion = content.hasFullVersion + ) + } + is LockscreenContent.Blocked.BlockDueToNoCategory -> { + binding.appCategoryTitle = null + binding.reason = BlockingReason.NotPartOfAnCategory + binding.blockedKindLabel = "App" - if (content.reason == BlockingReason.RequiresCurrentDevice && !didOpenSetCurrentDeviceScreen && isResumed) { - setThisDeviceAsCurrentDevice() - } else null - } - is LockscreenContent.BlockDueToNoCategory -> { - binding.activityName = if (content.enableActivityLevelBlocking) activityName?.removePrefix(packageName) else null + setupHandlers( + deviceId = content.deviceId, + blockedCategoryId = null, + userRelatedData = content.userRelatedData + ) - binding.appCategoryTitle = null - binding.reason = BlockingReason.NotPartOfAnCategory - binding.blockedKindLabel = "App" - - setupHandlers( - deviceId = content.deviceId, - blockedCategoryId = null, - userRelatedData = content.userRelatedData - ) - - bindAddToCategoryOptions(content.userRelatedData) + bindAddToCategoryOptions( + userRelatedData = content.userRelatedData, + blockedPackageName = content.appPackageName + ) + } + }.let {/* require handling all paths */} } }.let {/* require handling all paths */} } diff --git a/app/src/main/res/layout/lock_activity.xml b/app/src/main/res/layout/lock_activity.xml index 600e469..969c974 100644 --- a/app/src/main/res/layout/lock_activity.xml +++ b/app/src/main/res/layout/lock_activity.xml @@ -13,9 +13,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . --> - \ No newline at end of file diff --git a/app/src/main/res/layout/lock_fragment.xml b/app/src/main/res/layout/lock_reason_fragment.xml similarity index 99% rename from app/src/main/res/layout/lock_fragment.xml rename to app/src/main/res/layout/lock_reason_fragment.xml index 9c08384..ac02ec5 100644 --- a/app/src/main/res/layout/lock_fragment.xml +++ b/app/src/main/res/layout/lock_reason_fragment.xml @@ -16,7 +16,7 @@ + tools:context=".ui.lock.LockReasonFragment">