mirror of https://github.com/readrops/Readrops.git
Remove unused files
This commit is contained in:
parent
e20bc62418
commit
26eaebf442
|
@ -2,7 +2,6 @@ package com.readrops.api
|
|||
|
||||
import com.readrops.api.localfeed.LocalRSSDataSource
|
||||
import com.readrops.api.services.Credentials
|
||||
import com.readrops.api.services.freshrss.FreshRSSDataSource
|
||||
import com.readrops.api.services.freshrss.NewFreshRSSDataSource
|
||||
import com.readrops.api.services.freshrss.NewFreshRSSService
|
||||
import com.readrops.api.services.freshrss.adapters.FreshRSSFeedsAdapter
|
||||
|
@ -12,7 +11,6 @@ import com.readrops.api.services.freshrss.adapters.FreshRSSItemsIdsAdapter
|
|||
import com.readrops.api.services.freshrss.adapters.FreshRSSUserInfoAdapter
|
||||
import com.readrops.api.services.nextcloudnews.NewNextcloudNewsDataSource
|
||||
import com.readrops.api.services.nextcloudnews.NewNextcloudNewsService
|
||||
import com.readrops.api.services.nextcloudnews.NextNewsDataSource
|
||||
import com.readrops.api.services.nextcloudnews.adapters.NextNewsFeedsAdapter
|
||||
import com.readrops.api.services.nextcloudnews.adapters.NextNewsFoldersAdapter
|
||||
import com.readrops.api.services.nextcloudnews.adapters.NextNewsItemsAdapter
|
||||
|
@ -48,8 +46,6 @@ val apiModule = module {
|
|||
|
||||
//region freshrss
|
||||
|
||||
factory { params -> FreshRSSDataSource(get(parameters = { params })) }
|
||||
|
||||
factory { params -> NewFreshRSSDataSource(get(parameters = { params })) }
|
||||
|
||||
factory { (credentials: Credentials) ->
|
||||
|
@ -75,8 +71,6 @@ val apiModule = module {
|
|||
|
||||
//region nextcloud news
|
||||
|
||||
factory { params -> NextNewsDataSource(get(parameters = { params })) }
|
||||
|
||||
factory { params -> NewNextcloudNewsDataSource(get(parameters = { params })) }
|
||||
|
||||
factory { (credentials: Credentials) ->
|
||||
|
|
|
@ -1,317 +0,0 @@
|
|||
package com.readrops.api.services.freshrss;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.readrops.api.services.SyncResult;
|
||||
import com.readrops.api.services.SyncType;
|
||||
import com.readrops.api.services.freshrss.adapters.FreshRSSUserInfo;
|
||||
import com.readrops.db.entities.Feed;
|
||||
import com.readrops.db.entities.Folder;
|
||||
import com.readrops.db.entities.Item;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.RequestBody;
|
||||
|
||||
public class FreshRSSDataSource {
|
||||
|
||||
private static final int MAX_ITEMS = 2500;
|
||||
private static final int MAX_STARRED_ITEMS = 1000;
|
||||
|
||||
public static final String GOOGLE_READ = "user/-/state/com.google/read";
|
||||
public static final String GOOGLE_UNREAD = "user/-/state/com.google/unread";
|
||||
public static final String GOOGLE_STARRED = "user/-/state/com.google/starred";
|
||||
public static final String GOOGLE_READING_LIST = "user/-/state/com.google/reading-list";
|
||||
|
||||
private static final String FEED_PREFIX = "feed/";
|
||||
|
||||
private final FreshRSSService api;
|
||||
|
||||
public FreshRSSDataSource(FreshRSSService api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call token API to generate a new token from account credentials
|
||||
*
|
||||
* @param login login
|
||||
* @param password password
|
||||
* @return the generated token
|
||||
*/
|
||||
public Single<String> login(@NonNull String login, @NonNull String password) {
|
||||
RequestBody requestBody = new MultipartBody.Builder()
|
||||
.setType(MultipartBody.FORM)
|
||||
.addFormDataPart("Email", login)
|
||||
.addFormDataPart("Passwd", password)
|
||||
.build();
|
||||
|
||||
return api.login(requestBody)
|
||||
.flatMap(response -> {
|
||||
Properties properties = new Properties();
|
||||
properties.load(new StringReader(response.string()));
|
||||
|
||||
return Single.just(properties.getProperty("Auth"));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a write token to modify feeds, folders and items on the server
|
||||
*
|
||||
* @return the write token generated by the server
|
||||
*/
|
||||
public Single<String> getWriteToken() {
|
||||
return api.getWriteToken()
|
||||
.flatMap(responseBody -> Single.just(responseBody.string()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve user information : name, email, id, profileId
|
||||
*
|
||||
* @return user information
|
||||
*/
|
||||
public Single<FreshRSSUserInfo> getUserInfo() {
|
||||
return api.getUserInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize feeds, folders, items and push read/unread items
|
||||
*
|
||||
* @param syncType INITIAL or CLASSIC
|
||||
* @param syncData data to sync (read/unread items ids, lastModified timestamp)
|
||||
* @param writeToken token for making modifications on the server
|
||||
* @return the result of the synchronization
|
||||
*/
|
||||
public Single<SyncResult> sync(@NonNull SyncType syncType, @NonNull FreshRSSSyncData syncData, @NonNull String writeToken) {
|
||||
if (syncType == SyncType.INITIAL_SYNC) {
|
||||
return Single.zip(setItemsReadState(syncData, writeToken).toSingleDefault(""),
|
||||
setItemsStarState(syncData, writeToken).toSingleDefault(""),
|
||||
getFolders(),
|
||||
getFeeds(),
|
||||
getItems(Arrays.asList(GOOGLE_READ, GOOGLE_STARRED), MAX_ITEMS, null),
|
||||
getItemsIds(GOOGLE_READ, GOOGLE_READING_LIST, MAX_ITEMS), // unread items ids
|
||||
getItemsIds(null, GOOGLE_STARRED, MAX_STARRED_ITEMS), // starred items ids
|
||||
getStarredItems(MAX_STARRED_ITEMS),
|
||||
(readState, starState, folders, feeds, items, unreadItemsIds, starredItemsIds, starredItems) ->
|
||||
new SyncResult(items, starredItems, feeds, new ArrayList<>(), folders, unreadItemsIds, Collections.emptyList(), starredItemsIds, false)
|
||||
);
|
||||
} else {
|
||||
return Single.zip(setItemsReadState(syncData, writeToken).toSingleDefault(""),
|
||||
setItemsStarState(syncData, writeToken).toSingleDefault(""),
|
||||
getFolders(),
|
||||
getFeeds(),
|
||||
getItems(null, MAX_ITEMS, syncData.getLastModified()),
|
||||
getItemsIds(GOOGLE_READ, GOOGLE_READING_LIST, MAX_ITEMS), // unread items ids
|
||||
getItemsIds(GOOGLE_UNREAD, GOOGLE_READING_LIST, MAX_ITEMS), // read items ids
|
||||
getItemsIds(null, GOOGLE_STARRED, MAX_STARRED_ITEMS), // starred items ids
|
||||
(readState, starState, folders, feeds, items, unreadItemsIds, readItemsIds, starredItemsIds) ->
|
||||
new SyncResult(items, Collections.emptyList(), feeds, new ArrayList<>(), folders, unreadItemsIds, readItemsIds, starredItemsIds, false)
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the feeds folders
|
||||
*
|
||||
* @return the feeds folders
|
||||
*/
|
||||
public Single<List<Folder>> getFolders() {
|
||||
return api.getFolders();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the feeds
|
||||
*
|
||||
* @return the feeds
|
||||
*/
|
||||
public Single<List<Feed>> getFeeds() {
|
||||
return api.getFeeds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the items
|
||||
*
|
||||
* @param excludeTargets type of items to exclude (read items and starred items)
|
||||
* @param max max number of items to fetch
|
||||
* @param lastModified fetch only items created after this timestamp
|
||||
* @return the items
|
||||
*/
|
||||
public Single<List<Item>> getItems(@Nullable List<String> excludeTargets, int max, @Nullable Long lastModified) {
|
||||
return api.getItems(excludeTargets, max, lastModified);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch starred items
|
||||
*
|
||||
* @param max max number of items to fetch
|
||||
* @return items
|
||||
*/
|
||||
public Single<List<Item>> getStarredItems(int max) {
|
||||
return api.getStarredItems(max);
|
||||
}
|
||||
|
||||
public Single<List<String>> getItemsIds(String excludeTarget, String includeTarget, int max) {
|
||||
return api.getItemsIds(excludeTarget, includeTarget, max);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mark items read or unread
|
||||
*
|
||||
* @param read true for read, false for unread
|
||||
* @param itemIds items ids to mark
|
||||
* @param token token for modifications
|
||||
* @return Completable
|
||||
*/
|
||||
public Completable setItemsReadState(boolean read, @NonNull List<String> itemIds, @NonNull String token) {
|
||||
if (read) {
|
||||
return api.setItemsState(token, GOOGLE_READ, null, itemIds);
|
||||
} else {
|
||||
return api.setItemsState(token, null, GOOGLE_READ, itemIds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark items as starred or unstarred
|
||||
*
|
||||
* @param starred true for starred, false for unstarred
|
||||
* @param itemIds items ids to mark
|
||||
* @param token token for modifications
|
||||
* @return Completable
|
||||
*/
|
||||
public Completable setItemsStarState(boolean starred, @NonNull List<String> itemIds, @NonNull String token) {
|
||||
if (starred) {
|
||||
return api.setItemsState(token, GOOGLE_STARRED, null, itemIds);
|
||||
} else {
|
||||
return api.setItemsState(token, null, GOOGLE_STARRED, itemIds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new feed
|
||||
*
|
||||
* @param token token for modifications
|
||||
* @param feedUrl url of the feed to parse
|
||||
* @return Completable
|
||||
*/
|
||||
public Completable createFeed(@NonNull String token, @NonNull String feedUrl) {
|
||||
return api.createOrDeleteFeed(token, FEED_PREFIX + feedUrl, "subscribe");
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a feed
|
||||
*
|
||||
* @param token token for modifications
|
||||
* @param feedUrl url of the feed to delete
|
||||
* @return Completable
|
||||
*/
|
||||
public Completable deleteFeed(@NonNull String token, @NonNull String feedUrl) {
|
||||
return api.createOrDeleteFeed(token, FEED_PREFIX + feedUrl, "unsubscribe");
|
||||
}
|
||||
|
||||
/**
|
||||
* Update feed title and folder
|
||||
*
|
||||
* @param token token for modifications
|
||||
* @param feedUrl url of the feed to update
|
||||
* @param title new title
|
||||
* @param folderId id of the new folder
|
||||
* @return Completable
|
||||
*/
|
||||
public Completable updateFeed(@NonNull String token, @NonNull String feedUrl, @NonNull String title, @NonNull String folderId) {
|
||||
return api.updateFeed(token, FEED_PREFIX + feedUrl, title, folderId, "edit");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new folder
|
||||
*
|
||||
* @param token token for modifications
|
||||
* @param tagName name of the new folder
|
||||
* @return Completable
|
||||
*/
|
||||
public Completable createFolder(@NonNull String token, @NonNull String tagName) {
|
||||
return api.createFolder(token, "user/-/label/" + tagName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update folder name
|
||||
*
|
||||
* @param token token for modifications
|
||||
* @param folderId id of the folder
|
||||
* @param name new folder name
|
||||
* @return Completable
|
||||
*/
|
||||
public Completable updateFolder(@NonNull String token, @NonNull String folderId, @NonNull String name) {
|
||||
return api.updateFolder(token, folderId, "user/-/label/" + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a folder
|
||||
*
|
||||
* @param token token for modifications
|
||||
* @param folderId id of the folder to delete
|
||||
* @return Completable
|
||||
*/
|
||||
public Completable deleteFolder(@NonNull String token, @NonNull String folderId) {
|
||||
return api.deleteFolder(token, folderId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set items star state
|
||||
*
|
||||
* @param syncData data containing items to mark
|
||||
* @param token token for modifications
|
||||
* @return A concatenation of two completable (read and unread completable)
|
||||
*/
|
||||
private Completable setItemsReadState(@NonNull FreshRSSSyncData syncData, @NonNull String token) {
|
||||
Completable readItemsCompletable;
|
||||
if (syncData.getReadIds().isEmpty()) {
|
||||
readItemsCompletable = Completable.complete();
|
||||
} else {
|
||||
readItemsCompletable = setItemsReadState(true, syncData.getReadIds(), token);
|
||||
}
|
||||
|
||||
Completable unreadItemsCompletable;
|
||||
if (syncData.getUnreadIds().isEmpty()) {
|
||||
unreadItemsCompletable = Completable.complete();
|
||||
} else {
|
||||
unreadItemsCompletable = setItemsReadState(false, syncData.getUnreadIds(), token);
|
||||
}
|
||||
|
||||
return readItemsCompletable.concatWith(unreadItemsCompletable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set items star state
|
||||
*
|
||||
* @param syncData data containing items to mark
|
||||
* @param token token for modifications
|
||||
* @return A concatenation of two completable (starred and unstarred completable)
|
||||
*/
|
||||
private Completable setItemsStarState(@NonNull FreshRSSSyncData syncData, @NonNull String token) {
|
||||
Completable starredItemsCompletable;
|
||||
if (syncData.getStarredIds().isEmpty()) {
|
||||
starredItemsCompletable = Completable.complete();
|
||||
} else {
|
||||
starredItemsCompletable = setItemsStarState(true, syncData.getStarredIds(), token);
|
||||
}
|
||||
|
||||
Completable unstarredItemsCompletable;
|
||||
if (syncData.getUnstarredIds().isEmpty()) {
|
||||
unstarredItemsCompletable = Completable.complete();
|
||||
} else {
|
||||
unstarredItemsCompletable = setItemsStarState(false, syncData.getUnstarredIds(), token);
|
||||
}
|
||||
|
||||
return starredItemsCompletable.concatWith(unstarredItemsCompletable);
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
package com.readrops.api.services.freshrss
|
||||
|
||||
import com.readrops.api.services.freshrss.adapters.FreshRSSUserInfo
|
||||
import com.readrops.db.entities.Feed
|
||||
import com.readrops.db.entities.Folder
|
||||
import com.readrops.db.entities.Item
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.http.*
|
||||
|
||||
interface FreshRSSService {
|
||||
|
||||
@POST("accounts/ClientLogin")
|
||||
fun login(@Body body: RequestBody?): Single<ResponseBody?>?
|
||||
|
||||
@get:GET("reader/api/0/token")
|
||||
val writeToken: Single<ResponseBody>
|
||||
|
||||
@get:GET("reader/api/0/user-info")
|
||||
val userInfo: Single<FreshRSSUserInfo>
|
||||
|
||||
@get:GET("reader/api/0/subscription/list?output=json")
|
||||
val feeds: Single<List<Feed>>
|
||||
|
||||
@get:GET("reader/api/0/tag/list?output=json")
|
||||
val folders: Single<List<Folder>>
|
||||
|
||||
@GET("reader/api/0/stream/contents/user/-/state/com.google/reading-list")
|
||||
fun getItems(@Query("xt") excludeTarget: List<String>?, @Query("n") max: Int,
|
||||
@Query("ot") lastModified: Long?): Single<List<Item>>
|
||||
|
||||
@GET("reader/api/0/stream/contents/user/-/state/com.google/starred")
|
||||
fun getStarredItems(@Query("n") max: Int): Single<List<Item>>
|
||||
|
||||
@GET("reader/api/0/stream/items/ids")
|
||||
fun getItemsIds(@Query("xt") excludeTarget: String?, @Query("s") includeTarget: String?,
|
||||
@Query("n") max: Int): Single<List<String>>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("reader/api/0/edit-tag")
|
||||
fun setItemsState(@Field("T") token: String, @Field("a") addAction: String?,
|
||||
@Field("r") removeAction: String?, @Field("i") itemIds: List<String>): Completable
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("reader/api/0/subscription/edit")
|
||||
fun createOrDeleteFeed(@Field("T") token: String, @Field("s") feedUrl: String, @Field("ac") action: String): Completable
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("reader/api/0/subscription/edit")
|
||||
fun updateFeed(@Field("T") token: String, @Field("s") feedUrl: String, @Field("t") title: String,
|
||||
@Field("a") folderId: String, @Field("ac") action: String): Completable
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("reader/api/0/edit-tag")
|
||||
fun createFolder(@Field("T") token: String, @Field("a") tagName: String): Completable
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("reader/api/0/rename-tag")
|
||||
fun updateFolder(@Field("T") token: String, @Field("s") folderId: String, @Field("dest") newFolderId: String): Completable
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("reader/api/0/disable-tag")
|
||||
fun deleteFolder(@Field("T") token: String, @Field("s") folderId: String): Completable
|
||||
|
||||
companion object {
|
||||
const val END_POINT = "/api/greader.php/"
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package com.readrops.api.services.freshrss.adapters
|
||||
|
||||
import com.readrops.api.services.freshrss.FreshRSSDataSource.GOOGLE_READ
|
||||
import com.readrops.api.services.freshrss.FreshRSSDataSource.GOOGLE_STARRED
|
||||
import com.readrops.api.services.freshrss.NewFreshRSSDataSource.Companion.GOOGLE_READ
|
||||
import com.readrops.api.services.freshrss.NewFreshRSSDataSource.Companion.GOOGLE_STARRED
|
||||
import com.readrops.api.utils.exceptions.ParseException
|
||||
import com.readrops.api.utils.extensions.nextNonEmptyString
|
||||
import com.readrops.api.utils.extensions.nextNullableString
|
||||
|
|
|
@ -1,300 +0,0 @@
|
|||
package com.readrops.api.services.nextcloudnews;
|
||||
|
||||
import android.content.res.Resources;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.readrops.api.services.SyncResult;
|
||||
import com.readrops.api.services.SyncType;
|
||||
import com.readrops.api.services.nextcloudnews.adapters.NextNewsUserAdapter;
|
||||
import com.readrops.api.utils.ApiUtils;
|
||||
import com.readrops.api.utils.exceptions.ConflictException;
|
||||
import com.readrops.api.utils.exceptions.UnknownFormatException;
|
||||
import com.readrops.api.utils.extensions.KonsumerExtensionsKt;
|
||||
import com.readrops.db.entities.Feed;
|
||||
import com.readrops.db.entities.Folder;
|
||||
import com.readrops.db.entities.Item;
|
||||
import com.readrops.db.entities.account.Account;
|
||||
import com.readrops.db.pojo.StarItem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class NextNewsDataSource {
|
||||
|
||||
private static final String TAG = NextNewsDataSource.class.getSimpleName();
|
||||
|
||||
private static final int MAX_ITEMS = 5000;
|
||||
private static final int MAX_STARRED_ITEMS = 1000;
|
||||
|
||||
private NextNewsService api;
|
||||
|
||||
public NextNewsDataSource(NextNewsService api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String login(OkHttpClient client, Account account) throws IOException {
|
||||
Request request = new Request.Builder()
|
||||
.url(account.getUrl() + "/ocs/v1.php/cloud/users/" + account.getLogin())
|
||||
.addHeader("OCS-APIRequest", "true")
|
||||
.build();
|
||||
|
||||
okhttp3.Response response = client.newCall(request).execute();
|
||||
|
||||
String displayName = new NextNewsUserAdapter().fromXml(KonsumerExtensionsKt
|
||||
.instantiateKonsumer(response.body().byteStream()));
|
||||
response.body().close();
|
||||
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<Feed> createFeed(String url, int folderId) throws IOException, UnknownFormatException {
|
||||
Response<List<Feed>> response = api.createFeed(url, folderId).execute();
|
||||
|
||||
if (!response.isSuccessful()) {
|
||||
if (response.code() == ApiUtils.HTTP_UNPROCESSABLE)
|
||||
throw new UnknownFormatException();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.body();
|
||||
}
|
||||
|
||||
public SyncResult sync(@NonNull SyncType syncType, @Nullable NextcloudNewsSyncData data) throws IOException {
|
||||
SyncResult syncResult = new SyncResult();
|
||||
switch (syncType) {
|
||||
case INITIAL_SYNC:
|
||||
initialSync(syncResult);
|
||||
break;
|
||||
case CLASSIC_SYNC:
|
||||
if (data == null)
|
||||
throw new NullPointerException("NextNewsSyncData can't be null");
|
||||
|
||||
classicSync(syncResult, data);
|
||||
break;
|
||||
}
|
||||
|
||||
return syncResult;
|
||||
}
|
||||
|
||||
private void initialSync(SyncResult syncResult) throws IOException {
|
||||
getFeedsAndFolders(syncResult);
|
||||
|
||||
// unread items
|
||||
Response<List<Item>> itemsResponse = api.getItems(ItemQueryType.ALL.value, false, MAX_ITEMS).execute();
|
||||
List<Item> itemList = itemsResponse.body();
|
||||
|
||||
if (!itemsResponse.isSuccessful())
|
||||
syncResult.setError(true);
|
||||
|
||||
if (itemList != null)
|
||||
syncResult.setItems(itemList);
|
||||
|
||||
// starred items
|
||||
Response<List<Item>> starredItemsResponse = api.getItems(ItemQueryType.STARRED.value, true, MAX_STARRED_ITEMS).execute();
|
||||
List<Item> starredItems = starredItemsResponse.body();
|
||||
|
||||
if (!itemsResponse.isSuccessful())
|
||||
syncResult.setError(true);
|
||||
|
||||
if (itemList != null)
|
||||
syncResult.setStarredItems(starredItems);
|
||||
}
|
||||
|
||||
private void classicSync(SyncResult syncResult, NextcloudNewsSyncData data) throws IOException {
|
||||
putModifiedItems(data, syncResult);
|
||||
getFeedsAndFolders(syncResult);
|
||||
|
||||
Response<List<Item>> itemsResponse = api.getNewItems(data.getLastModified(), ItemQueryType.ALL.value).execute();
|
||||
List<Item> itemList = itemsResponse.body();
|
||||
|
||||
if (!itemsResponse.isSuccessful())
|
||||
syncResult.setError(true);
|
||||
|
||||
if (itemList != null)
|
||||
syncResult.setItems(itemList);
|
||||
}
|
||||
|
||||
private void getFeedsAndFolders(SyncResult syncResult) throws IOException {
|
||||
Response<List<Feed>> feedResponse = api.getFeeds().execute();
|
||||
List<Feed> feedList = feedResponse.body();
|
||||
|
||||
if (!feedResponse.isSuccessful())
|
||||
syncResult.setError(true);
|
||||
|
||||
Response<List<Folder>> folderResponse = api.getFolders().execute();
|
||||
List<Folder> folderList = folderResponse.body();
|
||||
|
||||
if (!folderResponse.isSuccessful())
|
||||
syncResult.setError(true);
|
||||
|
||||
if (folderList != null)
|
||||
syncResult.setFolders(folderList);
|
||||
|
||||
if (feedList != null)
|
||||
syncResult.setFeeds(feedList);
|
||||
|
||||
}
|
||||
|
||||
private void putModifiedItems(NextcloudNewsSyncData data, SyncResult syncResult) throws IOException {
|
||||
/*setReadState(data.getReadIds(), syncResult, StateType.READ);
|
||||
setReadState(data.getUnreadIds(), syncResult, StateType.UNREAD);
|
||||
|
||||
setStarState(data.getStarredIds(), syncResult, StateType.STAR);
|
||||
setStarState(data.getUnstarredIds(), syncResult, StateType.UNSTAR);*/
|
||||
}
|
||||
|
||||
public List<Folder> createFolder(Folder folder) throws IOException, UnknownFormatException, ConflictException {
|
||||
Map<String, String> folderNameMap = new HashMap<>();
|
||||
folderNameMap.put("name", folder.getName());
|
||||
|
||||
Response<List<Folder>> foldersResponse = api.createFolder(folderNameMap).execute();
|
||||
|
||||
if (foldersResponse.isSuccessful())
|
||||
return foldersResponse.body();
|
||||
else if (foldersResponse.code() == ApiUtils.HTTP_UNPROCESSABLE)
|
||||
throw new UnknownFormatException();
|
||||
else if (foldersResponse.code() == ApiUtils.HTTP_CONFLICT)
|
||||
throw new ConflictException();
|
||||
else
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public boolean deleteFolder(Folder folder) throws IOException {
|
||||
Response response = api.deleteFolder(Integer.parseInt(folder.getRemoteId())).execute();
|
||||
|
||||
if (response.isSuccessful())
|
||||
return true;
|
||||
else if (response.code() == ApiUtils.HTTP_NOT_FOUND)
|
||||
throw new Resources.NotFoundException();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean renameFolder(Folder folder) throws IOException, UnknownFormatException, ConflictException {
|
||||
Map<String, String> folderNameMap = new HashMap<>();
|
||||
folderNameMap.put("name", folder.getName());
|
||||
|
||||
Response response = api.renameFolder(Integer.parseInt(folder.getRemoteId()), folderNameMap).execute();
|
||||
|
||||
if (response.isSuccessful())
|
||||
return true;
|
||||
else {
|
||||
switch (response.code()) {
|
||||
case ApiUtils.HTTP_NOT_FOUND:
|
||||
throw new Resources.NotFoundException();
|
||||
case ApiUtils.HTTP_UNPROCESSABLE:
|
||||
throw new UnknownFormatException();
|
||||
case ApiUtils.HTTP_CONFLICT:
|
||||
throw new ConflictException();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean deleteFeed(int feedId) throws IOException {
|
||||
Response response = api.deleteFeed(feedId).execute();
|
||||
|
||||
if (response.isSuccessful())
|
||||
return true;
|
||||
else if (response.code() == ApiUtils.HTTP_NOT_FOUND)
|
||||
throw new Resources.NotFoundException();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean changeFeedFolder(Feed feed) throws IOException {
|
||||
Map<String, Integer> folderIdMap = new HashMap<>();
|
||||
folderIdMap.put("folderId", Integer.parseInt(feed.getRemoteFolderId()));
|
||||
|
||||
Response response = api.changeFeedFolder(Integer.parseInt(feed.getRemoteId()), folderIdMap).execute();
|
||||
|
||||
if (response.isSuccessful())
|
||||
return true;
|
||||
else if (response.code() == ApiUtils.HTTP_NOT_FOUND)
|
||||
throw new Resources.NotFoundException();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean renameFeed(Feed feed) throws IOException {
|
||||
Map<String, String> feedTitleMap = new HashMap<>();
|
||||
feedTitleMap.put("feedTitle", feed.getName());
|
||||
|
||||
Response response = api.renameFeed(Integer.parseInt(feed.getRemoteId()), feedTitleMap).execute();
|
||||
|
||||
if (response.isSuccessful())
|
||||
return true;
|
||||
else if (response.code() == ApiUtils.HTTP_NOT_FOUND)
|
||||
throw new Resources.NotFoundException();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setReadState(List<String> items, SyncResult syncResult, StateType stateType) throws IOException {
|
||||
if (!items.isEmpty()) {
|
||||
Map<String, List<String>> itemIdsMap = new HashMap<>();
|
||||
itemIdsMap.put("items", items);
|
||||
|
||||
Response readItemsResponse = api.setReadState(stateType.name().toLowerCase(),
|
||||
itemIdsMap).execute();
|
||||
|
||||
if (!readItemsResponse.isSuccessful())
|
||||
syncResult.setError(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void setStarState(List<StarItem> items, SyncResult syncResult, StateType stateType) throws IOException {
|
||||
if (!items.isEmpty()) {
|
||||
List<Map<String, String>> body = new ArrayList<>();
|
||||
for (StarItem item : items) {
|
||||
Map<String, String> itemBody = new HashMap<>();
|
||||
itemBody.put("feedId", item.getFeedRemoteId());
|
||||
itemBody.put("guidHash", item.getGuidHash());
|
||||
|
||||
body.add(itemBody);
|
||||
}
|
||||
|
||||
Response response = api.setStarState(stateType.name().toLowerCase(),
|
||||
Collections.singletonMap("items", body)).execute();
|
||||
if (!response.isSuccessful()) {
|
||||
syncResult.setError(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum StateType {
|
||||
READ,
|
||||
UNREAD,
|
||||
STAR,
|
||||
UNSTAR
|
||||
}
|
||||
|
||||
public enum ItemQueryType {
|
||||
ALL(3),
|
||||
STARRED(2);
|
||||
|
||||
private int value;
|
||||
|
||||
ItemQueryType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package com.readrops.api.services.nextcloudnews
|
||||
|
||||
import com.readrops.db.entities.Feed
|
||||
import com.readrops.db.entities.Folder
|
||||
import com.readrops.db.entities.Item
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.*
|
||||
|
||||
interface NextNewsService {
|
||||
|
||||
@GET("/ocs/v1.php/cloud/users/{userId}")
|
||||
@Headers("OCS-APIRequest: true")
|
||||
fun getUser(@Path("userId") userId: String): Call<ResponseBody>
|
||||
|
||||
@get:GET("folders")
|
||||
val folders: Call<List<Folder>>
|
||||
|
||||
@get:GET("feeds")
|
||||
val feeds: Call<List<Feed>>
|
||||
|
||||
@GET("items")
|
||||
fun getItems(@Query("type") type: Int, @Query("getRead") read: Boolean, @Query("batchSize") batchSize: Int): Call<List<Item>>
|
||||
|
||||
@GET("items/updated")
|
||||
fun getNewItems(@Query("lastModified") lastModified: Long, @Query("type") type: Int): Call<List<Item>>
|
||||
|
||||
@PUT("items/{stateType}/multiple")
|
||||
fun setReadState(@Path("stateType") stateType: String, @Body itemIdsMap: Map<String, List<String>>): Call<ResponseBody>
|
||||
|
||||
@PUT("items/{starType}/multiple")
|
||||
fun setStarState(@Path("starType") starType: String?, @Body body: Map<String?, List<Map<String, String>>>): Call<ResponseBody>
|
||||
|
||||
@POST("feeds")
|
||||
fun createFeed(@Query("url") url: String, @Query("folderId") folderId: Int): Call<List<Feed>>
|
||||
|
||||
@DELETE("feeds/{feedId}")
|
||||
fun deleteFeed(@Path("feedId") feedId: Int): Call<Void?>?
|
||||
|
||||
@PUT("feeds/{feedId}/move")
|
||||
fun changeFeedFolder(@Path("feedId") feedId: Int, @Body folderIdMap: Map<String, Int>): Call<ResponseBody>
|
||||
|
||||
@PUT("feeds/{feedId}/rename")
|
||||
fun renameFeed(@Path("feedId") feedId: Int, @Body feedTitleMap: Map<String, String>): Call<ResponseBody>
|
||||
|
||||
@POST("folders")
|
||||
fun createFolder(@Body folderName: Map<String, String>): Call<List<Folder>>
|
||||
|
||||
@DELETE("folders/{folderId}")
|
||||
fun deleteFolder(@Path("folderId") folderId: Int): Call<ResponseBody>
|
||||
|
||||
@PUT("folders/{folderId}")
|
||||
fun renameFolder(@Path("folderId") folderId: Int, @Body folderName: Map<String, String>): Call<ResponseBody>
|
||||
|
||||
companion object {
|
||||
const val END_POINT = "/index.php/apps/news/api/v1-2/"
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ import com.readrops.api.TestUtils
|
|||
import com.readrops.api.apiModule
|
||||
import com.readrops.api.enqueueOK
|
||||
import com.readrops.api.enqueueStream
|
||||
import com.readrops.api.services.nextcloudnews.NextNewsDataSource.ItemQueryType
|
||||
import com.readrops.db.entities.account.Account
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
|
@ -94,7 +93,7 @@ class NextcloudNewsDataSourceTest : KoinTest {
|
|||
val stream = TestUtils.loadResource("services/nextcloudnews/adapters/items.json")
|
||||
mockServer.enqueueStream(stream)
|
||||
|
||||
val items = nextcloudNewsDataSource.getItems(ItemQueryType.ALL.value, false, 10)
|
||||
val items = nextcloudNewsDataSource.getItems(NewNextcloudNewsDataSource.ItemQueryType.ALL.value, false, 10)
|
||||
val request = mockServer.takeRequest()
|
||||
|
||||
assertTrue { items.size == 3 }
|
||||
|
|
|
@ -166,7 +166,7 @@ class FreshRSSRepository(
|
|||
|
||||
if (itemsToInsert.isNotEmpty()) {
|
||||
itemsToInsert.sortWith(Item::compareTo)
|
||||
database.itemDao().insert(itemsToInsert)
|
||||
database.newItemDao().insert(itemsToInsert)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ class LocalRSSRepository(
|
|||
val itemsToInsert = mutableListOf<Item>()
|
||||
|
||||
for (item in items) {
|
||||
if (!database.itemDao().itemExists(item.guid!!, feed.accountId)) {
|
||||
if (!database.newItemDao().itemExists(item.guid!!, feed.accountId)) {
|
||||
if (item.description != null) {
|
||||
item.cleanDescription = Jsoup.parse(item.description).text()
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ class NextcloudNewsRepository(
|
|||
account.lastModified = newLastModified
|
||||
database.newAccountDao().updateLastModified(newLastModified, account.id)
|
||||
|
||||
database.itemStateChangesDao().resetStateChanges(account.id)
|
||||
database.newItemStateChangeDao().resetStateChanges(account.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
package com.readrops.app.compose
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
|
@ -6,12 +6,6 @@ import androidx.room.RoomDatabase
|
|||
import androidx.room.TypeConverters
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.readrops.db.dao.AccountDao
|
||||
import com.readrops.db.dao.FeedDao
|
||||
import com.readrops.db.dao.FolderDao
|
||||
import com.readrops.db.dao.ItemDao
|
||||
import com.readrops.db.dao.ItemStateChangeDao
|
||||
import com.readrops.db.dao.ItemStateDao
|
||||
import com.readrops.db.dao.newdao.NewAccountDao
|
||||
import com.readrops.db.dao.newdao.NewFeedDao
|
||||
import com.readrops.db.dao.newdao.NewFolderDao
|
||||
|
@ -34,18 +28,6 @@ import com.readrops.db.entities.account.Account
|
|||
)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class Database : RoomDatabase() {
|
||||
abstract fun feedDao(): FeedDao
|
||||
|
||||
abstract fun itemDao(): ItemDao
|
||||
|
||||
abstract fun folderDao(): FolderDao
|
||||
|
||||
abstract fun accountDao(): AccountDao
|
||||
|
||||
abstract fun itemStateDao(): ItemStateDao
|
||||
|
||||
abstract fun itemStateChangesDao(): ItemStateChangeDao
|
||||
|
||||
// new dao
|
||||
|
||||
abstract fun newFeedDao(): NewFeedDao
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
package com.readrops.db;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.paging.DataSource;
|
||||
import androidx.paging.PositionalDataSource;
|
||||
|
||||
/**
|
||||
* Workaround class to avoid item recycler view scrolling down when updating data
|
||||
* This class is to keep until a new version of androidx paging is released with
|
||||
* bug https://issuetracker.google.com/issues/123834703 merged.
|
||||
* @param <T>
|
||||
*/
|
||||
public class RoomFactoryWrapper<T> extends DataSource.Factory<Integer, T> {
|
||||
final DataSource.Factory<Integer, T> m_wrappedFactory;
|
||||
|
||||
public RoomFactoryWrapper(@NonNull DataSource.Factory<Integer, T> wrappedFactory) {
|
||||
m_wrappedFactory = wrappedFactory;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DataSource<Integer, T> create() {
|
||||
return new DataSourceWrapper<>((PositionalDataSource<T>) m_wrappedFactory.create());
|
||||
}
|
||||
|
||||
public static class DataSourceWrapper<T> extends PositionalDataSource<T> {
|
||||
final PositionalDataSource<T> m_wrappedSource;
|
||||
|
||||
DataSourceWrapper(PositionalDataSource<T> wrappedSource) {
|
||||
m_wrappedSource = wrappedSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInvalidatedCallback(@NonNull InvalidatedCallback onInvalidatedCallback) {
|
||||
m_wrappedSource.addInvalidatedCallback(onInvalidatedCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeInvalidatedCallback(
|
||||
@NonNull InvalidatedCallback onInvalidatedCallback) {
|
||||
m_wrappedSource.removeInvalidatedCallback(onInvalidatedCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
m_wrappedSource.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvalid() {
|
||||
return m_wrappedSource.isInvalid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadInitial(@NonNull LoadInitialParams params,
|
||||
@NonNull LoadInitialCallback<T> callback) {
|
||||
// Workaround for paging bug: https://issuetracker.google.com/issues/123834703
|
||||
// edit initial load position to start 1/2 load ahead of requested position
|
||||
int newStartPos = params.placeholdersEnabled
|
||||
? params.requestedStartPosition
|
||||
: Math.max(0, params.requestedStartPosition - (params.requestedLoadSize / 2));
|
||||
m_wrappedSource.loadInitial(new LoadInitialParams(
|
||||
newStartPos,
|
||||
params.requestedLoadSize,
|
||||
params.pageSize,
|
||||
params.placeholdersEnabled
|
||||
), callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadRange(@NonNull LoadRangeParams params,
|
||||
@NonNull LoadRangeCallback<T> callback) {
|
||||
m_wrappedSource.loadRange(params, callback);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package com.readrops.db.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import com.readrops.db.entities.account.Account
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
|
||||
@Dao
|
||||
interface AccountDao : BaseDao<Account> {
|
||||
|
||||
@Query("Select * from Account")
|
||||
fun selectAllAsync(): LiveData<List<Account>>
|
||||
|
||||
@Query("Select * From Account Where id = :accountId")
|
||||
fun selectAsync(accountId: Int): LiveData<Account>
|
||||
|
||||
@Query("Select * from Account")
|
||||
fun selectAll(): List<Account>
|
||||
|
||||
@Query("Select * From Account Where id = :accountId")
|
||||
fun select(accountId: Int): Account
|
||||
|
||||
@Query("Update Account set last_modified = :lastModified Where id = :accountId")
|
||||
fun updateLastModified(accountId: Int, lastModified: Long)
|
||||
|
||||
@Query("Update Account set current_account = 0 Where id Not In (:accountId)")
|
||||
fun deselectOldCurrentAccount(accountId: Int)
|
||||
|
||||
@Query("Update Account set current_account = 1 Where id = :accountId")
|
||||
fun setCurrentAccount(accountId: Int)
|
||||
|
||||
@get:Query("Select count(*) From Account")
|
||||
val accountCount: Single<Int>
|
||||
|
||||
@Query("Update Account set writeToken = :writeToken Where id = :accountId")
|
||||
fun updateWriteToken(accountId: Int, writeToken: String)
|
||||
|
||||
@Query("Update Account set notifications_enabled = :enabled Where id = :accountId")
|
||||
fun updateNotificationState(accountId: Int, enabled: Boolean): Completable
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package com.readrops.db.dao
|
||||
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Update
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
|
||||
interface BaseDao<T> {
|
||||
|
||||
@Insert
|
||||
fun insert(entity: T): Single<Long>
|
||||
|
||||
// only here for compatibility with LocalFeedRepository
|
||||
// which hasn't been written with rxjava usage in mind
|
||||
@Insert
|
||||
fun compatInsert(entity: T): Long
|
||||
|
||||
@Insert
|
||||
fun insert(entities: List<T>): List<Long>
|
||||
|
||||
@Update
|
||||
fun update(entity: T): Completable
|
||||
|
||||
@Update
|
||||
fun update(entities: List<T>): Completable
|
||||
|
||||
@Delete
|
||||
fun delete(entity: T): Completable
|
||||
|
||||
@Delete
|
||||
fun delete(entities: List<T>): Completable
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
package com.readrops.db.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.RoomWarnings
|
||||
import androidx.room.Transaction
|
||||
import com.readrops.db.entities.Feed
|
||||
import com.readrops.db.entities.account.Account
|
||||
import com.readrops.db.pojo.FeedWithFolder
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
import java.lang.Exception
|
||||
import java.util.ArrayList
|
||||
|
||||
@Dao
|
||||
abstract class FeedDao : BaseDao<Feed> {
|
||||
|
||||
@Query("Select * from Feed Where account_id = :accountId order by name ASC")
|
||||
abstract fun getFeeds(accountId: Int): List<Feed>
|
||||
|
||||
@get:Query("Select * from Feed Order By name ASC")
|
||||
abstract val allFeeds: LiveData<List<Feed>>
|
||||
|
||||
@Query("Select * from Feed Where id = :feedId")
|
||||
abstract fun getFeedById(feedId: Int): Feed
|
||||
|
||||
@Query("Select case When :feedUrl In (Select url from Feed Where account_id = :accountId) Then 1 else 0 end")
|
||||
abstract fun feedExists(feedUrl: String, accountId: Int): Boolean
|
||||
|
||||
@Query("Select case When :remoteId In (Select remoteId from Feed Where account_id = :accountId) Then 1 else 0 end")
|
||||
abstract fun remoteFeedExists(remoteId: String, accountId: Int): Boolean
|
||||
|
||||
@Query("Select count(*) from Feed Where account_id = :accountId")
|
||||
abstract fun getFeedCount(accountId: Int): Single<Int>
|
||||
|
||||
@Query("Select * from Feed Where url = :feedUrl And account_id = :accountId")
|
||||
abstract fun getFeedByUrl(feedUrl: String, accountId: Int): Feed
|
||||
|
||||
@Query("Select id from Feed Where remoteId = :remoteId And account_id = :accountId")
|
||||
abstract fun getFeedIdByRemoteId(remoteId: String, accountId: Int): Int
|
||||
|
||||
@Query("Select * from Feed Where folder_id = :folderId")
|
||||
abstract fun getFeedsByFolder(folderId: Int): List<Feed>
|
||||
|
||||
@Query("Select * from Feed Where account_id = :accountId And folder_id is null")
|
||||
abstract fun getFeedsWithoutFolder(accountId: Int): List<Feed>
|
||||
|
||||
@Query("Update Feed set etag = :etag, last_modified = :lastModified Where id = :feedId")
|
||||
abstract fun updateHeaders(etag: String, lastModified: String, feedId: Int)
|
||||
|
||||
@Query("Update Feed set name = :feedName, url = :feedUrl, folder_id = :folderId Where id = :feedId")
|
||||
abstract fun updateFeedFields(feedId: Int, feedName: String, feedUrl: String, folderId: Int)
|
||||
|
||||
@Query("Update Feed set name = :name, folder_id = :folderId Where remoteId = :remoteFeedId And account_id = :accountId")
|
||||
abstract fun updateNameAndFolder(remoteFeedId: String, accountId: Int, name: String, folderId: Int?)
|
||||
|
||||
@Query("Update Feed set text_color = :textColor, background_color = :bgColor Where id = :feedId")
|
||||
abstract fun updateColors(feedId: Int, textColor: Int, bgColor: Int)
|
||||
|
||||
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
|
||||
@Query("Select Feed.name as feed_name, Feed.id as feed_id, Folder.name as folder_name, Folder.id as folder_id, Folder.remoteId as folder_remoteId, Folder.account_id as folder_account_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.text_color as feed_text_color, Feed.background_color as feed_background_color" +
|
||||
", Feed.account_id as feed_account_id, Feed.notification_enabled as feed_notification_enabled, Feed.siteUrl as feed_siteUrl, Feed.remoteId as feed_remoteId from Feed Left Join Folder on Feed.folder_id = Folder.id Where Feed.account_id = :accountId Order by Feed.name")
|
||||
abstract fun getAllFeedsWithFolder(accountId: Int): LiveData<List<FeedWithFolder>>
|
||||
|
||||
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
|
||||
@Query("Select id, name, icon_url, notification_enabled, text_color, background_color, account_id From Feed Where account_id = :accountId")
|
||||
abstract fun getFeedsForNotifPermission(accountId: Int): LiveData<List<Feed>>
|
||||
|
||||
@Query("Select * From Feed Where id in (:ids)")
|
||||
abstract fun selectFromIdList(ids: List<Long>): List<Feed>
|
||||
|
||||
@Query("Select remoteId From Feed Where account_id = :accountId")
|
||||
abstract fun getFeedRemoteIdsOfAccount(accountId: Int): MutableList<String>
|
||||
|
||||
@Query("Delete from Feed Where remoteId in (:ids) And account_id = :accountId")
|
||||
abstract fun deleteByIds(ids: List<String>, accountId: Int)
|
||||
|
||||
@Query("Select id From Folder Where remoteId = :remoteId And account_id = :accountId")
|
||||
abstract fun getRemoteFolderLocalId(remoteId: String, accountId: Int): Int
|
||||
|
||||
@Query("Update Feed set notification_enabled = :enabled Where id = :feedId")
|
||||
abstract fun updateFeedNotificationState(feedId: Int, enabled: Boolean): Completable
|
||||
|
||||
@Query("Update Feed set notification_enabled = :enabled Where account_id = :accountId")
|
||||
abstract fun updateAllFeedsNotificationState(accountId: Int, enabled: Boolean): Completable
|
||||
|
||||
/**
|
||||
* Insert, update and delete feeds, by account
|
||||
*
|
||||
* @param feeds feeds to insert or update
|
||||
* @param account owner of the feeds
|
||||
* @return the list of the inserted feeds ids
|
||||
*/
|
||||
@Transaction
|
||||
open fun feedsUpsert(feeds: List<Feed>, account: Account): List<Long> {
|
||||
val accountFeedIds = getFeedRemoteIdsOfAccount(account.id)
|
||||
val feedsToInsert = arrayListOf<Feed>()
|
||||
|
||||
for (feed in feeds) {
|
||||
val folderId: Int? = try {
|
||||
val remoteFolderId = feed.remoteFolderId!!.toInt()
|
||||
if (remoteFolderId == 0) null else getRemoteFolderLocalId(feed.remoteFolderId!!, account.id)
|
||||
} catch (e: Exception) {
|
||||
if (feed.remoteFolderId == null) null else getRemoteFolderLocalId(feed.remoteFolderId!!, account.id)
|
||||
}
|
||||
|
||||
if (remoteFeedExists(feed.remoteId!!, account.id)) {
|
||||
updateNameAndFolder(feed.remoteId!!, account.id, feed.name!!, folderId)
|
||||
accountFeedIds.remove(feed.remoteId)
|
||||
} else {
|
||||
feed.folderId = folderId
|
||||
feedsToInsert.add(feed)
|
||||
}
|
||||
}
|
||||
|
||||
if (accountFeedIds.isNotEmpty())
|
||||
deleteByIds(accountFeedIds, account.id)
|
||||
|
||||
return insert(feedsToInsert)
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package com.readrops.db.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import com.readrops.db.entities.Folder
|
||||
import com.readrops.db.entities.account.Account
|
||||
import com.readrops.db.pojo.FolderWithFeedCount
|
||||
import java.util.ArrayList
|
||||
|
||||
@Dao
|
||||
abstract class FolderDao : BaseDao<Folder> {
|
||||
|
||||
@Query("Select * from Folder Where account_id = :accountId Order By name ASC")
|
||||
abstract fun getAllFolders(accountId: Int): LiveData<List<Folder>>
|
||||
|
||||
@Query("Select Folder.*, count(Feed.id) as feed_count from Folder Left Join Feed on Folder.id = Feed.folder_id Where Folder.account_id = :accountId Group by Folder.id Order By name ASC")
|
||||
abstract fun getFoldersWithFeedCount(accountId: Int): LiveData<List<FolderWithFeedCount>>
|
||||
|
||||
@Query("Select * from Folder Where account_id = :accountId Order By name ASC")
|
||||
abstract fun getFolders(accountId: Int): List<Folder>
|
||||
|
||||
@Query("Update Folder set name = :name Where remoteId = :remoteFolderId And account_id = :accountId")
|
||||
abstract fun updateName(remoteFolderId: String, accountId: Int, name: String)
|
||||
|
||||
@Query("Select case When :remoteId In (Select remoteId From Folder Where account_id = :accountId) Then 1 else 0 end")
|
||||
abstract fun remoteFolderExists(remoteId: String, accountId: Int): Boolean
|
||||
|
||||
@Query("Select * from Folder Where id = :folderId")
|
||||
abstract fun select(folderId: Int): Folder
|
||||
|
||||
@Query("Select remoteId From Folder Where account_id = :accountId")
|
||||
abstract fun getFolderRemoteIdsOfAccount(accountId: Int): MutableList<String>
|
||||
|
||||
@Query("Delete From Folder Where remoteId in (:ids) And account_id = :accountId")
|
||||
abstract fun deleteByIds(ids: List<String>, accountId: Int)
|
||||
|
||||
@Query("Select * From Folder Where name = :name And account_id = :accountId")
|
||||
abstract fun getFolderByName(name: String, accountId: Int): Folder
|
||||
|
||||
/**
|
||||
* Insert, update and delete folders
|
||||
*
|
||||
* @param folders folders to insert or update
|
||||
* @param account owner of the feeds
|
||||
* @return the list of the inserted folders ids
|
||||
*/
|
||||
@Transaction
|
||||
open fun foldersUpsert(folders: List<Folder>, account: Account): List<Long> {
|
||||
val accountFolderIds = getFolderRemoteIdsOfAccount(account.id)
|
||||
val foldersToInsert = arrayListOf<Folder>()
|
||||
|
||||
for (folder in folders) {
|
||||
if (remoteFolderExists(folder.remoteId!!, account.id)) {
|
||||
updateName(folder.remoteId!!, account.id, folder.name!!)
|
||||
accountFolderIds.remove(folder.remoteId)
|
||||
} else {
|
||||
foldersToInsert.add(folder)
|
||||
}
|
||||
}
|
||||
|
||||
if (accountFolderIds.isNotEmpty())
|
||||
deleteByIds(accountFolderIds, account.id)
|
||||
|
||||
return insert(foldersToInsert)
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package com.readrops.db.dao
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.paging.DataSource
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.RawQuery
|
||||
import androidx.sqlite.db.SupportSQLiteQuery
|
||||
import com.readrops.db.entities.Feed
|
||||
import com.readrops.db.entities.Folder
|
||||
import com.readrops.db.entities.Item
|
||||
import com.readrops.db.entities.ItemState
|
||||
import com.readrops.db.pojo.ItemWithFeed
|
||||
import com.readrops.db.pojo.StarItem
|
||||
import io.reactivex.Completable
|
||||
|
||||
@Dao
|
||||
interface ItemDao : BaseDao<Item> {
|
||||
|
||||
@RawQuery(observedEntities = [Item::class, Folder::class, Feed::class, ItemState::class])
|
||||
fun selectAll(query: SupportSQLiteQuery): DataSource.Factory<Int, ItemWithFeed>
|
||||
|
||||
@Query("Select * From Item Where id = :itemId")
|
||||
fun select(itemId: Int): Item
|
||||
|
||||
@Query("Select case When :guid In (Select guid From Item Inner Join Feed on Item.feed_id = Feed.id and account_id = :accountId) Then 1 else 0 end")
|
||||
fun itemExists(guid: String, accountId: Int): Boolean
|
||||
|
||||
@Query("Select case When :remoteId In (Select remoteId from Item) And :feedId In (Select feed_id From Item) Then 1 else 0 end")
|
||||
fun remoteItemExists(remoteId: String, feedId: Int): Boolean
|
||||
|
||||
@Query("Select * From Item Where remoteId = :remoteId And feed_id = :feedId")
|
||||
fun selectByRemoteId(remoteId: String, feedId: Int): Item
|
||||
|
||||
@Query("Update Item Set read = :read Where id = :itemId")
|
||||
fun setReadState(itemId: Int, read: Boolean): Completable
|
||||
|
||||
@Query("Update Item set starred = :starred Where id = :itemId")
|
||||
fun setStarState(itemId: Int, starred: Boolean): Completable
|
||||
|
||||
@Query("Update Item set read = :readState Where feed_id In (Select id From Feed Where account_id = :accountId)")
|
||||
fun setAllItemsReadState(readState: Int, accountId: Int): Completable
|
||||
|
||||
@Query("Update Item set read = :readState Where feed_id = :feedId")
|
||||
fun setAllFeedItemsReadState(feedId: Int, readState: Int): Completable
|
||||
|
||||
@Query("Update Item set read_it_later = :readLater Where id = :itemId")
|
||||
fun setReadItLater(readLater: Boolean, itemId: Int): Completable
|
||||
|
||||
@Query("Select count(*) From Item Where feed_id = :feedId And read = 0")
|
||||
fun getUnreadCount(feedId: Int): Int
|
||||
|
||||
@RawQuery(observedEntities = [Item::class, ItemState::class])
|
||||
fun getItemById(query: SupportSQLiteQuery): LiveData<ItemWithFeed>
|
||||
|
||||
@Query("Select Item.guid, Feed.remoteId as feedRemoteId From Item Inner Join Feed On Item.feed_id = Feed.id Where Item.remoteId In (:remoteIds) And account_id = :accountId")
|
||||
fun getStarChanges(remoteIds: List<String>, accountId: Int): List<StarItem>
|
||||
|
||||
@Query("Update Item set read = :read, starred = :starred Where remoteId = :remoteId")
|
||||
fun setReadAndStarState(remoteId: String, read: Boolean, starred: Boolean)
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
package com.readrops.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import com.readrops.db.entities.Item
|
||||
import com.readrops.db.entities.ItemStateChange
|
||||
import com.readrops.db.pojo.ItemReadStarState
|
||||
import io.reactivex.Completable
|
||||
|
||||
@Dao
|
||||
interface ItemStateChangeDao : BaseDao<ItemStateChange> {
|
||||
|
||||
@Insert
|
||||
fun insertItemStateChange(itemStateChange: ItemStateChange)
|
||||
|
||||
@Delete
|
||||
fun deleteItemStateChange(itemStateChange: ItemStateChange)
|
||||
|
||||
@Query("Delete From ItemStateChange Where account_id = :accountId")
|
||||
fun resetStateChanges(accountId: Int)
|
||||
|
||||
@Query("Select case When ItemState.remote_id is NULL Or ItemState.read = 1 Then 1 else 0 End read, " +
|
||||
"case When ItemState.remote_id is NULL Or ItemState.starred = 1 Then 1 else 0 End starred," +
|
||||
"ItemStateChange.read_change, ItemStateChange.star_change, Item.remoteId " +
|
||||
"From ItemStateChange Inner Join Item On ItemStateChange.id = Item.id " +
|
||||
"Left Join ItemState On ItemState.remote_id = Item.remoteId Where ItemStateChange.account_id = :accountId")
|
||||
fun getItemStateChanges(accountId: Int): List<ItemReadStarState>
|
||||
|
||||
@Query("Select Item.read, Item.starred," +
|
||||
"ItemStateChange.read_change, ItemStateChange.star_change, Item.remoteId " +
|
||||
"From ItemStateChange Inner Join Item On ItemStateChange.id = Item.id " +
|
||||
"Where ItemStateChange.account_id = :accountId")
|
||||
fun getNextcloudNewsStateChanges(accountId: Int): List<ItemReadStarState>
|
||||
|
||||
@Query("Select Case When :itemId In (Select id From ItemStateChange Where read_change = 1) Then 1 Else 0 End")
|
||||
fun readStateChangeExists(itemId: Int): Boolean
|
||||
|
||||
@Query("Select Case When :itemId In (Select id From ItemStateChange Where star_change = 1) Then 1 Else 0 End")
|
||||
fun starStateChangeExists(itemId: Int): Boolean
|
||||
|
||||
fun upsertItemReadStateChange(item: Item, accountId: Int, useSeparateState: Boolean) = Completable.create {
|
||||
if (itemStateChangeExists(item.id, accountId)) {
|
||||
val oldItemReadState = if (useSeparateState)
|
||||
getItemReadState(item.remoteId!!, accountId)
|
||||
else
|
||||
getStandardItemReadState(item.remoteId!!, accountId)
|
||||
|
||||
val readChange = item.isRead != oldItemReadState
|
||||
|
||||
if (readChange) {
|
||||
val oldItemStateChange = selectItemStateChange(item.id)
|
||||
val newReadChange = !oldItemStateChange.readChange
|
||||
|
||||
if (!newReadChange && !oldItemStateChange.starChange) {
|
||||
deleteItemStateChange(oldItemStateChange)
|
||||
} else {
|
||||
updateItemReadStateChange(newReadChange, oldItemStateChange.id)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
insertItemStateChange(ItemStateChange(id = item.id, readChange = true, accountId = accountId))
|
||||
}
|
||||
|
||||
it.onComplete()
|
||||
}
|
||||
|
||||
fun upsertItemStarStateChange(item: Item, accountId: Int, useSeparateState: Boolean) = Completable.create {
|
||||
if (itemStateChangeExists(item.id, accountId)) {
|
||||
val oldItemStarState = if (useSeparateState)
|
||||
getItemStarState(item.remoteId!!, accountId)
|
||||
else
|
||||
getStandardItemStarState(item.remoteId!!, accountId)
|
||||
|
||||
val starChange = item.isStarred != oldItemStarState
|
||||
|
||||
if (starChange) {
|
||||
val oldItemStateChange = selectItemStateChange(item.id)
|
||||
val newStarChange = !oldItemStateChange.starChange
|
||||
|
||||
if (!newStarChange && !oldItemStateChange.readChange) {
|
||||
deleteItemStateChange(oldItemStateChange)
|
||||
} else {
|
||||
updateItemStarStateChange(newStarChange, oldItemStateChange.id)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
insertItemStateChange(ItemStateChange(id = item.id, starChange = true, accountId = accountId))
|
||||
}
|
||||
|
||||
it.onComplete()
|
||||
}
|
||||
|
||||
@Query("Select * From ItemStateChange Where id = :id")
|
||||
fun selectItemStateChange(id: Int): ItemStateChange
|
||||
|
||||
@Query("Select case When Exists (Select id, account_id From ItemStateChange Where id = :id And account_id = :accountId) Then 1 else 0 End")
|
||||
fun itemStateChangeExists(id: Int, accountId: Int): Boolean
|
||||
|
||||
@Query("Select read From ItemState Where remote_id = :remoteId And account_id = :accountId")
|
||||
fun getItemReadState(remoteId: String, accountId: Int): Boolean
|
||||
|
||||
@Query("Select read From Item Inner Join Feed On Item.feed_id = Feed.id Where Item.remoteId = :remoteId And account_id = :accountId")
|
||||
fun getStandardItemReadState(remoteId: String, accountId: Int): Boolean
|
||||
|
||||
@Query("Select starred From ItemState Where remote_id = :remoteId And account_id = :accountId")
|
||||
fun getItemStarState(remoteId: String, accountId: Int): Boolean
|
||||
|
||||
@Query("Select starred From Item Inner Join Feed On Item.feed_id = Feed.id Where Item.remoteId = :remoteId And account_id = :accountId")
|
||||
fun getStandardItemStarState(remoteId: String, accountId: Int): Boolean
|
||||
|
||||
@Query("Update ItemStateChange set read_change = :readChange Where id = :id")
|
||||
fun updateItemReadStateChange(readChange: Boolean, id: Int)
|
||||
|
||||
@Query("Update ItemStateChange set star_change = :starChange Where id = :id")
|
||||
fun updateItemStarStateChange(starChange: Boolean, id: Int)
|
||||
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
package com.readrops.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import com.readrops.db.entities.ItemState
|
||||
import io.reactivex.Completable
|
||||
|
||||
@Dao
|
||||
interface ItemStateDao : BaseDao<ItemState> {
|
||||
|
||||
@Query("Delete From ItemState Where account_id = :accountId")
|
||||
fun deleteItemsStates(accountId: Int)
|
||||
|
||||
@Query("Delete From ItemState Where remote_id = :remoteId And account_id = :accountId")
|
||||
fun deleteItemState(remoteId: String, accountId: Int)
|
||||
|
||||
@Insert
|
||||
fun insertItemStates(items: List<ItemState>)
|
||||
|
||||
@Insert
|
||||
fun insertItemState(itemState: ItemState)
|
||||
|
||||
@Query("Update ItemState set read = :read Where remote_id = :remoteId And account_id = :accountId")
|
||||
fun updateItemReadState(read: Boolean, remoteId: String, accountId: Int)
|
||||
|
||||
@Query("Update ItemState set starred = :star Where remote_id = :remoteId And account_id = :accountId")
|
||||
fun updateItemStarState(star: Boolean, remoteId: String, accountId: Int)
|
||||
|
||||
@Query("Select case When Exists (Select remote_id, account_id From ItemState Where remote_id = :remoteId And account_id = :accountId) Then 1 else 0 End")
|
||||
fun itemStateExists(remoteId: String, accountId: Int): Boolean
|
||||
|
||||
fun upsertItemReadState(itemState: ItemState) = Completable.create {
|
||||
if (itemStateExists(itemState.remoteId, itemState.accountId)) {
|
||||
updateItemReadState(itemState.read, itemState.remoteId, itemState.accountId)
|
||||
} else {
|
||||
insertItemState(itemState)
|
||||
}
|
||||
|
||||
it.onComplete()
|
||||
}
|
||||
|
||||
fun upsertItemStarState(itemState: ItemState) = Completable.create {
|
||||
if (itemStateExists(itemState.remoteId, itemState.accountId)) {
|
||||
updateItemStarState(itemState.starred, itemState.remoteId, itemState.accountId)
|
||||
} else {
|
||||
insertItemState(itemState)
|
||||
}
|
||||
|
||||
it.onComplete()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue