5 | * you must abide by the form of mountain technology license. 6 | * you can get a copy of the license 7 | *
8 | * http://www.voviv.com/ 9 | *
10 | * unless applicable law requires or written consent of the software
11 | * license released under distributed on an "as is" basis,
12 | * without any form of guarantee or conditions, express or implied.
13 | * view license management authority and specific language
14 | * under the limit of permission.
15 | */
16 |
17 | import com.fernandocejas.android10.sample.presentation.view.component.AutoLoadImageView;
18 |
19 | import org.robobinding.annotation.ViewBinding;
20 | import org.robobinding.customviewbinding.CustomViewBinding;
21 |
22 | /**
23 | * Title:ImageUrlViewBinding
24 | * Description:
25 | * User: Hunter
26 | * Author: 2015-08-12
27 | * Create Time: 14:58
28 | * Modify the person:
29 | * Modified:
30 | * Modify Note:
31 | * @version
32 | */
33 | @ViewBinding(simpleOneWayProperties = {"imageUrl"})
34 | public class ImageUrlViewBinding extends CustomViewBinding
5 | * you must abide by the form of mountain technology license.
6 | * you can get a copy of the license
7 | *
8 | * http://www.voviv.com/
9 | *
10 | * unless applicable law requires or written consent of the software
11 | * license released under distributed on an "as is" basis,
12 | * without any form of guarantee or conditions, express or implied.
13 | * view license management authority and specific language
14 | * under the limit of permission.
15 | */
16 |
17 | import com.fernandocejas.android10.sample.presentation.internal.di.PerActivity;
18 | import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper;
19 | import com.fernandocejas.android10.sample.presentation.viewmodel.UserDetailsView;
20 | import com.fernandocejas.android10.sample.presentation.viewmodel.UserDetailsViewModel;
21 | import com.fernandocejas.android10.sample.presentation.viewmodel.UserListView;
22 | import com.fernandocejas.android10.sample.presentation.viewmodel.UserListViewModel;
23 | import com.fernandocejas.android10.sample.domain.interactor.UseCase;
24 |
25 | import javax.inject.Named;
26 |
27 | import dagger.Module;
28 | import dagger.Provides;
29 |
30 | /**
31 | * Title:ViewModelModule
32 | * Description:
33 | * User: Hunter
34 | * Author: 2015-08-12
35 | * Create Time: 11:50
36 | * Modify the person:
37 | * Modified:
38 | * Modify Note:
39 | * @version
40 | */
41 | @Module
42 | public class ViewModelModule {
43 | @Provides @PerActivity
44 | public UserListViewModel getUserListViewModel(UserListView userListView, @Named("userList") UseCase getUserListUserCase, UserModelDataMapper userModelDataMapper) {
45 | UserListViewModel vm = new UserListViewModel(userListView, getUserListUserCase, userModelDataMapper);
46 | return vm;
47 | }
48 |
49 | @Provides @PerActivity
50 | public UserDetailsViewModel getUserDetailsViewModel(UserDetailsView userDetailsView,
51 | @Named("userDetails") UseCase getUserDetailsUseCase, UserModelDataMapper userModelDataMapper) {
52 | UserDetailsViewModel vm = new UserDetailsViewModel(userDetailsView, getUserDetailsUseCase, userModelDataMapper);
53 | return vm;
54 | }
55 | }
--------------------------------------------------------------------------------
/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/view/fragment/BaseFragment.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2014 android10.org. All rights reserved.
3 | * @author Fernando Cejas (the android10 coder)
4 | */
5 | package com.fernandocejas.android10.sample.presentation.view.fragment;
6 |
7 | import android.app.Fragment;
8 | import android.os.Bundle;
9 | import android.widget.Toast;
10 |
11 | import com.fernandocejas.android10.sample.presentation.AndroidApplication;
12 | import com.fernandocejas.android10.sample.presentation.internal.di.HasComponent;
13 | import com.fernandocejas.android10.sample.presentation.internal.di.components.ApplicationComponent;
14 | import com.fernandocejas.android10.sample.presentation.internal.di.modules.ActivityModule;
15 |
16 | import org.robobinding.ViewBinder;
17 | import org.robobinding.binder.BinderFactory;
18 |
19 | /**
20 | * Base {@link android.app.Fragment} class for every fragment in this application.
21 | */
22 | public abstract class BaseFragment extends Fragment {
23 |
24 | @Override public void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setRetainInstance(true);
27 | }
28 |
29 | protected ViewBinder createViewBinder(boolean withPreInitializingViews) {
30 | BinderFactory binderFactory = ((AndroidApplication) getActivity().getApplication()).getReusableBinderFactory();
31 | return binderFactory.createViewBinder(getActivity(), withPreInitializingViews);
32 | }
33 | /**
34 | * Shows a {@link android.widget.Toast} message.
35 | *
36 | * @param message An string representing a message to be shown.
37 | */
38 | protected void showToastMessage(String message) {
39 | Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
40 | }
41 |
42 | /**
43 | * Gets a component for dependency injection by its type.
44 | */
45 | @SuppressWarnings("unchecked")
46 | protected > users();
30 |
31 | /**
32 | * Get an {@link rx.Observable} which will emit a {@link User}.
33 | *
34 | * @param userId The user id used to retrieve user data.
35 | */
36 | Observable
> userEntityList();
30 |
31 | /**
32 | * Get an {@link rx.Observable} which will emit a {@link UserEntity} by its id.
33 | *
34 | * @param userId The id to retrieve user data.
35 | */
36 | Observable
> userEntityList();
37 |
38 | /**
39 | * Retrieves an {@link rx.Observable} which will emit a {@link UserEntity}.
40 | *
41 | * @param userId The user id used to get user data.
42 | */
43 | Observable
> userEntityList() {
40 | //TODO: implement simple cache for storing/retrieving collections of users.
41 | throw new UnsupportedOperationException("Operation is not available!!!");
42 | }
43 |
44 | @Override public Observable
> userEntityList() {
52 | return this.restApi.userEntityList();
53 | }
54 |
55 | @Override public Observable
> users() {
52 | //we always get all users from the cloud
53 | final UserDataStore userDataStore = this.userDataStoreFactory.createCloudDataStore();
54 | return userDataStore.userEntityList()
55 | .map(userEntities -> this.userEntityDataMapper.transform(userEntities));
56 | }
57 |
58 | @SuppressWarnings("Convert2MethodRef")
59 | @Override public Observable
>() {}.getType();
69 | userEntityCollection = this.gson.fromJson(userListJsonResponse, listOfUserEntityType);
70 |
71 | return userEntityCollection;
72 | } catch (JsonSyntaxException jsonException) {
73 | throw jsonException;
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/UseCase.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.domain.interactor;
17 |
18 | import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
19 | import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
20 | import rx.Subscriber;
21 | import rx.Observable;
22 | import rx.Subscription;
23 | import rx.schedulers.Schedulers;
24 | import rx.subscriptions.Subscriptions;
25 |
26 | /**
27 | * Abstract class for a Use Case (Interactor in terms of Clean Architecture).
28 | * This interface represents a execution unit for different use cases (this means any use case
29 | * in the application should implement this contract).
30 | *
31 | * By convention each UseCase implementation will return the result using a {@link rx.Subscriber}
32 | * that will execute its job in a background thread and will post the result in the UI thread.
33 | */
34 | public abstract class UseCase {
35 |
36 | private final ThreadExecutor threadExecutor;
37 | private final PostExecutionThread postExecutionThread;
38 |
39 | private Subscription subscription = Subscriptions.empty();
40 |
41 | protected UseCase(ThreadExecutor threadExecutor,
42 | PostExecutionThread postExecutionThread) {
43 | this.threadExecutor = threadExecutor;
44 | this.postExecutionThread = postExecutionThread;
45 | }
46 |
47 | /**
48 | * Builds an {@link rx.Observable} which will be used when executing the current {@link UseCase}.
49 | */
50 | protected abstract Observable buildUseCaseObservable();
51 |
52 | /**
53 | * Executes the current use case.
54 | *
55 | * @param UseCaseSubscriber The guy who will be listen to the observable build with {@link #buildUseCaseObservable()}.
56 | */
57 | @SuppressWarnings("unchecked")
58 | public void execute(Subscriber UseCaseSubscriber) {
59 | this.subscription = this.buildUseCaseObservable()
60 | .subscribeOn(Schedulers.from(threadExecutor))
61 | .observeOn(postExecutionThread.getScheduler())
62 | .subscribe(UseCaseSubscriber);
63 | }
64 |
65 | /**
66 | * Unsubscribes from current {@link rx.Subscription}.
67 | */
68 | public void unsubscribe() {
69 | if (!subscription.isUnsubscribed()) {
70 | subscription.unsubscribe();
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/data/src/test/java/com/fernandocejas/android10/sample/data/cache/serializer/JsonSerializerTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.cache.serializer;
17 |
18 | import com.fernandocejas.android10.sample.data.ApplicationTestCase;
19 | import com.fernandocejas.android10.sample.data.entity.UserEntity;
20 | import org.junit.Before;
21 | import org.junit.Test;
22 |
23 | import static org.hamcrest.CoreMatchers.equalTo;
24 | import static org.hamcrest.CoreMatchers.is;
25 | import static org.junit.Assert.assertThat;
26 |
27 | public class JsonSerializerTest extends ApplicationTestCase {
28 |
29 | private static final String JSON_RESPONSE = "{\n"
30 | + " \"id\": 1,\n"
31 | + " \"cover_url\": \"http://www.android10.org/myapi/cover_1.jpg\",\n"
32 | + " \"full_name\": \"Simon Hill\",\n"
33 | + " \"description\": \"Curabitur gravida nisi at nibh. In hac habitasse platea dictumst. Aliquam augue quam, sollicitudin vitae, consectetuer eget, rutrum at, lorem.\\n\\nInteger tincidunt ante vel ipsum. Praesent blandit lacinia erat. Vestibulum sed magna at nunc commodo placerat.\\n\\nPraesent blandit. Nam nulla. Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.\",\n"
34 | + " \"followers\": 7484,\n"
35 | + " \"email\": \"jcooper@babbleset.edu\"\n"
36 | + "}";
37 |
38 | private JsonSerializer jsonSerializer;
39 |
40 | @Before
41 | public void setUp() {
42 | jsonSerializer = new JsonSerializer();
43 | }
44 |
45 | @Test
46 | public void testSerializeHappyCase() {
47 | UserEntity userEntityOne = jsonSerializer.deserialize(JSON_RESPONSE);
48 | String jsonString = jsonSerializer.serialize(userEntityOne);
49 | UserEntity userEntityTwo = jsonSerializer.deserialize(jsonString);
50 |
51 | assertThat(userEntityOne.getUserId(), is(userEntityTwo.getUserId()));
52 | assertThat(userEntityOne.getFullname(), is(equalTo(userEntityTwo.getFullname())));
53 | assertThat(userEntityOne.getFollowers(), is(userEntityTwo.getFollowers()));
54 | }
55 |
56 | @Test
57 | public void testDesearializeHappyCase() {
58 | UserEntity userEntity = jsonSerializer.deserialize(JSON_RESPONSE);
59 |
60 | assertThat(userEntity.getUserId(), is(1));
61 | assertThat(userEntity.getFullname(), is("Simon Hill"));
62 | assertThat(userEntity.getFollowers(), is(7484));
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/data/src/main/java/com/fernandocejas/android10/sample/data/net/ApiConnection.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 Fernando Cejas Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.fernandocejas.android10.sample.data.net;
17 |
18 | import android.support.annotation.Nullable;
19 | import com.squareup.okhttp.OkHttpClient;
20 | import com.squareup.okhttp.Request;
21 | import java.io.IOException;
22 | import java.net.MalformedURLException;
23 | import java.net.URL;
24 | import java.util.concurrent.Callable;
25 | import java.util.concurrent.TimeUnit;
26 |
27 | /**
28 | * Api Connection class used to retrieve data from the cloud.
29 | * Implements {@link java.util.concurrent.Callable} so when executed asynchronously can
30 | * return a value.
31 | */
32 | public class ApiConnection implements Callable
> userEntityList() {
52 | return Observable.create(new Observable.OnSubscribe
>() {
53 | @Override public void call(Subscriber super List
> {
85 |
86 | @Override public void onCompleted() {
87 | UserListViewModel.this.hideViewLoading();
88 | }
89 |
90 | @Override public void onError(Throwable e) {
91 | UserListViewModel.this.hideViewLoading();
92 | UserListViewModel.this.showErrorMessage(new DefaultErrorBundle((Exception) e));
93 | UserListViewModel.this.showViewRetry();
94 | }
95 |
96 | @Override public void onNext(List