From 900ee4f31c0815ae1d72a51e5ae0bd3e70b34223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 23 Jan 2025 15:32:49 +0100 Subject: [PATCH 1/3] MOBILE-4687 comments: Scroll to bottom when opening keyboard --- scripts/langindex.json | 1 - src/core/features/comments/lang.json | 1 - .../features/comments/pages/viewer/viewer.ts | 67 ++++++++++++------- .../comments/tests/behat/basic_usage.feature | 13 ++-- 4 files changed, 48 insertions(+), 34 deletions(-) diff --git a/scripts/langindex.json b/scripts/langindex.json index 272d14f62e8..08759b89d9b 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -1558,7 +1558,6 @@ "core.comments.commentscount": "moodle", "core.comments.commentsnotworking": "local_moodlemobileapp", "core.comments.deletecommentbyon": "moodle", - "core.comments.eventcommentcreated": "moodle", "core.comments.eventcommentdeleted": "moodle", "core.comments.nocomments": "moodle", "core.comments.savecomment": "moodle", diff --git a/src/core/features/comments/lang.json b/src/core/features/comments/lang.json index 1ff89ef1ff8..e5a1140e751 100644 --- a/src/core/features/comments/lang.json +++ b/src/core/features/comments/lang.json @@ -4,7 +4,6 @@ "commentscount": "Comments ({{$a}})", "commentsnotworking": "Comments cannot be retrieved", "deletecommentbyon": "Delete comment posted by {{$a.user}} on {{$a.time}}", - "eventcommentcreated": "Comment created", "eventcommentdeleted": "Comment deleted", "nocomments": "No comments", "savecomment": "Save comment", diff --git a/src/core/features/comments/pages/viewer/viewer.ts b/src/core/features/comments/pages/viewer/viewer.ts index f1c02a17454..5de3365d54f 100644 --- a/src/core/features/comments/pages/viewer/viewer.ts +++ b/src/core/features/comments/pages/viewer/viewer.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Component, OnDestroy, OnInit, ViewChild, AfterViewInit } from '@angular/core'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { ActivatedRoute } from '@angular/router'; import { CoreSites } from '@services/sites'; @@ -40,11 +40,12 @@ import { CoreNetwork } from '@services/network'; import moment from 'moment-timezone'; import { Subscription } from 'rxjs'; import { CoreAnimations } from '@components/animations'; -import { CoreKeyboard } from '@singletons/keyboard'; import { CoreToasts, ToastDuration } from '@services/overlays/toasts'; import { CoreLoadings } from '@services/overlays/loadings'; import { CORE_COMMENTS_AUTO_SYNCED } from '@features/comments/constants'; import { CoreAlerts } from '@services/overlays/alerts'; +import { CoreWait } from '@singletons/wait'; +import { CoreDom } from '@singletons/dom'; /** * Page that displays comments. @@ -55,7 +56,7 @@ import { CoreAlerts } from '@services/overlays/alerts'; animations: [CoreAnimations.SLIDE_IN_OUT], styleUrls: ['../../../../../theme/components/discussion.scss', 'viewer.scss'], }) -export class CoreCommentsViewerPage implements OnInit, OnDestroy { +export class CoreCommentsViewerPage implements OnInit, OnDestroy, AfterViewInit { @ViewChild(IonContent) content?: IonContent; @@ -86,7 +87,10 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { protected addDeleteCommentsAvailable = false; protected syncObserver?: CoreEventObserver; protected onlineObserver: Subscription; + protected keyboardObserver: CoreEventObserver; protected viewDestroyed = false; + protected scrollBottom = true; + protected scrollElement?: HTMLElement; constructor( protected route: ActivatedRoute, @@ -118,6 +122,11 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { this.isOnline = CoreNetwork.isOnline(); }); }); + + this.keyboardObserver = CoreEvents.on(CoreEvents.KEYBOARD_CHANGE, (keyboardHeight: number) => { + // Force when opening. + this.scrollToBottom(keyboardHeight > 0); + }); } /** @@ -150,6 +159,13 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { await this.fetchComments(true); } + /** + * View has been initialized. + */ + async ngAfterViewInit(): Promise { + this.scrollElement = await this.content?.getScrollElement(); + } + /** * Fetches the comments. * @@ -164,6 +180,8 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { await CorePromiseUtils.ignoreErrors(this.syncComments(showErrors)); } + this.scrollBottom = CoreDom.scrollIsBottom(this.scrollElement, 5); + try { // Get comments data. const commentsResponse = await CoreComments.getComments( @@ -210,9 +228,7 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { this.refreshIcon = CoreConstants.ICON_REFRESH; this.syncIcon = CoreConstants.ICON_SYNC; - if (this.page == 0) { - this.scrollToBottom(); - } + this.scrollToBottom(this.page === 0); } } @@ -314,7 +330,6 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { * @param text Comment text to add. */ async addComment(text: string): Promise { - CoreKeyboard.close(); const loadingModal = await CoreLoadings.show('core.sending', true); // Freeze the add comment button. this.sending = true; @@ -328,14 +343,6 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { this.area, ); - CoreToasts.show({ - message: commentsResponse ? 'core.comments.eventcommentcreated' : 'core.datastoredoffline', - translateMessage: true, - duration: ToastDuration.LONG, - position: 'bottom', - positionAnchor: 'viewer-footer', - }); - if (commentsResponse) { this.invalidateComments(); @@ -364,11 +371,11 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { } catch (error) { CoreAlerts.showError(error); } finally { - loadingModal.dismiss(); this.sending = false; + await loadingModal.dismiss(); // New comments. - this.scrollToBottom(); + this.scrollToBottom(true); } } @@ -604,14 +611,25 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { /** * Scroll bottom when render has finished. + * + * @param force Whether to force scroll to bottom. */ - protected scrollToBottom(): void { - // Need a timeout to leave time to the view to be rendered. - setTimeout(() => { - if (!this.viewDestroyed) { - this.content?.scrollToBottom(); - } - }, 100); + protected async scrollToBottom(force = false): Promise { + if (this.viewDestroyed) { + return; + } + + // Check if scroll is at bottom. If so, scroll bottom after rendering since there might be something new. + if (!this.scrollBottom && !force) { + return; + } + + // Leave time for the view to be rendered. + await CoreWait.nextTicks(5); + + if (!this.viewDestroyed && this.content) { + this.content.scrollToBottom(0); + } } /** @@ -650,6 +668,7 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { this.syncObserver?.off(); this.onlineObserver.unsubscribe(); this.viewDestroyed = true; + this.keyboardObserver.off(); } } diff --git a/src/core/features/comments/tests/behat/basic_usage.feature b/src/core/features/comments/tests/behat/basic_usage.feature index ef8c80588e2..6c41adf3ecc 100644 --- a/src/core/features/comments/tests/behat/basic_usage.feature +++ b/src/core/features/comments/tests/behat/basic_usage.feature @@ -38,8 +38,8 @@ Feature: Test basic usage of comments in app And I press "Comments (0)" in the app And I set the field "Add a comment..." to "comment test teacher" in the app And I press "Send" in the app - Then I should find "Comment created" in the app And I should find "comment test teacher" in the app + And I should not find "There are offline comments to be synchronised" in the app When I go back in the app And I should find "Comments (1)" in the app @@ -51,9 +51,9 @@ Feature: Test basic usage of comments in app And I press "Comments (1)" in the app And I set the field "Add a comment..." to "comment test student" in the app And I press "Send" in the app - Then I should find "Comment created" in the app And I should find "comment test teacher" in the app And I should find "comment test student" in the app + And I should not find "There are offline comments to be synchronised" in the app When I go back in the app And I press "Comments (2)" in the app @@ -78,7 +78,6 @@ Feature: Test basic usage of comments in app And I switch network connection to offline And I set the field "Add a comment..." to "comment test" in the app And I press "Send" in the app - Then I should find "Data stored in the device because it couldn't be sent. It will be sent automatically later." in the app And I should find "There are offline comments to be synchronised." in the app And I should find "comment test" in the app @@ -126,8 +125,8 @@ Feature: Test basic usage of comments in app And I press "Comments (0)" in the app And I set the field "Add a comment..." to "comment test teacher" in the app And I press "Send" in the app - Then I should find "Comment created" in the app And I should find "comment test teacher" in the app + And I should not find "There are offline comments to be synchronised" in the app And I go back in the app And I should find "Comments (1)" in the app @@ -138,9 +137,9 @@ Feature: Test basic usage of comments in app And I press "Comments (1)" in the app And I set the field "Add a comment..." to "comment test student" in the app And I press "Send" in the app - Then I should find "Comment created" in the app And I should find "comment test teacher" in the app And I should find "comment test student" in the app + And I should not find "There are offline comments to be synchronised" in the app When I go back in the app And I press "Comments (2)" in the app @@ -166,7 +165,6 @@ Feature: Test basic usage of comments in app And I switch network connection to offline And I set the field "Add a comment..." to "comment test" in the app And I press "Send" in the app - Then I should find "Data stored in the device because it couldn't be sent. It will be sent automatically later." in the app And I should find "There are offline comments to be synchronised." in the app And I should find "comment test" in the app @@ -218,8 +216,8 @@ Feature: Test basic usage of comments in app When I press "Comments (0)" in the app And I set the field "Add a comment..." to "comment test" in the app And I press "Send" in the app - Then I should find "Comment created" in the app And I should find "comment test" in the app + And I should not find "There are offline comments to be synchronised" in the app When I go back in the app And I press "Comments (1)" in the app @@ -249,7 +247,6 @@ Feature: Test basic usage of comments in app And I switch network connection to offline And I set the field "Add a comment..." to "comment test" in the app And I press "Send" in the app - Then I should find "Data stored in the device because it couldn't be sent. It will be sent automatically later." in the app And I should find "There are offline comments to be synchronised." in the app And I should find "comment test" in the app From 58293dbcd580baa9b75957a8645bb6543b5473ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Tue, 28 Jan 2025 08:59:53 +0100 Subject: [PATCH 2/3] MOBILE-4687 combobox: Improve how selection is shown --- src/core/components/combobox/core-combobox.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/components/combobox/core-combobox.html b/src/core/components/combobox/core-combobox.html index 0ce11bc9a6c..7b82ff63f64 100644 --- a/src/core/components/combobox/core-combobox.html +++ b/src/core/components/combobox/core-combobox.html @@ -15,7 +15,7 @@ {{ label }},
- {{selection}} +