Rework Fever read/star state management
This commit is contained in:
parent
f7cd8ac998
commit
0c3c3d8ddb
@ -6,7 +6,6 @@ import com.readrops.api.services.fever.FeverDataSource
|
|||||||
import com.readrops.api.services.fever.FeverSyncData
|
import com.readrops.api.services.fever.FeverSyncData
|
||||||
import com.readrops.api.services.fever.ItemAction
|
import com.readrops.api.services.fever.ItemAction
|
||||||
import com.readrops.api.services.fever.adapters.FeverFeeds
|
import com.readrops.api.services.fever.adapters.FeverFeeds
|
||||||
import com.readrops.api.utils.ApiUtils
|
|
||||||
import com.readrops.api.utils.exceptions.LoginFailedException
|
import com.readrops.api.utils.exceptions.LoginFailedException
|
||||||
import com.readrops.app.util.Utils
|
import com.readrops.app.util.Utils
|
||||||
import com.readrops.db.Database
|
import com.readrops.db.Database
|
||||||
@ -14,8 +13,8 @@ import com.readrops.db.entities.Feed
|
|||||||
import com.readrops.db.entities.Folder
|
import com.readrops.db.entities.Folder
|
||||||
import com.readrops.db.entities.Item
|
import com.readrops.db.entities.Item
|
||||||
import com.readrops.db.entities.ItemState
|
import com.readrops.db.entities.ItemState
|
||||||
|
import com.readrops.db.entities.ItemStateChange
|
||||||
import com.readrops.db.entities.account.Account
|
import com.readrops.db.entities.account.Account
|
||||||
import okhttp3.MultipartBody
|
|
||||||
|
|
||||||
class FeverRepository(
|
class FeverRepository(
|
||||||
database: Database,
|
database: Database,
|
||||||
@ -89,20 +88,40 @@ class FeverRepository(
|
|||||||
override suspend fun deleteFolder(folder: Folder) {}
|
override suspend fun deleteFolder(folder: Folder) {}
|
||||||
|
|
||||||
override suspend fun setItemReadState(item: Item) {
|
override suspend fun setItemReadState(item: Item) {
|
||||||
val action =
|
val action = if (item.isRead) {
|
||||||
if (item.isRead) ItemAction.ReadStateAction.ReadAction else ItemAction.ReadStateAction.UnreadAction
|
ItemAction.ReadStateAction.ReadAction
|
||||||
|
} else {
|
||||||
|
ItemAction.ReadStateAction.UnreadAction
|
||||||
|
}
|
||||||
|
|
||||||
return setItemState(item, action)
|
return setItemState(item, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setItemStarState(item: Item) {
|
override suspend fun setItemStarState(item: Item) {
|
||||||
val action =
|
val action = if (item.isStarred) {
|
||||||
if (item.isStarred) ItemAction.StarStateAction.StarAction else ItemAction.StarStateAction.UnstarAction
|
ItemAction.StarStateAction.StarAction
|
||||||
|
} else {
|
||||||
|
ItemAction.StarStateAction.UnstarAction
|
||||||
|
}
|
||||||
|
|
||||||
return setItemState(item, action)
|
return setItemState(item, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun setItemState(item: Item, action: ItemAction) {
|
private suspend fun setItemState(item: Item, action: ItemAction) {
|
||||||
try {
|
try {
|
||||||
feverDataSource.setItemState(account.login!!, account.password!!, action.value, item.remoteId!!)
|
val currentState = database.itemStateDao().selectItemState(account.id, item.remoteId!!)
|
||||||
|
|
||||||
|
// if new state the same as the current one, do nothing
|
||||||
|
if (action is ItemAction.ReadStateAction) {
|
||||||
|
if (item.isRead == currentState.read) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (item.isStarred == currentState.starred) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val itemState = ItemState(
|
val itemState = ItemState(
|
||||||
read = item.isRead,
|
read = item.isRead,
|
||||||
starred = item.isStarred,
|
starred = item.isStarred,
|
||||||
@ -110,21 +129,32 @@ class FeverRepository(
|
|||||||
accountId = account.id,
|
accountId = account.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
val completable = if (action is ItemAction.ReadStateAction) {
|
// local state change
|
||||||
|
if (action is ItemAction.ReadStateAction) {
|
||||||
database.itemStateDao().upsertItemReadState(itemState)
|
database.itemStateDao().upsertItemReadState(itemState)
|
||||||
} else {
|
} else {
|
||||||
database.itemStateDao().upsertItemStarState(itemState)
|
database.itemStateDao().upsertItemStarState(itemState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remote state change
|
||||||
|
feverDataSource.setItemState(
|
||||||
|
account.login!!,
|
||||||
|
account.password!!,
|
||||||
|
action.value,
|
||||||
|
item.remoteId!!
|
||||||
|
)
|
||||||
|
|
||||||
|
// time to process item state changes which couldn't be sent previously (no network for example)
|
||||||
|
sendPreviousItemStateChanges()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
val completable = if (action is ItemAction.ReadStateAction) {
|
// error occurred, probably network error, so we keep this change until the next state change
|
||||||
|
if (action is ItemAction.ReadStateAction) {
|
||||||
super.setItemReadState(item)
|
super.setItemReadState(item)
|
||||||
} else {
|
} else {
|
||||||
super.setItemStarState(item)
|
super.setItemStarState(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.e(TAG, "setItemStarState: ${e.message}")
|
Log.e(TAG, "setItemStarState: ${e.message}")
|
||||||
error(e.message!!)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,12 +164,26 @@ class FeverRepository(
|
|||||||
|
|
||||||
for (stateChange in stateChanges) {
|
for (stateChange in stateChanges) {
|
||||||
val action = if (stateChange.readChange) {
|
val action = if (stateChange.readChange) {
|
||||||
if (stateChange.read) ItemAction.ReadStateAction.ReadAction else ItemAction.ReadStateAction.UnreadAction
|
when {
|
||||||
} else { // star change
|
stateChange.read -> ItemAction.ReadStateAction.ReadAction
|
||||||
if (stateChange.starred) ItemAction.StarStateAction.StarAction else ItemAction.StarStateAction.UnstarAction
|
else -> ItemAction.ReadStateAction.UnreadAction
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
when {
|
||||||
|
stateChange.starred -> ItemAction.StarStateAction.StarAction
|
||||||
|
else -> ItemAction.StarStateAction.UnstarAction
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
feverDataSource.setItemState(account.login!!, account.password!!, action.value, stateChange.remoteId)
|
feverDataSource.setItemState(
|
||||||
|
account.login!!,
|
||||||
|
account.password!!,
|
||||||
|
action.value,
|
||||||
|
stateChange.remoteId
|
||||||
|
)
|
||||||
|
|
||||||
|
database.itemStateChangeDao()
|
||||||
|
.delete(ItemStateChange(id = stateChange.id, accountId = account.id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +239,9 @@ class FeverRepository(
|
|||||||
|
|
||||||
database.itemStateDao().insert(unreadIds.map { unreadId ->
|
database.itemStateDao().insert(unreadIds.map { unreadId ->
|
||||||
val starred = starredIds.any { starredId -> starredId == unreadId }
|
val starred = starredIds.any { starredId -> starredId == unreadId }
|
||||||
if (starred) starredIds.remove(unreadId)
|
if (starred) {
|
||||||
|
starredIds.remove(unreadId)
|
||||||
|
}
|
||||||
|
|
||||||
ItemState(
|
ItemState(
|
||||||
id = 0,
|
id = 0,
|
||||||
@ -219,14 +265,6 @@ class FeverRepository(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFeverRequestBody(): MultipartBody {
|
|
||||||
val credentials = ApiUtils.md5hash("${account.login}:${account.password}")
|
|
||||||
return MultipartBody.Builder()
|
|
||||||
.setType(MultipartBody.FORM)
|
|
||||||
.addFormDataPart("api_key", credentials)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val TAG: String = FeverRepository::class.java.simpleName
|
val TAG: String = FeverRepository::class.java.simpleName
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,11 @@ interface ItemStateChangeDao: BaseDao<ItemStateChange> {
|
|||||||
@Query("Delete From ItemStateChange Where account_id = :accountId")
|
@Query("Delete From ItemStateChange Where account_id = :accountId")
|
||||||
suspend fun resetStateChanges(accountId: Int)
|
suspend fun resetStateChanges(accountId: Int)
|
||||||
|
|
||||||
@Query("Select case When ItemState.remote_id is NULL Or ItemState.read = 1 Then 1 else 0 End read, " +
|
@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," +
|
case When ItemState.remote_id is NULL Or ItemState.starred = 1 Then 1 else 0 End starred,
|
||||||
"ItemStateChange.read_change, ItemStateChange.star_change, Item.remote_id " +
|
ItemStateChange.id as id, ItemStateChange.read_change, ItemStateChange.star_change, Item.remote_id From ItemStateChange
|
||||||
"From ItemStateChange Inner Join Item On ItemStateChange.id = Item.id " +
|
Inner Join Item On ItemStateChange.id = Item.id Left Join ItemState On ItemState.remote_id = Item.remote_id
|
||||||
"Left Join ItemState On ItemState.remote_id = Item.remote_id Where ItemStateChange.account_id = :accountId")
|
Where ItemStateChange.account_id = :accountId""")
|
||||||
suspend fun selectItemStateChanges(accountId: Int): List<ItemReadStarState>
|
suspend fun selectItemStateChanges(accountId: Int): List<ItemReadStarState>
|
||||||
|
|
||||||
@Query("Select Case When :itemId In (Select id From ItemStateChange Where read_change = 1) Then 1 Else 0 End")
|
@Query("Select Case When :itemId In (Select id From ItemStateChange Where read_change = 1) Then 1 Else 0 End")
|
||||||
|
@ -7,6 +7,9 @@ import com.readrops.db.entities.ItemState
|
|||||||
@Dao
|
@Dao
|
||||||
interface ItemStateDao : BaseDao<ItemState> {
|
interface ItemStateDao : BaseDao<ItemState> {
|
||||||
|
|
||||||
|
@Query("Select * From ItemState Where account_id = :accountId And remote_id = :remoteId")
|
||||||
|
suspend fun selectItemState(accountId: Int, remoteId: String): ItemState
|
||||||
|
|
||||||
@Query("Delete From ItemState Where account_id = :accountId")
|
@Query("Delete From ItemState Where account_id = :accountId")
|
||||||
suspend fun deleteItemStates(accountId: Int)
|
suspend fun deleteItemStates(accountId: Int)
|
||||||
|
|
||||||
|
@ -8,10 +8,14 @@ import androidx.room.PrimaryKey
|
|||||||
import com.readrops.db.entities.account.Account
|
import com.readrops.db.entities.account.Account
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
foreignKeys = [ForeignKey(
|
foreignKeys = [
|
||||||
entity = Account::class, parentColumns = ["id"],
|
ForeignKey(
|
||||||
childColumns = ["account_id"], onDelete = ForeignKey.CASCADE
|
entity = Account::class,
|
||||||
)]
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["account_id"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
data class ItemStateChange(
|
data class ItemStateChange(
|
||||||
@PrimaryKey val id: Int = 0,
|
@PrimaryKey val id: Int = 0,
|
||||||
@ -21,10 +25,14 @@ data class ItemStateChange(
|
|||||||
)
|
)
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
foreignKeys = [ForeignKey(
|
foreignKeys = [
|
||||||
entity = Account::class, parentColumns = ["id"],
|
ForeignKey(
|
||||||
childColumns = ["account_id"], onDelete = ForeignKey.CASCADE
|
entity = Account::class,
|
||||||
)],
|
parentColumns = ["id"],
|
||||||
|
childColumns = ["account_id"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
],
|
||||||
indices = [Index( // TODO check potential performance regression at insertion when synchronizing
|
indices = [Index( // TODO check potential performance regression at insertion when synchronizing
|
||||||
value = ["remote_id", "account_id"],
|
value = ["remote_id", "account_id"],
|
||||||
unique = true
|
unique = true
|
||||||
|
@ -3,6 +3,7 @@ package com.readrops.db.pojo
|
|||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
|
|
||||||
data class ItemReadStarState(
|
data class ItemReadStarState(
|
||||||
|
val id: Int,
|
||||||
@ColumnInfo(name = "remote_id") val remoteId: String,
|
@ColumnInfo(name = "remote_id") val remoteId: String,
|
||||||
val read: Boolean,
|
val read: Boolean,
|
||||||
val starred: Boolean,
|
val starred: Boolean,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user