diff options
29 files changed, 704 insertions, 120 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a36ebe04..5d815b6d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -50,8 +50,8 @@ android:theme="@style/AppTheme.NoActionBarWithTranslucentStatusBar" /> <activity android:name=".ViewUserDetailActivity" - android:label="@string/title_activity_view_user_detail" - android:theme="@style/AppTheme.NoActionBar" /> + android:parentActivityName=".MainActivity" + android:theme="@style/AppTheme.NoActionBarWithTranslucentStatusBar" /> </application> </manifest>
\ No newline at end of file diff --git a/app/src/main/java/SubredditDatabase/SubredditDao.java b/app/src/main/java/SubredditDatabase/SubredditDao.java index ac291f9a..df763c93 100644 --- a/app/src/main/java/SubredditDatabase/SubredditDao.java +++ b/app/src/main/java/SubredditDatabase/SubredditDao.java @@ -14,7 +14,7 @@ public interface SubredditDao { @Query("DELETE FROM subreddits") void deleteAllSubreddits(); - @Query("SELECT * from subreddits WHERE name = :namePrefixed") + @Query("SELECT * from subreddits WHERE name = :namePrefixed LIMIT 1") LiveData<SubredditData> getSubredditLiveDataByName(String namePrefixed); @Query("SELECT * from subreddits WHERE name = :namePrefixed LIMIT 1") diff --git a/app/src/main/java/SubredditDatabase/SubredditRepository.java b/app/src/main/java/SubredditDatabase/SubredditRepository.java index 495f6e3d..4e435da9 100644 --- a/app/src/main/java/SubredditDatabase/SubredditRepository.java +++ b/app/src/main/java/SubredditDatabase/SubredditRepository.java @@ -20,14 +20,14 @@ public class SubredditRepository { } public void insert(SubredditData subredditData) { - new SubredditRepository.insertAsyncTask(mSubredditDao).execute(subredditData); + new InsertAsyncTask(mSubredditDao).execute(subredditData); } - private static class insertAsyncTask extends AsyncTask<SubredditData, Void, Void> { + private static class InsertAsyncTask extends AsyncTask<SubredditData, Void, Void> { private SubredditDao mAsyncTaskDao; - insertAsyncTask(SubredditDao dao) { + InsertAsyncTask(SubredditDao dao) { mAsyncTaskDao = dao; } diff --git a/app/src/main/java/SubredditDatabase/SubredditViewModel.java b/app/src/main/java/SubredditDatabase/SubredditViewModel.java index a9d176b3..19c2d726 100644 --- a/app/src/main/java/SubredditDatabase/SubredditViewModel.java +++ b/app/src/main/java/SubredditDatabase/SubredditViewModel.java @@ -11,7 +11,7 @@ public class SubredditViewModel extends AndroidViewModel { private SubredditRepository mSubredditRepository; private LiveData<SubredditData> mSubredditLiveData; - SubredditViewModel(Application application, String id) { + public SubredditViewModel(Application application, String id) { super(application); mSubredditRepository = new SubredditRepository(application, id); mSubredditLiveData = mSubredditRepository.getSubredditLiveData(); diff --git a/app/src/main/java/SubscribedUserDatabase/SubscribedUserDao.java b/app/src/main/java/SubscribedUserDatabase/SubscribedUserDao.java index 2b61a666..83bdf6fe 100644 --- a/app/src/main/java/SubscribedUserDatabase/SubscribedUserDao.java +++ b/app/src/main/java/SubscribedUserDatabase/SubscribedUserDao.java @@ -16,6 +16,12 @@ public interface SubscribedUserDao { @Query("DELETE FROM subscribed_users") void deleteAllSubscribedUsers(); - @Query("SELECT * from subscribed_users ORDER BY name COLLATE NOCASE ASC") + @Query("SELECT * FROM subscribed_users ORDER BY name COLLATE NOCASE ASC") LiveData<List<SubscribedUserData>> getAllSubscribedUsers(); + + @Query("SELECT * FROM subscribed_users WHERE name = :userName LIMIT 1") + SubscribedUserData getSubscribedUser(String userName); + + @Query("DELETE FROM subscribed_users WHERE name = :userName") + void deleteSubscribedUser(String userName); } diff --git a/app/src/main/java/SubscribedUserDatabase/SubscribedUserData.java b/app/src/main/java/SubscribedUserDatabase/SubscribedUserData.java index 8494e784..41947efe 100644 --- a/app/src/main/java/SubscribedUserDatabase/SubscribedUserData.java +++ b/app/src/main/java/SubscribedUserDatabase/SubscribedUserData.java @@ -9,24 +9,17 @@ import android.support.annotation.NonNull; public class SubscribedUserData { @PrimaryKey @NonNull - @ColumnInfo(name = "id") - private String id; @ColumnInfo(name = "name") private String name; @ColumnInfo(name = "icon") private String iconUrl; - public SubscribedUserData(@NonNull String id, String name, String iconUrl) { - this.id = id; + public SubscribedUserData(@NonNull String name, String iconUrl) { this.name = name; this.iconUrl = iconUrl; } @NonNull - public String getId() { - return id; - } - public String getName() { return name; } diff --git a/app/src/main/java/User/UserDao.java b/app/src/main/java/User/UserDao.java index ec6bb7e2..7aba086d 100644 --- a/app/src/main/java/User/UserDao.java +++ b/app/src/main/java/User/UserDao.java @@ -1,5 +1,6 @@ package User; +import android.arch.lifecycle.LiveData; import android.arch.persistence.room.Dao; import android.arch.persistence.room.Insert; import android.arch.persistence.room.OnConflictStrategy; @@ -8,11 +9,14 @@ import android.arch.persistence.room.Query; @Dao public interface UserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) - void insert(User user); + void insert(UserData userData); @Query("DELETE FROM users") void deleteAllUsers(); - @Query("SELECT * FROM users WHERE user_name = :userName LIMIT 1") - User getUserData(String userName); + @Query("SELECT * FROM users WHERE name = :userName LIMIT 1") + LiveData<UserData> getUserLiveData(String userName); + + @Query("SELECT * FROM users WHERE name = :userName LIMIT 1") + UserData getUserData(String userName); } diff --git a/app/src/main/java/User/User.java b/app/src/main/java/User/UserData.java index 3fd8dcb3..89eafb96 100644 --- a/app/src/main/java/User/User.java +++ b/app/src/main/java/User/UserData.java @@ -2,17 +2,12 @@ package User; import android.arch.persistence.room.ColumnInfo; import android.arch.persistence.room.Entity; -import android.arch.persistence.room.PrimaryKey; import android.support.annotation.NonNull; +import SubscribedUserDatabase.SubscribedUserData; + @Entity(tableName = "users") -public class User { - @PrimaryKey - @NonNull - @ColumnInfo(name = "user_name") - private String userName; - @ColumnInfo(name = "icon") - private String icon; +public class UserData extends SubscribedUserData { @ColumnInfo(name = "banner") private String banner; @ColumnInfo(name = "karma") @@ -22,24 +17,14 @@ public class User { @ColumnInfo(name = "is_friend") private boolean isFriend; - User(@NonNull String userName, String icon, String banner, int karma, boolean isGold, boolean isFriend) { - this.userName = userName; - this.icon = icon; + public UserData(@NonNull String name, String iconUrl, String banner, int karma, boolean isGold, boolean isFriend) { + super(name, iconUrl); this.banner = banner; this.karma = karma; this.isGold = isGold; this.isFriend = isFriend; } - @NonNull - public String getUserName() { - return userName; - } - - public String getIcon() { - return icon; - } - public String getBanner() { return banner; } diff --git a/app/src/main/java/User/UserRepository.java b/app/src/main/java/User/UserRepository.java new file mode 100644 index 00000000..d505db2b --- /dev/null +++ b/app/src/main/java/User/UserRepository.java @@ -0,0 +1,39 @@ +package User; + +import android.app.Application; +import android.arch.lifecycle.LiveData; +import android.os.AsyncTask; + +public class UserRepository { + private UserDao mUserDao; + private LiveData<UserData> mUserLiveData; + + UserRepository(Application application, String userName) { + mUserDao = UserRoomDatabase.getDatabase(application).userDao(); + + mUserLiveData = mUserDao.getUserLiveData(userName); + } + + LiveData<UserData> getUserLiveData() { + return mUserLiveData; + } + + public void insert(UserData userData) { + new InsertAsyncTask(mUserDao).execute(userData); + } + + private static class InsertAsyncTask extends AsyncTask<UserData, Void, Void> { + + private UserDao mAsyncTaskDao; + + InsertAsyncTask(UserDao dao) { + mAsyncTaskDao = dao; + } + + @Override + protected Void doInBackground(final UserData... params) { + mAsyncTaskDao.insert(params[0]); + return null; + } + } +} diff --git a/app/src/main/java/User/UserRoomDatabase.java b/app/src/main/java/User/UserRoomDatabase.java index 31ca1259..288400a6 100644 --- a/app/src/main/java/User/UserRoomDatabase.java +++ b/app/src/main/java/User/UserRoomDatabase.java @@ -5,7 +5,7 @@ import android.arch.persistence.room.Room; import android.arch.persistence.room.RoomDatabase; import android.content.Context; -@Database(entities = {User.class}, version = 1) +@Database(entities = {UserData.class}, version = 1) public abstract class UserRoomDatabase extends RoomDatabase { private static UserRoomDatabase INSTANCE; diff --git a/app/src/main/java/User/UserViewModel.java b/app/src/main/java/User/UserViewModel.java new file mode 100644 index 00000000..a006e253 --- /dev/null +++ b/app/src/main/java/User/UserViewModel.java @@ -0,0 +1,48 @@ +package User; + +import android.app.Application; +import android.arch.lifecycle.AndroidViewModel; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; +import android.support.annotation.NonNull; + +import SubredditDatabase.SubredditViewModel; + +public class UserViewModel extends AndroidViewModel { + private UserRepository mSubredditRepository; + private LiveData<UserData> mUserLiveData; + + public UserViewModel(Application application, String id) { + super(application); + mSubredditRepository = new UserRepository(application, id); + mUserLiveData = mSubredditRepository.getUserLiveData(); + } + + public LiveData<UserData> getUserLiveData() { + return mUserLiveData; + } + + public void insert(UserData userData) { + mSubredditRepository.insert(userData); + } + + public static class Factory extends ViewModelProvider.NewInstanceFactory { + + @NonNull + private final Application mApplication; + + private final String userName; + + public Factory(@NonNull Application application, String userName) { + mApplication = application; + this.userName = userName; + } + + @Override + public <T extends ViewModel> T create(Class<T> modelClass) { + //noinspection unchecked + return (T) new UserViewModel(mApplication, userName); + } + } +} diff --git a/app/src/main/java/User/FetchUserData.java b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchUserData.java index edaa3b14..9bfcf7c3 100644 --- a/app/src/main/java/User/FetchUserData.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchUserData.java @@ -1,16 +1,16 @@ -package User; +package ml.docilealligator.infinityforreddit; import android.support.annotation.NonNull; import android.util.Log; -import ml.docilealligator.infinityforreddit.RedditAPI; +import User.UserData; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Retrofit; public class FetchUserData { public interface FetchUserDataListener { - void onFetchUserDataSuccess(User user); + void onFetchUserDataSuccess(UserData userData); void onFetchUserDataFail(); } @@ -23,10 +23,10 @@ public class FetchUserData { @Override public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) { if(response.isSuccessful()) { - ParseUserData.parseMyInfo(response.body(), new ParseUserData.ParseUserDataListener() { + ParseUserData.parseUserData(response.body(), new ParseUserData.ParseUserDataListener() { @Override - public void onParseUserDataSuccess(User user) { - fetchUserDataListener.onFetchUserDataSuccess(user); + public void onParseUserDataSuccess(UserData userData) { + fetchUserDataListener.onFetchUserDataSuccess(userData); } @Override diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/InsertUserDataAsyncTask.java b/app/src/main/java/ml/docilealligator/infinityforreddit/InsertUserDataAsyncTask.java index 823e014e..6db03920 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/InsertUserDataAsyncTask.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/InsertUserDataAsyncTask.java @@ -2,27 +2,27 @@ package ml.docilealligator.infinityforreddit; import android.os.AsyncTask; -import User.User; +import User.UserData; import User.UserDao; public class InsertUserDataAsyncTask extends AsyncTask<Void, Void, Void> { private UserDao userDao; - private User user; + private UserData userData; private InsertUserDataCallback insertUserDataCallback; public interface InsertUserDataCallback { void insertSuccess(); } - public InsertUserDataAsyncTask(UserDao userDao, User user, InsertUserDataCallback insertUserDataCallback) { + public InsertUserDataAsyncTask(UserDao userDao, UserData userData, InsertUserDataCallback insertUserDataCallback) { this.userDao = userDao; - this.user = user; + this.userData = userData; this.insertUserDataCallback = insertUserDataCallback; } @Override protected Void doInBackground(Void... voids) { - userDao.insert(user); + userDao.insert(userData); return null; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/LoadUserDataAsyncTask.java b/app/src/main/java/ml/docilealligator/infinityforreddit/LoadUserDataAsyncTask.java index be8c182c..704c3e08 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/LoadUserDataAsyncTask.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/LoadUserDataAsyncTask.java @@ -2,8 +2,7 @@ package ml.docilealligator.infinityforreddit; import android.os.AsyncTask; -import User.FetchUserData; -import User.User; +import User.UserData; import User.UserDao; import retrofit2.Retrofit; @@ -29,7 +28,7 @@ public class LoadUserDataAsyncTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... voids) { if(userDao.getUserData(userName) != null) { - iconImageUrl = userDao.getUserData(userName).getIcon(); + iconImageUrl = userDao.getUserData(userName).getIconUrl(); hasUserInDb = true; } else { hasUserInDb = false; @@ -45,13 +44,8 @@ public class LoadUserDataAsyncTask extends AsyncTask<Void, Void, Void> { } else { FetchUserData.fetchUserData(retrofit, userName, new FetchUserData.FetchUserDataListener() { @Override - public void onFetchUserDataSuccess(User user) { - new InsertUserDataAsyncTask(userDao, user, new InsertUserDataAsyncTask.InsertUserDataCallback() { - @Override - public void insertSuccess() { - loadUserDataAsyncTaskListener.loadUserDataSuccess(user.getIcon()); - } - }).execute(); + public void onFetchUserDataSuccess(UserData userData) { + new InsertUserDataAsyncTask(userDao, userData, () -> loadUserDataAsyncTaskListener.loadUserDataSuccess(userData.getIconUrl())).execute(); } @Override diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java index 773ec885..7254bfcf 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java @@ -20,6 +20,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import com.bumptech.glide.Glide; @@ -61,6 +62,7 @@ public class MainActivity extends AppCompatActivity { @BindView(R.id.subscriptions_label_main_activity) TextView subscriptionsLabelTextView; @BindView(R.id.subscribed_user_recycler_view_main_activity) RecyclerView subscribedUserRecyclerView; @BindView(R.id.following_label_main_activity) TextView followingLabelTextView; + @BindView(R.id.profile_linear_layout_main_activity) LinearLayout profileLinearLayout; private TextView mNameTextView; private TextView mKarmaTextView; @@ -153,13 +155,14 @@ public class MainActivity extends AppCompatActivity { glide.load(mBannerImageUrl).into(mBannerImageView); } - final SubscribedSubredditRecyclerViewAdapter subredditadapter = new SubscribedSubredditRecyclerViewAdapter(this, - new SubscribedSubredditRecyclerViewAdapter.OnItemClickListener() { - @Override - public void onClick() { - drawer.closeDrawers(); - } - }); + profileLinearLayout.setOnClickListener(view -> { + Intent intent = new Intent(MainActivity.this, ViewUserDetailActivity.class); + intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mName); + startActivity(intent); + }); + + final SubscribedSubredditRecyclerViewAdapter subredditadapter = + new SubscribedSubredditRecyclerViewAdapter(this, drawer::closeDrawers); subscribedSubredditRecyclerView.setAdapter(subredditadapter); mSubscribedSubredditViewModel = ViewModelProviders.of(this).get(SubscribedSubredditViewModel.class); @@ -176,13 +179,8 @@ public class MainActivity extends AppCompatActivity { } }); - final SubscribedUserRecyclerViewAdapter userAdapter = new SubscribedUserRecyclerViewAdapter(this, - new SubscribedUserRecyclerViewAdapter.OnItemClickListener() { - @Override - public void onClick() { - drawer.closeDrawers(); - } - }); + final SubscribedUserRecyclerViewAdapter userAdapter = + new SubscribedUserRecyclerViewAdapter(this, drawer::closeDrawers); subscribedUserRecyclerView.setAdapter(userAdapter); mSubscribedUserViewModel = ViewModelProviders.of(this).get(SubscribedUserViewModel.class); mSubscribedUserViewModel.getAllSubscribedUsers().observe(this, new Observer<List<SubscribedUserData>>() { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkComponent.java b/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkComponent.java index 354dfbea..747dead0 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkComponent.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkComponent.java @@ -11,4 +11,5 @@ interface NetworkComponent { void inject(PostFragment postFragment); void inject(ViewPostDetailActivity viewPostDetailActivity); void inject(ViewSubredditDetailActivity viewSubredditDetailActivity); + void inject(ViewUserDetailActivity viewUserDetailActivity); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseSubscribedThing.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseSubscribedThing.java index 6b9ef580..fc69c82b 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseSubscribedThing.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseSubscribedThing.java @@ -94,7 +94,7 @@ class ParseSubscribedThing { if(data.getString(JSONUtils.SUBREDDIT_TYPE_KEY) .equals(JSONUtils.SUBREDDIT_TYPE_VALUE_USER)) { //It's a user - newSubscribedUserData.add(new SubscribedUserData(id, name.substring(2), iconUrl)); + newSubscribedUserData.add(new SubscribedUserData(name.substring(2), iconUrl)); } else { String subredditFullName = data.getString(JSONUtils.DISPLAY_NAME); String description = data.getString(JSONUtils.PUBLIC_DESCRIPTION_KEY).trim(); diff --git a/app/src/main/java/User/ParseUserData.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseUserData.java index b6a7a39c..12402f03 100644 --- a/app/src/main/java/User/ParseUserData.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseUserData.java @@ -1,4 +1,4 @@ -package User; +package ml.docilealligator.infinityforreddit; import android.os.AsyncTask; import android.util.Log; @@ -6,15 +6,15 @@ import android.util.Log; import org.json.JSONException; import org.json.JSONObject; -import ml.docilealligator.infinityforreddit.JSONUtils; +import User.UserData; public class ParseUserData { interface ParseUserDataListener { - void onParseUserDataSuccess(User user); + void onParseUserDataSuccess(UserData userData); void onParseUserDataFail(); } - static void parseMyInfo(String response, ParseUserDataListener parseUserDataListener) { + static void parseUserData(String response, ParseUserDataListener parseUserDataListener) { new ParseUserDataAsyncTask(response, parseUserDataListener).execute(); } @@ -23,15 +23,16 @@ public class ParseUserData { private ParseUserDataListener parseUserDataListener; private boolean parseFailed; - private User user; + private UserData userData; ParseUserDataAsyncTask(String response, ParseUserDataListener parseUserDataListener){ try { + Log.i("response", response); jsonResponse = new JSONObject(response); this.parseUserDataListener = parseUserDataListener; parseFailed = false; } catch (JSONException e) { - Log.i("user data json error", e.getMessage()); + Log.i("userdata json error", e.getMessage()); parseUserDataListener.onParseUserDataFail(); } } @@ -43,7 +44,7 @@ public class ParseUserData { String userName = jsonResponse.getString(JSONUtils.NAME_KEY); String iconImageUrl = jsonResponse.getString(JSONUtils.ICON_IMG_KEY); String bannerImageUrl = ""; - if(!jsonResponse.isNull(JSONUtils.SUBREDDIT_KEY)) { + if(jsonResponse.has(JSONUtils.SUBREDDIT_KEY) && !jsonResponse.isNull(JSONUtils.SUBREDDIT_KEY)) { bannerImageUrl = jsonResponse.getJSONObject(JSONUtils.SUBREDDIT_KEY).getString(JSONUtils.BANNER_IMG_KEY); } int linkKarma = jsonResponse.getInt(JSONUtils.LINK_KARMA_KEY); @@ -52,7 +53,7 @@ public class ParseUserData { boolean isGold = jsonResponse.getBoolean(JSONUtils.IS_GOLD_KEY); boolean isFriend = jsonResponse.getBoolean(JSONUtils.IS_FRIEND_KEY); - user = new User(userName, iconImageUrl, bannerImageUrl, karma, isGold, isFriend); + userData = new UserData(userName, iconImageUrl, bannerImageUrl, karma, isGold, isFriend); } catch (JSONException e) { parseFailed = true; Log.i("parse user data error", e.getMessage()); @@ -63,7 +64,7 @@ public class ParseUserData { @Override protected void onPostExecute(Void aVoid) { if(!parseFailed) { - parseUserDataListener.onParseUserDataSuccess(user); + parseUserDataListener.onParseUserDataSuccess(userData); } else { parseUserDataListener.onParseUserDataFail(); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java index bc851a8f..35e95b75 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java @@ -300,6 +300,7 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo if(canStartActivity) { canStartActivity = false; Intent intent = new Intent(mContext, ViewUserDetailActivity.class); + intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, post.getAuthor()); mContext.startActivity(intent); } }); @@ -310,6 +311,7 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo if(canStartActivity) { canStartActivity = false; Intent intent = new Intent(mContext, ViewUserDetailActivity.class); + intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, post.getAuthor()); mContext.startActivity(intent); } }); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java index 25b74317..25f83bbd 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java @@ -3,11 +3,13 @@ package ml.docilealligator.infinityforreddit; import java.util.Map; import retrofit2.Call; +import retrofit2.http.DELETE; import retrofit2.http.FieldMap; import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; import retrofit2.http.HeaderMap; import retrofit2.http.POST; +import retrofit2.http.PUT; import retrofit2.http.Path; import retrofit2.http.Query; @@ -45,4 +47,10 @@ public interface RedditAPI { @FormUrlEncoded @POST("api/subscribe") Call<String> subredditSubscription(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params); + + @PUT("/api/v1/me/friends/username") + Call<String> subscribeUser(@HeaderMap Map<String, String> headers); + + @DELETE("/api/v1/me/friends/username") + Call<String> unsubscribeUser(@HeaderMap Map<String, String> headers); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditUtils.java index d598f684..627b7f10 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditUtils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditUtils.java @@ -30,7 +30,7 @@ public class RedditUtils { static final String AUTHORIZATION_KEY = "Authorization"; static final String AUTHORIZATION_BASE = "bearer "; - static final String USER_AGENT_KEY = "User-Agent"; + static final String USER_AGENT_KEY = "UserData-Agent"; static final String USER_AGENT = ""; static final String GRANT_TYPE_KEY = "grant_type"; @@ -47,6 +47,7 @@ public class RedditUtils { static final String ACTION_KEY = "action"; static final String SR_NAME_KEY = "sr_name"; + static final String SR_KEY = "sr"; static Map<String, String> getHttpBasicAuthHeader() { Map<String, String> params = new HashMap<>(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserRecyclerViewAdapter.java index 013d75c1..bec617c6 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserRecyclerViewAdapter.java @@ -1,6 +1,7 @@ package ml.docilealligator.infinityforreddit; import android.content.Context; +import android.content.Intent; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; @@ -27,6 +28,7 @@ import jp.wasabeef.glide.transformations.RoundedCornersTransformation; public class SubscribedUserRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private List<SubscribedUserData> mSubscribedUserData; + private Context mContext; private RequestManager glide; private OnItemClickListener mOnItemClickListener; @@ -35,6 +37,7 @@ public class SubscribedUserRecyclerViewAdapter extends RecyclerView.Adapter<Recy } SubscribedUserRecyclerViewAdapter(Context context, OnItemClickListener onItemClickListener) { + mContext = context; glide = Glide.with(context.getApplicationContext()); mOnItemClickListener = onItemClickListener; } @@ -47,13 +50,11 @@ public class SubscribedUserRecyclerViewAdapter extends RecyclerView.Adapter<Recy @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int i) { - viewHolder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - //Need to be implemented - - mOnItemClickListener.onClick(); - } + viewHolder.itemView.setOnClickListener(view -> { + Intent intent = new Intent(mContext, ViewUserDetailActivity.class); + intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mSubscribedUserData.get(viewHolder.getAdapterPosition()).getName()); + mContext.startActivity(intent); + mOnItemClickListener.onClick(); }); if(!mSubscribedUserData.get(i).getIconUrl().equals("")) { glide.load(mSubscribedUserData.get(i).getIconUrl()) diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/UserFollowing.java b/app/src/main/java/ml/docilealligator/infinityforreddit/UserFollowing.java new file mode 100644 index 00000000..c5af5a26 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/UserFollowing.java @@ -0,0 +1,117 @@ +package ml.docilealligator.infinityforreddit; + +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.support.annotation.NonNull; +import android.util.Log; + +import java.util.HashMap; +import java.util.Map; + +import SubscribedUserDatabase.SubscribedUserDao; +import SubscribedUserDatabase.SubscribedUserData; +import User.UserData; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Retrofit; + +class UserFollowing { + interface UserFollowingListener { + void onUserFollowingSuccess(); + void onUserFollowingFail(); + } + + static void followUser(Retrofit oauthRetrofit, Retrofit retrofit, + SharedPreferences authInfoSharedPreferences, String userName, + SubscribedUserDao subscribedUserDao, + UserFollowingListener userFollowingListener) { + userFollowing(oauthRetrofit, retrofit, authInfoSharedPreferences, userName, "sub", + subscribedUserDao, userFollowingListener); + } + + static void unfollowUser(Retrofit oauthRetrofit, Retrofit retrofit, + SharedPreferences authInfoSharedPreferences, String userName, + SubscribedUserDao subscribedUserDao, + UserFollowingListener userFollowingListener) { + userFollowing(oauthRetrofit, retrofit, authInfoSharedPreferences, userName, "unsub", + subscribedUserDao, userFollowingListener); + } + + private static void userFollowing(Retrofit oauthRetrofit, Retrofit retrofit, SharedPreferences authInfoSharedPreferences, + String userName, String action, SubscribedUserDao subscribedUserDao, + UserFollowingListener userFollowingListener) { + RedditAPI api = oauthRetrofit.create(RedditAPI.class); + + String accessToken = authInfoSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); + + Map<String, String> params = new HashMap<>(); + params.put(RedditUtils.ACTION_KEY, action); + params.put(RedditUtils.SR_KEY, "u/" + userName); + + Call<String> subredditSubscriptionCall = api.subredditSubscription(RedditUtils.getOAuthHeader(accessToken), params); + subredditSubscriptionCall.enqueue(new Callback<String>() { + @Override + public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) { + if(response.isSuccessful()) { + if(action.equals("sub")) { + FetchUserData.fetchUserData(retrofit, userName, new FetchUserData.FetchUserDataListener() { + @Override + public void onFetchUserDataSuccess(UserData userData) { + new UpdateSubscriptionAsyncTask(subscribedUserDao, userData, true).execute(); + } + + @Override + public void onFetchUserDataFail() { + + } + }); + } else { + new UpdateSubscriptionAsyncTask(subscribedUserDao, userName, false).execute(); + } + userFollowingListener.onUserFollowingSuccess(); + } else { + Log.i("call failed", response.message()); + userFollowingListener.onUserFollowingFail(); + } + } + + @Override + public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) { + Log.i("call failed", t.getMessage()); + userFollowingListener.onUserFollowingFail(); + } + }); + } + + private static class UpdateSubscriptionAsyncTask extends AsyncTask<Void, Void, Void> { + + private SubscribedUserDao subscribedUserDao; + private String userName; + private SubscribedUserData subscribedUserData; + private boolean isSubscribing; + + UpdateSubscriptionAsyncTask(SubscribedUserDao subscribedUserDao, String userName, + boolean isSubscribing) { + this.subscribedUserDao = subscribedUserDao; + this.userName = userName; + this.isSubscribing = isSubscribing; + } + + UpdateSubscriptionAsyncTask(SubscribedUserDao subscribedUserDao, SubscribedUserData subscribedUserData, + boolean isSubscribing) { + this.subscribedUserDao = subscribedUserDao; + this.subscribedUserData = subscribedUserData; + this.isSubscribing = isSubscribing; + } + + @Override + protected Void doInBackground(Void... voids) { + if(isSubscribing) { + subscribedUserDao.insert(subscribedUserData); + } else { + subscribedUserDao.deleteSubscribedUser(userName);; + } + return null; + } + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewSubredditDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewSubredditDetailActivity.java index cf9b0f9a..67042e55 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewSubredditDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewSubredditDetailActivity.java @@ -22,7 +22,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; -import android.widget.Toast; import com.bumptech.glide.Glide; import com.bumptech.glide.RequestManager; @@ -104,11 +103,11 @@ public class ViewSubredditDetailActivity extends AppCompatActivity { ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams(); params.topMargin = statusBarHeight; - final String subredditName = getIntent().getExtras().getString(EXTRA_SUBREDDIT_NAME_KEY); + String subredditName = getIntent().getExtras().getString(EXTRA_SUBREDDIT_NAME_KEY); - final String title = "r/" + subredditName; - final CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar_layout_view_subreddit_detail_activity); - final AppBarLayout appBarLayout = findViewById(R.id.app_bar_layout_view_subreddit_detail_activity); + String title = "r/" + subredditName; + CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar_layout_view_subreddit_detail_activity); + AppBarLayout appBarLayout = findViewById(R.id.app_bar_layout_view_subreddit_detail_activity); appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { int previousVerticalOffset = 0; @@ -136,10 +135,10 @@ public class ViewSubredditDetailActivity extends AppCompatActivity { }); subscribedSubredditDao = SubscribedSubredditRoomDatabase.getDatabase(this).subscribedSubredditDao(); - glide = Glide.with(ViewSubredditDetailActivity.this); + glide = Glide.with(this); - SubredditViewModel.Factory factory = new SubredditViewModel.Factory(getApplication(), subredditName); - mSubredditViewModel = ViewModelProviders.of(this, factory).get(SubredditViewModel.class); + mSubredditViewModel = ViewModelProviders.of(this, new SubredditViewModel.Factory(getApplication(), subredditName)) + .get(SubredditViewModel.class); mSubredditViewModel.getSubredditLiveData().observe(this, subredditData -> { if(subredditData != null) { if(subredditData.getBannerUrl().equals("")) { @@ -279,7 +278,7 @@ public class ViewSubredditDetailActivity extends AppCompatActivity { @Override public void onParseSubredditDataFail() { - Toast.makeText(ViewSubredditDetailActivity.this, "Cannot fetch subreddit info", Toast.LENGTH_SHORT).show(); + makeSnackbar(R.string.cannot_fetch_subreddit_info); } }); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java index 0ec59030..8b3fa0a1 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java @@ -1,13 +1,78 @@ package ml.docilealligator.infinityforreddit; +import android.arch.lifecycle.ViewModelProviders; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.chip.Chip; +import android.support.design.widget.AppBarLayout; +import android.support.design.widget.CollapsingToolbarLayout; +import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestManager; +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.RequestOptions; +import com.bumptech.glide.request.target.Target; +import com.felipecsl.gifimageview.library.GifImageView; + +import javax.inject.Inject; +import javax.inject.Named; + +import SubscribedUserDatabase.SubscribedUserDao; +import SubscribedUserDatabase.SubscribedUserData; +import SubscribedUserDatabase.SubscribedUserRoomDatabase; +import User.UserDao; +import User.UserData; +import User.UserRoomDatabase; +import User.UserViewModel; +import butterknife.BindView; +import butterknife.ButterKnife; +import jp.wasabeef.glide.transformations.RoundedCornersTransformation; +import retrofit2.Retrofit; public class ViewUserDetailActivity extends AppCompatActivity { static final String EXTRA_USER_NAME_KEY = "EUNK"; + @BindView(R.id.coordinator_layout_view_user_detail_activity) CoordinatorLayout coordinatorLayout; + @BindView(R.id.banner_image_view_view_user_detail_activity) ImageView bannerImageView; + @BindView(R.id.icon_gif_image_view_view_user_detail_activity) GifImageView iconGifImageView; + @BindView(R.id.user_name_text_view_view_user_detail_activity) TextView userNameTextView; + @BindView(R.id.subscribe_user_chip_view_user_detail_activity) Chip subscribeUserChip; + @BindView(R.id.karma_text_view_view_user_detail_activity) TextView karmaTextView; + + private SubscribedUserDao subscribedUserDao; + private RequestManager glide; + private UserViewModel userViewModel; + + private boolean subscriptionReady = false; + + @Inject + @Named("no_oauth") + Retrofit mRetrofit; + + @Inject + @Named("oauth") + Retrofit mOauthRetrofit; + + @Inject + @Named("auth_info") + SharedPreferences sharedPreferences; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -15,6 +80,254 @@ public class ViewUserDetailActivity extends AppCompatActivity { Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); - + ButterKnife.bind(this); + + ((Infinity) getApplication()).getmNetworkComponent().inject(this); + + setSupportActionBar(toolbar); + + //Get status bar height + int statusBarHeight = 0; + int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resourceId > 0) { + statusBarHeight = getResources().getDimensionPixelSize(resourceId); + } + + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams(); + params.topMargin = statusBarHeight; + + String userName = getIntent().getExtras().getString(EXTRA_USER_NAME_KEY); + String title = "u/" + userName; + + CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar_layout_view_user_detail_activity); + AppBarLayout appBarLayout = findViewById(R.id.app_bar_layout_view_user_detail_activity); + + appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { + int previousVerticalOffset = 0; + int scrollRange = -1; + + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { + if(scrollRange == -1) { + scrollRange = appBarLayout.getTotalScrollRange(); + } else { + if(verticalOffset < previousVerticalOffset) { + //Scroll down + if(scrollRange - Math.abs(verticalOffset) <= toolbar.getHeight()) { + collapsingToolbarLayout.setTitle(title); + } + } else { + //Scroll up + if(scrollRange - Math.abs(verticalOffset) > toolbar.getHeight()) { + collapsingToolbarLayout.setTitle(" ");//carefull there should a space between double quote otherwise it wont work + } + } + previousVerticalOffset = verticalOffset; + } + } + }); + + subscribeUserChip.setOnClickListener(view -> { + if(subscriptionReady) { + subscriptionReady = false; + if(subscribeUserChip.getText().equals(getResources().getString(R.string.subscribe))) { + UserFollowing.followUser(mOauthRetrofit, mRetrofit, sharedPreferences, + userName, subscribedUserDao, new UserFollowing.UserFollowingListener() { + @Override + public void onUserFollowingSuccess() { + subscribeUserChip.setText(R.string.unfollow); + subscribeUserChip.setChipBackgroundColor(getResources().getColorStateList(R.color.colorAccent)); + makeSnackbar(R.string.followed); + subscriptionReady = true; + } + + @Override + public void onUserFollowingFail() { + makeSnackbar(R.string.follow_failed); + subscriptionReady = true; + } + }); + } else { + UserFollowing.unfollowUser(mOauthRetrofit, mRetrofit, sharedPreferences, + userName, subscribedUserDao, new UserFollowing.UserFollowingListener() { + @Override + public void onUserFollowingSuccess() { + subscribeUserChip.setText(R.string.follow); + subscribeUserChip.setChipBackgroundColor(getResources().getColorStateList(R.color.colorPrimaryDark)); + makeSnackbar(R.string.unfollowed); + subscriptionReady = true; + } + + @Override + public void onUserFollowingFail() { + makeSnackbar(R.string.unfollow_failed); + subscriptionReady = true; + } + }); + } + } + }); + + subscribedUserDao = SubscribedUserRoomDatabase.getDatabase(this).subscribedUserDao(); + + new CheckIsFollowingUserAsyncTask(subscribedUserDao, userName, new CheckIsFollowingUserAsyncTask.CheckIsFollowingUserListener() { + @Override + public void isSubscribed() { + subscribeUserChip.setText(R.string.unfollow); + subscribeUserChip.setChipBackgroundColor(getResources().getColorStateList(R.color.colorAccent)); + subscriptionReady = true; + } + + @Override + public void isNotSubscribed() { + subscribeUserChip.setText(R.string.follow); + subscribeUserChip.setChipBackgroundColor(getResources().getColorStateList(R.color.colorPrimaryDark)); + subscriptionReady = true; + } + }).execute(); + + glide = Glide.with(this); + + userViewModel = ViewModelProviders.of(this, new UserViewModel.Factory(getApplication(), userName)) + .get(UserViewModel.class); + userViewModel.getUserLiveData().observe(this, userData -> { + if(userData != null) { + if(userData.getBanner().equals("")) { + bannerImageView.setOnClickListener(view -> { + //Do nothing since the user has no banner image + }); + } else { + glide.load(userData.getBanner()).into(bannerImageView); + bannerImageView.setOnClickListener(view -> { + Intent intent = new Intent(this, ViewImageActivity.class); + intent.putExtra(ViewImageActivity.TITLE_KEY, title); + intent.putExtra(ViewImageActivity.IMAGE_URL_KEY, userData.getBanner()); + intent.putExtra(ViewImageActivity.FILE_NAME_KEY, userName + "-banner"); + startActivity(intent); + }); + } + + if(userData.getIconUrl().equals("")) { + glide.load(getDrawable(R.drawable.subreddit_default_icon)) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(216, 0))) + .into(iconGifImageView); + iconGifImageView.setOnClickListener(view -> { + //Do nothing since the user has no icon image + }); + } else { + glide.load(userData.getIconUrl()) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(216, 0))) + .error(glide.load(R.drawable.subreddit_default_icon)) + .listener(new RequestListener<Drawable>() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) { + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) { + if(resource instanceof Animatable) { + //This is a gif + ((Animatable) resource).start(); + iconGifImageView.startAnimation(); + } + return false; + } + }) + .into(iconGifImageView); + iconGifImageView.setOnClickListener(view -> { + Intent intent = new Intent(this, ViewImageActivity.class); + intent.putExtra(ViewImageActivity.TITLE_KEY, title); + intent.putExtra(ViewImageActivity.IMAGE_URL_KEY, userData.getIconUrl()); + intent.putExtra(ViewImageActivity.FILE_NAME_KEY, userName + "-icon"); + startActivity(intent); + }); + } + + String userFullName = "u/" + userData.getName(); + userNameTextView.setText(userFullName); + String karma = getString(R.string.karma_info, userData.getKarma()); + karmaTextView.setText(karma); + } + }); + + FetchUserData.fetchUserData(mRetrofit, userName, new FetchUserData.FetchUserDataListener() { + @Override + public void onFetchUserDataSuccess(UserData userData) { + new InsertUserDataAsyncTask(UserRoomDatabase.getDatabase(ViewUserDetailActivity.this).userDao(), userData).execute(); + } + + @Override + public void onFetchUserDataFail() { + makeSnackbar(R.string.cannot_fetch_user_info); + } + }); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + } + return false; + } + + private void makeSnackbar(int resId) { + Snackbar.make(coordinatorLayout, resId, Snackbar.LENGTH_SHORT).show(); + } + + private static class InsertUserDataAsyncTask extends AsyncTask<Void, Void, Void> { + + private UserDao userDao; + private UserData subredditData; + + InsertUserDataAsyncTask(UserDao userDao, UserData userData) { + this.userDao = userDao; + this.subredditData = userData; + } + + @Override + protected Void doInBackground(final Void... params) { + userDao.insert(subredditData); + return null; + } + } + + private static class CheckIsFollowingUserAsyncTask extends AsyncTask<Void, Void, Void> { + + private SubscribedUserDao subscribedUserDao; + private String userName; + private SubscribedUserData subscribedUserData; + private CheckIsFollowingUserListener checkIsFollowingUserListener; + + interface CheckIsFollowingUserListener { + void isSubscribed(); + void isNotSubscribed(); + } + + CheckIsFollowingUserAsyncTask(SubscribedUserDao subscribedUserDao, String userName, + CheckIsFollowingUserListener checkIsFollowingUserListener) { + this.subscribedUserDao = subscribedUserDao; + this.userName = userName; + this.checkIsFollowingUserListener = checkIsFollowingUserListener; + } + + @Override + protected Void doInBackground(Void... voids) { + subscribedUserData = subscribedUserDao.getSubscribedUser(userName); + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + if(subscribedUserData != null) { + checkIsFollowingUserListener.isSubscribed(); + } else { + checkIsFollowingUserListener.isNotSubscribed(); + } + } } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4e6dd8aa..5da5a9d3 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -35,6 +35,7 @@ layout="@layout/nav_header_main" /> <LinearLayout + android:id="@+id/profile_linear_layout_main_activity" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" diff --git a/app/src/main/res/layout/activity_view_user_detail.xml b/app/src/main/res/layout/activity_view_user_detail.xml index 76dbba91..a292d390 100644 --- a/app/src/main/res/layout/activity_view_user_detail.xml +++ b/app/src/main/res/layout/activity_view_user_detail.xml @@ -4,33 +4,97 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:fitsSystemWindows="true" + android:id="@+id/coordinator_layout_view_user_detail_activity" tools:context=".ViewUserDetailActivity"> <android.support.design.widget.AppBarLayout - android:id="@+id/app_bar" + android:id="@+id/app_bar_layout_view_user_detail_activity" android:layout_width="match_parent" - android:layout_height="@dimen/app_bar_height" - android:fitsSystemWindows="true" + android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.design.widget.CollapsingToolbarLayout - android:id="@+id/toolbar_layout" + android:id="@+id/collapsing_toolbar_layout_view_user_detail_activity" android:layout_width="match_parent" android:layout_height="match_parent" - android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" - app:layout_scrollFlags="scroll|exitUntilCollapsed" + app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed" app:toolbarId="@+id/toolbar"> + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ImageView + android:id="@+id/banner_image_view_view_user_detail_activity" + android:layout_width="match_parent" + android:scaleType="centerCrop" + android:layout_height="180dp" + android:contentDescription="@string/content_description_banner_imageview" /> + + <com.felipecsl.gifimageview.library.GifImageView + android:id="@+id/icon_gif_image_view_view_user_detail_activity" + android:layout_width="72dp" + android:layout_height="72dp" + android:layout_marginTop="-36dp" + app:civ_border_color="@android:color/white" + app:civ_border_width="1dp" + android:layout_below="@id/banner_image_view_view_user_detail_activity" + android:layout_centerHorizontal="true" + android:elevation="4dp" + app:civ_circle_background_color="@android:color/white"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingTop="36dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:layout_below="@id/banner_image_view_view_user_detail_activity" + android:background="@android:color/white"> + + <TextView + android:id="@+id/user_name_text_view_view_user_detail_activity" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:textSize="18sp" + android:textColor="@color/colorAccent" + android:layout_gravity="center_horizontal"/> + + <TextView + android:id="@+id/karma_text_view_view_user_detail_activity" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:textColor="@android:color/black" + android:layout_gravity="center_horizontal"/> + + <android.support.design.chip.Chip + android:id="@+id/subscribe_user_chip_view_user_detail_activity" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:layout_marginBottom="16dp" + android:textColor="@android:color/white" + android:layout_gravity="center_horizontal"/> + + </LinearLayout> + + </RelativeLayout> + <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" - app:popupTheme="@style/AppTheme.PopupOverlay" /> + app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed" + app:popupTheme="@style/AppTheme.PopupOverlay" + app:navigationIcon="?attr/homeAsUpIndicator"/> </android.support.design.widget.CollapsingToolbarLayout> + </android.support.design.widget.AppBarLayout> <include layout="@layout/content_view_user_detail" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7084659c..cab97bbb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -26,6 +26,8 @@ <string name="subscriptions">Subscriptions</string> <string name="subscribers_number_detail">Subscribers: %1$d</string> <string name="online_subscribers_number_detail">Online: %1$d</string> + <string name="cannot_fetch_subreddit_info">Cannot fetch subreddit info</string> + <string name="cannot_fetch_user_info">Cannot fetch user info</string> <string name="gilded">x%1$d</string> <string name="title_activity_view_user_detail">ViewUserDetailActivity</string> @@ -49,15 +51,15 @@ "and use of imagery guide visual treatments. These elements do far more than please the " "eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge " "imagery, large scale typography, and intentional white space create a bold and graphic " - "interface that immerse the user in the experience.\n" - "An emphasis on user actions makes core functionality immediately apparent and provides " - "waypoints for the user.\n\n" + "interface that immerse the userData in the experience.\n" + "An emphasis on userData actions makes core functionality immediately apparent and provides " + "waypoints for the userData.\n\n" "Motion provides meaning.\n\n" - "Motion respects and reinforces the user as the prime mover. Primary user actions are " + "Motion respects and reinforces the userData as the prime mover. Primary userData actions are " "inflection points that initiate motion, transforming the whole design.\n" - "All action takes place in a single environment. Objects are presented to the user without " + "All action takes place in a single environment. Objects are presented to the userData without " "breaking the continuity of experience even as they transform and reorganize.\n" "Motion is meaningful and appropriate, serving to focus attention and maintain continuity. " "Feedback is subtle yet clear. Transitions are efficient yet coherent.\n\n" @@ -96,7 +98,7 @@ "Responsive elevation and dynamic elevation offsets.\n\n" "Some component types have responsive elevation, meaning they change elevation in response " - "to user input (e.g., normal, focused, and pressed) or system events. These elevation " + "to userData input (e.g., normal, focused, and pressed) or system events. These elevation " "changes are consistently implemented using dynamic elevation offsets.\n" "Dynamic elevation offsets are the goal elevation that a component moves towards, relative " "to the component’s resting state. They ensure that elevation changes are consistent " @@ -113,10 +115,10 @@ "whether on a per component basis or using the entire app layout.\n" "On a component level, components can move or be removed before they cause interference. " "For example, a floating action button (FAB) can disappear or move off screen before a " - "user picks up a card, or it can move if a snackbar appears.\n" + "userData picks up a card, or it can move if a snackbar appears.\n" "On the layout level, design your app layout to minimize opportunities for interference. " "For example, position the FAB to one side of stream of a cards so the FAB won’t interfere " - "when a user tries to pick up one of cards.\n\n" + "when a userData tries to pick up one of cards.\n\n" </string> <string name="subscribe">Subscribe</string> @@ -126,5 +128,12 @@ <string name="unsubscribed">Unsubscribed</string>" <string name="unsubscribe_failed">Unsubscribe Failed</string> + <string name="follow">Follow</string> + <string name="unfollow">Unfollow</string> + <string name="followed">Followed</string> + <string name="follow_failed">Following Failed</string> + <string name="unfollowed">Unfollowed</string> + <string name="unfollow_failed">Unfollowing Failed</string> + <string name="content_description_banner_imageview">Subreddit Banner Image</string> </resources> @@ -119,7 +119,7 @@ if $cygwin ; then SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments + # Add a userData-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi |