Swipe down to refresh (main view)

This commit is contained in:
Philipp Heckel 2021-11-14 14:20:30 -05:00
parent 276d773152
commit 09a5d5b4f5
6 changed files with 31 additions and 23 deletions

View file

@ -73,6 +73,9 @@ dependencies {
// RecyclerView // RecyclerView
implementation "androidx.recyclerview:recyclerview:$rootProject.recyclerViewVersion" implementation "androidx.recyclerview:recyclerview:$rootProject.recyclerViewVersion"
// Swipe down to refresh
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
// Material design // Material design
implementation "com.google.android.material:material:$rootProject.materialVersion" implementation "com.google.android.material:material:$rootProject.materialVersion"

View file

@ -19,14 +19,12 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.work.WorkManager
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.data.Notification import io.heckel.ntfy.data.Notification
import io.heckel.ntfy.data.topicShortUrl import io.heckel.ntfy.data.topicShortUrl
import io.heckel.ntfy.data.topicUrl import io.heckel.ntfy.data.topicUrl
import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.NotificationService
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.util.* import java.util.*

View file

@ -6,7 +6,6 @@ import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.ActionMode import android.view.ActionMode
@ -19,6 +18,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.work.* import androidx.work.*
import com.google.firebase.messaging.FirebaseMessaging import com.google.firebase.messaging.FirebaseMessaging
import io.heckel.ntfy.R import io.heckel.ntfy.R
@ -27,10 +27,6 @@ import io.heckel.ntfy.data.Subscription
import io.heckel.ntfy.data.topicShortUrl import io.heckel.ntfy.data.topicShortUrl
import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.ApiService
import io.heckel.ntfy.msg.NotificationService import io.heckel.ntfy.msg.NotificationService
import io.heckel.ntfy.msg.SubscriberService
import io.heckel.ntfy.msg.SubscriberService.ServiceState
import io.heckel.ntfy.msg.SubscriberService.Actions
import io.heckel.ntfy.msg.SubscriberService.Companion.readServiceState
import io.heckel.ntfy.work.PollWorker import io.heckel.ntfy.work.PollWorker
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -38,6 +34,7 @@ import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.random.Random import kotlin.random.Random
class MainActivity : AppCompatActivity(), ActionMode.Callback { class MainActivity : AppCompatActivity(), ActionMode.Callback {
private val viewModel by viewModels<SubscriptionsViewModel> { private val viewModel by viewModels<SubscriptionsViewModel> {
SubscriptionsViewModelFactory((application as Application).repository) SubscriptionsViewModelFactory((application as Application).repository)
@ -46,6 +43,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback {
private val api = ApiService() private val api = ApiService()
private lateinit var mainList: RecyclerView private lateinit var mainList: RecyclerView
private lateinit var mainListContainer: SwipeRefreshLayout
private lateinit var adapter: MainAdapter private lateinit var adapter: MainAdapter
private lateinit var fab: View private lateinit var fab: View
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
@ -73,6 +71,11 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback {
onSubscribeButtonClick() onSubscribeButtonClick()
} }
// Swipewn to refresh
mainListContainer = findViewById(R.id.main_subscriptions_list_swipe_container)
mainListContainer.setOnRefreshListener { refreshAllSubscriptions() }
mainListContainer.setColorSchemeResources(R.color.primaryColor)
// Update main list based on viewModel (& its datasource/livedata) // Update main list based on viewModel (& its datasource/livedata)
val noEntries: View = findViewById(R.id.main_no_subscriptions) val noEntries: View = findViewById(R.id.main_no_subscriptions)
val onSubscriptionClick = { s: Subscription -> onSubscriptionItemClick(s) } val onSubscriptionClick = { s: Subscription -> onSubscriptionItemClick(s) }
@ -86,10 +89,10 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback {
it?.let { subscriptions -> it?.let { subscriptions ->
adapter.submitList(subscriptions as MutableList<Subscription>) adapter.submitList(subscriptions as MutableList<Subscription>)
if (it.isEmpty()) { if (it.isEmpty()) {
mainList.visibility = View.GONE mainListContainer.visibility = View.GONE
noEntries.visibility = View.VISIBLE noEntries.visibility = View.VISIBLE
} else { } else {
mainList.visibility = View.VISIBLE mainListContainer.visibility = View.VISIBLE
noEntries.visibility = View.GONE noEntries.visibility = View.GONE
} }
} }
@ -134,10 +137,6 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) { return when (item.itemId) {
R.id.main_menu_refresh -> {
refreshAllSubscriptions()
true
}
R.id.main_menu_source -> { R.id.main_menu_source -> {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_source_url)))) startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_source_url))))
true true
@ -230,12 +229,16 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback {
} else { } else {
getString(R.string.refresh_message_result, newNotificationsCount) getString(R.string.refresh_message_result, newNotificationsCount)
} }
runOnUiThread { Toast.makeText(this@MainActivity, toastMessage, Toast.LENGTH_LONG).show() } runOnUiThread {
Toast.makeText(this@MainActivity, toastMessage, Toast.LENGTH_LONG).show()
mainListContainer.isRefreshing = false
}
Log.d(TAG, "Finished polling for new notifications") Log.d(TAG, "Finished polling for new notifications")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Polling failed: ${e.message}", e) Log.e(TAG, "Polling failed: ${e.message}", e)
runOnUiThread { runOnUiThread {
Toast.makeText(this@MainActivity, getString(R.string.refresh_message_error, e.message), Toast.LENGTH_LONG).show() Toast.makeText(this@MainActivity, getString(R.string.refresh_message_error, e.message), Toast.LENGTH_LONG).show()
mainListContainer.isRefreshing = false
} }
} }
} }

View file

@ -4,15 +4,21 @@
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/main_subscriptions_list" android:id="@+id/main_subscriptions_list_swipe_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:background="?android:attr/selectableItemBackground" android:visibility="gone">
app:layoutManager="LinearLayoutManager" android:visibility="gone"/> <androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_subscriptions_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
app:layoutManager="LinearLayoutManager"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -1,5 +1,4 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/main_menu_refresh" android:title="@string/main_menu_refresh"/>
<item android:id="@+id/main_menu_source" android:title="@string/main_menu_source_title"/> <item android:id="@+id/main_menu_source" android:title="@string/main_menu_source_title"/>
<item android:id="@+id/main_menu_website" android:title="@string/main_menu_website_title"/> <item android:id="@+id/main_menu_website" android:title="@string/main_menu_website_title"/>
</menu> </menu>

View file

@ -16,8 +16,7 @@
<!-- Main activity: Action bar --> <!-- Main activity: Action bar -->
<string name="main_action_bar_title">Subscribed topics</string> <string name="main_action_bar_title">Subscribed topics</string>
<string name="main_menu_refresh">Force refresh</string> <string name="main_menu_source_title">Report bugs</string>
<string name="main_menu_source_title">Show source &amp; license</string>
<string name="main_menu_source_url">https://heckel.io/ntfy-android</string> <string name="main_menu_source_url">https://heckel.io/ntfy-android</string>
<string name="main_menu_website_title">Visit ntfy.sh</string> <string name="main_menu_website_title">Visit ntfy.sh</string>