diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/LoadSubredditIconAsyncTask.java b/app/src/main/java/ml/docilealligator/infinityforreddit/LoadSubredditIconAsyncTask.java index 928951fc..97795c54 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/LoadSubredditIconAsyncTask.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/LoadSubredditIconAsyncTask.java @@ -1,31 +1,22 @@ package ml.docilealligator.infinityforreddit; -import android.content.Context; import android.os.AsyncTask; -import com.bumptech.glide.Glide; - -import java.lang.ref.WeakReference; - -import de.hdodenhof.circleimageview.CircleImageView; - class LoadSubredditIconAsyncTask extends AsyncTask { - private final WeakReference contextWeakReference; - private final WeakReference circleImageViewWeakReference; + interface LoadSubredditIconAsyncTaskListener { + void loadIconSuccess(String iconImageUrl); + } private SubredditDao subredditDao; private String subredditName; private String iconImageUrl; - private PostData postData; + private LoadSubredditIconAsyncTaskListener loadSubredditIconAsyncTaskListener; - LoadSubredditIconAsyncTask(Context context, CircleImageView iconImageView, - SubredditDao subredditDao, String subredditName, - PostData postData) { - contextWeakReference = new WeakReference<>(context); - circleImageViewWeakReference = new WeakReference<>(iconImageView); + LoadSubredditIconAsyncTask(SubredditDao subredditDao, String subredditName, + LoadSubredditIconAsyncTaskListener loadSubredditIconAsyncTaskListener) { this.subredditDao = subredditDao; this.subredditName = subredditName; - this.postData = postData; + this.loadSubredditIconAsyncTaskListener = loadSubredditIconAsyncTaskListener; } @Override @@ -41,7 +32,8 @@ class LoadSubredditIconAsyncTask extends AsyncTask { @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); - Context context = contextWeakReference.get(); + loadSubredditIconAsyncTaskListener.loadIconSuccess(iconImageUrl); + /*Context context = contextWeakReference.get(); CircleImageView circleImageView = circleImageViewWeakReference.get(); if(context != null && circleImageView != null) { @@ -52,6 +44,6 @@ class LoadSubredditIconAsyncTask extends AsyncTask { } } - postData.setSubredditIconUrl(iconImageUrl); + postData.setSubredditIconUrl(iconImageUrl);*/ } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ParsePost.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ParsePost.java index caebd825..ffc2be9b 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ParsePost.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ParsePost.java @@ -70,7 +70,9 @@ class ParsePost { String title = data.getString(JSONUtils.TITLE_KEY); int score = data.getInt(JSONUtils.SCORE_KEY); int voteType; + int gilded = data.getInt(JSONUtils.GILDED_KEY); boolean nsfw = data.getBoolean(JSONUtils.NSFW_KEY); + boolean stickied = data.getBoolean(JSONUtils.STICKIED_KEY); if(data.isNull(JSONUtils.LIKES_KEY)) { voteType = 0; @@ -93,10 +95,10 @@ class ParsePost { //Cross post data = data.getJSONArray(JSONUtils.CROSSPOST_PARENT_LIST).getJSONObject(0); parseData(data, permalink, newPostData, id, fullName, subredditName, - formattedPostTime, title, previewUrl, score, voteType, nsfw, i); + formattedPostTime, title, previewUrl, score, voteType, gilded, nsfw, stickied, i); } else { parseData(data, permalink, newPostData, id, fullName, subredditName, - formattedPostTime, title, previewUrl, score, voteType, nsfw, i); + formattedPostTime, title, previewUrl, score, voteType, gilded, nsfw, stickied, i); } } } catch (JSONException e) { @@ -119,8 +121,9 @@ class ParsePost { } private void parseData(JSONObject data, String permalink, ArrayList bestPostData, - String id, String fullName, String subredditName, String formattedPostTime, String title, - String previewUrl, int score, int voteType, boolean nsfw, int i) throws JSONException { + String id, String fullName, String subredditName, String formattedPostTime, + String title, String previewUrl, int score, int voteType, int gilded, + boolean nsfw, boolean stickied, int i) throws JSONException { boolean isVideo = data.getBoolean(JSONUtils.IS_VIDEO_KEY); String url = data.getString(JSONUtils.URL_KEY); @@ -129,7 +132,8 @@ class ParsePost { //Text post Log.i("text", Integer.toString(i)); int postType = PostData.TEXT_TYPE; - PostData postData = new PostData(id, fullName, subredditName, formattedPostTime, title, permalink, score, postType, voteType, nsfw); + PostData postData = new PostData(id, fullName, subredditName, formattedPostTime, + title, permalink, score, postType, voteType, gilded, nsfw, stickied); if(data.isNull(JSONUtils.SELFTEXT_HTML_KEY)) { postData.setSelfText(""); } else { @@ -140,7 +144,13 @@ class ParsePost { //No preview link post Log.i("no preview link", Integer.toString(i)); int postType = PostData.NO_PREVIEW_LINK_TYPE; - PostData linkPostData = new PostData(id, fullName, subredditName, formattedPostTime, title, previewUrl, url, permalink, score, postType, voteType, nsfw); + PostData linkPostData = new PostData(id, fullName, subredditName, formattedPostTime, + title, previewUrl, url, permalink, score, postType, voteType, gilded, nsfw, stickied); + if(data.isNull(JSONUtils.SELFTEXT_HTML_KEY)) { + linkPostData.setSelfText(""); + } else { + linkPostData.setSelfText(data.getString(JSONUtils.SELFTEXT_HTML_KEY).trim()); + } bestPostData.add(linkPostData); } } else if(isVideo) { @@ -150,7 +160,8 @@ class ParsePost { int postType = PostData.VIDEO_TYPE; String videoUrl = redditVideoObject.getString(JSONUtils.DASH_URL_KEY); - PostData videoPostData = new PostData(id, fullName, subredditName, formattedPostTime, title, previewUrl, permalink, score, postType, voteType, nsfw, true); + PostData videoPostData = new PostData(id, fullName, subredditName, formattedPostTime, + title, previewUrl, permalink, score, postType, voteType, gilded, nsfw, stickied, true); videoPostData.setVideoUrl(videoUrl); videoPostData.setDownloadableGifOrVideo(false); @@ -164,7 +175,8 @@ class ParsePost { int postType = PostData.GIF_VIDEO_TYPE; String videoUrl = variations.getJSONObject(JSONUtils.VARIANTS_KEY).getJSONObject(JSONUtils.MP4_KEY).getJSONObject(JSONUtils.SOURCE_KEY).getString(JSONUtils.URL_KEY); String gifDownloadUrl = variations.getJSONObject(JSONUtils.VARIANTS_KEY).getJSONObject(JSONUtils.GIF_KEY).getJSONObject(JSONUtils.SOURCE_KEY).getString(JSONUtils.URL_KEY); - PostData post = new PostData(id, fullName, subredditName, formattedPostTime, title, previewUrl, permalink, score, postType, voteType, nsfw, false); + PostData post = new PostData(id, fullName, subredditName, formattedPostTime, title, + previewUrl, permalink, score, postType, voteType, gilded, nsfw, stickied, false); post.setVideoUrl(videoUrl); post.setDownloadableGifOrVideo(true); @@ -178,7 +190,8 @@ class ParsePost { String videoUrl = data.getJSONObject(JSONUtils.PREVIEW_KEY) .getJSONObject(JSONUtils.REDDIT_VIDEO_PREVIEW_KEY).getString(JSONUtils.DASH_URL_KEY); - PostData post = new PostData(id, fullName, subredditName, formattedPostTime, title, previewUrl, permalink, score, postType, voteType, nsfw, true); + PostData post = new PostData(id, fullName, subredditName, formattedPostTime, title, + previewUrl, permalink, score, postType, voteType, gilded, nsfw, stickied, true); post.setVideoUrl(videoUrl); post.setDownloadableGifOrVideo(false); @@ -189,12 +202,19 @@ class ParsePost { //Image post Log.i("image", Integer.toString(i)); int postType = PostData.IMAGE_TYPE; - bestPostData.add(new PostData(id, fullName, subredditName, formattedPostTime, title, url, url, permalink, score, postType, voteType, nsfw)); + bestPostData.add(new PostData(id, fullName, subredditName, formattedPostTime, + title, url, url, permalink, score, postType, voteType, gilded, nsfw, stickied)); } else { //Link post Log.i("link", Integer.toString(i)); int postType = PostData.LINK_TYPE; - PostData linkPostData = new PostData(id, fullName, subredditName, formattedPostTime, title, previewUrl, url, permalink, score, postType, voteType, nsfw); + PostData linkPostData = new PostData(id, fullName, subredditName, formattedPostTime, + title, previewUrl, url, permalink, score, postType, voteType, gilded, nsfw, stickied); + if(data.isNull(JSONUtils.SELFTEXT_HTML_KEY)) { + linkPostData.setSelfText(""); + } else { + linkPostData.setSelfText(data.getString(JSONUtils.SELFTEXT_HTML_KEY).trim()); + } bestPostData.add(linkPostData); } } @@ -203,12 +223,14 @@ class ParsePost { //Image post Log.i("CP no preview image", Integer.toString(i)); int postType = PostData.IMAGE_TYPE; - bestPostData.add(new PostData(id, fullName, subredditName, formattedPostTime, title, url, url, permalink, score, postType, voteType, nsfw)); + bestPostData.add(new PostData(id, fullName, subredditName, formattedPostTime, title, + url, url, permalink, score, postType, voteType, gilded, nsfw, stickied)); } else { //Link post Log.i("CP no preview link", Integer.toString(i)); int postType = PostData.LINK_TYPE; - PostData linkPostData = new PostData(id, fullName, subredditName, formattedPostTime, title, previewUrl, url, permalink, score, postType, voteType, nsfw); + PostData linkPostData = new PostData(id, fullName, subredditName, formattedPostTime, + title, previewUrl, url, permalink, score, postType, voteType, gilded, nsfw, stickied); bestPostData.add(linkPostData); } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostData.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostData.java index c91cc333..0626088f 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostData.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostData.java @@ -30,11 +30,15 @@ class PostData implements Parcelable { private int score; private int postType; private int voteType; + private int gilded; private boolean nsfw; + private boolean stickied; private boolean isDashVideo; private boolean isDownloadableGifOrVideo; - PostData(String id, String fullName, String subredditName, String postTime, String title, String previewUrl, String permalink, int score, int postType, int voteType, boolean nsfw, boolean isDashVideo) { + PostData(String id, String fullName, String subredditName, String postTime, String title, + String previewUrl, String permalink, int score, int postType, int voteType, int gilded, + boolean nsfw, boolean stickied, boolean isDashVideo) { this.id = id; this.fullName = fullName; this.subredditName = subredditName; @@ -45,11 +49,15 @@ class PostData implements Parcelable { this.score = score; this.postType = postType; this.voteType = voteType; + this.gilded = gilded; this.nsfw = nsfw; + this.stickied = stickied; this.isDashVideo = isDashVideo; } - PostData(String id, String fullName, String subredditName, String postTime, String title, String previewUrl, String url, String permalink, int score, int postType, int voteType, boolean nsfw) { + PostData(String id, String fullName, String subredditName, String postTime, String title, + String previewUrl, String url, String permalink, int score, int postType, int voteType, + int gilded, boolean nsfw, boolean stickied) { this.id = id; this.fullName = fullName; this.subredditName = subredditName; @@ -61,10 +69,14 @@ class PostData implements Parcelable { this.score = score; this.postType = postType; this.voteType = voteType; + this.gilded = gilded; this.nsfw = nsfw; + this.stickied = stickied; } - PostData(String id, String fullName, String subredditName, String postTime, String title, String permalink, int score, int postType, int voteType, boolean nsfw) { + PostData(String id, String fullName, String subredditName, String postTime, String title, + String permalink, int score, int postType, int voteType, int gilded, boolean nsfw, + boolean stickied) { this.id = id; this.fullName = fullName; this.subredditName = subredditName; @@ -74,7 +86,9 @@ class PostData implements Parcelable { this.score = score; this.postType = postType; this.voteType = voteType; + this.gilded = gilded; this.nsfw = nsfw; + this.stickied = stickied; } protected PostData(Parcel in) { @@ -93,7 +107,9 @@ class PostData implements Parcelable { score = in.readInt(); postType = in.readInt(); voteType = in.readInt(); + gilded = in.readInt(); nsfw = in.readByte() != 0; + stickied = in.readByte() != 0; isDashVideo = in.readByte() != 0; isDownloadableGifOrVideo = in.readByte() != 0; } @@ -198,7 +214,11 @@ class PostData implements Parcelable { return voteType; } - public boolean getNSFW() { + public int getGilded() { + return gilded; + } + + public boolean isNSFW() { return nsfw; } @@ -219,6 +239,10 @@ class PostData implements Parcelable { return isDownloadableGifOrVideo; } + public boolean isStickied() { + return stickied; + } + @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeString(id); @@ -236,7 +260,9 @@ class PostData implements Parcelable { parcel.writeInt(score); parcel.writeInt(postType); parcel.writeInt(voteType); + parcel.writeInt(gilded); parcel.writeByte((byte) (nsfw ? 1 : 0)); + parcel.writeByte((byte) (stickied ? 1 : 0)); parcel.writeByte((byte) (isDashVideo ? 1 : 0)); parcel.writeByte((byte) (isDownloadableGifOrVideo ? 1 : 0)); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java index 49220d94..e8b10896 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java @@ -188,10 +188,6 @@ public class PostFragment extends Fragment { mProgressBar.setVisibility(View.VISIBLE); - /*Uri uri = Uri.parse(RedditUtils.OAUTH_API_BASE_URI + RedditUtils.BEST_POST_SUFFIX) - .buildUpon().appendQueryParameter(RedditUtils.RAW_JSON_KEY, RedditUtils.RAW_JSON_VALUE) - .build();*/ - StringRequest postRequest = new StringRequest(Request.Method.GET, mQueryPostUrl, new Response.Listener() { @Override public void onResponse(String response) { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java index 933af11d..724fb753 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java @@ -86,22 +86,36 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter 0) { + ((DataViewHolder) holder).gildedImageView.setVisibility(View.VISIBLE); + glide.load(R.drawable.gold).into(((DataViewHolder) holder).gildedImageView); + ((DataViewHolder) holder).gildedNumberTextView.setVisibility(View.VISIBLE); + String gildedNumber = mContext.getResources().getString(R.string.gilded, gilded); + ((DataViewHolder) holder).gildedNumberTextView.setText(gildedNumber); + } + if(nsfw) { ((DataViewHolder) holder).nsfwTextView.setVisibility(View.VISIBLE); } @@ -147,6 +169,11 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter 0) { + gildedImageView.setVisibility(View.VISIBLE); + Glide.with(this).load(R.drawable.gold).into(gildedImageView); + gildedNumberTextView.setVisibility(View.VISIBLE); + String gildedNumber = getResources().getString(R.string.gilded, mPostData.getGilded()); + gildedNumberTextView.setText(gildedNumber); + } + + if(mPostData.isNSFW()) { nsfwTextView.setVisibility(View.VISIBLE); } scoreTextView.setText(Integer.toString(mPostData.getScore())); @@ -177,6 +204,10 @@ public class ViewPostDetailActivity extends AppCompatActivity { case PostData.LINK_TYPE: relativeLayout.setVisibility(View.VISIBLE); typeTextView.setText("LINK"); + if(!mPostData.getSelfText().equals("")) { + contentTextView.setVisibility(View.VISIBLE); + contentTextView.setHtml(mPostData.getSelfText()); + } String linkPreviewUrl = mPostData.getPreviewUrl(); Glide.with(this).load(linkPreviewUrl).listener(new RequestListener() { @Override @@ -279,6 +310,10 @@ public class ViewPostDetailActivity extends AppCompatActivity { break; case PostData.NO_PREVIEW_LINK_TYPE: typeTextView.setText("LINK"); + if(!mPostData.getSelfText().equals("")) { + contentTextView.setVisibility(View.VISIBLE); + contentTextView.setHtml(mPostData.getSelfText()); + } noPreviewLinkImageView.setVisibility(View.VISIBLE); noPreviewLinkImageView.setOnClickListener(new View.OnClickListener() { @Override @@ -535,4 +570,12 @@ public class ViewPostDetailActivity extends AppCompatActivity { finish(); } } + + @Override + protected void onDestroy() { + super.onDestroy(); + if(mLoadSubredditIconAsyncTask != null) { + mLoadSubredditIconAsyncTask.cancel(true); + } + } } diff --git a/app/src/main/res/drawable/gold.png b/app/src/main/res/drawable/gold.png new file mode 100644 index 00000000..df04fbe8 Binary files /dev/null and b/app/src/main/res/drawable/gold.png differ diff --git a/app/src/main/res/drawable/thumbtack.png b/app/src/main/res/drawable/thumbtack.png new file mode 100644 index 00000000..b537f614 Binary files /dev/null and b/app/src/main/res/drawable/thumbtack.png differ diff --git a/app/src/main/res/layout/activity_view_post_detail.xml b/app/src/main/res/layout/activity_view_post_detail.xml index d3b0b3ce..64a648c2 100644 --- a/app/src/main/res/layout/activity_view_post_detail.xml +++ b/app/src/main/res/layout/activity_view_post_detail.xml @@ -103,6 +103,27 @@ android:background="@drawable/rounded_corner" android:textColor="@android:color/white" /> + + + + + + + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_marginStart="16dp" + android:layout_marginEnd="16dp"> + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index bb250be8..ed9b8e8a 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,4 +7,6 @@ #E91E63 #88000000 + + #FFC107 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c7505627..2014e3bb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -22,93 +22,6 @@ Subscriptions Subscribers: %1$d Online: %1$d - - "Material is the metaphor.\n\n" - "A material metaphor is the unifying theory of a rationalized space and a system of motion." - "The material is grounded in tactile reality, inspired by the study of paper and ink, yet " - "technologically advanced and open to imagination and magic.\n" - "Surfaces and edges of the material provide visual cues that are grounded in reality. The " - "use of familiar tactile attributes helps users quickly understand affordances. Yet the " - "flexibility of the material creates new affordances that supercede those in the physical " - "world, without breaking the rules of physics.\n" - "The fundamentals of light, surface, and movement are key to conveying how objects move, " - "interact, and exist in space and in relation to each other. Realistic lighting shows " - "seams, divides space, and indicates moving parts.\n\n" - - "Bold, graphic, intentional.\n\n" - - "The foundational elements of print based design typography, grids, space, scale, color, " - "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" - - "Motion provides meaning.\n\n" - - "Motion respects and reinforces the user as the prime mover. Primary user 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 " - "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" - - "3D world.\n\n" - - "The material environment is a 3D space, which means all objects have x, y, and z " - "dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the " - "positive z-axis extending towards the viewer. Every sheet of material occupies a single " - "position along the z-axis and has a standard 1dp thickness.\n" - "On the web, the z-axis is used for layering and not for perspective. The 3D world is " - "emulated by manipulating the y-axis.\n\n" - - "Light and shadow.\n\n" - - "Within the material environment, virtual lights illuminate the scene. Key lights create " - "directional shadows, while ambient light creates soft shadows from all angles.\n" - "Shadows in the material environment are cast by these two light sources. In Android " - "development, shadows occur when light sources are blocked by sheets of material at " - "various positions along the z-axis. On the web, shadows are depicted by manipulating the " - "y-axis only. The following example shows the card with a height of 6dp.\n\n" - - "Resting elevation.\n\n" - - "All material objects, regardless of size, have a resting elevation, or default elevation " - "that does not change. If an object changes elevation, it should return to its resting " - "elevation as soon as possible.\n\n" - - "Component elevations.\n\n" - - "The resting elevation for a component type is consistent across apps (e.g., FAB elevation " - "does not vary from 6dp in one app to 16dp in another app).\n" - "Components may have different resting elevations across platforms, depending on the depth " - "of the environment (e.g., TV has a greater depth than mobile or desktop).\n\n" - - "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 " - "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 " - "across actions and component types. For example, all components that lift on press have " - "the same elevation change relative to their resting elevation.\n" - "Once the input event is completed or cancelled, the component will return to its resting " - "elevation.\n\n" - - "Avoiding elevation interference.\n\n" - - "Components with responsive elevations may encounter other components as they move between " - "their resting elevations and dynamic elevation offsets. Because material cannot pass " - "through other material, components avoid interfering with one another any number of ways, " - "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" - "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" - + x%1$d