Add item readtime on item list activity and item activity

This commit is contained in:
Shinokuni 2019-02-08 18:22:42 +00:00
parent cc88fc8334
commit a1d4112322
13 changed files with 197 additions and 24 deletions

46
.idea/assetWizardSettings.xml generated Normal file
View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WizardSettings">
<option name="children">
<map>
<entry key="vectorWizard">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="vectorAssetStep">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="clipartAsset">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="url" value="jar:file:/Applications/Android%20Studio.app/Contents/plugins/android/lib/android.jar!/images/material_design_icons/device/ic_access_time_black_24dp.xml" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
<option name="values">
<map>
<entry key="outputName" value="ic_read_time" />
<entry key="sourceFile" value="$USER_HOME$" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</component>
</project>

View File

@ -14,6 +14,7 @@ import android.view.View;
import android.webkit.WebSettings; import android.webkit.WebSettings;
import android.webkit.WebView; import android.webkit.WebView;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import com.readrops.app.database.ItemWithFeed; import com.readrops.app.database.ItemWithFeed;
@ -37,6 +38,8 @@ public class ItemActivity extends AppCompatActivity {
private TextView author; private TextView author;
private TextView readTime; private TextView readTime;
private RelativeLayout readTimeLayout;
private CollapsingToolbarLayout toolbarLayout; private CollapsingToolbarLayout toolbarLayout;
private ReadropsWebView webView; private ReadropsWebView webView;
@ -71,6 +74,7 @@ public class ItemActivity extends AppCompatActivity {
title = findViewById(R.id.activity_item_title); title = findViewById(R.id.activity_item_title);
author = findViewById(R.id.activity_item_author); author = findViewById(R.id.activity_item_author);
readTime = findViewById(R.id.activity_item_readtime); readTime = findViewById(R.id.activity_item_readtime);
readTimeLayout = findViewById(R.id.activity_item_readtime_layout);
viewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()).create(ItemViewModel.class); viewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()).create(ItemViewModel.class);
viewModel.getItemById(itemId).observe(this, this::bindUI); viewModel.getItemById(itemId).observe(this, this::bindUI);
@ -87,6 +91,18 @@ public class ItemActivity extends AppCompatActivity {
author.setVisibility(View.VISIBLE); author.setVisibility(View.VISIBLE);
} }
if (item.getReadTime() > 0) {
int minutes = (int)Math.round(item.getReadTime());
if (minutes < 1)
readTime.setText(getResources().getString(R.string.read_time_lower_than_1));
else if (minutes > 1)
readTime.setText(getResources().getString(R.string.read_time, String.valueOf(minutes)));
else
readTime.setText(getResources().getString(R.string.read_time_one_minute));
readTimeLayout.setVisibility(View.VISIBLE);
}
webView.setItem(itemWithFeed); webView.setItem(itemWithFeed);
} }
} }

View File

@ -203,18 +203,22 @@ public class LocalFeedRepository extends ARepository implements QueryCallback {
for (Item dbItem : items) { for (Item dbItem : items) {
if (!Boolean.valueOf(database.itemDao().guidExist(dbItem.getGuid()))) { if (!Boolean.valueOf(database.itemDao().guidExist(dbItem.getGuid()))) {
if (dbItem.getDescription() != null) { if (dbItem.getDescription() != null) {
dbItem.setCleanDescription(Jsoup.parse(dbItem.getDescription()).text());
if (dbItem.getImageLink() == null) { if (dbItem.getImageLink() == null) {
String imageUrl = HtmlParser.getDescImageLink(dbItem.getDescription(), feed.getSiteUrl()); String imageUrl = HtmlParser.getDescImageLink(dbItem.getDescription(), feed.getSiteUrl());
if (imageUrl != null) { if (imageUrl != null) {
dbItem.setImageLink(imageUrl); dbItem.setImageLink(imageUrl);
if (dbItem.getContent() != null) // removing cover image in content if found in description if (dbItem.getContent() != null) {
// removing cover image in content if found in description
dbItem.setContent(HtmlParser.deleteCoverImage(dbItem.getContent())); dbItem.setContent(HtmlParser.deleteCoverImage(dbItem.getContent()));
}
}
dbItem.setCleanDescription(Jsoup.parse(dbItem.getDescription()).text()); dbItem.setReadTime(Utils.readTimeFromString(dbItem.getContent()));
} else
dbItem.setReadTime(Utils.readTimeFromString(dbItem.getCleanDescription()));
}
}
} }
database.itemDao().insert(dbItem); database.itemDao().insert(dbItem);

View File

@ -90,6 +90,7 @@ public class MainActivity extends AppCompatActivity implements SimpleCallback, S
viewModel.getItemsWithFeed().observe(this, (itemWithFeeds -> { viewModel.getItemsWithFeed().observe(this, (itemWithFeeds -> {
newItems = itemWithFeeds; newItems = itemWithFeeds;
if (!refreshLayout.isRefreshing()) if (!refreshLayout.isRefreshing())
adapter.submitList(newItems); adapter.submitList(newItems);
})); }));

View File

@ -1,6 +1,7 @@
package com.readrops.app; package com.readrops.app;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -104,6 +105,15 @@ public class MainItemListAdapter extends ListAdapter<ItemWithFeed, MainItemListA
if (itemWithFeed.getColor() != 0) if (itemWithFeed.getColor() != 0)
viewHolder.feedName.setTextColor(itemWithFeed.getColor()); viewHolder.feedName.setTextColor(itemWithFeed.getColor());
Resources resources = viewHolder.itemView.getResources();
int minutes = (int)Math.round(itemWithFeed.getItem().getReadTime());
if (minutes < 1)
viewHolder.itemReadTime.setText(resources.getString(R.string.read_time_lower_than_1));
else if (minutes > 1)
viewHolder.itemReadTime.setText(resources.getString(R.string.read_time, String.valueOf(minutes)));
else
viewHolder.itemReadTime.setText(resources.getString(R.string.read_time_one_minute));
} }
@Override @Override
@ -149,6 +159,7 @@ public class MainItemListAdapter extends ListAdapter<ItemWithFeed, MainItemListA
private TextView itemDescription; private TextView itemDescription;
private ImageView feedIcon; private ImageView feedIcon;
private ImageView itemImage; private ImageView itemImage;
private TextView itemReadTime;
ItemViewHolder(@NonNull View itemView) { ItemViewHolder(@NonNull View itemView) {
super(itemView); super(itemView);
@ -166,6 +177,7 @@ public class MainItemListAdapter extends ListAdapter<ItemWithFeed, MainItemListA
itemDescription = itemView.findViewById(R.id.item_description); itemDescription = itemView.findViewById(R.id.item_description);
feedIcon = itemView.findViewById(R.id.item_feed_icon); feedIcon = itemView.findViewById(R.id.item_feed_icon);
itemImage = itemView.findViewById(R.id.item_image); itemImage = itemView.findViewById(R.id.item_image);
itemReadTime = itemView.findViewById(R.id.item_readtime);
} }
private void bind(ItemWithFeed itemWithFeed) { private void bind(ItemWithFeed itemWithFeed) {
@ -180,6 +192,8 @@ public class MainItemListAdapter extends ListAdapter<ItemWithFeed, MainItemListA
itemDescription.setText(item.getCleanDescription()); itemDescription.setText(item.getCleanDescription());
} else } else
itemDescription.setVisibility(View.GONE); itemDescription.setVisibility(View.GONE);
} }
public ImageView getItemImage() { public ImageView getItemImage() {

View File

@ -20,7 +20,7 @@ public interface ItemDao {
@Query("Select * from Item Order By pub_date DESC") @Query("Select * from Item Order By pub_date DESC")
LiveData<List<Item>> getAll(); LiveData<List<Item>> getAll();
@Query("Select Item.id, title, clean_description, image_link, pub_date, name, color, icon_url from Item Inner Join Feed on Item.feed_id = Feed.id Order By Item.id DESC") @Query("Select Item.id, title, clean_description, image_link, pub_date, name, color, icon_url, read_time from Item Inner Join Feed on Item.feed_id = Feed.id Order By Item.id DESC")
LiveData<List<ItemWithFeed>> getAllItemWithFeeds(); LiveData<List<ItemWithFeed>> getAllItemWithFeeds();
@Query("Select case When :guid In (Select guid from Item) Then 'true' else 'false' end") @Query("Select case When :guid In (Select guid from Item) Then 'true' else 'false' end")
@ -32,6 +32,6 @@ public interface ItemDao {
@Insert @Insert
void insertAll(List<Item> items); void insertAll(List<Item> items);
@Query("Select title, Item.description, content, pub_date, author, 0 as color, name from Item Inner Join Feed on Item.feed_id = Feed.id And Item.id = :id") @Query("Select title, Item.description, content, pub_date, author, 0 as color, read_time, name from Item Inner Join Feed on Item.feed_id = Feed.id And Item.id = :id")
LiveData<ItemWithFeed> getItemById(int id); LiveData<ItemWithFeed> getItemById(int id);
} }

View File

@ -47,6 +47,9 @@ public class Item {
@ColumnInfo(index = true) @ColumnInfo(index = true)
private String guid; private String guid;
@ColumnInfo(name = "read_time")
private double readTime;
public int getId() { public int getId() {
return id; return id;
} }
@ -139,6 +142,14 @@ public class Item {
return getImageLink() != null; return getImageLink() != null;
} }
public double getReadTime() {
return readTime;
}
public void setReadTime(double readTime) {
this.readTime = readTime;
}
public String getText() { public String getText() {
if (content != null) if (content != null)
return content; return content;

View File

@ -23,6 +23,8 @@ public final class Utils {
public static final String HTTPS_PREFIX = "https://"; public static final String HTTPS_PREFIX = "https://";
public static final int AVERAGE_WORDS_PER_MINUTE = 250;
public static void displayErrorInMainThread(Context context, String message) { public static void displayErrorInMainThread(Context context, String message) {
Toast toast = Toast.makeText(context, message, Toast.LENGTH_LONG); Toast toast = Toast.makeText(context, message, Toast.LENGTH_LONG);
@ -55,4 +57,11 @@ public final class Utils {
return displayMetrics.widthPixels; return displayMetrics.widthPixels;
} }
public static double readTimeFromString(String value) {
int nbWords = value.split("\\s+").length;
double minutes = (double)nbWords / AVERAGE_WORDS_PER_MINUTE;
return minutes;
}
} }

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/>
</vector>

View File

@ -58,6 +58,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Headline" android:textAppearance="@style/Base.TextAppearance.AppCompat.Headline"
android:layout_marginBottom="8dp"
tools:text="This is a title" /> tools:text="This is a title" />
<TextView <TextView
@ -66,20 +67,42 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/activity_item_title" android:layout_below="@id/activity_item_title"
android:layout_marginTop="8dp"
android:visibility="gone" android:visibility="gone"
tools:text="By Santa Klaus" /> tools:text="By Santa Klaus"
tools:visibility="visible"/>
<RelativeLayout
android:id="@+id/activity_item_readtime_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_below="@id/activity_item_title"
tools:visibility="visible">
<ImageView
android:id="@+id/activity_item_readtime_icon"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_toStartOf="@id/activity_item_readtime"
android:layout_alignBottom="@id/activity_item_readtime_icon"
android:layout_centerVertical="true"
android:src="@drawable/ic_read_time" />
<TextView <TextView
android:id="@+id/activity_item_readtime" android:id="@+id/activity_item_readtime"
style="@style/Base.TextAppearance.AppCompat.Body1" style="@style/Base.TextAppearance.AppCompat.Body1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/activity_item_title"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_marginTop="8dp" android:layout_alignParentRight="true"
android:visibility="gone" android:layout_marginLeft="4dp"
tools:text="3 minutes reading" /> android:layout_marginStart="4dp"
android:layout_centerHorizontal="true"
android:textAlignment="viewStart"
tools:text="3 minutes read" />
</RelativeLayout>
</RelativeLayout> </RelativeLayout>
<com.readrops.app.utils.ReadropsWebView <com.readrops.app.utils.ReadropsWebView

View File

@ -64,6 +64,13 @@
android:layout_below="@id/layout_start" android:layout_below="@id/layout_start"
android:layout_marginTop="6dp"> android:layout_marginTop="6dp">
<RelativeLayout
android:id="@+id/item_feed_title_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_toStartOf="@id/item_readtime">
<ImageView <ImageView
android:id="@+id/item_feed_icon" android:id="@+id/item_feed_icon"
android:layout_width="20dp" android:layout_width="20dp"
@ -76,17 +83,43 @@
android:id="@+id/item_feed_title" android:id="@+id/item_feed_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="6dp" android:layout_alignParentEnd="true"
android:layout_marginLeft="6dp" android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_toRightOf="@id/item_feed_icon" android:layout_toRightOf="@id/item_feed_icon"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1"
tools:text="Numerama" /> tools:text="Numerama" />
</RelativeLayout>
<TextView
android:id="@+id/item_readtime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginLeft="6dp"
android:layout_toStartOf="@id/item_interpoint"
tools:text="3 mins read" />
<TextView
android:id="@+id/item_interpoint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_toStartOf="@id/item_date"
android:text="@string/interpoint"
android:textStyle="bold" />
<TextView <TextView
android:id="@+id/item_date" android:id="@+id/item_date"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
tools:text="January 10 2019" /> tools:text="January 10 2019" />
</RelativeLayout> </RelativeLayout>

View File

@ -17,5 +17,8 @@
<string name="add_feed_connexion_error">Erreur de connexion au site</string> <string name="add_feed_connexion_error">Erreur de connexion au site</string>
<string name="add_feed_unknownhost_error">Site inconnu</string> <string name="add_feed_unknownhost_error">Site inconnu</string>
<string name="by_author">par %1$s</string> <string name="by_author">par %1$s</string>
<string name="read_time">%1$s minutes</string>
<string name="read_time_lower_than_1">Moins d\'une minute</string>
<string name="read_time_one_minute">1 minute</string>
</resources> </resources>

View File

@ -18,4 +18,8 @@
<string name="add_feed_connexion_error">Connection error</string> <string name="add_feed_connexion_error">Connection error</string>
<string name="add_feed_unknownhost_error">Unknown host</string> <string name="add_feed_unknownhost_error">Unknown host</string>
<string name="by_author">by %1$s</string> <string name="by_author">by %1$s</string>
<string name="read_time">%1$s mins read</string>
<string name="read_time_lower_than_1">Less than a minute</string>
<string name="read_time_one_minute">1 min read</string>
<string name="interpoint" translatable="false">·</string>
</resources> </resources>