viewcontroller viewModel management logic now in separate module
rename FragmentWithState to StatefulFragment fix navigation class files packages
This commit is contained in:
parent
2015daf5d1
commit
372750eee4
|
|
@ -20,7 +20,8 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
api project(":navigation-base")
|
||||
implementation project(":logging")
|
||||
implementation project(":navigation-base")
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package ru.touchin.roboswag.bottom_navigation_fragment
|
||||
package ru.touchin.roboswag.bottom_navigation_base
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.IdRes
|
||||
|
|
@ -6,13 +6,14 @@ import androidx.fragment.app.FragmentManager
|
|||
import ru.touchin.roboswag.navigation_base.FragmentNavigation
|
||||
import ru.touchin.roboswag.navigation_base.activities.NavigationActivity
|
||||
|
||||
abstract class BaseBottomNavigationActivity<
|
||||
TNavigation : FragmentNavigation,
|
||||
TNavigationFragment : BaseBottomNavigationFragment<*>,
|
||||
TNavigationContainer : BaseNavigationContainerFragment<*, TNavigation>> : NavigationActivity<TNavigation>() {
|
||||
abstract class BaseBottomNavigationActivity<TNavigation, TNavigationFragment, TNavigationContainer> : NavigationActivity<TNavigation>()
|
||||
where TNavigation : FragmentNavigation,
|
||||
TNavigationFragment : BaseBottomNavigationFragment<*>,
|
||||
TNavigationContainer : BaseNavigationContainerFragment<*, TNavigation>
|
||||
{
|
||||
|
||||
val innerNavigation: TNavigation
|
||||
get() = getNavigationContainer(supportFragmentManager)?.navigation ?: navigation
|
||||
get() = getNavigationContainer(supportFragmentManager)?.navigation ?: navigation
|
||||
|
||||
/**
|
||||
* Navigates to the given navigation tab.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package ru.touchin.roboswag.bottom_navigation_fragment
|
||||
package ru.touchin.roboswag.bottom_navigation_base
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
|
|
@ -13,16 +13,17 @@ import androidx.core.view.children
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException
|
||||
import ru.touchin.roboswag.navigation_base.fragments.BaseFragment
|
||||
import ru.touchin.roboswag.navigation_base.fragments.StatefulFragment
|
||||
|
||||
abstract class BaseBottomNavigationController<TNavigationTab : BaseNavigationTab>(
|
||||
private val tabs: SparseArray<TNavigationTab>,
|
||||
private val context: Context,
|
||||
private val fragmentManager: FragmentManager,
|
||||
@IdRes private val defaultTabId: Int = 0, // If it zero back press with empty fragment back stack would close the app
|
||||
@IdRes private val contentContainerViewId: Int,
|
||||
@LayoutRes private val contentContainerLayoutId: Int,
|
||||
private val wrapWithNavigationContainer: Boolean = false
|
||||
@IdRes private val contentContainerViewId: Int,
|
||||
@IdRes private val defaultTabId: Int = 0, // If it zero back press with empty fragment back stack would close the app
|
||||
private val wrapWithNavigationContainer: Boolean = false,
|
||||
private val onReselectListener: (() -> Unit)? = null
|
||||
) {
|
||||
|
||||
private var callback: FragmentManager.FragmentLifecycleCallbacks? = null
|
||||
|
|
@ -111,7 +112,9 @@ abstract class BaseBottomNavigationController<TNavigationTab : BaseNavigationTab
|
|||
|
||||
protected open fun getNavigationContainerClass(): Class<out BaseNavigationContainerFragment<*, *>> = BaseNavigationContainerFragment::class.java
|
||||
|
||||
protected open fun onTabReselected() = Unit
|
||||
protected open fun onTabReselected() {
|
||||
onReselectListener?.invoke()
|
||||
}
|
||||
|
||||
protected open fun isTabClass(tab: TNavigationTab, fragment: Fragment?) = if (wrapWithNavigationContainer) {
|
||||
(fragment as BaseNavigationContainerFragment<*, *>).getContainedClass()
|
||||
|
|
@ -130,7 +133,7 @@ abstract class BaseBottomNavigationController<TNavigationTab : BaseNavigationTab
|
|||
Fragment.instantiate(
|
||||
context,
|
||||
clazz.name,
|
||||
BaseFragment.args(state)
|
||||
StatefulFragment.args(state)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package ru.touchin.roboswag.bottom_navigation_fragment
|
||||
package ru.touchin.roboswag.bottom_navigation_base
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package ru.touchin.roboswag.bottom_navigation_fragment
|
||||
package ru.touchin.roboswag.bottom_navigation_base
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
package ru.touchin.roboswag.bottom_navigation_fragment
|
||||
package ru.touchin.roboswag.bottom_navigation_base
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import ru.touchin.roboswag.navigation_base.fragments.EmptyState
|
||||
import ru.touchin.roboswag.navigation_base.extensions.copy
|
||||
|
||||
open class BaseNavigationTab(
|
||||
open val cls: Class<*>,
|
||||
|
|
@ -14,31 +13,13 @@ open class BaseNavigationTab(
|
|||
val saveStateOnSwitching: Boolean = true
|
||||
) {
|
||||
|
||||
/**
|
||||
* It is value as class body property instead of value as constructor parameter to specify
|
||||
* custom getter of this field which returns copy of Parcelable every time it be called.
|
||||
* This is necessary to avoid modifying this value if it would be a value as constructor parameter
|
||||
* and every getting of this value would return the same instance.
|
||||
*/
|
||||
val state = state
|
||||
get() = field.copy()
|
||||
|
||||
private fun Parcelable.copy(): Parcelable =
|
||||
if (this is EmptyState) {
|
||||
EmptyState
|
||||
} else {
|
||||
val parcel = Parcel.obtain()
|
||||
|
||||
parcel.writeParcelable(this, 0)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val result = parcel.readParcelable<Parcelable>(
|
||||
javaClass.classLoader ?: Thread.currentThread().contextClassLoader
|
||||
) ?: throw IllegalStateException("Failed to copy tab state")
|
||||
|
||||
parcel.recycle()
|
||||
|
||||
result
|
||||
}
|
||||
/**
|
||||
* It is value as class body property instead of value as constructor parameter to specify
|
||||
* custom getter of this field which returns copy of Parcelable every time it be called.
|
||||
* This is necessary to avoid modifying this value if it would be a value as constructor parameter
|
||||
* and every getting of this value would return the same instance.
|
||||
*/
|
||||
val state = state
|
||||
get() = field.copy()
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
api project(":navigation-base")
|
||||
api project(":bottom-navigation-base")
|
||||
implementation project(":navigation-base")
|
||||
implementation project(":bottom-navigation-base")
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package ru.touchin.roboswag.bottom_navigation_fragment
|
||||
|
||||
import ru.touchin.roboswag.bottom_navigation_base.BaseBottomNavigationActivity
|
||||
import ru.touchin.roboswag.navigation_base.FragmentNavigation
|
||||
|
||||
abstract class BottomNavigationActivity :
|
||||
|
|
|
|||
|
|
@ -5,21 +5,23 @@ import android.util.SparseArray
|
|||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import ru.touchin.roboswag.bottom_navigation_base.BaseBottomNavigationController
|
||||
|
||||
class BottomNavigationController(
|
||||
context: Context,
|
||||
fragments: SparseArray<NavigationTab>,
|
||||
fragmentManager: FragmentManager,
|
||||
wrapWithNavigationContainer: Boolean = false,
|
||||
@IdRes private val defaultTabId: Int = 0, // If it zero back press with empty fragment back stack would close the app
|
||||
@IdRes private val contentContainerViewId: Int,
|
||||
@LayoutRes private val contentContainerLayoutId: Int,
|
||||
private val onReselectListener: (() -> Unit)? = null
|
||||
@IdRes private val contentContainerViewId: Int,
|
||||
@IdRes private val defaultTabId: Int = 0, // If it zero back press with empty fragment back stack would close the app
|
||||
onReselectListener: (() -> Unit)? = null
|
||||
) : BaseBottomNavigationController<NavigationTab>(
|
||||
tabs = fragments,
|
||||
context = context,
|
||||
fragmentManager = fragmentManager,
|
||||
defaultTabId = defaultTabId,
|
||||
onReselectListener = onReselectListener,
|
||||
contentContainerViewId = contentContainerViewId,
|
||||
contentContainerLayoutId = contentContainerLayoutId,
|
||||
wrapWithNavigationContainer = wrapWithNavigationContainer
|
||||
|
|
@ -27,8 +29,4 @@ class BottomNavigationController(
|
|||
|
||||
override fun getNavigationContainerClass() = NavigationContainerFragment::class.java
|
||||
|
||||
override fun onTabReselected() {
|
||||
onReselectListener?.invoke()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package ru.touchin.roboswag.bottom_navigation_fragment
|
||||
|
||||
import ru.touchin.roboswag.bottom_navigation_base.BaseBottomNavigationFragment
|
||||
|
||||
abstract class BottomNavigationFragment : BaseBottomNavigationFragment<NavigationTab>() {
|
||||
|
||||
override fun createNavigationController() = BottomNavigationController(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package ru.touchin.roboswag.bottom_navigation_fragment
|
||||
|
||||
import android.os.Parcelable
|
||||
import ru.touchin.roboswag.bottom_navigation_base.BaseNavigationContainerFragment
|
||||
import ru.touchin.roboswag.navigation_base.FragmentNavigation
|
||||
import ru.touchin.roboswag.navigation_base.fragments.BaseFragment
|
||||
import ru.touchin.roboswag.navigation_base.fragments.StatefulFragment
|
||||
|
||||
class NavigationContainerFragment : BaseNavigationContainerFragment<BaseFragment<out BottomNavigationActivity, Parcelable>, FragmentNavigation>() {
|
||||
class NavigationContainerFragment :
|
||||
BaseNavigationContainerFragment<StatefulFragment<out BottomNavigationActivity, Parcelable>, FragmentNavigation>() {
|
||||
|
||||
override val navigation by lazy {
|
||||
FragmentNavigation(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
package ru.touchin.roboswag.bottom_navigation_fragment
|
||||
|
||||
import android.os.Parcelable
|
||||
import ru.touchin.roboswag.navigation_base.fragments.BaseFragment
|
||||
import ru.touchin.roboswag.bottom_navigation_base.BaseNavigationTab
|
||||
import ru.touchin.roboswag.navigation_base.fragments.StatefulFragment
|
||||
|
||||
class NavigationTab(
|
||||
override val cls: Class<out BaseFragment<*, *>>,
|
||||
override val cls: Class<out StatefulFragment<*, *>>,
|
||||
state: Parcelable,
|
||||
saveStateOnSwitching: Boolean = true
|
||||
) : BaseNavigationTab(cls, state, saveStateOnSwitching)
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion versions.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(":lifecycle")
|
||||
implementation project(":navigation-viewcontroller")
|
||||
|
||||
compileOnly "javax.inject:javax.inject:1"
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
implementation "androidx.appcompat:appcompat:$versions.appcompat"
|
||||
|
||||
implementation "androidx.fragment:fragment:$versions.fragment"
|
||||
implementation "androidx.fragment:fragment-ktx:$versions.fragment"
|
||||
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:$versions.lifecycle"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<manifest package="ru.touchin.lifecycle_viewcontroller"/>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package ru.touchin.lifecycle_viewcontroller.extensions
|
||||
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelStoreOwner
|
||||
import ru.touchin.lifecycle_viewcontroller.viewmodel.LifecycleViewModelProviders
|
||||
import ru.touchin.roboswag.navigation_viewcontroller.viewcontrollers.ViewController
|
||||
import androidx.fragment.app.activityViewModels as androidActivityViewModels
|
||||
import androidx.fragment.app.viewModels as androidViewModels
|
||||
|
||||
@MainThread
|
||||
inline fun <reified VM : ViewModel> ViewController<*, *>.viewModels(
|
||||
noinline ownerProducer: () -> ViewModelStoreOwner = { this.fragment },
|
||||
noinline factoryProducer: () -> ViewModelProvider.Factory = { LifecycleViewModelProviders.getViewModelFactory(this) }
|
||||
) = this.fragment.androidViewModels<VM>(ownerProducer, factoryProducer)
|
||||
|
||||
@MainThread
|
||||
inline fun <reified VM : ViewModel> ViewController<*, *>.parentViewModels(
|
||||
noinline ownerProducer: () -> ViewModelStoreOwner = { this.fragment.parentFragment!! },
|
||||
noinline factoryProducer: () -> ViewModelProvider.Factory = {
|
||||
LifecycleViewModelProviders.getViewModelFactory(this.fragment.parentFragment!!)
|
||||
}
|
||||
) = viewModels<VM>(ownerProducer, factoryProducer)
|
||||
|
||||
@MainThread
|
||||
inline fun <reified VM : ViewModel> ViewController<*, *>.targetViewModels(
|
||||
noinline ownerProducer: () -> ViewModelStoreOwner = { this.fragment.targetFragment!! },
|
||||
noinline factoryProducer: () -> ViewModelProvider.Factory = {
|
||||
LifecycleViewModelProviders.getViewModelFactory(this.fragment.targetFragment!!)
|
||||
}
|
||||
) = viewModels<VM>(ownerProducer, factoryProducer)
|
||||
|
||||
@MainThread
|
||||
inline fun <reified VM : ViewModel> ViewController<*, *>.activityViewModels(
|
||||
noinline factoryProducer: () -> ViewModelProvider.Factory = { LifecycleViewModelProviders.getViewModelFactory(activity) }
|
||||
) = this.fragment.androidActivityViewModels<VM>(factoryProducer)
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package ru.touchin.lifecycle_viewcontroller.viewmodel
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import ru.touchin.lifecycle.viewmodel.BaseLifecycleViewModelProviders
|
||||
import ru.touchin.lifecycle.viewmodel.ViewModelFactoryProvider
|
||||
import ru.touchin.roboswag.navigation_viewcontroller.viewcontrollers.ViewController
|
||||
|
||||
object LifecycleViewModelProviders : BaseLifecycleViewModelProviders() {
|
||||
|
||||
/**
|
||||
* Returns ViewModelProvider.Factory instance from current lifecycleOwner.
|
||||
* Search #ViewModelFactoryProvider are produced according to priorities:
|
||||
* 1. View controller;
|
||||
* 2. Fragment;
|
||||
* 3. Parent fragment recursively;
|
||||
* 4. Activity;
|
||||
* 5. Application.
|
||||
*/
|
||||
override fun getViewModelFactory(provider: Any): ViewModelProvider.Factory =
|
||||
when (provider) {
|
||||
is ViewModelFactoryProvider -> provider.viewModelFactory
|
||||
is ViewController<*, *> -> getViewModelFactory(provider.fragment)
|
||||
is Fragment -> getViewModelFactory(provider.parentFragment ?: provider.requireActivity())
|
||||
is Activity -> getViewModelFactory(provider.application)
|
||||
else -> throw IllegalArgumentException("View model factory not found.")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,8 +19,6 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
api project(":navigation-viewcontroller")
|
||||
|
||||
compileOnly "javax.inject:javax.inject:1"
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
package ru.touchin.lifecycle.viewmodel
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
|
||||
abstract class BaseLifecycleViewModelProviders {
|
||||
|
||||
/**
|
||||
* Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given
|
||||
* {@code lifecycleOwner} is alive. More detailed explanation is in {@link ViewModel}.
|
||||
* <p>
|
||||
* It uses the given {@link Factory} to instantiate new ViewModels.
|
||||
*
|
||||
* @param lifecycleOwner a lifecycle owner, in whose scope ViewModels should be retained (ViewController, Fragment, Activity)
|
||||
* @param factory a {@code Factory} to instantiate new ViewModels
|
||||
* @return a ViewModelProvider instance
|
||||
*/
|
||||
open fun of(
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
factory: ViewModelProvider.Factory = LifecycleViewModelProviders.getViewModelFactory(lifecycleOwner)
|
||||
): ViewModelProvider =
|
||||
when (lifecycleOwner) {
|
||||
is Fragment -> ViewModelProvider(lifecycleOwner, factory)
|
||||
is FragmentActivity -> ViewModelProvider(lifecycleOwner, factory)
|
||||
else -> throw IllegalArgumentException("Not supported LifecycleOwner.")
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ViewModelProvider.Factory instance from current lifecycleOwner.
|
||||
* Search #ViewModelFactoryProvider are produced according to priorities:
|
||||
* 1. Fragment;
|
||||
* 2. Parent fragment recursively;
|
||||
* 3. Activity;
|
||||
* 4. Application.
|
||||
*/
|
||||
open fun getViewModelFactory(provider: Any): ViewModelProvider.Factory =
|
||||
when (provider) {
|
||||
is ViewModelFactoryProvider -> provider.viewModelFactory
|
||||
is Fragment -> LifecycleViewModelProviders.getViewModelFactory(provider.parentFragment ?: provider.requireActivity())
|
||||
is Activity -> LifecycleViewModelProviders.getViewModelFactory(provider.application)
|
||||
else -> throw IllegalArgumentException("View model factory not found.")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,49 +1,3 @@
|
|||
package ru.touchin.lifecycle.viewmodel
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import ru.touchin.roboswag.navigation_viewcontroller.viewcontrollers.ViewController
|
||||
|
||||
object LifecycleViewModelProviders {
|
||||
|
||||
/**
|
||||
* Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given
|
||||
* {@code lifecycleOwner} is alive. More detailed explanation is in {@link ViewModel}.
|
||||
* <p>
|
||||
* It uses the given {@link Factory} to instantiate new ViewModels.
|
||||
*
|
||||
* @param lifecycleOwner a lifecycle owner, in whose scope ViewModels should be retained (ViewController, Fragment, Activity)
|
||||
* @param factory a {@code Factory} to instantiate new ViewModels
|
||||
* @return a ViewModelProvider instance
|
||||
*/
|
||||
fun of(lifecycleOwner: LifecycleOwner, factory: ViewModelProvider.Factory = getViewModelFactory(lifecycleOwner)): ViewModelProvider =
|
||||
when (lifecycleOwner) {
|
||||
is ViewController<*, *> -> ViewModelProviders.of(lifecycleOwner.fragment, factory)
|
||||
is Fragment -> ViewModelProviders.of(lifecycleOwner, factory)
|
||||
is FragmentActivity -> ViewModelProviders.of(lifecycleOwner, factory)
|
||||
else -> throw IllegalArgumentException("Not supported LifecycleOwner.")
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ViewModelProvider.Factory instance from current lifecycleOwner.
|
||||
* Search #ViewModelFactoryProvider are produced according to priorities:
|
||||
* 1. View controller;
|
||||
* 2. Fragment;
|
||||
* 3. Parent fragment recursively;
|
||||
* 4. Activity;
|
||||
* 5. Application.
|
||||
*/
|
||||
fun getViewModelFactory(provider: Any): ViewModelProvider.Factory =
|
||||
when (provider) {
|
||||
is ViewModelFactoryProvider -> provider.viewModelFactory
|
||||
is ViewController<*, *> -> getViewModelFactory(provider.fragment)
|
||||
is Fragment -> getViewModelFactory(provider.parentFragment ?: provider.requireActivity())
|
||||
is Activity -> getViewModelFactory(provider.application)
|
||||
else -> throw IllegalArgumentException("View model factory not found.")
|
||||
}
|
||||
|
||||
}
|
||||
object LifecycleViewModelProviders : BaseLifecycleViewModelProviders()
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
api project(":utils")
|
||||
api project(":logging")
|
||||
implementation project(":utils")
|
||||
implementation project(":logging")
|
||||
|
||||
api 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
|
||||
api 'net.danlew:android.joda:2.10.2'
|
||||
implementation 'net.danlew:android.joda:2.10.2'
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import ru.touchin.roboswag.core.log.Lc
|
||||
import ru.touchin.roboswag.navigation_base.fragments.FragmentWithState
|
||||
import ru.touchin.roboswag.navigation_base.fragments.StatefulFragment
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
|
|
@ -169,14 +169,14 @@ open class FragmentNavigation(
|
|||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info.
|
||||
*/
|
||||
fun <T : Parcelable> push(
|
||||
fragmentClass: KClass<out FragmentWithState<*, out T>>,
|
||||
fragmentClass: KClass<out StatefulFragment<*, out T>>,
|
||||
state: T,
|
||||
addToStack: Boolean = true,
|
||||
backStackName: String? = null,
|
||||
tag: String? = null,
|
||||
transactionSetup: ((FragmentTransaction) -> Unit)? = null
|
||||
) {
|
||||
push(fragmentClass.java, FragmentWithState.args(state), addToStack, backStackName, tag, transactionSetup)
|
||||
push(fragmentClass.java, StatefulFragment.args(state), addToStack, backStackName, tag, transactionSetup)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -216,14 +216,14 @@ open class FragmentNavigation(
|
|||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info.
|
||||
*/
|
||||
fun <T : Parcelable> pushForResult(
|
||||
fragmentClass: KClass<out FragmentWithState<*, out T>>,
|
||||
fragmentClass: KClass<out StatefulFragment<*, out T>>,
|
||||
targetFragment: Fragment,
|
||||
targetRequestCode: Int,
|
||||
state: T,
|
||||
tag: String? = null,
|
||||
transactionSetup: ((FragmentTransaction) -> Unit)? = null
|
||||
) {
|
||||
pushForResult(fragmentClass.java, targetFragment, targetRequestCode, FragmentWithState.args(state), tag, transactionSetup)
|
||||
pushForResult(fragmentClass.java, targetFragment, targetRequestCode, StatefulFragment.args(state), tag, transactionSetup)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -270,13 +270,13 @@ open class FragmentNavigation(
|
|||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info.
|
||||
*/
|
||||
fun <T : Parcelable> setInitial(
|
||||
fragmentClass: KClass<out FragmentWithState<*, out T>>,
|
||||
fragmentClass: KClass<out StatefulFragment<*, out T>>,
|
||||
state: T,
|
||||
tag: String? = null,
|
||||
transactionSetup: ((FragmentTransaction) -> Unit)? = null
|
||||
) {
|
||||
beforeSetInitialActions()
|
||||
setAsTop(fragmentClass.java, FragmentWithState.args(state), false, tag, transactionSetup)
|
||||
setAsTop(fragmentClass.java, StatefulFragment.args(state), false, tag, transactionSetup)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
package ru.touchin.roboswag.navigation_base.extensions
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import ru.touchin.roboswag.navigation_base.fragments.EmptyState
|
||||
|
||||
// This method used to check unique state of each fragment.
|
||||
// If two fragments share same class for state, you should not pass state instance of current fragment to the one you transition to
|
||||
fun <T : Parcelable> Parcelable.reserialize(): T {
|
||||
var parcel = Parcel.obtain()
|
||||
|
||||
parcel.writeParcelable(this, 0)
|
||||
|
||||
val serializableBytes = parcel.marshall()
|
||||
|
||||
parcel.recycle()
|
||||
|
||||
parcel = Parcel.obtain().apply {
|
||||
unmarshall(serializableBytes, 0, serializableBytes.size)
|
||||
setDataPosition(0)
|
||||
}
|
||||
|
||||
val result = parcel.readParcelable<T>(Thread.currentThread().contextClassLoader)
|
||||
?: throw IllegalStateException("It must not be null")
|
||||
|
||||
parcel.recycle()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun Parcelable.copy(): Parcelable =
|
||||
if (this is EmptyState) {
|
||||
EmptyState
|
||||
} else {
|
||||
val parcel = Parcel.obtain()
|
||||
|
||||
parcel.writeParcelable(this, 0)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val result = parcel.readParcelable<Parcelable>(
|
||||
javaClass.classLoader ?: Thread.currentThread().contextClassLoader
|
||||
) ?: throw IllegalStateException("Failed to copy tab state")
|
||||
|
||||
parcel.recycle()
|
||||
|
||||
result
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
package ru.touchin.roboswag.navigation_base.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import ru.touchin.roboswag.navigation_base.BuildConfig
|
||||
import ru.touchin.roboswag.navigation_base.extensions.reserialize
|
||||
|
||||
open class FragmentWithState<TActivity : FragmentActivity, TState : Parcelable>(
|
||||
open class StatefulFragment<TActivity : FragmentActivity, TState : Parcelable>(
|
||||
@LayoutRes layoutRes: Int
|
||||
) : BaseFragment<TActivity>(layoutRes) {
|
||||
|
||||
|
|
@ -16,20 +16,6 @@ open class FragmentWithState<TActivity : FragmentActivity, TState : Parcelable>(
|
|||
|
||||
fun args(state: Parcelable?): Bundle = Bundle().also { it.putParcelable(BASE_FRAGMENT_STATE_EXTRA, state) }
|
||||
|
||||
// This method used to check unique state of each fragment.
|
||||
// If two fragments share same class for state, you should not pass state instance of current fragment to the one you transition to
|
||||
private fun <T : Parcelable> reserialize(parcelable: T): T {
|
||||
var parcel = Parcel.obtain()
|
||||
parcel.writeParcelable(parcelable, 0)
|
||||
val serializableBytes = parcel.marshall()
|
||||
parcel.recycle()
|
||||
parcel = Parcel.obtain()
|
||||
parcel.unmarshall(serializableBytes, 0, serializableBytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
val result = parcel.readParcelable<T>(Thread.currentThread().contextClassLoader) ?: throw IllegalStateException("It must not be null")
|
||||
parcel.recycle()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
protected lateinit var state: TState
|
||||
|
|
@ -43,7 +29,7 @@ open class FragmentWithState<TActivity : FragmentActivity, TState : Parcelable>(
|
|||
?: throw IllegalStateException("Fragment state can't be null")
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
state = reserialize(state)
|
||||
state = state.reserialize()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -9,12 +9,11 @@ import androidx.lifecycle.LifecycleObserver
|
|||
import ru.touchin.roboswag.components.utils.UiUtils
|
||||
import ru.touchin.roboswag.navigation_base.activities.BaseActivity
|
||||
import ru.touchin.roboswag.navigation_base.activities.OnBackPressedListener
|
||||
import ru.touchin.roboswag.navigation_base.fragments.BaseFragment
|
||||
import ru.touchin.roboswag.navigation_base.fragments.FragmentWithState
|
||||
import ru.touchin.roboswag.navigation_base.fragments.StatefulFragment
|
||||
|
||||
abstract class KeyboardResizeableFragment<TActivity : BaseActivity, TState : Parcelable>(
|
||||
@LayoutRes layoutRes: Int
|
||||
) : FragmentWithState<TActivity, TState>(
|
||||
) : StatefulFragment<TActivity, TState>(
|
||||
layoutRes
|
||||
) {
|
||||
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
api project(":utils")
|
||||
api project(":logging")
|
||||
api project(":navigation-base")
|
||||
implementation project(":utils")
|
||||
implementation project(":logging")
|
||||
implementation project(":navigation-base")
|
||||
|
||||
api 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
|
||||
api 'net.danlew:android.joda:2.10.2'
|
||||
implementation 'net.danlew:android.joda:2.10.2'
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue