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

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

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

View File

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

View File

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

View File

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

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

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