Removed from navigation-new most of copypasta
This commit is contained in:
parent
5a31d2de87
commit
e1465ff60e
|
|
@ -18,6 +18,7 @@ android {
|
|||
dependencies {
|
||||
api project(":utils")
|
||||
api project(":logging")
|
||||
api project(":navigation")
|
||||
api project(":api-logansquare")
|
||||
|
||||
api 'androidx.multidex:multidex:2.0.1'
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import androidx.fragment.app.FragmentManager
|
|||
import androidx.fragment.app.FragmentTransaction
|
||||
import ru.touchin.roboswag.core.log.Lc
|
||||
import ru.touchin.roboswag.components.navigation_new.fragments.BaseFragment
|
||||
import ru.touchin.roboswag.components.navigation_new.viewcontrollers.EmptyState
|
||||
import ru.touchin.roboswag.components.navigation.viewcontrollers.EmptyState
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,208 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation_new
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import ru.touchin.roboswag.components.navigation_new.activities.BaseActivity
|
||||
import ru.touchin.roboswag.components.navigation_new.activities.OnBackPressedListener
|
||||
import ru.touchin.roboswag.components.utils.UiUtils
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 11/03/16.
|
||||
* Simple realization of one-side [ActionBarDrawerToggle].
|
||||
*/
|
||||
class SimpleActionBarDrawerToggle(
|
||||
private val activity: BaseActivity,
|
||||
val drawerLayout: DrawerLayout,
|
||||
private val sidebar: View
|
||||
) : ActionBarDrawerToggle(activity, drawerLayout, 0, 0), FragmentManager.OnBackStackChangedListener, OnBackPressedListener {
|
||||
|
||||
private var isInvalidateOptionsMenuSupported = true
|
||||
|
||||
private var hamburgerShowed: Boolean = false
|
||||
private var sidebarDisabled: Boolean = false
|
||||
|
||||
private var slideOffset: Float = 0f
|
||||
private var slidePosition: Float = 0f
|
||||
|
||||
private var hamburgerAnimator: ValueAnimator? = null
|
||||
private var firstAnimation = true
|
||||
|
||||
init {
|
||||
drawerLayout.addDrawerListener(this)
|
||||
activity.supportFragmentManager.addOnBackStackChangedListener(this)
|
||||
activity.addOnBackPressedListener(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set turn on/off invocation of supportInvalidateOptionsMenu
|
||||
*
|
||||
* @param isInvalidateOptionsMenuSupported flag for turning on/off invocation.
|
||||
*/
|
||||
fun setInvalidateOptionsMenuSupported(isInvalidateOptionsMenuSupported: Boolean) {
|
||||
this.isInvalidateOptionsMenuSupported = isInvalidateOptionsMenuSupported
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if sidebar is opened.
|
||||
*
|
||||
* @return True if sidebar is opened.
|
||||
*/
|
||||
fun isOpened(): Boolean = drawerLayout.isDrawerOpen(sidebar)
|
||||
|
||||
/**
|
||||
* Disables sidebar. So it will be in closed state and couldn't be opened.
|
||||
*/
|
||||
fun disableSidebar() {
|
||||
sidebarDisabled = true
|
||||
close()
|
||||
update()
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables sidebar. So it could be opened.
|
||||
*/
|
||||
fun enableSidebar() {
|
||||
sidebarDisabled = false
|
||||
update()
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides hamburger icon. Use it if there are some fragments in activity's stack.
|
||||
*/
|
||||
fun hideHamburger() {
|
||||
syncState()
|
||||
hamburgerShowed = true
|
||||
update()
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows hamburger icon. Use it if there are no fragments in activity's stack or current fragment is like top.
|
||||
*/
|
||||
fun showHamburger() {
|
||||
syncState()
|
||||
hamburgerShowed = false
|
||||
update()
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens sidebar.
|
||||
*/
|
||||
fun open() {
|
||||
if (!sidebarDisabled && !drawerLayout.isDrawerOpen(sidebar)) {
|
||||
drawerLayout.openDrawer(sidebar)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes sidebar.
|
||||
*/
|
||||
fun close() {
|
||||
if (drawerLayout.isDrawerOpen(sidebar)) {
|
||||
drawerLayout.closeDrawer(sidebar)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to process clicking on hamburger. It is needed to be called from [android.app.Activity.onOptionsItemSelected].
|
||||
* If this method won't be called then opening-closing won't work.
|
||||
*
|
||||
* @param item Selected item.
|
||||
* @return True if item clicking processed.
|
||||
*/
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean = shouldShowHamburger() && super.onOptionsItemSelected(item)
|
||||
|
||||
/**
|
||||
* Call it when back stack of activity's fragments have changed.
|
||||
*/
|
||||
override fun onBackStackChanged() {
|
||||
close()
|
||||
}
|
||||
|
||||
/**
|
||||
* Call it when system back button have pressed.
|
||||
*/
|
||||
override fun onBackPressed(): Boolean = if (isOpened()) {
|
||||
close()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
override fun onDrawerClosed(view: View) {
|
||||
if (isInvalidateOptionsMenuSupported) {
|
||||
activity.invalidateOptionsMenu()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDrawerSlide(drawerView: View, offset: Float) {
|
||||
if (offset in slideOffset..slidePosition
|
||||
|| offset in slidePosition..slideOffset) {
|
||||
slideOffset = offset
|
||||
}
|
||||
super.onDrawerSlide(drawerView, slideOffset)
|
||||
}
|
||||
|
||||
/**
|
||||
* Call it at [android.app.Activity.onPostCreate].
|
||||
*/
|
||||
override fun syncState() {
|
||||
cancelAnimation()
|
||||
super.syncState()
|
||||
}
|
||||
|
||||
override fun onDrawerOpened(drawerView: View) {
|
||||
UiUtils.OfViews.hideSoftInput(activity)
|
||||
if (isInvalidateOptionsMenuSupported) {
|
||||
activity.invalidateOptionsMenu()
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldShowHamburger(): Boolean = !hamburgerShowed && !sidebarDisabled
|
||||
|
||||
private fun update() {
|
||||
setHamburgerState(shouldShowHamburger())
|
||||
drawerLayout.setDrawerLockMode(if (sidebarDisabled) DrawerLayout.LOCK_MODE_LOCKED_CLOSED else DrawerLayout.LOCK_MODE_UNLOCKED)
|
||||
}
|
||||
|
||||
private fun setHamburgerState(showHamburger: Boolean) {
|
||||
if (!firstAnimation) {
|
||||
cancelAnimation()
|
||||
hamburgerAnimator = ValueAnimator.ofFloat(slideOffset, if (showHamburger) 0f else 1f)
|
||||
hamburgerAnimator!!.addUpdateListener { animation -> onDrawerSlide(drawerLayout, animation.animatedValue as Float) }
|
||||
hamburgerAnimator!!.start()
|
||||
} else {
|
||||
slideOffset = if (showHamburger) 0f else 1f
|
||||
onDrawerSlide(drawerLayout, slideOffset)
|
||||
}
|
||||
slidePosition = if (showHamburger) 0f else 1f
|
||||
firstAnimation = false
|
||||
}
|
||||
|
||||
private fun cancelAnimation() {
|
||||
hamburgerAnimator?.cancel()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Touch Instinct
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation_new;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.StrictMode;
|
||||
import android.util.Log;
|
||||
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
|
||||
import net.danlew.android.joda.JodaTimeAndroid;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.multidex.MultiDex;
|
||||
import io.fabric.sdk.android.Fabric;
|
||||
import ru.touchin.roboswag.core.log.ConsoleLogProcessor;
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.log.LcGroup;
|
||||
import ru.touchin.roboswag.core.log.LcLevel;
|
||||
import ru.touchin.roboswag.core.log.LogProcessor;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
import ru.touchin.templates.ApiModel;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 10/03/16.
|
||||
* Base class of application to extends for Touch Instinct related projects.
|
||||
*/
|
||||
public abstract class TouchinApp extends Application {
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(@NonNull final Context base) {
|
||||
super.attachBaseContext(base);
|
||||
MultiDex.install(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
JodaTimeAndroid.init(this);
|
||||
if (BuildConfig.DEBUG) {
|
||||
enableStrictMode();
|
||||
Lc.initialize(new ConsoleLogProcessor(LcLevel.VERBOSE), true);
|
||||
LcGroup.UI_LIFECYCLE.disable();
|
||||
} else {
|
||||
try {
|
||||
final Crashlytics crashlytics = new Crashlytics();
|
||||
Fabric.with(this, crashlytics);
|
||||
Fabric.getLogger().setLogLevel(Log.ERROR);
|
||||
Lc.initialize(new CrashlyticsLogProcessor(crashlytics), false);
|
||||
} catch (final NoClassDefFoundError error) {
|
||||
Lc.initialize(new ConsoleLogProcessor(LcLevel.INFO), false);
|
||||
Lc.e("Crashlytics initialization error! Did you forget to add\n"
|
||||
+ "compile('com.crashlytics.sdk.android:crashlytics:+@aar') {\n"
|
||||
+ " transitive = true;\n"
|
||||
+ "}\n"
|
||||
+ "to your build.gradle?", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void enableStrictMode() {
|
||||
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
|
||||
.detectAll()
|
||||
.permitDiskReads()
|
||||
.permitDiskWrites()
|
||||
.penaltyLog()
|
||||
.build());
|
||||
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
|
||||
.detectAll()
|
||||
.penaltyLog()
|
||||
.build());
|
||||
}
|
||||
|
||||
private static class CrashlyticsLogProcessor extends LogProcessor {
|
||||
|
||||
@NonNull
|
||||
private final Crashlytics crashlytics;
|
||||
|
||||
public CrashlyticsLogProcessor(@NonNull final Crashlytics crashlytics) {
|
||||
super(LcLevel.INFO);
|
||||
this.crashlytics = crashlytics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processLogMessage(@NonNull final LcGroup group,
|
||||
@NonNull final LcLevel level,
|
||||
@NonNull final String tag,
|
||||
@NonNull final String message,
|
||||
@Nullable final Throwable throwable) {
|
||||
if (group == LcGroup.UI_LIFECYCLE) {
|
||||
crashlytics.core.log(level.getPriority(), tag, message);
|
||||
} else if (!level.lessThan(LcLevel.ASSERT)
|
||||
|| (group == ApiModel.API_VALIDATION_LC_GROUP && level == LcLevel.ERROR)) {
|
||||
Log.e(tag, message);
|
||||
if (throwable != null) {
|
||||
crashlytics.core.log(level.getPriority(), tag, message);
|
||||
crashlytics.core.logException(throwable);
|
||||
} else {
|
||||
final ShouldNotHappenException exceptionToLog = new ShouldNotHappenException(tag + ':' + message);
|
||||
reduceStackTrace(exceptionToLog);
|
||||
crashlytics.core.logException(exceptionToLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reduceStackTrace(@NonNull final Throwable throwable) {
|
||||
final StackTraceElement[] stackTrace = throwable.getStackTrace();
|
||||
final List<StackTraceElement> reducedStackTraceList = new ArrayList<>();
|
||||
for (int i = stackTrace.length - 1; i >= 0; i--) {
|
||||
final StackTraceElement stackTraceElement = stackTrace[i];
|
||||
if (stackTraceElement.getClassName().contains(getClass().getSimpleName())
|
||||
|| stackTraceElement.getClassName().contains(LcGroup.class.getName())
|
||||
|| stackTraceElement.getClassName().contains(Lc.class.getName())) {
|
||||
break;
|
||||
}
|
||||
reducedStackTraceList.add(0, stackTraceElement);
|
||||
}
|
||||
StackTraceElement[] reducedStackTrace = new StackTraceElement[reducedStackTraceList.size()];
|
||||
reducedStackTrace = reducedStackTraceList.toArray(reducedStackTrace);
|
||||
throwable.setStackTrace(reducedStackTrace);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation_new.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import ru.touchin.roboswag.components.navigation_new.keyboard_resizeable.KeyboardBehaviorDetector
|
||||
import ru.touchin.roboswag.components.navigation_new.viewcontrollers.LifecycleLoggingObserver
|
||||
import ru.touchin.roboswag.core.log.Lc
|
||||
import ru.touchin.roboswag.core.log.LcGroup
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 08/03/2016.
|
||||
* Base activity to use in components repository.
|
||||
*/
|
||||
abstract class BaseActivity : AppCompatActivity() {
|
||||
|
||||
private val onBackPressedListeners = ArrayList<OnBackPressedListener>()
|
||||
|
||||
open val keyboardBehaviorDetector: KeyboardBehaviorDetector? = null
|
||||
|
||||
init {
|
||||
lifecycle.addObserver(LifecycleLoggingObserver())
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
|
||||
super.onCreate(savedInstanceState, persistentState)
|
||||
// Possible work around for market launches. See http://code.google.com/p/android/issues/detail?id=2373
|
||||
// for more details. Essentially, the market launches the main activity on top of other activities.
|
||||
// we never want this to happen. Instead, we check if we are the root and if not, we finish.
|
||||
if (!isTaskRoot && intent.hasCategory(Intent.CATEGORY_LAUNCHER) && Intent.ACTION_MAIN == intent.action) {
|
||||
Lc.e("Finishing activity as it is launcher but not root")
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
LcGroup.UI_LIFECYCLE.i("${Lc.getCodePoint(this)} requestCode: $requestCode; resultCode: $resultCode")
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(stateToSave: Bundle) {
|
||||
super.onSaveInstanceState(stateToSave)
|
||||
LcGroup.UI_LIFECYCLE.i(Lc.getCodePoint(this))
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
|
||||
open fun addOnBackPressedListener(onBackPressedListener: OnBackPressedListener) {
|
||||
onBackPressedListeners.add(onBackPressedListener)
|
||||
}
|
||||
|
||||
open fun removeOnBackPressedListener(onBackPressedListener: OnBackPressedListener) {
|
||||
onBackPressedListeners.remove(onBackPressedListener)
|
||||
}
|
||||
|
||||
open fun removeAllOnBackPressedListeners() {
|
||||
onBackPressedListeners.clear()
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
onBackPressedListeners.reversed().forEach { onBackPressedListener ->
|
||||
if (onBackPressedListener.onBackPressed()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package ru.touchin.roboswag.components.navigation_new.activities
|
||||
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import ru.touchin.roboswag.components.navigation_new.viewcontrollers.ViewControllerNavigation
|
||||
import ru.touchin.roboswag.components.navigation.activities.BaseActivity
|
||||
import ru.touchin.roboswag.components.navigation.viewcontrollers.ViewControllerNavigation
|
||||
import ru.touchin.roboswag.components.navigation_new.FragmentNavigation
|
||||
|
||||
/**
|
||||
* Created by Daniil Borisovskii on 15/08/2019.
|
||||
|
|
@ -14,7 +16,7 @@ abstract class NavigationActivity : BaseActivity() {
|
|||
protected open val transition = FragmentTransaction.TRANSIT_NONE
|
||||
|
||||
open val navigation by lazy {
|
||||
ViewControllerNavigation<NavigationActivity>(
|
||||
FragmentNavigation(
|
||||
this,
|
||||
supportFragmentManager,
|
||||
fragmentContainerViewId,
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
package ru.touchin.roboswag.components.navigation_new.activities;
|
||||
|
||||
public interface OnBackPressedListener {
|
||||
|
||||
boolean onBackPressed();
|
||||
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ import androidx.fragment.app.FragmentActivity
|
|||
import butterknife.ButterKnife
|
||||
import butterknife.Unbinder
|
||||
import ru.touchin.roboswag.components.navigation_new.BuildConfig
|
||||
import ru.touchin.roboswag.components.navigation_new.viewcontrollers.LifecycleLoggingObserver
|
||||
import ru.touchin.roboswag.components.navigation.viewcontrollers.LifecycleLoggingObserver
|
||||
|
||||
open class BaseFragment<TActivity : FragmentActivity, TState : Parcelable>(@LayoutRes layoutRes: Int) : Fragment(layoutRes) {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,260 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation_new.fragments
|
||||
|
||||
import android.animation.Animator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.Animation
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import ru.touchin.roboswag.components.navigation_new.BuildConfig
|
||||
import ru.touchin.roboswag.components.navigation_new.viewcontrollers.ViewController
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 21/10/2015.
|
||||
* Fragment instantiated in specific activity of [TActivity] type that is holding [ViewController] inside.
|
||||
*
|
||||
* @param <TState> Type of object which is representing it's fragment state;
|
||||
* @param <TActivity> Type of [FragmentActivity] where fragment could be attached to.
|
||||
</TActivity></TState> */
|
||||
@Suppress("detekt.TooManyFunctions", "UNCHECKED_CAST")
|
||||
open class ViewControllerFragment<TActivity : FragmentActivity, TState : Parcelable> : Fragment() {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val VIEW_CONTROLLER_CLASS_EXTRA = "VIEW_CONTROLLER_CLASS_EXTRA"
|
||||
private const val VIEW_CONTROLLER_STATE_EXTRA = "VIEW_CONTROLLER_STATE_EXTRA"
|
||||
|
||||
/**
|
||||
* Creates [Bundle] which will store state.
|
||||
*
|
||||
* @param state State to use into ViewController.
|
||||
* @return Returns bundle with state inside.
|
||||
*/
|
||||
fun args(viewControllerClass: Class<out ViewController<*, *>>, state: Parcelable?): Bundle = Bundle().apply {
|
||||
putSerializable(VIEW_CONTROLLER_CLASS_EXTRA, viewControllerClass)
|
||||
putParcelable(VIEW_CONTROLLER_STATE_EXTRA, state)
|
||||
}
|
||||
|
||||
private fun <T : Parcelable> reserialize(parcelable: T, classLoader: ClassLoader): 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>(classLoader) ?: throw IllegalStateException("It must not be null")
|
||||
parcel.recycle()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
lateinit var state: TState private set
|
||||
|
||||
lateinit var viewControllerClass: Class<ViewController<TActivity, TState>> private set
|
||||
|
||||
private var viewController: ViewController<out TActivity, out TState>? = null
|
||||
|
||||
private var pendingActivityResult: ActivityResult? = null
|
||||
|
||||
private var appeared: Boolean = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setHasOptionsMenu(true)
|
||||
|
||||
viewControllerClass = arguments?.getSerializable(VIEW_CONTROLLER_CLASS_EXTRA) as? Class<ViewController<TActivity, TState>>
|
||||
?: throw IllegalArgumentException("View controller class must be not-null")
|
||||
|
||||
state = savedInstanceState?.getParcelable<TState>(VIEW_CONTROLLER_STATE_EXTRA)
|
||||
?: arguments?.getParcelable(VIEW_CONTROLLER_STATE_EXTRA)
|
||||
?: throw IllegalStateException("State is required and null")
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
state = reserialize(state, state.javaClass.classLoader
|
||||
?: Thread.currentThread().contextClassLoader)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
val newViewController = createViewController(
|
||||
ViewController.CreationContext(requireActivity(), this, inflater, container),
|
||||
savedInstanceState
|
||||
)
|
||||
viewController = newViewController
|
||||
newViewController.onCreate()
|
||||
return newViewController.view
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
val activityResult = pendingActivityResult
|
||||
if (viewController != null && activityResult != null) {
|
||||
viewController?.onActivityResult(activityResult.requestCode, activityResult.resultCode, activityResult.data)
|
||||
pendingActivityResult = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? =
|
||||
viewController?.onCreateAnimation(transit, enter, nextAnim)
|
||||
|
||||
override fun onCreateAnimator(transit: Int, enter: Boolean, nextAnim: Int): Animator? =
|
||||
viewController?.onCreateAnimator(transit, enter, nextAnim)
|
||||
|
||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||
super.onViewStateRestored(savedInstanceState)
|
||||
viewController?.onViewStateRestored(savedInstanceState)
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
if (!appeared && isMenuVisible) {
|
||||
onAppear()
|
||||
}
|
||||
viewController?.onStart()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when fragment is moved in started state and it's [.isMenuVisible] sets to true.
|
||||
* Usually it is indicating that user can't see fragment on screen and useful to track analytics events.
|
||||
*/
|
||||
private fun onAppear() {
|
||||
appeared = true
|
||||
viewController?.onAppear()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
viewController?.onResume()
|
||||
}
|
||||
|
||||
override fun onLowMemory() {
|
||||
super.onLowMemory()
|
||||
viewController?.onLowMemory()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
viewController?.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
viewController?.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||
viewController?.onOptionsItemSelected(item) == true || super.onOptionsItemSelected(item)
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
viewController?.onPause()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||
super.onSaveInstanceState(savedInstanceState)
|
||||
viewController?.onSaveInstanceState(savedInstanceState)
|
||||
savedInstanceState.putParcelable(VIEW_CONTROLLER_STATE_EXTRA, state)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when fragment is moved in stopped state or it's [.isMenuVisible] sets to false.
|
||||
* Usually it is indicating that user can't see fragment on screen and useful to track analytics events.
|
||||
*/
|
||||
private fun onDisappear() {
|
||||
appeared = false
|
||||
viewController?.onDisappear()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
if (appeared) {
|
||||
onDisappear()
|
||||
}
|
||||
viewController?.onStop()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
viewController?.onDestroy()
|
||||
viewController = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
viewController?.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
viewController?.onActivityResult(requestCode, resultCode, data) ?: let {
|
||||
pendingActivityResult = ActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun setMenuVisibility(menuVisible: Boolean) {
|
||||
super.setMenuVisibility(menuVisible)
|
||||
if (activity != null && view != null) {
|
||||
val started = lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
|
||||
if (!appeared && menuVisible && started) {
|
||||
onAppear()
|
||||
}
|
||||
if (appeared && (!menuVisible || !started)) {
|
||||
onDisappear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createViewController(
|
||||
creationContext: ViewController.CreationContext,
|
||||
savedInstanceState: Bundle?
|
||||
): ViewController<out TActivity, out TState> {
|
||||
if (viewControllerClass.constructors.size != 1) {
|
||||
throw IllegalStateException("There should be single constructor for $viewControllerClass")
|
||||
}
|
||||
val constructor = viewControllerClass.constructors[0]
|
||||
return when (constructor.parameterTypes.size) {
|
||||
1 -> constructor.newInstance(creationContext)
|
||||
2 -> constructor.newInstance(creationContext, savedInstanceState)
|
||||
else -> throw IllegalArgumentException("Wrong constructor parameters count: ${constructor.parameterTypes.size}")
|
||||
} as ViewController<out TActivity, out TState>
|
||||
}
|
||||
|
||||
override fun toString(): String = "${super.toString()} ViewController: $viewControllerClass"
|
||||
|
||||
private data class ActivityResult(val requestCode: Int, val resultCode: Int, val data: Intent?)
|
||||
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
package ru.touchin.roboswag.components.navigation_new.keyboard_resizeable
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import ru.touchin.roboswag.components.navigation_new.activities.BaseActivity
|
||||
|
||||
// The workaround forces an activity to resize when keyboard appears in the full-screen mode
|
||||
class KeyboardBehaviorDetector(
|
||||
activity: BaseActivity,
|
||||
fragmentContainerId: Int
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private const val SCREEN_TO_KEYBOARD_HEIGHT_RATIO = 4.75
|
||||
}
|
||||
|
||||
private val contentContainer = activity.findViewById(android.R.id.content) as ViewGroup
|
||||
private val fragmentContainer = activity.findViewById(fragmentContainerId) as ViewGroup
|
||||
private lateinit var rootView: View
|
||||
private val listener = { possiblyResizeChildOfContent() }
|
||||
|
||||
private var keyboardHideListener: (() -> Unit)? = null
|
||||
private var keyboardShowListener: ((Int) -> Unit)? = null
|
||||
|
||||
fun setKeyboardHideListener(listener: () -> Unit) {
|
||||
keyboardHideListener = listener
|
||||
}
|
||||
|
||||
fun removeKeyboardHideListener() {
|
||||
keyboardHideListener = null
|
||||
}
|
||||
|
||||
fun setKeyboardShowListener(listener: (Int) -> Unit) {
|
||||
keyboardShowListener = listener
|
||||
}
|
||||
|
||||
fun removeKeyboardShowListener() {
|
||||
keyboardShowListener = null
|
||||
}
|
||||
|
||||
// Call this in "onResume()" of a fragment
|
||||
fun startDetection() {
|
||||
rootView = fragmentContainer.getChildAt(0)
|
||||
|
||||
contentContainer.viewTreeObserver.addOnGlobalLayoutListener(listener)
|
||||
}
|
||||
|
||||
// Call this in "onPause()" of a fragment
|
||||
fun stopDetection() {
|
||||
contentContainer.viewTreeObserver.removeOnGlobalLayoutListener(listener)
|
||||
}
|
||||
|
||||
//https://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android?rq=1
|
||||
private fun possiblyResizeChildOfContent() {
|
||||
val rect = Rect()
|
||||
rootView.getWindowVisibleDisplayFrame(rect)
|
||||
val height = rootView.context.resources.displayMetrics.heightPixels
|
||||
val diff = height - rect.bottom
|
||||
|
||||
if (diff > rootView.rootView.height / SCREEN_TO_KEYBOARD_HEIGHT_RATIO) {
|
||||
keyboardShowListener?.invoke(diff)
|
||||
} else {
|
||||
keyboardHideListener?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
package ru.touchin.roboswag.components.navigation_new.keyboard_resizeable
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.LayoutRes
|
||||
import ru.touchin.roboswag.components.navigation_new.activities.BaseActivity
|
||||
import ru.touchin.roboswag.components.navigation_new.activities.OnBackPressedListener
|
||||
import ru.touchin.roboswag.components.navigation_new.viewcontrollers.ViewController
|
||||
import ru.touchin.roboswag.components.utils.UiUtils
|
||||
|
||||
abstract class KeyboardResizeableViewController<TActivity : BaseActivity, TState : Parcelable>(
|
||||
@LayoutRes layoutRes: Int,
|
||||
creationContext: CreationContext
|
||||
) : ViewController<TActivity, TState>(
|
||||
creationContext,
|
||||
layoutRes
|
||||
) {
|
||||
init {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
|
||||
creationContext.container?.requestApplyInsets()
|
||||
}
|
||||
}
|
||||
|
||||
private var keyboardIsVisible: Boolean = false
|
||||
|
||||
private val keyboardHideListener = OnBackPressedListener {
|
||||
if (keyboardIsVisible) {
|
||||
UiUtils.OfViews.hideSoftInput(activity)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private var isHideKeyboardOnBackEnabled = false
|
||||
|
||||
protected open fun onKeyboardShow(diff: Int = 0) {}
|
||||
|
||||
protected open fun onKeyboardHide() {}
|
||||
|
||||
protected fun hideKeyboardOnBackPressed() {
|
||||
isHideKeyboardOnBackEnabled = true
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (isHideKeyboardOnBackEnabled) activity.addOnBackPressedListener(keyboardHideListener)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
if (isHideKeyboardOnBackEnabled) activity.removeOnBackPressedListener(keyboardHideListener)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
activity.keyboardBehaviorDetector?.apply {
|
||||
setKeyboardHideListener {
|
||||
if (keyboardIsVisible) {
|
||||
onKeyboardHide()
|
||||
}
|
||||
keyboardIsVisible = false
|
||||
}
|
||||
setKeyboardShowListener { diff ->
|
||||
if (!keyboardIsVisible) {
|
||||
onKeyboardShow(diff)
|
||||
}
|
||||
keyboardIsVisible = true
|
||||
}
|
||||
startDetection()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
activity.keyboardBehaviorDetector?.apply {
|
||||
removeKeyboardHideListener()
|
||||
removeKeyboardShowListener()
|
||||
stopDetection()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package ru.touchin.roboswag.components.navigation_new.viewcontrollers
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
object EmptyState : Parcelable {
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) = Unit
|
||||
|
||||
override fun describeContents() = 0
|
||||
|
||||
@JvmField
|
||||
val CREATOR = object : Parcelable.Creator<EmptyState> {
|
||||
override fun createFromParcel(parcel: Parcel) = EmptyState
|
||||
|
||||
override fun newArray(size: Int): Array<EmptyState?> = arrayOfNulls(size)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package ru.touchin.roboswag.components.navigation_new.viewcontrollers
|
||||
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import ru.touchin.roboswag.core.log.Lc
|
||||
import ru.touchin.roboswag.core.log.LcGroup
|
||||
|
||||
class LifecycleLoggingObserver : LifecycleObserver {
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
|
||||
fun onAnyLifecycleEvent() {
|
||||
LcGroup.UI_LIFECYCLE.i(Lc.getCodePoint(this))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,309 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation_new.viewcontrollers
|
||||
|
||||
import android.animation.Animator
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.Animation
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import ru.touchin.roboswag.components.navigation_new.fragments.ViewControllerFragment
|
||||
import ru.touchin.roboswag.components.utils.UiUtils
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 21/10/2015.
|
||||
* Class to control view of specific fragment, activity and application by logic bridge.
|
||||
*
|
||||
* @param <TActivity> Type of activity where such [ViewController] could be;
|
||||
* @param <TState> Type of state;
|
||||
</TState></TActivity> */
|
||||
@Suppress("detekt.TooManyFunctions", "UNCHECKED_CAST")
|
||||
open class ViewController<TActivity : FragmentActivity, TState : Parcelable>(
|
||||
creationContext: CreationContext,
|
||||
@LayoutRes layoutRes: Int
|
||||
) : LifecycleOwner {
|
||||
|
||||
val activity: TActivity = creationContext.activity as TActivity
|
||||
|
||||
val fragment: ViewControllerFragment<out TActivity, out TState> = creationContext.fragment as ViewControllerFragment<out TActivity, out TState>
|
||||
|
||||
val state = fragment.state
|
||||
|
||||
val view: View = creationContext.inflater.inflate(layoutRes, creationContext.container, false)
|
||||
|
||||
init {
|
||||
lifecycle.addObserver(LifecycleLoggingObserver())
|
||||
}
|
||||
|
||||
override fun getLifecycle(): Lifecycle = fragment.viewLifecycleOwner.lifecycle
|
||||
|
||||
/**
|
||||
* Look for a child view with the given id. If this view has the given id, return this view.
|
||||
*
|
||||
* @param id The id to search for;
|
||||
* @return The view that has the given id in the hierarchy.
|
||||
*/
|
||||
fun <T : View> findViewById(@IdRes id: Int): T = view.findViewById(id)
|
||||
|
||||
/**
|
||||
* Return a localized, styled CharSequence from the application's package's
|
||||
* default string table.
|
||||
*
|
||||
* @param resId Resource id for the CharSequence text
|
||||
*/
|
||||
fun getText(@StringRes resId: Int): CharSequence = activity.getText(resId)
|
||||
|
||||
/**
|
||||
* Return a localized string from the application's package's default string table.
|
||||
*
|
||||
* @param resId Resource id for the string
|
||||
*/
|
||||
fun getString(@StringRes resId: Int): String = activity.getString(resId)
|
||||
|
||||
/**
|
||||
* Return a localized formatted string from the application's package's default string table, substituting the format arguments as defined in
|
||||
* [java.util.Formatter] and [java.lang.String.format].
|
||||
*
|
||||
* @param resId Resource id for the format string
|
||||
* @param formatArgs The format arguments that will be used for substitution.
|
||||
*/
|
||||
fun getString(@StringRes resId: Int, vararg formatArgs: Any): String = activity.getString(resId, *formatArgs)
|
||||
|
||||
/**
|
||||
* Return the color value associated with a particular resource ID.
|
||||
* Starting in [android.os.Build.VERSION_CODES.M], the returned
|
||||
* color will be styled for the specified Context's theme.
|
||||
*
|
||||
* @param resId The resource id to search for data;
|
||||
* @return int A single color value in the form 0xAARRGGBB.
|
||||
*/
|
||||
@ColorInt
|
||||
fun getColor(@ColorRes resId: Int): Int = ContextCompat.getColor(activity, resId)
|
||||
|
||||
/**
|
||||
* Returns a color state list associated with a particular resource ID.
|
||||
*
|
||||
*
|
||||
* Starting in [android.os.Build.VERSION_CODES.M], the returned
|
||||
* color state list will be styled for the specified Context's theme.
|
||||
*
|
||||
* @param resId The desired resource identifier, as generated by the aapt
|
||||
* tool. This integer encodes the package, type, and resource
|
||||
* entry. The value 0 is an invalid identifier.
|
||||
* @return A color state list, or `null` if the resource could not be resolved.
|
||||
* @throws android.content.res.Resources.NotFoundException if the given ID
|
||||
* does not exist.
|
||||
*/
|
||||
fun getColorStateList(@ColorRes resId: Int): ColorStateList? = ContextCompat.getColorStateList(activity, resId)
|
||||
|
||||
/**
|
||||
* Returns a drawable object associated with a particular resource ID.
|
||||
* Starting in [android.os.Build.VERSION_CODES.LOLLIPOP], the
|
||||
* returned drawable will be styled for the specified Context's theme.
|
||||
*
|
||||
* @param resId The resource id to search for data;
|
||||
* @return Drawable An object that can be used to draw this resource.
|
||||
*/
|
||||
fun getDrawable(@DrawableRes resId: Int): Drawable? = ContextCompat.getDrawable(activity, resId)
|
||||
|
||||
fun startActivity(intent: Intent) {
|
||||
fragment.startActivity(intent)
|
||||
}
|
||||
|
||||
fun startActivityForResult(intent: Intent, requestCode: Int) {
|
||||
fragment.startActivityForResult(intent, requestCode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls when activity configuring ActionBar, Toolbar, Sidebar etc.
|
||||
* If it will be called or not depends on [Fragment.hasOptionsMenu] and [Fragment.isMenuVisible].
|
||||
*
|
||||
* @param menu The options menu in which you place your items;
|
||||
* @param inflater Helper to inflate menu items.
|
||||
*/
|
||||
open fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) = Unit
|
||||
|
||||
/**
|
||||
* Prepare the standard options menu to be displayed. This is
|
||||
* called right before the menu is shown, every time it is shown.
|
||||
* You can use this method to efficiently enable/disable items or otherwise
|
||||
* dynamically modify the contents.
|
||||
*
|
||||
* @param menu The options menu as last shown or first initialized by onCreateOptionsMenu().
|
||||
*
|
||||
* @see [Fragment.hasOptionsMenu]
|
||||
* @see [onCreateOptionsMenu]
|
||||
*/
|
||||
open fun onPrepareOptionsMenu(menu: Menu?) = Unit
|
||||
|
||||
/**
|
||||
* Calls right after construction of [ViewController].
|
||||
* Happens at [ViewControllerFragment.onActivityCreated].
|
||||
*/
|
||||
open fun onCreate() = Unit
|
||||
|
||||
/**
|
||||
* Called when a fragment loads an animation. Note that if
|
||||
* [FragmentTransaction.setCustomAnimations] was called with
|
||||
* [Animator] resources instead of [Animation] resources, `nextAnim`
|
||||
* will be an animator resource.
|
||||
*
|
||||
* @param transit The value set in [FragmentTransaction.setTransition] or 0 if not
|
||||
* set.
|
||||
* @param enter `true` when the fragment is added/attached/shown or `false` when
|
||||
* the fragment is removed/detached/hidden.
|
||||
* @param nextAnim The resource set in
|
||||
* [FragmentTransaction.setCustomAnimations],
|
||||
* [FragmentTransaction.setCustomAnimations], or
|
||||
* 0 if neither was called. The value will depend on the current operation.
|
||||
*/
|
||||
open fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? = null
|
||||
|
||||
/**
|
||||
* Called when a fragment loads an animator. This will be called when
|
||||
* [.onCreateAnimation] returns null. Note that if
|
||||
* [FragmentTransaction.setCustomAnimations] was called with
|
||||
* [Animation] resources instead of [Animator] resources, `nextAnim`
|
||||
* will be an animation resource.
|
||||
*
|
||||
* @param transit The value set in [FragmentTransaction.setTransition] or 0 if not
|
||||
* set.
|
||||
* @param enter `true` when the fragment is added/attached/shown or `false` when
|
||||
* the fragment is removed/detached/hidden.
|
||||
* @param nextAnim The resource set in
|
||||
* [FragmentTransaction.setCustomAnimations],
|
||||
* [FragmentTransaction.setCustomAnimations], or
|
||||
* 0 if neither was called. The value will depend on the current operation.
|
||||
*/
|
||||
open fun onCreateAnimator(transit: Int, enter: Boolean, nextAnim: Int): Animator? = null
|
||||
|
||||
/**
|
||||
* Calls when [ViewController] saved state has been restored into the view hierarchy.
|
||||
* Happens at [ViewControllerFragment.onViewStateRestored].
|
||||
*/
|
||||
open fun onViewStateRestored(savedInstanceState: Bundle?) = Unit
|
||||
|
||||
/**
|
||||
* Calls when [ViewController] have started.
|
||||
* Happens at [ViewControllerFragment.onStart].
|
||||
*/
|
||||
open fun onStart() {
|
||||
UiUtils.OfViews.hideSoftInput(view)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when fragment is moved in started state and it's [.getFragment] sets to true.
|
||||
* Usually it is indicating that user can't see fragment on screen and useful to track analytics events.
|
||||
*/
|
||||
open fun onAppear() = Unit
|
||||
|
||||
/**
|
||||
* Calls when [ViewController] have resumed.
|
||||
* Happens at [ViewControllerFragment.onResume].
|
||||
*/
|
||||
open fun onResume() = Unit
|
||||
|
||||
/**
|
||||
* Calls when [ViewController] have goes near out of memory state.
|
||||
* Happens at [ViewControllerFragment.onLowMemory].
|
||||
*/
|
||||
open fun onLowMemory() = Unit
|
||||
|
||||
/**
|
||||
* Calls when [ViewController] have paused.
|
||||
* Happens at [ViewControllerFragment.onPause].
|
||||
*/
|
||||
open fun onPause() = Unit
|
||||
|
||||
/**
|
||||
* Calls when [ViewController] should save it's state.
|
||||
* Happens at [ViewControllerFragment.onSaveInstanceState].
|
||||
* Try not to use such method for saving state but use [ViewControllerFragment.state] from [.getFragment].
|
||||
*/
|
||||
open fun onSaveInstanceState(savedInstanceState: Bundle) = Unit
|
||||
|
||||
/**
|
||||
* Called when fragment is moved in stopped state or it's [.getFragment] sets to false.
|
||||
* Usually it is indicating that user can't see fragment on screen and useful to track analytics events.
|
||||
*/
|
||||
open fun onDisappear() = Unit
|
||||
|
||||
/**
|
||||
* Calls when [ViewController] have stopped.
|
||||
* Happens at [ViewControllerFragment.onStop].
|
||||
*/
|
||||
open fun onStop() = Unit
|
||||
|
||||
/**
|
||||
* Calls when [ViewController] have destroyed.
|
||||
* Happens usually at [ViewControllerFragment.onDestroyView]. In some cases at [ViewControllerFragment.onDestroy].
|
||||
*/
|
||||
open fun onDestroy() = Unit
|
||||
|
||||
/**
|
||||
* Calls when [ViewController] have requested permissions results.
|
||||
* Happens at [ViewControllerFragment.onRequestPermissionsResult] ()}.
|
||||
*/
|
||||
open fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) = Unit
|
||||
|
||||
/**
|
||||
* Callback from parent fragment.
|
||||
*/
|
||||
open fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) = Unit
|
||||
|
||||
/**
|
||||
* Similar to [ViewControllerFragment.onOptionsItemSelected].
|
||||
*
|
||||
* @param item Selected menu item;
|
||||
* @return True if selection processed.
|
||||
*/
|
||||
open fun onOptionsItemSelected(item: MenuItem): Boolean = false
|
||||
|
||||
/**
|
||||
* Helper class to simplify constructor override.
|
||||
*/
|
||||
data class CreationContext(
|
||||
val activity: FragmentActivity,
|
||||
val fragment: ViewControllerFragment<*, *>,
|
||||
val inflater: LayoutInflater,
|
||||
val container: ViewGroup?
|
||||
)
|
||||
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation_new.viewcontrollers
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
|
||||
import ru.touchin.roboswag.components.navigation_new.FragmentNavigation
|
||||
import ru.touchin.roboswag.components.navigation_new.fragments.ViewControllerFragment
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 07/03/2016.
|
||||
* Navigation based on [ViewController]s which are creating by [Fragment]s.
|
||||
* So basically it is just [FragmentNavigation] where most of fragments should be inherited from [ViewControllerFragment].
|
||||
*
|
||||
* @param TActivity Type of activity where [ViewController]s should be showed.
|
||||
*/
|
||||
open class ViewControllerNavigation<TActivity : FragmentActivity>(
|
||||
context: Context,
|
||||
fragmentManager: FragmentManager,
|
||||
@IdRes containerViewId: Int,
|
||||
transition: Int = FragmentTransaction.TRANSIT_FRAGMENT_OPEN
|
||||
) : FragmentNavigation(context, fragmentManager, containerViewId, transition) {
|
||||
|
||||
/**
|
||||
* Pushes [ViewController] on top of stack with specific [ViewControllerFragment.getState] and with specific transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of [ViewController] to be pushed;
|
||||
* @param state [Parcelable] of [ViewController]'s fragment;
|
||||
* @param addToStack Flag to add this transaction to the back stack;
|
||||
* @param backStackName Name of [Fragment] in back stack;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param TState Type of state of fragment.
|
||||
*/
|
||||
fun <TState : Parcelable> pushViewController(
|
||||
viewControllerClass: Class<out ViewController<out TActivity, TState>>,
|
||||
state: TState,
|
||||
addToStack: Boolean = true,
|
||||
backStackName: String? = null,
|
||||
transactionSetup: ((FragmentTransaction) -> Unit)? = null
|
||||
) {
|
||||
addToStack(
|
||||
ViewControllerFragment::class.java,
|
||||
null,
|
||||
0,
|
||||
addToStack,
|
||||
ViewControllerFragment.args(viewControllerClass, state),
|
||||
backStackName,
|
||||
transactionSetup
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes [ViewController] on top of stack with specific [ViewControllerFragment.getState]
|
||||
* and with specific [TTargetFragment] and transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of [ViewController] to be pushed;
|
||||
* @param targetFragment [ViewControllerFragment] to be set as target;
|
||||
* @param state [Parcelable] of [ViewController]'s fragment;
|
||||
* @param backStackName Name of [Fragment] in back stack;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param TState Type of state of fragment;
|
||||
* @param TTargetFragment Type of target fragment.
|
||||
*/
|
||||
fun <TState : Parcelable, TTargetFragment : Fragment> pushViewControllerForResult(
|
||||
viewControllerClass: Class<out ViewController<out TActivity, TState>>,
|
||||
state: TState,
|
||||
targetFragment: TTargetFragment,
|
||||
targetRequestCode: Int,
|
||||
backStackName: String? = null,
|
||||
transactionSetup: ((FragmentTransaction) -> Unit)? = null
|
||||
) {
|
||||
addToStack(
|
||||
ViewControllerFragment::class.java,
|
||||
targetFragment,
|
||||
targetRequestCode,
|
||||
true,
|
||||
ViewControllerFragment.args(viewControllerClass, state),
|
||||
backStackName,
|
||||
transactionSetup
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes [ViewController] on top of stack with specific [ViewControllerFragment.getState] and with specific transaction setup
|
||||
* and with [.TOP_FRAGMENT_TAG_MARK] tag used for simple up/back navigation.
|
||||
*
|
||||
* @param viewControllerClass Class of [ViewController] to be pushed;
|
||||
* @param state [Parcelable] of [ViewController]'s fragment;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param TState Type of state of fragment.
|
||||
*/
|
||||
fun <TState : Parcelable> setViewControllerAsTop(
|
||||
viewControllerClass: Class<out ViewController<out TActivity, TState>>,
|
||||
state: TState,
|
||||
addToStack: Boolean = true,
|
||||
transactionSetup: ((FragmentTransaction) -> Unit)? = null
|
||||
) {
|
||||
addToStack(
|
||||
ViewControllerFragment::class.java,
|
||||
null,
|
||||
0,
|
||||
addToStack,
|
||||
ViewControllerFragment.args(viewControllerClass, state),
|
||||
TOP_FRAGMENT_TAG_MARK,
|
||||
transactionSetup
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops all [Fragment]s and places new initial [ViewController] on top of stack
|
||||
* with specific [ViewControllerFragment.getState] and specific transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of [ViewController] to be pushed;
|
||||
* @param state [Parcelable] of [ViewController]'s fragment;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param TState Type of state of fragment.
|
||||
*/
|
||||
fun <TState : Parcelable> setInitialViewController(
|
||||
viewControllerClass: Class<out ViewController<out TActivity, TState>>,
|
||||
state: TState,
|
||||
transactionSetup: ((FragmentTransaction) -> Unit)? = null
|
||||
) {
|
||||
beforeSetInitialActions()
|
||||
setViewControllerAsTop(viewControllerClass, state, false, transactionSetup)
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue