Skip to content

Commit

Permalink
WIP predictive back change handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
EricKuck committed Jan 16, 2024
1 parent 5a1746b commit fbfe3ce
Show file tree
Hide file tree
Showing 19 changed files with 294 additions and 77 deletions.
9 changes: 8 additions & 1 deletion conductor-modules/androidx-transition/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@ plugins {
}

android {
compileSdkVersion libs.versions.compilesdk.get() as Integer
compileSdk libs.versions.compilesdk.get() as Integer

compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}

defaultConfig {
minSdkVersion libs.versions.minsdk.get()
targetSdkVersion libs.versions.targetsdk.get()
versionCode Integer.parseInt(project.VERSION_CODE)
versionName project.VERSION_NAME
}

namespace "com.bluelinelabs.conductor.androidxtransition"
}

dependencies {
Expand Down

This file was deleted.

13 changes: 12 additions & 1 deletion conductor-modules/viewpager/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,25 @@ plugins {
}

android {
compileSdkVersion libs.versions.compilesdk.get() as Integer
compileSdk libs.versions.compilesdk.get() as Integer

compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}

kotlinOptions {
jvmTarget = "11"
}

defaultConfig {
minSdkVersion libs.versions.minsdk.get()
targetSdkVersion libs.versions.targetsdk.get()
versionCode Integer.parseInt(project.VERSION_CODE)
versionName project.VERSION_NAME
}

namespace "com.bluelinelabs.conductor.viewpager"
}

dependencies {
Expand Down
3 changes: 0 additions & 3 deletions conductor-modules/viewpager/src/main/AndroidManifest.xml

This file was deleted.

13 changes: 12 additions & 1 deletion conductor-modules/viewpager2/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@ plugins {
}

android {
compileSdkVersion libs.versions.compilesdk.get() as Integer
compileSdk libs.versions.compilesdk.get() as Integer

compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}

kotlinOptions {
jvmTarget = "11"
}

defaultConfig {
minSdkVersion libs.versions.minsdk.get()
Expand All @@ -20,6 +29,8 @@ android {
includeAndroidResources = true
}
}

namespace "com.bluelinelabs.conductor.viewpager2"
}

dependencies {
Expand Down
3 changes: 0 additions & 3 deletions conductor-modules/viewpager2/src/main/AndroidManifest.xml

This file was deleted.

13 changes: 12 additions & 1 deletion conductor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@ plugins {
}

android {
compileSdkVersion libs.versions.compilesdk.get() as Integer
compileSdk libs.versions.compilesdk.get() as Integer

compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}

kotlinOptions {
jvmTarget = "11"
}

defaultConfig {
minSdkVersion libs.versions.minsdk.get()
Expand All @@ -15,6 +24,8 @@ android {
versionName project.VERSION_NAME
consumerProguardFiles 'proguard-rules.txt'
}

namespace "com.bluelinelabs.conductor"
}

dependencies {
Expand Down
3 changes: 0 additions & 3 deletions conductor/src/main/AndroidManifest.xml

This file was deleted.

102 changes: 102 additions & 0 deletions conductor/src/main/java/com/bluelinelabs/conductor/Controller.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
Expand All @@ -16,6 +17,7 @@
import android.view.View;
import android.view.ViewGroup;

import androidx.activity.BackEventCompat;
import androidx.activity.ComponentActivity;
import androidx.activity.OnBackPressedCallback;
import androidx.activity.OnBackPressedDispatcher;
Expand All @@ -24,6 +26,7 @@
import androidx.annotation.Nullable;
import androidx.lifecycle.LifecycleOwner;

import com.bluelinelabs.conductor.internal.BackGestureViewState;
import com.bluelinelabs.conductor.internal.ClassUtils;
import com.bluelinelabs.conductor.internal.ControllerLifecycleOwner;
import com.bluelinelabs.conductor.internal.OwnViewTreeLifecycleAndRegistry;
Expand Down Expand Up @@ -97,6 +100,9 @@ public abstract class Controller {
private boolean isContextAvailable;

final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) {
ControllerChangeHandler.ChangeTransaction popTransaction = null;
List<BackGestureViewState> viewsForGesture = null;

@Override
public void handleOnBackPressed() {
// Root-level routers should have PopRootControllerMode.NEVER, and so should never return false here.
Expand All @@ -111,6 +117,102 @@ public void handleOnBackPressed() {
}
}
}

@Override
public void handleOnBackStarted(@NonNull BackEventCompat backEvent) {
Log.d("KUCK", "it has begun");
ControllerChangeHandler.ChangeTransaction transaction = getPopTransaction();
if (transaction != null && transaction.changeHandler != null && transaction.changeHandler.getEnableOnBackGestureCallbacks()) {
if (transaction.to != null && transaction.to.view == null) {
viewsForGesture = viewsForGesture(transaction, new ArrayList<>());
}

for (int i = viewsForGesture.size() - 1; i > 0; i--) {
transaction.container.addView(viewsForGesture.get(i).getView());
}

transaction.changeHandler.handleOnBackStarted(
transaction.container,
transaction.to != null ? transaction.to.view : null,
transaction.from.view,
backEvent
);
}
}

@Override
public void handleOnBackProgressed(@NonNull BackEventCompat backEvent) {
Log.d("KUCK", "it has progressed");

ControllerChangeHandler.ChangeTransaction transaction = getPopTransaction();
if (transaction != null && transaction.changeHandler != null && transaction.changeHandler.getEnableOnBackGestureCallbacks()) {
transaction.changeHandler.handleOnBackProgressed(
transaction.container,
transaction.to != null ? transaction.to.view : null,
transaction.from.view,
backEvent
);
}
}

@Override
public void handleOnBackCancelled() {
Log.d("KUCK", "it has canceled");

ControllerChangeHandler.ChangeTransaction transaction = getPopTransaction();
if (transaction != null && transaction.changeHandler != null && transaction.changeHandler.getEnableOnBackGestureCallbacks()) {
transaction.changeHandler.handleOnBackCancelled(
transaction.container,
transaction.to != null ? transaction.to.view : null,
transaction.from.view
);
}

for (int i = 0; i < viewsForGesture.size(); i++) {
BackGestureViewState state = viewsForGesture.get(i);
ViewGroup parent = (ViewGroup) state.getView().getParent();
if (parent != null) {
parent.removeView(state.getView());
}

if (state.getInflatedForGesture()) {
state.getController().removeViewReference(state.getView().getContext());
}
}

viewsForGesture.clear();
}

private ControllerChangeHandler.ChangeTransaction getPopTransaction() {
if (popTransaction == null) {
popTransaction = router.popTransaction(Controller.this);
}
return popTransaction;
}

private List<BackGestureViewState> viewsForGesture(
ControllerChangeHandler.ChangeTransaction transaction,
List<BackGestureViewState> aggregator
) {
if (transaction.to != null) {
View view = transaction.to.view;
boolean inflated = false;
if (view == null) {
view = transaction.to.inflate(transaction.container);
inflated = true;
} else if (view.getParent() != null) {
return aggregator;
}

aggregator.add(new BackGestureViewState(transaction.to, view, inflated));

if (!transaction.changeHandler.getRemovesFromViewOnPush()) {
viewsForGesture(router.popTransaction(transaction.to), aggregator);
}
}

return aggregator;
}
};

public final LifecycleOwner lifecycleOwner = new ControllerLifecycleOwner(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.bluelinelabs.conductor
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.activity.BackEventCompat
import androidx.annotation.RestrictTo
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler
import com.bluelinelabs.conductor.internal.ClassUtils
Expand Down Expand Up @@ -50,6 +51,8 @@ abstract class ControllerChangeHandler {

private var hasBeenUsed = false

open val enableOnBackGestureCallbacks = false

init {
try {
javaClass.getConstructor()
Expand Down Expand Up @@ -112,9 +115,9 @@ abstract class ControllerChangeHandler {
*/
open fun copy(): ControllerChangeHandler = fromBundle(toBundle())!!

open fun handleOnBackStarted(container: ViewGroup, to: View?, from: View, swipeEdge: Int) {}
open fun handleOnBackStarted(container: ViewGroup, to: View?, from: View, event: BackEventCompat) {}

open fun handleOnBackProgressed(container: ViewGroup, to: View?, from: View, progress: Float, swipeEdge: Int) {}
open fun handleOnBackProgressed(container: ViewGroup, to: View?, from: View, event: BackEventCompat) {}

open fun handleOnBackCancelled(container: ViewGroup, to: View?, from: View) {}

Expand Down
31 changes: 31 additions & 0 deletions conductor/src/main/java/com/bluelinelabs/conductor/Router.java
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,37 @@ private void popToTransaction(@NonNull RouterTransaction transaction, @Nullable
}
}

@Nullable
ChangeTransaction popTransaction(@NonNull Controller controller) {
RouterTransaction from = null;
RouterTransaction to = null;

Iterator<RouterTransaction> iterator = backstack.iterator();
while (iterator.hasNext()) {
RouterTransaction transaction = iterator.next();
if (transaction.controller() == controller) {
from = transaction;
if (iterator.hasNext()) {
to = iterator.next();
}
break;
}
}

if (from == null) {
return null;
}

return new ChangeTransaction(
to != null ? to.controller() : null,
from.controller(),
false,
container,
from.popChangeHandler(),
Collections.emptyList()
);
}

void watchContainerAttach() {
container.post(new Runnable() {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.bluelinelabs.conductor.internal

import android.view.View
import com.bluelinelabs.conductor.Controller

class BackGestureViewState(
val controller: Controller,
val view: View,
val inflatedForGesture: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import androidx.savedstate.setViewTreeSavedStateRegistryOwner
import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
import com.bluelinelabs.conductor.R

/**
* This class sets the [ViewTreeLifecycleOwner] and [ViewTreeSavedStateRegistryOwner] which is
Expand Down Expand Up @@ -56,8 +55,8 @@ internal class OwnViewTreeLifecycleAndRegistry private constructor(
* it on purpose.
*/
if (
view.getTag(R.id.view_tree_lifecycle_owner) == null &&
view.getTag(R.id.view_tree_saved_state_registry_owner) == null
view.getTag(androidx.lifecycle.runtime.R.id.view_tree_lifecycle_owner) == null &&
view.getTag(androidx.savedstate.R.id.view_tree_saved_state_registry_owner) == null
) {
view.setViewTreeLifecycleOwner(this@OwnViewTreeLifecycleAndRegistry)
view.setViewTreeSavedStateRegistryOwner(this@OwnViewTreeLifecycleAndRegistry)
Expand Down
10 changes: 6 additions & 4 deletions demo/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,22 @@ android {
compose = true
}

compileSdkVersion 33
compileSdk 34

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}

kotlinOptions {
jvmTarget = "1.8"
jvmTarget = "11"
}

composeOptions {
kotlinCompilerExtensionVersion libs.versions.compose.compiler.get()
}

namespace "com.bluelinelabs.conductor.demo"
}

dependencies {
Expand Down
Loading

0 comments on commit fbfe3ce

Please sign in to comment.