12 Commits

Author SHA1 Message Date
terrakok 427592e309 Merge branch 'develop' 2016-11-22 18:52:45 +03:00
terrakok b3e32c154f Merge pull request #13 from Jeevuz/develop
Upgrade to version 1.1
2016-11-22 19:51:08 +04:00
Vasili Chyrvon 69feb03db6 Upgrade to version 1.1 2016-11-22 18:39:31 +03:00
terrakok 1505ba87af Merge pull request #12 from Jeevuz/develop
Bages and new How to add part
2016-11-22 19:14:35 +04:00
Vasili Chyrvon 3dfb107a21 Changed russian readme 2016-11-22 18:10:38 +03:00
Vasili Chyrvon 458d9b053e Added badges 2016-11-22 18:04:58 +03:00
Vasili Chyrvon 93cecdee1d Published on jcenter. 2016-11-22 17:25:05 +03:00
terrakok 457c70e026 Merge pull request #10 from laomo/develop
Add app stub and remove android dependency
2016-11-22 12:38:39 +04:00
laomo e88b08d8ce Add app stub and remove android dependency 2016-11-22 16:04:49 +08:00
terrakok 4e896d3631 added the startup screen to show the transitions between Activities 2016-11-21 23:28:04 +03:00
terrakok a5404b0939 Merge pull request #7 from Jeevuz/patch-1
Update README.md
2016-11-20 08:12:40 +04:00
Vasili Chyrvon 4d096351cc Update README.md 2016-11-20 01:35:19 +03:00
21 changed files with 336 additions and 54 deletions
+32 -34
View File
@@ -1,31 +1,28 @@
# Cicerone
[![Bintray](https://img.shields.io/bintray/v/terrakok/terramaven/cicerone.svg)](https://bintray.com/terrakok/terramaven/cicerone)
[![License](https://img.shields.io/badge/license-APACHE2-blue.svg)](http://choosealicense.com/licenses/apache-2.0/)
Cicerone (a guide who gives information to sightseers) is a lightweight library that makes the navigation in an Android app easy.
It designed for using with MVP architecture (try [Moxy](https://github.com/Arello-Mobile/Moxy)), but it fits to work in other ways.
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.
## Main advantages
+ not tied to Fragments
+ not framework
+ is not tied to Fragments
+ not a framework
+ short navigation calls (no builders)
+ lifecycle-safely!
+ functional is simple to extent
+ adapted for Unit Testing
+ lifecycle-safe!
+ functionality is simple to extend
+ suitable for Unit Testing
## How to connect?
Add the following lines to build.gradle:
## How to add
Add the dependency in your build.gradle:
```groovy
repositories {
maven {
url 'https://dl.bintray.com/terrakok/terramaven/'
}
}
dependencies {
//Cicerone
compile 'ru.terrakok.cicerone:cicerone:1.0'
compile 'ru.terrakok.cicerone:cicerone:1.1'
}
```
And initialise library for example with application:
Initialize the library (for example in your Application class):
```java
public class SampleApplication extends MvpApplication {
public static SampleApplication INSTANCE;
@@ -76,10 +73,11 @@ public class SamplePresenter extends Presenter<SampleView> {
}
```
Router converts the navigation calls to Comand sets and sends them to CommandBuffer.
Command Buffer checks whether there _"active"_ Navigator.
If yes, it caused the necessary commands for the requested transfer.
If not, the command added to the queue, which will be applied as soon as _"active"_ Navigator.
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.
```java
protected void executeCommand(Command command) {
@@ -91,8 +89,8 @@ protected void executeCommand(Command command) {
}
```
Navigator - implements the navigation commands, e.g. anonymous class inside the Activity.
Activity provides Navigator for CommandBuffer in _onResume_ and remove 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_.
```java
@Override
@@ -110,27 +108,27 @@ protected void onPause() {
private Navigator navigator = new Navigator() {
@Override
public void applyCommand(Command command) {
//implements commands logic
//implement commands logic
}
};
```
## Navigation commands
These command set will fulfill needs of the most application. But if you require more - supply your own!
This commands set will fulfill the needs of the most applications. But if you need something special - just add it!
+ Forward - Opens new screen
![](https://habrastorage.org/files/862/77e/b20/86277eb20b574dae8307ac4f64b0f090.png)
+ Back - Rolls back the last transition from the screens chain
+ Back - Rolls back the last transition
![](https://habrastorage.org/files/059/b63/2d3/059b632d3a7c4515a534b9e5e881c8f0.png)
+ BackTo - Rolls back to the needed screen from the screens chain
+ BackTo - Rolls back to the needed screen in the screens chain
![](https://habrastorage.org/files/a45/4f4/c34/a454f4c340764632ad0669014ad5550d.png)
+ Replace - Replaces the current screen
![](https://habrastorage.org/files/4ae/95c/fee/4ae95cfee4c04f038ad17d358ab08d07.png)
+ SystemMessage - Shows system message (Alert, Toast, Snack etc)
+ SystemMessage - Shows system message (Alert, Toast, Snack, etc.)
![](https://habrastorage.org/files/6e7/1a6/4ed/6e71a64edec04079bf33faa7ab39606f.png)
## Ready navigators
The library provides ready navigators for _Activity_.
To use them, just give the container and pass _FragmentManager_.
## 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.
```java
private Navigator navigator = new SupportFragmentNavigator(
getSupportFragmentManager(), R.id.main_container) {
@@ -151,13 +149,13 @@ private Navigator navigator = new SupportFragmentNavigator(
};
```
## Sample
Library usage examples, ready navigators and more can be found in the sample application.
To see how to add, initialize and use the library and predefined navigators check out the sample.
![](https://habrastorage.org/files/16d/2ee/6e3/16d2ee6e33a0428eb4f0dcab8ce6b294.gif)
## Participants
+ idea and realization - Konstantin Tckhovrebov (@terrakok)
+ architectural advice, documentation and publication - Vasily Chirvon (@Jeevuz)
+ idea and code - Konstantin Tskhovrebov (@terrakok)
+ architecture advice, documentation and publication - Vasili Chyrvon (@Jeevuz)
## License
+2 -8
View File
@@ -12,17 +12,11 @@ Cicerone (_"чи-че-ро́-не"_ - устар. гид) - легкая биб
+ приспособлена для Unit тестов
## Как подключить?
Добавьте в build.gradle следующие строки:
Добавьте в build.gradle зависимость:
```groovy
repositories {
maven {
url 'https://dl.bintray.com/terrakok/terramaven/'
}
}
dependencies {
//Cicerone
compile 'ru.terrakok.cicerone:cicerone:1.0'
compile 'ru.terrakok.cicerone:cicerone:1.1'
}
```
И инициализируйте библиотеку, например, так:
+2 -3
View File
@@ -6,8 +6,7 @@ sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
dependencies {
compileOnly 'com.google.android:android:4.0.1.2'
compileOnly project(':stub-appcompat')
compileOnly project(':stub-android')
}
ext {
@@ -16,7 +15,7 @@ ext {
bintrayName = 'cicerone'
publishedGroupId = 'ru.terrakok.cicerone'
artifact = 'cicerone'
libraryVersion = '1.0'
libraryVersion = '1.1'
gitUrl = 'https://github.com/terrakok/Cicerone'
allLicenses = ['Apache-2.0']
}
@@ -2,7 +2,3 @@ apply plugin: 'java'
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
dependencies {
compileOnly 'com.google.android:android:4.0.1.2'
}
@@ -0,0 +1,7 @@
package android.app;
/***
* Created by laomo on 2016-11-21.
*/
public class Activity {
}
@@ -0,0 +1,36 @@
package android.app;
import android.os.Bundle;
/***
* Created by laomo on 2016-11-21.
*/
public class Fragment {
public void onCreate(Bundle savedInstanceState) {
throw new RuntimeException("Stub!");
}
public void onStart() {
throw new RuntimeException("Stub!");
}
public void onDestroyView() {
throw new RuntimeException("Stub!");
}
public void onDestroy() {
throw new RuntimeException("Stub!");
}
public void onSaveInstanceState(Bundle outState) {
throw new RuntimeException("Stub!");
}
final public boolean isRemoving() {
throw new RuntimeException("Stub!");
}
public final Activity getActivity() {
throw new RuntimeException("Stub!");
}
}
@@ -0,0 +1,41 @@
package android.app;
/***
* Created by laomo on 2016-11-21.
*/
public class FragmentManager {
public FragmentTransaction beginTransaction() {
throw new RuntimeException("Stub!");
}
public boolean executePendingTransactions() {
throw new RuntimeException("Stub!");
}
public void popBackStack() {
throw new RuntimeException("Stub!");
}
public boolean popBackStackImmediate() {
throw new RuntimeException("Stub!");
}
public boolean popBackStackImmediate(String name, int flags) {
throw new RuntimeException("Stub!");
}
public int getBackStackEntryCount() {
throw new RuntimeException("Stub!");
}
public BackStackEntry getBackStackEntryAt(int index) {
throw new RuntimeException("Stub!");
}
public interface BackStackEntry {
int getId();
String getName();
}
}
@@ -0,0 +1,18 @@
package android.app;
/***
* Created by laomo on 2016-11-21.
*/
public class FragmentTransaction {
public FragmentTransaction replace(int containerViewId, Fragment fragment) {
throw new RuntimeException("Stub!");
}
public FragmentTransaction addToBackStack(String name) {
throw new RuntimeException("Stub!");
}
public int commit() {
throw new RuntimeException("Stub!");
}
}
@@ -0,0 +1,7 @@
package android.os;
/***
* Created by laomo on 2016-11-21.
*/
public class Bundle {
}
+5 -3
View File
@@ -7,15 +7,17 @@
android:name=".SampleApplication"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:theme="@style/AppTheme"
android:label="@string/app_name">
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name=".ui.main.MainActivity">
android:name=".ui.start.StartActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".ui.main.MainActivity"/>
</application>
</manifest>
@@ -7,4 +7,6 @@ package ru.terrakok.cicerone.sample;
public class Screens {
public static final String SAMPLE_SCREEN = "sample_screen_";
public static final String START_ACTIVITY_SCREEN = "start activity screen";
public static final String MAIN_ACTIVITY_SCREEN = "main activity screen";
}
@@ -0,0 +1,26 @@
package ru.terrakok.cicerone.sample.mvp.start;
import com.arellomobile.mvp.MvpPresenter;
import ru.terrakok.cicerone.Router;
import ru.terrakok.cicerone.sample.SampleApplication;
import ru.terrakok.cicerone.sample.Screens;
/**
* Created by terrakok 21.11.16
*/
public class StartActivityPresenter extends MvpPresenter<StartActivityView> {
private Router router;
public StartActivityPresenter() {
router = SampleApplication.INSTANCE.getRouter();
}
public void onNextPressed() {
router.replaceScreen(Screens.MAIN_ACTIVITY_SCREEN);
}
public void onBackPressed() {
router.exit();
}
}
@@ -0,0 +1,9 @@
package ru.terrakok.cicerone.sample.mvp.start;
import com.arellomobile.mvp.MvpView;
/**
* Created by terrakok 21.11.16
*/
public interface StartActivityView extends MvpView {
}
@@ -0,0 +1,113 @@
package ru.terrakok.cicerone.sample.ui.start;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.arellomobile.mvp.MvpAppCompatActivity;
import com.arellomobile.mvp.presenter.InjectPresenter;
import ru.terrakok.cicerone.Navigator;
import ru.terrakok.cicerone.commands.Back;
import ru.terrakok.cicerone.commands.Command;
import ru.terrakok.cicerone.commands.Forward;
import ru.terrakok.cicerone.commands.Replace;
import ru.terrakok.cicerone.commands.SystemMessage;
import ru.terrakok.cicerone.sample.R;
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.main.MainActivity;
/**
* Created by terrakok 21.11.16
*/
public class StartActivity extends MvpAppCompatActivity implements StartActivityView {
@InjectPresenter
StartActivityPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
initViews();
}
private void initViews() {
findViewById(R.id.lets_go_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
presenter.onNextPressed();
}
});
}
@Override
protected void onResume() {
super.onResume();
SampleApplication.INSTANCE.getNavigatorHolder().setNavigator(navigator);
}
@Override
protected void onPause() {
SampleApplication.INSTANCE.getNavigatorHolder().removeNavigator();
super.onPause();
}
@Override
public void onBackPressed() {
presenter.onBackPressed();
}
private Navigator navigator = new Navigator() {
@Override
public void applyCommand(Command command) {
if (command instanceof Forward) {
forward((Forward) command);
} else if (command instanceof Replace) {
replace((Replace) command);
} else if (command instanceof Back) {
back();
} else if (command instanceof SystemMessage) {
Toast.makeText(StartActivity.this, ((SystemMessage) command).getMessage(), Toast.LENGTH_SHORT).show();
} else {
Log.e("Cicerone", "Illegal command for this screen: " + command.getClass().getSimpleName());
}
}
private void forward(Forward command) {
switch (command.getScreenKey()) {
case Screens.START_ACTIVITY_SCREEN:
startActivity(new Intent(StartActivity.this, StartActivity.class));
break;
case Screens.MAIN_ACTIVITY_SCREEN:
startActivity(new Intent(StartActivity.this, MainActivity.class));
break;
default:
Log.e("Cicerone", "Unknown screen: " + command.getScreenKey());
break;
}
}
private void replace(Replace command) {
switch (command.getScreenKey()) {
case Screens.START_ACTIVITY_SCREEN:
case Screens.MAIN_ACTIVITY_SCREEN:
forward(new Forward(command.getScreenKey(), command.getTransitionData()));
finish();
break;
default:
Log.e("Cicerone", "Unknown screen: " + command.getScreenKey());
break;
}
}
private void back() {
finish();
}
};
}
@@ -0,0 +1,32 @@
<?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">
<android.support.v4.widget.Space
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="16dp"
android:text="@string/cicerone_description"
android:textSize="18sp"/>
<android.support.v4.widget.Space
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
android:id="@+id/lets_go_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="@string/lets_go"/>
</LinearLayout>
+2
View File
@@ -1,3 +1,5 @@
<resources>
<string name="app_name">Cicerone Sample</string>
<string name="cicerone_description">Cicerone is a lightweight library that makes the navigation in an Android app easy.</string>
<string name="lets_go">Lets Go!</string>
</resources>
+2 -2
View File
@@ -1,2 +1,2 @@
include ':library', ':sample', ':stub-appcompat'
project(':stub-appcompat').projectDir = new File('library/stub-appcompat')
include ':library', ':sample', ':stub-android'
project(':stub-android').projectDir = new File('library/stub-android')