Compare commits

...

19 Commits

Author SHA1 Message Date
Denis Karmyshakov e6dd2c5bcd
Merge pull request #131 from TouchInstinct/logging
toString for ViewControllerFragment
2018-08-22 17:55:05 +03:00
Denis Karmyshakov 13441b3563 toString for ViewControllerFragment 2018-06-15 21:15:12 +03:00
Anton Domnikov 2f0799ae21 Feature/push stateless targeted view controller for result (#116) 2018-02-19 16:08:21 +03:00
Anton Domnikov 096a2643a0 added ability to push stateless targeted view controllers for result (#113) 2018-02-16 15:28:50 +03:00
maxbach 8a892136f0 Add to MaterialLoadingBar method setColor (#111) 2017-12-28 15:20:19 +03:00
Denis Karmyshakov 31973bf99e Gradle update (#107) 2017-11-20 19:20:05 +03:00
Arseniy Borisov 7bd7137b82 Update by payload fixed (#106) 2017-11-13 12:09:58 +03:00
Denis Karmyshakov 848e4ec287 Merge pull request #103 from TouchInstinct/versions_in_constants
Versions in constants
2017-10-04 13:12:56 +03:00
Denis Karmyshakov 38358cf999 Versions in constants 2017-10-04 13:10:49 +03:00
Denis Karmyshakov e33827ee36 Versions in constants 2017-10-04 13:05:39 +03:00
Ilia Kurtov b1103f61d8 Merge pull request #97 from TouchInstinct/lib_update
rxjava version
2017-09-15 16:29:09 +03:00
gorodeckii ef733a5d87 rxjava version 2017-09-15 15:17:38 +03:00
Gavriil 795c3b698a RxJava version update (#96) 2017-09-11 18:51:07 +03:00
Arseniy Borisov cb919c65b1 format javadoc (#94) 2017-09-04 17:35:57 +03:00
Elena Bobkova 77957b2346 fixed on activity result bindings for large files (#89) 2017-08-14 15:32:00 +03:00
Gavriil 78786250d3 Bugs/fix of sinstateks (#87)
* fix of wrong delaying items
2017-08-09 17:19:05 +03:00
Gavriil 89dff2e1f5 Merge pull request #86 from TouchInstinct/feature/deeplinks-master
Feature/deeplinks master
2017-08-04 18:54:13 +03:00
Ilia Kurtov 93142fdae1 static 2017-08-04 16:41:27 +03:00
Ilia Kurtov 379e0f0cad Base classes for deeplinks processing 2017-08-04 16:41:20 +03:00
13 changed files with 371 additions and 39 deletions

View File

@ -1,9 +1,7 @@
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
apply plugin: 'me.tatarka.retrolambda'
android { android {
compileSdkVersion 25 compileSdkVersion compileSdk
buildToolsVersion '25.0.3'
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
@ -16,11 +14,11 @@ android {
} }
dependencies { dependencies {
compile project(':libraries:core') api project(':libraries:core')
provided 'com.android.support:appcompat-v7:25.4.0' compileOnly "com.android.support:appcompat-v7:$supportLibraryVersion"
provided 'com.android.support:recyclerview-v7:25.4.0' compileOnly "com.android.support:recyclerview-v7:$supportLibraryVersion"
provided 'io.reactivex:rxandroid:1.2.1' compileOnly "io.reactivex:rxandroid:$rxAndroidVersion"
provided 'io.reactivex:rxjava:1.3.0' compileOnly "io.reactivex:rxjava:$rxJavaVersion"
} }

View File

@ -104,6 +104,11 @@ public abstract class ObservableCollectionAdapter<TItem, TItemViewHolder extends
lifecycleBindable.untilDestroy(observableCollectionSubject lifecycleBindable.untilDestroy(observableCollectionSubject
.switchMap(optional -> { .switchMap(optional -> {
final ObservableCollection<TItem> collection = optional.get(); final ObservableCollection<TItem> collection = optional.get();
if (collection instanceof ObservableList) {
innerCollection.setDiffUtilsSource((ObservableList<TItem>) collection);
} else {
innerCollection.setDiffUtilsSource(null);
}
return collection != null ? collection.observeItems() : Observable.just(Collections.emptyList()); return collection != null ? collection.observeItems() : Observable.just(Collections.emptyList());
}), innerCollection::set); }), innerCollection::set);
lifecycleBindable.untilDestroy(createMoreAutoLoadingObservable()); lifecycleBindable.untilDestroy(createMoreAutoLoadingObservable());

View File

@ -0,0 +1,75 @@
/*
* 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.deeplinks;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import ru.touchin.roboswag.components.navigation.activities.BaseActivity;
/**
* Controller that helps to manage deep links in activity.
* It helps to save and restore deep link and deletes deep link info from intent.
* As tin he base class - call methods that starts with 'on' prefix from activity.
*
* @see #onActivityRestoreInstanceState(Bundle)
* @see #onActivitySavedInstanceState(Bundle)
*/
public abstract class ActivityDeepLinkController<TActivity extends BaseActivity> extends DeepLinkController<TActivity> {
private static final String DEEP_LINK_EXTRA = "DEEP_LINK_EXTRA";
/**
* Call this method on restore instance state -
* in {@link Activity#onCreate(Bundle)} or in {@link Activity#onRestoreInstanceState(Bundle)}.
*
* @param savedInstanceState - activity's savedInstanceState.
*/
public void onActivityRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
final String deepLinkUrl = savedInstanceState.getString(DEEP_LINK_EXTRA, null);
onNewDeepLink(deepLinkUrl == null ? null : Uri.parse(deepLinkUrl));
}
/**
* Call this method while saving stat of activity - in {@link Activity#onSaveInstanceState(Bundle)}.
*
* @param stateToSave - activity's stateToSave.
*/
public void onActivitySavedInstanceState(@NonNull final Bundle stateToSave) {
if (getDeepLinkUri() != null) {
stateToSave.putString(DEEP_LINK_EXTRA, getDeepLinkUri().toString());
}
}
/**
* Helps to delete info about deep link from activity's intent and from this controller.
* Call this after successful deep link processing.
*
* @param activity - that should delete info about processed deep link.
*/
protected void deleteDeepLink(@NonNull final TActivity activity) {
onNewDeepLink(null);
activity.getIntent().setData(null);
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.deeplinks;
import android.net.Uri;
import android.support.annotation.NonNull;
import ru.touchin.roboswag.components.navigation.activities.BaseActivity;
/**
* Created by Ilia Kurtov on 04.08.2015.
* Class that helps to operate with deep links.
*
* @param <TActivity> Type of Activity to process deep links.
*/
public interface DeepLink<TActivity extends BaseActivity> {
/**
* Called by deep link to provide unique name.
*/
@NonNull
String getName();
/**
* Called by deep link to decide - whenever deep link should process uri or if we are already on that screen that deep link links to.
*/
boolean isOnSuchScreen(@NonNull TActivity activity, @NonNull Uri deepLinkUri);
/**
* Called by deep link to navigate to the specific screen.
*/
void navigateTo(@NonNull TActivity activity, @NonNull Uri deepLinkUri);
}

View File

@ -0,0 +1,123 @@
/*
* 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.deeplinks;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import ru.touchin.roboswag.components.navigation.activities.BaseActivity;
/**
* Created by Ilia Kurtov on 04.08.2015.
* Controller for deep links. Its main goal to decide when deep link should be processed.
* Call methods that starts with 'on' prefix from {@link TActivity} that should process deep links.
*
* @param <TActivity> Type of Activity to process deep links.
* @see #onNewDeepLink(Uri)
* @see #onActivityReadyToProcessDeepLink(BaseActivity)
* @see #onActivityStopBeingReady()
*/
public abstract class DeepLinkController<TActivity extends BaseActivity> {
@Nullable
private Uri deepLinkUri;
@Nullable
private TActivity activity;
private boolean allowDeepLinkToProcess = true;
/**
* Get current deep link.
*
* @return - current deep link
*/
@Nullable
protected Uri getDeepLinkUri() {
return deepLinkUri;
}
/**
* Call this method after receiving new deep link {@link Uri} from your activity.
* It saves new deepLinkUri and tries to process deep link if possible.
* In most common cases call this method in {@link Activity#onCreate(Bundle)}
* if bundle == null or if you want to restore deep link
* in {@link Activity#onCreate(Bundle)} or in {@link Activity#onRestoreInstanceState(Bundle)}
* methods.
*
* @param deepLinkUri - received deep link.
*/
public void onNewDeepLink(@Nullable final Uri deepLinkUri) {
this.deepLinkUri = deepLinkUri;
startToProcessDeepLinkIfPossible();
}
/**
* Call this method when your activity should be ready to process deep link.
* In most common cases call this method on {@link Activity#onStart()}
*
* @param activity - that should be able to process deep link.
*/
public void onActivityReadyToProcessDeepLink(@NonNull final TActivity activity) {
this.activity = activity;
startToProcessDeepLinkIfPossible();
}
/**
* Call this method when your activity stopped being ready to process deep link.
* In most common cases call this method on {@link Activity#onStop()}
*/
public void onActivityStopBeingReady() {
activity = null;
}
/**
* This method should be called when you need to add additional condition
* for processing deep links. By default {@link #allowDeepLinkToProcess}
* equals true.
*
* @param allowDeepLinkToProcess - pass true here if you want to allow deep
* link to process, otherwise - pass false.
*/
public void setAllowDeepLinkToProcess(final boolean allowDeepLinkToProcess) {
this.allowDeepLinkToProcess = allowDeepLinkToProcess;
startToProcessDeepLinkIfPossible();
}
private void startToProcessDeepLinkIfPossible() {
if (activity != null && deepLinkUri != null && allowDeepLinkToProcess) {
processDeepLink(activity, deepLinkUri);
}
}
/**
* This method would be called if there are non null {@link TActivity},
* non null {@link #deepLinkUri} and {@link #allowDeepLinkToProcess} equals true.
* Don't forget to call activity.getIntent().setData(null) after deep link processing
*
* @param activity - that should be able to process deep link.
* @param deepLinkUri - received deep link.
*/
protected abstract void processDeepLink(@NonNull final TActivity activity,
@NonNull final Uri deepLinkUri);
}

View File

@ -0,0 +1,51 @@
/*
* 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.deeplinks;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import ru.touchin.roboswag.components.navigation.activities.BaseActivity;
/**
* Created by Ilia Kurtov on 04.08.2015.
* Simple DeepLinkController that process deep links as it is. When deep links received it would have been processing and navigating id should.
*/
public abstract class SimpleActivityDeepLinkController<TActivity extends BaseActivity, TDeepLink extends DeepLink<TActivity>>
extends ActivityDeepLinkController<TActivity> {
@Override
protected void processDeepLink(@NonNull final TActivity activity, @NonNull final Uri deepLinkUri) {
deleteDeepLink(activity);
final TDeepLink deepLink = getDeepLinkByUri(deepLinkUri);
if (deepLink != null && !deepLink.isOnSuchScreen(activity, deepLinkUri)) {
deleteDeepLink(activity);
deepLink.navigateTo(activity, deepLinkUri);
}
}
/**
* Returns deep link that extending {@link DeepLink}.
*/
@Nullable
protected abstract TDeepLink getDeepLinkByUri(@NonNull final Uri deepLinkUri);
}

View File

@ -211,6 +211,26 @@ public class ViewControllerNavigation<TActivity extends ViewControllerActivity<?
addViewControllerToStack(viewControllerClass, null, state, null, transactionSetup); addViewControllerToStack(viewControllerClass, null, state, null, transactionSetup);
} }
/**
* Pushes {@link ViewController} on top of stack with specific {@link StatelessTargetedViewControllerFragment#getState()}
* and with specific {@link TargetedViewControllerFragment#getTarget()}.
*
* @param viewControllerClass Class of {@link ViewController} to be pushed;
* @param targetFragment {@link ViewControllerFragment} to be set as target;
* @param <TTargetState> Type of state of target fragment. State is using to affect on that fragment;
* @param <TTargetFragment> Type of target fragment.
*/
@SuppressWarnings("CPD-START")
public <TTargetState extends AbstractState,
TTargetFragment extends ViewControllerFragment<? extends TTargetState, TActivity>> void pushStatelessTargetedViewControllerForResult(
@NonNull final Class<? extends ViewController<TActivity,
TargetedViewControllerFragment<AbstractState, TTargetState, TActivity>>> viewControllerClass,
@NonNull final TTargetFragment targetFragment) {
addToStack(StatelessTargetedViewControllerFragment.class, targetFragment,
StatelessTargetedViewControllerFragment.createState(viewControllerClass),
viewControllerClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null);
}
/** /**
* Pushes {@link ViewController} on top of stack with specific {@link StatelessTargetedViewControllerFragment#getTarget()}. * Pushes {@link ViewController} on top of stack with specific {@link StatelessTargetedViewControllerFragment#getTarget()}.
* *
@ -219,6 +239,7 @@ public class ViewControllerNavigation<TActivity extends ViewControllerActivity<?
* @param <TTargetState> Type of state of target fragment. State is using to affect on that fragment; * @param <TTargetState> Type of state of target fragment. State is using to affect on that fragment;
* @param <TTargetFragment> Type of target fragment. * @param <TTargetFragment> Type of target fragment.
*/ */
@SuppressWarnings("CPD-END")
public <TTargetState extends AbstractState, public <TTargetState extends AbstractState,
TTargetFragment extends ViewControllerFragment<? extends TTargetState, TActivity>> void pushViewControllerForResult( TTargetFragment extends ViewControllerFragment<? extends TTargetState, TActivity>> void pushViewControllerForResult(
@NonNull final Class<? extends ViewController<TActivity, @NonNull final Class<? extends ViewController<TActivity,

View File

@ -114,7 +114,7 @@ public abstract class BaseActivity extends AppCompatActivity
@NonNull @NonNull
public Observable<Intent> observeActivityResult(final int requestCode) { public Observable<Intent> observeActivityResult(final int requestCode) {
return lastActivityResult return lastActivityResult
.switchMap(optional -> { .concatMap(optional -> {
final HalfNullablePair<Integer, Intent> activityResult = optional.get(); final HalfNullablePair<Integer, Intent> activityResult = optional.get();
if (activityResult == null || activityResult.getFirst() != requestCode) { if (activityResult == null || activityResult.getFirst() != requestCode) {
return Observable.empty(); return Observable.empty();

View File

@ -384,6 +384,12 @@ public abstract class ViewControllerFragment<TState extends AbstractState, TActi
super.onDestroy(); super.onDestroy();
} }
@NonNull
@Override
public String toString() {
return super.toString() + "ViewController: " + getViewControllerClass();
}
private static class PlaceholderView extends FrameLayout { private static class PlaceholderView extends FrameLayout {
@NonNull @NonNull

View File

@ -49,7 +49,7 @@ public class BaseLifecycleBindable implements LifecycleBindable {
@NonNull @NonNull
private final BehaviorSubject<Boolean> isStartedSubject = BehaviorSubject.create(); private final BehaviorSubject<Boolean> isStartedSubject = BehaviorSubject.create();
@NonNull @NonNull
private final BehaviorSubject<Boolean> isInAfterSaving = BehaviorSubject.create(false); private final BehaviorSubject<Boolean> isInAfterSaving = BehaviorSubject.create();
/** /**
* Call it on parent's onCreate method. * Call it on parent's onCreate method.
@ -62,10 +62,8 @@ public class BaseLifecycleBindable implements LifecycleBindable {
* Call it on parent's onStart method. * Call it on parent's onStart method.
*/ */
public void onStart() { public void onStart() {
if (!isStartedSubject.hasValue() || !isStartedSubject.getValue()) {
isStartedSubject.onNext(true); isStartedSubject.onNext(true);
} }
}
/** /**
* Call it on parent's onResume method. * Call it on parent's onResume method.
@ -87,10 +85,8 @@ public class BaseLifecycleBindable implements LifecycleBindable {
* Call it on parent's onStop method. * Call it on parent's onStop method.
*/ */
public void onStop() { public void onStop() {
if (!isStartedSubject.hasValue() || isStartedSubject.getValue()) {
isStartedSubject.onNext(false); isStartedSubject.onNext(false);
} }
}
/** /**
* Call it on parent's onDestroy method. * Call it on parent's onDestroy method.
@ -127,8 +123,8 @@ public class BaseLifecycleBindable implements LifecycleBindable {
@NonNull final Action1<T> onNextAction, @NonNull final Action1<T> onNextAction,
@NonNull final Action1<Throwable> onErrorAction, @NonNull final Action1<Throwable> onErrorAction,
@NonNull final Action0 onCompletedAction) { @NonNull final Action0 onCompletedAction) {
return until(observable, isStartedSubject.map(started -> !started) return until(observable.delay(item -> isInAfterSaving.first(inAfterSaving -> !inAfterSaving)),
.delay(item -> isInAfterSaving.filter(inAfterSaving -> !inAfterSaving)), isStartedSubject.map(started -> !started),
onNextAction, onErrorAction, onCompletedAction); onNextAction, onErrorAction, onCompletedAction);
} }
@ -151,9 +147,7 @@ public class BaseLifecycleBindable implements LifecycleBindable {
public <T> Subscription untilStop(@NonNull final Single<T> single, public <T> Subscription untilStop(@NonNull final Single<T> single,
@NonNull final Action1<T> onSuccessAction, @NonNull final Action1<T> onSuccessAction,
@NonNull final Action1<Throwable> onErrorAction) { @NonNull final Action1<Throwable> onErrorAction) {
return until(single.toObservable(), isStartedSubject.map(started -> !started) return untilStop(single.toObservable(), onSuccessAction, onErrorAction, Actions.empty());
.delay(item -> isInAfterSaving.filter(inAfterSaving -> !inAfterSaving)),
onSuccessAction, onErrorAction, Actions.empty());
} }
@NonNull @NonNull
@ -176,9 +170,7 @@ public class BaseLifecycleBindable implements LifecycleBindable {
public Subscription untilStop(@NonNull final Completable completable, public Subscription untilStop(@NonNull final Completable completable,
@NonNull final Action0 onCompletedAction, @NonNull final Action0 onCompletedAction,
@NonNull final Action1<Throwable> onErrorAction) { @NonNull final Action1<Throwable> onErrorAction) {
return until(completable.toObservable(), isStartedSubject.map(started -> !started) return untilStop(completable.toObservable(), Actions.empty(), onErrorAction, onCompletedAction);
.delay(item -> isInAfterSaving.filter(inAfterSaving -> !inAfterSaving)),
Actions.empty(), onErrorAction, onCompletedAction);
} }
@NonNull @NonNull

View File

@ -22,6 +22,7 @@ package ru.touchin.roboswag.components.views;
import android.content.Context; import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.os.Build; import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatImageView; import android.support.v7.widget.AppCompatImageView;
@ -107,4 +108,13 @@ public class MaterialLoadingBar extends AppCompatImageView {
super.onDetachedFromWindow(); super.onDetachedFromWindow();
} }
/**
* Set color of loader.
*
* @param colorInt Color of loader to be set.
*/
public void setColor(@ColorInt final int colorInt) {
progressDrawable.setColor(colorInt);
}
} }