diff --git a/library/src/androidTest/java/sample/viewmodel/inloop/eu/viewmodelsample/ApplicationTest.java b/library/src/androidTest/java/eu/inloop/androidviewviewmodel/ApplicationTest.java similarity index 86% rename from library/src/androidTest/java/sample/viewmodel/inloop/eu/viewmodelsample/ApplicationTest.java rename to library/src/androidTest/java/eu/inloop/androidviewviewmodel/ApplicationTest.java index 3844758..0b61135 100644 --- a/library/src/androidTest/java/sample/viewmodel/inloop/eu/viewmodelsample/ApplicationTest.java +++ b/library/src/androidTest/java/eu/inloop/androidviewviewmodel/ApplicationTest.java @@ -1,4 +1,4 @@ -package sample.viewmodel.inloop.eu.viewmodelsample; +package eu.inloop.androidviewviewmodel; import android.app.Application; import android.test.ApplicationTestCase; diff --git a/library/src/main/java/eu/inloop/androidviewviewmodel/TestActivity.java b/library/src/main/java/eu/inloop/androidviewviewmodel/TestActivity.java new file mode 100644 index 0000000..ea8d06a --- /dev/null +++ b/library/src/main/java/eu/inloop/androidviewviewmodel/TestActivity.java @@ -0,0 +1,55 @@ +package eu.inloop.androidviewviewmodel; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +import eu.inloop.androidviewviewmodel.viewpresenter.PresenterView; +import eu.inloop.androidviewviewmodel.viewpresenter.ViewLifecycleManager; +import eu.inloop.viewmodel.R; + +public class TestActivity extends AppCompatActivity { + + private ViewLifecycleManager viewViewModelManager = new ViewLifecycleManager(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_main); + + PresenterView view1 = (PresenterView) findViewById(R.id.test_view); + + viewViewModelManager.onPresentedViewCreated(view1); + } + + @Override + protected void onStart() { + super.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + viewViewModelManager.onPresenterViewActivated(); + } + + @Override + protected void onPause() { + super.onPause(); + viewViewModelManager.onPresenterViewDeactivated(); + } + + @Override + protected void onStop() { + super.onStop(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + boolean permanent = isFinishing(); + viewViewModelManager.onDestroy(permanent); + } + +} diff --git a/library/src/main/java/eu/inloop/androidviewviewmodel/TestView.java b/library/src/main/java/eu/inloop/androidviewviewmodel/TestView.java new file mode 100644 index 0000000..f8e20c5 --- /dev/null +++ b/library/src/main/java/eu/inloop/androidviewviewmodel/TestView.java @@ -0,0 +1,79 @@ +package eu.inloop.androidviewviewmodel; + +import android.content.Context; +import android.os.Parcelable; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.widget.TextView; + +import java.util.UUID; + +import eu.inloop.androidviewviewmodel.TestViewPresenter; +import eu.inloop.androidviewviewmodel.TestViewView; +import eu.inloop.androidviewviewmodel.viewpresenter.ViewStateHelper; + +public class TestView extends TextView implements TestViewView { + + private UUID presenterId; + private TestViewPresenter presenter; + + public TestView(Context context) { + super(context); + } + + public TestView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public TestView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public boolean hasPresenterId() { + return presenterId != null; + } + + @Nullable + @Override + public UUID getPresenterId() { + return presenterId; + } + + @Override + public void setPresenterId(UUID presenterId) { + this.presenterId = presenterId; + } + + @Override + public TestViewPresenter createPresenter() { + return new TestViewPresenter(); + } + + @Override + public void setPresenter(TestViewPresenter presenter) { + this.presenter = presenter; + } + + @Override + public TestViewPresenter getPresenter() { + return presenter; + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable state = super.onSaveInstanceState(); + return ViewStateHelper.saveState(this, state); + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + Parcelable superState = ViewStateHelper.restoreState(this, state); + super.onRestoreInstanceState(superState); + } + + @Override + public void setText(String text) { + super.setText(text); + } +} diff --git a/library/src/main/java/eu/inloop/androidviewviewmodel/TestViewPresenter.java b/library/src/main/java/eu/inloop/androidviewviewmodel/TestViewPresenter.java new file mode 100644 index 0000000..669dbf8 --- /dev/null +++ b/library/src/main/java/eu/inloop/androidviewviewmodel/TestViewPresenter.java @@ -0,0 +1,51 @@ +package eu.inloop.androidviewviewmodel; + +import android.util.Log; + +import java.util.Date; + +import eu.inloop.androidviewviewmodel.viewpresenter.Presenter; + +public class TestViewPresenter implements Presenter { + + private TestViewView mTestView; + + @Override + public boolean hasPresenterView() { + return mTestView != null; + } + + @Override + public TestViewView getPresenterView() { + return mTestView; + } + + @Override + public void setPresenterView(TestViewView presenterView) { + this.mTestView = presenterView; + } + + @Override + public void onCreate() { + Log.v("PRS", "Created"); + } + + @Override + public void onStart() { + long timestamp = System.currentTimeMillis(); + Date date = new Date(timestamp); + mTestView.setText(date.toString()); + + Log.v("PRS", "Start"); + } + + @Override + public void onStop() { + Log.v("PRS", "Stop"); + } + + @Override + public void onDestroy() { + Log.v("PRS", "Destroy"); + } +} diff --git a/library/src/main/java/eu/inloop/androidviewviewmodel/TestViewView.java b/library/src/main/java/eu/inloop/androidviewviewmodel/TestViewView.java new file mode 100644 index 0000000..14a464e --- /dev/null +++ b/library/src/main/java/eu/inloop/androidviewviewmodel/TestViewView.java @@ -0,0 +1,9 @@ +package eu.inloop.androidviewviewmodel; + +import eu.inloop.androidviewviewmodel.viewpresenter.PresenterView; + +public interface TestViewView extends PresenterView { + + void setText(String text); + +} diff --git a/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/Presenter.java b/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/Presenter.java new file mode 100644 index 0000000..5386295 --- /dev/null +++ b/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/Presenter.java @@ -0,0 +1,13 @@ +package eu.inloop.androidviewviewmodel.viewpresenter; + +public interface Presenter { + + boolean hasPresenterView(); + V getPresenterView(); + void setPresenterView(V presenterView); + + void onCreate(); + void onStart(); + void onStop(); + void onDestroy(); +} diff --git a/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/PresenterProvider.java b/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/PresenterProvider.java new file mode 100644 index 0000000..2b6784b --- /dev/null +++ b/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/PresenterProvider.java @@ -0,0 +1,33 @@ +package eu.inloop.androidviewviewmodel.viewpresenter; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class PresenterProvider { + + private static final PresenterProvider INSTANCE = new PresenterProvider(); + + public static PresenterProvider getInstance() { + return INSTANCE; + } + + private final Map presentersMap = new HashMap<>(); + + public boolean usesId(UUID id) { + return presentersMap.containsKey(id); + } + + public void storePresenter(UUID id, Presenter presenter) { + presentersMap.put(id, presenter); + } + + public T retrievePresenter(UUID id) { + return (T)presentersMap.get(id); + } + + public T removePresenter(UUID id) { + return (T)presentersMap.remove(id); + } + +} diff --git a/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/PresenterView.java b/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/PresenterView.java new file mode 100644 index 0000000..beb06e0 --- /dev/null +++ b/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/PresenterView.java @@ -0,0 +1,18 @@ +package eu.inloop.androidviewviewmodel.viewpresenter; + +import android.support.annotation.Nullable; + +import java.util.UUID; + +public interface PresenterView { + + boolean hasPresenterId(); + @Nullable + UUID getPresenterId(); + void setPresenterId(UUID presenterId); + + T createPresenter(); + void setPresenter(T presenter); + T getPresenter(); + +} diff --git a/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/ViewLifecycleManager.java b/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/ViewLifecycleManager.java new file mode 100644 index 0000000..cddc779 --- /dev/null +++ b/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/ViewLifecycleManager.java @@ -0,0 +1,77 @@ +package eu.inloop.androidviewviewmodel.viewpresenter; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class ViewLifecycleManager { + + private static PresenterProvider sPresenterProvider = PresenterProvider.getInstance(); + + private List presentersViewsList = new ArrayList<>(); + + public ViewLifecycleManager onPresentedViewCreated(PresenterView presenterView) { + presentersViewsList.add(presenterView); + return this; + } + + public void onPresenterViewActivated() { + for (PresenterView presenterView : presentersViewsList) { + if (!presenterView.hasPresenterId()) { + createPresenterForView(presenterView); + } + + UUID id = presenterView.getPresenterId(); + Presenter presenter = sPresenterProvider.retrievePresenter(id); + + presenterView.setPresenter(presenter); + presenter.setPresenterView(presenterView); + + presenter.onStart(); + } + } + + private void createPresenterForView(PresenterView presenterView) { + UUID id = generatePresenterId(); + presenterView.setPresenterId(id); + Presenter presenter = presenterView.createPresenter(); + sPresenterProvider.storePresenter(id, presenter); + + presenter.onCreate(); + } + + private UUID generatePresenterId() { + UUID id; + do { + id = UUID.randomUUID(); + } while (sPresenterProvider.usesId(id)); + + return id; + } + + public void onPresenterViewDeactivated() { + for (PresenterView presenterView : presentersViewsList) { + Presenter presenter = presenterView.getPresenter(); + presenter.onStop(); + } + } + + public void onPresenterViewDestroyed(PresenterView presenterView) { + UUID presenterId = presenterView.getPresenterId(); + Presenter presenter = sPresenterProvider.retrievePresenter(presenterId); + presenter.setPresenterView(null); + } + + public void onDestroy(boolean permanent) { + if (permanent) { + for (PresenterView presenterView : presentersViewsList) { + UUID presenterId = presenterView.getPresenterId(); + Presenter presenter = sPresenterProvider.removePresenter(presenterId); + presenter.onDestroy(); + } + } + + presentersViewsList.clear(); + } + +} diff --git a/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/ViewStateHelper.java b/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/ViewStateHelper.java new file mode 100644 index 0000000..a847ce1 --- /dev/null +++ b/library/src/main/java/eu/inloop/androidviewviewmodel/viewpresenter/ViewStateHelper.java @@ -0,0 +1,32 @@ +package eu.inloop.androidviewviewmodel.viewpresenter; + +import android.os.Bundle; +import android.os.Parcelable; + +import java.util.UUID; + +public class ViewStateHelper { + + private static final String SUPER_STATE = "superState"; + private static final String PRESENTER_ID = "presenterId"; + + public static Parcelable saveState(PresenterView presenterView, Parcelable superState) { + Bundle bundle = new Bundle(); + bundle.putParcelable(SUPER_STATE, superState); + + UUID presenterId = presenterView.getPresenterId(); + bundle.putSerializable(PRESENTER_ID, presenterId); + + return bundle; + } + + public static Parcelable restoreState(PresenterView presenterView, Parcelable state) { + Bundle bundle = (Bundle) state; + + UUID presenterId = (UUID) bundle.getSerializable(PRESENTER_ID); + presenterView.setPresenterId(presenterId); + + return bundle.getParcelable(SUPER_STATE); + } + +} diff --git a/library/src/main/res/layout/activity_main.xml b/library/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..9cab793 --- /dev/null +++ b/library/src/main/res/layout/activity_main.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/library/src/main/res/menu/menu_main.xml b/library/src/main/res/menu/menu_main.xml new file mode 100644 index 0000000..3b27d8e --- /dev/null +++ b/library/src/main/res/menu/menu_main.xml @@ -0,0 +1,10 @@ + + + diff --git a/library/src/main/res/mipmap-hdpi/ic_launcher.png b/library/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..cde69bc Binary files /dev/null and b/library/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/library/src/main/res/mipmap-mdpi/ic_launcher.png b/library/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c133a0c Binary files /dev/null and b/library/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/library/src/main/res/mipmap-xhdpi/ic_launcher.png b/library/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..bfa42f0 Binary files /dev/null and b/library/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/library/src/main/res/mipmap-xxhdpi/ic_launcher.png b/library/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..324e72c Binary files /dev/null and b/library/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/library/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/library/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..aee44e1 Binary files /dev/null and b/library/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/library/src/main/res/values-v21/styles.xml b/library/src/main/res/values-v21/styles.xml new file mode 100644 index 0000000..251fb9f --- /dev/null +++ b/library/src/main/res/values-v21/styles.xml @@ -0,0 +1,9 @@ +> + + + diff --git a/library/src/main/res/values-w820dp/dimens.xml b/library/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 0000000..63fc816 --- /dev/null +++ b/library/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/library/src/main/res/values/colors.xml b/library/src/main/res/values/colors.xml new file mode 100644 index 0000000..3ab3e9c --- /dev/null +++ b/library/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #3F51B5 + #303F9F + #FF4081 + diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml new file mode 100644 index 0000000..812cb7b --- /dev/null +++ b/library/src/main/res/values/dimens.xml @@ -0,0 +1,6 @@ + + + 16dp + 16dp + 16dp + diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml new file mode 100644 index 0000000..8fbf652 --- /dev/null +++ b/library/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + AndroidViewViewModel + Settings + diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml new file mode 100644 index 0000000..177cefc --- /dev/null +++ b/library/src/main/res/values/styles.xml @@ -0,0 +1,20 @@ + + + + + + + +