Skip to content

Commit

Permalink
Removed God activities
Browse files Browse the repository at this point in the history
  • Loading branch information
AllanHasegawa committed Jul 30, 2017
1 parent 58ea1c9 commit e7c6d4a
Show file tree
Hide file tree
Showing 12 changed files with 395 additions and 192 deletions.
24 changes: 1 addition & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,6 @@
# Catter2

Catter2 is a small educational Android app created to show how to refactor an app to use Dagger2.

Topics covered:

1. [God activities](https://en.wikipedia.org/wiki/God_object)
1. Single Responsibility Principle
1. Dependency Injection
1. Lifetime of instances
1. Organizing and accessing your instances
1. and, Dagger2!


# In action!

![Catter2 in action](https://giant.gfycat.com/RapidGlassBasilisk.gif)


# How to study this repo

All the instructions are in the following blog post:

[TODO: add blog post url here]

Please see the README.md from the master branch.

# License

Expand Down
19 changes: 0 additions & 19 deletions app/src/main/java/io/catter2/FavoriteModel.java

This file was deleted.

72 changes: 15 additions & 57 deletions app/src/main/java/io/catter2/FavoritesActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
Expand All @@ -12,15 +11,12 @@
import android.util.Log;
import android.view.View;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.List;

import io.catter2.favorites.GetFavoritesUseCase;

public class FavoritesActivity extends AppCompatActivity {

static String SP_USER_FAVORITES_KEY = "user-favorites-urls-%s";
private static String TAG = "ImagesRvAdapter";
private static String ARG_USER_TOKEN = "favorites-user-token";

Expand All @@ -36,7 +32,8 @@ static public void launch(Context context, String userToken, boolean clearTop) {
private RecyclerView recyclerView;
private ImagesRvAdapter rvAdapter;
private String userToken;
private SharedPreferences.OnSharedPreferenceChangeListener sharedPrefListener;

private GetFavoritesUseCase getFavoritesUseCase;

@Override
protected void onCreate(Bundle savedInstanceState) {
Expand Down Expand Up @@ -65,59 +62,20 @@ public void onClick(View view) {
}
Log.d(TAG, "UserToken: " + userToken);

setupFavoritesSharedPref(userToken);
getFavoritesUseCase = new GetFavoritesUseCase(this, userToken);
getFavoritesUseCase.getFavorites(new GetFavoritesUseCase.Callback() {
@Override
public void favoriteUrlsUpdated(List<String> favoriteUrls) {
Log.d(TAG, "Updated favorites: " + favoriteUrls.toString());
rvAdapter.updateImageUrls(favoriteUrls);
}
});
}

@Override
protected void onDestroy() {
SharedPreferences pref = getSharedPreferences(
getString(R.string.pref_key_user_data), Context.MODE_PRIVATE);
pref.unregisterOnSharedPreferenceChangeListener(sharedPrefListener);
getFavoritesUseCase.clear();
getFavoritesUseCase = null;
super.onDestroy();
}

private void setupFavoritesSharedPref(final String userToken) {
SharedPreferences pref = getSharedPreferences(
getString(R.string.pref_key_user_data), Context.MODE_PRIVATE);
sharedPrefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.d(TAG, "Key changed: " + key);
String prefKey = String.format(SP_USER_FAVORITES_KEY, userToken);
if (key.equals(prefKey)) {
updateFavorites(sharedPreferences);
}
}
};
pref.registerOnSharedPreferenceChangeListener(sharedPrefListener);
updateFavorites(pref);
}

private void updateFavorites(SharedPreferences pref) {
String prefKey = String.format(SP_USER_FAVORITES_KEY, userToken);
Log.d(TAG, "PrefKey: " + prefKey);
Set<String> entriesSet = pref.getStringSet(prefKey, new HashSet<String>());

ArrayList<FavoriteModel> favorites = new ArrayList<>(entriesSet.size());
for (String entry : entriesSet) {
String[] decoded = entry.split(";");
favorites.add(new FavoriteModel(Long.valueOf(decoded[1]), decoded[0]));
}

Collections.sort(favorites, new Comparator<FavoriteModel>() {
@Override
public int compare(FavoriteModel o1, FavoriteModel o2) {
return (int) (o2.getTimeAdded() - o1.getTimeAdded());
}
});

ArrayList<String> urlsSorted = new ArrayList<>(favorites.size());
for (FavoriteModel favorite : favorites) {
urlsSorted.add(favorite.getUrl());
}

Log.d(TAG, "Updated favorites: " + urlsSorted.toString());
rvAdapter.updateImageUrls(new ArrayList<>(urlsSorted));
}

}
108 changes: 31 additions & 77 deletions app/src/main/java/io/catter2/ListActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
Expand All @@ -15,18 +14,10 @@

import com.plattysoft.leonids.ParticleSystem;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.List;

import io.catter2.cat_api.CatImageModel;
import io.catter2.cat_api.CatImagesModel;
import io.catter2.cat_api.RetrofitTheCatAPI;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.simplexml.SimpleXmlConverterFactory;
import io.catter2.cat_api.FetchCatImagesUseCase;
import io.catter2.favorites.AddFavoriteUseCase;

public class ListActivity extends AppCompatActivity {
private static String TAG = "List";
Expand All @@ -41,6 +32,9 @@ static public void launch(Context context, String userToken) {
private String userToken;
private RecyclerView recyclerView;

private AddFavoriteUseCase addFavoriteUseCase;
private FetchCatImagesUseCase fetchCatImagesUseCase;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Expand All @@ -66,7 +60,15 @@ public void imageClicked(ImageView view, String url) {
recyclerView.setAdapter(adapter);


fetchCatImages(adapter);
addFavoriteUseCase = new AddFavoriteUseCase(this, userToken);
fetchCatImagesUseCase = new FetchCatImagesUseCase();

fetchCatImagesUseCase.getImagesUrls(new FetchCatImagesUseCase.Callback() {
@Override
public void imagesUrls(List<String> urls) {
adapter.updateImageUrls(urls);
}
});
}

@Override
Expand All @@ -79,71 +81,23 @@ public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}

private void fetchCatImages(final ImagesRvAdapter adapter) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://thecatapi.com/api/")
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
RetrofitTheCatAPI retrofitTheCatApi = retrofit.create(RetrofitTheCatAPI.class);
retrofitTheCatApi.listCatsWithHat().enqueue(new Callback<CatImagesModel>() {
@Override
public void onResponse(Call<CatImagesModel> call, Response<CatImagesModel> response) {
ArrayList<String> imageUrls = new ArrayList<>();
if (response.body().catImages != null) {
for (CatImageModel img : response.body().catImages) {
Log.d(TAG, "Found: " + img.url);
imageUrls.add(img.url);
}
}
adapter.updateImageUrls(imageUrls);
}

@Override
public void onFailure(Call<CatImagesModel> call, Throwable t) {
Log.e(TAG, "Error fetching cat images", t);
}
});
}

private void addUrlToUserFavoritesList(ImageView view, String url) {
SharedPreferences pref = getSharedPreferences(
getString(R.string.pref_key_user_data), Context.MODE_PRIVATE);
String prefKey = String.format(FavoritesActivity.SP_USER_FAVORITES_KEY, userToken);
Log.d(TAG, "Pref key: " + prefKey);
Set<String> oldUrls = pref.getStringSet(prefKey, new HashSet<String>());

boolean hasUrl = false;
for (String entry : oldUrls) {
String oldUrl = entry.split(";")[0];
if (oldUrl.equals(url)) {
hasUrl = true;
break;
}
}

if (hasUrl) {
Snackbar.make(recyclerView, R.string.list_user_favorite_url_already_in, Snackbar.LENGTH_SHORT)
.show();
return;
boolean imageAdded = addFavoriteUseCase.addFavoriteUrl(url);

int msgId;
if (imageAdded) {
msgId = R.string.list_user_favorite_url_added_success;
new ParticleSystem(ListActivity.this, 500, R.mipmap.azunyan_2, 2000)
.setAcceleration(0.0005f, 90)
.setSpeedRange(0.2f, 0.5f)
.setRotationSpeedRange(90, 180)
.setInitialRotationRange(0, 180)
.setFadeOut(500)
.setScaleRange(0.1f, 1.0f)
.oneShot(view, 100);
} else {
msgId = R.string.list_user_favorite_url_already_in;
}

HashSet<String> newUrls = new HashSet<>(oldUrls);
long timeNow = System.currentTimeMillis();
String timeNowStr = String.valueOf(timeNow);
newUrls.add(url + ";" + timeNowStr);

pref.edit().putStringSet(prefKey, newUrls).apply();

new ParticleSystem(ListActivity.this, 500, R.mipmap.azunyan_2, 2000)
.setAcceleration(0.0005f, 90)
.setSpeedRange(0.2f, 0.5f)
.setRotationSpeedRange(90, 180)
.setInitialRotationRange(0, 180)
.setFadeOut(500)
.setScaleRange(0.1f, 1.0f)
.oneShot(view, 100);

Snackbar.make(recyclerView, R.string.list_user_favorite_url_added_success, Snackbar.LENGTH_SHORT)
.show();
Snackbar.make(recyclerView, msgId, Snackbar.LENGTH_SHORT).show();
}
}
25 changes: 9 additions & 16 deletions app/src/main/java/io/catter2/LoginActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,13 @@
import android.widget.EditText;
import android.widget.TextView;

import io.catter2.login.LoginUseCase;

/**
* A login screen that offers login via username/password.
*/
public class LoginActivity extends AppCompatActivity {

/**
* A dummy authentication store containing known user names and passwords.
*/
private static final String[] DUMMY_CREDENTIALS = new String[]{
"me:123:token9", "yo:hunter2:token2"
};

private AutoCompleteTextView usernameActv;
private EditText passwordEt;
private TextView errorTv;
Expand Down Expand Up @@ -59,16 +54,14 @@ private void attemptLogin() {
String username = usernameActv.getText().toString();
String password = passwordEt.getText().toString();

for (String credential : DUMMY_CREDENTIALS) {
String[] split = credential.split(":");
if (username.equals(split[0]) && password.equals(split[1])) {
String token = split[2];
FavoritesActivity.launch(this, token, false);
return;
}
}
LoginUseCase uc = new LoginUseCase();
String token = uc.login(username, password);

errorTv.setVisibility(View.VISIBLE);
if (token != null) {
FavoritesActivity.launch(this, token, false);
} else {
errorTv.setVisibility(View.VISIBLE);
}
}
}

45 changes: 45 additions & 0 deletions app/src/main/java/io/catter2/cat_api/FetchCatImagesUseCase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.catter2.cat_api;

import android.util.Log;

import java.util.ArrayList;
import java.util.List;

import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.simplexml.SimpleXmlConverterFactory;

public class FetchCatImagesUseCase {
public interface Callback {
void imagesUrls(List<String> urls);
}

private static String TAG = "FetchCatImagesUseCase";

public void getImagesUrls(final Callback callback) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://thecatapi.com/api/")
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
RetrofitTheCatAPI retrofitTheCatApi = retrofit.create(RetrofitTheCatAPI.class);
retrofitTheCatApi.listCatsWithHat().enqueue(new retrofit2.Callback<CatImagesModel>() {
@Override
public void onResponse(Call<CatImagesModel> call, Response<CatImagesModel> response) {
ArrayList<String> imageUrls = new ArrayList<>();
if (response.body().catImages != null) {
for (CatImageModel img : response.body().catImages) {
Log.d(TAG, "Found: " + img.url);
imageUrls.add(img.url);
}
}
callback.imagesUrls(imageUrls);
}

@Override
public void onFailure(Call<CatImagesModel> call, Throwable t) {
Log.e(TAG, "Error fetching cat images", t);
}
});
}
}
Loading

0 comments on commit e7c6d4a

Please sign in to comment.