mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-06 03:50:23 +02:00
Use a more reliable fragment id generation
This commit is contained in:
parent
dac0ce74fe
commit
c0d723ee00
3 changed files with 28 additions and 15 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 - 2021 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2023 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
|
||||||
|
@ -16,9 +16,19 @@
|
||||||
package io.timelimit.android
|
package io.timelimit.android
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.view.View
|
||||||
import com.jakewharton.threetenabp.AndroidThreeTen
|
import com.jakewharton.threetenabp.AndroidThreeTen
|
||||||
|
|
||||||
class Application : Application() {
|
class Application : Application() {
|
||||||
|
// two legacy screens use small id numbers as they want; by running generateViewId() often enough,
|
||||||
|
// all ids that are harcoded this way are not returned from generateViewId
|
||||||
|
init { (0..1024).forEach { _ -> View.generateViewId() } }
|
||||||
|
|
||||||
|
// allocate some view ids for Fragments that are not used for anything else
|
||||||
|
// by running this in the Application class, there is a high chance that these
|
||||||
|
// are always the same ids so that there is no trouble when restoring state
|
||||||
|
val viewIdPool = (0..4).map { View.generateViewId() }
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,6 @@ class MainActivity : AppCompatActivity(), ActivityViewModelHolder, U2fManager.De
|
||||||
private const val EXTRA_AUTH_HANDOVER = "authHandover"
|
private const val EXTRA_AUTH_HANDOVER = "authHandover"
|
||||||
private const val MAIN_MODEL_STATE = "mainModelState"
|
private const val MAIN_MODEL_STATE = "mainModelState"
|
||||||
private const val FRAGMENT_IDS_STATE = "fragmentIds"
|
private const val FRAGMENT_IDS_STATE = "fragmentIds"
|
||||||
private const val NEXT_FRAGMENT_ID = "nextFragmentId"
|
|
||||||
|
|
||||||
private var authHandover: Triple<Long, Long, AuthenticatedUser>? = null
|
private var authHandover: Triple<Long, Long, AuthenticatedUser>? = null
|
||||||
|
|
||||||
|
@ -114,7 +113,6 @@ class MainActivity : AppCompatActivity(), ActivityViewModelHolder, U2fManager.De
|
||||||
}
|
}
|
||||||
|
|
||||||
private val mainModel by viewModels<MainModel>()
|
private val mainModel by viewModels<MainModel>()
|
||||||
private var fragmentIds = mutableSetOf<Int>()
|
|
||||||
private val syncModel: SyncStatusModel by lazy {
|
private val syncModel: SyncStatusModel by lazy {
|
||||||
ViewModelProviders.of(this).get(SyncStatusModel::class.java)
|
ViewModelProviders.of(this).get(SyncStatusModel::class.java)
|
||||||
}
|
}
|
||||||
|
@ -134,8 +132,7 @@ class MainActivity : AppCompatActivity(), ActivityViewModelHolder, U2fManager.De
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
mainModel.state.value = savedInstanceState.getSerializable(MAIN_MODEL_STATE) as State
|
mainModel.state.value = savedInstanceState.getSerializable(MAIN_MODEL_STATE) as State
|
||||||
fragmentIds.addAll(savedInstanceState.getIntegerArrayList(FRAGMENT_IDS_STATE) ?: emptyList())
|
mainModel.fragmentIds.addAll(savedInstanceState.getIntegerArrayList(FRAGMENT_IDS_STATE) ?: emptyList())
|
||||||
mainModel.nextFragmentId = savedInstanceState.getInt(NEXT_FRAGMENT_ID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
|
@ -279,7 +276,7 @@ class MainActivity : AppCompatActivity(), ActivityViewModelHolder, U2fManager.De
|
||||||
screen = screen,
|
screen = screen,
|
||||||
executeCommand = ::execute,
|
executeCommand = ::execute,
|
||||||
fragmentManager = supportFragmentManager,
|
fragmentManager = supportFragmentManager,
|
||||||
fragmentIds = fragmentIds,
|
fragmentIds = mainModel.fragmentIds,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(paddingValues)
|
.padding(paddingValues)
|
||||||
|
@ -300,8 +297,7 @@ class MainActivity : AppCompatActivity(), ActivityViewModelHolder, U2fManager.De
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
|
|
||||||
outState.putSerializable(MAIN_MODEL_STATE, mainModel.state.value)
|
outState.putSerializable(MAIN_MODEL_STATE, mainModel.state.value)
|
||||||
outState.putIntegerArrayList(FRAGMENT_IDS_STATE, ArrayList(fragmentIds))
|
outState.putIntegerArrayList(FRAGMENT_IDS_STATE, ArrayList(mainModel.fragmentIds))
|
||||||
outState.putInt(NEXT_FRAGMENT_ID, mainModel.nextFragmentId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
|
@ -373,7 +369,7 @@ class MainActivity : AppCompatActivity(), ActivityViewModelHolder, U2fManager.De
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cleanupFragments() {
|
private fun cleanupFragments() {
|
||||||
fragmentIds
|
mainModel.fragmentIds
|
||||||
.filter { fragmentId ->
|
.filter { fragmentId ->
|
||||||
var v = mainModel.state.value as State?
|
var v = mainModel.state.value as State?
|
||||||
|
|
||||||
|
@ -385,8 +381,7 @@ class MainActivity : AppCompatActivity(), ActivityViewModelHolder, U2fManager.De
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
.map { supportFragmentManager.findFragmentById(it) }
|
.mapNotNull { supportFragmentManager.findFragmentById(it) }
|
||||||
.filterNotNull()
|
|
||||||
.filter { it.isDetached }
|
.filter { it.isDetached }
|
||||||
.forEach {
|
.forEach {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
|
@ -399,7 +394,7 @@ class MainActivity : AppCompatActivity(), ActivityViewModelHolder, U2fManager.De
|
||||||
.remove(it)
|
.remove(it)
|
||||||
.commitAllowingStateLoss()
|
.commitAllowingStateLoss()
|
||||||
|
|
||||||
fragmentIds.remove(id)
|
mainModel.fragmentIds.remove(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ class MainModel(application: Application): AndroidViewModel(application) {
|
||||||
|
|
||||||
val activityCommand: ReceiveChannel<ActivityCommand> = activityCommandInternal
|
val activityCommand: ReceiveChannel<ActivityCommand> = activityCommandInternal
|
||||||
val state = MutableStateFlow(State.LaunchState as State)
|
val state = MutableStateFlow(State.LaunchState as State)
|
||||||
var nextFragmentId = 1
|
var fragmentIds = mutableSetOf<Int>()
|
||||||
|
|
||||||
val screen: Flow<Screen> = flow {
|
val screen: Flow<Screen> = flow {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -93,9 +93,17 @@ class MainModel(application: Application): AndroidViewModel(application) {
|
||||||
is State.DiagnoseScreen.DeviceOwner -> emitAll(DeviceOwnerHandling.processState(logic, scope, authenticationModelApi, state))
|
is State.DiagnoseScreen.DeviceOwner -> emitAll(DeviceOwnerHandling.processState(logic, scope, authenticationModelApi, state))
|
||||||
is FragmentState -> emitAll(state.transformWhile {
|
is FragmentState -> emitAll(state.transformWhile {
|
||||||
if (it is FragmentState && it !is State.Overview) {
|
if (it is FragmentState && it !is State.Overview) {
|
||||||
if (it.containerId == null) it.containerId = nextFragmentId++
|
val containerId = it.containerId ?: run {
|
||||||
|
((application as io.timelimit.android.Application).viewIdPool - fragmentIds).firstOrNull()?.also { id ->
|
||||||
|
it.containerId = id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emit(Screen.FragmentScreen(it, it.toolbarIcons, it.toolbarOptions, it, it.containerId!!))
|
if (containerId != null) {
|
||||||
|
fragmentIds.add(containerId)
|
||||||
|
|
||||||
|
emit(Screen.FragmentScreen(it, it.toolbarIcons, it.toolbarOptions, it, containerId))
|
||||||
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
} else false
|
} else false
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue