diff --git a/.idea/misc.xml b/.idea/misc.xml
index 9f98f69..07ec910 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -24,6 +24,8 @@
+
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index f8fc09d..9979963 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -57,6 +57,7 @@ dependencies {
implementation(libs.androidx.core)
implementation(libs.androidx.appcompat)
implementation(libs.material)
+ implementation(libs.accompanist.swiperefresh)
implementation(libs.bundles.compose)
implementation(libs.lifecycle)
implementation(libs.hilt.android.core)
diff --git a/app/src/main/java/com/wbrawner/nanoflux/data/viewmodel/MainViewModel.kt b/app/src/main/java/com/wbrawner/nanoflux/data/viewmodel/MainViewModel.kt
index 9aea217..aeda9dc 100644
--- a/app/src/main/java/com/wbrawner/nanoflux/data/viewmodel/MainViewModel.kt
+++ b/app/src/main/java/com/wbrawner/nanoflux/data/viewmodel/MainViewModel.kt
@@ -6,15 +6,10 @@ import com.wbrawner.nanoflux.network.repository.CategoryRepository
import com.wbrawner.nanoflux.network.repository.EntryRepository
import com.wbrawner.nanoflux.network.repository.FeedRepository
import com.wbrawner.nanoflux.network.repository.IconRepository
-import com.wbrawner.nanoflux.storage.model.Entry
-import com.wbrawner.nanoflux.storage.model.EntryAndFeed
import com.wbrawner.nanoflux.syncAll
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
import timber.log.Timber
import javax.inject.Inject
@@ -28,11 +23,9 @@ class MainViewModel @Inject constructor(
) : ViewModel() {
init {
- viewModelScope.launch {
- withContext(Dispatchers.IO) {
- if (entryRepository.getCount() == 0L) {
- syncAll(categoryRepository, feedRepository, iconRepository, entryRepository)
- }
+ viewModelScope.launch(Dispatchers.IO) {
+ if (entryRepository.getCount() == 0L) {
+ syncAll(categoryRepository, feedRepository, iconRepository, entryRepository)
}
}
}
diff --git a/app/src/main/java/com/wbrawner/nanoflux/data/viewmodel/UnreadViewModel.kt b/app/src/main/java/com/wbrawner/nanoflux/data/viewmodel/UnreadViewModel.kt
index d22402b..6ad7052 100644
--- a/app/src/main/java/com/wbrawner/nanoflux/data/viewmodel/UnreadViewModel.kt
+++ b/app/src/main/java/com/wbrawner/nanoflux/data/viewmodel/UnreadViewModel.kt
@@ -37,4 +37,12 @@ class UnreadViewModel @Inject constructor(
// TODO: Get Base URL
fun getShareUrl(entry: Entry) = "baseUrl/${entry.shareCode}"
+
+ fun refresh() = viewModelScope.launch(Dispatchers.IO) {
+ _loading.emit(true)
+ feedRepository.getAll(fetch = true)
+ categoryRepository.getAll(fetch = true)
+ entryRepository.getAll(fetch = true)
+ _loading.emit(false)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/wbrawner/nanoflux/ui/Entries.kt b/app/src/main/java/com/wbrawner/nanoflux/ui/Entries.kt
index 9efa378..0551935 100644
--- a/app/src/main/java/com/wbrawner/nanoflux/ui/Entries.kt
+++ b/app/src/main/java/com/wbrawner/nanoflux/ui/Entries.kt
@@ -20,6 +20,8 @@ import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+import com.google.accompanist.swiperefresh.SwipeRefresh
+import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
import com.wbrawner.nanoflux.NanofluxApp
import com.wbrawner.nanoflux.storage.model.*
import java.util.*
@@ -32,20 +34,26 @@ fun EntryList(
onFeedClicked: (feed: Feed) -> Unit,
onToggleReadClicked: (entry: Entry) -> Unit,
onStarClicked: (entry: Entry) -> Unit,
- onExternalLinkClicked: (entry: Entry) -> Unit
+ onExternalLinkClicked: @Composable (entry: Entry) -> Unit,
+ isRefreshing: Boolean,
+ onRefresh: () -> Unit
) {
- // TODO: Add pull to refresh
- LazyColumn {
- items(entries) { entry ->
- EntryListItem(
- entry.entry,
- entry.feed,
- onEntryItemClicked,
- onFeedClicked,
- onToggleReadClicked,
- onStarClicked,
- onExternalLinkClicked
- )
+ SwipeRefresh(
+ state = rememberSwipeRefreshState(isRefreshing = isRefreshing),
+ onRefresh = onRefresh
+ ) {
+ LazyColumn {
+ items(entries) { entry ->
+ EntryListItem(
+ entry.entry,
+ entry.feed,
+ onEntryItemClicked,
+ onFeedClicked,
+ onToggleReadClicked,
+ onStarClicked,
+ onExternalLinkClicked
+ )
+ }
}
}
}
@@ -58,7 +66,7 @@ fun EntryListItem(
onFeedClicked: (feed: Feed) -> Unit,
onToggleReadClicked: (entry: Entry) -> Unit,
onStarClicked: (entry: Entry) -> Unit,
- onExternalLinkClicked: (entry: Entry) -> Unit
+ onExternalLinkClicked: @Composable (entry: Entry) -> Unit
) {
// val swipeState = rememberSwipeableState(initialValue = entry.status)
Column(
@@ -121,13 +129,15 @@ fun EntryListItem(
}
val context = LocalContext.current
IconButton(onClick = {
- context.startActivity(Intent(Intent.ACTION_SEND).apply {
+ val intent = Intent(Intent.ACTION_SEND).apply {
// TODO: Get base url from viewmodel or something
+ type = "text/plain"
putExtra(
Intent.EXTRA_TEXT,
"https://wbrawner.com/entry/share/${entry.shareCode}"
)
- })
+ }
+ context.startActivity(Intent.createChooser(intent, null))
}) {
Icon(
imageVector = Icons.Default.Share,
diff --git a/app/src/main/java/com/wbrawner/nanoflux/ui/MainScreen.kt b/app/src/main/java/com/wbrawner/nanoflux/ui/MainScreen.kt
index 92b0fea..c51c36a 100644
--- a/app/src/main/java/com/wbrawner/nanoflux/ui/MainScreen.kt
+++ b/app/src/main/java/com/wbrawner/nanoflux/ui/MainScreen.kt
@@ -109,6 +109,12 @@ fun MainScaffold(
composable("unread") {
UnreadScreen(navController, snackbarHostState, hiltViewModel())
}
+ composable("starred") {
+ UnreadScreen(navController, snackbarHostState, hiltViewModel())
+ }
+ composable("history") {
+ UnreadScreen(navController, snackbarHostState, hiltViewModel())
+ }
composable(
"entries/{entryId}",
arguments = listOf(navArgument("entryId") { type = NavType.LongType })
diff --git a/app/src/main/java/com/wbrawner/nanoflux/ui/UnreadScreen.kt b/app/src/main/java/com/wbrawner/nanoflux/ui/UnreadScreen.kt
index ac50c82..fadf45e 100644
--- a/app/src/main/java/com/wbrawner/nanoflux/ui/UnreadScreen.kt
+++ b/app/src/main/java/com/wbrawner/nanoflux/ui/UnreadScreen.kt
@@ -1,7 +1,10 @@
package com.wbrawner.nanoflux.ui
+import android.content.Intent
+import android.net.Uri
import androidx.compose.material.*
import androidx.compose.runtime.*
+import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.wbrawner.nanoflux.data.viewmodel.UnreadViewModel
@@ -17,30 +20,30 @@ fun UnreadScreen(
val errorMessage by unreadViewModel.errorMessage.collectAsState()
val entries by unreadViewModel.entries.collectAsState(emptyList())
val coroutineScope = rememberCoroutineScope()
- if (loading) {
- CircularProgressIndicator()
- }
errorMessage?.let {
coroutineScope.launch {
when (snackbarHostState.showSnackbar(it, "Retry")) {
-// SnackbarResult.ActionPerformed -> unreadViewModel.loadUnread()
+ SnackbarResult.ActionPerformed -> unreadViewModel.refresh()
else -> unreadViewModel.dismissError()
}
}
}
- if (entries.isEmpty()) {
- Text("TODO: No entries")
- } else {
- EntryList(
- entries = entries,
- onEntryItemClicked = {
- navController.navigate("entries/${it.id}")
- },
- onFeedClicked = {
- navController.navigate("feeds/${it.id}")
- },
- onToggleReadClicked = { /*TODO*/ },
- onStarClicked = { /*TODO*/ }) {
+ EntryList(
+ entries = entries,
+ onEntryItemClicked = {
+ navController.navigate("entries/${it.id}")
+ },
+ onFeedClicked = {
+ navController.navigate("feeds/${it.id}")
+ },
+ onToggleReadClicked = { /*TODO*/ },
+ onStarClicked = { /*TODO*/ },
+ onExternalLinkClicked = {
+ LocalContext.current.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(it.url)))
+ },
+ isRefreshing = loading,
+ onRefresh = {
+ unreadViewModel.refresh()
}
- }
+ )
}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 52ed3d9..ef07eed 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -18,6 +18,7 @@ versionName = "1.0"
work = "2.7.1"
[libraries]
+accompanist-swiperefresh = { module = "com.google.accompanist:accompanist-swiperefresh", version = "0.26.3-beta"}
androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
material = { module = "com.google.android.material:material", version.ref = "material" }
diff --git a/network/src/main/java/com/wbrawner/nanoflux/network/repository/EntryRepository.kt b/network/src/main/java/com/wbrawner/nanoflux/network/repository/EntryRepository.kt
index 1f376e5..b750f75 100644
--- a/network/src/main/java/com/wbrawner/nanoflux/network/repository/EntryRepository.kt
+++ b/network/src/main/java/com/wbrawner/nanoflux/network/repository/EntryRepository.kt
@@ -14,11 +14,11 @@ class EntryRepository @Inject constructor(
private val entryDao: EntryDao,
private val logger: Timber.Tree
) {
- fun observeUnread(): Flow> = entryDao.observeAll()
+ fun observeUnread(): Flow> = entryDao.observeUnread()
fun getCount(): Long = entryDao.getCount()
- suspend fun getAll(fetch: Boolean = false, afterId: Long = 0): List {
+ suspend fun getAll(fetch: Boolean = false, afterId: Long? = null): List {
if (fetch) {
getEntries { page ->
apiService.getEntries(
@@ -76,4 +76,10 @@ class EntryRepository @Inject constructor(
totalPages = response.total / 100
}
}
+}
+
+enum class EntryStatus {
+ UNREAD,
+ STARRED,
+ HISTORY
}
\ No newline at end of file
diff --git a/storage/src/main/java/com/wbrawner/nanoflux/storage/dao/EntryDao.kt b/storage/src/main/java/com/wbrawner/nanoflux/storage/dao/EntryDao.kt
index 52ec07b..fd8c19e 100644
--- a/storage/src/main/java/com/wbrawner/nanoflux/storage/dao/EntryDao.kt
+++ b/storage/src/main/java/com/wbrawner/nanoflux/storage/dao/EntryDao.kt
@@ -11,11 +11,15 @@ interface EntryDao {
fun getCount(): Long
@Transaction
- @Query("SELECT * FROM Entry ORDER BY createdAt DESC")
+ @Query("SELECT * FROM Entry ORDER BY publishedAt DESC")
fun observeAll(): Flow>
@Transaction
- @Query("SELECT * FROM Entry ORDER BY createdAt DESC")
+ @Query("SELECT * FROM Entry WHERE status = \"UNREAD\" ORDER BY publishedAt DESC")
+ fun observeUnread(): Flow>
+
+ @Transaction
+ @Query("SELECT * FROM Entry ORDER BY publishedAt DESC")
fun getAll(): List
@Transaction
diff --git a/storage/src/main/java/com/wbrawner/nanoflux/storage/dao/FeedDao.kt b/storage/src/main/java/com/wbrawner/nanoflux/storage/dao/FeedDao.kt
index 9ee945b..67ec955 100644
--- a/storage/src/main/java/com/wbrawner/nanoflux/storage/dao/FeedDao.kt
+++ b/storage/src/main/java/com/wbrawner/nanoflux/storage/dao/FeedDao.kt
@@ -7,7 +7,7 @@ import com.wbrawner.nanoflux.storage.model.FeedCategoryIcon
@Dao
interface FeedDao {
@Transaction
- @Query("SELECT * FROM Feed")
+ @Query("SELECT * FROM Feed ORDER BY title ASC")
fun getAll(): List
@Transaction