Feed database insertion now works with RSS 2.0 feeds, insert dialog is OK

This commit is contained in:
Shinokuni 2019-01-30 19:43:47 +00:00
parent aa692c8222
commit 3b8e3c742a
14 changed files with 228 additions and 76 deletions

View File

@ -7,6 +7,7 @@ import android.os.Looper;
import com.readrops.app.database.Database;
import com.readrops.app.database.entities.Item;
import com.readrops.readropslibrary.ParsingResult;
import com.readrops.readropslibrary.localfeed.RSSNetwork;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@ -35,9 +36,15 @@ public abstract class ARepository {
public abstract void moveFeed(Item item);
protected void failureCallBackInMainThread(Exception ex) {
protected void failureCallBackInMainThread(Exception e) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> callback.onFailure(ex));
handler.post(() -> callback.onFailure(e));
}
protected void postCallBackSuccess() {
// we go back to the main thread
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> callback.onSuccess());
}
}

View File

@ -11,10 +11,13 @@ import com.readrops.app.database.entities.Item;
import com.readrops.readropslibrary.HtmlParser;
import com.readrops.readropslibrary.ParsingResult;
import com.readrops.readropslibrary.QueryCallback;
import com.readrops.readropslibrary.localfeed.AItem;
import com.readrops.readropslibrary.localfeed.AFeed;
import com.readrops.readropslibrary.localfeed.RSSNetwork;
import com.readrops.readropslibrary.localfeed.atom.ATOMEntry;
import com.readrops.readropslibrary.localfeed.atom.ATOMFeed;
import com.readrops.readropslibrary.localfeed.json.JSONFeed;
import com.readrops.readropslibrary.localfeed.json.JSONItem;
import com.readrops.readropslibrary.localfeed.rss.RSSFeed;
import com.readrops.readropslibrary.localfeed.rss.RSSItem;
import java.text.ParseException;
@ -23,7 +26,7 @@ import java.util.List;
public class LocalFeedRepository extends ARepository implements QueryCallback {
public static final String TAG = LocalFeedRepository.class.getSimpleName();
private static final String TAG = LocalFeedRepository.class.getSimpleName();
private LiveData<List<Item>> items;
private List<Feed> feeds;
@ -53,16 +56,21 @@ public class LocalFeedRepository extends ARepository implements QueryCallback {
}
}
// we go back to the main thread
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> callback.onSuccess());
postCallBackSuccess();
});
}
@Override
public void addFeed(ParsingResult result) {
executor.execute(() -> {
try {
RSSNetwork rssNet = new RSSNetwork();
rssNet.request(result.getUrl(), this);
postCallBackSuccess();
} catch (Exception e) {
failureCallBackInMainThread(e);
}
});
}
@ -80,39 +88,84 @@ public class LocalFeedRepository extends ARepository implements QueryCallback {
@Override
public void onSyncSuccess(List<? extends AItem> items, RSSNetwork.RSSType type, String feedUrl) {
public void onSyncSuccess(AFeed feed, RSSNetwork.RSSType type) {
switch (type) {
case RSS_2:
List<RSSItem> rssItems = (List<RSSItem>)items;
parseRSSItems(rssItems, feedUrl);
parseRSSItems(((RSSFeed) feed));
break;
case RSS_ATOM:
List<ATOMEntry> atomItems = (List<ATOMEntry>)items;
parseATOMItems(atomItems, feedUrl);
parseATOMItems(((ATOMFeed) feed));
break;
case RSS_JSON:
List<JSONItem> jsonItems = (List<JSONItem>)items;
parseJSONItems(jsonItems, feedUrl);
parseJSONItems(((JSONFeed) feed));
break;
}
}
@Override
public void onSyncFailure(Exception ex) {
failureCallBackInMainThread(ex);
public void onSyncFailure(Exception e) {
failureCallBackInMainThread(e);
}
private void parseRSSItems(List<RSSItem> items, String feedUrl) {
Feed feed = database.feedDao().getFeedByUrl(feedUrl);
private void parseRSSItems(RSSFeed rssFeed) {
Feed dbFeed = database.feedDao().getFeedByUrl(rssFeed.getChannel().getFeedUrl());
if (dbFeed == null) {
dbFeed = Feed.feedFromRSS(rssFeed.getChannel());
database.feedDao().insert(dbFeed);
dbFeed.setId(database.feedDao().getFeedIdByUrl(rssFeed.getChannel().getFeedUrl()));
}
List<Item> dbItems = new ArrayList<>();
try {
dbItems = Item.itemsFromRSS(items, feed);
dbItems = Item.itemsFromRSS(rssFeed.getChannel().getItems(), dbFeed);
} catch (ParseException e) {
e.printStackTrace();
failureCallBackInMainThread(e);
}
for (Item dbItem : dbItems) {
insertItems(dbItems);
}
private void parseATOMItems(ATOMFeed feed) {
Feed dbFeed = database.feedDao().getFeedByUrl(feed.getLink());
if (dbFeed == null) {
dbFeed = Feed.feedFromATOM(feed);
database.feedDao().insert(dbFeed);
dbFeed.setId(database.feedDao().getFeedIdByUrl(feed.getLink()));
}
List<Item> dbItems = new ArrayList<>();
try {
dbItems = Item.itemsFromATOM(feed.getEntries(), dbFeed);
} catch (ParseException e) {
failureCallBackInMainThread(e);
}
insertItems(dbItems);
}
private void parseJSONItems(JSONFeed feed) {
Feed dbFeed = database.feedDao().getFeedByUrl(feed.getFeedUrl());
if (dbFeed == null) {
dbFeed = Feed.feedFromJSON(feed);
database.feedDao().insert(dbFeed);
dbFeed.setId(database.feedDao().getFeedIdByUrl(feed.getFeedUrl()));
}
List<Item> dbItems = new ArrayList<>();
try {
dbItems = Item.itemsFromJSON(feed.getItems(), dbFeed);
} catch (ParseException e) {
failureCallBackInMainThread(e);
}
insertItems(dbItems);
}
private void insertItems(List<Item> items) {
for (Item dbItem : items) {
if (!Boolean.valueOf(database.itemDao().guidExist(dbItem.getGuid()))) {
dbItem.setImageLink(HtmlParser.getDescImageLink(dbItem.getDescription()));
@ -122,36 +175,4 @@ public class LocalFeedRepository extends ARepository implements QueryCallback {
}
}
private void parseATOMItems(List<ATOMEntry> items, String feedUrl) {
Feed feed = database.feedDao().getFeedByUrl(feedUrl);
List<Item> dbItems = new ArrayList<>();
try {
dbItems = Item.itemsFromATOM(items, feed);
} catch (ParseException e) {
e.printStackTrace();
}
for (Item dbItem : dbItems) {
if (!Boolean.valueOf(database.itemDao().guidExist(dbItem.getGuid())))
database.itemDao().insert(dbItem);
}
}
private void parseJSONItems(List<JSONItem> items, String feedUrl) {
Feed feed = database.feedDao().getFeedByUrl(feedUrl);
List<Item> dbItems = new ArrayList<>();
try {
dbItems = Item.itemsFromJSON(items, feed);
} catch (ParseException e) {
e.printStackTrace();
}
for (Item dbItem : dbItems) {
if (!Boolean.valueOf(database.itemDao().guidExist(dbItem.getGuid())))
database.itemDao().insert(dbItem);
}
}
}

View File

@ -186,6 +186,7 @@ public class MainActivity extends AppCompatActivity implements SimpleCallback, S
}
public void insertNewFeed(ParsingResult result) {
refreshLayout.setRefreshing(true);
viewModel.addFeed(result);
}
}

View File

@ -24,4 +24,7 @@ public interface FeedDao {
@Query("Select * from Feed Where url = :feedUrl")
Feed getFeedByUrl(String feedUrl);
@Query("Select id from Feed Where url = :feedUrl")
int getFeedIdByUrl(String feedUrl);
}

View File

@ -3,6 +3,8 @@ package com.readrops.app.database.entities;
import android.arch.persistence.room.*;
import com.readrops.readropslibrary.localfeed.atom.ATOMFeed;
import com.readrops.readropslibrary.localfeed.json.JSONFeed;
import com.readrops.readropslibrary.localfeed.rss.RSSChannel;
@Entity
@ -17,6 +19,10 @@ public class Feed {
private String url;
private String siteUrl;
private String lastUpdated;
public Feed() {
}
@ -52,6 +58,14 @@ public class Feed {
this.url = url;
}
public String getSiteUrl() {
return siteUrl;
}
public void setSiteUrl(String siteUrl) {
this.siteUrl = siteUrl;
}
public String getName() {
return name;
}
@ -60,11 +74,44 @@ public class Feed {
this.name = name;
}
public String getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(String lastUpdated) {
this.lastUpdated = lastUpdated;
}
public static Feed feedFromRSS(RSSChannel channel) {
Feed feed = new Feed();
feed.setUrl(channel.getLink());
feed.setName(channel.getTitle());
feed.setUrl(channel.getFeedUrl());
feed.setSiteUrl(channel.getUrl());
feed.setDescription(channel.getDescription());
feed.setLastUpdated(channel.getLastUpdated());
return feed;
}
public static Feed feedFromATOM(ATOMFeed atomFeed) {
Feed feed = new Feed();
feed.setName(atomFeed.getTitle());
feed.setDescription(atomFeed.getSubtitle());
feed.setUrl(atomFeed.getLink());
feed.setLastUpdated(atomFeed.getUpdated());
return feed;
}
public static Feed feedFromJSON(JSONFeed jsonFeed) {
Feed feed = new Feed();
feed.setName(jsonFeed.getTitle());
feed.setUrl(jsonFeed.getFeedUrl());
feed.setDescription(jsonFeed.getDescription());
//feed.setLastUpdated(jsonFeed.); maybe later ?
return feed;
}

View File

@ -4,7 +4,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground">
<TextView
android:id="@+id/add_feed_item_label"

View File

@ -1,14 +1,12 @@
package com.readrops.readropslibrary;
import com.readrops.readropslibrary.localfeed.AItem;
import com.readrops.readropslibrary.localfeed.AFeed;
import com.readrops.readropslibrary.localfeed.RSSNetwork;
import java.util.List;
public interface QueryCallback {
void onSyncSuccess(List<? extends AItem> items, RSSNetwork.RSSType type, String feedUrl);
void onSyncSuccess(AFeed feed, RSSNetwork.RSSType type);
void onSyncFailure(Exception ex);
void onSyncFailure(Exception e);
}

View File

@ -0,0 +1,7 @@
package com.readrops.readropslibrary.localfeed;
/*
A simple class to give an abstract level to rss/atom/json feed classes
*/
public abstract class AFeed {
}

View File

@ -1,7 +1,5 @@
package com.readrops.readropslibrary.localfeed;
import android.util.Log;
import com.google.gson.Gson;
import com.readrops.readropslibrary.QueryCallback;
import com.readrops.readropslibrary.Utils.Utils;
@ -13,7 +11,6 @@ import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import java.io.InputStream;
import java.util.List;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@ -57,16 +54,16 @@ public class RSSNetwork {
switch (type) {
case RSS_2:
RSSFeed rssFeed = serializer.read(RSSFeed.class, xml);
callback.onSyncSuccess(rssFeed.getChannel().getItems(), type, url);
callback.onSyncSuccess(rssFeed, type);
break;
case RSS_ATOM:
ATOMFeed atomFeed = serializer.read(ATOMFeed.class, stream);
callback.onSyncSuccess(atomFeed.getEntries(), type, url);
callback.onSyncSuccess(atomFeed, type);
break;
case RSS_JSON:
Gson gson = new Gson();
JSONFeed feed = gson.fromJson(Utils.inputStreamToString(stream), JSONFeed.class);
callback.onSyncSuccess(feed.getItems(), type, url);
callback.onSyncSuccess(feed, type);
break;
}
}

View File

@ -1,5 +1,7 @@
package com.readrops.readropslibrary.localfeed.atom;
import com.readrops.readropslibrary.localfeed.AFeed;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;
@ -7,7 +9,7 @@ import org.simpleframework.xml.Root;
import java.util.List;
@Root(name = "feed", strict = false)
public class ATOMFeed {
public class ATOMFeed extends AFeed {
@Element(required = false)
private String title;

View File

@ -1,10 +1,11 @@
package com.readrops.readropslibrary.localfeed.json;
import com.google.gson.annotations.SerializedName;
import com.readrops.readropslibrary.localfeed.AFeed;
import java.util.List;
public class JSONFeed {
public class JSONFeed extends AFeed {
private String title;

View File

@ -15,8 +15,12 @@ public class RSSChannel {
@Element(name = "description", required = false)
private String description;
@Element(name = "link", required = false)
private String link;
// workaround to get the two links (feed and regular)
@ElementList(name = "link", inline = true, required = false)
private List<RSSLink> links;
@Element(name = "lastBuildDate", required = false)
private String lastUpdated;
@Element(required = false)
private RSSImage image;
@ -24,7 +28,6 @@ public class RSSChannel {
@ElementList(inline = true, required = false)
private List<RSSItem> items;
public String getTitle() {
return title;
}
@ -41,12 +44,12 @@ public class RSSChannel {
this.description = description;
}
public String getLink() {
return link;
public List<RSSLink> getLinks() {
return links;
}
public void setLink(String link) {
this.link = link;
public void setLinks(List<RSSLink> links) {
this.links = links;
}
public List<RSSItem> getItems() {
@ -56,4 +59,34 @@ public class RSSChannel {
public void setItems(List<RSSItem> items) {
this.items = items;
}
public String getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(String lastUpdated) {
this.lastUpdated = lastUpdated;
}
public RSSImage getImage() {
return image;
}
public void setImage(RSSImage image) {
this.image = image;
}
public String getFeedUrl() {
if (links.size() > 0)
return links.get(0).getHref();
else
return null;
}
public String getUrl() {
if (links.size() > 1)
return links.get(1).getText();
else
return null;
}
}

View File

@ -1,10 +1,12 @@
package com.readrops.readropslibrary.localfeed.rss;
import com.readrops.readropslibrary.localfeed.AFeed;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
@Root(name = "rss", strict = false)
public class RSSFeed {
public class RSSFeed extends AFeed {
@Element(name = "channel", required = false)
private RSSChannel channel;

View File

@ -0,0 +1,32 @@
package com.readrops.readropslibrary.localfeed.rss;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.Text;
@Root(name = "link", strict = false)
public class RSSLink {
@Text(required = false)
private String text;
@Attribute(name = "href", required = false)
private String href;
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}