From 2d503dfaf6b48fe9dbd1d24a7e4ab0e71a6459c6 Mon Sep 17 00:00:00 2001 From: Koen <koen@pop-os.localdomain> Date: Fri, 16 Feb 2024 13:56:14 +0100 Subject: [PATCH] Added scroll to top. Full scrollable parent comment and Polycentric process secret backup and automatic database recovery. --- app/build.gradle | 12 +- .../PolycentricCreateProfileActivity.kt | 7 + .../PolycentricImportProfileActivity.kt | 7 + .../mainactivity/main/VideoDetailView.kt | 1 - .../polycentric/PolycentricStorage.kt | 42 ++++ .../platformplayer/states/StatePolycentric.kt | 72 +++++-- .../views/overlays/RepliesOverlay.kt | 5 + .../views/segments/CommentsList.kt | 11 + app/src/main/res/layout/overlay_replies.xml | 192 +++++++++--------- .../main/res/layout/view_comments_list.xml | 22 +- app/src/main/res/values/strings.xml | 1 + dep/polycentricandroid | 2 +- 12 files changed, 250 insertions(+), 124 deletions(-) create mode 100644 app/src/main/java/com/futo/platformplayer/polycentric/PolycentricStorage.kt diff --git a/app/build.gradle b/app/build.gradle index ecde6342..8d66c56c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -162,14 +162,14 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" //HTTP - implementation "com.squareup.okhttp3:okhttp:4.11.0" + implementation "com.squareup.okhttp3:okhttp:4.12.0" //JSON implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2" //Used for structured json implementation 'com.google.code.gson:gson:2.10.1' //Used for complex/anonymous cases like during development conversions (eg. V8RemoteObject) //JS - implementation("com.caoccao.javet:javet-android:3.0.2") + implementation("com.caoccao.javet:javet-android:3.0.3") //Exoplayer implementation 'androidx.media3:media3-exoplayer:1.2.1' @@ -179,8 +179,8 @@ dependencies { implementation 'androidx.media3:media3-exoplayer-rtsp:1.2.1' implementation 'androidx.media3:media3-exoplayer-smoothstreaming:1.2.1' implementation 'androidx.media3:media3-transformer:1.2.1' - implementation 'androidx.navigation:navigation-fragment-ktx:2.7.6' - implementation 'androidx.navigation:navigation-ui-ktx:2.7.6' + implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7' + implementation 'androidx.navigation:navigation-ui-ktx:2.7.7' implementation 'androidx.media:media:1.7.0' //Other @@ -189,7 +189,7 @@ dependencies { implementation 'com.google.android.flexbox:flexbox:3.0.0' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'com.arthenica:ffmpeg-kit-full:5.1' - implementation 'org.jetbrains.kotlin:kotlin-reflect:1.9.0' + implementation 'org.jetbrains.kotlin:kotlin-reflect:1.9.21' implementation 'com.github.dhaval2404:imagepicker:2.1' implementation 'com.google.zxing:core:3.4.1' implementation 'com.journeyapps:zxing-android-embedded:4.3.0' @@ -214,7 +214,7 @@ dependencies { testImplementation 'junit:junit:4.13.2' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3' - testImplementation "org.jetbrains.kotlin:kotlin-test:1.8.22" + testImplementation "org.jetbrains.kotlin:kotlin-test:1.9.21" testImplementation "org.xmlunit:xmlunit-core:2.9.1" testImplementation "org.mockito:mockito-core:5.4.0" androidTestImplementation 'androidx.test.ext:junit:1.1.5' diff --git a/app/src/main/java/com/futo/platformplayer/activities/PolycentricCreateProfileActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/PolycentricCreateProfileActivity.kt index 4986a186..078c692d 100644 --- a/app/src/main/java/com/futo/platformplayer/activities/PolycentricCreateProfileActivity.kt +++ b/app/src/main/java/com/futo/platformplayer/activities/PolycentricCreateProfileActivity.kt @@ -12,6 +12,7 @@ import com.futo.platformplayer.R import com.futo.platformplayer.UIDialogs import com.futo.platformplayer.fullyBackfillServersAnnounceExceptions import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.polycentric.PolycentricStorage import com.futo.platformplayer.setNavigationBarColorAndIcons import com.futo.platformplayer.states.StateApp import com.futo.platformplayer.states.StatePolycentric @@ -70,6 +71,12 @@ class PolycentricCreateProfileActivity : AppCompatActivity() { processHandle = ProcessHandle.create(); Store.instance.addProcessSecret(processHandle.processSecret); + try { + PolycentricStorage.instance.addProcessSecret(processHandle.processSecret) + } catch (e: Throwable) { + Logger.e(TAG, "Failed to save process secret to secret storage.", e) + } + processHandle.addServer("https://srv1-stg.polycentric.io"); processHandle.setUsername(username); StatePolycentric.instance.setProcessHandle(processHandle); diff --git a/app/src/main/java/com/futo/platformplayer/activities/PolycentricImportProfileActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/PolycentricImportProfileActivity.kt index d4a98f58..825463b3 100644 --- a/app/src/main/java/com/futo/platformplayer/activities/PolycentricImportProfileActivity.kt +++ b/app/src/main/java/com/futo/platformplayer/activities/PolycentricImportProfileActivity.kt @@ -13,6 +13,7 @@ import com.futo.platformplayer.R import com.futo.platformplayer.UIDialogs import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.polycentric.PolycentricCache +import com.futo.platformplayer.polycentric.PolycentricStorage import com.futo.platformplayer.setNavigationBarColorAndIcons import com.futo.platformplayer.states.StateApp import com.futo.platformplayer.states.StatePolycentric @@ -126,6 +127,12 @@ class PolycentricImportProfileActivity : AppCompatActivity() { val processSecret = ProcessSecret(keyPair, Process.random()); Store.instance.addProcessSecret(processSecret); + try { + PolycentricStorage.instance.addProcessSecret(processSecret) + } catch (e: Throwable) { + Logger.e(TAG, "Failed to save process secret to secret storage.", e) + } + val processHandle = processSecret.toProcessHandle(); for (e in exportBundle.events.eventsList) { diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt index fa56598c..b08b86e6 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt @@ -12,7 +12,6 @@ import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.graphics.drawable.Icon import android.net.Uri -import android.provider.Browser import android.support.v4.media.session.PlaybackStateCompat import android.text.Spanned import android.util.AttributeSet diff --git a/app/src/main/java/com/futo/platformplayer/polycentric/PolycentricStorage.kt b/app/src/main/java/com/futo/platformplayer/polycentric/PolycentricStorage.kt new file mode 100644 index 00000000..ca028ac3 --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/polycentric/PolycentricStorage.kt @@ -0,0 +1,42 @@ +package com.futo.platformplayer.polycentric + +import com.futo.platformplayer.encryption.GEncryptionProviderV1 +import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.stores.FragmentedStorage +import com.futo.platformplayer.stores.StringArrayStorage +import com.futo.polycentric.core.ProcessSecret +import com.futo.polycentric.core.base64ToByteArray +import com.futo.polycentric.core.toBase64 +import userpackage.Protocol + +class PolycentricStorage { + private val _processSecrets = FragmentedStorage.get<StringArrayStorage>("processSecrets"); + + fun addProcessSecret(processSecret: ProcessSecret) { + _processSecrets.addDistinct(GEncryptionProviderV1.instance.encrypt(processSecret.toProto().toByteArray()).toBase64()) + _processSecrets.saveBlocking() + } + + fun getProcessSecrets(): List<ProcessSecret> { + val processSecrets = arrayListOf<ProcessSecret>() + for (p in _processSecrets.getAllValues()) { + try { + processSecrets.add(ProcessSecret.fromProto(Protocol.StorageTypeProcessSecret.parseFrom(GEncryptionProviderV1.instance.decrypt(p.base64ToByteArray())))) + } catch (e: Throwable) { + Logger.i(TAG, "Failed to decrypt process secret", e); + } + } + return processSecrets + } + + companion object { + val TAG = "PolycentricStorage"; + private var _instance : PolycentricStorage? = null; + val instance : PolycentricStorage + get(){ + if(_instance == null) + _instance = PolycentricStorage(); + return _instance!!; + }; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt b/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt index b81b08c0..bed1ba3b 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt @@ -23,6 +23,7 @@ import com.futo.platformplayer.dp import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.polycentric.PolycentricCache +import com.futo.platformplayer.polycentric.PolycentricStorage import com.futo.platformplayer.resolveChannelUrl import com.futo.platformplayer.selectBestImage import com.futo.platformplayer.stores.FragmentedStorage @@ -67,28 +68,40 @@ class StatePolycentric { return } - try { - val db = SqlLiteDbHelper(context); - Store.initializeSqlLiteStore(db); + for (i in 0 .. 1) { + try { + val db = SqlLiteDbHelper(context); + Store.initializeSqlLiteStore(db); - val activeProcessHandleString = _activeProcessHandle.value; - if (activeProcessHandleString.isNotEmpty()) { - try { - val system = PublicKey.fromProto(Protocol.PublicKey.parseFrom(activeProcessHandleString.base64ToByteArray())); - setProcessHandle(Store.instance.getProcessSecret(system)?.toProcessHandle()); - } catch (e: Throwable) { - db.upgradeOldSecrets(db.writableDatabase); + val activeProcessHandleString = _activeProcessHandle.value; + if (activeProcessHandleString.isNotEmpty()) { + try { + val system = PublicKey.fromProto(Protocol.PublicKey.parseFrom(activeProcessHandleString.base64ToByteArray())); + setProcessHandle(Store.instance.getProcessSecret(system)?.toProcessHandle()); + } catch (e: Throwable) { + db.upgradeOldSecrets(db.writableDatabase); + + val system = PublicKey.fromProto(Protocol.PublicKey.parseFrom(activeProcessHandleString.base64ToByteArray())); + setProcessHandle(Store.instance.getProcessSecret(system)?.toProcessHandle()); - val system = PublicKey.fromProto(Protocol.PublicKey.parseFrom(activeProcessHandleString.base64ToByteArray())); - setProcessHandle(Store.instance.getProcessSecret(system)?.toProcessHandle()); + Log.i(TAG, "Failed to initialize Polycentric.", e) + } + } + + getProcessHandles() + break; + } catch (e: Throwable) { + if (i == 0) { + Logger.i(TAG, "Clearing Polycentric database due to corruption"); + val db = SqlLiteDbHelper(context); + db.recreate() + } else { + _transientEnabled = false + UIDialogs.showGeneralErrorDialog(context, "Failed to initialize Polycentric.", e); Log.i(TAG, "Failed to initialize Polycentric.", e) } } - } catch (e: Throwable) { - _transientEnabled = false - UIDialogs.showGeneralErrorDialog(context, "Failed to initialize Polycentric.", e); - Log.i(TAG, "Failed to initialize Polycentric.", e) } } @@ -103,7 +116,32 @@ class StatePolycentric { return listOf() } - return Store.instance.getProcessSecrets().map { it.toProcessHandle(); }; + val storeProcessSecrets = Store.instance.getProcessSecrets().toMutableList() + val processSecrets = PolycentricStorage.instance.getProcessSecrets() + + for (processSecret in processSecrets) + { + if (!storeProcessSecrets.contains(processSecret)) { + try { + Store.instance.addProcessSecret(processSecret) + } catch (e: Throwable) { + Logger.e(TAG, "Failed to backfill process secret.") + } + } + } + + for (processSecret in storeProcessSecrets) + { + if (!processSecrets.contains(processSecret)) { + try { + PolycentricStorage.instance.addProcessSecret(processSecret) + } catch (e: Throwable) { + Logger.e(TAG, "Failed to backfill process secret.") + } + } + } + + return (storeProcessSecrets + processSecrets).distinct().map { it.toProcessHandle() } } fun setProcessHandle(processHandle: ProcessHandle?) { diff --git a/app/src/main/java/com/futo/platformplayer/views/overlays/RepliesOverlay.kt b/app/src/main/java/com/futo/platformplayer/views/overlays/RepliesOverlay.kt index 19c5dd22..9d9ef35e 100644 --- a/app/src/main/java/com/futo/platformplayer/views/overlays/RepliesOverlay.kt +++ b/app/src/main/java/com/futo/platformplayer/views/overlays/RepliesOverlay.kt @@ -51,9 +51,11 @@ class RepliesOverlay : LinearLayout { private var _onCommentAdded: ((comment: IPlatformComment) -> Unit)? = null; private val _loaderOverlay: LoaderOverlay private val _client = ManagedHttpClient() + private val _layoutItems: LinearLayout constructor(context: Context, attrs: AttributeSet? = null) : super(context, attrs) { inflate(context, R.layout.overlay_replies, this) + _layoutItems = findViewById(R.id.layout_items) _topbar = findViewById(R.id.topbar); _commentsList = findViewById(R.id.comments_list); _addCommentView = findViewById(R.id.add_comment_view); @@ -65,6 +67,9 @@ class RepliesOverlay : LinearLayout { _loaderOverlay = findViewById(R.id.loader_overlay) setLoading(false); + _layoutItems.removeView(_layoutParentComment) + _commentsList.setPrependedView(_layoutParentComment) + _addCommentView.onCommentAdded.subscribe { _commentsList.addComment(it); _onCommentAdded?.invoke(it); diff --git a/app/src/main/java/com/futo/platformplayer/views/segments/CommentsList.kt b/app/src/main/java/com/futo/platformplayer/views/segments/CommentsList.kt index 57732acb..0eb95434 100644 --- a/app/src/main/java/com/futo/platformplayer/views/segments/CommentsList.kt +++ b/app/src/main/java/com/futo/platformplayer/views/segments/CommentsList.kt @@ -71,6 +71,9 @@ class CommentsList : ConstraintLayout { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy); onScrolled(); + + val totalScrollDistance = recyclerView.computeVerticalScrollOffset() + _layoutScrollToTop.visibility = if (totalScrollDistance > recyclerView.height) View.VISIBLE else View.GONE } }; @@ -82,6 +85,7 @@ class CommentsList : ConstraintLayout { private var _loading = false; private val _prependedView: FrameLayout; private var _readonly: Boolean = false; + private val _layoutScrollToTop: FrameLayout; var onRepliesClick = Event1<IPlatformComment>(); var onCommentsLoaded = Event1<Int>(); @@ -90,6 +94,13 @@ class CommentsList : ConstraintLayout { LayoutInflater.from(context).inflate(R.layout.view_comments_list, this, true); _recyclerComments = findViewById(R.id.recycler_comments); + + _layoutScrollToTop = findViewById(R.id.layout_scroll_to_top); + _layoutScrollToTop.setOnClickListener { + _recyclerComments.smoothScrollToPosition(0) + } + _layoutScrollToTop.visibility = View.GONE + _textMessage = TextView(context).apply { layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT).apply { setMargins(0, 30, 0, 0) diff --git a/app/src/main/res/layout/overlay_replies.xml b/app/src/main/res/layout/overlay_replies.xml index 51bb4b4c..f788c826 100644 --- a/app/src/main/res/layout/overlay_replies.xml +++ b/app/src/main/res/layout/overlay_replies.xml @@ -1,111 +1,108 @@ <?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" - android:background="@color/black" - xmlns:app="http://schemas.android.com/apk/res-auto"> - - <com.futo.platformplayer.views.overlays.OverlayTopbar - android:id="@+id/topbar" - android:layout_width="match_parent" - android:layout_height="40dp" - app:title="Replies" - app:metadata="3 replies" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintRight_toRightOf="parent" /> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> - <androidx.constraintlayout.widget.ConstraintLayout - android:id="@+id/layout_parent_comment" - android:layout_height="wrap_content" - android:layout_width="match_parent" - app:layout_constraintTop_toBottomOf="@id/topbar" - app:layout_constraintLeft_toLeftOf="parent" - android:layout_marginStart="12dp" - android:layout_marginEnd="12dp" - android:layout_marginTop="6dp" - android:padding="12dp" - android:background="@drawable/background_16_round_4dp"> + <LinearLayout android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/black" + android:orientation="vertical" + android:id="@+id/layout_items"> - <com.futo.platformplayer.views.others.CreatorThumbnail - android:id="@+id/image_thumbnail" - android:layout_width="25dp" - android:layout_height="25dp" - android:contentDescription="@string/channel_image" - app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintTop_toTopOf="parent" - tools:src="@drawable/placeholder_channel_thumbnail" /> + <com.futo.platformplayer.views.overlays.OverlayTopbar + android:id="@+id/topbar" + android:layout_width="match_parent" + android:layout_height="40dp" + app:title="Replies" + app:metadata="3 replies" /> - <TextView - android:id="@+id/text_author" - android:layout_width="wrap_content" + <com.futo.platformplayer.views.comments.AddCommentView + android:id="@+id/add_comment_view" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="10dp" - android:ellipsize="end" - android:gravity="center_vertical" - android:maxLines="1" - android:fontFamily="@font/inter_regular" - android:textColor="@color/white" - android:textSize="14sp" - app:layout_constraintLeft_toRightOf="@id/image_thumbnail" - app:layout_constraintTop_toTopOf="@id/image_thumbnail" - tools:text="ShortCircuit" /> + android:layout_marginTop="12dp" + android:layout_marginStart="12dp" + android:layout_marginEnd="12dp" /> - <TextView - android:id="@+id/text_metadata" - android:layout_width="0dp" + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/layout_parent_comment" android:layout_height="wrap_content" - android:ellipsize="end" - android:gravity="center_vertical" - android:maxLines="1" - android:fontFamily="@font/inter_regular" - android:textColor="@color/gray_ac" - android:textSize="14sp" - app:layout_constraintBottom_toBottomOf="@id/text_author" - app:layout_constraintLeft_toRightOf="@id/text_author" - app:layout_constraintRight_toRightOf="parent" - app:layout_constraintTop_toTopOf="@id/text_author" - tools:text=" • 3 years ago" /> + android:layout_width="match_parent" + android:layout_marginStart="12dp" + android:layout_marginEnd="12dp" + android:layout_marginBottom="12dp" + android:padding="12dp" + android:background="@drawable/background_16_round_4dp"> - <com.futo.platformplayer.views.behavior.NonScrollingTextView - android:id="@+id/text_body" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginTop="5dp" - android:layout_marginStart="10dp" - android:background="@color/transparent" - android:fontFamily="@font/inter_regular" - android:isScrollContainer="false" - android:textColor="#CCCCCC" - android:textSize="13sp" - android:maxLines="3" - android:ellipsize="end" - app:layout_constraintTop_toBottomOf="@id/text_metadata" - app:layout_constraintLeft_toRightOf="@id/image_thumbnail" - app:layout_constraintRight_toRightOf="parent" - tools:text="@string/lorem_ipsum" /> + <com.futo.platformplayer.views.others.CreatorThumbnail + android:id="@+id/image_thumbnail" + android:layout_width="25dp" + android:layout_height="25dp" + android:contentDescription="@string/channel_image" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:src="@drawable/placeholder_channel_thumbnail" /> - </androidx.constraintlayout.widget.ConstraintLayout> + <TextView + android:id="@+id/text_author" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="10dp" + android:ellipsize="end" + android:gravity="center_vertical" + android:maxLines="1" + android:fontFamily="@font/inter_regular" + android:textColor="@color/white" + android:textSize="14sp" + app:layout_constraintLeft_toRightOf="@id/image_thumbnail" + app:layout_constraintTop_toTopOf="@id/image_thumbnail" + tools:text="ShortCircuit" /> - <com.futo.platformplayer.views.comments.AddCommentView - android:id="@+id/add_comment_view" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="12dp" - android:layout_marginStart="12dp" - android:layout_marginEnd="12dp" - app:layout_constraintTop_toBottomOf="@id/layout_parent_comment" - app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintRight_toRightOf="parent" /> + <TextView + android:id="@+id/text_metadata" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:ellipsize="end" + android:gravity="center_vertical" + android:maxLines="1" + android:fontFamily="@font/inter_regular" + android:textColor="@color/gray_ac" + android:textSize="14sp" + app:layout_constraintBottom_toBottomOf="@id/text_author" + app:layout_constraintLeft_toRightOf="@id/text_author" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="@id/text_author" + tools:text=" • 3 years ago" /> - <com.futo.platformplayer.views.segments.CommentsList - android:id="@+id/comments_list" - android:layout_width="match_parent" - android:layout_height="0dp" - app:layout_constraintTop_toBottomOf="@id/add_comment_view" - app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginTop="12dp" /> + <com.futo.platformplayer.views.behavior.NonScrollingTextView + android:id="@+id/text_body" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="5dp" + android:layout_marginStart="10dp" + android:background="@color/transparent" + android:fontFamily="@font/inter_regular" + android:isScrollContainer="false" + android:textColor="#CCCCCC" + android:textSize="13sp" + android:ellipsize="end" + app:layout_constraintTop_toBottomOf="@id/text_metadata" + app:layout_constraintLeft_toRightOf="@id/image_thumbnail" + app:layout_constraintRight_toRightOf="parent" + tools:text="@string/lorem_ipsum" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <com.futo.platformplayer.views.segments.CommentsList + android:id="@+id/comments_list" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:layout_marginTop="12dp" /> + </LinearLayout> <com.futo.platformplayer.views.overlays.LoaderOverlay android:id="@+id/loader_overlay" @@ -113,5 +110,4 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:clickable="true" /> - -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file +</FrameLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/view_comments_list.xml b/app/src/main/res/layout/view_comments_list.xml index 48318415..b51feb50 100644 --- a/app/src/main/res/layout/view_comments_list.xml +++ b/app/src/main/res/layout/view_comments_list.xml @@ -7,5 +7,25 @@ android:id="@+id/recycler_comments" android:layout_width="match_parent" android:layout_height="match_parent" /> - + + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom|center_horizontal" + android:layout_marginBottom="12dp" + android:paddingBottom="7dp" + android:paddingEnd="14dp" + android:paddingTop="7dp" + android:paddingStart="14dp" + android:background="@drawable/background_pill" + android:id="@+id/layout_scroll_to_top"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/scroll_to_top" + android:textColor="@color/white" + android:fontFamily="@font/inter_regular" + android:textSize="14dp"/> + </FrameLayout> </FrameLayout> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5dc24aef..fea3d914 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -751,6 +751,7 @@ <string name="select">Select</string> <string name="zoom">Zoom</string> <string name="check_to_see_if_an_update_is_available">Check to see if an update is available.</string> + <string name="scroll_to_top">Scroll to top</string> <string-array name="home_screen_array"> <item>Recommendations</item> <item>Subscriptions</item> diff --git a/dep/polycentricandroid b/dep/polycentricandroid index 7695198e..5a61f4d0 160000 --- a/dep/polycentricandroid +++ b/dep/polycentricandroid @@ -1 +1 @@ -Subproject commit 7695198eeaeaaea4726712c460081c411ef67866 +Subproject commit 5a61f4d02527f299097a3cbea5395c5532594a24 -- GitLab