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.localfeed.LocalRSSDataSource
|
||||||
import com.readrops.api.services.Credentials
|
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.NewFreshRSSDataSource
|
||||||
import com.readrops.api.services.freshrss.NewFreshRSSService
|
import com.readrops.api.services.freshrss.NewFreshRSSService
|
||||||
import com.readrops.api.services.freshrss.adapters.FreshRSSFeedsAdapter
|
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.freshrss.adapters.FreshRSSUserInfoAdapter
|
||||||
import com.readrops.api.services.nextcloudnews.NewNextcloudNewsDataSource
|
import com.readrops.api.services.nextcloudnews.NewNextcloudNewsDataSource
|
||||||
import com.readrops.api.services.nextcloudnews.NewNextcloudNewsService
|
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.NextNewsFeedsAdapter
|
||||||
import com.readrops.api.services.nextcloudnews.adapters.NextNewsFoldersAdapter
|
import com.readrops.api.services.nextcloudnews.adapters.NextNewsFoldersAdapter
|
||||||
import com.readrops.api.services.nextcloudnews.adapters.NextNewsItemsAdapter
|
import com.readrops.api.services.nextcloudnews.adapters.NextNewsItemsAdapter
|
||||||
|
@ -48,8 +46,6 @@ val apiModule = module {
|
||||||
|
|
||||||
//region freshrss
|
//region freshrss
|
||||||
|
|
||||||
factory { params -> FreshRSSDataSource(get(parameters = { params })) }
|
|
||||||
|
|
||||||
factory { params -> NewFreshRSSDataSource(get(parameters = { params })) }
|
factory { params -> NewFreshRSSDataSource(get(parameters = { params })) }
|
||||||
|
|
||||||
factory { (credentials: Credentials) ->
|
factory { (credentials: Credentials) ->
|
||||||
|
@ -75,8 +71,6 @@ val apiModule = module {
|
||||||
|
|
||||||
//region nextcloud news
|
//region nextcloud news
|
||||||
|
|
||||||
factory { params -> NextNewsDataSource(get(parameters = { params })) }
|
|
||||||
|
|
||||||
factory { params -> NewNextcloudNewsDataSource(get(parameters = { params })) }
|
factory { params -> NewNextcloudNewsDataSource(get(parameters = { params })) }
|
||||||
|
|
||||||
factory { (credentials: Credentials) ->
|
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
|
package com.readrops.api.services.freshrss.adapters
|
||||||
|
|
||||||
import com.readrops.api.services.freshrss.FreshRSSDataSource.GOOGLE_READ
|
import com.readrops.api.services.freshrss.NewFreshRSSDataSource.Companion.GOOGLE_READ
|
||||||
import com.readrops.api.services.freshrss.FreshRSSDataSource.GOOGLE_STARRED
|
import com.readrops.api.services.freshrss.NewFreshRSSDataSource.Companion.GOOGLE_STARRED
|
||||||
import com.readrops.api.utils.exceptions.ParseException
|
import com.readrops.api.utils.exceptions.ParseException
|
||||||
import com.readrops.api.utils.extensions.nextNonEmptyString
|
import com.readrops.api.utils.extensions.nextNonEmptyString
|
||||||
import com.readrops.api.utils.extensions.nextNullableString
|
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.apiModule
|
||||||
import com.readrops.api.enqueueOK
|
import com.readrops.api.enqueueOK
|
||||||
import com.readrops.api.enqueueStream
|
import com.readrops.api.enqueueStream
|
||||||
import com.readrops.api.services.nextcloudnews.NextNewsDataSource.ItemQueryType
|
|
||||||
import com.readrops.db.entities.account.Account
|
import com.readrops.db.entities.account.Account
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
import com.squareup.moshi.Types
|
import com.squareup.moshi.Types
|
||||||
|
@ -94,7 +93,7 @@ class NextcloudNewsDataSourceTest : KoinTest {
|
||||||
val stream = TestUtils.loadResource("services/nextcloudnews/adapters/items.json")
|
val stream = TestUtils.loadResource("services/nextcloudnews/adapters/items.json")
|
||||||
mockServer.enqueueStream(stream)
|
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()
|
val request = mockServer.takeRequest()
|
||||||
|
|
||||||
assertTrue { items.size == 3 }
|
assertTrue { items.size == 3 }
|
||||||
|
|
|
@ -166,7 +166,7 @@ class FreshRSSRepository(
|
||||||
|
|
||||||
if (itemsToInsert.isNotEmpty()) {
|
if (itemsToInsert.isNotEmpty()) {
|
||||||
itemsToInsert.sortWith(Item::compareTo)
|
itemsToInsert.sortWith(Item::compareTo)
|
||||||
database.itemDao().insert(itemsToInsert)
|
database.newItemDao().insert(itemsToInsert)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ class LocalRSSRepository(
|
||||||
val itemsToInsert = mutableListOf<Item>()
|
val itemsToInsert = mutableListOf<Item>()
|
||||||
|
|
||||||
for (item in items) {
|
for (item in items) {
|
||||||
if (!database.itemDao().itemExists(item.guid!!, feed.accountId)) {
|
if (!database.newItemDao().itemExists(item.guid!!, feed.accountId)) {
|
||||||
if (item.description != null) {
|
if (item.description != null) {
|
||||||
item.cleanDescription = Jsoup.parse(item.description).text()
|
item.cleanDescription = Jsoup.parse(item.description).text()
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ class NextcloudNewsRepository(
|
||||||
account.lastModified = newLastModified
|
account.lastModified = newLastModified
|
||||||
database.newAccountDao().updateLastModified(newLastModified, account.id)
|
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.TypeConverters
|
||||||
import androidx.room.migration.Migration
|
import androidx.room.migration.Migration
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
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.NewAccountDao
|
||||||
import com.readrops.db.dao.newdao.NewFeedDao
|
import com.readrops.db.dao.newdao.NewFeedDao
|
||||||
import com.readrops.db.dao.newdao.NewFolderDao
|
import com.readrops.db.dao.newdao.NewFolderDao
|
||||||
|
@ -34,18 +28,6 @@ import com.readrops.db.entities.account.Account
|
||||||
)
|
)
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
abstract class Database : RoomDatabase() {
|
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
|
// new dao
|
||||||
|
|
||||||
abstract fun newFeedDao(): NewFeedDao
|
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