mirror of
https://github.com/readrops/Readrops.git
synced 2025-01-29 18:09:28 +01:00
Requesting folders, feeds and items from Nextcloud News now works
This commit is contained in:
parent
3903bb6eb1
commit
92ce491771
@ -5,7 +5,6 @@ import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Update;
|
||||
|
||||
import com.readrops.app.database.entities.Feed;
|
||||
import com.readrops.app.database.pojo.FeedWithFolder;
|
||||
@ -21,8 +20,8 @@ public interface FeedDao {
|
||||
@Insert
|
||||
long insert(Feed feed);
|
||||
|
||||
@Update
|
||||
void update(Feed feed);
|
||||
@Insert
|
||||
long[] insert(List<Feed> feeds);
|
||||
|
||||
@Query("Delete From Feed Where id = :feedId")
|
||||
void delete(int feedId);
|
||||
@ -30,12 +29,18 @@ public interface FeedDao {
|
||||
@Query("Select case When :feedUrl In (Select url from Feed) Then 'true' else 'false' end")
|
||||
String feedExists(String feedUrl);
|
||||
|
||||
@Query("Select case When :remoteId In (Select remoteId from Feed) Then 1 else 0 end")
|
||||
boolean remoteFeedExists(int remoteId);
|
||||
|
||||
@Query("Select count(*) from Feed")
|
||||
int getFeedCount();
|
||||
|
||||
@Query("Select * from Feed Where url = :feedUrl")
|
||||
Feed getFeedByUrl(String feedUrl);
|
||||
|
||||
@Query("Select * from Feed Where remoteId = :remoteId")
|
||||
Feed getFeedByRemoteId(int remoteId);
|
||||
|
||||
@Query("Select * from Feed Where folder_id = :folderId")
|
||||
List<Feed> getFeedsByFolder(int folderId);
|
||||
|
||||
@ -48,9 +53,15 @@ public interface FeedDao {
|
||||
@Query("Update Feed set name = :feedName, url = :feedUrl, folder_id = :folderId Where id = :feedId")
|
||||
void updateFeedFields(int feedId, String feedName, String feedUrl, int folderId);
|
||||
|
||||
@Query("Update Feed set text_color = :textColor, background_color = :bgColor Where id = :feedId")
|
||||
void updateColors(int feedId, int textColor, int bgColor);
|
||||
|
||||
@Query("Select Feed.name as feed_name, Feed.id as feed_id, Folder.name as folder_name, Folder.id as folder_id," +
|
||||
"Feed.description as feed_description, Feed.icon_url as feed_icon_url, Feed.url as feed_url, Feed.folder_id as feed_folder_id" +
|
||||
", Feed.siteUrl as feed_siteUrl from Feed Inner Join Folder on Feed.folder_id = Folder.id Order by Feed.name")
|
||||
LiveData<List<FeedWithFolder>> getAllFeedsWithFolder();
|
||||
|
||||
@Query("Select * From Feed Where id in (:ids)")
|
||||
List<Feed> selectFromIdList(long[] ids);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,15 @@ public interface FolderDao {
|
||||
@Insert
|
||||
long insert(Folder folder);
|
||||
|
||||
@Insert
|
||||
long[] insert(List<Folder> folders);
|
||||
|
||||
@Delete
|
||||
void delete(Folder folder);
|
||||
|
||||
@Query("Select id From Folder Where remoteId = :remoteId")
|
||||
int getRemoteFolderLocalId(int remoteId);
|
||||
|
||||
@Query("Select case When :remoteId In (Select remoteId from Folder) Then 1 else 0 end")
|
||||
boolean remoteFolderExists(int remoteId);
|
||||
}
|
||||
|
@ -2,18 +2,19 @@ package com.readrops.app.database.dao;
|
||||
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.paging.DataSource;
|
||||
import androidx.paging.PageKeyedDataSource;
|
||||
import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.RawQuery;
|
||||
import androidx.sqlite.db.SupportSQLiteQuery;
|
||||
|
||||
import com.readrops.app.database.entities.Feed;
|
||||
import com.readrops.app.database.entities.Folder;
|
||||
import com.readrops.app.database.pojo.ItemWithFeed;
|
||||
import com.readrops.app.database.entities.Item;
|
||||
import com.readrops.app.database.pojo.ItemWithFeed;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface ItemDao {
|
||||
@ -24,9 +25,15 @@ public interface ItemDao {
|
||||
@Query("Select case When :guid In (Select guid from Item) Then 'true' else 'false' end")
|
||||
String guidExist(String guid);
|
||||
|
||||
@Query("Select case When :remoteId In (Select remoteId from Item) Then 1 else 0 end")
|
||||
boolean remoteItemExists(int remoteId);
|
||||
|
||||
@Insert
|
||||
long insert(Item item);
|
||||
|
||||
@Insert
|
||||
long[] insert(List<Item> items);
|
||||
|
||||
/**
|
||||
* Set an item read or unread
|
||||
* @param itemId id of the item to update
|
||||
|
@ -1,11 +1,15 @@
|
||||
package com.readrops.app.database.entities;
|
||||
|
||||
|
||||
import androidx.room.*;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.ForeignKey;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import com.readrops.readropslibrary.localfeed.atom.ATOMFeed;
|
||||
import com.readrops.readropslibrary.localfeed.json.JSONFeed;
|
||||
@ -14,8 +18,6 @@ import com.readrops.readropslibrary.localfeed.rss.RSSFeed;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
|
||||
import static androidx.room.ForeignKey.NO_ACTION;
|
||||
|
||||
@Entity(foreignKeys = @ForeignKey(entity = Folder.class, parentColumns = "id", childColumns = "folder_id", onDelete = ForeignKey.SET_NULL))
|
||||
public class Feed implements Parcelable {
|
||||
|
||||
@ -33,7 +35,7 @@ public class Feed implements Parcelable {
|
||||
private String lastUpdated;
|
||||
|
||||
@ColumnInfo(name = "text_color")
|
||||
private @ColorInt int textColor;
|
||||
private @ColorInt int textColor;
|
||||
|
||||
@ColumnInfo(name = "background_color")
|
||||
private @ColorInt int backgroundColor;
|
||||
@ -46,9 +48,11 @@ public class Feed implements Parcelable {
|
||||
@ColumnInfo(name = "last_modified")
|
||||
private String lastModified;
|
||||
|
||||
@ColumnInfo(name = "folder_id")
|
||||
@ColumnInfo(name = "folder_id", index = true)
|
||||
private int folderId;
|
||||
|
||||
private int remoteId;
|
||||
|
||||
@Ignore
|
||||
private int unreadCount;
|
||||
|
||||
@ -76,6 +80,7 @@ public class Feed implements Parcelable {
|
||||
etag = in.readString();
|
||||
lastModified = in.readString();
|
||||
folderId = in.readInt();
|
||||
remoteId = in.readInt();
|
||||
}
|
||||
|
||||
public static final Creator<Feed> CREATOR = new Creator<Feed>() {
|
||||
@ -194,6 +199,14 @@ public class Feed implements Parcelable {
|
||||
this.unreadCount = unreadCount;
|
||||
}
|
||||
|
||||
public int getRemoteId() {
|
||||
return remoteId;
|
||||
}
|
||||
|
||||
public void setRemoteId(int remoteId) {
|
||||
this.remoteId = remoteId;
|
||||
}
|
||||
|
||||
public static Feed feedFromRSS(RSSFeed rssFeed) {
|
||||
Feed feed = new Feed();
|
||||
RSSChannel channel = rssFeed.getChannel();
|
||||
@ -270,5 +283,6 @@ public class Feed implements Parcelable {
|
||||
dest.writeString(etag);
|
||||
dest.writeString(lastModified);
|
||||
dest.writeInt(folderId);
|
||||
dest.writeInt(remoteId);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
package com.readrops.app.database.entities;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.Ignore;
|
||||
import androidx.room.PrimaryKey;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
@Entity
|
||||
public class Folder implements Parcelable, Comparable<Folder> {
|
||||
@ -14,6 +15,8 @@ public class Folder implements Parcelable, Comparable<Folder> {
|
||||
|
||||
private String name;
|
||||
|
||||
private int remoteId;
|
||||
|
||||
public Folder() {
|
||||
|
||||
}
|
||||
@ -46,6 +49,14 @@ public class Folder implements Parcelable, Comparable<Folder> {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getRemoteId() {
|
||||
return remoteId;
|
||||
}
|
||||
|
||||
public void setRemoteId(int remoteId) {
|
||||
this.remoteId = remoteId;
|
||||
}
|
||||
|
||||
public static final Creator<Folder> CREATOR = new Creator<Folder>() {
|
||||
@Override
|
||||
public Folder createFromParcel(Parcel in) {
|
||||
|
@ -47,7 +47,7 @@ public class Item implements Comparable<Item> {
|
||||
|
||||
private String content;
|
||||
|
||||
@ColumnInfo(name = "feed_id")
|
||||
@ColumnInfo(name = "feed_id", index = true)
|
||||
private int feedId;
|
||||
|
||||
@ColumnInfo(index = true)
|
||||
@ -61,6 +61,8 @@ public class Item implements Comparable<Item> {
|
||||
@ColumnInfo(name = "read_it_later")
|
||||
private boolean readItLater;
|
||||
|
||||
private int remoteId;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
@ -184,6 +186,14 @@ public class Item implements Comparable<Item> {
|
||||
this.readItLater = readItLater;
|
||||
}
|
||||
|
||||
public int getRemoteId() {
|
||||
return remoteId;
|
||||
}
|
||||
|
||||
public void setRemoteId(int remoteId) {
|
||||
this.remoteId = remoteId;
|
||||
}
|
||||
|
||||
public static List<Item> itemsFromRSS(List<RSSItem> items, Feed feed) throws ParseException {
|
||||
List<Item> dbItems = new ArrayList<>();
|
||||
|
||||
|
@ -2,17 +2,18 @@ package com.readrops.app.repositories;
|
||||
|
||||
import android.app.Application;
|
||||
import android.graphics.Bitmap;
|
||||
import androidx.palette.graphics.Palette;
|
||||
import android.util.Patterns;
|
||||
|
||||
import com.readrops.app.database.pojo.FeedWithFolder;
|
||||
import com.readrops.app.utils.FeedInsertionResult;
|
||||
import com.readrops.app.utils.HtmlParser;
|
||||
import com.readrops.app.utils.Utils;
|
||||
import androidx.palette.graphics.Palette;
|
||||
|
||||
import com.readrops.app.database.Database;
|
||||
import com.readrops.app.database.entities.Feed;
|
||||
import com.readrops.app.database.entities.Folder;
|
||||
import com.readrops.app.database.pojo.FeedWithFolder;
|
||||
import com.readrops.app.utils.FeedInsertionResult;
|
||||
import com.readrops.app.utils.HtmlParser;
|
||||
import com.readrops.app.utils.ParsingResult;
|
||||
import com.readrops.app.utils.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
@ -79,13 +80,16 @@ public abstract class ARepository {
|
||||
}
|
||||
}
|
||||
|
||||
protected void setFeedColors(String favUrl, Feed feed) throws IOException {
|
||||
protected void setFeedColors(String favUrl, Feed feed) {
|
||||
Bitmap favicon = Utils.getImageFromUrl(favUrl);
|
||||
Palette palette = Palette.from(favicon).generate();
|
||||
|
||||
feed.setTextColor(palette.getDominantSwatch().getRgb());
|
||||
if (favicon != null) {
|
||||
Palette palette = Palette.from(favicon).generate();
|
||||
|
||||
if (palette.getMutedSwatch() != null)
|
||||
feed.setBackgroundColor(palette.getMutedSwatch().getRgb());
|
||||
feed.setTextColor(palette.getDominantSwatch().getRgb());
|
||||
|
||||
if (palette.getMutedSwatch() != null)
|
||||
feed.setBackgroundColor(palette.getMutedSwatch().getRgb());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -219,6 +219,8 @@ public class LocalFeedRepository extends ARepository {
|
||||
}
|
||||
|
||||
private void insertItems(Collection<Item> items, Feed feed) {
|
||||
List<Item> itemsToInsert = new ArrayList<>();
|
||||
|
||||
for (Item dbItem : items) {
|
||||
if (!Boolean.valueOf(database.itemDao().guidExist(dbItem.getGuid()))) {
|
||||
if (dbItem.getDescription() != null) {
|
||||
@ -247,9 +249,11 @@ public class LocalFeedRepository extends ARepository {
|
||||
else if (dbItem.getDescription() != null)
|
||||
dbItem.setReadTime(Utils.readTimeFromString(dbItem.getCleanDescription()));
|
||||
|
||||
database.itemDao().insert(dbItem);
|
||||
itemsToInsert.add(dbItem);
|
||||
}
|
||||
}
|
||||
|
||||
database.itemDao().insert(itemsToInsert);
|
||||
}
|
||||
|
||||
private FeedInsertionResult.FeedInsertionError getErrorFromException(Exception e) {
|
||||
|
@ -1,25 +1,38 @@
|
||||
package com.readrops.app.repositories;
|
||||
|
||||
import android.app.Application;
|
||||
import android.util.TimingLogger;
|
||||
|
||||
import com.readrops.app.database.entities.Feed;
|
||||
import com.readrops.app.database.entities.Folder;
|
||||
import com.readrops.app.database.entities.Item;
|
||||
import com.readrops.app.database.pojo.FeedWithFolder;
|
||||
import com.readrops.app.utils.FeedInsertionResult;
|
||||
import com.readrops.app.utils.FeedMatcher;
|
||||
import com.readrops.app.utils.ItemMatcher;
|
||||
import com.readrops.app.utils.ParsingResult;
|
||||
import com.readrops.app.utils.Utils;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.Credentials;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.NextNewsAPI;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.SyncResults;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFeed;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFolder;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsItem;
|
||||
import com.readrops.readropslibrary.utils.LibUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
public class NextNewsRepository extends ARepository {
|
||||
|
||||
private static final String TAG = NextNewsRepository.class.getSimpleName();
|
||||
|
||||
public NextNewsRepository(Application application) {
|
||||
super(application);
|
||||
}
|
||||
@ -31,7 +44,18 @@ public class NextNewsRepository extends ARepository {
|
||||
NextNewsAPI newsAPI = new NextNewsAPI();
|
||||
|
||||
Credentials credentials = new Credentials("", LibUtils.NEXTCLOUD_PASSWORD, "");
|
||||
newsAPI.sync(credentials, NextNewsAPI.SyncType.INITIAL_SYNC, null);
|
||||
SyncResults results = newsAPI.sync(credentials, NextNewsAPI.SyncType.INITIAL_SYNC, null);
|
||||
|
||||
TimingLogger timings = new TimingLogger(TAG, "sync");
|
||||
insertFolders(results.getFolders());
|
||||
timings.addSplit("insert folders");
|
||||
|
||||
insertFeeds(results.getFeeds());
|
||||
timings.addSplit("insert feeds");
|
||||
|
||||
insertItems(results.getItems());
|
||||
timings.addSplit("insert items");
|
||||
timings.dumpToLog();
|
||||
|
||||
emitter.onComplete();
|
||||
} catch (IOException e) {
|
||||
@ -60,4 +84,77 @@ public class NextNewsRepository extends ARepository {
|
||||
public Completable addFolder(Folder folder) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void insertFeeds(List<NextNewsFeed> feeds) {
|
||||
List<Feed> newFeeds = new ArrayList<>();
|
||||
|
||||
for (NextNewsFeed nextNewsFeed : feeds) {
|
||||
|
||||
if (!database.feedDao().remoteFeedExists(nextNewsFeed.getId())) {
|
||||
Feed feed = FeedMatcher.nextNewsFeedToFeed(nextNewsFeed);
|
||||
|
||||
// if the Nextcloud feed has a folder, it is already inserted, so we have to get its local id
|
||||
if (nextNewsFeed.getFolderId() != 0) {
|
||||
int folderId = database.folderDao().getRemoteFolderLocalId(nextNewsFeed.getFolderId());
|
||||
|
||||
if (folderId != 0)
|
||||
feed.setFolderId(folderId);
|
||||
}
|
||||
|
||||
newFeeds.add(feed);
|
||||
}
|
||||
}
|
||||
|
||||
long[] ids = database.feedDao().insert(newFeeds);
|
||||
|
||||
List<Feed> insertedFeeds = database.feedDao().selectFromIdList(ids);
|
||||
Observable.<Feed>create(emitter -> {
|
||||
for (Feed feed : insertedFeeds) {
|
||||
setFavIconUtils(feed);
|
||||
emitter.onNext(feed);
|
||||
}
|
||||
}).subscribeOn(Schedulers.computation())
|
||||
.observeOn(Schedulers.io())
|
||||
.doOnNext(feed1 -> database.feedDao().updateColors(feed1.getId(),
|
||||
feed1.getTextColor(), feed1.getBackgroundColor()))
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
private void insertFolders(List<NextNewsFolder> folders) {
|
||||
List<Folder> newFolders = new ArrayList<>();
|
||||
|
||||
for (NextNewsFolder nextNewsFolder : folders) {
|
||||
|
||||
if (!database.folderDao().remoteFolderExists(nextNewsFolder.getId())) {
|
||||
Folder folder = new Folder(nextNewsFolder.getName());
|
||||
folder.setRemoteId(nextNewsFolder.getId());
|
||||
|
||||
newFolders.add(folder);
|
||||
}
|
||||
}
|
||||
|
||||
database.folderDao().insert(newFolders);
|
||||
}
|
||||
|
||||
private void insertItems(List<NextNewsItem> items) {
|
||||
List<Item> newItems = new ArrayList<>();
|
||||
|
||||
for (NextNewsItem nextNewsItem : items) {
|
||||
|
||||
if (!database.itemDao().remoteItemExists(nextNewsItem.getId())) {
|
||||
try {
|
||||
Feed feed = database.feedDao().getFeedByRemoteId(nextNewsItem.getFeedId());
|
||||
Item item = ItemMatcher.nextNewsItemToItem(nextNewsItem, feed);
|
||||
|
||||
item.setReadTime(Utils.readTimeFromString(item.getContent()));
|
||||
|
||||
newItems.add(item);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
database.itemDao().insert(newItems);
|
||||
}
|
||||
}
|
||||
|
24
app/src/main/java/com/readrops/app/utils/FeedMatcher.java
Normal file
24
app/src/main/java/com/readrops/app/utils/FeedMatcher.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.readrops.app.utils;
|
||||
|
||||
import com.readrops.app.database.entities.Feed;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFeed;
|
||||
|
||||
public final class FeedMatcher {
|
||||
|
||||
public static Feed nextNewsFeedToFeed(NextNewsFeed feed) {
|
||||
Feed newFeed = new Feed();
|
||||
|
||||
newFeed.setName(feed.getTitle());
|
||||
newFeed.setUrl(feed.getUrl());
|
||||
newFeed.setSiteUrl(feed.getLink());
|
||||
newFeed.setUnreadCount(feed.getUnreadCount());
|
||||
|
||||
newFeed.setFolderId(feed.getFolderId());
|
||||
newFeed.setIconUrl(feed.getFaviconLink());
|
||||
|
||||
newFeed.setRemoteId(feed.getId());
|
||||
|
||||
return newFeed;
|
||||
}
|
||||
|
||||
}
|
@ -100,7 +100,7 @@ public final class HtmlParser {
|
||||
String head = body.substring(body.indexOf("<head>"), body.indexOf("</head>"));
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
Log.d(TAG, "parsing time : " + String.valueOf(end - start));
|
||||
Log.d(TAG, "parsing time : " + (end - start));
|
||||
|
||||
return head;
|
||||
}
|
||||
|
34
app/src/main/java/com/readrops/app/utils/ItemMatcher.java
Normal file
34
app/src/main/java/com/readrops/app/utils/ItemMatcher.java
Normal file
@ -0,0 +1,34 @@
|
||||
package com.readrops.app.utils;
|
||||
|
||||
import com.readrops.app.database.entities.Feed;
|
||||
import com.readrops.app.database.entities.Item;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsItem;
|
||||
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.LocalDateTime;
|
||||
|
||||
public final class ItemMatcher {
|
||||
|
||||
public static Item nextNewsItemToItem(NextNewsItem nextNewsItem, Feed feed) {
|
||||
Item item = new Item();
|
||||
|
||||
item.setRemoteId(nextNewsItem.getId());
|
||||
item.setTitle(nextNewsItem.getTitle());
|
||||
|
||||
if (!nextNewsItem.getAuthor().isEmpty())
|
||||
item.setAuthor(nextNewsItem.getAuthor());
|
||||
|
||||
item.setPubDate(new LocalDateTime(nextNewsItem.getPubDate() * 1000L,
|
||||
DateTimeZone.getDefault()));
|
||||
item.setContent(nextNewsItem.getBody());
|
||||
|
||||
|
||||
item.setLink(nextNewsItem.getUrl());
|
||||
item.setGuid(nextNewsItem.getGuid());
|
||||
item.setRead(!nextNewsItem.isUnread());
|
||||
|
||||
item.setFeedId(feed.getId());
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
@ -12,14 +12,15 @@ import android.graphics.drawable.ShapeDrawable;
|
||||
import android.graphics.drawable.shapes.OvalShape;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.IOException;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
@ -45,17 +46,23 @@ public final class Utils {
|
||||
|
||||
}
|
||||
|
||||
public static Bitmap getImageFromUrl(String url) throws IOException {
|
||||
OkHttpClient okHttpClient = new OkHttpClient();
|
||||
Request request = new Request.Builder().url(url).build();
|
||||
public static Bitmap getImageFromUrl(String url) {
|
||||
try {
|
||||
OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
||||
.callTimeout(5, TimeUnit.SECONDS)
|
||||
.build();
|
||||
Request request = new Request.Builder().url(url).build();
|
||||
|
||||
Response response = okHttpClient.newCall(request).execute();
|
||||
Response response = okHttpClient.newCall(request).execute();
|
||||
|
||||
if (response.isSuccessful()) {
|
||||
InputStream inputStream = response.body().byteStream();
|
||||
return BitmapFactory.decodeStream(inputStream);
|
||||
} else
|
||||
return null;
|
||||
if (response.isSuccessful()) {
|
||||
InputStream inputStream = response.body().byteStream();
|
||||
return BitmapFactory.decodeStream(inputStream);
|
||||
} else
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
return null; // no way to get the favicon
|
||||
}
|
||||
}
|
||||
|
||||
public static int getDeviceWidth(Activity activity) {
|
||||
|
@ -1,17 +1,9 @@
|
||||
package com.readrops.app.views;
|
||||
|
||||
import androidx.paging.PagedListAdapter;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@ -20,6 +12,13 @@ import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.paging.PagedListAdapter;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.ListPreloader;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
@ -30,8 +29,8 @@ import com.bumptech.glide.request.RequestOptions;
|
||||
import com.bumptech.glide.request.transition.DrawableCrossFadeFactory;
|
||||
import com.bumptech.glide.util.ViewPreloadSizeProvider;
|
||||
import com.readrops.app.R;
|
||||
import com.readrops.app.database.pojo.ItemWithFeed;
|
||||
import com.readrops.app.database.entities.Item;
|
||||
import com.readrops.app.database.pojo.ItemWithFeed;
|
||||
import com.readrops.app.utils.DateUtils;
|
||||
import com.readrops.app.utils.GlideRequests;
|
||||
import com.readrops.app.utils.Utils;
|
||||
@ -40,8 +39,6 @@ import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static com.bumptech.glide.load.resource.bitmap.BitmapTransitionOptions.withCrossFade;
|
||||
|
||||
public class MainItemListAdapter extends PagedListAdapter<ItemWithFeed, MainItemListAdapter.ItemViewHolder> implements ListPreloader.PreloadModelProvider<String> {
|
||||
|
||||
private GlideRequests glideRequests;
|
||||
@ -73,7 +70,9 @@ public class MainItemListAdapter extends PagedListAdapter<ItemWithFeed, MainItem
|
||||
itemWithFeed.getFeedName().equals(t1.getFeedName()) &&
|
||||
itemWithFeed.getFolder().getName().equals(t1.getFolder().getName()) &&
|
||||
item.isRead() == item1.isRead() &&
|
||||
item.isReadItLater() == item1.isReadItLater();
|
||||
item.isReadItLater() == item1.isReadItLater() &&
|
||||
itemWithFeed.getColor() == t1.getColor() &&
|
||||
itemWithFeed.getBgColor() == t1.getBgColor();
|
||||
}
|
||||
};
|
||||
|
||||
@ -123,7 +122,8 @@ public class MainItemListAdapter extends PagedListAdapter<ItemWithFeed, MainItem
|
||||
viewHolder.itemImage.setVisibility(View.GONE);
|
||||
|
||||
if (itemWithFeed.getFeedIconUrl() != null) {
|
||||
glideRequests.load(itemWithFeed.getFeedIconUrl())
|
||||
glideRequests.
|
||||
load(itemWithFeed.getFeedIconUrl())
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.placeholder(R.drawable.ic_rss_feed)
|
||||
.into(viewHolder.feedIcon);
|
||||
@ -222,6 +222,7 @@ public class MainItemListAdapter extends PagedListAdapter<ItemWithFeed, MainItem
|
||||
public RequestBuilder<Drawable> getPreloadRequestBuilder(@NonNull String url) {
|
||||
return glideRequests
|
||||
.load(url)
|
||||
.centerCrop()
|
||||
.apply(requestOptions)
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.transition(DrawableTransitionOptions.withCrossFade(FADE_FACTORY));
|
||||
|
@ -2,12 +2,13 @@ package com.readrops.app;
|
||||
|
||||
import com.readrops.app.utils.DateUtils;
|
||||
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.LocalDateTime;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
@ -39,4 +40,11 @@ public class ExampleUnitTest {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeStamptoDateTest() {
|
||||
LocalDateTime localDateTime = new LocalDateTime(1367270544 * 1000L, DateTimeZone.getDefault());
|
||||
|
||||
assertEquals(0, localDateTime.compareTo(new LocalDateTime(2013, 4, 29, 21, 22, 24)));
|
||||
}
|
||||
}
|
@ -1,8 +1,5 @@
|
||||
package com.readrops.readropslibrary.services;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFeed;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFeeds;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFolders;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsItems;
|
||||
@ -11,9 +8,11 @@ import java.util.List;
|
||||
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.PUT;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface NextNewsService {
|
||||
|
||||
@ -25,21 +24,24 @@ public interface NextNewsService {
|
||||
@GET("feeds")
|
||||
Call<NextNewsFeeds> getFeeds();
|
||||
|
||||
@GET("items?type={type}&getRead={read}&batchSize={batchSize}")
|
||||
Call<NextNewsItems> getItems(@Path("type") int type, @Path("read") boolean read, @Path("batchSize") int batchSize);
|
||||
@GET("items")
|
||||
Call<NextNewsItems> getItems(@Query("type") int type, @Query("getRead") boolean read, @Query("batchSize") int batchSize);
|
||||
|
||||
@GET("items/updated?lastModified={lastModified}&type=3")
|
||||
Call<NextNewsItems> getNewItems(@Path("lastModified") long lastModified);
|
||||
@GET("items/updated?type=3")
|
||||
Call<NextNewsItems> getNewItems(@Query("lastModified") long lastModified);
|
||||
|
||||
@PUT("items/read/multiple")
|
||||
Call<ResponseBody> setReadArticles();
|
||||
Call<ResponseBody> setReadArticles(@Body List<Integer> itemsIds);
|
||||
|
||||
@PUT("items/unread/multiple")
|
||||
Call<ResponseBody> setUnreadArticles();
|
||||
Call<ResponseBody> setUnreadArticles(@Body List<Integer> itemsIds);
|
||||
|
||||
@PUT("items/starred/multiple")
|
||||
Call<ResponseBody> setStarredArticles();
|
||||
Call<ResponseBody> setStarredArticles(@Body List<Integer> itemsIds);
|
||||
|
||||
@PUT("items/unstarred/multiple")
|
||||
Call<ResponseBody> setUnstarredArticles();
|
||||
Call<ResponseBody> setUnstarredArticles(@Body List<Integer> itemsIds);
|
||||
|
||||
@PUT("items/{stateType}/multiple")
|
||||
Call<ResponseBody> setArticlesState(@Path("stateType") String stateType, @Body List<Integer> items);
|
||||
}
|
||||
|
@ -2,36 +2,17 @@ package com.readrops.readropslibrary.services.nextcloudnews;
|
||||
|
||||
public class Credentials {
|
||||
|
||||
private String login;
|
||||
|
||||
private String password;
|
||||
private String base64;
|
||||
|
||||
private String url;
|
||||
|
||||
public Credentials(String login, String password, String url) {
|
||||
this.login = login;
|
||||
this.password = password;
|
||||
this.base64 = okhttp3.Credentials.basic(login, password);
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String toBase64() {
|
||||
return okhttp3.Credentials.basic(login, password);
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
public void setLogin(String login) {
|
||||
this.login = login;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
public String getBase64() {
|
||||
return base64;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
|
@ -1,21 +1,25 @@
|
||||
package com.readrops.readropslibrary.services.nextcloudnews;
|
||||
|
||||
import android.util.TimingLogger;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.readrops.readropslibrary.services.NextNewsService;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFeeds;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFolders;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsItems;
|
||||
import com.readrops.readropslibrary.utils.HttpManager;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import retrofit2.Response;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
public class NextNewsAPI {
|
||||
|
||||
private static final String TAG = NextNewsAPI.class.getSimpleName();
|
||||
|
||||
public NextNewsAPI() {
|
||||
|
||||
}
|
||||
@ -28,15 +32,41 @@ public class NextNewsAPI {
|
||||
.build();
|
||||
}
|
||||
|
||||
public void sync(@NonNull Credentials credentials, @NonNull SyncType syncType, @Nullable SyncData data) throws IOException {
|
||||
public SyncResults sync(@NonNull Credentials credentials, @NonNull SyncType syncType, @Nullable SyncData data) throws IOException {
|
||||
HttpManager httpManager = new HttpManager(credentials);
|
||||
Retrofit retrofit = getConfiguredRetrofitInstance(httpManager);
|
||||
|
||||
NextNewsService api = retrofit.create(NextNewsService.class);
|
||||
|
||||
TimingLogger timings = new TimingLogger(TAG, "sync");
|
||||
|
||||
NextNewsFeeds feedList = api.getFeeds().execute().body();
|
||||
timings.addSplit("get feeds");
|
||||
|
||||
NextNewsFolders folderList = api.getFolders().execute().body();
|
||||
timings.addSplit("get folders");
|
||||
|
||||
NextNewsItems itemList = api.getItems(3, false, 300).execute().body();
|
||||
timings.addSplit("get items");
|
||||
timings.dumpToLog();
|
||||
|
||||
SyncResults results = new SyncResults();
|
||||
results.setFeeds(feedList.getFeeds());
|
||||
results.setFolders(folderList.getFolders());
|
||||
results.setItems(itemList.getItems());
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public enum SyncType {
|
||||
INITIAL_SYNC,
|
||||
CLASSIC_SYNC
|
||||
}
|
||||
|
||||
public enum StateType {
|
||||
READ,
|
||||
UNREAD,
|
||||
STARRED,
|
||||
UNSTARRED
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
package com.readrops.readropslibrary.services.nextcloudnews;
|
||||
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFeed;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFolder;
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SyncResults {
|
||||
|
||||
private List<NextNewsFolder> folders;
|
||||
|
||||
private List<NextNewsFeed> feeds;
|
||||
|
||||
private List<NextNewsItem> items;
|
||||
|
||||
public SyncResults() {
|
||||
}
|
||||
|
||||
public List<NextNewsFolder> getFolders() {
|
||||
return folders;
|
||||
}
|
||||
|
||||
public void setFolders(List<NextNewsFolder> folders) {
|
||||
this.folders = folders;
|
||||
}
|
||||
|
||||
public List<NextNewsFeed> getFeeds() {
|
||||
return feeds;
|
||||
}
|
||||
|
||||
public void setFeeds(List<NextNewsFeed> feeds) {
|
||||
this.feeds = feeds;
|
||||
}
|
||||
|
||||
public List<NextNewsItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public void setItems(List<NextNewsItem> items) {
|
||||
this.items = items;
|
||||
}
|
||||
}
|
@ -10,13 +10,13 @@ public class NextNewsFeed {
|
||||
|
||||
private String faviconLink;
|
||||
|
||||
private float added;
|
||||
private long added;
|
||||
|
||||
private float folderId;
|
||||
private int folderId;
|
||||
|
||||
private float unreadCount;
|
||||
private int unreadCount;
|
||||
|
||||
private float ordering;
|
||||
private int ordering;
|
||||
|
||||
private String link;
|
||||
|
||||
@ -54,35 +54,35 @@ public class NextNewsFeed {
|
||||
this.faviconLink = faviconLink;
|
||||
}
|
||||
|
||||
public float getAdded() {
|
||||
public long getAdded() {
|
||||
return added;
|
||||
}
|
||||
|
||||
public void setAdded(float added) {
|
||||
public void setAdded(long added) {
|
||||
this.added = added;
|
||||
}
|
||||
|
||||
public float getFolderId() {
|
||||
public int getFolderId() {
|
||||
return folderId;
|
||||
}
|
||||
|
||||
public void setFolderId(float folderId) {
|
||||
public void setFolderId(int folderId) {
|
||||
this.folderId = folderId;
|
||||
}
|
||||
|
||||
public float getUnreadCount() {
|
||||
public int getUnreadCount() {
|
||||
return unreadCount;
|
||||
}
|
||||
|
||||
public void setUnreadCount(float unreadCount) {
|
||||
public void setUnreadCount(int unreadCount) {
|
||||
this.unreadCount = unreadCount;
|
||||
}
|
||||
|
||||
public float getOrdering() {
|
||||
public int getOrdering() {
|
||||
return ordering;
|
||||
}
|
||||
|
||||
public void setOrdering(float ordering) {
|
||||
public void setOrdering(int ordering) {
|
||||
this.ordering = ordering;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ public class NextNewsItem {
|
||||
|
||||
private String author;
|
||||
|
||||
private float pubDate;
|
||||
private long pubDate;
|
||||
|
||||
private String body;
|
||||
|
||||
@ -22,13 +22,13 @@ public class NextNewsItem {
|
||||
|
||||
private String enclosureLink;
|
||||
|
||||
private float feedId;
|
||||
private int feedId;
|
||||
|
||||
private boolean unread;
|
||||
|
||||
private boolean starred;
|
||||
|
||||
private float lastModified;
|
||||
private long lastModified;
|
||||
|
||||
private String fingerprint;
|
||||
|
||||
@ -80,11 +80,11 @@ public class NextNewsItem {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public float getPubDate() {
|
||||
public long getPubDate() {
|
||||
return pubDate;
|
||||
}
|
||||
|
||||
public void setPubDate(float pubDate) {
|
||||
public void setPubDate(long pubDate) {
|
||||
this.pubDate = pubDate;
|
||||
}
|
||||
|
||||
@ -112,11 +112,11 @@ public class NextNewsItem {
|
||||
this.enclosureLink = enclosureLink;
|
||||
}
|
||||
|
||||
public float getFeedId() {
|
||||
public int getFeedId() {
|
||||
return feedId;
|
||||
}
|
||||
|
||||
public void setFeedId(float feedId) {
|
||||
public void setFeedId(int feedId) {
|
||||
this.feedId = feedId;
|
||||
}
|
||||
|
||||
@ -136,11 +136,11 @@ public class NextNewsItem {
|
||||
this.starred = starred;
|
||||
}
|
||||
|
||||
public float getLastModified() {
|
||||
public long getLastModified() {
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
public void setLastModified(float lastModified) {
|
||||
public void setLastModified(long lastModified) {
|
||||
this.lastModified = lastModified;
|
||||
}
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
package com.readrops.readropslibrary.services.nextcloudnews.json;
|
||||
|
||||
public class SyncResults {
|
||||
|
||||
|
||||
}
|
@ -40,7 +40,7 @@ public class HttpManager {
|
||||
Request request = chain.request();
|
||||
|
||||
request = request.newBuilder()
|
||||
.addHeader("Authorization", credentials.toBase64())
|
||||
.addHeader("Authorization", credentials.getBase64())
|
||||
.build();
|
||||
|
||||
return chain.proceed(request);
|
||||
|
Loading…
x
Reference in New Issue
Block a user