Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 98b1ff265f | |||
| 9464fae539 | |||
| db0061a416 | |||
| 8b2b1e0137 | |||
| 2ac7848bbb | |||
| 29bc51db6f | |||
| e2f78e8185 | |||
| 3eb0302046 | |||
| 933fdd2715 | |||
| 143b144cbf | |||
| eeb5d20b8c | |||
| fe79f30c25 | |||
| 0ee0df0bcc | |||
| f665c263ee | |||
| 835d6425be | |||
| 851535ab28 | |||
| e4bb13b025 | |||
| 4e0f36d57a | |||
| 752c22c0b9 | |||
| ced094ea55 | |||
| ecd214fa36 | |||
| dcfe1a32b8 | |||
| 4120ce878d | |||
| c9ca3f76da | |||
| 9a7b4421c2 | |||
| 81774d2d12 | |||
| 30f2f736c0 | |||
| 0f59f588b8 | |||
| 68bc8c809c | |||
| 37d5818413 | |||
| 7344926349 | |||
| 357f8d9670 | |||
| d8266b02b8 | |||
| 7337901f19 | |||
| 2e647aec0e | |||
| e10725955b | |||
| f357e9db3a | |||
| 5ed9df5409 | |||
| b493cf5a7b | |||
| 2be8ac0db2 | |||
| b317498d95 | |||
| 230d7ba064 | |||
| b5c2d20ea3 | |||
| 1647377fb1 | |||
| f6b8c0bfe1 | |||
| 5a4eeef49f | |||
| 340e659502 | |||
| f88ab56ee9 | |||
| 3e26610157 | |||
| 906baccdfe | |||
| 72d100197a | |||
| 10918fd759 | |||
| c02d5a1ff8 |
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Konstantin Tskhovrebov (@terrakok)
|
||||
and Vasili Chyrvon (@Jeevuz)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,18 +1,18 @@
|
||||
# Cicerone
|
||||
[](https://bintray.com/terrakok/terramaven/cicerone/_latestVersion)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
[](https://gitter.im/terrakok/Cicerone)
|
||||
|
||||
[](https://android-arsenal.com/details/1/4700)
|
||||
[](http://androidweekly.net/issues/issue-250)
|
||||
[](https://t.me/Cicerone_ENG)
|
||||
[](https://t.me/Cicerone_RUS)
|
||||
[](http://androidweekly.net/issues/issue-250)
|
||||
[](http://androidweekly.net/issues/issue-271)
|
||||
|
||||

|
||||
|
||||
Cicerone (a guide, one who conducts sightseers) is a lightweight library that makes the navigation in an Android app easy.
|
||||
It was designed to be used with the MVP pattern (try [Moxy](https://github.com/Arello-Mobile/Moxy)), but will work great with any architecture.
|
||||
|
||||
[Russian version readme](https://github.com/terrakok/Cicerone/blob/develop/README_RUS.md)
|
||||
|
||||
## Main advantages
|
||||
+ is not tied to Fragments
|
||||
+ not a framework
|
||||
@@ -21,6 +21,11 @@ It was designed to be used with the MVP pattern (try [Moxy](https://github.com/A
|
||||
+ functionality is simple to extend
|
||||
+ suitable for Unit Testing
|
||||
|
||||
## Additional features
|
||||
+ easy screen result subscription
|
||||
+ predefined navigator ready for setup transition animation
|
||||
**See the sample application**
|
||||
|
||||
## How to add
|
||||
Add the dependency in your build.gradle:
|
||||
```groovy
|
||||
@@ -84,21 +89,21 @@ public class SamplePresenter extends Presenter<SampleView> {
|
||||
Router converts the navigation call to the set of Commands and sends them to CommandBuffer.
|
||||
|
||||
CommandBuffer checks whether there are _"active"_ Navigator:
|
||||
If yes, it passes the commands to the Navigator. Navigator will process them to achive the desired transition.
|
||||
If no, then CommandBuffer saves the commands in a queue, and will apply them as soon as new _"active"_ Navigator will appear.
|
||||
- If yes, it passes the commands to the Navigator. Navigator will process them to achive the desired transition.
|
||||
- If no, then CommandBuffer saves the commands in a queue, and will apply them as soon as new _"active"_ Navigator will appear.
|
||||
|
||||
```java
|
||||
protected void executeCommand(Command command) {
|
||||
if (navigator != null) {
|
||||
navigator.applyCommand(command);
|
||||
} else {
|
||||
pendingCommands.add(command);
|
||||
void executeCommands(Command[] commands) {
|
||||
if (navigator != null) {
|
||||
navigator.applyCommands(commands);
|
||||
} else {
|
||||
pendingCommands.add(commands);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Navigator processes the navigation commands. Usually it is an anonymous class inside the Activity.
|
||||
Activity provides Navigator to the CommandBuffer in _onResume_ and removes it in _onPause_.
|
||||
Navigator processes the navigation commands. Usually it is an anonymous class inside the Activity.
|
||||
Activity provides Navigator to the CommandBuffer in _onResume_ and removes it in _onPause_.
|
||||
|
||||
**Attention**: Use _onResumeFragments()_ with FragmentActivity ([more info](https://developer.android.com/reference/android/support/v4/app/FragmentActivity.html#onResume()))
|
||||
|
||||
@@ -125,45 +130,54 @@ private Navigator navigator = new Navigator() {
|
||||
|
||||
## Navigation commands
|
||||
This commands set will fulfill the needs of the most applications. But if you need something special - just add it!
|
||||
+ Forward - Opens new screen
|
||||
+ Forward - Opens new screen
|
||||

|
||||
+ Back - Rolls back the last transition
|
||||
+ Back - Rolls back the last transition
|
||||

|
||||
+ BackTo - Rolls back to the needed screen in the screens chain
|
||||
+ BackTo - Rolls back to the needed screen in the screens chain
|
||||

|
||||
+ Replace - Replaces the current screen
|
||||
+ Replace - Replaces the current screen
|
||||

|
||||
+ SystemMessage - Shows system message (Alert, Toast, Snack, etc.)
|
||||
+ SystemMessage - Shows system message (Alert, Toast, Snack, etc.)
|
||||

|
||||
|
||||
## Predefined navigators
|
||||
The library provides predefined navigators for _Fragments_ to use inside _Activity_.
|
||||
To use, just provide it with the container and _FragmentManager_ and override few simple methods.
|
||||
The library provides predefined navigators for _Fragments_ to use inside _Activity_.
|
||||
To use, just provide it with the container and _FragmentManager_ and override few simple methods.
|
||||
```java
|
||||
private Navigator navigator = new SupportFragmentNavigator(
|
||||
getSupportFragmentManager(), R.id.main_container) {
|
||||
private Navigator navigator = new SupportAppNavigator(this, R.id.container) {
|
||||
@Override
|
||||
protected Intent createActivityIntent(Context context, String screenKey, Object data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Fragment createFragment(String screenKey, Object data) {
|
||||
return SampleFragment.getNewInstance((int) data);
|
||||
switch (screenKey) {
|
||||
case Screens.PROFILE_SCREEN:
|
||||
return new ProfileFragment();
|
||||
case Screens.SELECT_PHOTO_SCREEN:
|
||||
return SelectPhotoFragment.getNewInstance((int) data);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showSystemMessage(String message) {
|
||||
Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exit() {
|
||||
finish();
|
||||
protected void setupFragmentTransactionAnimation(
|
||||
Command command,
|
||||
Fragment currentFragment,
|
||||
Fragment nextFragment,
|
||||
FragmentTransaction fragmentTransaction) {
|
||||
//setup animation
|
||||
}
|
||||
};
|
||||
```
|
||||
## Sample
|
||||
To see how to add, initialize and use the library and predefined navigators check out the sample.
|
||||
|
||||

|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Participants
|
||||
+ idea and code - Konstantin Tskhovrebov (@terrakok)
|
||||
@@ -171,7 +185,10 @@ To see how to add, initialize and use the library and predefined navigators chec
|
||||
|
||||
## License
|
||||
```
|
||||
The MIT License (MIT)
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Konstantin Tskhovrebov (@terrakok)
|
||||
and Vasili Chyrvon (@Jeevuz)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -190,4 +207,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
```
|
||||
@@ -1,5 +1,9 @@
|
||||
# Cicerone
|
||||
|
||||
[](https://t.me/Cicerone_RUS)
|
||||
|
||||

|
||||
|
||||
Cicerone (_"чи-че-ро́-не"_ - устар. гид) - легкая библиотека для простой реализации навигации в андроид приложении.
|
||||
Разработана для использования в MVP архитектуре (попробуйте [Moxy](https://github.com/Arello-Mobile/Moxy)), но легко встраивается в любые решения.
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.0'
|
||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
||||
|
||||
// For the library uploading to the Bintray
|
||||
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.1'
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Fri Mar 10 17:09:31 MSK 2017
|
||||
#Sat Dec 23 00:31:04 MSK 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-all.zip
|
||||
|
||||
@@ -15,7 +15,7 @@ ext {
|
||||
bintrayName = 'cicerone'
|
||||
publishedGroupId = 'ru.terrakok.cicerone'
|
||||
artifact = 'cicerone'
|
||||
libraryVersion = '1.2.1'
|
||||
libraryVersion = '3.0.0'
|
||||
gitUrl = 'https://github.com/terrakok/Cicerone'
|
||||
allLicenses = ['MIT']
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone;
|
||||
|
||||
import ru.terrakok.cicerone.commands.Command;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 12.10.16
|
||||
*/
|
||||
|
||||
/**
|
||||
* BaseRouter is an abstract class to implement high-level navigation.
|
||||
* Extend it to add needed transition methods.
|
||||
@@ -23,11 +22,11 @@ public abstract class BaseRouter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends navigation command to {@link CommandBuffer}.
|
||||
* Sends navigation command array to {@link CommandBuffer}.
|
||||
*
|
||||
* @param command navigation command to execute
|
||||
* @param commands navigation command array to execute
|
||||
*/
|
||||
protected void executeCommand(Command command) {
|
||||
commandBuffer.executeCommand(command);
|
||||
protected void executeCommands(Command... commands) {
|
||||
commandBuffer.executeCommands(commands);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package ru.terrakok.cicerone;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 11.10.16
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone;
|
||||
|
||||
/**
|
||||
* Cicerone is the holder for other library components.
|
||||
* To use it, instantiate it using one of the {@link #create()} methods.
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone;
|
||||
|
||||
import java.util.LinkedList;
|
||||
@@ -5,25 +9,20 @@ import java.util.Queue;
|
||||
|
||||
import ru.terrakok.cicerone.commands.Command;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 12.10.16
|
||||
*/
|
||||
|
||||
/**
|
||||
* Passes navigation command to an active {@link Navigator}
|
||||
* or stores it in the pending commands queue to pass it later.
|
||||
*/
|
||||
class CommandBuffer implements NavigatorHolder {
|
||||
private Navigator navigator;
|
||||
private Queue<Command> pendingCommands = new LinkedList<>();
|
||||
private Queue<Command[]> pendingCommands = new LinkedList<>();
|
||||
|
||||
@Override
|
||||
public void setNavigator(Navigator navigator) {
|
||||
this.navigator = navigator;
|
||||
while (!pendingCommands.isEmpty()) {
|
||||
if (navigator != null) {
|
||||
executeCommand(pendingCommands.poll());
|
||||
executeCommands(pendingCommands.poll());
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
@@ -34,15 +33,15 @@ class CommandBuffer implements NavigatorHolder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes {@code command} to the {@link Navigator} if it available.
|
||||
* Passes {@code commands} to the {@link Navigator} if it available.
|
||||
* Else puts it to the pending commands queue to pass it later.
|
||||
* @param command navigation command
|
||||
* @param commands navigation command array
|
||||
*/
|
||||
public void executeCommand(Command command) {
|
||||
void executeCommands(Command[] commands) {
|
||||
if (navigator != null) {
|
||||
navigator.applyCommand(command);
|
||||
navigator.applyCommands(commands);
|
||||
} else {
|
||||
pendingCommands.add(command);
|
||||
pendingCommands.add(commands);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone;
|
||||
|
||||
import ru.terrakok.cicerone.commands.Command;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 11.10.16
|
||||
*/
|
||||
|
||||
/**
|
||||
* The low-level navigation interface.
|
||||
* Navigator is the one who actually performs any transition.
|
||||
@@ -16,7 +15,7 @@ public interface Navigator {
|
||||
/**
|
||||
* Performs transition described by the navigation command
|
||||
*
|
||||
* @param command the navigation command to apply
|
||||
* @param commands the navigation command array to apply per single transaction
|
||||
*/
|
||||
void applyCommand(Command command);
|
||||
void applyCommands(Command[] commands);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package ru.terrakok.cicerone;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 11.10.16
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone;
|
||||
|
||||
/**
|
||||
* Navigator holder interface.
|
||||
* Use it to connect a {@link Navigator} to the {@link Cicerone}.
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import ru.terrakok.cicerone.commands.Back;
|
||||
import ru.terrakok.cicerone.commands.BackTo;
|
||||
import ru.terrakok.cicerone.commands.Forward;
|
||||
import ru.terrakok.cicerone.commands.Replace;
|
||||
import ru.terrakok.cicerone.commands.SystemMessage;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 12.10.16
|
||||
*/
|
||||
import ru.terrakok.cicerone.result.ResultListener;
|
||||
|
||||
/**
|
||||
* Router is the class for high-level navigation.
|
||||
@@ -19,10 +21,49 @@ import ru.terrakok.cicerone.commands.SystemMessage;
|
||||
*/
|
||||
public class Router extends BaseRouter {
|
||||
|
||||
private HashMap<Integer, ResultListener> resultListeners = new HashMap<>();
|
||||
|
||||
public Router() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to the screen result.<br>
|
||||
* <b>Note:</b> only one listener can subscribe to a unique resultCode!<br>
|
||||
* You must call a <b>removeResultListener()</b> to avoid a memory leak.
|
||||
*
|
||||
* @param resultCode key for filter results
|
||||
* @param listener result listener
|
||||
*/
|
||||
public void setResultListener(Integer resultCode, ResultListener listener) {
|
||||
resultListeners.put(resultCode, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from the screen result.
|
||||
*
|
||||
* @param resultCode key for filter results
|
||||
*/
|
||||
public void removeResultListener(Integer resultCode) {
|
||||
resultListeners.remove(resultCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send result data to subscriber.
|
||||
*
|
||||
* @param resultCode result data key
|
||||
* @param result result data
|
||||
* @return TRUE if listener was notified and FALSE otherwise
|
||||
*/
|
||||
protected boolean sendResult(Integer resultCode, Object result) {
|
||||
ResultListener resultListener = resultListeners.get(resultCode);
|
||||
if (resultListener != null) {
|
||||
resultListener.onResult(result);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open new screen and add it to the screens chain.
|
||||
*
|
||||
@@ -39,7 +80,7 @@ public class Router extends BaseRouter {
|
||||
* @param data initialisation parameters for the new screen
|
||||
*/
|
||||
public void navigateTo(String screenKey, Object data) {
|
||||
executeCommand(new Forward(screenKey, data));
|
||||
executeCommands(new Forward(screenKey, data));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,8 +101,10 @@ public class Router extends BaseRouter {
|
||||
* @param data initialisation parameters for the new screen
|
||||
*/
|
||||
public void newScreenChain(String screenKey, Object data) {
|
||||
executeCommand(new BackTo(null));
|
||||
executeCommand(new Forward(screenKey, data));
|
||||
executeCommands(
|
||||
new BackTo(null),
|
||||
new Forward(screenKey, data)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,8 +123,10 @@ public class Router extends BaseRouter {
|
||||
* @param data initialisation parameters for the root
|
||||
*/
|
||||
public void newRootScreen(String screenKey, Object data) {
|
||||
executeCommand(new BackTo(null));
|
||||
executeCommand(new Replace(screenKey, data));
|
||||
executeCommands(
|
||||
new BackTo(null),
|
||||
new Replace(screenKey, data)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,7 +151,7 @@ public class Router extends BaseRouter {
|
||||
* @param data initialisation parameters for the new screen
|
||||
*/
|
||||
public void replaceScreen(String screenKey, Object data) {
|
||||
executeCommand(new Replace(screenKey, data));
|
||||
executeCommands(new Replace(screenKey, data));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,7 +162,7 @@ public class Router extends BaseRouter {
|
||||
* @param screenKey screen key
|
||||
*/
|
||||
public void backTo(String screenKey) {
|
||||
executeCommand(new BackTo(screenKey));
|
||||
executeCommands(new BackTo(screenKey));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,8 +170,10 @@ public class Router extends BaseRouter {
|
||||
* It's mostly used to finish the application or close a supplementary navigation chain.
|
||||
*/
|
||||
public void finishChain() {
|
||||
executeCommand(new BackTo(null));
|
||||
executeCommand(new Back());
|
||||
executeCommands(
|
||||
new BackTo(null),
|
||||
new Back()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,7 +182,18 @@ public class Router extends BaseRouter {
|
||||
* the processing of the {@link Back} command in a {@link Navigator} implementation.
|
||||
*/
|
||||
public void exit() {
|
||||
executeCommand(new Back());
|
||||
executeCommands(new Back());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return to the previous screen in the chain and send result data.
|
||||
*
|
||||
* @param resultCode result data key
|
||||
* @param result result data
|
||||
*/
|
||||
public void exitWithResult(Integer resultCode, Object result) {
|
||||
exit();
|
||||
sendResult(resultCode, result);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,8 +202,10 @@ public class Router extends BaseRouter {
|
||||
* @param message message to show
|
||||
*/
|
||||
public void exitWithMessage(String message) {
|
||||
executeCommand(new Back());
|
||||
executeCommand(new SystemMessage(message));
|
||||
executeCommands(
|
||||
new Back(),
|
||||
new SystemMessage(message)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,6 +214,6 @@ public class Router extends BaseRouter {
|
||||
* @param message message to show
|
||||
*/
|
||||
public void showSystemMessage(String message) {
|
||||
executeCommand(new SystemMessage(message));
|
||||
executeCommands(new SystemMessage(message));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
/*
|
||||
* Created by Vasili Chyrvon (vasili.chyrvon@gmail.com)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone.android;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import ru.terrakok.cicerone.commands.BackTo;
|
||||
@@ -17,8 +23,6 @@ import ru.terrakok.cicerone.commands.Replace;
|
||||
* This navigator DOESN'T provide full featured Activity navigation,
|
||||
* but can ease Activity start or replace from current navigator.
|
||||
* </p>
|
||||
*
|
||||
* @author Vasili Chyrvon (vasili.chyrvon@gmail.com)
|
||||
*/
|
||||
public abstract class AppNavigator extends FragmentNavigator {
|
||||
|
||||
@@ -34,32 +38,61 @@ public abstract class AppNavigator extends FragmentNavigator {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to create option for start activity
|
||||
*
|
||||
* @param command current navigation command. Will be only {@link Forward} or {@link Replace}
|
||||
* @param activityIntent activity intent
|
||||
* @return transition options
|
||||
*/
|
||||
protected Bundle createStartActivityOptions(Command command, Intent activityIntent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyCommand(Command command) {
|
||||
if (command instanceof Forward) {
|
||||
Forward forward = (Forward) command;
|
||||
Intent activityIntent = createActivityIntent(forward.getScreenKey(), forward.getTransitionData());
|
||||
protected void forward(Forward command) {
|
||||
Intent activityIntent = createActivityIntent(activity, command.getScreenKey(), command.getTransitionData());
|
||||
|
||||
// Start activity
|
||||
if (activityIntent != null) {
|
||||
activity.startActivity(activityIntent);
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (command instanceof Replace) {
|
||||
Replace replace = (Replace) command;
|
||||
Intent activityIntent = createActivityIntent(replace.getScreenKey(), replace.getTransitionData());
|
||||
|
||||
// Replace activity
|
||||
if (activityIntent != null) {
|
||||
activity.startActivity(activityIntent);
|
||||
activity.finish();
|
||||
return;
|
||||
}
|
||||
// Start activity
|
||||
if (activityIntent != null) {
|
||||
Bundle options = createStartActivityOptions(command, activityIntent);
|
||||
checkAndStartActivity(command.getScreenKey(), activityIntent, options);
|
||||
} else {
|
||||
super.forward(command);
|
||||
}
|
||||
}
|
||||
|
||||
// Use default fragments navigation
|
||||
super.applyCommand(command);
|
||||
@Override
|
||||
protected void replace(Replace command) {
|
||||
Intent activityIntent = createActivityIntent(activity, command.getScreenKey(), command.getTransitionData());
|
||||
|
||||
// Replace activity
|
||||
if (activityIntent != null) {
|
||||
Bundle options = createStartActivityOptions(command, activityIntent);
|
||||
checkAndStartActivity(command.getScreenKey(), activityIntent, options);
|
||||
activity.finish();
|
||||
} else {
|
||||
super.replace(command);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAndStartActivity(String screenKey, Intent activityIntent, Bundle options) {
|
||||
// Check if we can start activity
|
||||
if (activityIntent.resolveActivity(activity.getPackageManager()) != null) {
|
||||
activity.startActivity(activityIntent, options);
|
||||
} else {
|
||||
unexistingActivity(screenKey, activityIntent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when there is no activity to open {@code screenKey}.
|
||||
*
|
||||
* @param screenKey screen key
|
||||
* @param activityIntent intent passed to start Activity for the {@code screenKey}
|
||||
*/
|
||||
protected void unexistingActivity(String screenKey, Intent activityIntent) {
|
||||
// Do nothing by default
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,11 +101,12 @@ public abstract class AppNavigator extends FragmentNavigator {
|
||||
* <b>Warning:</b> This method does not work with {@link BackTo} command.
|
||||
* </p>
|
||||
*
|
||||
* @param context
|
||||
* @param screenKey screen key
|
||||
* @param data initialization data, can be null
|
||||
* @return intent to start Activity for the passed screen key
|
||||
*/
|
||||
protected abstract Intent createActivityIntent(String screenKey, Object data);
|
||||
protected abstract Intent createActivityIntent(Context context, String screenKey, Object data);
|
||||
|
||||
@Override
|
||||
protected void showSystemMessage(String message) {
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone.android;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import ru.terrakok.cicerone.Navigator;
|
||||
import ru.terrakok.cicerone.commands.Back;
|
||||
@@ -11,17 +18,12 @@ import ru.terrakok.cicerone.commands.Forward;
|
||||
import ru.terrakok.cicerone.commands.Replace;
|
||||
import ru.terrakok.cicerone.commands.SystemMessage;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 11.10.16
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@link Navigator} implementation based on the fragments.
|
||||
* <p>
|
||||
* {@link BackTo} navigation command will return to the root if
|
||||
* needed screen isn't found in the screens chain.
|
||||
* To change this behavior override {@link #backToUnexisting()} method.
|
||||
* To change this behavior override {@link #backToUnexisting(String)} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* {@link Back} command will call {@link #exit()} method if current screen is the root.
|
||||
@@ -30,6 +32,7 @@ import ru.terrakok.cicerone.commands.SystemMessage;
|
||||
public abstract class FragmentNavigator implements Navigator {
|
||||
private FragmentManager fragmentManager;
|
||||
private int containerId;
|
||||
private LinkedList<String> localStackCopy;
|
||||
|
||||
/**
|
||||
* Creates FragmentNavigator.
|
||||
@@ -42,74 +45,173 @@ public abstract class FragmentNavigator implements Navigator {
|
||||
this.containerId = containerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyCommand(Command command) {
|
||||
if (command instanceof Forward) {
|
||||
Forward forward = (Forward) command;
|
||||
Fragment fragment = createFragment(forward.getScreenKey(), forward.getTransitionData());
|
||||
if (fragment == null) {
|
||||
unknownScreen(command);
|
||||
return;
|
||||
}
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.replace(containerId, fragment)
|
||||
.addToBackStack(forward.getScreenKey())
|
||||
.commit();
|
||||
} else if (command instanceof Back) {
|
||||
if (fragmentManager.getBackStackEntryCount() > 0) {
|
||||
fragmentManager.popBackStackImmediate();
|
||||
} else {
|
||||
exit();
|
||||
}
|
||||
} else if (command instanceof Replace) {
|
||||
Replace replace = (Replace) command;
|
||||
Fragment fragment = createFragment(replace.getScreenKey(), replace.getTransitionData());
|
||||
if (fragment == null) {
|
||||
unknownScreen(command);
|
||||
return;
|
||||
}
|
||||
if (fragmentManager.getBackStackEntryCount() > 0) {
|
||||
fragmentManager.popBackStackImmediate();
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.replace(containerId, fragment)
|
||||
.addToBackStack(replace.getScreenKey())
|
||||
.commit();
|
||||
} else {
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.replace(containerId, fragment)
|
||||
.commit();
|
||||
}
|
||||
} else if (command instanceof BackTo) {
|
||||
String key = ((BackTo) command).getScreenKey();
|
||||
/**
|
||||
* Override this method to setup custom fragment transaction animation.
|
||||
*
|
||||
* @param command current navigation command. Will be only {@link Forward} or {@link Replace}
|
||||
* @param currentFragment current fragment in container
|
||||
* (for {@link Replace} command it will be screen previous in new chain, NOT replaced screen)
|
||||
* @param nextFragment next screen fragment
|
||||
* @param fragmentTransaction fragment transaction
|
||||
*/
|
||||
protected void setupFragmentTransactionAnimation(Command command,
|
||||
Fragment currentFragment,
|
||||
Fragment nextFragment,
|
||||
FragmentTransaction fragmentTransaction) {
|
||||
}
|
||||
|
||||
if (key == null) {
|
||||
backToRoot();
|
||||
} else {
|
||||
boolean hasScreen = false;
|
||||
for (int i = 0; i < fragmentManager.getBackStackEntryCount(); i++) {
|
||||
if (key.equals(fragmentManager.getBackStackEntryAt(i).getName())) {
|
||||
fragmentManager.popBackStackImmediate(key, 0);
|
||||
hasScreen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasScreen) {
|
||||
backToUnexisting();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void applyCommands(Command[] commands) {
|
||||
fragmentManager.executePendingTransactions();
|
||||
|
||||
//copy stack before apply commands
|
||||
copyStackToLocal();
|
||||
|
||||
for (Command command : commands) {
|
||||
applyCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyStackToLocal() {
|
||||
localStackCopy = new LinkedList<>();
|
||||
|
||||
final int stackSize = fragmentManager.getBackStackEntryCount();
|
||||
for (int i = 0; i < stackSize; i++) {
|
||||
localStackCopy.add(fragmentManager.getBackStackEntryAt(i).getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform transition described by the navigation command
|
||||
*
|
||||
* @param command the navigation command to apply
|
||||
*/
|
||||
protected void applyCommand(Command command) {
|
||||
if (command instanceof Forward) {
|
||||
forward((Forward) command);
|
||||
} else if (command instanceof Back) {
|
||||
back();
|
||||
} else if (command instanceof Replace) {
|
||||
replace((Replace) command);
|
||||
} else if (command instanceof BackTo) {
|
||||
backTo((BackTo) command);
|
||||
} else if (command instanceof SystemMessage) {
|
||||
showSystemMessage(((SystemMessage) command).getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void backToRoot() {
|
||||
for (int i = 0; i < fragmentManager.getBackStackEntryCount(); i++) {
|
||||
fragmentManager.popBackStack();
|
||||
/**
|
||||
* Performs {@link Forward} command transition
|
||||
*/
|
||||
protected void forward(Forward command) {
|
||||
Fragment fragment = createFragment(command.getScreenKey(), command.getTransitionData());
|
||||
|
||||
if (fragment == null) {
|
||||
unknownScreen(command);
|
||||
return;
|
||||
}
|
||||
fragmentManager.executePendingTransactions();
|
||||
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
|
||||
setupFragmentTransactionAnimation(
|
||||
command,
|
||||
fragmentManager.findFragmentById(containerId),
|
||||
fragment,
|
||||
fragmentTransaction
|
||||
);
|
||||
|
||||
fragmentTransaction
|
||||
.replace(containerId, fragment)
|
||||
.addToBackStack(command.getScreenKey())
|
||||
.commit();
|
||||
localStackCopy.add(command.getScreenKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs {@link Forward} command transition
|
||||
*/
|
||||
protected void back() {
|
||||
if (localStackCopy.size() > 0) {
|
||||
fragmentManager.popBackStack();
|
||||
localStackCopy.pop();
|
||||
} else {
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs {@link Replace} command transition
|
||||
*/
|
||||
protected void replace(Replace command) {
|
||||
Fragment fragment = createFragment(command.getScreenKey(), command.getTransitionData());
|
||||
|
||||
if (fragment == null) {
|
||||
unknownScreen(command);
|
||||
return;
|
||||
}
|
||||
|
||||
if (localStackCopy.size() > 0) {
|
||||
fragmentManager.popBackStack();
|
||||
localStackCopy.pop();
|
||||
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
|
||||
setupFragmentTransactionAnimation(
|
||||
command,
|
||||
fragmentManager.findFragmentById(containerId),
|
||||
fragment,
|
||||
fragmentTransaction
|
||||
);
|
||||
|
||||
fragmentTransaction
|
||||
.replace(containerId, fragment)
|
||||
.addToBackStack(command.getScreenKey())
|
||||
.commit();
|
||||
localStackCopy.add(command.getScreenKey());
|
||||
|
||||
} else {
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
|
||||
setupFragmentTransactionAnimation(
|
||||
command,
|
||||
fragmentManager.findFragmentById(containerId),
|
||||
fragment,
|
||||
fragmentTransaction
|
||||
);
|
||||
|
||||
fragmentTransaction
|
||||
.replace(containerId, fragment)
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs {@link BackTo} command transition
|
||||
*/
|
||||
protected void backTo(BackTo command) {
|
||||
String key = command.getScreenKey();
|
||||
|
||||
if (key == null) {
|
||||
backToRoot();
|
||||
|
||||
} else {
|
||||
int index = localStackCopy.indexOf(key);
|
||||
int size = localStackCopy.size();
|
||||
|
||||
if (index != -1) {
|
||||
for (int i = 1; i < size - index; i++) {
|
||||
localStackCopy.pop();
|
||||
}
|
||||
fragmentManager.popBackStack(key, 0);
|
||||
} else {
|
||||
backToUnexisting(command.getScreenKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void backToRoot() {
|
||||
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
localStackCopy.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,9 +236,11 @@ public abstract class FragmentNavigator implements Navigator {
|
||||
protected abstract void exit();
|
||||
|
||||
/**
|
||||
* Called when we tried to back to some specific screen, but didn't found it.
|
||||
* Called when we tried to back to some specific screen (via {@link BackTo} command),
|
||||
* but didn't found it.
|
||||
* @param screenKey screen key
|
||||
*/
|
||||
protected void backToUnexisting() {
|
||||
protected void backToUnexisting(String screenKey) {
|
||||
backToRoot();
|
||||
}
|
||||
|
||||
@@ -147,4 +251,4 @@ public abstract class FragmentNavigator implements Navigator {
|
||||
protected void unknownScreen(Command command) {
|
||||
throw new RuntimeException("Can't create a screen for passed screenKey.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
/*
|
||||
* Created by Vasili Chyrvon (vasili.chyrvon@gmail.com)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone.android;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.widget.Toast;
|
||||
@@ -18,8 +24,6 @@ import ru.terrakok.cicerone.commands.Replace;
|
||||
* This navigator DOESN'T provide full featured Activity navigation,
|
||||
* but can ease Activity start or replace from current navigator.
|
||||
* </p>
|
||||
*
|
||||
* @author Vasili Chyrvon (vasili.chyrvon@gmail.com)
|
||||
*/
|
||||
public abstract class SupportAppNavigator extends SupportFragmentNavigator {
|
||||
|
||||
@@ -35,32 +39,61 @@ public abstract class SupportAppNavigator extends SupportFragmentNavigator {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to create option for start activity
|
||||
*
|
||||
* @param command current navigation command. Will be only {@link Forward} or {@link Replace}
|
||||
* @param activityIntent activity intent
|
||||
* @return transition options
|
||||
*/
|
||||
protected Bundle createStartActivityOptions(Command command, Intent activityIntent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyCommand(Command command) {
|
||||
if (command instanceof Forward) {
|
||||
Forward forward = (Forward) command;
|
||||
Intent activityIntent = createActivityIntent(forward.getScreenKey(), forward.getTransitionData());
|
||||
protected void forward(Forward command) {
|
||||
Intent activityIntent = createActivityIntent(activity, command.getScreenKey(), command.getTransitionData());
|
||||
|
||||
// Start activity
|
||||
if (activityIntent != null) {
|
||||
activity.startActivity(activityIntent);
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (command instanceof Replace) {
|
||||
Replace replace = (Replace) command;
|
||||
Intent activityIntent = createActivityIntent(replace.getScreenKey(), replace.getTransitionData());
|
||||
|
||||
// Replace activity
|
||||
if (activityIntent != null) {
|
||||
activity.startActivity(activityIntent);
|
||||
activity.finish();
|
||||
return;
|
||||
}
|
||||
// Start activity
|
||||
if (activityIntent != null) {
|
||||
Bundle options = createStartActivityOptions(command, activityIntent);
|
||||
checkAndStartActivity(command.getScreenKey(), activityIntent, options);
|
||||
} else {
|
||||
super.forward(command);
|
||||
}
|
||||
}
|
||||
|
||||
// Use default fragments navigation
|
||||
super.applyCommand(command);
|
||||
@Override
|
||||
protected void replace(Replace command) {
|
||||
Intent activityIntent = createActivityIntent(activity, command.getScreenKey(), command.getTransitionData());
|
||||
|
||||
// Replace activity
|
||||
if (activityIntent != null) {
|
||||
Bundle options = createStartActivityOptions(command, activityIntent);
|
||||
checkAndStartActivity(command.getScreenKey(), activityIntent, options);
|
||||
activity.finish();
|
||||
} else {
|
||||
super.replace(command);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAndStartActivity(String screenKey, Intent activityIntent, Bundle options) {
|
||||
// Check if we can start activity
|
||||
if (activityIntent.resolveActivity(activity.getPackageManager()) != null) {
|
||||
activity.startActivity(activityIntent, options);
|
||||
} else {
|
||||
unexistingActivity(screenKey, activityIntent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when there is no activity to open {@code screenKey}.
|
||||
*
|
||||
* @param screenKey screen key
|
||||
* @param activityIntent intent passed to start Activity for the {@code screenKey}
|
||||
*/
|
||||
protected void unexistingActivity(String screenKey, Intent activityIntent) {
|
||||
// Do nothing by default
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +106,7 @@ public abstract class SupportAppNavigator extends SupportFragmentNavigator {
|
||||
* @param data initialization data, can be null
|
||||
* @return intent to start Activity for the passed screen key
|
||||
*/
|
||||
protected abstract Intent createActivityIntent(String screenKey, Object data);
|
||||
protected abstract Intent createActivityIntent(Context context, String screenKey, Object data);
|
||||
|
||||
@Override
|
||||
protected void showSystemMessage(String message) {
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone.android;
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import ru.terrakok.cicerone.Navigator;
|
||||
import ru.terrakok.cicerone.commands.Back;
|
||||
@@ -11,17 +18,12 @@ import ru.terrakok.cicerone.commands.Forward;
|
||||
import ru.terrakok.cicerone.commands.Replace;
|
||||
import ru.terrakok.cicerone.commands.SystemMessage;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 11.10.16
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@link Navigator} implementation based on the support fragments.
|
||||
* <p>
|
||||
* {@link BackTo} navigation command will return to the root if
|
||||
* needed screen isn't found in the screens chain.
|
||||
* To change this behavior override {@link #backToUnexisting()} method.
|
||||
* To change this behavior override {@link #backToUnexisting(String)} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* {@link Back} command will call {@link #exit()} method if current screen is the root.
|
||||
@@ -30,6 +32,7 @@ import ru.terrakok.cicerone.commands.SystemMessage;
|
||||
public abstract class SupportFragmentNavigator implements Navigator {
|
||||
private FragmentManager fragmentManager;
|
||||
private int containerId;
|
||||
protected LinkedList<String> localStackCopy;
|
||||
|
||||
/**
|
||||
* Creates SupportFragmentNavigator.
|
||||
@@ -42,74 +45,173 @@ public abstract class SupportFragmentNavigator implements Navigator {
|
||||
this.containerId = containerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyCommand(Command command) {
|
||||
if (command instanceof Forward) {
|
||||
Forward forward = (Forward) command;
|
||||
Fragment fragment = createFragment(forward.getScreenKey(), forward.getTransitionData());
|
||||
if (fragment == null) {
|
||||
unknownScreen(command);
|
||||
return;
|
||||
}
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.replace(containerId, fragment)
|
||||
.addToBackStack(forward.getScreenKey())
|
||||
.commit();
|
||||
} else if (command instanceof Back) {
|
||||
if (fragmentManager.getBackStackEntryCount() > 0) {
|
||||
fragmentManager.popBackStackImmediate();
|
||||
} else {
|
||||
exit();
|
||||
}
|
||||
} else if (command instanceof Replace) {
|
||||
Replace replace = (Replace) command;
|
||||
Fragment fragment = createFragment(replace.getScreenKey(), replace.getTransitionData());
|
||||
if (fragment == null) {
|
||||
unknownScreen(command);
|
||||
return;
|
||||
}
|
||||
if (fragmentManager.getBackStackEntryCount() > 0) {
|
||||
fragmentManager.popBackStackImmediate();
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.replace(containerId, fragment)
|
||||
.addToBackStack(replace.getScreenKey())
|
||||
.commit();
|
||||
} else {
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.replace(containerId, fragment)
|
||||
.commit();
|
||||
}
|
||||
} else if (command instanceof BackTo) {
|
||||
String key = ((BackTo) command).getScreenKey();
|
||||
/**
|
||||
* Override this method to setup custom fragment transaction animation.
|
||||
*
|
||||
* @param command current navigation command. Will be only {@link Forward} or {@link Replace}
|
||||
* @param currentFragment current fragment in container
|
||||
* (for {@link Replace} command it will be screen previous in new chain, NOT replaced screen)
|
||||
* @param nextFragment next screen fragment
|
||||
* @param fragmentTransaction fragment transaction
|
||||
*/
|
||||
protected void setupFragmentTransactionAnimation(Command command,
|
||||
Fragment currentFragment,
|
||||
Fragment nextFragment,
|
||||
FragmentTransaction fragmentTransaction) {
|
||||
}
|
||||
|
||||
if (key == null) {
|
||||
backToRoot();
|
||||
} else {
|
||||
boolean hasScreen = false;
|
||||
for (int i = 0; i < fragmentManager.getBackStackEntryCount(); i++) {
|
||||
if (key.equals(fragmentManager.getBackStackEntryAt(i).getName())) {
|
||||
fragmentManager.popBackStackImmediate(key, 0);
|
||||
hasScreen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasScreen) {
|
||||
backToUnexisting();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void applyCommands(Command[] commands) {
|
||||
fragmentManager.executePendingTransactions();
|
||||
|
||||
//copy stack before apply commands
|
||||
copyStackToLocal();
|
||||
|
||||
for (Command command : commands) {
|
||||
applyCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyStackToLocal() {
|
||||
localStackCopy = new LinkedList<>();
|
||||
|
||||
final int stackSize = fragmentManager.getBackStackEntryCount();
|
||||
for (int i = 0; i < stackSize; i++) {
|
||||
localStackCopy.add(fragmentManager.getBackStackEntryAt(i).getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform transition described by the navigation command
|
||||
*
|
||||
* @param command the navigation command to apply
|
||||
*/
|
||||
protected void applyCommand(Command command) {
|
||||
if (command instanceof Forward) {
|
||||
forward((Forward) command);
|
||||
} else if (command instanceof Back) {
|
||||
back();
|
||||
} else if (command instanceof Replace) {
|
||||
replace((Replace) command);
|
||||
} else if (command instanceof BackTo) {
|
||||
backTo((BackTo) command);
|
||||
} else if (command instanceof SystemMessage) {
|
||||
showSystemMessage(((SystemMessage) command).getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void backToRoot() {
|
||||
for (int i = 0; i < fragmentManager.getBackStackEntryCount(); i++) {
|
||||
fragmentManager.popBackStack();
|
||||
/**
|
||||
* Performs {@link Forward} command transition
|
||||
*/
|
||||
protected void forward(Forward command) {
|
||||
Fragment fragment = createFragment(command.getScreenKey(), command.getTransitionData());
|
||||
|
||||
if (fragment == null) {
|
||||
unknownScreen(command);
|
||||
return;
|
||||
}
|
||||
fragmentManager.executePendingTransactions();
|
||||
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
|
||||
setupFragmentTransactionAnimation(
|
||||
command,
|
||||
fragmentManager.findFragmentById(containerId),
|
||||
fragment,
|
||||
fragmentTransaction
|
||||
);
|
||||
|
||||
fragmentTransaction
|
||||
.replace(containerId, fragment)
|
||||
.addToBackStack(command.getScreenKey())
|
||||
.commit();
|
||||
localStackCopy.add(command.getScreenKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs {@link Back} command transition
|
||||
*/
|
||||
protected void back() {
|
||||
if (localStackCopy.size() > 0) {
|
||||
fragmentManager.popBackStack();
|
||||
localStackCopy.pop();
|
||||
} else {
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs {@link Replace} command transition
|
||||
*/
|
||||
protected void replace(Replace command) {
|
||||
Fragment fragment = createFragment(command.getScreenKey(), command.getTransitionData());
|
||||
|
||||
if (fragment == null) {
|
||||
unknownScreen(command);
|
||||
return;
|
||||
}
|
||||
|
||||
if (localStackCopy.size() > 0) {
|
||||
fragmentManager.popBackStack();
|
||||
localStackCopy.pop();
|
||||
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
|
||||
setupFragmentTransactionAnimation(
|
||||
command,
|
||||
fragmentManager.findFragmentById(containerId),
|
||||
fragment,
|
||||
fragmentTransaction
|
||||
);
|
||||
|
||||
fragmentTransaction
|
||||
.replace(containerId, fragment)
|
||||
.addToBackStack(command.getScreenKey())
|
||||
.commit();
|
||||
localStackCopy.add(command.getScreenKey());
|
||||
|
||||
} else {
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
|
||||
setupFragmentTransactionAnimation(
|
||||
command,
|
||||
fragmentManager.findFragmentById(containerId),
|
||||
fragment,
|
||||
fragmentTransaction
|
||||
);
|
||||
|
||||
fragmentTransaction
|
||||
.replace(containerId, fragment)
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs {@link BackTo} command transition
|
||||
*/
|
||||
protected void backTo(BackTo command) {
|
||||
String key = command.getScreenKey();
|
||||
|
||||
if (key == null) {
|
||||
backToRoot();
|
||||
|
||||
} else {
|
||||
int index = localStackCopy.indexOf(key);
|
||||
int size = localStackCopy.size();
|
||||
|
||||
if (index != -1) {
|
||||
for (int i = 1; i < size - index; i++) {
|
||||
localStackCopy.pop();
|
||||
}
|
||||
fragmentManager.popBackStack(key, 0);
|
||||
} else {
|
||||
backToUnexisting(command.getScreenKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void backToRoot() {
|
||||
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
localStackCopy.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,9 +236,11 @@ public abstract class SupportFragmentNavigator implements Navigator {
|
||||
protected abstract void exit();
|
||||
|
||||
/**
|
||||
* Called when we tried to back to some specific screen, but didn't found it.
|
||||
* Called when we tried to back to some specific screen (via {@link BackTo} command),
|
||||
* but didn't found it.
|
||||
* @param screenKey screen key
|
||||
*/
|
||||
protected void backToUnexisting() {
|
||||
protected void backToUnexisting(String screenKey) {
|
||||
backToRoot();
|
||||
}
|
||||
|
||||
@@ -146,4 +250,4 @@ public abstract class SupportFragmentNavigator implements Navigator {
|
||||
protected void unknownScreen(Command command) {
|
||||
throw new RuntimeException("Can't create a screen for passed screenKey.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package ru.terrakok.cicerone.commands;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 11.10.16
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone.commands;
|
||||
|
||||
/**
|
||||
* Rolls back the last transition from the screens chain.
|
||||
*/
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone.commands;
|
||||
|
||||
import ru.terrakok.cicerone.Navigator;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 11.10.16
|
||||
*/
|
||||
|
||||
/**
|
||||
* Rolls back to the needed screen from the screens chain.
|
||||
* Behavior in the case when no needed screens found depends on an implementation of the {@link Navigator}.
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package ru.terrakok.cicerone.commands;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 11.10.16
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone.commands;
|
||||
|
||||
/**
|
||||
* Navigation command describes screens transition.
|
||||
* that can be processed by {@link ru.terrakok.cicerone.Navigator}.
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package ru.terrakok.cicerone.commands;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 11.10.16
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone.commands;
|
||||
|
||||
/**
|
||||
* Opens new screen.
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package ru.terrakok.cicerone.commands;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 11.10.16
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone.commands;
|
||||
|
||||
/**
|
||||
* Replaces the current screen.
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package ru.terrakok.cicerone.commands;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 11.10.16
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone.commands;
|
||||
|
||||
/**
|
||||
* Shows system message.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok)
|
||||
*/
|
||||
|
||||
package ru.terrakok.cicerone.result;
|
||||
|
||||
public interface ResultListener {
|
||||
|
||||
/**
|
||||
* Received result from screen.
|
||||
*
|
||||
* @param resultData
|
||||
*/
|
||||
void onResult(Object resultData);
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package android.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
/***
|
||||
* Created by laomo on 2016-11-21.
|
||||
@@ -11,6 +12,10 @@ public class Activity extends Context {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public void startActivity(Intent intent, Bundle options) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public FragmentManager getFragmentManager() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package android.app;
|
||||
* Created by laomo on 2016-11-21.
|
||||
*/
|
||||
public class FragmentManager {
|
||||
public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
|
||||
|
||||
public FragmentTransaction beginTransaction() {
|
||||
throw new RuntimeException("Stub!");
|
||||
@@ -17,11 +18,7 @@ public class FragmentManager {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public boolean popBackStackImmediate() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public boolean popBackStackImmediate(String name, int flags) {
|
||||
public void popBackStack(String name, int flags) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
@@ -33,6 +30,10 @@ public class FragmentManager {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public Fragment findFragmentById(int id) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public interface BackStackEntry {
|
||||
int getId();
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package android.content;
|
||||
|
||||
|
||||
public class ComponentName {
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
package android.content;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
/**
|
||||
* @author Konstantin Tskhovrebov (aka terrakok). Date: 10.03.17
|
||||
*/
|
||||
|
||||
public class Context {
|
||||
public PackageManager getPackageManager() { throw new RuntimeException("Stub!"); }
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package android.content;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tckhovrebov (aka @terrakok)
|
||||
* on 22.02.17
|
||||
*/
|
||||
|
||||
public class Intent {
|
||||
public ComponentName resolveActivity(PackageManager pm) { throw new RuntimeException("Stub!"); }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package android.content.pm;
|
||||
|
||||
|
||||
public class PackageManager {
|
||||
}
|
||||
@@ -6,6 +6,7 @@ package android.support.v4.app;
|
||||
*/
|
||||
|
||||
public class FragmentManager {
|
||||
public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
|
||||
|
||||
public FragmentTransaction beginTransaction() {
|
||||
throw new RuntimeException("Stub!");
|
||||
@@ -19,11 +20,7 @@ public class FragmentManager {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public boolean popBackStackImmediate() {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public boolean popBackStackImmediate(String name, int flags) {
|
||||
public void popBackStack(String name, int flags) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
@@ -35,6 +32,9 @@ public class FragmentManager {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public Fragment findFragmentById(int id) {
|
||||
throw new RuntimeException("Stub!");
|
||||
}
|
||||
|
||||
public interface BackStackEntry {
|
||||
int getId();
|
||||
|
||||
+9
-9
@@ -6,10 +6,10 @@ repositories {
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion '25.0.2'
|
||||
buildToolsVersion '26.0.2'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 25
|
||||
versionCode 1
|
||||
versionName "1.0.0"
|
||||
@@ -35,23 +35,23 @@ ext {
|
||||
|
||||
dependencies {
|
||||
// Support libraries
|
||||
compile "com.android.support:appcompat-v7:$supportLibraryVersion"
|
||||
compile "com.android.support:design:$supportLibraryVersion"
|
||||
implementation "com.android.support:appcompat-v7:$supportLibraryVersion"
|
||||
implementation "com.android.support:design:$supportLibraryVersion"
|
||||
|
||||
//MVP Moxy
|
||||
compile "com.arello-mobile:moxy:$moxyVersion"
|
||||
compile "com.arello-mobile:moxy-app-compat:$moxyVersion"
|
||||
provided "com.arello-mobile:moxy-compiler:$moxyVersion"
|
||||
implementation "com.arello-mobile:moxy:$moxyVersion"
|
||||
implementation "com.arello-mobile:moxy-app-compat:$moxyVersion"
|
||||
annotationProcessor "com.arello-mobile:moxy-compiler:$moxyVersion"
|
||||
|
||||
//Cicerone
|
||||
compile project(':library')
|
||||
|
||||
//DI
|
||||
compile "com.google.dagger:dagger:$daggerVersion"
|
||||
implementation "com.google.dagger:dagger:$daggerVersion"
|
||||
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
|
||||
//Bottom Navigation Bar
|
||||
compile ('com.ashokvarma.android:bottom-navigation-bar:1.3.0') {
|
||||
implementation ('com.ashokvarma.android:bottom-navigation-bar:1.3.0') {
|
||||
exclude group: "com.android.support", module: "design"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,5 +20,6 @@
|
||||
|
||||
<activity android:name=".ui.main.MainActivity"/>
|
||||
<activity android:name=".ui.bottom.BottomNavigationActivity"/>
|
||||
<activity android:name=".ui.animations.ProfileActivity"/>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -18,4 +18,7 @@ public class Screens {
|
||||
|
||||
public static final String FORWARD_SCREEN = "forward screen";
|
||||
public static final String GITHUB_SCREEN = "github screen";
|
||||
|
||||
public static final String PROFILE_SCREEN = "profile screen";
|
||||
public static final String SELECT_PHOTO_SCREEN = "select photo screen";
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ import javax.inject.Singleton;
|
||||
import dagger.Component;
|
||||
import ru.terrakok.cicerone.sample.dagger.module.LocalNavigationModule;
|
||||
import ru.terrakok.cicerone.sample.dagger.module.NavigationModule;
|
||||
import ru.terrakok.cicerone.sample.ui.animations.ProfileActivity;
|
||||
import ru.terrakok.cicerone.sample.ui.animations.photos.SelectPhotoFragment;
|
||||
import ru.terrakok.cicerone.sample.ui.animations.profile.ProfileFragment;
|
||||
import ru.terrakok.cicerone.sample.ui.bottom.BottomNavigationActivity;
|
||||
import ru.terrakok.cicerone.sample.ui.bottom.TabContainerFragment;
|
||||
import ru.terrakok.cicerone.sample.ui.main.MainActivity;
|
||||
@@ -31,4 +34,10 @@ public interface AppComponent {
|
||||
void inject(BottomNavigationActivity activity);
|
||||
|
||||
void inject(TabContainerFragment fragment);
|
||||
|
||||
void inject(ProfileFragment fragment);
|
||||
|
||||
void inject(SelectPhotoFragment fragment);
|
||||
|
||||
void inject(ProfileActivity activity);
|
||||
}
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package ru.terrakok.cicerone.sample.mvp.animation.photos;
|
||||
|
||||
import com.arellomobile.mvp.InjectViewState;
|
||||
import com.arellomobile.mvp.MvpPresenter;
|
||||
|
||||
import ru.terrakok.cicerone.Router;
|
||||
import ru.terrakok.cicerone.sample.R;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok) on 14.07.17.
|
||||
*/
|
||||
|
||||
@InjectViewState
|
||||
public class SelectPhotoPresenter extends MvpPresenter<SelectPhotoView> {
|
||||
private Router router;
|
||||
private final int RESULT_CODE;
|
||||
|
||||
public SelectPhotoPresenter(Router router, int resultCode) {
|
||||
this.router = router;
|
||||
RESULT_CODE = resultCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFirstViewAttach() {
|
||||
super.onFirstViewAttach();
|
||||
|
||||
getViewState().showPhotos(new int[] {
|
||||
R.drawable.ava_1,
|
||||
R.drawable.ava_2,
|
||||
R.drawable.ava_3,
|
||||
R.drawable.ava_4
|
||||
});
|
||||
}
|
||||
|
||||
public void onPhotoClick(int photoRes) {
|
||||
router.exitWithResult(RESULT_CODE, photoRes);
|
||||
}
|
||||
|
||||
public void onBackPressed() {
|
||||
router.exit();
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package ru.terrakok.cicerone.sample.mvp.animation.photos;
|
||||
|
||||
import com.arellomobile.mvp.MvpView;
|
||||
import com.arellomobile.mvp.viewstate.strategy.AddToEndSingleStrategy;
|
||||
import com.arellomobile.mvp.viewstate.strategy.StateStrategyType;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok) on 14.07.17.
|
||||
*/
|
||||
|
||||
@StateStrategyType(AddToEndSingleStrategy.class)
|
||||
public interface SelectPhotoView extends MvpView {
|
||||
void showPhotos(int[] resurceIds);
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package ru.terrakok.cicerone.sample.mvp.animation.profile;
|
||||
|
||||
import com.arellomobile.mvp.InjectViewState;
|
||||
import com.arellomobile.mvp.MvpPresenter;
|
||||
|
||||
import ru.terrakok.cicerone.Router;
|
||||
import ru.terrakok.cicerone.result.ResultListener;
|
||||
import ru.terrakok.cicerone.sample.Screens;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok) on 14.07.17.
|
||||
*/
|
||||
|
||||
@InjectViewState
|
||||
public class ProfilePresenter extends MvpPresenter<ProfileView> {
|
||||
private static final int PHOTO_RESULT_CODE = 42;
|
||||
|
||||
private Router router;
|
||||
private int currentPhoto;
|
||||
|
||||
public ProfilePresenter(int defaultPhoto, Router router) {
|
||||
currentPhoto = defaultPhoto;
|
||||
this.router = router;
|
||||
|
||||
router.setResultListener(PHOTO_RESULT_CODE, new ResultListener() {
|
||||
@Override
|
||||
public void onResult(Object resultData) {
|
||||
currentPhoto = (int) resultData;
|
||||
updatePhoto();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFirstViewAttach() {
|
||||
super.onFirstViewAttach();
|
||||
updatePhoto();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
router.removeResultListener(PHOTO_RESULT_CODE);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private void updatePhoto() {
|
||||
getViewState().showPhoto(currentPhoto);
|
||||
}
|
||||
|
||||
public void onPhotoClicked() {
|
||||
router.navigateTo(Screens.SELECT_PHOTO_SCREEN, PHOTO_RESULT_CODE);
|
||||
}
|
||||
|
||||
public void onBackPressed() {
|
||||
router.exit();
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package ru.terrakok.cicerone.sample.mvp.animation.profile;
|
||||
|
||||
import com.arellomobile.mvp.MvpView;
|
||||
import com.arellomobile.mvp.viewstate.strategy.AddToEndSingleStrategy;
|
||||
import com.arellomobile.mvp.viewstate.strategy.StateStrategyType;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok) on 14.07.17.
|
||||
*/
|
||||
|
||||
@StateStrategyType(AddToEndSingleStrategy.class)
|
||||
public interface ProfileView extends MvpView {
|
||||
void showPhoto(int resId);
|
||||
}
|
||||
@@ -60,6 +60,7 @@ public class SamplePresenter extends MvpPresenter<SampleView> {
|
||||
future = executorService.schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//WARNING! Navigation must be only in UI thread. this method works only for sample :)
|
||||
router.navigateTo(Screens.SAMPLE_SCREEN + (screenNumber + 1), screenNumber + 1);
|
||||
}
|
||||
}, 5, TimeUnit.SECONDS);
|
||||
|
||||
@@ -23,6 +23,10 @@ public class StartActivityPresenter extends MvpPresenter<StartActivityView> {
|
||||
router.navigateTo(Screens.BOTTOM_NAVIGATION_ACTIVITY_SCREEN);
|
||||
}
|
||||
|
||||
public void onResultWithAnimationPressed() {
|
||||
router.navigateTo(Screens.PROFILE_SCREEN);
|
||||
}
|
||||
|
||||
public void onBackPressed() {
|
||||
router.exit();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
package ru.terrakok.cicerone.sample.ui.animations;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.transition.ChangeBounds;
|
||||
import android.view.View;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import ru.terrakok.cicerone.Navigator;
|
||||
import ru.terrakok.cicerone.NavigatorHolder;
|
||||
import ru.terrakok.cicerone.android.SupportAppNavigator;
|
||||
import ru.terrakok.cicerone.commands.Command;
|
||||
import ru.terrakok.cicerone.commands.Forward;
|
||||
import ru.terrakok.cicerone.commands.Replace;
|
||||
import ru.terrakok.cicerone.sample.R;
|
||||
import ru.terrakok.cicerone.sample.SampleApplication;
|
||||
import ru.terrakok.cicerone.sample.Screens;
|
||||
import ru.terrakok.cicerone.sample.ui.animations.photos.SelectPhotoFragment;
|
||||
import ru.terrakok.cicerone.sample.ui.animations.profile.ProfileFragment;
|
||||
import ru.terrakok.cicerone.sample.ui.common.BackButtonListener;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok) on 14.07.17.
|
||||
*/
|
||||
|
||||
public class ProfileActivity extends AppCompatActivity {
|
||||
public static final String PHOTO_TRANSITION = "photo_trasition";
|
||||
|
||||
@Inject
|
||||
NavigatorHolder navigatorHolder;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
SampleApplication.INSTANCE.getAppComponent().inject(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_container);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
navigator.applyCommands(new Command[]{new Replace(Screens.PROFILE_SCREEN, null)});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResumeFragments() {
|
||||
super.onResumeFragments();
|
||||
navigatorHolder.setNavigator(navigator);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
navigatorHolder.removeNavigator();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
private Navigator navigator = new SupportAppNavigator(this, R.id.container) {
|
||||
@Override
|
||||
protected Intent createActivityIntent(Context context, String screenKey, Object data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Fragment createFragment(String screenKey, Object data) {
|
||||
switch (screenKey) {
|
||||
case Screens.PROFILE_SCREEN:
|
||||
return new ProfileFragment();
|
||||
case Screens.SELECT_PHOTO_SCREEN:
|
||||
return SelectPhotoFragment.getNewInstance((int) data);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupFragmentTransactionAnimation(Command command, Fragment currentFragment, Fragment nextFragment, FragmentTransaction fragmentTransaction) {
|
||||
if (command instanceof Forward
|
||||
&& currentFragment instanceof ProfileFragment
|
||||
&& nextFragment instanceof SelectPhotoFragment) {
|
||||
setupSharedElementForProfileToSelectPhoto(
|
||||
(ProfileFragment) currentFragment,
|
||||
(SelectPhotoFragment) nextFragment,
|
||||
fragmentTransaction
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void setupSharedElementForProfileToSelectPhoto(ProfileFragment profileFragment,
|
||||
SelectPhotoFragment selectPhotoFragment,
|
||||
FragmentTransaction fragmentTransaction) {
|
||||
ChangeBounds changeBounds = new ChangeBounds();
|
||||
selectPhotoFragment.setSharedElementEnterTransition(changeBounds);
|
||||
selectPhotoFragment.setSharedElementReturnTransition(changeBounds);
|
||||
profileFragment.setSharedElementEnterTransition(changeBounds);
|
||||
profileFragment.setSharedElementReturnTransition(changeBounds);
|
||||
|
||||
View view = profileFragment.getAvatarViewForAnimation();
|
||||
fragmentTransaction.addSharedElement(view, PHOTO_TRANSITION);
|
||||
selectPhotoFragment.setAnimationDestinationId((Integer) view.getTag());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.container);
|
||||
if (fragment != null
|
||||
&& fragment instanceof BackButtonListener
|
||||
&& ((BackButtonListener) fragment).onBackPressed()) {
|
||||
return;
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
package ru.terrakok.cicerone.sample.ui.animations.photos;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.arellomobile.mvp.MvpAppCompatFragment;
|
||||
import com.arellomobile.mvp.presenter.InjectPresenter;
|
||||
import com.arellomobile.mvp.presenter.ProvidePresenter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import ru.terrakok.cicerone.Router;
|
||||
import ru.terrakok.cicerone.sample.R;
|
||||
import ru.terrakok.cicerone.sample.SampleApplication;
|
||||
import ru.terrakok.cicerone.sample.mvp.animation.photos.SelectPhotoPresenter;
|
||||
import ru.terrakok.cicerone.sample.mvp.animation.photos.SelectPhotoView;
|
||||
import ru.terrakok.cicerone.sample.ui.animations.ProfileActivity;
|
||||
import ru.terrakok.cicerone.sample.ui.common.BackButtonListener;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok) on 14.07.17.
|
||||
*/
|
||||
|
||||
public class SelectPhotoFragment extends MvpAppCompatFragment implements SelectPhotoView, BackButtonListener {
|
||||
private static final String ARG_RESULT_CODE = "arg_result_code";
|
||||
private static final String ARG_ANIM_DESTINATION = "arg_anim_dest";
|
||||
|
||||
private ImageView photo1;
|
||||
private ImageView photo2;
|
||||
private ImageView photo3;
|
||||
private ImageView photo4;
|
||||
|
||||
@Inject
|
||||
Router router;
|
||||
|
||||
@InjectPresenter
|
||||
SelectPhotoPresenter presenter;
|
||||
|
||||
public static SelectPhotoFragment getNewInstance(int resultCode) {
|
||||
SelectPhotoFragment fragment = new SelectPhotoFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(ARG_RESULT_CODE, resultCode);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public void setAnimationDestinationId(int resId) {
|
||||
Bundle arguments = getArguments();
|
||||
arguments.putInt(ARG_ANIM_DESTINATION, resId);
|
||||
setArguments(arguments);
|
||||
}
|
||||
|
||||
private int getAnimationDestionationId() {
|
||||
return getArguments().getInt(ARG_ANIM_DESTINATION);
|
||||
}
|
||||
|
||||
@ProvidePresenter
|
||||
SelectPhotoPresenter providePresenter() {
|
||||
return new SelectPhotoPresenter(router, getArguments().getInt(ARG_RESULT_CODE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
SampleApplication.INSTANCE.getAppComponent().inject(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_select_photo, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
photo1 = (ImageView) view.findViewById(R.id.select_image_1);
|
||||
photo2 = (ImageView) view.findViewById(R.id.select_image_2);
|
||||
photo3 = (ImageView) view.findViewById(R.id.select_image_3);
|
||||
photo4 = (ImageView) view.findViewById(R.id.select_image_4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
photo1.setOnClickListener(clickListener);
|
||||
photo2.setOnClickListener(clickListener);
|
||||
photo3.setOnClickListener(clickListener);
|
||||
photo4.setOnClickListener(clickListener);
|
||||
}
|
||||
|
||||
private View.OnClickListener clickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
photo1.setTransitionName(null);
|
||||
photo2.setTransitionName(null);
|
||||
photo3.setTransitionName(null);
|
||||
photo4.setTransitionName(null);
|
||||
v.setTransitionName(ProfileActivity.PHOTO_TRANSITION);
|
||||
presenter.onPhotoClick((Integer) v.getTag());
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void showPhotos(int[] resurceIds) {
|
||||
if (resurceIds.length >= 4) {
|
||||
photo1.setImageResource(resurceIds[0]);
|
||||
photo2.setImageResource(resurceIds[1]);
|
||||
photo3.setImageResource(resurceIds[2]);
|
||||
photo4.setImageResource(resurceIds[3]);
|
||||
|
||||
photo1.setTag(resurceIds[0]);
|
||||
photo2.setTag(resurceIds[1]);
|
||||
photo3.setTag(resurceIds[2]);
|
||||
photo4.setTag(resurceIds[3]);
|
||||
|
||||
//for shared element animation
|
||||
int animRes = getAnimationDestionationId();
|
||||
photo1.setTransitionName(animRes == resurceIds[0] ? ProfileActivity.PHOTO_TRANSITION : null);
|
||||
photo2.setTransitionName(animRes == resurceIds[1] ? ProfileActivity.PHOTO_TRANSITION : null);
|
||||
photo3.setTransitionName(animRes == resurceIds[2] ? ProfileActivity.PHOTO_TRANSITION : null);
|
||||
photo4.setTransitionName(animRes == resurceIds[3] ? ProfileActivity.PHOTO_TRANSITION : null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed() {
|
||||
presenter.onBackPressed();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package ru.terrakok.cicerone.sample.ui.animations.profile;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.arellomobile.mvp.MvpAppCompatFragment;
|
||||
import com.arellomobile.mvp.presenter.InjectPresenter;
|
||||
import com.arellomobile.mvp.presenter.ProvidePresenter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import ru.terrakok.cicerone.Router;
|
||||
import ru.terrakok.cicerone.sample.R;
|
||||
import ru.terrakok.cicerone.sample.SampleApplication;
|
||||
import ru.terrakok.cicerone.sample.mvp.animation.profile.ProfilePresenter;
|
||||
import ru.terrakok.cicerone.sample.mvp.animation.profile.ProfileView;
|
||||
import ru.terrakok.cicerone.sample.ui.animations.ProfileActivity;
|
||||
import ru.terrakok.cicerone.sample.ui.common.BackButtonListener;
|
||||
|
||||
/**
|
||||
* Created by Konstantin Tskhovrebov (aka @terrakok) on 14.07.17.
|
||||
*/
|
||||
|
||||
public class ProfileFragment extends MvpAppCompatFragment implements ProfileView, BackButtonListener {
|
||||
private ImageView avatar;
|
||||
|
||||
@Inject
|
||||
Router router;
|
||||
|
||||
@InjectPresenter
|
||||
ProfilePresenter presenter;
|
||||
|
||||
@ProvidePresenter
|
||||
ProfilePresenter providePresenter() {
|
||||
return new ProfilePresenter(R.drawable.ava_1, router);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
SampleApplication.INSTANCE.getAppComponent().inject(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_profile, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
avatar = (ImageView) view.findViewById(R.id.avatar_imageView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
avatar.setTransitionName(ProfileActivity.PHOTO_TRANSITION);
|
||||
avatar.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
presenter.onPhotoClicked();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPhoto(int resId) {
|
||||
avatar.setImageResource(resId);
|
||||
|
||||
//for shared element animation
|
||||
avatar.setTag(resId);
|
||||
}
|
||||
|
||||
public View getAvatarViewForAnimation() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed() {
|
||||
presenter.onBackPressed();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -155,7 +155,11 @@ public class BottomNavigationActivity extends MvpAppCompatActivity implements Bo
|
||||
|
||||
private Navigator navigator = new Navigator() {
|
||||
@Override
|
||||
public void applyCommand(Command command) {
|
||||
public void applyCommands(Command[] commands) {
|
||||
for (Command command : commands) applyCommand(command);
|
||||
}
|
||||
|
||||
private void applyCommand(Command command) {
|
||||
if (command instanceof Back) {
|
||||
finish();
|
||||
} else if (command instanceof SystemMessage) {
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package ru.terrakok.cicerone.sample.ui.bottom;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
@@ -89,7 +90,7 @@ public class TabContainerFragment extends Fragment implements RouterProvider, Ba
|
||||
navigator = new SupportAppNavigator(getActivity(), getChildFragmentManager(), R.id.ftc_container) {
|
||||
|
||||
@Override
|
||||
protected Intent createActivityIntent(String screenKey, Object data) {
|
||||
protected Intent createActivityIntent(Context context, String screenKey, Object data) {
|
||||
if (screenKey.equals(Screens.GITHUB_SCREEN)) {
|
||||
return new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/terrakok/Cicerone"));
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import com.arellomobile.mvp.MvpAppCompatActivity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -17,10 +19,7 @@ import javax.inject.Inject;
|
||||
import ru.terrakok.cicerone.Navigator;
|
||||
import ru.terrakok.cicerone.NavigatorHolder;
|
||||
import ru.terrakok.cicerone.android.SupportFragmentNavigator;
|
||||
import ru.terrakok.cicerone.commands.Back;
|
||||
import ru.terrakok.cicerone.commands.BackTo;
|
||||
import ru.terrakok.cicerone.commands.Command;
|
||||
import ru.terrakok.cicerone.commands.Forward;
|
||||
import ru.terrakok.cicerone.commands.Replace;
|
||||
import ru.terrakok.cicerone.sample.R;
|
||||
import ru.terrakok.cicerone.sample.SampleApplication;
|
||||
@@ -58,9 +57,10 @@ public class MainActivity extends MvpAppCompatActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyCommand(Command command) {
|
||||
super.applyCommand(command);
|
||||
updateScreenNames(command);
|
||||
public void applyCommands(Command[] commands) {
|
||||
super.applyCommands(commands);
|
||||
getSupportFragmentManager().executePendingTransactions();
|
||||
printScreensScheme();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,7 +73,7 @@ public class MainActivity extends MvpAppCompatActivity {
|
||||
screensSchemeTV = (TextView) findViewById(R.id.screens_scheme);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
navigator.applyCommand(new Replace(Screens.SAMPLE_SCREEN, 1));
|
||||
navigator.applyCommands(new Command[]{new Replace(Screens.SAMPLE_SCREEN, 1)});
|
||||
} else {
|
||||
screenNames = (List<String>) savedInstanceState.getSerializable(STATE_SCREEN_NAMES);
|
||||
printScreensScheme();
|
||||
@@ -110,35 +110,22 @@ public class MainActivity extends MvpAppCompatActivity {
|
||||
outState.putSerializable(STATE_SCREEN_NAMES, (Serializable) screenNames);
|
||||
}
|
||||
|
||||
private void updateScreenNames(Command command) {
|
||||
if (command instanceof Back) {
|
||||
if (screenNames.size() > 0) {
|
||||
screenNames.remove(screenNames.size() - 1);
|
||||
}
|
||||
} else if (command instanceof Forward) {
|
||||
int i = (int) ((Forward) command).getTransitionData();
|
||||
screenNames.add(i + "");
|
||||
} else if (command instanceof Replace) {
|
||||
int i = (int) ((Replace) command).getTransitionData();
|
||||
if (screenNames.size() > 0) {
|
||||
screenNames.remove(screenNames.size() - 1);
|
||||
}
|
||||
screenNames.add(i + "");
|
||||
} else if (command instanceof BackTo) {
|
||||
screenNames = new ArrayList<>(screenNames.subList(0, getSupportFragmentManager().getBackStackEntryCount() + 1));
|
||||
}
|
||||
printScreensScheme();
|
||||
}
|
||||
|
||||
private void printScreensScheme() {
|
||||
String str = "";
|
||||
for (String name : screenNames) {
|
||||
if (!str.isEmpty()) {
|
||||
str += "➔" + name;
|
||||
} else {
|
||||
str = "[" + name + "]";
|
||||
ArrayList<Integer> keys = new ArrayList<>();
|
||||
|
||||
List<Fragment> fragments = getSupportFragmentManager().getFragments();
|
||||
for (Fragment fragment : fragments) {
|
||||
if (fragment instanceof SampleFragment) {
|
||||
keys.add(((SampleFragment) fragment).getNumber());
|
||||
}
|
||||
}
|
||||
screensSchemeTV.setText("Chain: " + str + "");
|
||||
Collections.sort(keys, new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
return o1 - o2;
|
||||
}
|
||||
});
|
||||
|
||||
screensSchemeTV.setText("Chain: " + keys.toString() + "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,10 @@ public class SampleFragment extends MvpAppCompatFragment implements SampleView,
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
return getArguments().getInt(EXTRA_NUMBER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
SampleApplication.INSTANCE.getAppComponent().inject(this);
|
||||
|
||||
@@ -25,6 +25,7 @@ import ru.terrakok.cicerone.sample.SampleApplication;
|
||||
import ru.terrakok.cicerone.sample.Screens;
|
||||
import ru.terrakok.cicerone.sample.mvp.start.StartActivityPresenter;
|
||||
import ru.terrakok.cicerone.sample.mvp.start.StartActivityView;
|
||||
import ru.terrakok.cicerone.sample.ui.animations.ProfileActivity;
|
||||
import ru.terrakok.cicerone.sample.ui.bottom.BottomNavigationActivity;
|
||||
import ru.terrakok.cicerone.sample.ui.main.MainActivity;
|
||||
|
||||
@@ -68,6 +69,12 @@ public class StartActivity extends MvpAppCompatActivity implements StartActivity
|
||||
presenter.onMultiPressed();
|
||||
}
|
||||
});
|
||||
findViewById(R.id.result_and_anim_button).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
presenter.onResultWithAnimationPressed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,9 +94,15 @@ public class StartActivity extends MvpAppCompatActivity implements StartActivity
|
||||
presenter.onBackPressed();
|
||||
}
|
||||
|
||||
//Sample fully custom navigator:
|
||||
private Navigator navigator = new Navigator() {
|
||||
|
||||
@Override
|
||||
public void applyCommand(Command command) {
|
||||
public void applyCommands(Command[] commands) {
|
||||
for (Command command : commands) applyCommand(command);
|
||||
}
|
||||
|
||||
private void applyCommand(Command command) {
|
||||
if (command instanceof Forward) {
|
||||
forward((Forward) command);
|
||||
} else if (command instanceof Replace) {
|
||||
@@ -114,6 +127,9 @@ public class StartActivity extends MvpAppCompatActivity implements StartActivity
|
||||
case Screens.BOTTOM_NAVIGATION_ACTIVITY_SCREEN:
|
||||
startActivity(new Intent(StartActivity.this, BottomNavigationActivity.class));
|
||||
break;
|
||||
case Screens.PROFILE_SCREEN:
|
||||
startActivity(new Intent(StartActivity.this, ProfileActivity.class));
|
||||
break;
|
||||
default:
|
||||
Log.e("Cicerone", "Unknown screen: " + command.getScreenKey());
|
||||
break;
|
||||
@@ -125,6 +141,7 @@ public class StartActivity extends MvpAppCompatActivity implements StartActivity
|
||||
case Screens.START_ACTIVITY_SCREEN:
|
||||
case Screens.MAIN_ACTIVITY_SCREEN:
|
||||
case Screens.BOTTOM_NAVIGATION_ACTIVITY_SCREEN:
|
||||
case Screens.PROFILE_SCREEN:
|
||||
forward(new Forward(command.getScreenKey(), command.getTransitionData()));
|
||||
finish();
|
||||
break;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 293 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 231 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 200 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 366 KiB |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
@@ -36,4 +36,11 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/multi_nav"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/result_and_anim_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/result_and_anim_nav"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/avatar_imageView"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_margin="40dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/ava_1"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:gravity="center"
|
||||
android:text="Click on image for select other photo"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/select_image_1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:scaleType="centerCrop"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/select_image_2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:scaleType="centerCrop"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/select_image_3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:scaleType="centerCrop"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/select_image_4"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:scaleType="centerCrop"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -3,6 +3,7 @@
|
||||
<string name="cicerone_description">Cicerone is a lightweight library that makes the navigation in an Android app easy.</string>
|
||||
<string name="ordinary_nav">Ordinary navigation</string>
|
||||
<string name="multi_nav">Multi navigation</string>
|
||||
<string name="result_and_anim_nav">Resulting and animation sample</string>
|
||||
|
||||
<string name="tab_android">Android</string>
|
||||
<string name="tab_bug">Bug</string>
|
||||
|
||||
Reference in New Issue
Block a user