Merge branch 'develop' into feature/local_rss_memory_improvements

This commit is contained in:
Shinokuni 2021-09-04 15:16:33 +02:00
commit 58122cb456
58 changed files with 652 additions and 1637 deletions

View File

@ -22,7 +22,7 @@ jobs:
- name: Build with Gradle
run: ./gradlew clean build
- name: Android Emulator Runner
uses: ReactiveCircus/android-emulator-runner@v2.19.0
uses: ReactiveCircus/android-emulator-runner@v2.20.0
with:
api-level: 29
script: ./gradlew connectedCheck

View File

@ -1,6 +1,5 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion rootProject.ext.compileSdkVersion

View File

@ -71,7 +71,7 @@ object OPMLParser {
if ((outline.outlines != null && !outline.outlines?.isEmpty()!!) || outline.xmlUrl.isNullOrEmpty()) {
// if the outline doesn't have text or title value but contains sub outlines,
// those sub outlines will be considered as not belonging to any folder and join the others at the top level of the hierarchy
val folder = if (outline.name != null) Folder(outline.name) else null
val folder = if (outline.name != null) Folder(name = outline.name) else null
outline.outlines?.forEach {
val recursiveFeedsFolders = parseOutline(it)
@ -108,7 +108,7 @@ object OPMLParser {
val feedOutlines = arrayListOf<Outline>()
for (feed in folderAndFeeds.value) {
val feedOutline = Outline(feed.name, feed.url, feed.siteUrl)
val feedOutline = Outline(feed.name, feed.url!!, feed.siteUrl)
feedOutlines += feedOutline
}
@ -117,7 +117,7 @@ object OPMLParser {
outlines += outline
} else {
for (feed in folderAndFeeds.value) {
outlines += Outline(feed.name, feed.url, feed.siteUrl)
outlines += Outline(feed.name, feed.url!!, feed.siteUrl)
}
}
}

View File

@ -12,7 +12,7 @@ abstract class Credentials(val authorization: String?, val url: String) {
companion object {
@JvmStatic
fun toCredentials(account: Account): Credentials {
val endPoint = getEndPoint(account.accountType)
val endPoint = getEndPoint(account.accountType!!)
return when (account.accountType) {
AccountType.NEXTCLOUD_NEWS -> NextNewsCredentials(account.login, account.password, account.url + endPoint)

View File

@ -12,7 +12,7 @@ import com.squareup.moshi.ToJson
class FreshRSSFeedsAdapter {
@ToJson
fun toJson(feed: Feed): String = ""
fun toJson(feeds: List<Feed>): String = ""
@SuppressLint("CheckResult")
@FromJson

View File

@ -12,7 +12,7 @@ import java.util.*
class FreshRSSFoldersAdapter {
@ToJson
fun toJson(folder: Folder): String = ""
fun toJson(folders: List<Folder>): String = ""
@SuppressLint("CheckResult")
@FromJson

View File

@ -14,7 +14,7 @@ import java.net.URI
class NextNewsFeedsAdapter {
@ToJson
fun toJson(feed: Feed): String = ""
fun toJson(feeds: List<Feed>): String = ""
@SuppressLint("CheckResult")
@FromJson

View File

@ -11,7 +11,7 @@ import com.squareup.moshi.ToJson
class NextNewsFoldersAdapter {
@ToJson
fun toJson(folder: Folder): String = ""
fun toJson(folders: List<Folder>): String = ""
@SuppressLint("CheckResult")
@FromJson

View File

@ -26,9 +26,9 @@ class RSS1ItemsAdapterTest {
assertEquals(items.size, 4)
assertEquals(item.title, "Google Expands its Flutter Development Kit To Windows Apps")
assertEquals(item.link.trim(), "https://developers.slashdot.org/story/20/09/23/1616231/google-expands-" +
assertEquals(item.link!!.trim(), "https://developers.slashdot.org/story/20/09/23/1616231/google-expands-" +
"its-flutter-development-kit-to-windows-apps?utm_source=rss1.0mainlinkanon&utm_medium=feed")
assertEquals(item.guid.trim(), "https://developers.slashdot.org/story/20/09/23/1616231/google-expands-" +
assertEquals(item.guid!!.trim(), "https://developers.slashdot.org/story/20/09/23/1616231/google-expands-" +
"its-flutter-development-kit-to-windows-apps?utm_source=rss1.0mainlinkanon&utm_medium=feed")
assertEquals(item.pubDate, DateUtils.parse("2020-09-23T16:15:00+00:00"))
assertEquals(item.author, "msmash")

View File

@ -25,11 +25,11 @@ class OPMLParserTest {
assertEquals(foldersAndFeeds?.size, 6)
assertEquals(foldersAndFeeds?.get(Folder("Folder 1"))?.size, 2)
assertEquals(foldersAndFeeds?.get(Folder("Subfolder 1"))?.size, 4)
assertEquals(foldersAndFeeds?.get(Folder("Subfolder 2"))?.size, 1)
assertEquals(foldersAndFeeds?.get(Folder("Sub subfolder 1"))?.size, 2)
assertEquals(foldersAndFeeds?.get(Folder("Sub subfolder 2"))?.size, 0)
assertEquals(foldersAndFeeds?.get(Folder(name = "Folder 1"))?.size, 2)
assertEquals(foldersAndFeeds?.get(Folder(name = "Subfolder 1"))?.size, 4)
assertEquals(foldersAndFeeds?.get(Folder(name = "Subfolder 2"))?.size, 1)
assertEquals(foldersAndFeeds?.get(Folder(name = "Sub subfolder 1"))?.size, 2)
assertEquals(foldersAndFeeds?.get(Folder(name = "Sub subfolder 2"))?.size, 0)
assertEquals(foldersAndFeeds?.get(null)?.size, 2)
stream.close()
@ -68,11 +68,11 @@ class OPMLParserTest {
val outputStream = FileOutputStream(file)
val foldersAndFeeds: Map<Folder?, List<Feed>> = HashMap<Folder?, List<Feed>>().apply {
put(null, listOf(Feed("Feed1", "", "https://feed1.com"),
Feed("Feed2", "", "https://feed2.com")))
put(Folder("Folder1"), listOf())
put(Folder("Folder2"), listOf(Feed("Feed3", "", "https://feed3.com"),
Feed("Feed4", "", "https://feed4.com")))
put(null, listOf(Feed(name = "Feed1", url = "https://feed1.com"),
Feed(name = "Feed2", url = "https://feed2.com")))
put(Folder(name = "Folder1"), listOf())
put(Folder(name = "Folder2"), listOf(Feed(name = "Feed3", url = "https://feed3.com"),
Feed(name = "Feed4", url ="https://feed4.com")))
}
OPMLParser.write(foldersAndFeeds, outputStream)
@ -87,8 +87,8 @@ class OPMLParserTest {
OPMLParser.read(inputStream).subscribe { result -> foldersAndFeeds2 = result }
assertEquals(foldersAndFeeds.size, foldersAndFeeds2?.size)
assertEquals(foldersAndFeeds[Folder("Folder1")]?.size, foldersAndFeeds2?.get(Folder("Folder1"))?.size)
assertEquals(foldersAndFeeds[Folder("Folder2")]?.size, foldersAndFeeds2?.get(Folder("Folder2"))?.size)
assertEquals(foldersAndFeeds[Folder(name = "Folder1")]?.size, foldersAndFeeds2?.get(Folder(name = "Folder1"))?.size)
assertEquals(foldersAndFeeds[Folder(name = "Folder2")]?.size, foldersAndFeeds2?.get(Folder(name = "Folder2"))?.size)
assertEquals(foldersAndFeeds[null]?.size, foldersAndFeeds2?.get(null)?.size)
inputStream.close()

View File

@ -79,7 +79,7 @@ public class AccountTypeListActivity extends AppCompatActivity {
startActivity(intent);
finish();
} else {
Account account = new Account(null, getString(AccountType.LOCAL.getName()), AccountType.LOCAL);
Account account = new Account(null, getString(AccountType.LOCAL.getTypeName()), AccountType.LOCAL);
account.setCurrentAccount(true);
viewModel.insert(account)
@ -150,7 +150,7 @@ public class AccountTypeListActivity extends AppCompatActivity {
}
private void parseOPMLFile(Uri uri, MaterialDialog dialog) {
Account account = new Account(null, getString(AccountType.LOCAL.getName()), AccountType.LOCAL);
Account account = new Account(null, getString(AccountType.LOCAL.getTypeName()), AccountType.LOCAL);
account.setCurrentAccount(true);
viewModel.insert(account)

View File

@ -33,7 +33,7 @@ public class AccountTypeListAdapter extends RecyclerView.Adapter<AccountTypeList
public void onBindViewHolder(@NonNull AccountTypeViewHolder holder, int position) {
AccountType accountType = accountTypes.get(position);
holder.binding.accountTypeName.setText(accountType.getName());
holder.binding.accountTypeName.setText(accountType.getTypeName());
holder.binding.accountTypeLogo.setImageResource(accountType.getIconRes());
holder.binding.getRoot().setOnClickListener(v -> listener.onItemClick(accountType));

View File

@ -65,8 +65,8 @@ public class AddAccountActivity extends AppCompatActivity {
fillFields();
} else {
binding.providerImage.setImageResource(accountType.getIconRes());
binding.providerName.setText(accountType.getName());
binding.addAccountName.setText(accountType.getName());
binding.providerName.setText(accountType.getTypeName());
binding.addAccountName.setText(accountType.getTypeName());
if (accountType == AccountType.FRESHRSS) {
binding.addAccountPasswordLayout.setHelperText(getString(R.string.password_helper));
@ -178,7 +178,7 @@ public class AddAccountActivity extends AppCompatActivity {
private void fillFields() {
binding.providerImage.setImageResource(accountToEdit.getAccountType().getIconRes());
binding.providerName.setText(accountToEdit.getAccountType().getName());
binding.providerName.setText(accountToEdit.getAccountType().getTypeName());
binding.addAccountUrl.setText(accountToEdit.getUrl());
binding.addAccountName.setText(accountToEdit.getAccountName());

View File

@ -44,7 +44,7 @@ public class AccountArrayAdapter extends ArrayAdapter<Account> {
TextView accountName = convertView.findViewById(R.id.account_type_name);
accountIcon.setImageResource(account.getAccountType().getIconRes());
accountName.setText(account.getAccountType().getName());
accountName.setText(account.getAccountType().getTypeName());
return convertView;
}

View File

@ -90,7 +90,8 @@ public class ManageFeedsFoldersActivity extends AppCompatActivity {
.title(R.string.add_folder)
.positiveText(R.string.validate)
.input(R.string.folder, 0, (dialog, input) -> {
Folder folder = new Folder(input.toString());
Folder folder = new Folder();
folder.setName(input.toString());
folder.setAccountId(account.getId());
viewModel.addFolder(folder)

View File

@ -41,7 +41,7 @@ public class ItemViewModel extends ViewModel {
public LiveData<ItemWithFeed> getItemById(int id) {
return database.itemDao().getItemById(ItemSelectionQueryBuilder.buildQuery(id,
account.getConfig().useSeparateState()));
account.getConfig().getUseSeparateState()));
}
public Completable setStarState(Item item) {

View File

@ -218,7 +218,7 @@ public class MainItemListAdapter extends PagedListAdapter<ItemWithFeed, MainItem
@NonNull
@Override
public List<String> getPreloadItems(int position) {
if (getItem(position).getItem().hasImage()) {
if (getItem(position).getItem().getHasImage()) {
String url = getItem(position).getItem().getImageLink();
return Collections.singletonList(url);
} else {
@ -296,13 +296,13 @@ public class MainItemListAdapter extends PagedListAdapter<ItemWithFeed, MainItem
binding.itemDescription.setText(item.getCleanDescription());
} else {
binding.itemDescription.setVisibility(View.GONE);
if (itemWithFeed.getItem().hasImage())
if (itemWithFeed.getItem().getHasImage())
binding.itemTitle.setMaxLines(4);
}
}
private void setImages(ItemWithFeed itemWithFeed) {
if (itemWithFeed.getItem().hasImage()) {
if (itemWithFeed.getItem().getHasImage()) {
binding.itemImage.setVisibility(View.VISIBLE);
glideRequests

View File

@ -70,7 +70,7 @@ public class MainViewModel extends ViewModel {
}
DataSource.Factory<Integer, ItemWithFeed> items;
items = database.itemDao().selectAll(ItemsQueryBuilder.buildItemsQuery(queryFilters, currentAccount.getConfig().useSeparateState()));
items = database.itemDao().selectAll(ItemsQueryBuilder.buildItemsQuery(queryFilters, currentAccount.getConfig().getUseSeparateState()));
lastFetch = new LivePagedListBuilder<>(new RoomFactoryWrapper<>(items),
new PagedList.Config.Builder()

View File

@ -51,7 +51,7 @@ class SyncResultAnalyser(val context: Context, private val syncResults: Map<Acco
if (feedsIdsForNewItems.size > 1 && itemCount > 1) {
notifContent.title = account.accountName
notifContent.content = context.getString(R.string.new_items, itemCount.toString())
notifContent.largeIcon = Utils.getBitmapFromDrawable(ContextCompat.getDrawable(context, account.accountType.iconRes))
notifContent.largeIcon = Utils.getBitmapFromDrawable(ContextCompat.getDrawable(context, account.accountType!!.iconRes))
} else if (feedsIdsForNewItems.size == 1) // new items from only one feed from one account
oneFeedCase(feedsIdsForNewItems.first(), syncResult.items)
else if (itemCount == 1)
@ -80,7 +80,7 @@ class SyncResultAnalyser(val context: Context, private val syncResults: Map<Acco
}
if (items.size == 1) {
val item = database.itemDao().selectByRemoteId(items.first().remoteId,
val item = database.itemDao().selectByRemoteId(items.first().remoteId!!,
items.first().feedId)
notifContent.content = item.title
notifContent.item = item

View File

@ -115,7 +115,7 @@ public abstract class ARepository {
}
public Completable setItemReadState(Item item) {
if (account.getConfig().useSeparateState()) {
if (account.getConfig().getUseSeparateState()) {
return database.itemStateChangesDao().upsertItemReadStateChange(item, account.getId(), true)
.andThen(database.itemStateDao().upsertItemReadState(new ItemState(0, item.isRead(),
item.isStarred(), item.getRemoteId(), account.getId())));
@ -145,7 +145,7 @@ public abstract class ARepository {
}
public Completable setItemStarState(Item item) {
if (account.getConfig().useSeparateState()) {
if (account.getConfig().getUseSeparateState()) {
return database.itemStateChangesDao().upsertItemStarStateChange(item, account.getId(), true)
.andThen(database.itemStateDao().upsertItemStarState(new ItemState(0, item.isRead(),
item.isStarred(), item.getRemoteId(), account.getId())));

View File

@ -31,7 +31,7 @@ fun getFaviconLink(feed: Feed) {
feed.iconUrl = if (feed.iconUrl != null)
feed.iconUrl
else
HtmlParser.getFaviconLink(feed.siteUrl)
HtmlParser.getFaviconLink(feed.siteUrl!!)
}

View File

@ -1,6 +1,7 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-parcelize'
android {
compileSdkVersion rootProject.ext.compileSdkVersion

View File

@ -1,31 +0,0 @@
package com.readrops.db;
import androidx.room.TypeConverter;
import com.readrops.db.entities.account.AccountType;
import org.joda.time.LocalDateTime;
public class Converters {
@TypeConverter
public LocalDateTime fromTimeStamp(Long value) {
return new LocalDateTime(value);
}
@TypeConverter
public long fromLocalDateTime(LocalDateTime localDateTime) {
return localDateTime.toDateTime().getMillis();
}
@TypeConverter
public AccountType fromAccountTypeCode(int ordinal) {
return AccountType.values()[ordinal];
}
@TypeConverter
public int getAccountTypeCode(AccountType accountType) {
return accountType.ordinal();
}
}

View File

@ -0,0 +1,28 @@
package com.readrops.db
import androidx.room.TypeConverter
import com.readrops.db.entities.account.AccountType
import org.joda.time.LocalDateTime
object Converters {
@TypeConverter
fun fromTimeStamp(value: Long): LocalDateTime {
return LocalDateTime(value)
}
@TypeConverter
fun fromLocalDateTime(localDateTime: LocalDateTime): Long {
return localDateTime.toDateTime().millis
}
@TypeConverter
fun fromAccountTypeCode(ordinal: Int): AccountType {
return AccountType.values()[ordinal]
}
@TypeConverter
fun getAccountTypeCode(accountType: AccountType): Int {
return accountType.ordinal
}
}

View File

@ -1,46 +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 java.util.List;
import io.reactivex.Completable;
import io.reactivex.Single;
@Dao
public interface AccountDao extends BaseDao<Account> {
@Query("Select * from Account")
LiveData<List<Account>> selectAllAsync();
@Query("Select * From Account Where id = :accountId")
LiveData<Account> selectAsync(int accountId);
@Query("Select * from Account")
List<Account> selectAll();
@Query("Select * From Account Where id = :accountId")
Account select(int accountId);
@Query("Update Account set last_modified = :lastModified Where id = :accountId")
void updateLastModified(int accountId, long lastModified);
@Query("Update Account set current_account = 0 Where id Not In (:accountId)")
void deselectOldCurrentAccount(int accountId);
@Query("Update Account set current_account = 1 Where id = :accountId")
void setCurrentAccount(int accountId);
@Query("Select count(*) From Account")
Single<Integer> getAccountCount();
@Query("Update Account set writeToken = :writeToken Where id = :accountId")
void updateWriteToken(int accountId, String writeToken);
@Query("Update Account set notifications_enabled = :enabled Where id = :accountId")
Completable updateNotificationState(int accountId, boolean enabled);
}

View File

@ -0,0 +1,42 @@
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,36 +0,0 @@
package com.readrops.db.dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Update;
import java.util.List;
import io.reactivex.Completable;
import io.reactivex.Single;
public interface BaseDao<T> {
@Insert
Single<Long> insert(T entity);
// only here for compatibility with LocalFeedRepository
// which hasn't been written with rxjava usage in mind
@Insert
long compatInsert(T entity);
@Insert
List<Long> insert(List<T> entities);
@Update
Completable update(T entity);
@Update
Completable update(List<T> entities);
@Delete
Completable delete(T entity);
@Delete
Completable delete(List<T> entities);
}

View File

@ -0,0 +1,33 @@
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,133 +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 java.util.ArrayList;
import java.util.List;
import io.reactivex.Completable;
import io.reactivex.Single;
@Dao
public abstract class FeedDao implements BaseDao<Feed> {
@Query("Select * from Feed Where account_id = :accountId order by name ASC")
public abstract List<Feed> getFeeds(int accountId);
@Query("Select * from Feed Order By name ASC")
public abstract LiveData<List<Feed>> getAllFeeds();
@Query("Select * from Feed Where id = :feedId")
public abstract Feed getFeedById(int feedId);
@Query("Select case When :feedUrl In (Select url from Feed Where account_id = :accountId) Then 1 else 0 end")
public abstract boolean feedExists(String feedUrl, int accountId);
@Query("Select case When :remoteId In (Select remoteId from Feed Where account_id = :accountId) Then 1 else 0 end")
public abstract boolean remoteFeedExists(String remoteId, int accountId);
@Query("Select count(*) from Feed Where account_id = :accountId")
public abstract Single<Integer> getFeedCount(int accountId);
@Query("Select * from Feed Where url = :feedUrl And account_id = :accountId")
public abstract Feed getFeedByUrl(String feedUrl, int accountId);
@Query("Select id from Feed Where remoteId = :remoteId And account_id = :accountId")
public abstract int getFeedIdByRemoteId(String remoteId, int accountId);
@Query("Select * from Feed Where folder_id = :folderId")
public abstract List<Feed> getFeedsByFolder(int folderId);
@Query("Select * from Feed Where account_id = :accountId And folder_id is null")
public abstract List<Feed> getFeedsWithoutFolder(int accountId);
@Query("Update Feed set etag = :etag, last_modified = :lastModified Where id = :feedId")
public abstract void updateHeaders(String etag, String lastModified, int feedId);
@Query("Update Feed set name = :feedName, url = :feedUrl, folder_id = :folderId Where id = :feedId")
public abstract void updateFeedFields(int feedId, String feedName, String feedUrl, Integer folderId);
@Query("Update Feed set name = :name, folder_id = :folderId Where remoteId = :remoteFeedId And account_id = :accountId")
public abstract void updateNameAndFolder(String remoteFeedId, int accountId, String name, Integer folderId);
@Query("Update Feed set text_color = :textColor, background_color = :bgColor Where id = :feedId")
public abstract void updateColors(int feedId, int textColor, int bgColor);
@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," +
"Feed.description as feed_description, Feed.icon_url as feed_icon_url, Feed.url as feed_url, Feed.folder_id as feed_folder_id" +
", Feed.siteUrl as feed_siteUrl, 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")
public abstract LiveData<List<FeedWithFolder>> getAllFeedsWithFolder(int accountId);
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
@Query("Select id, name, icon_url, notification_enabled, text_color, background_color, account_id From Feed Where account_id = :accountId")
public abstract LiveData<List<Feed>> getFeedsForNotifPermission(int accountId);
@Query("Select * From Feed Where id in (:ids)")
public abstract List<Feed> selectFromIdList(List<Long> ids);
@Query("Select remoteId From Feed Where account_id = :accountId")
public abstract List<String> getFeedRemoteIdsOfAccount(int accountId);
@Query("Delete from Feed Where remoteId in (:ids) And account_id = :accountId")
abstract void deleteByIds(List<String> ids, int accountId);
@Query("Select id From Folder Where remoteId = :remoteId And account_id = :accountId")
abstract int getRemoteFolderLocalId(String remoteId, int accountId);
@Query("Update Feed set notification_enabled = :enabled Where id = :feedId")
public abstract Completable updateFeedNotificationState(int feedId, boolean enabled);
@Query("Update Feed set notification_enabled = :enabled Where account_id = :accountId")
public abstract Completable updateAllFeedsNotificationState(int accountId, boolean enabled);
/**
* 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
public List<Long> feedsUpsert(List<Feed> feeds, Account account) {
List<String> accountFeedIds = getFeedRemoteIdsOfAccount(account.getId());
List<Feed> feedsToInsert = new ArrayList<>();
for (Feed feed : feeds) {
Integer folderId;
try {
int remoteFolderId = Integer.parseInt(feed.getRemoteFolderId());
folderId = remoteFolderId == 0 ? null : getRemoteFolderLocalId(feed.getRemoteFolderId(), account.getId());
} catch (Exception e) {
folderId = feed.getRemoteFolderId() == null ? null : getRemoteFolderLocalId(feed.getRemoteFolderId(), account.getId());
}
if (remoteFeedExists(feed.getRemoteId(), account.getId())) {
updateNameAndFolder(feed.getRemoteId(), account.getId(), feed.getName(), folderId);
accountFeedIds.remove(feed.getRemoteId());
} else {
feed.setFolderId(folderId);
feedsToInsert.add(feed);
}
}
if (!accountFeedIds.isEmpty()) {
deleteByIds(accountFeedIds, account.getId());
}
return insert(feedsToInsert);
}
}

View File

@ -0,0 +1,123 @@
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,73 +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;
import java.util.List;
@Dao
public abstract class FolderDao implements BaseDao<Folder> {
@Query("Select * from Folder Where account_id = :accountId Order By name ASC")
public abstract LiveData<List<Folder>> getAllFolders(int accountId);
@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")
public abstract LiveData<List<FolderWithFeedCount>> getFoldersWithFeedCount(int accountId);
@Query("Select * from Folder Where account_id = :accountId Order By name ASC")
public abstract List<Folder> getFolders(int accountId);
@Query("Update Folder set name = :name Where remoteId = :remoteFolderId And account_id = :accountId")
public abstract void updateName(String remoteFolderId, int accountId, String name);
@Query("Select case When :remoteId In (Select remoteId From Folder Where account_id = :accountId) Then 1 else 0 end")
abstract boolean remoteFolderExists(String remoteId, int accountId);
@Query("Select * from Folder Where id = :folderId")
public abstract Folder select(int folderId);
@Query("Select remoteId From Folder Where account_id = :accountId")
public abstract List<String> getFolderRemoteIdsOfAccount(int accountId);
@Query("Delete From Folder Where remoteId in (:ids) And account_id = :accountId")
abstract void deleteByIds(List<String> ids, int accountId);
@Query("Select * From Folder Where name = :name And account_id = :accountId")
public abstract Folder getFolderByName(String name, int accountId);
/**
* 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
public List<Long> foldersUpsert(List<Folder> folders, Account account) {
List<String> accountFolderIds = getFolderRemoteIdsOfAccount(account.getId());
List<Folder> foldersToInsert = new ArrayList<>();
for (Folder folder : folders) {
if (remoteFolderExists(folder.getRemoteId(), account.getId())) {
updateName(folder.getRemoteId(), account.getId(), folder.getName());
accountFolderIds.remove(folder.getRemoteId());
} else {
foldersToInsert.add(folder);
}
}
if (!accountFolderIds.isEmpty()) {
deleteByIds(accountFolderIds, account.getId());
}
return insert(foldersToInsert);
}
}

View File

@ -0,0 +1,68 @@
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,66 +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 java.util.List;
import io.reactivex.Completable;
@Dao
public interface ItemDao extends BaseDao<Item> {
@RawQuery(observedEntities = {Item.class, Folder.class, Feed.class, ItemState.class})
DataSource.Factory<Integer, ItemWithFeed> selectAll(SupportSQLiteQuery query);
@Query("Select * From Item Where id = :itemId")
Item select(int itemId);
@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")
boolean itemExists(String guid, int accountId);
@Query("Select case When :remoteId In (Select remoteId from Item) And :feedId In (Select feed_id From Item) Then 1 else 0 end")
boolean remoteItemExists(String remoteId, int feedId);
@Query("Select * From Item Where remoteId = :remoteId And feed_id = :feedId")
Item selectByRemoteId(String remoteId, int feedId);
@Query("Update Item Set read = :read Where id = :itemId")
Completable setReadState(int itemId, boolean read);
@Query("Update Item set starred = :starred Where id = :itemId")
Completable setStarState(int itemId, boolean starred);
@Query("Update Item set read = :readState Where feed_id In (Select id From Feed Where account_id = :accountId)")
Completable setAllItemsReadState(int readState, int accountId);
@Query("Update Item set read = :readState Where feed_id = :feedId")
Completable setAllFeedItemsReadState(int feedId, int readState);
@Query("Update Item set read_it_later = :readLater Where id = :itemId")
Completable setReadItLater(boolean readLater, int itemId);
@Query("Select count(*) From Item Where feed_id = :feedId And read = 0")
int getUnreadCount(int feedId);
@RawQuery(observedEntities = {Item.class, ItemState.class})
LiveData<ItemWithFeed> getItemById(SupportSQLiteQuery query);
@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")
List<StarItem> getStarChanges(List<String> remoteIds, int accountId);
@Query("Update Item set read = :read, starred = :starred Where remoteId = :remoteId")
void setReadAndStarState(String remoteId, boolean read, boolean starred);
}

View File

@ -0,0 +1,61 @@
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

@ -43,9 +43,9 @@ interface ItemStateChangeDao : BaseDao<ItemStateChange> {
fun upsertItemReadStateChange(item: Item, accountId: Int, useSeparateState: Boolean) = Completable.create {
if (itemStateChangeExists(item.id, accountId)) {
val oldItemReadState = if (useSeparateState)
getItemReadState(item.remoteId, accountId)
getItemReadState(item.remoteId!!, accountId)
else
getStandardItemReadState(item.remoteId, accountId)
getStandardItemReadState(item.remoteId!!, accountId)
val readChange = item.isRead != oldItemReadState
@ -69,9 +69,9 @@ interface ItemStateChangeDao : BaseDao<ItemStateChange> {
fun upsertItemStarStateChange(item: Item, accountId: Int, useSeparateState: Boolean) = Completable.create {
if (itemStateChangeExists(item.id, accountId)) {
val oldItemStarState = if (useSeparateState)
getItemStarState(item.remoteId, accountId)
getItemStarState(item.remoteId!!, accountId)
else
getStandardItemStarState(item.remoteId, accountId)
getStandardItemStarState(item.remoteId!!, accountId)
val starChange = item.isStarred != oldItemStarState

View File

@ -1,271 +0,0 @@
package com.readrops.db.entities;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.ColorInt;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
import com.readrops.db.entities.account.Account;
@Entity(foreignKeys = {@ForeignKey(entity = Folder.class, parentColumns = "id",
childColumns = "folder_id", onDelete = ForeignKey.SET_NULL),
@ForeignKey(entity = Account.class, parentColumns = "id", childColumns = "account_id",
onDelete = ForeignKey.CASCADE)})
public class Feed implements Parcelable {
@PrimaryKey(autoGenerate = true)
private int id;
private String name;
private String description;
private String url;
private String siteUrl;
private String lastUpdated;
@ColumnInfo(name = "text_color")
private @ColorInt
int textColor;
@ColumnInfo(name = "background_color")
private @ColorInt
int backgroundColor;
@ColumnInfo(name = "icon_url")
private String iconUrl;
private String etag;
@ColumnInfo(name = "last_modified")
private String lastModified;
@ColumnInfo(name = "folder_id", index = true)
private Integer folderId; // nullable foreign key so Integer instead of int
private String remoteId; // remote id can be string or int
@ColumnInfo(name = "account_id", index = true)
private int accountId;
@ColumnInfo(name = "notification_enabled", defaultValue = "1")
private boolean notificationEnabled;
@Ignore
private int unreadCount;
@Ignore
private String remoteFolderId;
public Feed() {
}
@Ignore
public Feed(String name, String description, String url) {
this.name = name;
this.description = description;
this.url = url;
}
protected Feed(Parcel in) {
id = in.readInt();
name = in.readString();
description = in.readString();
url = in.readString();
siteUrl = in.readString();
lastUpdated = in.readString();
textColor = in.readInt();
backgroundColor = in.readInt();
iconUrl = in.readString();
etag = in.readString();
lastModified = in.readString();
int parcelFolderId = in.readInt();
folderId = parcelFolderId == 0 ? null : parcelFolderId;
remoteId = in.readString();
notificationEnabled = in.readByte() != 0;
}
public static final Creator<Feed> CREATOR = new Creator<Feed>() {
@Override
public Feed createFromParcel(Parcel in) {
return new Feed(in);
}
@Override
public Feed[] newArray(int size) {
return new Feed[size];
}
};
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getSiteUrl() {
return siteUrl;
}
public void setSiteUrl(String siteUrl) {
this.siteUrl = siteUrl;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(String lastUpdated) {
this.lastUpdated = lastUpdated;
}
public @ColorInt
int getTextColor() {
return textColor;
}
public void setTextColor(@ColorInt int textColor) {
this.textColor = textColor;
}
public @ColorInt
int getBackgroundColor() {
return backgroundColor;
}
public void setBackgroundColor(@ColorInt int backgroundColor) {
this.backgroundColor = backgroundColor;
}
public String getIconUrl() {
return iconUrl;
}
public void setIconUrl(String iconUrl) {
this.iconUrl = iconUrl;
}
public String getEtag() {
return etag;
}
public void setEtag(String etag) {
this.etag = etag;
}
public String getLastModified() {
return lastModified;
}
public void setLastModified(String lastModified) {
this.lastModified = lastModified;
}
public Integer getFolderId() {
return folderId;
}
public void setFolderId(Integer folderId) {
this.folderId = folderId;
}
public int getUnreadCount() {
return unreadCount;
}
public void setUnreadCount(int unreadCount) {
this.unreadCount = unreadCount;
}
public String getRemoteId() {
return remoteId;
}
public void setRemoteId(String remoteId) {
this.remoteId = remoteId;
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int accountId) {
this.accountId = accountId;
}
public boolean isNotificationEnabled() {
return notificationEnabled;
}
public void setNotificationEnabled(boolean notificationEnabled) {
this.notificationEnabled = notificationEnabled;
}
public String getRemoteFolderId() {
return remoteFolderId;
}
public void setRemoteFolderId(String remoteFolderId) {
this.remoteFolderId = remoteFolderId;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
dest.writeString(description);
dest.writeString(url);
dest.writeString(siteUrl);
dest.writeString(lastUpdated);
dest.writeInt(textColor);
dest.writeInt(backgroundColor);
dest.writeString(iconUrl);
dest.writeString(etag);
dest.writeString(lastModified);
dest.writeInt(folderId == null ? 0 : folderId);
dest.writeString(remoteId);
dest.writeByte((byte) (notificationEnabled ? 1 : 0));
}
}

View File

@ -0,0 +1,31 @@
package com.readrops.db.entities
import android.os.Parcelable
import androidx.annotation.ColorInt
import androidx.room.*
import com.readrops.db.entities.account.Account
import kotlinx.parcelize.Parcelize
@Parcelize
@Entity(foreignKeys = [ForeignKey(entity = Folder::class, parentColumns = ["id"], childColumns = ["folder_id"],
onDelete = ForeignKey.SET_NULL), ForeignKey(entity = Account::class, parentColumns = ["id"],
childColumns = ["account_id"], onDelete = ForeignKey.CASCADE)])
data class Feed(
@PrimaryKey(autoGenerate = true) var id: Int = 0,
var name: String? = null,
var description: String? = null,
var url: String? = null,
var siteUrl: String? = null,
var lastUpdated: String? = null,
@ColumnInfo(name = "text_color") @ColorInt var textColor: Int = 0,
@ColumnInfo(name = "background_color") @ColorInt var backgroundColor: Int = 0,
@ColumnInfo(name = "icon_url") var iconUrl: String? = null,
var etag: String? = null,
@ColumnInfo(name = "last_modified") var lastModified: String? = null,
@ColumnInfo(name = "folder_id", index = true) var folderId: Int? = null,
var remoteId: String? = null,
@ColumnInfo(name = "account_id", index = true) var accountId: Int = 0,
@ColumnInfo(name = "notification_enabled", defaultValue = "1") var isNotificationEnabled: Boolean = false,
@Ignore var unreadCount: Int = 0,
@Ignore var remoteFolderId: String? = null,
) : Parcelable

View File

@ -1,123 +0,0 @@
package com.readrops.db.entities;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
import com.readrops.db.entities.account.Account;
import java.util.Objects;
@Entity(foreignKeys = @ForeignKey(entity = Account.class, parentColumns = "id",
childColumns = "account_id", onDelete = ForeignKey.CASCADE))
public class Folder implements Parcelable, Comparable<Folder> {
@PrimaryKey(autoGenerate = true)
private int id;
private String name;
private String remoteId;
@ColumnInfo(name = "account_id", index = true)
private int accountId;
public Folder() {
}
@Ignore
public Folder(String name) {
this.name = name;
}
protected Folder(Parcel in) {
id = in.readInt();
name = in.readString();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRemoteId() {
return remoteId;
}
public void setRemoteId(String remoteId) {
this.remoteId = remoteId;
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int accountId) {
this.accountId = accountId;
}
public static final Creator<Folder> CREATOR = new Creator<Folder>() {
@Override
public Folder createFromParcel(Parcel in) {
return new Folder(in);
}
@Override
public Folder[] newArray(int size) {
return new Folder[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
} else if (!(o instanceof Folder)) {
return false;
} else {
Folder folder = (Folder) o;
return id == folder.id && Objects.equals(name, folder.name) &&
Objects.equals(remoteId, folder.remoteId) &&
accountId == folder.accountId;
}
}
@Override
public int hashCode() {
return Objects.hash(id, name, remoteId, accountId);
}
@Override
public int compareTo(Folder o) {
return this.getName().compareTo(o.getName());
}
}

View File

@ -0,0 +1,22 @@
package com.readrops.db.entities
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import com.readrops.db.entities.account.Account
import kotlinx.parcelize.Parcelize
@Parcelize
@Entity(foreignKeys = [ForeignKey(entity = Account::class, parentColumns = ["id"],
childColumns = ["account_id"], onDelete = ForeignKey.CASCADE)])
data class Folder(
@PrimaryKey(autoGenerate = true) var id: Int = 0,
var name: String? = null,
var remoteId: String? = null,
@ColumnInfo(name = "account_id", index = true) var accountId: Int = 0,
) : Parcelable, Comparable<Folder> {
override fun compareTo(other: Folder): Int = this.name!!.compareTo(other.name!!)
}

View File

@ -1,211 +0,0 @@
package com.readrops.db.entities;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
import org.joda.time.LocalDateTime;
import static androidx.room.ForeignKey.CASCADE;
@Entity(foreignKeys = @ForeignKey(entity = Feed.class, parentColumns = "id", childColumns = "feed_id", onDelete = CASCADE))
public class Item implements Comparable<Item> {
@PrimaryKey(autoGenerate = true)
private int id;
private String title;
private String description;
@ColumnInfo(name = "clean_description")
private String cleanDescription;
private String link;
@ColumnInfo(name = "image_link")
private String imageLink;
private String author;
@ColumnInfo(name = "pub_date")
private LocalDateTime pubDate;
private String content;
@ColumnInfo(name = "feed_id", index = true)
private int feedId;
@ColumnInfo(index = true)
private String guid;
@ColumnInfo(name = "read_time")
private double readTime;
private boolean read;
private boolean starred;
@ColumnInfo(name = "read_it_later")
private boolean readItLater;
private String remoteId;
@Ignore
private String feedRemoteId;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getCleanDescription() {
return cleanDescription;
}
public void setCleanDescription(String cleanDescription) {
this.cleanDescription = cleanDescription;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getImageLink() {
return imageLink;
}
public void setImageLink(String imageLink) {
this.imageLink = imageLink;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public LocalDateTime getPubDate() {
return pubDate;
}
public void setPubDate(LocalDateTime pubDate) {
this.pubDate = pubDate;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getGuid() {
return guid;
}
public void setGuid(String guid) {
this.guid = guid;
}
public int getFeedId() {
return feedId;
}
public void setFeedId(int feedId) {
this.feedId = feedId;
}
public boolean hasImage() {
return getImageLink() != null;
}
public double getReadTime() {
return readTime;
}
public void setReadTime(double readTime) {
this.readTime = readTime;
}
public String getText() {
if (content != null)
return content;
else
return description;
}
public boolean isRead() {
return read;
}
public void setRead(boolean read) {
this.read = read;
}
public boolean isStarred() {
return starred;
}
public void setStarred(boolean starred) {
this.starred = starred;
}
public boolean isReadItLater() {
return readItLater;
}
public void setReadItLater(boolean readItLater) {
this.readItLater = readItLater;
}
public String getRemoteId() {
return remoteId;
}
public void setRemoteId(String remoteId) {
this.remoteId = remoteId;
}
public String getFeedRemoteId() {
return feedRemoteId;
}
public void setFeedRemoteId(String feedRemoteId) {
this.feedRemoteId = feedRemoteId;
}
@Override
public int compareTo(Item o) {
return this.pubDate.compareTo(o.getPubDate());
}
}

View File

@ -0,0 +1,38 @@
package com.readrops.db.entities
import android.os.Parcelable
import androidx.room.*
import kotlinx.parcelize.Parcelize
import org.joda.time.LocalDateTime
@Parcelize
@Entity(foreignKeys = [ForeignKey(entity = Feed::class, parentColumns = ["id"],
childColumns = ["feed_id"], onDelete = ForeignKey.CASCADE)])
data class Item(
@PrimaryKey(autoGenerate = true) var id: Int = 0,
var title: String? = null,
var description: String? = null,
@ColumnInfo(name = "clean_description") var cleanDescription: String? = null,
var link: String? = null,
@ColumnInfo(name = "image_link") var imageLink: String? = null,
var author: String? = null,
@ColumnInfo(name = "pub_date") var pubDate: LocalDateTime? = null,
var content: String? = null,
@ColumnInfo(name = "feed_id", index = true) var feedId: Int = 0,
@ColumnInfo(index = true) var guid: String? = null,
@ColumnInfo(name = "read_time") var readTime: Double = 0.0,
@ColumnInfo(name = "read") var isRead: Boolean = false,
@ColumnInfo(name = "starred") var isStarred: Boolean = false,
@ColumnInfo(name = "read_it_later") var isReadItLater: Boolean = false,
var remoteId: String? = null,
@Ignore var feedRemoteId: String? = null,
) : Parcelable, Comparable<Item> {
val text
get() = if (content != null) content else description
val hasImage
get() = imageLink != null
override fun compareTo(other: Item): Int = this.pubDate!!.compareTo(other.pubDate)
}

View File

@ -1,230 +0,0 @@
package com.readrops.db.entities.account;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.Nullable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
@Entity
public class Account implements Parcelable {
@PrimaryKey(autoGenerate = true)
private int id;
private String url;
@ColumnInfo(name = "account_name")
private String accountName;
@ColumnInfo(name = "displayed_name")
private String displayedName;
@ColumnInfo(name = "account_type")
private AccountType accountType;
@ColumnInfo(name = "last_modified")
private long lastModified;
@ColumnInfo(name = "current_account")
private boolean currentAccount;
private String token;
private String writeToken; // TODO : see if there is a better solution to store specific service account fields
@ColumnInfo(name = "notifications_enabled")
private boolean notificationsEnabled;
@Ignore
private String login;
@Ignore
private String password;
public Account() {
}
@Ignore
public Account(String url, String accountName, AccountType accountType) {
this.url = url;
this.accountName = accountName;
this.accountType = accountType;
}
protected Account(Parcel in) {
id = in.readInt();
url = in.readString();
accountName = in.readString();
accountType = AccountType.values()[in.readInt()];
displayedName = in.readString();
lastModified = in.readLong();
currentAccount = in.readByte() != 0;
login = in.readString();
password = in.readString();
token = in.readString();
writeToken = in.readString();
notificationsEnabled = in.readByte() != 0;
}
public static final Creator<Account> CREATOR = new Creator<Account>() {
@Override
public Account createFromParcel(Parcel in) {
return new Account(in);
}
@Override
public Account[] newArray(int size) {
return new Account[size];
}
};
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public String getDisplayedName() {
return displayedName;
}
public void setDisplayedName(String displayedName) {
this.displayedName = displayedName;
}
public AccountType getAccountType() {
return accountType;
}
public void setAccountType(AccountType accountType) {
this.accountType = accountType;
}
public long getLastModified() {
return lastModified;
}
public void setLastModified(long lastModified) {
this.lastModified = lastModified;
}
public boolean isCurrentAccount() {
return currentAccount;
}
public void setCurrentAccount(boolean currentAccount) {
this.currentAccount = currentAccount;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getLoginKey() {
return accountType.name() + "_login_" + id;
}
public String getPasswordKey() {
return accountType.name() + "_password_" + id;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getWriteToken() {
return writeToken;
}
public void setWriteToken(String writeToken) {
this.writeToken = writeToken;
}
public boolean isNotificationsEnabled() {
return notificationsEnabled;
}
public void setNotificationsEnabled(boolean notificationsEnabled) {
this.notificationsEnabled = notificationsEnabled;
}
public AccountConfig getConfig() {
return accountType.getAccountConfig();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(url);
dest.writeString(accountName);
dest.writeInt(accountType.ordinal());
dest.writeString(displayedName);
dest.writeLong(lastModified);
dest.writeByte((byte) (currentAccount ? 1 : 0));
dest.writeString(login);
dest.writeString(password);
dest.writeString(token);
dest.writeString(writeToken);
dest.writeByte((byte) (notificationsEnabled ? 1 : 0));
}
public boolean isLocal() {
return accountType == AccountType.LOCAL;
}
public boolean is(AccountType accountType) {
return this.accountType == accountType;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj == null)
return false;
else if (!(obj instanceof Account))
return false;
else
return this.id == ((Account) obj).getId();
}
}

View File

@ -0,0 +1,43 @@
package com.readrops.db.entities.account
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
import kotlinx.parcelize.Parcelize
@Parcelize
@Entity
data class Account(
@PrimaryKey(autoGenerate = true) var id: Int = 0,
var url: String? = null,
@ColumnInfo(name = "account_name") var accountName: String? = null,
@ColumnInfo(name = "displayed_name") var displayedName: String? = null,
@ColumnInfo(name = "account_type") var accountType: AccountType? = null,
@ColumnInfo(name = "last_modified") var lastModified: Long = 0,
@ColumnInfo(name = "current_account") var isCurrentAccount: Boolean = false,
var token: String? = null,
var writeToken: String? = null, // TODO : see if there is a better solution to store specific service account fields
@ColumnInfo(name = "notifications_enabled") var isNotificationsEnabled: Boolean = false,
@Ignore var login: String? = null,
@Ignore var password: String? = null,
) : Parcelable {
constructor(accountUrl: String?, accountName: String, accountType: AccountType):
this(url = accountUrl, accountName = accountName, accountType = accountType)
val config: AccountConfig
get() = accountType!!.accountConfig!!
val isLocal
get() = accountType == AccountType.LOCAL
fun `is`(accountType: AccountType) = this.accountType == accountType
val loginKey
get() = accountType!!.name + "_login_" + id
val passwordKey
get() = accountType!!.name + "_password_" + id
}

View File

@ -1,90 +0,0 @@
package com.readrops.db.entities.account;
public class AccountConfig {
public static final AccountConfig LOCAL = new AccountConfigBuilder()
.setFeedUrlEditable(true)
.setFolderCreation(true)
.setNoFolderCase(false)
.setUseSeparateState(false)
.build();
public static final AccountConfig NEXTCLOUD_NEWS = new AccountConfigBuilder()
.setFeedUrlEditable(false)
.setFolderCreation(true)
.setNoFolderCase(false)
.setUseSeparateState(false)
.build();
public static final AccountConfig FRESHRSS = new AccountConfigBuilder()
.setFeedUrlEditable(false)
.setFolderCreation(false)
.setNoFolderCase(true)
.setUseSeparateState(true)
.build();
private final boolean feedUrlEditable;
private final boolean folderCreation;
private final boolean noFolderCase;
/*
Let knows if it uses ItemState table to synchronize state
*/
private final boolean useSeparateState;
public boolean isFeedUrlEditable() {
return feedUrlEditable;
}
public boolean isFolderCreation() {
return folderCreation;
}
public boolean isNoFolderCase() {
return noFolderCase;
}
public boolean useSeparateState() {
return useSeparateState;
}
public AccountConfig(AccountConfigBuilder builder) {
this.feedUrlEditable = builder.feedUrlEditable;
this.folderCreation = builder.folderCreation;
this.noFolderCase = builder.noFolderCase;
this.useSeparateState = builder.useSeparateState;
}
public static class AccountConfigBuilder {
private boolean feedUrlEditable;
private boolean folderCreation;
private boolean noFolderCase;
private boolean useSeparateState;
public AccountConfigBuilder setFeedUrlEditable(boolean feedUrlEditable) {
this.feedUrlEditable = feedUrlEditable;
return this;
}
public AccountConfigBuilder setFolderCreation(boolean folderCreation) {
this.folderCreation = folderCreation;
return this;
}
public AccountConfigBuilder setNoFolderCase(boolean noFolderCase) {
this.noFolderCase = noFolderCase;
return this;
}
public AccountConfigBuilder setUseSeparateState(boolean useSeparateState) {
this.useSeparateState = useSeparateState;
return this;
}
public AccountConfig build() {
return new AccountConfig(this);
}
}
}

View File

@ -0,0 +1,39 @@
package com.readrops.db.entities.account
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class AccountConfig(
val isFeedUrlEditable: Boolean, // Enables or disables feed url modification in management screen
val isFolderCreation: Boolean, // Enables or disables folder creation in management screen
val isNoFolderCase: Boolean, // Add a "No folder" option when modifying a feed's folder
val useSeparateState: Boolean, // Let knows if it uses ItemState table to synchronize state
) : Parcelable {
companion object {
@JvmField
val LOCAL = AccountConfig(
isFeedUrlEditable = true,
isFolderCreation = true,
isNoFolderCase = false,
useSeparateState = false,
)
@JvmField
val NEXTCLOUD_NEWS = AccountConfig(
isFeedUrlEditable = false,
isFolderCreation = true,
isNoFolderCase = false,
useSeparateState = false,
)
@JvmField
val FRESHRSS = AccountConfig(
isFeedUrlEditable = false,
isFolderCreation = false,
isNoFolderCase = true,
useSeparateState = true,
)
}
}

View File

@ -1,65 +0,0 @@
package com.readrops.db.entities.account;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.DrawableRes;
import androidx.annotation.StringRes;
import com.readrops.db.R;
public enum AccountType implements Parcelable {
LOCAL(R.mipmap.ic_launcher, R.string.local_account, AccountConfig.LOCAL),
NEXTCLOUD_NEWS(R.drawable.ic_nextcloud_news, R.string.nextcloud_news, AccountConfig.NEXTCLOUD_NEWS),
FEEDLY(R.drawable.ic_feedly, R.string.feedly, null),
FRESHRSS(R.drawable.ic_freshrss, R.string.freshrss, AccountConfig.FRESHRSS);
private @DrawableRes
int iconRes;
private @StringRes
int name;
private AccountConfig accountConfig;
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(ordinal());
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<AccountType> CREATOR = new Creator<AccountType>() {
@Override
public AccountType createFromParcel(Parcel in) {
return AccountType.values()[in.readInt()];
}
@Override
public AccountType[] newArray(int size) {
return new AccountType[size];
}
};
public @DrawableRes
int getIconRes() {
return iconRes;
}
public @StringRes
int getName() {
return name;
}
public AccountConfig getAccountConfig() {
return accountConfig;
}
AccountType(@DrawableRes int iconRes, @StringRes int name, AccountConfig accountConfig) {
this.iconRes = iconRes;
this.name = name;
this.accountConfig = accountConfig;
}
}

View File

@ -0,0 +1,17 @@
package com.readrops.db.entities.account
import android.os.Parcelable
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import com.readrops.db.R
import kotlinx.parcelize.Parcelize
@Parcelize
enum class AccountType(@DrawableRes val iconRes: Int,
@StringRes val typeName: Int,
val accountConfig: AccountConfig?) : Parcelable {
LOCAL(R.mipmap.ic_launcher, R.string.local_account, AccountConfig.LOCAL),
NEXTCLOUD_NEWS(R.drawable.ic_nextcloud_news, R.string.nextcloud_news, AccountConfig.NEXTCLOUD_NEWS),
FEEDLY(R.drawable.ic_feedly, R.string.feedly, null),
FRESHRSS(R.drawable.ic_freshrss, R.string.freshrss, AccountConfig.FRESHRSS);
}

View File

@ -1,9 +1,9 @@
package com.readrops.db.filters;
public enum FilterType {
enum class FilterType {
FEED_FILTER,
FOLDER_FILER,
READ_IT_LATER_FILTER,
STARS_FILTER,
NO_FILTER
}
}

View File

@ -1,6 +0,0 @@
package com.readrops.db.filters;
public enum ListSortType {
NEWEST_TO_OLDEST,
OLDEST_TO_NEWEST
}

View File

@ -0,0 +1,6 @@
package com.readrops.db.filters
enum class ListSortType {
NEWEST_TO_OLDEST,
OLDEST_TO_NEWEST
}

View File

@ -1,68 +0,0 @@
package com.readrops.db.pojo;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.room.Embedded;
import com.readrops.db.entities.Feed;
import com.readrops.db.entities.Folder;
public class FeedWithFolder implements Parcelable {
@Embedded(prefix = "feed_")
private Feed feed;
@Embedded(prefix = "folder_")
private Folder folder;
public FeedWithFolder() {
}
protected FeedWithFolder(Parcel in) {
feed = in.readParcelable(Feed.class.getClassLoader());
folder = in.readParcelable(Folder.class.getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(feed, flags);
dest.writeParcelable(folder, flags);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<FeedWithFolder> CREATOR = new Creator<FeedWithFolder>() {
@Override
public FeedWithFolder createFromParcel(Parcel in) {
return new FeedWithFolder(in);
}
@Override
public FeedWithFolder[] newArray(int size) {
return new FeedWithFolder[size];
}
};
public Feed getFeed() {
return feed;
}
public void setFeed(Feed feed) {
this.feed = feed;
}
public Folder getFolder() {
return folder;
}
public void setFolder(Folder folder) {
this.folder = folder;
}
}

View File

@ -0,0 +1,13 @@
package com.readrops.db.pojo
import android.os.Parcelable
import androidx.room.Embedded
import com.readrops.db.entities.Feed
import com.readrops.db.entities.Folder
import kotlinx.parcelize.Parcelize
@Parcelize
data class FeedWithFolder(
@Embedded(prefix = "feed_") val feed: Feed,
@Embedded(prefix = "folder_") val folder: Folder,
) : Parcelable

View File

@ -1,34 +0,0 @@
package com.readrops.db.pojo;
import androidx.room.ColumnInfo;
import androidx.room.Embedded;
import com.readrops.db.entities.Folder;
public class FolderWithFeedCount {
@Embedded
private Folder folder;
@ColumnInfo(name = "feed_count")
private int feedCount;
public FolderWithFeedCount() {
}
public Folder getFolder() {
return folder;
}
public void setFolder(Folder folder) {
this.folder = folder;
}
public int getFeedCount() {
return feedCount;
}
public void setFeedCount(int feedCount) {
this.feedCount = feedCount;
}
}

View File

@ -0,0 +1,10 @@
package com.readrops.db.pojo
import androidx.room.ColumnInfo
import androidx.room.Embedded
import com.readrops.db.entities.Folder
data class FolderWithFeedCount(
@Embedded val folder: Folder,
@ColumnInfo(name = "feed_count") val feedCount: Int,
)

View File

@ -2,8 +2,10 @@ package com.readrops.db.pojo
import androidx.room.ColumnInfo
data class ItemReadStarState(val remoteId: String,
val read: Boolean,
val starred: Boolean,
@ColumnInfo(name = "read_change") val readChange: Boolean,
@ColumnInfo(name = "star_change") val starChange: Boolean)
data class ItemReadStarState(
val remoteId: String,
val read: Boolean,
val starred: Boolean,
@ColumnInfo(name = "read_change") val readChange: Boolean,
@ColumnInfo(name = "star_change") val starChange: Boolean,
)

View File

@ -1,99 +0,0 @@
package com.readrops.db.pojo;
import androidx.room.ColumnInfo;
import androidx.room.Embedded;
import androidx.annotation.ColorInt;
import com.readrops.db.entities.Folder;
import com.readrops.db.entities.Item;
public class ItemWithFeed {
@Embedded
private Item item;
@ColumnInfo(name = "name")
private String feedName;
@ColumnInfo(name = "feedId")
private int feedId;
@ColumnInfo(name = "text_color")
private @ColorInt int color;
@ColumnInfo(name = "background_color")
private @ColorInt int bgColor;
@ColumnInfo(name = "icon_url")
private String feedIconUrl;
@ColumnInfo(name = "siteUrl")
private String websiteUrl;
@Embedded(prefix = "folder_")
private Folder folder;
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public String getFeedName() {
return feedName;
}
public void setFeedName(String feedName) {
this.feedName = feedName;
}
public int getFeedId() {
return feedId;
}
public void setFeedId(int feedId) {
this.feedId = feedId;
}
public @ColorInt int getColor() {
return color;
}
public void setColor(@ColorInt int color) {
this.color = color;
}
public String getFeedIconUrl() {
return feedIconUrl;
}
public void setFeedIconUrl(String feedIconUrl) {
this.feedIconUrl = feedIconUrl;
}
public @ColorInt int getBgColor() {
return bgColor;
}
public void setBgColor(@ColorInt int bgColor) {
this.bgColor = bgColor;
}
public Folder getFolder() {
return folder;
}
public void setFolder(Folder folder) {
this.folder = folder;
}
public String getWebsiteUrl() {
return websiteUrl;
}
public void setWebsiteUrl(String websiteUrl) {
this.websiteUrl = websiteUrl;
}
}

View File

@ -0,0 +1,18 @@
package com.readrops.db.pojo
import androidx.annotation.ColorInt
import androidx.room.ColumnInfo
import androidx.room.Embedded
import com.readrops.db.entities.Folder
import com.readrops.db.entities.Item
data class ItemWithFeed(
@Embedded val item: Item,
@ColumnInfo(name = "name") val feedName: String,
@ColumnInfo(name = "feedId") val feedId: Int,
@ColumnInfo(name = "text_color") @ColorInt val color: Int,
@ColumnInfo(name = "background_color") @ColorInt val bgColor: Int,
@ColumnInfo(name = "icon_url") val feedIconUrl: String?,
@ColumnInfo(name = "siteUrl") val websiteUrl: String?,
@Embedded(prefix = "folder_") val folder: Folder,
)

View File

@ -3,5 +3,7 @@ package com.readrops.db.pojo
import androidx.room.ColumnInfo
data class StarItem(@ColumnInfo val feedRemoteId: String,
@ColumnInfo(name = "guid") val guidHash: String)
data class StarItem(
@ColumnInfo val feedRemoteId: String,
@ColumnInfo(name = "guid") val guidHash: String,
)