diff --git a/app/src/main/java/io/github/hidroh/materialistic/ItemActivity.java b/app/src/main/java/io/github/hidroh/materialistic/ItemActivity.java index bdc9ff90e..457a5a753 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/ItemActivity.java +++ b/app/src/main/java/io/github/hidroh/materialistic/ItemActivity.java @@ -381,11 +381,11 @@ private void bindData(@Nullable final WebItem story) { postedTextView.append(story.getDisplayedAuthor(this, true, 0)); postedTextView.setMovementMethod(LinkMovementMethod.getInstance()); switch (story.getType()) { - case Item.JOB_TYPE: + case WebItem.JOB_TYPE: postedTextView.setCompoundDrawablesWithIntrinsicBounds( R.drawable.ic_work_white_18dp, 0, 0, 0); break; - case Item.POLL_TYPE: + case WebItem.POLL_TYPE: postedTextView.setCompoundDrawablesWithIntrinsicBounds( R.drawable.ic_poll_white_18dp, 0, 0, 0); break; diff --git a/app/src/main/java/io/github/hidroh/materialistic/data/Favorite.java b/app/src/main/java/io/github/hidroh/materialistic/data/Favorite.java deleted file mode 100644 index fbafe7079..000000000 --- a/app/src/main/java/io/github/hidroh/materialistic/data/Favorite.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2016 Ha Duy Trung - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.github.hidroh.materialistic.data; - -import android.content.Context; -import android.net.Uri; -import android.os.Parcel; -import android.support.annotation.NonNull; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.TextUtils; - -import io.github.hidroh.materialistic.AppUtils; -import io.github.hidroh.materialistic.R; -import io.github.hidroh.materialistic.annotation.Synthetic; - -/** - * Represents a favorite item - */ -public class Favorite implements WebItem { - private String itemId; - private String url; - private String title; - private long time; - private boolean favorite; - private Spannable displayedTime; - private final Spannable displayedAuthor = new SpannableString(""); - - public static final Creator CREATOR = new Creator() { - @Override - public Favorite createFromParcel(Parcel source) { - return new Favorite(source); - } - - @Override - public Favorite[] newArray(int size) { - return new Favorite[size]; - } - }; - - Favorite(String itemId, String url, String title, long time) { - this.itemId = itemId; - this.url = url; - this.title = title; - this.time = time; - this.favorite = true; - } - - @Synthetic - Favorite(Parcel source) { - itemId = source.readString(); - url = source.readString(); - title = source.readString(); - favorite = source.readInt() != 0; - time = source.readLong(); - } - - @Override - public String getUrl() { - return url; - } - - @Override - public boolean isStoryType() { - return true; - } - - @Override - public String getId() { - return itemId; - } - - @Override - public long getLongId() { - return Long.valueOf(itemId); - } - - @Override - public String getDisplayedTitle() { - return title; - } - - @Override - public Spannable getDisplayedAuthor(Context context, boolean linkify, int color) { - return displayedAuthor; - } - - @Override - public Spannable getDisplayedTime(Context context) { - if (displayedTime == null) { - displayedTime = new SpannableString(context.getString(R.string.saved, - AppUtils.getAbbreviatedTimeSpan(time))); - } - return displayedTime; - } - - @Override - public String getSource() { - return TextUtils.isEmpty(url) ? null : Uri.parse(url).getHost(); - } - - @NonNull - @Override - public String getType() { - // TODO treating all saved items as stories for now - return STORY_TYPE; - } - - @Override - public boolean isFavorite() { - return favorite; - } - - @Override - public void setFavorite(boolean favorite) { - this.favorite = favorite; - } - - @Override - public String toString() { - return String.format("%s (%s) - %s", title, url, String.format(HackerNewsClient.WEB_ITEM_PATH, itemId)); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(itemId); - dest.writeString(url); - dest.writeString(title); - dest.writeInt(favorite ? 1 : 0); - dest.writeLong(time); - } - - long getTime() { - return time; - } -} diff --git a/app/src/main/java/io/github/hidroh/materialistic/data/Favorite.kt b/app/src/main/java/io/github/hidroh/materialistic/data/Favorite.kt new file mode 100644 index 000000000..b8575a33c --- /dev/null +++ b/app/src/main/java/io/github/hidroh/materialistic/data/Favorite.kt @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016 Ha Duy Trung + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.hidroh.materialistic.data + +import android.content.Context +import android.net.Uri +import android.os.Parcel +import android.os.Parcelable +import android.text.Spannable +import android.text.SpannableString +import io.github.hidroh.materialistic.AppUtils +import io.github.hidroh.materialistic.R +import io.github.hidroh.materialistic.data.WebItem.Companion.STORY_TYPE + +open class Favorite(override val id: String, override val url: String?, override val displayedTitle: String, val time: Long) : WebItem { + override var isFavorite: Boolean = true + private val displayedAuthor = SpannableString("") + private var displayedTime: Spannable? = null + + constructor(parcel: Parcel) : this(parcel.readString()!!, parcel.readString()!!, parcel.readString()!!, parcel.readLong()) { + isFavorite = parcel.readInt() != 0 + } + + override val isStoryType: Boolean + get() = true + override val longId: Long + get() = id.toLong() + override val source: String? + get() = if (url.isNullOrEmpty()) null else Uri.parse(url).host + override val type: String + // TODO treating all saved items as stories for now + get() = STORY_TYPE + + + override fun getDisplayedAuthor(context: Context, linkify: Boolean, color: Int): Spannable { + return displayedAuthor + } + + override fun getDisplayedTime(context: Context): Spannable { + if (displayedTime == null) { + displayedTime = SpannableString(context.getString(R.string.saved, AppUtils.getAbbreviatedTimeSpan(time))) + } + return displayedTime!! + } + + + override fun describeContents(): Int { + return 0 + } + + override fun writeToParcel(dest: Parcel, flags: Int) { + dest.writeString(id) + dest.writeString(url) + dest.writeString(displayedTitle) + dest.writeLong(time) + dest.writeInt(if (isFavorite) 1 else 0) + } + + companion object { + @JvmField + val CREATOR: Parcelable.Creator = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel): Favorite { + return Favorite(source) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/github/hidroh/materialistic/data/HackerNewsClient.java b/app/src/main/java/io/github/hidroh/materialistic/data/HackerNewsClient.java index 5a87f0ac2..e00411bd9 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/data/HackerNewsClient.java +++ b/app/src/main/java/io/github/hidroh/materialistic/data/HackerNewsClient.java @@ -93,7 +93,7 @@ public void getItem(final String itemId, @CacheMode int cacheMode, ResponseListe (isViewed, favorite, hackerNewsItem) -> { if (hackerNewsItem != null) { hackerNewsItem.preload(); - hackerNewsItem.setIsViewed(isViewed); + hackerNewsItem.setViewed(isViewed); hackerNewsItem.setFavorite(favorite); } return hackerNewsItem; diff --git a/app/src/main/java/io/github/hidroh/materialistic/data/HackerNewsItem.java b/app/src/main/java/io/github/hidroh/materialistic/data/HackerNewsItem.java index 97bb50c8e..fb9107016 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/data/HackerNewsItem.java +++ b/app/src/main/java/io/github/hidroh/materialistic/data/HackerNewsItem.java @@ -232,6 +232,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeLong(previous); } + @NonNull @Override public String getId() { return String.valueOf(id); @@ -250,11 +251,11 @@ public String getTitle() { @Override public String getDisplayedTitle() { switch (getType()) { - case COMMENT_TYPE: + case WebItem.COMMENT_TYPE: return text; - case JOB_TYPE: - case STORY_TYPE: - case POLL_TYPE: // TODO poll need to display options + case WebItem.JOB_TYPE: + case WebItem.STORY_TYPE: + case WebItem.POLL_TYPE: // TODO poll need to display options default: return title; } @@ -263,11 +264,12 @@ public String getDisplayedTitle() { @NonNull @Override public String getType() { - return !TextUtils.isEmpty(type) ? type : STORY_TYPE; + return !TextUtils.isEmpty(type) ? type : WebItem.STORY_TYPE; } + @NonNull @Override - public Spannable getDisplayedAuthor(Context context, boolean linkify, int color) { + public Spannable getDisplayedAuthor(@NonNull Context context, boolean linkify, int color) { if (displayedAuthor == null) { if (TextUtils.isEmpty(by)) { displayedAuthor = new SpannableString(""); @@ -286,8 +288,9 @@ public Spannable getDisplayedAuthor(Context context, boolean linkify, int color) return displayedAuthor; } + @NonNull @Override - public Spannable getDisplayedTime(Context context) { + public Spannable getDisplayedTime(@NonNull Context context) { if (displayedTime == null) { SpannableStringBuilder builder = new SpannableStringBuilder(dead ? context.getString(R.string.dead_prefix) + " " : ""); @@ -330,9 +333,9 @@ public boolean hasNewKids() { @Override public String getUrl() { switch (getType()) { - case JOB_TYPE: - case POLL_TYPE: - case COMMENT_TYPE: + case WebItem.JOB_TYPE: + case WebItem.POLL_TYPE: + case WebItem.COMMENT_TYPE: return getItemUrl(getId()); default: return TextUtils.isEmpty(url) ? getItemUrl(getId()) : url; @@ -356,7 +359,7 @@ public void onClick(View view) { } @Override - public void updateDrawState(TextPaint ds) { + public void updateDrawState(@NonNull TextPaint ds) { super.updateDrawState(ds); ds.setUnderlineText(false); } @@ -416,11 +419,11 @@ public CharSequence getDisplayedText() { @Override public boolean isStoryType() { switch (getType()) { - case STORY_TYPE: - case POLL_TYPE: - case JOB_TYPE: + case WebItem.STORY_TYPE: + case WebItem.POLL_TYPE: + case WebItem.JOB_TYPE: return true; - case COMMENT_TYPE: + case WebItem.COMMENT_TYPE: default: return false; } @@ -457,7 +460,7 @@ public boolean isViewed() { } @Override - public void setIsViewed(boolean isViewed) { + public void setViewed(boolean isViewed) { viewed = isViewed; } diff --git a/app/src/main/java/io/github/hidroh/materialistic/data/Item.java b/app/src/main/java/io/github/hidroh/materialistic/data/Item.java deleted file mode 100644 index 810bbe352..000000000 --- a/app/src/main/java/io/github/hidroh/materialistic/data/Item.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 2016 Ha Duy Trung - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.github.hidroh.materialistic.data; - -import android.content.Context; - -/** - * Represents an item that can be displayed as story/comment - */ -public interface Item extends WebItem { - - /** - * Sets information from given item - * @param info source item - */ - void populate(Item info); - - /** - * Gets raw item type, used to be parsed by {@link #getType()} - * @return string type or null - * @see Type - */ - String getRawType(); - - /** - * Gets raw URL - * @return string URL or null - * @see #getUrl() - */ - String getRawUrl(); - - /** - * Gets array of kid IDs - * @return array of kid IDs or null - * @see #getKidCount() - * @see #getKidItems() - */ - long[] getKids(); - - /** - * Gets author name - * @return author name or null - * @see WebItem#getDisplayedAuthor(Context, boolean, int) - */ - String getBy(); - - /** - * Gets posted time - * @return posted time as Unix timestamp in seconds - * @see WebItem#getDisplayedAuthor(Context, boolean, int) - */ - long getTime(); - - /** - * Gets title - * @return title or null - * @see #getDisplayedTitle() - */ - String getTitle(); - - /** - * Gets item text - * @return item text or null - * @see #getDisplayedTitle() - */ - String getText(); - - /** - * Gets number of kids, contained in {@link #getKids()} - * @return number of kids - * @see #getKids() - * @see #getKidItems() - */ - int getKidCount(); - - /** - * Gets previous number of kids, before {@link #populate(Item)} is called - * @return previous number of kids - * @see #setLastKidCount(int) - */ - int getLastKidCount(); - - /** - * Sets previous number of kids, before {@link #populate(Item)} is called - * @param lastKidCount previous number of kids - */ - void setLastKidCount(int lastKidCount); - - /** - * Checks if item has new kids after {@link #populate(Item)} - * @return true if has new kids, false otherwise - */ - boolean hasNewKids(); - - /** - * Gets array of kids, with corresponding IDs in {@link #getKids()} - * @return array of kids or null - * @see #getKids() - * @see #getKidCount() - */ - Item[] getKidItems(); - - /** - * Gets item's current revision. A revision can be used to determined if item state is stale - * and needs updated - * @return current revision - * @see #setLocalRevision(int) - * @see #populate(Item) - * @see #setFavorite(boolean) - */ - int getLocalRevision(); - - /** - * Updates item's current revision to new one - * @param localRevision new item revision - * @see #getLocalRevision() - */ - void setLocalRevision(int localRevision); - - /** - * Gets item's descendants if any - * @return item's descendants or -1 if none - */ - int getDescendants(); - - /** - * Indicates if this item has been viewed - * @return true if viewed, falst if not, null if unknown - */ - boolean isViewed(); - - /** - * Sets item view status - * @param isViewed true if has been viewed, false otherwise - */ - void setIsViewed(boolean isViewed); - - /** - * Gets item level, i.e. how many ascendants it has - * @return item level - */ - int getLevel(); - - /** - * Gets parent ID if any - * @return parent ID or 0 if none - */ - String getParent(); - - /** - * Gets parent item if any - * @return parent item or null - */ - Item getParentItem(); - - /** - * Checks if item has been deleted - * @return true if deleted, false otherwise - */ - boolean isDeleted(); - - /** - * Checks if item is dead - * @return true if dead, false otherwise - */ - boolean isDead(); - - /** - * Gets item's score - * @return item's score - */ - int getScore(); - - /** - * Increments item's score - */ - void incrementScore(); - - /** - * Checks if item has been voted via a user action - * @return true if voted, false otherwise - * @see #incrementScore() - */ - boolean isVoted(); - - /** - * Checks if item has pending vote via a user action - * @return true if pending voted, false otherwise - * @see #incrementScore() - */ - boolean isPendingVoted(); - - /** - * Clears pending voted status - * @see #isPendingVoted() - * @see #incrementScore() - */ - void clearPendingVoted(); - - /** - * Checks if item is collapsed - * @return true if collapsed, false otherwise - */ - boolean isCollapsed(); - - /** - * Sets item collapsed state - * @param collapsed true to collapse, false otherwise - */ - void setCollapsed(boolean collapsed); - - /** - * Gets item's rank among its siblings - * @return item's rank - */ - int getRank(); - - /** - * Checks if item content is expanded - * @return true if expanded, false otherwise - */ - boolean isContentExpanded(); - - /** - * Sets item content expanded state - * @param expanded true to expand, false otherwise - */ - void setContentExpanded(boolean expanded); - - long getNeighbour(int direction); - - CharSequence getDisplayedText(); -} diff --git a/app/src/main/java/io/github/hidroh/materialistic/data/Item.kt b/app/src/main/java/io/github/hidroh/materialistic/data/Item.kt new file mode 100644 index 000000000..8064dc9de --- /dev/null +++ b/app/src/main/java/io/github/hidroh/materialistic/data/Item.kt @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2016 Ha Duy Trung + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.hidroh.materialistic.data + +/** + * Represents an item that can be displayed as story/comment + */ +interface Item : WebItem { + + /** + * raw item type, used to be parsed by [.getType] + * @see WebItem.Type + */ + val rawType: String + + /** + * raw URL + * @see url + */ + val rawUrl: String + + /** + * array of kid IDs + * @see kidCount + * @see kidItems + */ + val kids: LongArray? + + /** + * author name + * @see WebItem.getDisplayedAuthor + */ + val by: String? + + /** + * posted time as Unix timestamp in seconds + * @see WebItem.getDisplayedAuthor + */ + val time: Long + + /** + * Gets title + * @see displayedTitle + */ + val title: String? + + /** + * Gets item text + * @see displayedTitle + */ + val text: String? + + /** + * Gets number of kids, contained in [kids] + * @see kids + * @see kidItems + */ + val kidCount: Int + + /** + * previous number of kids, before [populate] is called + * @see kidCount + */ + var lastKidCount: Int + + /** + * array of kids, with corresponding IDs in [.getKids] + * @see kids + * @see kidCount + */ + val kidItems: Array? + + /** + * item's current revision. A revision can be used to determined if item state is stale + * and needs updated + * @see populate + * @see isFavorite + */ + var localRevision: Int + + /** + * item's descendants if any or -1 if none + */ + val descendants: Int + + /** + * Indicates if this item has been viewed. true if viewed, false if not + */ + var isViewed: Boolean + + /** + * item level, i.e. how many ascendants it has + */ + val level: Int + + /** + * parent ID if any or 0 if none + */ + val parent: String + + /** + * parent item if any + */ + val parentItem: Item? + + /** + * Checks if item has been deleted + */ + val isDeleted: Boolean + + /** + * Checks if item is dead + */ + val isDead: Boolean + + /** + * item's score + */ + val score: Int + + /** + * Checks if item has been voted via a user action + * @see incrementScore + */ + val isVoted: Boolean + + /** + * Checks if item has pending vote via a user action + * @see incrementScore + */ + val isPendingVoted: Boolean + + /** + * Checks if item is collapsed + */ + var isCollapsed: Boolean + + /** + * item's rank among its siblings + */ + val rank: Int + + /** + * Checks if item content is expanded + */ + var isContentExpanded: Boolean + + val displayedText: CharSequence + + /** + * Sets information from given item + * @param info source item + */ + fun populate(info: Item) + + /** + * Checks if item has new kids after [.populate] + * @return true if has new kids, false otherwise + */ + fun hasNewKids(): Boolean + + /** + * Increments item's score + */ + fun incrementScore() + + /** + * Clears pending voted status + * @see isPendingVoted + * @see incrementScore + */ + fun clearPendingVoted() + + fun getNeighbour(direction: Int): Long +} diff --git a/app/src/main/java/io/github/hidroh/materialistic/data/WebItem.java b/app/src/main/java/io/github/hidroh/materialistic/data/WebItem.java deleted file mode 100644 index 720176abb..000000000 --- a/app/src/main/java/io/github/hidroh/materialistic/data/WebItem.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2016 Ha Duy Trung - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.github.hidroh.materialistic.data; - -import android.content.Context; -import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.StringDef; -import android.text.Spannable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Represents an item that can be displayed by a {@link android.webkit.WebView} - */ -public interface WebItem extends Parcelable { - @Retention(RetentionPolicy.SOURCE) - @StringDef({ - JOB_TYPE, - STORY_TYPE, - COMMENT_TYPE, - POLL_TYPE - }) - /* - Item types - */ - @interface Type {} - String JOB_TYPE = "job"; - String STORY_TYPE = "story"; - String COMMENT_TYPE = "comment"; - String POLL_TYPE = "poll"; - - /** - * Gets formatted title to display - * @return formatted title or null - */ - String getDisplayedTitle(); - - /** - * Gets item URL to pass to {@link android.webkit.WebView#loadUrl(String)} - * @return URL or null - */ - String getUrl(); - - /** - * Checks if item is not a comment - * @return true if is not a comment, false otherwise - */ - boolean isStoryType(); - - /** - * Gets item ID string - * @return item ID string - */ - String getId(); - - /** - * Gets item ID - * @return item ID - */ - long getLongId(); - - /** - * Gets item source - * @return item source or null - */ - String getSource(); - - /** - * Gets formatted author for display - * @param context an instance of {@link Context} - * @param linkify true to display author as a hyperlink, false otherwise - * @param color optional decorator color for author, or 0 - * @return displayed author - */ - Spannable getDisplayedAuthor(Context context, boolean linkify, int color); - - /** - * Gets formatted posted time for display - * @param context resources provider - * @return displayed time - */ - Spannable getDisplayedTime(Context context); - - /** - * Gets item type - * @return item type - */ - @NonNull - @Type - String getType(); - - /** - * Checks if item is marked as favorite - * @return true if favorite, false otherwise - * @see #setFavorite(boolean) - */ - boolean isFavorite(); - - /** - * Updates item's favorite status to given status - * @param favorite true if favorite, false otherwise - * @see #isFavorite() - */ - void setFavorite(boolean favorite); -} diff --git a/app/src/main/java/io/github/hidroh/materialistic/data/WebItem.kt b/app/src/main/java/io/github/hidroh/materialistic/data/WebItem.kt new file mode 100644 index 000000000..5007d8b0b --- /dev/null +++ b/app/src/main/java/io/github/hidroh/materialistic/data/WebItem.kt @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016 Ha Duy Trung + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.hidroh.materialistic.data + +import android.content.Context +import android.os.Parcelable +import android.support.annotation.StringDef +import android.text.Spannable + +/** + * Represents an item that can be displayed by a [android.webkit.WebView] + */ +interface WebItem : Parcelable { + + /** + * formatted title to display + */ + val displayedTitle: String? + + /** + * item URL to pass to [android.webkit.WebView.loadUrl] + */ + val url: String? + + /** + * item is not a comment + */ + val isStoryType: Boolean + + /** + * item's ID string + */ + val id: String + + /** + * Gets item's ID + */ + val longId: Long + + /** + * item's source + */ + val source: String? + + /** + * Item's type + */ + @get:Type + val type: String + + /** + * item's favorite status + */ + var isFavorite: Boolean + + @Retention(AnnotationRetention.SOURCE) + @StringDef(JOB_TYPE, STORY_TYPE, COMMENT_TYPE, POLL_TYPE) + annotation class Type + + /** + * Gets formatted author for display + * @param context an instance of [Context] + * @param linkify true to display author as a hyperlink, false otherwise + * @param color optional decorator color for author, or 0 + * @return displayed author + */ + fun getDisplayedAuthor(context: Context, linkify: Boolean, color: Int): Spannable + + /** + * Gets formatted posted time for display + * @param context resources provider + * @return displayed time + */ + fun getDisplayedTime(context: Context): Spannable + + companion object { + const val JOB_TYPE = "job" + const val STORY_TYPE = "story" + const val COMMENT_TYPE = "comment" + const val POLL_TYPE = "poll" + } +} diff --git a/app/src/main/java/io/github/hidroh/materialistic/widget/StoryRecyclerViewAdapter.java b/app/src/main/java/io/github/hidroh/materialistic/widget/StoryRecyclerViewAdapter.java index ad4f28084..e960fec76 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/widget/StoryRecyclerViewAdapter.java +++ b/app/src/main/java/io/github/hidroh/materialistic/widget/StoryRecyclerViewAdapter.java @@ -132,7 +132,7 @@ public boolean areItemsTheSame(Item item1, Item item2) { item.setFavorite(false); item.setLocalRevision(mFavoriteRevision); } else { - item.setIsViewed(true); + item.setViewed(true); } notifyItemChanged(position); }; diff --git a/app/src/main/java/io/github/hidroh/materialistic/widget/StoryView.java b/app/src/main/java/io/github/hidroh/materialistic/widget/StoryView.java index ac87d918c..00eefab33 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/widget/StoryView.java +++ b/app/src/main/java/io/github/hidroh/materialistic/widget/StoryView.java @@ -174,12 +174,12 @@ public void setStory(@NonNull WebItem story, int hotThreshold) { mPostedTextView.setText(story.getDisplayedTime(getContext())); mPostedTextView.append(story.getDisplayedAuthor(getContext(), false, 0)); switch (story.getType()) { - case Item.JOB_TYPE: + case WebItem.JOB_TYPE: mSourceTextView.setText(null); mSourceTextView.setCompoundDrawablesWithIntrinsicBounds( R.drawable.ic_work_white_18dp, 0, 0, 0); break; - case Item.POLL_TYPE: + case WebItem.POLL_TYPE: mSourceTextView.setText(null); mSourceTextView.setCompoundDrawablesWithIntrinsicBounds( R.drawable.ic_poll_white_18dp, 0, 0, 0); diff --git a/app/src/main/java/io/github/hidroh/materialistic/widget/SubmissionRecyclerViewAdapter.java b/app/src/main/java/io/github/hidroh/materialistic/widget/SubmissionRecyclerViewAdapter.java index ea46ab457..477a134f6 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/widget/SubmissionRecyclerViewAdapter.java +++ b/app/src/main/java/io/github/hidroh/materialistic/widget/SubmissionRecyclerViewAdapter.java @@ -28,6 +28,7 @@ import io.github.hidroh.materialistic.ThreadPreviewActivity; import io.github.hidroh.materialistic.data.Item; import io.github.hidroh.materialistic.data.ItemManager; +import io.github.hidroh.materialistic.data.WebItem; public class SubmissionRecyclerViewAdapter extends ItemRecyclerViewAdapter { private final Item[] mItems; @@ -70,7 +71,7 @@ protected void bind(final SubmissionViewHolder holder, final Item item) { if (item == null) { return; } - final boolean isComment = TextUtils.equals(item.getType(), Item.COMMENT_TYPE); + final boolean isComment = TextUtils.equals(item.getType(), WebItem.COMMENT_TYPE); holder.mPostedTextView.setText(item.getDisplayedTime(mContext)); holder.mPostedTextView.append(item.getDisplayedAuthor(mContext, false, 0)); if (isComment) { diff --git a/app/src/main/java/io/github/hidroh/materialistic/widget/ThreadPreviewRecyclerViewAdapter.java b/app/src/main/java/io/github/hidroh/materialistic/widget/ThreadPreviewRecyclerViewAdapter.java index 7964252b8..e9666f94c 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/widget/ThreadPreviewRecyclerViewAdapter.java +++ b/app/src/main/java/io/github/hidroh/materialistic/widget/ThreadPreviewRecyclerViewAdapter.java @@ -31,6 +31,7 @@ import io.github.hidroh.materialistic.R; import io.github.hidroh.materialistic.data.Item; import io.github.hidroh.materialistic.data.ItemManager; +import io.github.hidroh.materialistic.data.WebItem; public class ThreadPreviewRecyclerViewAdapter extends ItemRecyclerViewAdapter { private final List mItems = new ArrayList<>(); @@ -86,7 +87,7 @@ protected void bind(SubmissionViewHolder holder, final Item item) { holder.mPostedTextView.append(item.getDisplayedAuthor(mContext, !TextUtils.equals(item.getBy(), mUsername), 0)); holder.mMoreButton.setVisibility(View.GONE); - if (TextUtils.equals(item.getType(), Item.COMMENT_TYPE)) { + if (TextUtils.equals(item.getType(), WebItem.COMMENT_TYPE)) { holder.mTitleTextView.setText(null); holder.itemView.setOnClickListener(null); holder.mCommentButton.setVisibility(View.GONE); diff --git a/app/src/test/java/io/github/hidroh/materialistic/BaseListActivityLandTest.java b/app/src/test/java/io/github/hidroh/materialistic/BaseListActivityLandTest.java index 8088ed9db..67ba6e058 100644 --- a/app/src/test/java/io/github/hidroh/materialistic/BaseListActivityLandTest.java +++ b/app/src/test/java/io/github/hidroh/materialistic/BaseListActivityLandTest.java @@ -142,6 +142,7 @@ public void testDefaultCommentView() { .apply(); controller.pause().resume(); activity.onItemSelected(new TestHnItem(1L) { + @NonNull @Override public String getId() { return "1"; @@ -265,6 +266,7 @@ public boolean isStoryType() { return true; } + @NonNull @Override public String getId() { return "1"; diff --git a/app/src/test/java/io/github/hidroh/materialistic/ListFragmentViewHolderTest.java b/app/src/test/java/io/github/hidroh/materialistic/ListFragmentViewHolderTest.java index 952e7cdc8..95f65dacb 100644 --- a/app/src/test/java/io/github/hidroh/materialistic/ListFragmentViewHolderTest.java +++ b/app/src/test/java/io/github/hidroh/materialistic/ListFragmentViewHolderTest.java @@ -20,18 +20,17 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RuntimeEnvironment; +import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; import org.robolectric.fakes.RoboMenuItem; import org.robolectric.shadows.ShadowPopupMenu; import org.robolectric.shadows.ShadowToast; -import org.robolectric.android.controller.ActivityController; import java.io.IOException; @@ -140,7 +139,7 @@ public String getBy() { @Test public void testStory() { - item.setIsViewed(true); + item.setViewed(true); verify(itemManager).getItem(any(), eq(ItemManager.MODE_DEFAULT), itemListener.capture()); itemListener.getValue().onResponse(item); RecyclerView.ViewHolder holder = adapter.getViewHolder(0); @@ -526,7 +525,7 @@ public void testAutoMarkAsViewed() { shadowRecyclerView.getScrollListener().onScrolled(recyclerView, 0, 1); verify(sessionManager).view(any()); - item.setIsViewed(true); + item.setViewed(true); testLayout.firstVisiblePosition = 1; shadowRecyclerView.getScrollListener().onScrolled(recyclerView, 0, 1); verify(sessionManager).view(any()); // should not trigger again diff --git a/app/src/test/java/io/github/hidroh/materialistic/data/FavoriteManagerTest.kt b/app/src/test/java/io/github/hidroh/materialistic/data/FavoriteManagerTest.kt index a92d441ac..500d9d3f5 100644 --- a/app/src/test/java/io/github/hidroh/materialistic/data/FavoriteManagerTest.kt +++ b/app/src/test/java/io/github/hidroh/materialistic/data/FavoriteManagerTest.kt @@ -62,14 +62,14 @@ class FavoriteManagerTest { fun setUp() { MockitoAnnotations.initMocks(this) savedStoriesDao.insert(MaterialisticDatabase.SavedStory.from(object : TestWebItem() { - override fun getDisplayedTitle() = "title" - override fun getUrl() = "http://example.com" - override fun getId() = "1" + override val displayedTitle get() = "title" + override val url get() = "http://example.com" + override val id get() = "1" })) savedStoriesDao.insert(MaterialisticDatabase.SavedStory.from(object : TestWebItem() { - override fun getDisplayedTitle() = "ask HN" - override fun getUrl() = "http://example.com" - override fun getId() = "2" + override val displayedTitle get() = "ask HN" + override val url get() = "http://example.com" + override val id get() = "2" })) val cache = Cache(database, savedStoriesDao, readStoriesDao, readableDao, Schedulers.immediate()) manager = FavoriteManager(cache, Schedulers.immediate(), savedStoriesDao) @@ -132,9 +132,9 @@ class FavoriteManagerTest { .activeNetworkInfo =ShadowNetworkInfo.newInstance(null, ConnectivityManager.TYPE_WIFI, 0, true, NetworkInfo.State.CONNECTED) manager.add(context, object : TestWebItem() { - override fun getDisplayedTitle() = "new title" - override fun getUrl() = "http://newitem.com" - override fun getId() = "3" + override val displayedTitle get() = "new title" + override val url get() = "http://newitem.com" + override val id get() = "3" }) verify(observer).onChanged(eq(Uri.parse("content://${BuildConfig.APPLICATION_ID}/saved/add/3"))) assertThat(ShadowContentResolver.isSyncActive(Account("Materialistic", BuildConfig.APPLICATION_ID), diff --git a/app/src/test/java/io/github/hidroh/materialistic/data/HackerNewsItemTest.java b/app/src/test/java/io/github/hidroh/materialistic/data/HackerNewsItemTest.java index 75da8bced..c88d45b5e 100644 --- a/app/src/test/java/io/github/hidroh/materialistic/data/HackerNewsItemTest.java +++ b/app/src/test/java/io/github/hidroh/materialistic/data/HackerNewsItemTest.java @@ -5,11 +5,11 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import io.github.hidroh.materialistic.test.TestRunner; import org.robolectric.RuntimeEnvironment; import io.github.hidroh.materialistic.R; import io.github.hidroh.materialistic.test.TestItem; +import io.github.hidroh.materialistic.test.TestRunner; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -40,7 +40,7 @@ public void testFavorite() { @Test public void testViewed() { assertFalse(item.isViewed()); - item.setIsViewed(true); + item.setViewed(true); assertTrue(item.isViewed()); } diff --git a/app/src/test/java/io/github/hidroh/materialistic/test/TestItem.java b/app/src/test/java/io/github/hidroh/materialistic/test/TestItem.java index 1aa0bd10c..f9b9c3a76 100644 --- a/app/src/test/java/io/github/hidroh/materialistic/test/TestItem.java +++ b/app/src/test/java/io/github/hidroh/materialistic/test/TestItem.java @@ -132,7 +132,7 @@ public boolean isViewed() { } @Override - public void setIsViewed(boolean isViewed) { + public void setViewed(boolean isViewed) { viewed = isViewed; }