Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor presentation MVP presenters and views #214

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import com.fernandocejas.android10.sample.domain.interactor.GetUserDetails;
import com.fernandocejas.android10.sample.domain.interactor.GetUserDetails.Params;
import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper;
import com.fernandocejas.android10.sample.presentation.presenter.UserDetailsPresenter;
import com.fernandocejas.android10.sample.presentation.view.UserDetailsView;
import com.fernandocejas.android10.sample.presentation.mvp.presenter.UserDetailsPresenter;
import com.fernandocejas.android10.sample.presentation.mvp.view.UserDetailsView;
import io.reactivex.observers.DisposableObserver;
import org.junit.Before;
import org.junit.Test;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import android.content.Context;
import com.fernandocejas.android10.sample.domain.interactor.GetUserList;
import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper;
import com.fernandocejas.android10.sample.presentation.presenter.UserListPresenter;
import com.fernandocejas.android10.sample.presentation.view.UserListView;
import com.fernandocejas.android10.sample.presentation.mvp.presenter.UserListPresenter;
import com.fernandocejas.android10.sample.presentation.mvp.view.UserListView;
import io.reactivex.observers.DisposableObserver;
import org.junit.Before;
import org.junit.Test;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
import com.fernandocejas.android10.sample.presentation.R;
import com.fernandocejas.android10.sample.presentation.view.activity.UserDetailsActivity;
import com.fernandocejas.android10.sample.presentation.ui.activity.UserDetailsActivity;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
import com.fernandocejas.android10.sample.presentation.R;
import com.fernandocejas.android10.sample.presentation.view.activity.UserListActivity;
import com.fernandocejas.android10.sample.presentation.ui.activity.UserListActivity;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
Expand Down
6 changes: 3 additions & 3 deletions presentation/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
android:theme="@style/AppTheme">

<activity
android:name=".view.activity.MainActivity"
android:name=".ui.activity.MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand All @@ -22,12 +22,12 @@
</activity>

<activity
android:name=".view.activity.UserListActivity"
android:name=".ui.activity.UserListActivity"
android:label="@string/activity_title_user_list">
</activity>

<activity
android:name=".view.activity.UserDetailsActivity"
android:name=".ui.activity.UserDetailsActivity"
android:label="@string/activity_title_user_details">
</activity>
</application>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
import com.fernandocejas.android10.sample.presentation.internal.di.modules.ApplicationModule;
import com.fernandocejas.android10.sample.presentation.view.activity.BaseActivity;
import com.fernandocejas.android10.sample.presentation.ui.activity.BaseActivity;
import dagger.Component;
import javax.inject.Singleton;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import com.fernandocejas.android10.sample.presentation.internal.di.PerActivity;
import com.fernandocejas.android10.sample.presentation.internal.di.modules.ActivityModule;
import com.fernandocejas.android10.sample.presentation.internal.di.modules.UserModule;
import com.fernandocejas.android10.sample.presentation.view.fragment.UserDetailsFragment;
import com.fernandocejas.android10.sample.presentation.view.fragment.UserListFragment;
import com.fernandocejas.android10.sample.presentation.ui.fragment.UserDetailsFragment;
import com.fernandocejas.android10.sample.presentation.ui.fragment.UserListFragment;
import dagger.Component;

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.fernandocejas.android10.sample.presentation.mvp.presenter;

import android.support.annotation.NonNull;

import com.fernandocejas.android10.sample.presentation.mvp.view.View;

public abstract class BasePresenter<VIEW extends View> implements Presenter<VIEW> {

protected VIEW view;

@Override
public void attachView(@NonNull VIEW view) {
this.view = view;
onViewAttached();
}

@Override
public void detachView() {
onViewDetached();
this.view = null;
}

@Override
public void resume() {
}

@Override
public void pause() {
}

public abstract void refreshData();

protected void onViewAttached() {
}

protected void onViewDetached() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright (C) 2015 Fernando Cejas Open Source Project
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fernandocejas.android10.sample.presentation.mvp.presenter;

import com.fernandocejas.android10.sample.presentation.mvp.view.View;

/**
* Interface representing a Presenter in a model view presenter (MVP) pattern.
*/
public interface Presenter<VIEW extends View> {

//TODO docs
void attachView(VIEW view);

//TODO docs
void detachView();

/**
* Method that control the lifecycle of the view. It should be called in the view's
* (Activity or Fragment) onResume() method.
*/
void resume();

/**
* Method that control the lifecycle of the view. It should be called in the view's
* (Activity or Fragment) onPause() method.
*/
void pause();


/**
* Method that control the lifecycle of the view. It should be called in the view's
* (Activity or Fragment) onDestroy() method.
*/
//void destroy();


//TODO docs
void refreshData();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* Copyright (C) 2015 Fernando Cejas Open Source Project
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fernandocejas.android10.sample.presentation.mvp.presenter;

import com.fernandocejas.android10.sample.domain.User;
import com.fernandocejas.android10.sample.domain.exception.DefaultErrorBundle;
import com.fernandocejas.android10.sample.domain.exception.ErrorBundle;
import com.fernandocejas.android10.sample.domain.interactor.DefaultObserver;
import com.fernandocejas.android10.sample.domain.interactor.GetUserDetails;
import com.fernandocejas.android10.sample.domain.interactor.GetUserDetails.Params;
import com.fernandocejas.android10.sample.presentation.internal.di.PerActivity;
import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper;
import com.fernandocejas.android10.sample.presentation.model.UserModel;
import com.fernandocejas.android10.sample.presentation.mvp.view.UserDetailsView;

import javax.inject.Inject;

/**
* {@link Presenter} that controls communication between views and models of the presentation
* layer.
*/
@PerActivity
public class UserDetailsPresenter extends BasePresenter<UserDetailsView> {

private final GetUserDetails getUserDetailsUseCase;
private final UserModelDataMapper userModelDataMapper;

private int userId;

@Inject
public UserDetailsPresenter(GetUserDetails getUserDetailsUseCase,
UserModelDataMapper userModelDataMapper) {
this.getUserDetailsUseCase = getUserDetailsUseCase;
this.userModelDataMapper = userModelDataMapper;
}

@Override
protected void onViewAttached() {
super.onViewAttached();
refreshData();
}

@Override
protected void onViewDetached() {
super.onViewDetached();
this.getUserDetailsUseCase.dispose();
}

@Override
public void refreshData() {
view.hideRetry();
view.showLoading();
this.getUserDetails(userId);
}

//TODO Ihor Vitruk: consider to use lombok library @Setter annotation
public void setUserId(int userId) {
this.userId = userId;
}

private void getUserDetails(int userId) {
this.getUserDetailsUseCase.execute(new UserDetailsObserver(), Params.forUser(userId));
}


private void showErrorMessage(ErrorBundle errorBundle) {
view.showError(errorBundle);
}

private void showUserDetailsInView(User user) {
final UserModel userModel = this.userModelDataMapper.transform(user);
view.renderUser(userModel);
}

private final class UserDetailsObserver extends DefaultObserver<User> {

@Override
public void onComplete() {
view.hideLoading();
}

@Override
public void onError(Throwable e) {
view.hideLoading();
view.hideRetry();
UserDetailsPresenter.this.showErrorMessage(new DefaultErrorBundle((Exception) e));
}

@Override
public void onNext(User user) {
UserDetailsPresenter.this.showUserDetailsInView(user);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* Copyright (C) 2015 Fernando Cejas Open Source Project
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fernandocejas.android10.sample.presentation.mvp.presenter;

import com.fernandocejas.android10.sample.domain.User;
import com.fernandocejas.android10.sample.domain.exception.DefaultErrorBundle;
import com.fernandocejas.android10.sample.domain.interactor.DefaultObserver;
import com.fernandocejas.android10.sample.domain.interactor.GetUserList;
import com.fernandocejas.android10.sample.presentation.internal.di.PerActivity;
import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper;
import com.fernandocejas.android10.sample.presentation.model.UserModel;
import com.fernandocejas.android10.sample.presentation.mvp.view.UserListView;

import java.util.Collection;
import java.util.List;

import javax.inject.Inject;

/**
* {@link Presenter} that controls communication between views and models of the presentation
* layer.
*/
@PerActivity
public class UserListPresenter extends BasePresenter<UserListView> {

private final GetUserList getUserListUseCase;
private final UserModelDataMapper userModelDataMapper;

@Inject
public UserListPresenter(GetUserList getUserListUserCase,
UserModelDataMapper userModelDataMapper) {
this.getUserListUseCase = getUserListUserCase;
this.userModelDataMapper = userModelDataMapper;
}

@Override
protected void onViewAttached() {
super.onViewAttached();
refreshData();
}

@Override
protected void onViewDetached() {
super.onViewDetached();
this.getUserListUseCase.dispose();
}

@Override
public void refreshData() {
this.loadUserList();
}

public void onUserClicked(UserModel userModel) {
view.viewUser(userModel);
}

/**
* Loads all users.
*/
private void loadUserList() {
view.hideRetry();
view.showLoading();
this.getUserList();
}

private void showUsersCollectionInView(Collection<User> usersCollection) {
final Collection<UserModel> userModelsCollection =
this.userModelDataMapper.transform(usersCollection);
view.renderUserList(userModelsCollection);
}

private void getUserList() {
this.getUserListUseCase.execute(new UserListObserver(), null);
}

private final class UserListObserver extends DefaultObserver<List<User>> {

@Override
public void onComplete() {
view.hideLoading();
}

@Override
public void onError(Throwable e) {
view.hideLoading();
view.showError(new DefaultErrorBundle((Exception) e));
view.showRetry();
}

@Override
public void onNext(List<User> users) {
UserListPresenter.this.showUsersCollectionInView(users);
}
}
}
Loading