View user details in ViewUserDetailActivity. Follow or unfollow user is not properly implemented right now. Change users and subscribed_users databases' schemes. Press Profile in navigation drawer to view my reddit info. Press the username in the post to view that account's info.

This commit is contained in:
Alex Ning 2019-01-11 11:33:32 +08:00
parent f0b149ce82
commit e48bb565a5
29 changed files with 704 additions and 120 deletions

View File

@ -50,8 +50,8 @@
android:theme="@style/AppTheme.NoActionBarWithTranslucentStatusBar" /> android:theme="@style/AppTheme.NoActionBarWithTranslucentStatusBar" />
<activity <activity
android:name=".ViewUserDetailActivity" android:name=".ViewUserDetailActivity"
android:label="@string/title_activity_view_user_detail" android:parentActivityName=".MainActivity"
android:theme="@style/AppTheme.NoActionBar" /> android:theme="@style/AppTheme.NoActionBarWithTranslucentStatusBar" />
</application> </application>
</manifest> </manifest>

View File

@ -14,7 +14,7 @@ public interface SubredditDao {
@Query("DELETE FROM subreddits") @Query("DELETE FROM subreddits")
void deleteAllSubreddits(); void deleteAllSubreddits();
@Query("SELECT * from subreddits WHERE name = :namePrefixed") @Query("SELECT * from subreddits WHERE name = :namePrefixed LIMIT 1")
LiveData<SubredditData> getSubredditLiveDataByName(String namePrefixed); LiveData<SubredditData> getSubredditLiveDataByName(String namePrefixed);
@Query("SELECT * from subreddits WHERE name = :namePrefixed LIMIT 1") @Query("SELECT * from subreddits WHERE name = :namePrefixed LIMIT 1")

View File

@ -20,14 +20,14 @@ public class SubredditRepository {
} }
public void insert(SubredditData subredditData) { 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; private SubredditDao mAsyncTaskDao;
insertAsyncTask(SubredditDao dao) { InsertAsyncTask(SubredditDao dao) {
mAsyncTaskDao = dao; mAsyncTaskDao = dao;
} }

View File

@ -11,7 +11,7 @@ public class SubredditViewModel extends AndroidViewModel {
private SubredditRepository mSubredditRepository; private SubredditRepository mSubredditRepository;
private LiveData<SubredditData> mSubredditLiveData; private LiveData<SubredditData> mSubredditLiveData;
SubredditViewModel(Application application, String id) { public SubredditViewModel(Application application, String id) {
super(application); super(application);
mSubredditRepository = new SubredditRepository(application, id); mSubredditRepository = new SubredditRepository(application, id);
mSubredditLiveData = mSubredditRepository.getSubredditLiveData(); mSubredditLiveData = mSubredditRepository.getSubredditLiveData();

View File

@ -16,6 +16,12 @@ public interface SubscribedUserDao {
@Query("DELETE FROM subscribed_users") @Query("DELETE FROM subscribed_users")
void deleteAllSubscribedUsers(); 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(); 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);
} }

View File

@ -9,24 +9,17 @@ import android.support.annotation.NonNull;
public class SubscribedUserData { public class SubscribedUserData {
@PrimaryKey @PrimaryKey
@NonNull @NonNull
@ColumnInfo(name = "id")
private String id;
@ColumnInfo(name = "name") @ColumnInfo(name = "name")
private String name; private String name;
@ColumnInfo(name = "icon") @ColumnInfo(name = "icon")
private String iconUrl; private String iconUrl;
public SubscribedUserData(@NonNull String id, String name, String iconUrl) { public SubscribedUserData(@NonNull String name, String iconUrl) {
this.id = id;
this.name = name; this.name = name;
this.iconUrl = iconUrl; this.iconUrl = iconUrl;
} }
@NonNull @NonNull
public String getId() {
return id;
}
public String getName() { public String getName() {
return name; return name;
} }

View File

@ -1,5 +1,6 @@
package User; package User;
import android.arch.lifecycle.LiveData;
import android.arch.persistence.room.Dao; import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert; import android.arch.persistence.room.Insert;
import android.arch.persistence.room.OnConflictStrategy; import android.arch.persistence.room.OnConflictStrategy;
@ -8,11 +9,14 @@ import android.arch.persistence.room.Query;
@Dao @Dao
public interface UserDao { public interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(User user); void insert(UserData userData);
@Query("DELETE FROM users") @Query("DELETE FROM users")
void deleteAllUsers(); void deleteAllUsers();
@Query("SELECT * FROM users WHERE user_name = :userName LIMIT 1") @Query("SELECT * FROM users WHERE name = :userName LIMIT 1")
User getUserData(String userName); LiveData<UserData> getUserLiveData(String userName);
@Query("SELECT * FROM users WHERE name = :userName LIMIT 1")
UserData getUserData(String userName);
} }

View File

@ -2,17 +2,12 @@ package User;
import android.arch.persistence.room.ColumnInfo; import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity; import android.arch.persistence.room.Entity;
import android.arch.persistence.room.PrimaryKey;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import SubscribedUserDatabase.SubscribedUserData;
@Entity(tableName = "users") @Entity(tableName = "users")
public class User { public class UserData extends SubscribedUserData {
@PrimaryKey
@NonNull
@ColumnInfo(name = "user_name")
private String userName;
@ColumnInfo(name = "icon")
private String icon;
@ColumnInfo(name = "banner") @ColumnInfo(name = "banner")
private String banner; private String banner;
@ColumnInfo(name = "karma") @ColumnInfo(name = "karma")
@ -22,24 +17,14 @@ public class User {
@ColumnInfo(name = "is_friend") @ColumnInfo(name = "is_friend")
private boolean isFriend; private boolean isFriend;
User(@NonNull String userName, String icon, String banner, int karma, boolean isGold, boolean isFriend) { public UserData(@NonNull String name, String iconUrl, String banner, int karma, boolean isGold, boolean isFriend) {
this.userName = userName; super(name, iconUrl);
this.icon = icon;
this.banner = banner; this.banner = banner;
this.karma = karma; this.karma = karma;
this.isGold = isGold; this.isGold = isGold;
this.isFriend = isFriend; this.isFriend = isFriend;
} }
@NonNull
public String getUserName() {
return userName;
}
public String getIcon() {
return icon;
}
public String getBanner() { public String getBanner() {
return banner; return banner;
} }

View File

@ -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;
}
}
}

View File

@ -5,7 +5,7 @@ import android.arch.persistence.room.Room;
import android.arch.persistence.room.RoomDatabase; import android.arch.persistence.room.RoomDatabase;
import android.content.Context; import android.content.Context;
@Database(entities = {User.class}, version = 1) @Database(entities = {UserData.class}, version = 1)
public abstract class UserRoomDatabase extends RoomDatabase { public abstract class UserRoomDatabase extends RoomDatabase {
private static UserRoomDatabase INSTANCE; private static UserRoomDatabase INSTANCE;

View File

@ -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);
}
}
}

View File

@ -1,16 +1,16 @@
package User; package ml.docilealligator.infinityforreddit;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import ml.docilealligator.infinityforreddit.RedditAPI; import User.UserData;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Retrofit; import retrofit2.Retrofit;
public class FetchUserData { public class FetchUserData {
public interface FetchUserDataListener { public interface FetchUserDataListener {
void onFetchUserDataSuccess(User user); void onFetchUserDataSuccess(UserData userData);
void onFetchUserDataFail(); void onFetchUserDataFail();
} }
@ -23,10 +23,10 @@ public class FetchUserData {
@Override @Override
public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) { public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) {
if(response.isSuccessful()) { if(response.isSuccessful()) {
ParseUserData.parseMyInfo(response.body(), new ParseUserData.ParseUserDataListener() { ParseUserData.parseUserData(response.body(), new ParseUserData.ParseUserDataListener() {
@Override @Override
public void onParseUserDataSuccess(User user) { public void onParseUserDataSuccess(UserData userData) {
fetchUserDataListener.onFetchUserDataSuccess(user); fetchUserDataListener.onFetchUserDataSuccess(userData);
} }
@Override @Override

View File

@ -2,27 +2,27 @@ package ml.docilealligator.infinityforreddit;
import android.os.AsyncTask; import android.os.AsyncTask;
import User.User; import User.UserData;
import User.UserDao; import User.UserDao;
public class InsertUserDataAsyncTask extends AsyncTask<Void, Void, Void> { public class InsertUserDataAsyncTask extends AsyncTask<Void, Void, Void> {
private UserDao userDao; private UserDao userDao;
private User user; private UserData userData;
private InsertUserDataCallback insertUserDataCallback; private InsertUserDataCallback insertUserDataCallback;
public interface InsertUserDataCallback { public interface InsertUserDataCallback {
void insertSuccess(); void insertSuccess();
} }
public InsertUserDataAsyncTask(UserDao userDao, User user, InsertUserDataCallback insertUserDataCallback) { public InsertUserDataAsyncTask(UserDao userDao, UserData userData, InsertUserDataCallback insertUserDataCallback) {
this.userDao = userDao; this.userDao = userDao;
this.user = user; this.userData = userData;
this.insertUserDataCallback = insertUserDataCallback; this.insertUserDataCallback = insertUserDataCallback;
} }
@Override @Override
protected Void doInBackground(Void... voids) { protected Void doInBackground(Void... voids) {
userDao.insert(user); userDao.insert(userData);
return null; return null;
} }

View File

@ -2,8 +2,7 @@ package ml.docilealligator.infinityforreddit;
import android.os.AsyncTask; import android.os.AsyncTask;
import User.FetchUserData; import User.UserData;
import User.User;
import User.UserDao; import User.UserDao;
import retrofit2.Retrofit; import retrofit2.Retrofit;
@ -29,7 +28,7 @@ public class LoadUserDataAsyncTask extends AsyncTask<Void, Void, Void> {
@Override @Override
protected Void doInBackground(Void... voids) { protected Void doInBackground(Void... voids) {
if(userDao.getUserData(userName) != null) { if(userDao.getUserData(userName) != null) {
iconImageUrl = userDao.getUserData(userName).getIcon(); iconImageUrl = userDao.getUserData(userName).getIconUrl();
hasUserInDb = true; hasUserInDb = true;
} else { } else {
hasUserInDb = false; hasUserInDb = false;
@ -45,13 +44,8 @@ public class LoadUserDataAsyncTask extends AsyncTask<Void, Void, Void> {
} else { } else {
FetchUserData.fetchUserData(retrofit, userName, new FetchUserData.FetchUserDataListener() { FetchUserData.fetchUserData(retrofit, userName, new FetchUserData.FetchUserDataListener() {
@Override @Override
public void onFetchUserDataSuccess(User user) { public void onFetchUserDataSuccess(UserData userData) {
new InsertUserDataAsyncTask(userDao, user, new InsertUserDataAsyncTask.InsertUserDataCallback() { new InsertUserDataAsyncTask(userDao, userData, () -> loadUserDataAsyncTaskListener.loadUserDataSuccess(userData.getIconUrl())).execute();
@Override
public void insertSuccess() {
loadUserDataAsyncTaskListener.loadUserDataSuccess(user.getIcon());
}
}).execute();
} }
@Override @Override

View File

@ -20,6 +20,7 @@ import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.bumptech.glide.Glide; 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.subscriptions_label_main_activity) TextView subscriptionsLabelTextView;
@BindView(R.id.subscribed_user_recycler_view_main_activity) RecyclerView subscribedUserRecyclerView; @BindView(R.id.subscribed_user_recycler_view_main_activity) RecyclerView subscribedUserRecyclerView;
@BindView(R.id.following_label_main_activity) TextView followingLabelTextView; @BindView(R.id.following_label_main_activity) TextView followingLabelTextView;
@BindView(R.id.profile_linear_layout_main_activity) LinearLayout profileLinearLayout;
private TextView mNameTextView; private TextView mNameTextView;
private TextView mKarmaTextView; private TextView mKarmaTextView;
@ -153,13 +155,14 @@ public class MainActivity extends AppCompatActivity {
glide.load(mBannerImageUrl).into(mBannerImageView); glide.load(mBannerImageUrl).into(mBannerImageView);
} }
final SubscribedSubredditRecyclerViewAdapter subredditadapter = new SubscribedSubredditRecyclerViewAdapter(this, profileLinearLayout.setOnClickListener(view -> {
new SubscribedSubredditRecyclerViewAdapter.OnItemClickListener() { Intent intent = new Intent(MainActivity.this, ViewUserDetailActivity.class);
@Override intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mName);
public void onClick() { startActivity(intent);
drawer.closeDrawers(); });
}
}); final SubscribedSubredditRecyclerViewAdapter subredditadapter =
new SubscribedSubredditRecyclerViewAdapter(this, drawer::closeDrawers);
subscribedSubredditRecyclerView.setAdapter(subredditadapter); subscribedSubredditRecyclerView.setAdapter(subredditadapter);
mSubscribedSubredditViewModel = ViewModelProviders.of(this).get(SubscribedSubredditViewModel.class); mSubscribedSubredditViewModel = ViewModelProviders.of(this).get(SubscribedSubredditViewModel.class);
@ -176,13 +179,8 @@ public class MainActivity extends AppCompatActivity {
} }
}); });
final SubscribedUserRecyclerViewAdapter userAdapter = new SubscribedUserRecyclerViewAdapter(this, final SubscribedUserRecyclerViewAdapter userAdapter =
new SubscribedUserRecyclerViewAdapter.OnItemClickListener() { new SubscribedUserRecyclerViewAdapter(this, drawer::closeDrawers);
@Override
public void onClick() {
drawer.closeDrawers();
}
});
subscribedUserRecyclerView.setAdapter(userAdapter); subscribedUserRecyclerView.setAdapter(userAdapter);
mSubscribedUserViewModel = ViewModelProviders.of(this).get(SubscribedUserViewModel.class); mSubscribedUserViewModel = ViewModelProviders.of(this).get(SubscribedUserViewModel.class);
mSubscribedUserViewModel.getAllSubscribedUsers().observe(this, new Observer<List<SubscribedUserData>>() { mSubscribedUserViewModel.getAllSubscribedUsers().observe(this, new Observer<List<SubscribedUserData>>() {

View File

@ -11,4 +11,5 @@ interface NetworkComponent {
void inject(PostFragment postFragment); void inject(PostFragment postFragment);
void inject(ViewPostDetailActivity viewPostDetailActivity); void inject(ViewPostDetailActivity viewPostDetailActivity);
void inject(ViewSubredditDetailActivity viewSubredditDetailActivity); void inject(ViewSubredditDetailActivity viewSubredditDetailActivity);
void inject(ViewUserDetailActivity viewUserDetailActivity);
} }

View File

@ -94,7 +94,7 @@ class ParseSubscribedThing {
if(data.getString(JSONUtils.SUBREDDIT_TYPE_KEY) if(data.getString(JSONUtils.SUBREDDIT_TYPE_KEY)
.equals(JSONUtils.SUBREDDIT_TYPE_VALUE_USER)) { .equals(JSONUtils.SUBREDDIT_TYPE_VALUE_USER)) {
//It's a user //It's a user
newSubscribedUserData.add(new SubscribedUserData(id, name.substring(2), iconUrl)); newSubscribedUserData.add(new SubscribedUserData(name.substring(2), iconUrl));
} else { } else {
String subredditFullName = data.getString(JSONUtils.DISPLAY_NAME); String subredditFullName = data.getString(JSONUtils.DISPLAY_NAME);
String description = data.getString(JSONUtils.PUBLIC_DESCRIPTION_KEY).trim(); String description = data.getString(JSONUtils.PUBLIC_DESCRIPTION_KEY).trim();

View File

@ -1,4 +1,4 @@
package User; package ml.docilealligator.infinityforreddit;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
@ -6,15 +6,15 @@ import android.util.Log;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import ml.docilealligator.infinityforreddit.JSONUtils; import User.UserData;
public class ParseUserData { public class ParseUserData {
interface ParseUserDataListener { interface ParseUserDataListener {
void onParseUserDataSuccess(User user); void onParseUserDataSuccess(UserData userData);
void onParseUserDataFail(); void onParseUserDataFail();
} }
static void parseMyInfo(String response, ParseUserDataListener parseUserDataListener) { static void parseUserData(String response, ParseUserDataListener parseUserDataListener) {
new ParseUserDataAsyncTask(response, parseUserDataListener).execute(); new ParseUserDataAsyncTask(response, parseUserDataListener).execute();
} }
@ -23,15 +23,16 @@ public class ParseUserData {
private ParseUserDataListener parseUserDataListener; private ParseUserDataListener parseUserDataListener;
private boolean parseFailed; private boolean parseFailed;
private User user; private UserData userData;
ParseUserDataAsyncTask(String response, ParseUserDataListener parseUserDataListener){ ParseUserDataAsyncTask(String response, ParseUserDataListener parseUserDataListener){
try { try {
Log.i("response", response);
jsonResponse = new JSONObject(response); jsonResponse = new JSONObject(response);
this.parseUserDataListener = parseUserDataListener; this.parseUserDataListener = parseUserDataListener;
parseFailed = false; parseFailed = false;
} catch (JSONException e) { } catch (JSONException e) {
Log.i("user data json error", e.getMessage()); Log.i("userdata json error", e.getMessage());
parseUserDataListener.onParseUserDataFail(); parseUserDataListener.onParseUserDataFail();
} }
} }
@ -43,7 +44,7 @@ public class ParseUserData {
String userName = jsonResponse.getString(JSONUtils.NAME_KEY); String userName = jsonResponse.getString(JSONUtils.NAME_KEY);
String iconImageUrl = jsonResponse.getString(JSONUtils.ICON_IMG_KEY); String iconImageUrl = jsonResponse.getString(JSONUtils.ICON_IMG_KEY);
String bannerImageUrl = ""; 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); bannerImageUrl = jsonResponse.getJSONObject(JSONUtils.SUBREDDIT_KEY).getString(JSONUtils.BANNER_IMG_KEY);
} }
int linkKarma = jsonResponse.getInt(JSONUtils.LINK_KARMA_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 isGold = jsonResponse.getBoolean(JSONUtils.IS_GOLD_KEY);
boolean isFriend = jsonResponse.getBoolean(JSONUtils.IS_FRIEND_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) { } catch (JSONException e) {
parseFailed = true; parseFailed = true;
Log.i("parse user data error", e.getMessage()); Log.i("parse user data error", e.getMessage());
@ -63,7 +64,7 @@ public class ParseUserData {
@Override @Override
protected void onPostExecute(Void aVoid) { protected void onPostExecute(Void aVoid) {
if(!parseFailed) { if(!parseFailed) {
parseUserDataListener.onParseUserDataSuccess(user); parseUserDataListener.onParseUserDataSuccess(userData);
} else { } else {
parseUserDataListener.onParseUserDataFail(); parseUserDataListener.onParseUserDataFail();
} }

View File

@ -300,6 +300,7 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo
if(canStartActivity) { if(canStartActivity) {
canStartActivity = false; canStartActivity = false;
Intent intent = new Intent(mContext, ViewUserDetailActivity.class); Intent intent = new Intent(mContext, ViewUserDetailActivity.class);
intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, post.getAuthor());
mContext.startActivity(intent); mContext.startActivity(intent);
} }
}); });
@ -310,6 +311,7 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo
if(canStartActivity) { if(canStartActivity) {
canStartActivity = false; canStartActivity = false;
Intent intent = new Intent(mContext, ViewUserDetailActivity.class); Intent intent = new Intent(mContext, ViewUserDetailActivity.class);
intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, post.getAuthor());
mContext.startActivity(intent); mContext.startActivity(intent);
} }
}); });

View File

@ -3,11 +3,13 @@ package ml.docilealligator.infinityforreddit;
import java.util.Map; import java.util.Map;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.http.DELETE;
import retrofit2.http.FieldMap; import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded; import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET; import retrofit2.http.GET;
import retrofit2.http.HeaderMap; import retrofit2.http.HeaderMap;
import retrofit2.http.POST; import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Path; import retrofit2.http.Path;
import retrofit2.http.Query; import retrofit2.http.Query;
@ -45,4 +47,10 @@ public interface RedditAPI {
@FormUrlEncoded @FormUrlEncoded
@POST("api/subscribe") @POST("api/subscribe")
Call<String> subredditSubscription(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params); 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);
} }

View File

@ -30,7 +30,7 @@ public class RedditUtils {
static final String AUTHORIZATION_KEY = "Authorization"; static final String AUTHORIZATION_KEY = "Authorization";
static final String AUTHORIZATION_BASE = "bearer "; 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 USER_AGENT = "";
static final String GRANT_TYPE_KEY = "grant_type"; static final String GRANT_TYPE_KEY = "grant_type";
@ -47,6 +47,7 @@ public class RedditUtils {
static final String ACTION_KEY = "action"; static final String ACTION_KEY = "action";
static final String SR_NAME_KEY = "sr_name"; static final String SR_NAME_KEY = "sr_name";
static final String SR_KEY = "sr";
static Map<String, String> getHttpBasicAuthHeader() { static Map<String, String> getHttpBasicAuthHeader() {
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();

View File

@ -1,6 +1,7 @@
package ml.docilealligator.infinityforreddit; package ml.docilealligator.infinityforreddit;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Animatable; import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@ -27,6 +28,7 @@ import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class SubscribedUserRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { public class SubscribedUserRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<SubscribedUserData> mSubscribedUserData; private List<SubscribedUserData> mSubscribedUserData;
private Context mContext;
private RequestManager glide; private RequestManager glide;
private OnItemClickListener mOnItemClickListener; private OnItemClickListener mOnItemClickListener;
@ -35,6 +37,7 @@ public class SubscribedUserRecyclerViewAdapter extends RecyclerView.Adapter<Recy
} }
SubscribedUserRecyclerViewAdapter(Context context, OnItemClickListener onItemClickListener) { SubscribedUserRecyclerViewAdapter(Context context, OnItemClickListener onItemClickListener) {
mContext = context;
glide = Glide.with(context.getApplicationContext()); glide = Glide.with(context.getApplicationContext());
mOnItemClickListener = onItemClickListener; mOnItemClickListener = onItemClickListener;
} }
@ -47,13 +50,11 @@ public class SubscribedUserRecyclerViewAdapter extends RecyclerView.Adapter<Recy
@Override @Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int i) { public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int i) {
viewHolder.itemView.setOnClickListener(new View.OnClickListener() { viewHolder.itemView.setOnClickListener(view -> {
@Override Intent intent = new Intent(mContext, ViewUserDetailActivity.class);
public void onClick(View view) { intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mSubscribedUserData.get(viewHolder.getAdapterPosition()).getName());
//Need to be implemented mContext.startActivity(intent);
mOnItemClickListener.onClick();
mOnItemClickListener.onClick();
}
}); });
if(!mSubscribedUserData.get(i).getIconUrl().equals("")) { if(!mSubscribedUserData.get(i).getIconUrl().equals("")) {
glide.load(mSubscribedUserData.get(i).getIconUrl()) glide.load(mSubscribedUserData.get(i).getIconUrl())

View File

@ -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;
}
}
}

View File

@ -22,7 +22,6 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager; import com.bumptech.glide.RequestManager;
@ -104,11 +103,11 @@ public class ViewSubredditDetailActivity extends AppCompatActivity {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams(); ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams();
params.topMargin = statusBarHeight; 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; String title = "r/" + subredditName;
final CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar_layout_view_subreddit_detail_activity); 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); AppBarLayout appBarLayout = findViewById(R.id.app_bar_layout_view_subreddit_detail_activity);
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
int previousVerticalOffset = 0; int previousVerticalOffset = 0;
@ -136,10 +135,10 @@ public class ViewSubredditDetailActivity extends AppCompatActivity {
}); });
subscribedSubredditDao = SubscribedSubredditRoomDatabase.getDatabase(this).subscribedSubredditDao(); 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, new SubredditViewModel.Factory(getApplication(), subredditName))
mSubredditViewModel = ViewModelProviders.of(this, factory).get(SubredditViewModel.class); .get(SubredditViewModel.class);
mSubredditViewModel.getSubredditLiveData().observe(this, subredditData -> { mSubredditViewModel.getSubredditLiveData().observe(this, subredditData -> {
if(subredditData != null) { if(subredditData != null) {
if(subredditData.getBannerUrl().equals("")) { if(subredditData.getBannerUrl().equals("")) {
@ -279,7 +278,7 @@ public class ViewSubredditDetailActivity extends AppCompatActivity {
@Override @Override
public void onParseSubredditDataFail() { public void onParseSubredditDataFail() {
Toast.makeText(ViewSubredditDetailActivity.this, "Cannot fetch subreddit info", Toast.LENGTH_SHORT).show(); makeSnackbar(R.string.cannot_fetch_subreddit_info);
} }
}); });
} }

View File

@ -1,13 +1,78 @@
package ml.docilealligator.infinityforreddit; 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.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.app.AppCompatActivity;
import android.support.v7.widget.Toolbar; 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 { public class ViewUserDetailActivity extends AppCompatActivity {
static final String EXTRA_USER_NAME_KEY = "EUNK"; 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 @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -15,6 +80,254 @@ public class ViewUserDetailActivity extends AppCompatActivity {
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(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();
}
}
} }
} }

View File

@ -35,6 +35,7 @@
layout="@layout/nav_header_main" /> layout="@layout/nav_header_main" />
<LinearLayout <LinearLayout
android:id="@+id/profile_linear_layout_main_activity"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="16dp" android:padding="16dp"

View File

@ -4,33 +4,97 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:id="@+id/coordinator_layout_view_user_detail_activity"
tools:context=".ViewUserDetailActivity"> tools:context=".ViewUserDetailActivity">
<android.support.design.widget.AppBarLayout <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_width="match_parent"
android:layout_height="@dimen/app_bar_height" android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay"> android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout <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_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary" app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed" app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
app:toolbarId="@+id/toolbar"> 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.support.v7.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin" 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.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>
<include layout="@layout/content_view_user_detail" /> <include layout="@layout/content_view_user_detail" />

View File

@ -26,6 +26,8 @@
<string name="subscriptions">Subscriptions</string> <string name="subscriptions">Subscriptions</string>
<string name="subscribers_number_detail">Subscribers: %1$d</string> <string name="subscribers_number_detail">Subscribers: %1$d</string>
<string name="online_subscribers_number_detail">Online: %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="gilded">x%1$d</string>
<string name="title_activity_view_user_detail">ViewUserDetailActivity</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 " "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 " "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 " "imagery, large scale typography, and intentional white space create a bold and graphic "
"interface that immerse the user in the experience.\n" "interface that immerse the userData in the experience.\n"
"An emphasis on user actions makes core functionality immediately apparent and provides " "An emphasis on userData actions makes core functionality immediately apparent and provides "
"waypoints for the user.\n\n" "waypoints for the userData.\n\n"
"Motion provides meaning.\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" "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" "breaking the continuity of experience even as they transform and reorganize.\n"
"Motion is meaningful and appropriate, serving to focus attention and maintain continuity. " "Motion is meaningful and appropriate, serving to focus attention and maintain continuity. "
"Feedback is subtle yet clear. Transitions are efficient yet coherent.\n\n" "Feedback is subtle yet clear. Transitions are efficient yet coherent.\n\n"
@ -96,7 +98,7 @@
"Responsive elevation and dynamic elevation offsets.\n\n" "Responsive elevation and dynamic elevation offsets.\n\n"
"Some component types have responsive elevation, meaning they change elevation in response " "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" "changes are consistently implemented using dynamic elevation offsets.\n"
"Dynamic elevation offsets are the goal elevation that a component moves towards, relative " "Dynamic elevation offsets are the goal elevation that a component moves towards, relative "
"to the components resting state. They ensure that elevation changes are consistent " "to the components 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" "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. " "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 " "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. " "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 wont interfere " "For example, position the FAB to one side of stream of a cards so the FAB wont 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>
<string name="subscribe">Subscribe</string> <string name="subscribe">Subscribe</string>
@ -126,5 +128,12 @@
<string name="unsubscribed">Unsubscribed</string>" <string name="unsubscribed">Unsubscribed</string>"
<string name="unsubscribe_failed">Unsubscribe Failed</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> <string name="content_description_banner_imageview">Subreddit Banner Image</string>
</resources> </resources>

2
gradlew vendored
View File

@ -119,7 +119,7 @@ if $cygwin ; then
SEP="|" SEP="|"
done done
OURCYGPATTERN="(^($ROOTDIRS))" OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments # Add a userData-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi fi