Move lock screen fragment within pager

This commit is contained in:
Jonas Lochmann 2020-11-02 01:00:00 +01:00
parent 73f1a22ab4
commit 7f207d0c08
No known key found for this signature in database
GPG key ID: 8B8C9AEE10FA5B36
6 changed files with 151 additions and 134 deletions

View file

@ -23,15 +23,18 @@ import android.os.Bundle
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import io.timelimit.android.R import io.timelimit.android.R
import io.timelimit.android.extensions.showSafe import io.timelimit.android.extensions.showSafe
import io.timelimit.android.logic.BlockingReason
import io.timelimit.android.logic.DefaultAppLogic import io.timelimit.android.logic.DefaultAppLogic
import io.timelimit.android.sync.network.UpdatePrimaryDeviceRequestType
import io.timelimit.android.ui.IsAppInForeground import io.timelimit.android.ui.IsAppInForeground
import io.timelimit.android.ui.login.NewLoginFragment import io.timelimit.android.ui.login.NewLoginFragment
import io.timelimit.android.ui.main.ActivityViewModel import io.timelimit.android.ui.main.ActivityViewModel
import io.timelimit.android.ui.main.ActivityViewModelHolder import io.timelimit.android.ui.main.ActivityViewModelHolder
import io.timelimit.android.ui.manage.child.primarydevice.UpdatePrimaryDeviceDialogFragment
import io.timelimit.android.ui.util.SyncStatusModel import io.timelimit.android.ui.util.SyncStatusModel
import kotlinx.android.synthetic.main.lock_activity.*
class LockActivity : AppCompatActivity(), ActivityViewModelHolder { class LockActivity : AppCompatActivity(), ActivityViewModelHolder {
companion object { companion object {
@ -58,6 +61,9 @@ class LockActivity : AppCompatActivity(), ActivityViewModelHolder {
} }
private val model: LockModel by viewModels() 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 override var ignoreStop: Boolean = false
@ -74,27 +80,30 @@ class LockActivity : AppCompatActivity(), ActivityViewModelHolder {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.lock_activity)
if (savedInstanceState == null) { setContentView(R.layout.lock_activity)
supportFragmentManager.beginTransaction()
.replace(R.id.container, LockFragment.newInstance(blockedPackageName, blockedActivityName))
.commitNow()
}
if (savedInstanceState == null) { if (savedInstanceState == null) {
stopMediaPlayback() stopMediaPlayback()
} }
val syncModel = ViewModelProviders.of(this).get(SyncStatusModel::class.java) syncModel.statusText.observe(this) { supportActionBar?.subtitle = it }
syncModel.statusText.observe(this, Observer {
supportActionBar?.subtitle = it
})
currentInstances.add(this) currentInstances.add(this)
model.init(blockedPackageName, blockedActivityName) 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() { override fun onDestroy() {
@ -103,9 +112,7 @@ class LockActivity : AppCompatActivity(), ActivityViewModelHolder {
currentInstances.remove(this) currentInstances.remove(this)
} }
override fun getActivityViewModel(): ActivityViewModel { override fun getActivityViewModel(): ActivityViewModel = activityModel
return ViewModelProviders.of(this).get(ActivityViewModel::class.java)
}
override fun showAuthenticationScreen() { override fun showAuthenticationScreen() {
NewLoginFragment().showSafe(supportFragmentManager, LOGIN_DIALOG_TAG) NewLoginFragment().showSafe(supportFragmentManager, LOGIN_DIALOG_TAG)
@ -115,12 +122,14 @@ class LockActivity : AppCompatActivity(), ActivityViewModelHolder {
super.onResume() super.onResume()
lockTaskModeWorkaround() lockTaskModeWorkaround()
isResumed = true
} }
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
lockTaskModeWorkaround() lockTaskModeWorkaround()
isResumed = false
} }
override fun onStart() { override fun onStart() {

View file

@ -0,0 +1,30 @@
/*
* 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.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()
}
}

View file

@ -54,6 +54,8 @@ class LockModel(application: Application): AndroidViewModel(application) {
val title: String? get() = logic.platformIntegration.getLocalAppTitle(packageAndActivityNameLiveInternal.value!!.first) val title: String? get() = logic.platformIntegration.getLocalAppTitle(packageAndActivityNameLiveInternal.value!!.first)
val icon: Drawable? get() = logic.platformIntegration.getAppIcon(packageAndActivityNameLiveInternal.value!!.first) val icon: Drawable? get() = logic.platformIntegration.getAppIcon(packageAndActivityNameLiveInternal.value!!.first)
val packageAndActivityNameLive: LiveData<Pair<String, String?>> = packageAndActivityNameLiveInternal
var didOpenSetCurrentDeviceScreen = false
fun init(packageName: String, activityName: String?) { fun init(packageName: String, activityName: String?) {
if (didInit) return if (didInit) return
@ -119,18 +121,21 @@ class LockModel(application: Application): AndroidViewModel(application) {
val categoryHandlings = appBaseHandling.categoryIds.map { handlingCache.get(it) } val categoryHandlings = appBaseHandling.categoryIds.map { handlingCache.get(it) }
val blockingHandling = categoryHandlings.find { it.shouldBlockActivities } 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, deviceAndUserRelatedData = deviceAndUserRelatedData,
blockingHandling = blockingHandling, blockingHandling = blockingHandling,
level = appBaseHandling.level, level = appBaseHandling.level,
userRelatedData = deviceAndUserRelatedData.userRelatedData, userRelatedData = deviceAndUserRelatedData.userRelatedData,
appBaseHandling = appBaseHandling appPackageName = packageName,
appActivityName = activityName
).also { scheduleUpdate((blockingHandling.dependsOnMaxTime - realTime.timeInMillis)) } ).also { scheduleUpdate((blockingHandling.dependsOnMaxTime - realTime.timeInMillis)) }
} else if (appBaseHandling is AppBaseHandling.BlockDueToNoCategory) { } else if (appBaseHandling is AppBaseHandling.BlockDueToNoCategory) {
value = LockscreenContent.BlockDueToNoCategory( value = LockscreenContent.Blocked.BlockDueToNoCategory(
userRelatedData = deviceAndUserRelatedData.userRelatedData, userRelatedData = deviceAndUserRelatedData.userRelatedData,
deviceId = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.id, deviceId = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.id,
enableActivityLevelBlocking = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.enableActivityLevelBlocking enableActivityLevelBlocking = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.enableActivityLevelBlocking,
appPackageName = packageName,
appActivityName = activityName
) )
} else { } else {
value = LockscreenContent.Close; return value = LockscreenContent.Close; return
@ -201,13 +206,20 @@ class LockModel(application: Application): AndroidViewModel(application) {
sealed class LockscreenContent { sealed class LockscreenContent {
object Close: LockscreenContent() object Close: LockscreenContent()
data class BlockedCategory( sealed class Blocked: LockscreenContent() {
abstract val userRelatedData: UserRelatedData
abstract val appPackageName: String
abstract val appActivityName: String?
abstract val enableActivityLevelBlocking: Boolean
class BlockedCategory(
val deviceAndUserRelatedData: DeviceAndUserRelatedData, val deviceAndUserRelatedData: DeviceAndUserRelatedData,
val blockingHandling: CategoryItselfHandling, val blockingHandling: CategoryItselfHandling,
val appBaseHandling: AppBaseHandling,
val level: BlockingLevel, val level: BlockingLevel,
val userRelatedData: UserRelatedData override val userRelatedData: UserRelatedData,
): LockscreenContent() { override val appPackageName: String,
override val appActivityName: String?
): Blocked() {
val appCategoryTitle = blockingHandling.createdWithCategoryRelatedData.category.title val appCategoryTitle = blockingHandling.createdWithCategoryRelatedData.category.title
val reason = blockingHandling.activityBlockingReason val reason = blockingHandling.activityBlockingReason
val deviceId = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.id val deviceId = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.id
@ -216,12 +228,15 @@ sealed class LockscreenContent {
val blockedCategoryId = blockingHandling.createdWithCategoryRelatedData.category.id val blockedCategoryId = blockingHandling.createdWithCategoryRelatedData.category.id
val deviceRelatedData = deviceAndUserRelatedData.deviceRelatedData val deviceRelatedData = deviceAndUserRelatedData.deviceRelatedData
val hasFullVersion = deviceRelatedData.isConnectedAndHasPremium || deviceRelatedData.isLocalMode val hasFullVersion = deviceRelatedData.isConnectedAndHasPremium || deviceRelatedData.isLocalMode
val enableActivityLevelBlocking = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.enableActivityLevelBlocking override val enableActivityLevelBlocking = deviceAndUserRelatedData.deviceRelatedData.deviceEntry.enableActivityLevelBlocking
} }
data class BlockDueToNoCategory( class BlockDueToNoCategory(
val userRelatedData: UserRelatedData, override val userRelatedData: UserRelatedData,
val deviceId: String, val deviceId: String,
val enableActivityLevelBlocking: Boolean override val enableActivityLevelBlocking: Boolean,
): LockscreenContent() override val appPackageName: String,
override val appActivityName: String?
): Blocked()
}
} }

View file

@ -30,8 +30,8 @@ import io.timelimit.android.data.extensions.sortedCategories
import io.timelimit.android.data.model.* import io.timelimit.android.data.model.*
import io.timelimit.android.data.model.derived.DeviceRelatedData 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.databinding.LockFragmentBinding
import io.timelimit.android.databinding.LockFragmentCategoryButtonBinding import io.timelimit.android.databinding.LockFragmentCategoryButtonBinding
import io.timelimit.android.databinding.LockReasonFragmentBinding
import io.timelimit.android.date.DateInTimezone import io.timelimit.android.date.DateInTimezone
import io.timelimit.android.livedata.* import io.timelimit.android.livedata.*
import io.timelimit.android.logic.* import io.timelimit.android.logic.*
@ -53,38 +53,13 @@ import io.timelimit.android.ui.payment.RequiresPurchaseDialogFragment
import io.timelimit.android.ui.view.SelectTimeSpanViewListener import io.timelimit.android.ui.view.SelectTimeSpanViewListener
import java.util.* import java.util.*
class LockFragment : Fragment() { class LockReasonFragment : Fragment() {
companion object { 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 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 val auth: ActivityViewModel by lazy { getActivityViewModel(requireActivity()) }
private lateinit var binding: LockFragmentBinding private lateinit var binding: LockReasonFragmentBinding
private val model: LockModel by activityViewModels() private val model: LockModel by activityViewModels()
private fun setupHandlers(deviceId: String, userRelatedData: UserRelatedData, blockedCategoryId: String?) { private fun setupHandlers(deviceId: String, userRelatedData: UserRelatedData, blockedCategoryId: String?) {
@ -140,23 +115,23 @@ class LockFragment : Fragment() {
(activity as LockActivity).showAuthenticationScreen() (activity as LockActivity).showAuthenticationScreen()
} }
override fun setThisDeviceAsCurrentDevice() = this@LockFragment.setThisDeviceAsCurrentDevice() override fun setThisDeviceAsCurrentDevice() = this@LockReasonFragment.setThisDeviceAsCurrentDevice()
override fun requestLocationPermission() { override fun requestLocationPermission() {
RequestWifiPermission.doRequest(this@LockFragment, LOCATION_REQUEST_CODE) RequestWifiPermission.doRequest(this@LockReasonFragment, LOCATION_REQUEST_CODE)
} }
} }
} }
private fun setThisDeviceAsCurrentDevice() { private fun setThisDeviceAsCurrentDevice() {
didOpenSetCurrentDeviceScreen = true model.didOpenSetCurrentDeviceScreen = true
UpdatePrimaryDeviceDialogFragment UpdatePrimaryDeviceDialogFragment
.newInstance(UpdatePrimaryDeviceRequestType.SetThisDevice) .newInstance(UpdatePrimaryDeviceRequestType.SetThisDevice)
.show(parentFragmentManager) .show(parentFragmentManager)
} }
private fun bindAddToCategoryOptions(userRelatedData: UserRelatedData) { private fun bindAddToCategoryOptions(userRelatedData: UserRelatedData, blockedPackageName: String) {
binding.addToCategoryOptions.removeAllViews() binding.addToCategoryOptions.removeAllViews()
userRelatedData.sortedCategories().forEach { (_, category) -> userRelatedData.sortedCategories().forEach { (_, category) ->
@ -166,7 +141,7 @@ class LockFragment : Fragment() {
auth.tryDispatchParentAction( auth.tryDispatchParentAction(
AddCategoryAppsAction( AddCategoryAppsAction(
categoryId = category.category.id, categoryId = category.category.id,
packageNames = listOf(packageName) packageNames = listOf(blockedPackageName)
) )
) )
} }
@ -238,22 +213,8 @@ class LockFragment : Fragment() {
model.missingNetworkIdPermission.observe(viewLifecycleOwner) { binding.missingNetworkIdPermission = it } 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 { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = LockFragmentBinding.inflate(layoutInflater, container, false) binding = LockReasonFragmentBinding.inflate(layoutInflater, container, false)
AuthenticationFab.manageAuthenticationFab( AuthenticationFab.manageAuthenticationFab(
fab = binding.fab, 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.appTitle = model.title ?: "???"
binding.appIcon.setImageDrawable(model.icon) binding.appIcon.setImageDrawable(model.icon)
@ -288,9 +249,11 @@ class LockFragment : Fragment() {
requireActivity().finish() requireActivity().finish()
} }
is LockscreenContent.BlockedCategory -> { is LockscreenContent.Blocked -> {
binding.activityName = if (content.enableActivityLevelBlocking) activityName?.removePrefix(packageName) else null binding.activityName = if (content.enableActivityLevelBlocking) content.appActivityName?.removePrefix(content.appPackageName) else null
when (content) {
is LockscreenContent.Blocked.BlockedCategory -> {
binding.appCategoryTitle = content.appCategoryTitle binding.appCategoryTitle = content.appCategoryTitle
binding.reason = content.reason binding.reason = content.reason
binding.blockedKindLabel = when (content.level) { binding.blockedKindLabel = when (content.level) {
@ -313,14 +276,8 @@ class LockFragment : Fragment() {
activity = requireActivity(), activity = requireActivity(),
hasFullVersion = content.hasFullVersion hasFullVersion = content.hasFullVersion
) )
if (content.reason == BlockingReason.RequiresCurrentDevice && !didOpenSetCurrentDeviceScreen && isResumed) {
setThisDeviceAsCurrentDevice()
} else null
} }
is LockscreenContent.BlockDueToNoCategory -> { is LockscreenContent.Blocked.BlockDueToNoCategory -> {
binding.activityName = if (content.enableActivityLevelBlocking) activityName?.removePrefix(packageName) else null
binding.appCategoryTitle = null binding.appCategoryTitle = null
binding.reason = BlockingReason.NotPartOfAnCategory binding.reason = BlockingReason.NotPartOfAnCategory
binding.blockedKindLabel = "App" binding.blockedKindLabel = "App"
@ -331,7 +288,12 @@ class LockFragment : Fragment() {
userRelatedData = content.userRelatedData userRelatedData = content.userRelatedData
) )
bindAddToCategoryOptions(content.userRelatedData) bindAddToCategoryOptions(
userRelatedData = content.userRelatedData,
blockedPackageName = content.appPackageName
)
}
}.let {/* require handling all paths */}
} }
}.let {/* require handling all paths */} }.let {/* require handling all paths */}
} }

View file

@ -13,9 +13,10 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
--> -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.viewpager.widget.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:id="@+id/container" android:id="@+id/pager"
tools:context=".ui.lock.LockActivity" /> tools:context=".ui.lock.LockActivity" />

View file

@ -16,7 +16,7 @@
<layout xmlns:android="http://schemas.android.com/apk/res/android" <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:context=".ui.lock.LockFragment"> tools:context=".ui.lock.LockReasonFragment">
<data> <data>
<variable <variable