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

View File

@ -26,7 +26,7 @@ public abstract class ItemAdapterDelegate<TViewHolder extends BindableViewHolder
* This item will be casted to {@link TItem} and passes to {@link #onBindViewHolder(TViewHolder, TItem, int, int)}.
*
* @param item Item to check;
* @param positionInAdapter Position of item in adapter;
* @param positionInAdapter Position of item in adapter;
* @param itemCollectionPosition Position of item in collection that contains item;
* @return True if item is processable by this delegate.
*/
@ -35,8 +35,8 @@ public abstract class ItemAdapterDelegate<TViewHolder extends BindableViewHolder
/**
* Returns unique ID of item to support stable ID's logic of RecyclerView's adapter.
*
* @param item Item to check;
* @param positionInAdapter Position of item in adapter;
* @param item Item to check;
* @param positionInAdapter Position of item in adapter;
* @param positionInCollection Position of item in collection that contains item;
* @return Unique item ID.
*/
@ -56,9 +56,9 @@ public abstract class ItemAdapterDelegate<TViewHolder extends BindableViewHolder
/**
* Binds item to created by this object ViewHolder.
*
* @param holder ViewHolder to bind item to;
* @param item Item to check;
* @param positionInAdapter Position of item in adapter;
* @param holder ViewHolder to bind item to;
* @param item Item to check;
* @param positionInAdapter Position of item in adapter;
* @param positionInCollection Position of item in collection that contains item;
*/
public abstract void onBindViewHolder(@NonNull final TViewHolder holder, @NonNull final TItem item,
@ -67,10 +67,10 @@ public abstract class ItemAdapterDelegate<TViewHolder extends BindableViewHolder
/**
* Binds item with payloads to created by this object ViewHolder.
*
* @param holder ViewHolder to bind item to;
* @param item Item to check;
* @param payloads Payloads;
* @param positionInAdapter Position of item in adapter;
* @param holder ViewHolder to bind item to;
* @param item Item to check;
* @param payloads Payloads;
* @param positionInAdapter Position of item in adapter;
* @param positionInCollection Position of item in collection that contains item;
*/
public void onBindViewHolder(@NonNull final TViewHolder holder, @NonNull final TItem item, @NonNull final List<Object> payloads,

View File

@ -104,6 +104,11 @@ public abstract class ObservableCollectionAdapter<TItem, TItemViewHolder extends
lifecycleBindable.untilDestroy(observableCollectionSubject
.switchMap(optional -> {
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());
}), innerCollection::set);
lifecycleBindable.untilDestroy(createMoreAutoLoadingObservable());
@ -607,8 +612,8 @@ public abstract class ObservableCollectionAdapter<TItem, TItemViewHolder extends
/**
* Enable diff utils algorithm in collection changes.
*
* @param detectMoves The flag that determines whether the {@link Change.Moved} changes will be generated or not;
* @param sameItemsPredicate Predicate for the determination of the same elements;
* @param detectMoves The flag that determines whether the {@link Change.Moved} changes will be generated or not;
* @param sameItemsPredicate Predicate for the determination of the same elements;
* @param changePayloadProducer Function that calculate change payload when items the same but contents are different.
*/
public void enableDiffUtils(final boolean detectMoves,

View File

@ -50,7 +50,7 @@ public abstract class PositionAdapterDelegate<TViewHolder extends BindableViewHo
/**
* Binds position to ViewHolder.
*
* @param holder ViewHolder to bind position to;
* @param holder ViewHolder to bind position to;
* @param positionInAdapter Position of item in adapter.
*/
public abstract void onBindViewHolder(@NonNull final TViewHolder holder, final int positionInAdapter);
@ -58,8 +58,8 @@ public abstract class PositionAdapterDelegate<TViewHolder extends BindableViewHo
/**
* Binds position with payloads to ViewHolder.
*
* @param holder ViewHolder to bind position to;
* @param payloads Payloads;
* @param holder ViewHolder to bind position to;
* @param payloads Payloads;
* @param positionInAdapter Position of item in adapter.
*/
public void onBindViewHolder(@NonNull final TViewHolder holder, @NonNull final List<Object> payloads, final int positionInAdapter) {

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);
}
/**
* 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()}.
*
@ -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 <TTargetFragment> Type of target fragment.
*/
@SuppressWarnings("CPD-END")
public <TTargetState extends AbstractState,
TTargetFragment extends ViewControllerFragment<? extends TTargetState, TActivity>> void pushViewControllerForResult(
@NonNull final Class<? extends ViewController<TActivity,

View File

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

View File

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

View File

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

View File

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