Add a basic feed request and display with some android architect components

This commit is contained in:
Shinokuni 2019-01-22 22:51:18 +00:00
parent 4d1d723158
commit 88aa232f81
26 changed files with 839 additions and 55 deletions

View File

@ -96,7 +96,7 @@ TERMS AND CONDITIONS
12. No Surrender of Others' Freedom. 12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License. 13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. Notwithstanding any other provision of this License, you have permission to url or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
14. Revised Versions of this License. 14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.

View File

@ -40,4 +40,7 @@ dependencies {
implementation 'com.squareup.retrofit2:converter-simplexml:2.4.0' implementation 'com.squareup.retrofit2:converter-simplexml:2.4.0'
implementation 'com.android.support:recyclerview-v7:28.0.0' implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation "android.arch.persistence.room:runtime:1.1.1"
annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
} }

View File

@ -0,0 +1,44 @@
package com.readrops.app;
import android.app.Application;
import android.os.Handler;
import android.os.Looper;
import com.readrops.app.database.Database;
import com.readrops.app.database.entities.Item;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public abstract class ARepository {
protected Executor executor;
protected SimpleCallback callback;
protected Database database;
protected ARepository(Application application) {
executor = Executors.newSingleThreadExecutor();
this.database = Database.getInstance(application);
}
public void setCallback(SimpleCallback callback) {
this.callback = callback;
}
public abstract void sync();
public abstract void addFeed(Item item);
public abstract void deleteFeed(Item item);
public abstract void moveFeed(Item item);
protected void failureCallBackInMainThread(Exception ex) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> {
callback.onFailure(ex);
});
}
}

View File

@ -0,0 +1,130 @@
package com.readrops.app;
import android.app.Application;
import android.arch.lifecycle.LiveData;
import android.os.Handler;
import com.readrops.app.database.Database;
import com.readrops.app.database.entities.Feed;
import com.readrops.app.database.entities.Item;
import com.readrops.readropslibrary.QueryCallback;
import com.readrops.readropslibrary.localfeed.AItem;
import com.readrops.readropslibrary.localfeed.RSSNetwork;
import com.readrops.readropslibrary.localfeed.atom.ATOMEntry;
import com.readrops.readropslibrary.localfeed.json.JSONItem;
import com.readrops.readropslibrary.localfeed.rss.RSSItem;
import java.util.List;
import static com.readrops.readropslibrary.localfeed.RSSNetwork.RSSType.RSS_2;
import static com.readrops.readropslibrary.localfeed.RSSNetwork.RSSType.RSS_ATOM;
import static com.readrops.readropslibrary.localfeed.RSSNetwork.RSSType.RSS_JSON;
public class LocalFeedRepository extends ARepository implements QueryCallback {
private LiveData<List<Item>> items;
public LocalFeedRepository(Application application) {
super(application);
items = database.itemDao().getAll();
}
public LiveData<List<Item>> getItems() {
return items;
}
@Override
public void sync() {
executor.execute(() -> {
RSSNetwork request = new RSSNetwork();
List<Feed> feeds = database.feedDao().getAllFeeds();
for (Feed feed : feeds) {
try {
request.request(feed.getUrl(), this);
} catch (Exception e) {
failureCallBackInMainThread(e);
}
}
callback.onSuccess();
});
}
@Override
public void addFeed(Item item) {
executor.execute(() -> {
});
}
@Override
public void deleteFeed(Item item) {
}
@Override
public void moveFeed(Item item) {
}
@Override
public void onSyncSuccess(List<? extends AItem> items, RSSNetwork.RSSType type, String feedUrl) {
switch (type) {
case RSS_2:
List<RSSItem> rssItems = (List<RSSItem>)items;
parseRSSItems(rssItems, feedUrl);
break;
case RSS_ATOM:
List<ATOMEntry> atomItems = (List<ATOMEntry>)items;
parseATOMItems(atomItems, feedUrl);
break;
case RSS_JSON:
List<JSONItem> jsonItems = (List<JSONItem>)items;
parseJSONItems(jsonItems, feedUrl);
break;
}
}
@Override
public void onSyncFailure(Exception ex) {
failureCallBackInMainThread(ex);
}
private void parseRSSItems(List<RSSItem> items, String feedUrl) {
Feed feed = database.feedDao().getFeedByUrl(feedUrl);
List<Item> dbItems = Item.itemsFromRSS(items, feed);
for (Item dbItem : dbItems) {
if (!Boolean.valueOf(database.itemDao().guidExist(dbItem.getGuid())))
database.itemDao().insert(dbItem);
}
}
private void parseATOMItems(List<ATOMEntry> items, String feedUrl) {
Feed feed = database.feedDao().getFeedByUrl(feedUrl);
List<Item> dbItems = Item.itemsFromATOM(items, feed);
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 = Item.itemsFromJSON(items, feed);
for (Item dbItem : dbItems) {
if (!Boolean.valueOf(database.itemDao().guidExist(dbItem.getGuid())))
database.itemDao().insert(dbItem);
}
}
}

View File

@ -1,5 +1,6 @@
package com.readrops.app; package com.readrops.app;
import android.arch.lifecycle.ViewModelProvider;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.DividerItemDecoration;
@ -7,9 +8,15 @@ import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.Log; import android.util.Log;
import com.readrops.app.database.entities.Item;
import com.readrops.readropslibrary.PageParser; import com.readrops.readropslibrary.PageParser;
import com.readrops.readropslibrary.QueryCallback;
import com.readrops.readropslibrary.Utils.Utils; import com.readrops.readropslibrary.Utils.Utils;
import com.readrops.readropslibrary.localfeed.AItem;
import com.readrops.readropslibrary.localfeed.RSSNetwork; import com.readrops.readropslibrary.localfeed.RSSNetwork;
import com.readrops.readropslibrary.localfeed.atom.ATOMEntry;
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.RSSFeed;
import com.readrops.readropslibrary.localfeed.rss.RSSItem; import com.readrops.readropslibrary.localfeed.rss.RSSItem;
@ -31,8 +38,9 @@ public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView; private RecyclerView recyclerView;
private MainAdapter adapter; private MainAdapter adapter;
private List<RSSItem> itemList; private List<Item> itemList;
private MainViewModel viewModel;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -50,42 +58,14 @@ public class MainActivity extends AppCompatActivity {
thread.start();*/ thread.start();*/
getItems(); viewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication()).create(MainViewModel.class);
} viewModel.getItems().observe(this, (List<Item> items) -> {
this.itemList = items;
private void getItems() {
RSSNetwork request = new RSSNetwork();
request.request("https://www.numerama.com/feed/", new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
InputStream stream = response.body().byteStream();
String xml = Utils.inputStreamToString(stream);
Serializer serializer = new Persister();
try {
RSSFeed rssFeed = serializer.read(RSSFeed.class, xml);
itemList = rssFeed.getChannel().getItems();
runOnUiThread(() -> {
initRecyclerView(); initRecyclerView();
}); });
viewModel.sync();
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
} }
private void initRecyclerView() { private void initRecyclerView() {
@ -99,6 +79,4 @@ public class MainActivity extends AppCompatActivity {
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
} }
} }

View File

@ -12,6 +12,7 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.readrops.app.database.entities.Item;
import com.readrops.readropslibrary.PageParser; import com.readrops.readropslibrary.PageParser;
import com.readrops.readropslibrary.localfeed.rss.RSSItem; import com.readrops.readropslibrary.localfeed.rss.RSSItem;
@ -19,10 +20,10 @@ import java.util.List;
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> { public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {
List<RSSItem> items; List<Item> items;
private Context context; private Context context;
public MainAdapter(Context context, List<RSSItem> items) { public MainAdapter(Context context, List<Item> items) {
this.context = context; this.context = context;
this.items = items; this.items = items;
} }
@ -38,13 +39,13 @@ public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {
@Override @Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) { public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
RSSItem item = items.get(i); Item item = items.get(i);
viewHolder.bind(item); viewHolder.bind(item);
Thread thread = new Thread(() -> { /*Thread thread = new Thread(() -> {
String imageUrl = PageParser.getOGImageLink(item.getLink()); String imageUrl = PageParser.getOGImageLink(item.getLink());
Glide.with(context).load(imageUrl).into(viewHolder.itemImage); Glide.with(context).load(imageUrl).into(viewHolder.itemImage);
}); });*/
} }
@ -66,7 +67,7 @@ public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {
itemImage = itemView.findViewById(R.id.item_image); itemImage = itemView.findViewById(R.id.item_image);
} }
private void bind(RSSItem item) { private void bind(Item item) {
itemTitle.setText(item.getTitle()); itemTitle.setText(item.getTitle());
} }
} }

View File

@ -0,0 +1,43 @@
package com.readrops.app;
import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.support.annotation.NonNull;
import com.readrops.app.database.entities.Item;
import java.util.List;
public class MainViewModel extends AndroidViewModel implements SimpleCallback {
private LiveData<List<Item>> items;
private LocalFeedRepository repository;
public MainViewModel(@NonNull Application application) {
super(application);
repository = new LocalFeedRepository(application);
repository.setCallback(this);
items = repository.getItems();
}
public LiveData<List<Item>> getItems() {
return items;
}
public void sync() {
repository.sync();
}
@Override
public void onSuccess() {
}
@Override
public void onFailure(Exception ex) {
}
}

View File

@ -0,0 +1,8 @@
package com.readrops.app;
public interface SimpleCallback {
void onSuccess();
void onFailure(Exception ex);
}

View File

@ -0,0 +1,47 @@
package com.readrops.app.database;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.room.Room;
import android.arch.persistence.room.RoomDatabase;
import android.content.Context;
import android.support.annotation.NonNull;
import com.readrops.app.database.dao.FeedDao;
import com.readrops.app.database.dao.ItemDao;
import com.readrops.app.database.entities.Feed;
import com.readrops.app.database.entities.Item;
@android.arch.persistence.room.Database(entities = {Feed.class, Item.class}, version = 1)
public abstract class Database extends RoomDatabase {
public abstract FeedDao feedDao();
public abstract ItemDao itemDao();
private static Database database;
public static Database getInstance(Context context) {
if (database == null)
database = Room.databaseBuilder(context, Database.class, "readrops-db").addCallback(roomCallback).build();
return database;
}
public static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
Feed feed1 = new Feed("XDA Developers", "desc", "https://www.xda-developers.com/feed/");
new Thread(() -> database.feedDao().insert(feed1)).start();
}
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
}
};
}

View File

@ -0,0 +1,27 @@
package com.readrops.app.database.dao;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.Query;
import com.readrops.app.database.entities.Feed;
import java.util.List;
@Dao
public interface FeedDao {
@Query("Select * from Feed")
List<Feed> getAllFeeds();
@Insert
void insert(Feed feed);
@Query("Select count(*) from Feed")
int getFeedCount();
@Query("Select * from Feed Where url = :feedUrl")
Feed getFeedByUrl(String feedUrl);
}

View File

@ -0,0 +1,30 @@
package com.readrops.app.database.dao;
import android.arch.lifecycle.LiveData;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.Query;
import com.readrops.app.database.entities.Item;
import java.util.List;
@Dao
public interface ItemDao {
@Query("Select * from Item Where feed_id = :feedId")
LiveData<List<Item>> getAllByFeed(int feedId);
@Query("Select * from Item")
LiveData<List<Item>> getAll();
@Query("Select case When :guid In (Select guid from Item) Then 'true' else 'false' end")
String guidExist(String guid);
@Insert
void insert(Item item);
@Insert
void insertAll(List<Item> items);
}

View File

@ -0,0 +1,70 @@
package com.readrops.app.database.entities;
import android.arch.persistence.room.*;
import com.readrops.readropslibrary.localfeed.rss.RSSChannel;
@Entity
public class Feed {
@PrimaryKey(autoGenerate = true)
private int id;
private String name;
private String description;
private String url;
public Feed() {
}
public Feed(String name, String description, String url) {
this.name = name;
this.description = description;
this.url = url;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static Feed feedFromRSS(RSSChannel channel) {
Feed feed = new Feed();
feed.setUrl(channel.getLink());
feed.setDescription(channel.getDescription());
return feed;
}
}

View File

@ -0,0 +1,185 @@
package com.readrops.app.database.entities;
import android.arch.persistence.room.*;
import com.readrops.readropslibrary.localfeed.atom.ATOMEntry;
import com.readrops.readropslibrary.localfeed.json.JSONItem;
import com.readrops.readropslibrary.localfeed.rss.RSSChannel;
import com.readrops.readropslibrary.localfeed.rss.RSSItem;
import java.util.ArrayList;
import java.util.List;
@Entity
(foreignKeys = @ForeignKey(entity = Feed.class, parentColumns = "id", childColumns = "feed_id"))
public class Item {
@PrimaryKey(autoGenerate = true)
private int id;
private String title;
private String description;
private String link;
@ColumnInfo(name = "image_link")
private String imageLink;
private String author;
@ColumnInfo(name = "pub_date")
private String pubDate;
private String content;
@ColumnInfo(name = "feed_id", index = true)
private int feedId;
@ColumnInfo(index = true)
private String guid;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getImageLink() {
return imageLink;
}
public void setImageLink(String imageLink) {
this.imageLink = imageLink;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getPubDate() {
return pubDate;
}
public void setPubDate(String pubDate) {
this.pubDate = pubDate;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getGuid() {
return guid;
}
public void setGuid(String guid) {
this.guid = guid;
}
public int getFeedId() {
return feedId;
}
public void setFeedId(int feedId) {
this.feedId = feedId;
}
public static List<Item> itemsFromRSS(List<RSSItem> items, Feed feed) {
List<Item> dbItems = new ArrayList<>();
for(RSSItem item : items) {
Item newItem = new Item();
newItem.setAuthor(item.getAuthor());
newItem.setContent(item.getContent());
newItem.setDescription(item.getDescription());
newItem.setGuid(item.getGuid());
newItem.setTitle(item.getTitle());
newItem.setImageLink(item.getImageLink());
newItem.setPubDate(item.getPubDate());
newItem.setLink(item.getLink());
newItem.setFeedId(feed.getId());
dbItems.add(newItem);
}
return dbItems;
}
public static List<Item> itemsFromATOM(List<ATOMEntry> items, Feed feed) {
List<Item> dbItems = new ArrayList<>();
for (ATOMEntry item : items) {
Item dbItem = new Item();
dbItem.setContent(item.getContent());
dbItem.setDescription(item.getSummary());
dbItem.setGuid(item.getId());
dbItem.setTitle(item.getTitle());
dbItem.setPubDate(item.getUpdated());
dbItem.setLink(item.getLink().getHref());
dbItem.setFeedId(feed.getId());
}
return dbItems;
}
public static List<Item> itemsFromJSON(List<JSONItem> items, Feed feed) {
List<Item> dbItems = new ArrayList<>();
for (JSONItem item : items) {
Item dbItem = new Item();
dbItem.setAuthor(item.getAuthor().getName());
dbItem.setContent(item.getContent());
dbItem.setDescription(item.getSummary());
dbItem.setGuid(item.getId());
dbItem.setTitle(item.getTitle());
dbItem.setPubDate(item.getPubDate());
dbItem.setLink(item.getUrl());
dbItem.setFeedId(feed.getId());
}
return dbItems;
}
}

View File

@ -1,5 +1,6 @@
#Tue Jan 15 18:55:37 GMT 2019
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip

10
gradlew vendored
View File

@ -7,16 +7,16 @@
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a url
PRG="$0" PRG="$0"
# Need this for relative symlinks. # Need this for relative symlinks.
while [ -h "$PRG" ] ; do while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"` ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'` url=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then if expr "$url" : '/.*' > /dev/null; then
PRG="$link" PRG="$url"
else else
PRG=`dirname "$PRG"`"/$link" PRG=`dirname "$PRG"`"/$url"
fi fi
done done
SAVED="`pwd`" SAVED="`pwd`"

View File

@ -0,0 +1,14 @@
package com.readrops.readropslibrary;
import com.readrops.readropslibrary.localfeed.AItem;
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 onSyncFailure(Exception ex);
}

View File

@ -0,0 +1,7 @@
package com.readrops.readropslibrary.localfeed;
/**
* Just an abstract class to wrap the three rss items types
*/
public abstract class AItem {
}

View File

@ -0,0 +1,8 @@
package com.readrops.readropslibrary.localfeed;
public interface OperationCallback {
void onSuccess();
void OnFailure();
}

View File

@ -1,16 +1,83 @@
package com.readrops.readropslibrary.localfeed; package com.readrops.readropslibrary.localfeed;
import com.google.gson.Gson;
import com.readrops.readropslibrary.QueryCallback;
import com.readrops.readropslibrary.Utils.Utils;
import com.readrops.readropslibrary.localfeed.atom.ATOMFeed;
import com.readrops.readropslibrary.localfeed.json.JSONFeed;
import com.readrops.readropslibrary.localfeed.rss.RSSFeed;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import java.io.InputStream;
import java.util.List;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response;
public class RSSNetwork { public class RSSNetwork {
public void request(String url, okhttp3.Callback callback) { /**
* Request the url given in parameter.
* This method is synchronous, <b>it has to be called from another thread than the main one</b>.
* @param url url to request
* @param callback result callback if success or error
* @throws Exception
*/
public void request(String url, final QueryCallback callback) throws Exception {
OkHttpClient okHttpClient = new OkHttpClient(); OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url(url).build(); Request request = new Request.Builder().url(url).build();
Response response = okHttpClient.newCall(request).execute();
okHttpClient.newCall(request).enqueue(callback); if (response.isSuccessful())
parseFeed(response.body().byteStream(), getRSSType(response.header("content-type")), callback, url);
else
callback.onSyncFailure(new Exception("Error " + response.code() + " when requesting url " + url));
}
private void parseFeed(InputStream stream, RSSType type, QueryCallback callback, String url) throws Exception {
//String xml = Utils.inputStreamToString(stream);
Serializer serializer = new Persister();
switch (type) {
case RSS_2:
RSSFeed rssFeed = serializer.read(RSSFeed.class, stream);
callback.onSyncSuccess(rssFeed.getChannel().getItems(), type, url);
break;
case RSS_ATOM:
ATOMFeed atomFeed = serializer.read(ATOMFeed.class, stream);
callback.onSyncSuccess(atomFeed.getEntries(), type, url);
break;
case RSS_JSON:
Gson gson = new Gson();
JSONFeed feed = gson.fromJson(Utils.inputStreamToString(stream), JSONFeed.class);
callback.onSyncSuccess(feed.getItems(), type, url);
break;
}
}
private RSSType getRSSType(String contentType) {
if (contentType.contains(RSSType.RSS_2.value))
return RSSType.RSS_2;
else if (contentType.contains(RSSType.RSS_ATOM.value))
return RSSType.RSS_ATOM;
else
return RSSType.RSS_JSON;
}
public enum RSSType {
RSS_2("rss"),
RSS_ATOM("atom"),
RSS_JSON("json");
private String value;
RSSType(String value) {
this.value = value;
}
} }

View File

@ -1,11 +1,13 @@
package com.readrops.readropslibrary.localfeed.atom; package com.readrops.readropslibrary.localfeed.atom;
import com.readrops.readropslibrary.localfeed.AItem;
import org.simpleframework.xml.Attribute; import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element; import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root; import org.simpleframework.xml.Root;
@Root(name = "entry", strict = false) @Root(name = "entry", strict = false)
public class ATOMEntry { public class ATOMEntry extends AItem {
@Element(required = false) @Element(required = false)
private String title; private String title;
@ -19,11 +21,68 @@ public class ATOMEntry {
@Element(required = false) @Element(required = false)
private String summary; private String summary;
@Element(required = false)
private String id;
@Element(required = false) @Element(required = false)
private String content; private String content;
@Attribute(name = "type", required = false) @Attribute(name = "type", required = false)
private String contentType; private String contentType;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public ATOMLink getLink() {
return link;
}
public void setLink(ATOMLink link) {
this.link = link;
}
public String getUpdated() {
return updated;
}
public void setUpdated(String updated) {
this.updated = updated;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
} }

View File

@ -27,4 +27,51 @@ public class ATOMFeed {
@ElementList(inline = true, required = false) @ElementList(inline = true, required = false)
private List<ATOMEntry> entries; private List<ATOMEntry> entries;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getSubtitle() {
return subtitle;
}
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
public String getUpdated() {
return updated;
}
public void setUpdated(String updated) {
this.updated = updated;
}
public ATOMAuthor getAuthor() {
return author;
}
public void setAuthor(ATOMAuthor author) {
this.author = author;
}
public List<ATOMEntry> getEntries() {
return entries;
}
public void setEntries(List<ATOMEntry> entries) {
this.entries = entries;
}
} }

View File

@ -12,4 +12,6 @@ public class ATOMLink {
public String getHref() { public String getHref() {
return href; return href;
} }
} }

View File

@ -34,4 +34,6 @@ public class JSONAuthor {
public void setAvatarUrl(String avatarUrl) { public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl; this.avatarUrl = avatarUrl;
} }
} }

View File

@ -1,8 +1,9 @@
package com.readrops.readropslibrary.localfeed.json; package com.readrops.readropslibrary.localfeed.json;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import com.readrops.readropslibrary.localfeed.AItem;
public class JSONItem { public class JSONItem extends AItem {
private String id; private String id;
@ -104,6 +105,14 @@ public class JSONItem {
this.author = author; this.author = author;
} }
public String getContent() {
if (contentHtml == null)
return contentText;
else
return contentHtml;
}
@SerializedName("date_modified") @SerializedName("date_modified")
private String modDate; private String modDate;

View File

@ -1,11 +1,13 @@
package com.readrops.readropslibrary.localfeed.rss; package com.readrops.readropslibrary.localfeed.rss;
import com.readrops.readropslibrary.localfeed.AItem;
import org.simpleframework.xml.Element; import org.simpleframework.xml.Element;
import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root; import org.simpleframework.xml.Root;
@Root(name = "item", strict = false) @Root(name = "item", strict = false)
public class RSSItem { public class RSSItem extends AItem {
@Element(name = "title", required = false) @Element(name = "title", required = false)
private String title; private String title;