-
-
Notifications
You must be signed in to change notification settings - Fork 530
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refact(Android): allow for different fragment types inside ScreenContainer #1887
Merged
Merged
Changes from 25 commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
55170ce
Add FragmentHolder interface
kkafar 1f31afb
Add ScreenFragmentWrapper interface
kkafar 103ce7e
Add onContainerUpdate to ScreenFragmentWrapper interface
kkafar 920a1a0
Add activity & context resolving methods to ScreenFragmentWrapper
kkafar 6e1ba67
Add childScreenContainers to ScreenFragmentWrapper interface
kkafar 50ccfaa
Add ScreenLifecycleEventDispatcher interface
kkafar 5c7f455
Rename ScreenLifecycleEventDispatcher -> ScreenEventDispatcher
kkafar 9692479
ScreenFragmentWrapper extends ScreenEventDispatcher
kkafar 108bdfa
Add more communication-with-continer-related methods to ScreenFragmen…
kkafar 2f8cbc8
Add View.recycle extension method
kkafar 36ca192
Fix method signatures in ScreenEventDispatcherInterface
kkafar 2562241
Partially migrate ScreenFragment
kkafar 6eb753f
Finish initial implementation of ScreenFragmentWrapper for ScreenFrag…
kkafar 33f4e11
Test migration of ScreenContainer to use ScreenFragmentWrapper instea…
kkafar 433441d
Fix type specs for ScreenContainer<*> -> just ScreenContainer
kkafar aa1fa27
Fix type specs in ScreenStackFragment
kkafar 519180b
Pass fragment wrapper to a Screen
kkafar 73e7d88
More adaptation in ScreenContainer
kkafar 732a0ec
Start separating ScreenStackFragmentWrapper interface
kkafar 745a647
Implement ScreenStackFragmentWrapper for ScreenStackFragment (in curr…
kkafar fafc033
Initial changes in ScreenStack
kkafar b05fdbd
Add canNavigateBack method to wrapper interface
kkafar b6f02bd
Add dismiss method to wrapper interface
kkafar 3e4373d
Finish initial migration of ScreenStack
kkafar 277fbd9
Make it compile
kkafar de2dadc
Remove cherry-pick leftover
kkafar e947d9a
Unify naming between properties and methods
kkafar ee40686
Revert "Add View.recycle extension method"
kkafar cc8b2df
Merge branch 'main' into @kkafar/partial-android-refactor
kkafar eac2adc
Fix nullability handling while casting newTop
kkafar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
android/src/main/java/com/swmansion/rnscreens/FragmentHolder.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.swmansion.rnscreens | ||
|
||
import androidx.fragment.app.Fragment | ||
|
||
interface FragmentHolder { | ||
val fragment: Fragment | ||
} | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,9 +16,9 @@ import com.facebook.react.modules.core.ChoreographerCompat | |
import com.facebook.react.modules.core.ReactChoreographer | ||
import com.swmansion.rnscreens.Screen.ActivityState | ||
|
||
open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(context) { | ||
open class ScreenContainer(context: Context?) : ViewGroup(context) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
@JvmField | ||
protected val mScreenFragments = ArrayList<T>() | ||
protected val mScreenFragments = ArrayList<ScreenFragmentWrapper>() | ||
@JvmField | ||
protected var mFragmentManager: FragmentManager? = null | ||
private var mIsAttached = false | ||
|
@@ -34,7 +34,7 @@ open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(co | |
layout(left, top, right, bottom) | ||
} | ||
} | ||
private var mParentScreenFragment: ScreenFragment? = null | ||
private var mParentScreenFragment: ScreenFragmentWrapper? = null | ||
|
||
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { | ||
var i = 0 | ||
|
@@ -87,14 +87,11 @@ open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(co | |
performUpdatesNow() | ||
} | ||
|
||
protected open fun adapt(screen: Screen): T { | ||
@Suppress("UNCHECKED_CAST") | ||
return ScreenFragment(screen) as T | ||
} | ||
protected open fun adapt(screen: Screen): ScreenFragmentWrapper = ScreenFragment(screen) | ||
|
||
fun addScreen(screen: Screen, index: Int) { | ||
val fragment = adapt(screen) | ||
screen.fragment = fragment | ||
screen.fragmentWrapper = fragment | ||
mScreenFragments.add(index, fragment) | ||
screen.container = this | ||
onScreenChanged() | ||
|
@@ -119,6 +116,8 @@ open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(co | |
|
||
fun getScreenAt(index: Int): Screen = mScreenFragments[index].screen | ||
|
||
fun getScreenFragmentWrapperAt(index: Int): ScreenFragmentWrapper = mScreenFragments[index] | ||
|
||
open val topScreen: Screen? | ||
get() = mScreenFragments.firstOrNull { getActivityState(it) === ActivityState.ON_TOP }?.screen | ||
|
||
|
@@ -174,10 +173,10 @@ open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(co | |
// Otherwise we expect to connect directly with root view and get root fragment manager | ||
if (parent is Screen) { | ||
checkNotNull( | ||
parent.fragment?.let { screenFragment -> | ||
mParentScreenFragment = screenFragment | ||
screenFragment.registerChildScreenContainer(this) | ||
setFragmentManager(screenFragment.childFragmentManager) | ||
parent.fragmentWrapper?.let { fragmentWrapper -> | ||
mParentScreenFragment = fragmentWrapper | ||
fragmentWrapper.addChildContainer(this) | ||
setFragmentManager(fragmentWrapper.fragment.childFragmentManager) | ||
} | ||
) { "Parent Screen does not have its Fragment attached" } | ||
} else { | ||
|
@@ -197,19 +196,19 @@ open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(co | |
.setReorderingAllowed(true) | ||
} | ||
|
||
private fun attachScreen(transaction: FragmentTransaction, screenFragment: ScreenFragment) { | ||
transaction.add(id, screenFragment) | ||
private fun attachScreen(transaction: FragmentTransaction, fragment: Fragment) { | ||
transaction.add(id, fragment) | ||
} | ||
|
||
private fun detachScreen(transaction: FragmentTransaction, screenFragment: ScreenFragment) { | ||
transaction.remove(screenFragment) | ||
private fun detachScreen(transaction: FragmentTransaction, fragment: Fragment) { | ||
transaction.remove(fragment) | ||
} | ||
|
||
private fun getActivityState(screenFragment: ScreenFragment): ActivityState? = | ||
screenFragment.screen.activityState | ||
private fun getActivityState(screenFragmentWrapper: ScreenFragmentWrapper): ActivityState? = | ||
screenFragmentWrapper.screen.activityState | ||
|
||
open fun hasScreen(screenFragment: ScreenFragment?): Boolean = | ||
mScreenFragments.contains(screenFragment) | ||
open fun hasScreen(screenFragmentWrapper: ScreenFragmentWrapper?): Boolean = | ||
mScreenFragments.contains(screenFragmentWrapper) | ||
|
||
override fun onAttachedToWindow() { | ||
super.onAttachedToWindow() | ||
|
@@ -246,7 +245,7 @@ open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(co | |
} | ||
} | ||
|
||
mParentScreenFragment?.unregisterChildScreenContainer(this) | ||
mParentScreenFragment?.removeChildContainer(this) | ||
mParentScreenFragment = null | ||
|
||
super.onDetachedFromWindow() | ||
|
@@ -320,13 +319,13 @@ open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(co | |
"mFragmentManager is null when performing update in ScreenContainer" | ||
}.fragments | ||
) | ||
for (screenFragment in mScreenFragments) { | ||
if (getActivityState(screenFragment) === ActivityState.INACTIVE && | ||
screenFragment.isAdded | ||
for (fragmentWrapper in mScreenFragments) { | ||
if (getActivityState(fragmentWrapper) === ActivityState.INACTIVE && | ||
fragmentWrapper.fragment.isAdded | ||
) { | ||
detachScreen(it, screenFragment) | ||
detachScreen(it, fragmentWrapper.fragment) | ||
} | ||
orphaned.remove(screenFragment) | ||
orphaned.remove(fragmentWrapper.fragment) | ||
} | ||
if (orphaned.isNotEmpty()) { | ||
val orphanedAry = orphaned.toTypedArray() | ||
|
@@ -344,30 +343,30 @@ open class ScreenContainer<T : ScreenFragment>(context: Context?) : ViewGroup(co | |
|
||
// attach newly activated screens | ||
var addedBefore = false | ||
val pendingFront: ArrayList<T> = ArrayList() | ||
val pendingFront: ArrayList<ScreenFragmentWrapper> = ArrayList() | ||
|
||
for (screenFragment in mScreenFragments) { | ||
val activityState = getActivityState(screenFragment) | ||
if (activityState !== ActivityState.INACTIVE && !screenFragment.isAdded) { | ||
for (fragmentWrapper in mScreenFragments) { | ||
val activityState = getActivityState(fragmentWrapper) | ||
if (activityState !== ActivityState.INACTIVE && !fragmentWrapper.fragment.isAdded) { | ||
addedBefore = true | ||
attachScreen(it, screenFragment) | ||
attachScreen(it, fragmentWrapper.fragment) | ||
} else if (activityState !== ActivityState.INACTIVE && addedBefore) { | ||
// we detach the screen and then reattach it later to make it appear on front | ||
detachScreen(it, screenFragment) | ||
pendingFront.add(screenFragment) | ||
detachScreen(it, fragmentWrapper.fragment) | ||
pendingFront.add(fragmentWrapper) | ||
} | ||
screenFragment.screen.setTransitioning(transitioning) | ||
fragmentWrapper.screen.setTransitioning(transitioning) | ||
} | ||
|
||
for (screenFragment in pendingFront) { | ||
attachScreen(it, screenFragment) | ||
attachScreen(it, screenFragment.fragment) | ||
} | ||
|
||
it.commitNowAllowingStateLoss() | ||
} | ||
} | ||
|
||
protected open fun notifyContainerUpdate() { | ||
topScreen?.fragment?.onContainerUpdate() | ||
topScreen?.fragmentWrapper?.onContainerUpdate() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
android/src/main/java/com/swmansion/rnscreens/ScreenEventDispatcher.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.swmansion.rnscreens | ||
|
||
interface ScreenEventDispatcher { | ||
fun canDispatchLifecycleEvent(event: ScreenFragment.ScreenLifecycleEvent): Boolean | ||
fun updateLastEventDispatched(event: ScreenFragment.ScreenLifecycleEvent) | ||
|
||
/** | ||
* Dispatches given screen lifecycle event to JS using screen from given fragment `fragmentWrapper` | ||
*/ | ||
fun dispatchLifecycleEvent(event: ScreenFragment.ScreenLifecycleEvent, fragmentWrapper: ScreenFragmentWrapper) | ||
|
||
/** | ||
* Dispatches given screen lifecycle event from all non-empty child containers to JS | ||
*/ | ||
fun dispatchLifecycleEventInChildContainers(event: ScreenFragment.ScreenLifecycleEvent) | ||
|
||
fun dispatchHeaderBackButtonClickedEvent() | ||
fun dispatchTransitionProgressEvent(alpha: Float, closing: Boolean) | ||
|
||
// Concrete dispatchers | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Decided to split this property to separate interface as this is the key idea behind this PR.
Also in the future I plan to make
ScreenFragmentWrapper
interfaces much more granular (split those into number of fine-grained interfaces.