More debugging. Source adding is still broken. Needs DB integration.
This commit is contained in:
parent
6e38e8753c
commit
4c69e72499
@ -133,7 +133,7 @@ class AddSourceActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
var items = api!!.spouts()
|
||||
if (items != null) {
|
||||
|
||||
@ -192,7 +192,7 @@ class AddSourceActivity : AppCompatActivity() {
|
||||
Toast.makeText(this, R.string.form_not_complete, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
else -> {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val response: SelfossModel.SuccessResponse? = api.createSourceForVersion(
|
||||
title,
|
||||
url,
|
||||
|
@ -235,7 +235,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
lastFetchDone = false
|
||||
handleDrawerItems()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
service.refreshFocusedItems(itemsNumber, applicationContext.isNetworkAvailable())
|
||||
getElementsAccordingToTab()
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
}
|
||||
@ -276,7 +275,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
|
||||
reloadBadgeContent()
|
||||
|
||||
val tagHashes = i.tags.split(",").map { it.longHash() }
|
||||
val tagHashes = i.tags.map { it.longHash() }
|
||||
tagsBadge = tagsBadge.map {
|
||||
if (tagHashes.contains(it.key)) {
|
||||
(it.key to (it.value - 1))
|
||||
@ -868,9 +867,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
override fun onTabUnselected(position: Int) = Unit
|
||||
|
||||
override fun onTabReselected(position: Int) {
|
||||
val layoutManager = binding.recyclerView.adapter
|
||||
|
||||
when (layoutManager) {
|
||||
when (val layoutManager = binding.recyclerView.adapter) {
|
||||
is StaggeredGridLayoutManager ->
|
||||
if (layoutManager.findFirstCompletelyVisibleItemPositions(null)[0] == 0) {
|
||||
getElementsAccordingToTab()
|
||||
@ -902,10 +900,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
|
||||
private fun fetchOnEmptyList() {
|
||||
binding.recyclerView.doOnNextLayout {
|
||||
// Todo:
|
||||
// if (SharedItems.focusedItems.size - 1 == getLastVisibleItem()) {
|
||||
// getElementsAccordingToTab(true)
|
||||
// }
|
||||
// TODO: do if last element (or is empty ?)
|
||||
getElementsAccordingToTab(true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -927,8 +923,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
}
|
||||
|
||||
private fun getLastVisibleItem() : Int {
|
||||
val manager = binding.recyclerView.layoutManager
|
||||
return when (manager) {
|
||||
return when (val manager = binding.recyclerView.layoutManager) {
|
||||
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(
|
||||
null
|
||||
).last()
|
||||
@ -945,8 +940,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
}
|
||||
|
||||
private fun getElementsAccordingToTab(
|
||||
appendResults: Boolean = false,
|
||||
offsetOverride: Int? = null
|
||||
appendResults: Boolean = false
|
||||
) {
|
||||
fun doGetAccordingToTab() {
|
||||
when (elementsShown) {
|
||||
@ -957,12 +951,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
}
|
||||
}
|
||||
|
||||
// Todo:
|
||||
// offset = if (appendResults) {
|
||||
// SharedItems.focusedItems.size - 1
|
||||
// } else {
|
||||
// 0
|
||||
// }
|
||||
offset = if (appendResults && items.size > 0) {
|
||||
items.size - 1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
firstVisible = if (appendResults) firstVisible else 0
|
||||
|
||||
doGetAccordingToTab()
|
||||
@ -970,41 +963,42 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
|
||||
private fun getUnRead(appendResults: Boolean = false) {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
// Todo:
|
||||
// if (appendResults || !SharedItems.fetchedUnread) {
|
||||
// binding.swipeRefreshLayout.isRefreshing = true
|
||||
// service.getUnreadItems(itemsNumber, offset, applicationContext.isNetworkAvailable())
|
||||
// binding.swipeRefreshLayout.isRefreshing = false
|
||||
// }
|
||||
// Todo: SharedItems.getUnRead()
|
||||
// Todo: items = SharedItems.focusedItems
|
||||
binding.swipeRefreshLayout.isRefreshing = true
|
||||
val apiItems = service.getUnreadItems(itemsNumber, offset, applicationContext.isNetworkAvailable())
|
||||
if (appendResults) {
|
||||
apiItems?.let { items.addAll(it) }
|
||||
} else {
|
||||
items = apiItems.orEmpty() as ArrayList<SelfossModel.Item>
|
||||
}
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
handleListResult()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRead(appendResults: Boolean = false) {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
// Todo:
|
||||
// if (appendResults || !SharedItems.fetchedAll) {
|
||||
// binding.swipeRefreshLayout.isRefreshing = true
|
||||
// service.getReadItems(itemsNumber, offset, applicationContext.isNetworkAvailable())
|
||||
// binding.swipeRefreshLayout.isRefreshing = false
|
||||
// }
|
||||
// SharedItems.getAll()
|
||||
// items = SharedItems.focusedItems
|
||||
binding.swipeRefreshLayout.isRefreshing = true
|
||||
val apiItems = service.getReadItems(itemsNumber, offset, applicationContext.isNetworkAvailable())
|
||||
if (appendResults) {
|
||||
apiItems?.let { items.addAll(it) }
|
||||
} else {
|
||||
items = apiItems.orEmpty() as ArrayList<SelfossModel.Item>
|
||||
}
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
handleListResult()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getStarred(appendResults: Boolean = false) {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
if (appendResults || !searchService.fetchedStarred) {
|
||||
binding.swipeRefreshLayout.isRefreshing = true
|
||||
service.getStarredItems(itemsNumber, offset, applicationContext.isNetworkAvailable())
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
binding.swipeRefreshLayout.isRefreshing = true
|
||||
val apiItems = service.getStarredItems(itemsNumber, offset, applicationContext.isNetworkAvailable())
|
||||
if (appendResults) {
|
||||
apiItems?.let { items.addAll(it) }
|
||||
} else {
|
||||
items = apiItems.orEmpty() as ArrayList<SelfossModel.Item>
|
||||
}
|
||||
// Todo: SharedItems.getStarred()
|
||||
// Todo: items = SharedItems.focusedItems
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
handleListResult()
|
||||
}
|
||||
}
|
||||
@ -1069,7 +1063,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
}
|
||||
binding.recyclerView.adapter = recyclerAdapter
|
||||
} else {
|
||||
(recyclerAdapter as ItemsAdapter<*>).updateAllItems()
|
||||
(recyclerAdapter as ItemsAdapter<*>).updateAllItems(items)
|
||||
}
|
||||
|
||||
reloadBadges()
|
||||
@ -1186,7 +1180,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
|
||||
if (this@HomeActivity.isNetworkAvailable(null, offlineShortcut)) {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val success = service.readAll(applicationContext.isNetworkAvailable())
|
||||
val success = service.readAll(items.map { it.id.toString() }, applicationContext.isNetworkAvailable())
|
||||
if (success) {
|
||||
Toast.makeText(
|
||||
this@HomeActivity,
|
||||
|
@ -130,7 +130,8 @@ class ReaderActivity : AppCompatActivity() {
|
||||
private fun readItem(item: SelfossModel.Item) {
|
||||
if (markOnScroll) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// Todo: SharedItems.readItem(applicationContext, api, db, item)
|
||||
api.markAsRead(item.id.toString())
|
||||
// TODO: update item in DB
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -177,7 +178,7 @@ class ReaderActivity : AppCompatActivity() {
|
||||
inflater.inflate(R.menu.reader_menu, menu)
|
||||
toolbarMenu = menu
|
||||
|
||||
if (allItems.isNotEmpty() && allItems[currentItem].starred == 1) {
|
||||
if (allItems.isNotEmpty() && allItems[currentItem].starred) {
|
||||
canRemoveFromFavorite()
|
||||
} else {
|
||||
canFavorite()
|
||||
@ -194,7 +195,7 @@ class ReaderActivity : AppCompatActivity() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
super.onPageSelected(position)
|
||||
|
||||
if (allItems[position].starred == 1) {
|
||||
if (allItems[position].starred) {
|
||||
canRemoveFromFavorite()
|
||||
} else {
|
||||
canFavorite()
|
||||
@ -225,26 +226,16 @@ class ReaderActivity : AppCompatActivity() {
|
||||
return true
|
||||
}
|
||||
R.id.star -> {
|
||||
if (allItems[binding.pager.currentItem].starred == 1) {
|
||||
if (allItems[binding.pager.currentItem].starred) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// Todo:
|
||||
// SharedItems.unstarItem(
|
||||
// this@ReaderActivity,
|
||||
// api,
|
||||
// db,
|
||||
// allItems[binding.pager.currentItem]
|
||||
// )
|
||||
api.unstarr(allItems[binding.pager.currentItem].id.toString())
|
||||
// TODO: update in DB
|
||||
}
|
||||
afterUnsave()
|
||||
} else {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// Todo:
|
||||
// SharedItems.starItem(
|
||||
// this@ReaderActivity,
|
||||
// api,
|
||||
// db,
|
||||
// allItems[binding.pager.currentItem]
|
||||
// )
|
||||
api.starr(allItems[binding.pager.currentItem].id.toString())
|
||||
// TODO: update in DB
|
||||
}
|
||||
afterSave()
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ class SourcesActivity : AppCompatActivity() {
|
||||
binding.recyclerView.layoutManager = mLayoutManager
|
||||
|
||||
if (this@SourcesActivity.isNetworkAvailable(binding.recyclerView)) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val response = api.sources()
|
||||
if (response != null) {
|
||||
items = response
|
||||
|
@ -59,7 +59,7 @@ class ItemCardAdapter(
|
||||
with(holder) {
|
||||
val itm = items[position]
|
||||
|
||||
binding.favButton.isSelected = itm.starred == 1
|
||||
binding.favButton.isSelected = itm.starred
|
||||
binding.title.text = itm.getTitleDecoded()
|
||||
|
||||
binding.title.setOnTouchListener(LinkOnTouchListener())
|
||||
@ -112,17 +112,19 @@ class ItemCardAdapter(
|
||||
binding.favButton.setOnClickListener {
|
||||
val item = items[bindingAdapterPosition]
|
||||
if (c.isNetworkAvailable()) {
|
||||
if (item.starred == 1) {
|
||||
if (item.starred) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// Todo: SharedItems.unstarItem(c, api, db, item)
|
||||
api.unstarr(item.id.toString())
|
||||
// TODO: save to db
|
||||
}
|
||||
item.starred = 0
|
||||
item.starred = false
|
||||
binding.favButton.isSelected = false
|
||||
} else {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// Todo: SharedItems.starItem(c, api, db, item)
|
||||
api.starr(item.id.toString())
|
||||
// TODO: save to db
|
||||
}
|
||||
item.starred = 1
|
||||
item.starred = true
|
||||
binding.favButton.isSelected = true
|
||||
}
|
||||
}
|
||||
|
@ -29,10 +29,10 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
abstract val searchService: SearchService
|
||||
abstract val updateItems: (ArrayList<SelfossModel.Item>) -> Unit
|
||||
|
||||
fun updateAllItems() {
|
||||
items = ArrayList() // TODO: SharedItems.focusedItems
|
||||
fun updateAllItems(items: ArrayList<SelfossModel.Item>) {
|
||||
this.items = items
|
||||
notifyDataSetChanged()
|
||||
updateItems(items)
|
||||
updateItems(this.items)
|
||||
}
|
||||
|
||||
private fun unmarkSnackbar(i: SelfossModel.Item, position: Int) {
|
||||
@ -44,14 +44,8 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
)
|
||||
.setAction(R.string.undo_string) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// Todo: SharedItems.unreadItem(app, api, db, i)
|
||||
unreadItemAtIndex(position, false)
|
||||
}
|
||||
// Todo:
|
||||
// if (SharedItems.displayedItems == "unread") {
|
||||
// addItemAtIndex(i, position)
|
||||
// } else {
|
||||
// notifyItemChanged(position)
|
||||
// }
|
||||
}
|
||||
|
||||
val view = s.view
|
||||
@ -68,17 +62,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
Snackbar.LENGTH_LONG
|
||||
)
|
||||
.setAction(R.string.undo_string) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// Todo: SharedItems.readItem(app, api, db, items[position])
|
||||
}
|
||||
// Todo: items = SharedItems.focusedItems
|
||||
// Todo:
|
||||
// if (SharedItems.displayedItems == "unread") {
|
||||
// notifyItemRemoved(position)
|
||||
// updateItems(items)
|
||||
// } else {
|
||||
// notifyItemChanged(position)
|
||||
// }
|
||||
readItemAtIndex(position)
|
||||
}
|
||||
|
||||
val view = s.view
|
||||
@ -88,18 +72,19 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
}
|
||||
|
||||
fun handleItemAtIndex(position: Int) {
|
||||
// Todo:
|
||||
// if (SharedItems.unreadItemStatusAtIndex(position)) {
|
||||
// readItemAtIndex(position)
|
||||
// } else {
|
||||
// unreadItemAtIndex(position)
|
||||
// }
|
||||
if (items[position].unread) {
|
||||
readItemAtIndex(position)
|
||||
} else {
|
||||
unreadItemAtIndex(position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun readItemAtIndex(position: Int) {
|
||||
private fun readItemAtIndex(position: Int, showSnackbar: Boolean = true) {
|
||||
val i = items[position]
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// Todo: SharedItems.readItem(app, api, db, i)
|
||||
api.markAsRead(i.id.toString())
|
||||
// TODO: update db
|
||||
|
||||
}
|
||||
// Todo:
|
||||
// if (SharedItems.displayedItems == "unread") {
|
||||
@ -109,15 +94,22 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
// } else {
|
||||
// notifyItemChanged(position)
|
||||
// }
|
||||
unmarkSnackbar(i, position)
|
||||
if (showSnackbar) {
|
||||
unmarkSnackbar(i, position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun unreadItemAtIndex(position: Int) {
|
||||
private fun unreadItemAtIndex(position: Int, showSnackbar: Boolean = true) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
api.unmarkAsRead(items[position].id.toString())
|
||||
// Todo: SharedItems.unreadItem(app, api, db, items[position])
|
||||
// TODO: update db
|
||||
|
||||
}
|
||||
notifyItemChanged(position)
|
||||
markSnackbar(position)
|
||||
if (showSnackbar) {
|
||||
markSnackbar(position)
|
||||
}
|
||||
}
|
||||
|
||||
fun addItemAtIndex(item: SelfossModel.Item, position: Int) {
|
||||
|
@ -28,7 +28,6 @@ import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAvailabl
|
||||
|
||||
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
|
||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
|
||||
import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
|
||||
import bou.amine.apps.readerforselfossv2.service.SearchService
|
||||
import bou.amine.apps.readerforselfossv2.service.SelfossService
|
||||
import bou.amine.apps.readerforselfossv2.utils.DateUtils
|
||||
@ -109,21 +108,33 @@ override fun doWork(): Result {
|
||||
}
|
||||
}
|
||||
|
||||
service.getAndStoreAllItems(context.isNetworkAvailable())
|
||||
// TODO: SharedItems.updateDatabase(db, dateUtils)
|
||||
storeItems(notifyNewItems, notificationManager)
|
||||
if (context.isNetworkAvailable()) {
|
||||
launch {
|
||||
try {
|
||||
val newItems = service.allNewItems()
|
||||
handleNewItemsNotification(newItems, notifyNewItems, notificationManager)
|
||||
val readItems = service.allReadItems()
|
||||
val starredItems = service.allStarredItems()
|
||||
// TODO: save all to DB
|
||||
} catch (e: Throwable) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
private fun storeItems(notifyNewItems: Boolean, notificationManager: NotificationManager) {
|
||||
private fun handleNewItemsNotification(
|
||||
newItems: List<SelfossModel.Item>?,
|
||||
notifyNewItems: Boolean,
|
||||
notificationManager: NotificationManager
|
||||
) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val apiItems = emptyList<SelfossModel.Item>() // TODO: SharedItems.items
|
||||
val apiItems = newItems.orEmpty()
|
||||
|
||||
|
||||
val newSize = apiItems.filter { it.unread == 1 }.size
|
||||
val newSize = apiItems.filter { it.unread }.size
|
||||
if (notifyNewItems && newSize > 0) {
|
||||
|
||||
val intent = Intent(context, MainActivity::class.java).apply {
|
||||
|
@ -111,7 +111,9 @@ class ArticleFragment : Fragment() {
|
||||
|
||||
service = SelfossService(SelfossApi(apiDetailsService), dbService, SearchService(DateUtils(apiDetailsService)))
|
||||
|
||||
item = requireArguments().getParcelable(ARG_ITEMS)!!
|
||||
val pi: ParecelableItem = requireArguments().getParcelable(ARG_ITEMS)!!
|
||||
|
||||
item = pi.toModel()
|
||||
|
||||
db = Room.databaseBuilder(
|
||||
requireContext(),
|
||||
@ -187,17 +189,12 @@ class ArticleFragment : Fragment() {
|
||||
R.id.share_action -> requireActivity().shareLink(url, contentTitle)
|
||||
R.id.open_action -> requireActivity().openInBrowserAsNewTask(this@ArticleFragment.item)
|
||||
R.id.unread_action -> if (context != null) {
|
||||
if (this@ArticleFragment.item.unread == 1) {
|
||||
if (this@ArticleFragment.item.unread) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// TODO:
|
||||
// dbService.readItem(
|
||||
// context!!,
|
||||
// api,
|
||||
// db,
|
||||
// this@ArticleFragment.item
|
||||
// )
|
||||
api.markAsRead(this@ArticleFragment.item.id.toString())
|
||||
// TODO: Update in DB
|
||||
}
|
||||
this@ArticleFragment.item.unread = 0
|
||||
this@ArticleFragment.item.unread = false
|
||||
Toast.makeText(
|
||||
context,
|
||||
R.string.marked_as_read,
|
||||
@ -205,15 +202,10 @@ class ArticleFragment : Fragment() {
|
||||
).show()
|
||||
} else {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
// TODO
|
||||
// .unreadItem(
|
||||
// context!!,
|
||||
// api,
|
||||
// db,
|
||||
// this@ArticleFragment.item
|
||||
// )
|
||||
api.unmarkAsRead(this@ArticleFragment.item.id.toString())
|
||||
// TODO: Update in DB
|
||||
}
|
||||
this@ArticleFragment.item.unread = 1
|
||||
this@ArticleFragment.item.unread = true
|
||||
Toast.makeText(
|
||||
context,
|
||||
R.string.marked_as_unread,
|
||||
|
@ -1,7 +1,9 @@
|
||||
package bou.amine.apps.readerforselfossv2.android.model
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.RequiresApi
|
||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@ -17,15 +19,29 @@ fun SelfossModel.Item.toParcelable() : ParecelableItem =
|
||||
this.icon,
|
||||
this.link,
|
||||
this.sourcetitle,
|
||||
this.tags
|
||||
this.tags.joinToString(",")
|
||||
)
|
||||
fun ParecelableItem.toModel() : SelfossModel.Item =
|
||||
SelfossModel.Item(
|
||||
this.id,
|
||||
this.datetime,
|
||||
this.title,
|
||||
this.content,
|
||||
this.unread,
|
||||
this.starred,
|
||||
this.thumbnail,
|
||||
this.icon,
|
||||
this.link,
|
||||
this.sourcetitle,
|
||||
this.tags.split(",")
|
||||
)
|
||||
data class ParecelableItem(
|
||||
@SerializedName("id") val id: String,
|
||||
@SerializedName("id") val id: Int,
|
||||
@SerializedName("datetime") val datetime: String,
|
||||
@SerializedName("title") val title: String,
|
||||
@SerializedName("content") val content: String,
|
||||
@SerializedName("unread") var unread: Int,
|
||||
@SerializedName("starred") var starred: Int,
|
||||
@SerializedName("unread") var unread: Boolean,
|
||||
@SerializedName("starred") var starred: Boolean,
|
||||
@SerializedName("thumbnail") val thumbnail: String?,
|
||||
@SerializedName("icon") val icon: String?,
|
||||
@SerializedName("link") val link: String,
|
||||
@ -42,12 +58,12 @@ data class ParecelableItem(
|
||||
}
|
||||
|
||||
constructor(source: Parcel) : this(
|
||||
id = source.readString().orEmpty(),
|
||||
id = source.readInt(),
|
||||
datetime = source.readString().orEmpty(),
|
||||
title = source.readString().orEmpty(),
|
||||
content = source.readString().orEmpty(),
|
||||
unread = source.readInt(),
|
||||
starred = source.readInt(),
|
||||
unread = source.readByte().toInt() != 0,
|
||||
starred = source.readByte().toInt() != 0,
|
||||
thumbnail = source.readString(),
|
||||
icon = source.readString(),
|
||||
link = source.readString().orEmpty(),
|
||||
@ -58,12 +74,12 @@ data class ParecelableItem(
|
||||
override fun describeContents() = 0
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
dest.writeString(id)
|
||||
dest.writeInt(id)
|
||||
dest.writeString(datetime)
|
||||
dest.writeString(title)
|
||||
dest.writeString(content)
|
||||
dest.writeInt(unread)
|
||||
dest.writeInt(starred)
|
||||
dest.writeByte(if (unread) 1 else 0)
|
||||
dest.writeByte(if (starred) 1 else 0)
|
||||
dest.writeString(thumbnail)
|
||||
dest.writeString(icon)
|
||||
dest.writeString(link)
|
||||
|
@ -23,11 +23,11 @@ class AndroidDeviceDatabaseService(db: AndroidDeviceDatabase, searchService: Sea
|
||||
}
|
||||
|
||||
override fun appendNewItems(newItems: List<SelfossModel.Item>) {
|
||||
var tmpItems = items
|
||||
if (tmpItems != newItems) {
|
||||
tmpItems = tmpItems.filter { item -> newItems.find { it.id == item.id } == null } as ArrayList<SelfossModel.Item>
|
||||
tmpItems.addAll(newItems)
|
||||
items = tmpItems
|
||||
var oldItems = items
|
||||
if (oldItems != newItems) {
|
||||
oldItems = oldItems.filter { item -> newItems.find { it.id == item.id } == null } as ArrayList<SelfossModel.Item>
|
||||
oldItems.addAll(newItems)
|
||||
items = oldItems
|
||||
|
||||
sortItems()
|
||||
getFocusedItems()
|
||||
|
@ -8,40 +8,41 @@ import bou.amine.apps.readerforselfossv2.service.ApiDetailsService
|
||||
|
||||
class AndroidApiDetailsService(c: Context) : ApiDetailsService {
|
||||
val settings: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(c)
|
||||
private var apiVersion: Int = -1
|
||||
private var baseUrl: String = ""
|
||||
private var userName: String = ""
|
||||
private var password: String = ""
|
||||
private var _apiVersion: Int = -1
|
||||
private var _baseUrl: String = ""
|
||||
private var _userName: String = ""
|
||||
private var _password: String = ""
|
||||
override fun logApiCalls(message: String) {
|
||||
Log.d("LogApiCalls", message)
|
||||
}
|
||||
|
||||
|
||||
override fun getApiVersion(): Int {
|
||||
if (apiVersion != -1) {
|
||||
apiVersion = settings.getInt("apiVersion", -1)!!
|
||||
if (_apiVersion == -1) {
|
||||
_apiVersion = settings.getInt("apiVersionMajor", -1)!!
|
||||
return settings.getInt("apiVersionMajor", -1)!!
|
||||
}
|
||||
return apiVersion
|
||||
return _apiVersion
|
||||
}
|
||||
|
||||
override fun getBaseUrl(): String {
|
||||
if (baseUrl.isEmpty()) {
|
||||
baseUrl = settings.getString("url", "")!!
|
||||
if (_baseUrl.isEmpty()) {
|
||||
_baseUrl = settings.getString("url", "")!!
|
||||
}
|
||||
return baseUrl
|
||||
return _baseUrl
|
||||
}
|
||||
|
||||
override fun getUserName(): String {
|
||||
if (userName.isEmpty()) {
|
||||
userName = settings.getString("login", "")!!
|
||||
if (_userName.isEmpty()) {
|
||||
_userName = settings.getString("login", "")!!
|
||||
}
|
||||
return userName
|
||||
return _userName
|
||||
}
|
||||
|
||||
override fun getPassword(): String {
|
||||
if (password.isEmpty()) {
|
||||
password = settings.getString("password", "")!!
|
||||
if (_password.isEmpty()) {
|
||||
_password = settings.getString("password", "")!!
|
||||
}
|
||||
return password
|
||||
return _password
|
||||
}
|
||||
}
|
@ -24,15 +24,6 @@ fun SelfossModel.Item.sourceAndDateText(dateUtils: DateUtils): String {
|
||||
}
|
||||
|
||||
fun SelfossModel.Item.toggleStar(): SelfossModel.Item {
|
||||
this.starred = if (this.starred == 0) 1 else 0
|
||||
this.starred = !this.starred
|
||||
return this
|
||||
}
|
||||
|
||||
fun List<SelfossModel.Item>.flattenTags(): List<SelfossModel.Item> =
|
||||
this.flatMap {
|
||||
val item = it
|
||||
val tags: List<String> = it.tags.split(",")
|
||||
tags.map { t ->
|
||||
item.copy(tags = t.trim())
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ fun TagEntity.toView(): SelfossModel.Tag =
|
||||
|
||||
fun SourceEntity.toView(): SelfossModel.Source =
|
||||
SelfossModel.Source(
|
||||
this.id,
|
||||
this.id.toInt(),
|
||||
this.title,
|
||||
this.tags.split(","),
|
||||
this.spout,
|
||||
@ -26,7 +26,7 @@ fun SourceEntity.toView(): SelfossModel.Source =
|
||||
|
||||
fun SelfossModel.Source.toEntity(): SourceEntity =
|
||||
SourceEntity(
|
||||
this.id,
|
||||
this.id.toString(),
|
||||
this.getTitleDecoded(),
|
||||
this.tags.joinToString(","),
|
||||
this.spout,
|
||||
@ -43,30 +43,30 @@ fun SelfossModel.Tag.toEntity(): TagEntity =
|
||||
|
||||
fun AndroidItemEntity.toView(): SelfossModel.Item =
|
||||
SelfossModel.Item(
|
||||
this.id,
|
||||
this.id.toInt(),
|
||||
this.datetime,
|
||||
this.title,
|
||||
this.content,
|
||||
if (this.unread) 1 else 0,
|
||||
if (this.starred) 1 else 0,
|
||||
this.unread,
|
||||
this.starred,
|
||||
this.thumbnail,
|
||||
this.icon,
|
||||
this.link,
|
||||
this.sourcetitle,
|
||||
this.tags
|
||||
this.tags.split(",")
|
||||
)
|
||||
|
||||
fun SelfossModel.Item.toEntity(): AndroidItemEntity =
|
||||
AndroidItemEntity(
|
||||
this.id,
|
||||
this.id.toString(),
|
||||
this.datetime,
|
||||
this.getTitleDecoded(),
|
||||
this.content,
|
||||
this.unread == 1,
|
||||
this.starred == 1,
|
||||
this.unread,
|
||||
this.starred,
|
||||
this.thumbnail,
|
||||
this.icon,
|
||||
this.link,
|
||||
this.getSourceTitle(),
|
||||
this.tags
|
||||
this.tags.joinToString(",")
|
||||
)
|
@ -7,6 +7,7 @@ import io.ktor.client.engine.*
|
||||
import io.ktor.client.engine.ProxyBuilder.http
|
||||
import io.ktor.client.plugins.auth.*
|
||||
import io.ktor.client.plugins.auth.providers.*
|
||||
import io.ktor.client.plugins.cache.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.*
|
||||
import io.ktor.http.*
|
||||
@ -19,6 +20,7 @@ class SelfossApi(private val apiDetailsService: ApiDetailsService) {
|
||||
|
||||
private val client = HttpClient() {
|
||||
install(ContentNegotiation) {
|
||||
install(HttpCache)
|
||||
json(Json {
|
||||
prettyPrint = true
|
||||
isLenient = true
|
||||
@ -100,7 +102,7 @@ class SelfossApi(private val apiDetailsService: ApiDetailsService) {
|
||||
}.body()
|
||||
|
||||
suspend fun spouts(): Map<String, SelfossModel.Spout>? =
|
||||
client.get(url("/a/spouts")) {
|
||||
client.get(url("/sources/spouts")) {
|
||||
parameter("username", apiDetailsService.getUserName())
|
||||
parameter("password", apiDetailsService.getPassword())
|
||||
}.body()
|
||||
@ -115,55 +117,38 @@ class SelfossApi(private val apiDetailsService: ApiDetailsService) {
|
||||
client.get(url("/api/about")).body()
|
||||
|
||||
suspend fun markAsRead(id: String): SelfossModel.SuccessResponse? =
|
||||
client.submitForm(
|
||||
url = url("/mark/$id"),
|
||||
formParameters = Parameters.build {
|
||||
append("username", apiDetailsService.getUserName())
|
||||
append("password", apiDetailsService.getPassword())
|
||||
},
|
||||
encodeInQuery = true
|
||||
).body()
|
||||
client.post(url("/mark/$id")) {
|
||||
parameter("username", apiDetailsService.getUserName())
|
||||
parameter("password", apiDetailsService.getPassword())
|
||||
}.body()
|
||||
|
||||
suspend fun unmarkAsRead(id: String): SelfossModel.SuccessResponse? =
|
||||
client.submitForm(
|
||||
url = url("/unmark/$id"),
|
||||
formParameters = Parameters.build {
|
||||
append("username", apiDetailsService.getUserName())
|
||||
append("password", apiDetailsService.getPassword())
|
||||
},
|
||||
encodeInQuery = true
|
||||
).body()
|
||||
client.post(url("/unmark/$id")) {
|
||||
parameter("username", apiDetailsService.getUserName())
|
||||
parameter("password", apiDetailsService.getPassword())
|
||||
}.body()
|
||||
|
||||
suspend fun starr(id: String): SelfossModel.SuccessResponse? =
|
||||
client.submitForm(
|
||||
url = url("/starr/$id"),
|
||||
formParameters = Parameters.build {
|
||||
append("username", apiDetailsService.getUserName())
|
||||
append("password", apiDetailsService.getPassword())
|
||||
},
|
||||
encodeInQuery = true
|
||||
).body()
|
||||
client.post(url("/starr/$id")) {
|
||||
parameter("username", apiDetailsService.getUserName())
|
||||
parameter("password", apiDetailsService.getPassword())
|
||||
}.body()
|
||||
|
||||
suspend fun unstarr(id: String): SelfossModel.SuccessResponse? =
|
||||
client.submitForm(
|
||||
url = url("/unstarr/$id"),
|
||||
formParameters = Parameters.build {
|
||||
append("username", apiDetailsService.getUserName())
|
||||
append("password", apiDetailsService.getPassword())
|
||||
},
|
||||
encodeInQuery = true
|
||||
).body()
|
||||
client.post(url("/unstarr/$id")) {
|
||||
parameter("username", apiDetailsService.getUserName())
|
||||
parameter("password", apiDetailsService.getPassword())
|
||||
}.body()
|
||||
|
||||
suspend fun markAllAsRead(ids: List<String>): SelfossModel.SuccessResponse? =
|
||||
client.submitForm(
|
||||
url = url("/mark"),
|
||||
formParameters = Parameters.build {
|
||||
append("username", apiDetailsService.getUserName())
|
||||
append("password", apiDetailsService.getPassword())
|
||||
append("ids[]", ids.joinToString(","))
|
||||
},
|
||||
encodeInQuery = true
|
||||
).body()
|
||||
url = url("/mark"),
|
||||
formParameters = Parameters.build {
|
||||
append("username", apiDetailsService.getUserName())
|
||||
append("password", apiDetailsService.getPassword())
|
||||
ids.map { append("ids[]", it) }
|
||||
}
|
||||
).body()
|
||||
|
||||
suspend fun createSourceForVersion(
|
||||
title: String,
|
||||
@ -186,19 +171,15 @@ class SelfossApi(private val apiDetailsService: ApiDetailsService) {
|
||||
tags: String,
|
||||
filter: String
|
||||
): SelfossModel.SuccessResponse? =
|
||||
client.submitForm(
|
||||
url = url("/source"),
|
||||
formParameters = Parameters.build {
|
||||
append("username", apiDetailsService.getUserName())
|
||||
append("password", apiDetailsService.getPassword())
|
||||
append("title", title)
|
||||
append("url", url)
|
||||
append("spout", spout)
|
||||
append("tags", tags)
|
||||
append("filter", filter)
|
||||
},
|
||||
encodeInQuery = true
|
||||
).body()
|
||||
client.post(url("/source")) {
|
||||
parameter("username", apiDetailsService.getUserName())
|
||||
parameter("password", apiDetailsService.getPassword())
|
||||
parameter("title", title)
|
||||
parameter("url", url)
|
||||
parameter("spout", spout)
|
||||
parameter("tags", tags)
|
||||
parameter("filter", filter)
|
||||
}.body()
|
||||
|
||||
private suspend fun createSource2(
|
||||
title: String,
|
||||
@ -207,21 +188,17 @@ class SelfossApi(private val apiDetailsService: ApiDetailsService) {
|
||||
tags: String,
|
||||
filter: String
|
||||
): SelfossModel.SuccessResponse? =
|
||||
client.submitForm(
|
||||
url = url("/source"),
|
||||
formParameters = Parameters.build {
|
||||
append("username", apiDetailsService.getUserName())
|
||||
append("password", apiDetailsService.getPassword())
|
||||
append("title", title)
|
||||
append("url", url)
|
||||
append("spout", spout)
|
||||
append("tags[]", tags)
|
||||
append("filter", filter)
|
||||
},
|
||||
encodeInQuery = true
|
||||
).body()
|
||||
client.post(url("/source")) {
|
||||
parameter("username", apiDetailsService.getUserName())
|
||||
parameter("password", apiDetailsService.getPassword())
|
||||
parameter("title", title)
|
||||
parameter("url", url)
|
||||
parameter("spout", spout)
|
||||
parameter("tags[]", tags)
|
||||
parameter("filter", filter)
|
||||
}.body()
|
||||
|
||||
suspend fun deleteSource(id: String): SelfossModel.SuccessResponse? =
|
||||
suspend fun deleteSource(id: Int): SelfossModel.SuccessResponse? =
|
||||
client.delete(url("/source/$id")) {
|
||||
parameter("username", apiDetailsService.getUserName())
|
||||
parameter("password", apiDetailsService.getPassword())
|
||||
|
@ -52,7 +52,7 @@ class SelfossModel {
|
||||
|
||||
@Serializable
|
||||
data class Source(
|
||||
val id: String,
|
||||
val id: Int,
|
||||
val title: String,
|
||||
val tags: List<String>,
|
||||
val spout: String,
|
||||
@ -62,16 +62,16 @@ class SelfossModel {
|
||||
|
||||
@Serializable
|
||||
data class Item(
|
||||
val id: String,
|
||||
val id: Int,
|
||||
val datetime: String,
|
||||
val title: String,
|
||||
val content: String,
|
||||
var unread: Int,
|
||||
var starred: Int,
|
||||
var unread: Boolean,
|
||||
var starred: Boolean,
|
||||
val thumbnail: String?,
|
||||
val icon: String?,
|
||||
val link: String,
|
||||
val sourcetitle: String,
|
||||
val tags: String
|
||||
val tags: List<String>
|
||||
)
|
||||
}
|
@ -27,8 +27,8 @@ abstract class DeviceDataBaseService<ItemEntity>(val db: DeviceDatabase<ItemEnti
|
||||
// This filtered items from items val. Do not use
|
||||
fun getFocusedItems() {}
|
||||
fun computeBadges() {
|
||||
searchService.badgeUnread = items.filter { item -> item.unread == 1 }.size
|
||||
searchService.badgeStarred = items.filter { item -> item.starred == 1 }.size
|
||||
searchService.badgeUnread = items.filter { item -> item.unread }.size
|
||||
searchService.badgeStarred = items.filter { item -> item.starred }.size
|
||||
searchService.badgeAll = items.size
|
||||
}
|
||||
}
|
@ -21,10 +21,6 @@ class SearchService(val dateUtils: DateUtils) {
|
||||
var tagFilter: String? = null
|
||||
var itemsCaching = false
|
||||
|
||||
var fetchedUnread = false
|
||||
var fetchedAll = false
|
||||
var fetchedStarred = false
|
||||
|
||||
var badgeUnread = -1
|
||||
var badgeAll = -1
|
||||
var badgeStarred = -1
|
||||
|
@ -7,90 +7,48 @@ import kotlinx.coroutines.*
|
||||
|
||||
class SelfossService<ItemEntity>(val api: SelfossApi, private val dbService: DeviceDataBaseService<ItemEntity>, private val searchService: SearchService) {
|
||||
|
||||
suspend fun getAndStoreAllItems(isNetworkAvailable: Boolean) = withContext(
|
||||
suspend fun getReadItems(itemsNumber: Int, offset: Int, isNetworkAvailable: Boolean): List<SelfossModel.Item>? = withContext(
|
||||
Dispatchers.Default) {
|
||||
if (isNetworkAvailable) {
|
||||
launch {
|
||||
try {
|
||||
enqueueArticles(allNewItems(), true)
|
||||
} catch (e: Throwable) {}
|
||||
}
|
||||
launch {
|
||||
try {
|
||||
enqueueArticles(allReadItems(), false)
|
||||
} catch (e: Throwable) {}
|
||||
}
|
||||
launch {
|
||||
try {
|
||||
enqueueArticles(allStarredItems(), false)
|
||||
} catch (e: Throwable) {}
|
||||
}
|
||||
val apiItems = readItems( itemsNumber, offset)
|
||||
// SAVE OR UPDATE IN DB
|
||||
return@withContext apiItems
|
||||
} else {
|
||||
launch { dbService.updateDatabase() }
|
||||
// GET FROM DB
|
||||
return@withContext emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun refreshFocusedItems(itemsNumber: Int, isNetworkAvailable: Boolean) = withContext(
|
||||
suspend fun getUnreadItems(itemsNumber: Int, offset: Int, isNetworkAvailable: Boolean): List<SelfossModel.Item>? = withContext(
|
||||
Dispatchers.Default) {
|
||||
if (isNetworkAvailable) {
|
||||
val response = when (searchService.displayedItems) {
|
||||
"read" -> readItems(itemsNumber, 0)
|
||||
"unread" -> newItems(itemsNumber, 0)
|
||||
"starred" -> starredItems(itemsNumber, 0)
|
||||
else -> readItems(itemsNumber, 0)
|
||||
}
|
||||
|
||||
if (response != null) {
|
||||
// TODO:
|
||||
// dbService.refreshFocusedItems(response.body() as ArrayList<SelfossModel.Item>)
|
||||
dbService.updateDatabase()
|
||||
}
|
||||
val apiItems = newItems(itemsNumber, offset)
|
||||
// SAVE OR UPDATE IN DB
|
||||
return@withContext apiItems
|
||||
} else {
|
||||
// GET FROM DB
|
||||
return@withContext emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getReadItems(itemsNumber: Int, offset: Int, isNetworkAvailable: Boolean) = withContext(
|
||||
suspend fun getStarredItems(itemsNumber: Int, offset: Int, isNetworkAvailable: Boolean): List<SelfossModel.Item>? = withContext(
|
||||
Dispatchers.Default) {
|
||||
if (isNetworkAvailable) {
|
||||
try {
|
||||
enqueueArticles(readItems( itemsNumber, offset), false)
|
||||
searchService.fetchedAll = true
|
||||
dbService.updateDatabase()
|
||||
} catch (e: Throwable) {}
|
||||
val apiItems = starredItems(itemsNumber, offset)
|
||||
// SAVE OR UPDATE IN DB
|
||||
return@withContext apiItems
|
||||
} else {
|
||||
// GET FROM DB
|
||||
return@withContext emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getUnreadItems(itemsNumber: Int, offset: Int, isNetworkAvailable: Boolean) = withContext(
|
||||
Dispatchers.Default) {
|
||||
if (isNetworkAvailable) {
|
||||
try {
|
||||
if (!searchService.fetchedUnread) {
|
||||
dbService.clearDBItems()
|
||||
}
|
||||
enqueueArticles(newItems(itemsNumber, offset), false)
|
||||
searchService.fetchedUnread = true
|
||||
} catch (e: Throwable) {}
|
||||
}
|
||||
dbService.updateDatabase()
|
||||
}
|
||||
|
||||
suspend fun getStarredItems(itemsNumber: Int, offset: Int, isNetworkAvailable: Boolean) = withContext(
|
||||
Dispatchers.Default) {
|
||||
if (isNetworkAvailable) {
|
||||
try {
|
||||
enqueueArticles(starredItems(itemsNumber, offset), false)
|
||||
searchService.fetchedStarred = true
|
||||
dbService.updateDatabase()
|
||||
} catch (e: Throwable) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun readAll(isNetworkAvailable: Boolean): Boolean {
|
||||
suspend fun readAll(ids: List<String>, isNetworkAvailable: Boolean): Boolean {
|
||||
// Add ids params
|
||||
var success = false
|
||||
if (isNetworkAvailable) {
|
||||
// Do api call to read all
|
||||
} else {
|
||||
// Do db call to read all
|
||||
success = api.markAllAsRead(ids)?.isSuccess == true
|
||||
// SAVE OR UPDATE IN DB
|
||||
}
|
||||
// refresh view
|
||||
return success
|
||||
@ -100,7 +58,6 @@ class SelfossService<ItemEntity>(val api: SelfossApi, private val dbService: Dev
|
||||
if (isNetworkAvailable) {
|
||||
try {
|
||||
val response = api.stats()
|
||||
|
||||
if (response != null) {
|
||||
searchService.badgeUnread = response.unread
|
||||
searchService.badgeAll = response.total
|
||||
@ -123,13 +80,13 @@ class SelfossService<ItemEntity>(val api: SelfossApi, private val dbService: Dev
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun allNewItems(): List<SelfossModel.Item>? =
|
||||
suspend fun allNewItems(): List<SelfossModel.Item>? =
|
||||
readItems(200, 0)
|
||||
|
||||
private suspend fun allReadItems(): List<SelfossModel.Item>? =
|
||||
suspend fun allReadItems(): List<SelfossModel.Item>? =
|
||||
newItems(200, 0)
|
||||
|
||||
private suspend fun allStarredItems(): List<SelfossModel.Item>? =
|
||||
suspend fun allStarredItems(): List<SelfossModel.Item>? =
|
||||
starredItems(200, 0)
|
||||
|
||||
private suspend fun readItems(
|
||||
|
Loading…
Reference in New Issue
Block a user