Remove unused files

This commit is contained in:
Shinokuni 2024-07-02 19:25:15 +02:00
parent e20bc62418
commit 26eaebf442
20 changed files with 6 additions and 1367 deletions

View File

@ -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) ->

View File

@ -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);
}
}

View File

@ -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/"
}
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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/"
}
}

View File

@ -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 }

View File

@ -166,7 +166,7 @@ class FreshRSSRepository(
if (itemsToInsert.isNotEmpty()) {
itemsToInsert.sortWith(Item::compareTo)
database.itemDao().insert(itemsToInsert)
database.newItemDao().insert(itemsToInsert)
}
}

View File

@ -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()
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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()
}
}