diff --git a/mobile/build.gradle b/mobile/build.gradle
index 321488ac4e..d411b8acbb 100644
--- a/mobile/build.gradle
+++ b/mobile/build.gradle
@@ -174,7 +174,8 @@ dependencies {
implementation "com.github.QuadFlask:colorpicker:0.0.15"
implementation "com.caverock:androidsvg-aar:1.4"
implementation "com.github.AppIntro:AppIntro:6.3.1"
- implementation 'com.github.chrisbanes:PhotoView:2.3.0'
+ implementation "com.github.chrisbanes:PhotoView:2.3.0"
+ implementation "com.faltenreich:skeletonlayout:5.0.0"
// MapView support
fullImplementation "com.google.android.gms:play-services-maps:18.2.0"
fossImplementation "org.osmdroid:osmdroid-android:6.1.18"
diff --git a/mobile/src/main/java/org/openhab/habdroid/ui/CloudNotificationListFragment.kt b/mobile/src/main/java/org/openhab/habdroid/ui/CloudNotificationListFragment.kt
index 91d2c1399a..c2bdd55667 100644
--- a/mobile/src/main/java/org/openhab/habdroid/ui/CloudNotificationListFragment.kt
+++ b/mobile/src/main/java/org/openhab/habdroid/ui/CloudNotificationListFragment.kt
@@ -21,6 +21,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
+import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.os.bundleOf
import androidx.core.view.isVisible
@@ -28,6 +29,7 @@ import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+import com.faltenreich.skeletonlayout.SkeletonLayout
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.json.JSONArray
@@ -50,6 +52,7 @@ import org.openhab.habdroid.util.map
*/
class CloudNotificationListFragment : Fragment(), View.OnClickListener, SwipeRefreshLayout.OnRefreshListener {
lateinit var recyclerView: RecyclerView
+ private lateinit var skeleton: SkeletonLayout
private lateinit var swipeLayout: SwipeRefreshLayout
private lateinit var retryButton: Button
private lateinit var emptyView: View
@@ -71,6 +74,13 @@ class CloudNotificationListFragment : Fragment(), View.OnClickListener, SwipeRef
emptyView = view.findViewById(android.R.id.empty)
emptyMessage = view.findViewById(R.id.empty_message)
emptyWatermark = view.findViewById(R.id.watermark)
+ skeleton = view.findViewById(R.id.skeletonLayout)
+ view.findViewById(R.id.skeletonList).apply {
+ repeat(10) {
+ addView(inflater.inflate(R.layout.notificationlist_item, null))
+ }
+ }
+ skeleton.showSkeleton()
swipeLayout = view.findViewById(R.id.swipe_container)
swipeLayout.setOnRefreshListener(this)
@@ -106,6 +116,7 @@ class CloudNotificationListFragment : Fragment(), View.OnClickListener, SwipeRef
override fun onRefresh() {
Log.d(TAG, "onRefresh()")
+ swipeLayout.isRefreshing = false
loadNotifications(true)
}
@@ -172,7 +183,7 @@ class CloudNotificationListFragment : Fragment(), View.OnClickListener, SwipeRef
val showEmpty = !loading && (adapter.itemCount == 0 || loadError)
recyclerView.isVisible = !showEmpty
emptyView.isVisible = showEmpty
- swipeLayout.isRefreshing = loading
+ skeleton.isVisible = loading
emptyMessage.setText(
if (loadError) R.string.notification_list_error else R.string.notification_list_empty
)
diff --git a/mobile/src/main/java/org/openhab/habdroid/ui/activity/ContentController.kt b/mobile/src/main/java/org/openhab/habdroid/ui/activity/ContentController.kt
index 3ba3781bc5..042b940646 100644
--- a/mobile/src/main/java/org/openhab/habdroid/ui/activity/ContentController.kt
+++ b/mobile/src/main/java/org/openhab/habdroid/ui/activity/ContentController.kt
@@ -41,6 +41,7 @@ import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks
import androidx.fragment.app.commit
import androidx.fragment.app.commitNow
+import com.faltenreich.skeletonlayout.SkeletonLayout
import java.util.Stack
import org.openhab.habdroid.R
import org.openhab.habdroid.core.OpenHabApplication
@@ -793,7 +794,9 @@ abstract class ContentController protected constructor(private val activity: Mai
descriptionText.text = arguments.getCharSequence(KEY_MESSAGE)
descriptionText.isVisible = !descriptionText.text.isNullOrEmpty()
- view.findViewById(R.id.progress).isVisible = arguments.getBoolean(KEY_PROGRESS)
+ val skeleton = view.findViewById(R.id.skeletonLayout)
+ skeleton.isVisible = arguments.getBoolean(KEY_PROGRESS)
+ skeleton.showSkeleton()
val watermark = view.findViewById(R.id.image)
diff --git a/mobile/src/main/res/layout/fragment_notificationlist.xml b/mobile/src/main/res/layout/fragment_notificationlist.xml
index 99fcfbda99..de85e15c31 100644
--- a/mobile/src/main/res/layout/fragment_notificationlist.xml
+++ b/mobile/src/main/res/layout/fragment_notificationlist.xml
@@ -54,6 +54,18 @@
+
+
+
+
+
diff --git a/mobile/src/main/res/layout/fragment_status.xml b/mobile/src/main/res/layout/fragment_status.xml
index bdc9e7f68b..88411c42e2 100644
--- a/mobile/src/main/res/layout/fragment_status.xml
+++ b/mobile/src/main/res/layout/fragment_status.xml
@@ -34,13 +34,39 @@
android:textColor="?colorOnSurfaceVariant"
tools:text="Some status message" />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+