Skip to content

Commit a0507b8

Browse files
committed
MOBILE-4653 keyboard: Change keyboard events to signals
1 parent a408c24 commit a0507b8

File tree

7 files changed

+85
-54
lines changed

7 files changed

+85
-54
lines changed

src/core/features/comments/pages/viewer/viewer.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import { Component, OnDestroy, OnInit, ViewChild, AfterViewInit } from '@angular/core';
15+
import { Component, OnDestroy, OnInit, ViewChild, AfterViewInit, effect } from '@angular/core';
1616
import { CoreEventObserver, CoreEvents } from '@singletons/events';
1717
import { ActivatedRoute } from '@angular/router';
1818
import { CoreSites } from '@services/sites';
@@ -46,6 +46,7 @@ import { CORE_COMMENTS_AUTO_SYNCED } from '@features/comments/constants';
4646
import { CoreAlerts } from '@services/overlays/alerts';
4747
import { CoreWait } from '@singletons/wait';
4848
import { CoreDom } from '@singletons/dom';
49+
import { CoreKeyboard } from '@singletons/keyboard';
4950

5051
/**
5152
* Page that displays comments.
@@ -87,7 +88,6 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy, AfterViewInit
8788
protected addDeleteCommentsAvailable = false;
8889
protected syncObserver?: CoreEventObserver;
8990
protected onlineObserver: Subscription;
90-
protected keyboardObserver: CoreEventObserver;
9191
protected viewDestroyed = false;
9292
protected scrollBottom = true;
9393
protected scrollElement?: HTMLElement;
@@ -123,9 +123,11 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy, AfterViewInit
123123
});
124124
});
125125

126-
this.keyboardObserver = CoreEvents.on(CoreEvents.KEYBOARD_CHANGE, (keyboardHeight: number) => {
127-
// Force when opening.
128-
this.scrollToBottom(keyboardHeight > 0);
126+
effect(() => {
127+
const shown = CoreKeyboard.getKeyboardShownSignal();
128+
129+
/// Force when opening.
130+
this.scrollToBottom(shown());
129131
});
130132
}
131133

@@ -668,7 +670,6 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy, AfterViewInit
668670
this.syncObserver?.off();
669671
this.onlineObserver.unsubscribe();
670672
this.viewDestroyed = true;
671-
this.keyboardObserver.off();
672673
}
673674

674675
}

src/core/features/editor/components/rich-text-editor/rich-text-editor.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
OnDestroy,
2424
Optional,
2525
AfterViewInit,
26+
effect,
2627
} from '@angular/core';
2728
import { FormControl } from '@angular/forms';
2829
import { IonTextarea, IonContent } from '@ionic/angular';
@@ -48,6 +49,7 @@ import { CoreSwiper } from '@singletons/swiper';
4849
import { CoreWait } from '@singletons/wait';
4950
import { toBoolean } from '@/core/transforms/boolean';
5051
import { CoreQRScan } from '@services/qrscan';
52+
import { CoreKeyboard } from '@singletons/keyboard';
5153

5254
/**
5355
* Component to display a rich text editor if enabled.
@@ -115,7 +117,6 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
115117
protected minHeight = 200; // Minimum height of the editor.
116118

117119
protected valueChangeSubscription?: Subscription;
118-
protected keyboardObserver?: CoreEventObserver;
119120
protected resetObserver?: CoreEventObserver;
120121
protected labelObserver?: MutationObserver;
121122
protected contentObserver?: MutationObserver;
@@ -176,6 +177,15 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
176177
this.contentChanged = new EventEmitter<string>();
177178
this.element = elementRef.nativeElement;
178179
this.pageInstance = 'app_' + Date.now(); // Generate a "unique" ID based on timestamp.
180+
181+
effect(() => {
182+
// Signal will be triggered when the keyboard is shown or hidden.
183+
CoreKeyboard.getKeyboardShownSignal();
184+
185+
// Opening or closing the keyboard also calls the resize function, but sometimes the resize is called too soon.
186+
// Check the height again, now the window height should have been updated.
187+
this.maximizeEditorSize();
188+
});
179189
}
180190

181191
/**
@@ -306,12 +316,6 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
306316
}, 50);
307317

308318
document.addEventListener('selectionchange', this.selectionChangeFunction);
309-
310-
this.keyboardObserver = CoreEvents.on(CoreEvents.KEYBOARD_CHANGE, () => {
311-
// Opening or closing the keyboard also calls the resize function, but sometimes the resize is called too soon.
312-
// Check the height again, now the window height should have been updated.
313-
this.maximizeEditorSize();
314-
});
315319
}
316320

317321
/**
@@ -1082,7 +1086,6 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
10821086
clearTimeout(this.hideMessageTimeout);
10831087

10841088
this.resetObserver?.off();
1085-
this.keyboardObserver?.off();
10861089
this.resizeListener?.off();
10871090

10881091
this.labelObserver?.disconnect();

src/core/features/mainmenu/pages/menu/menu.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
15+
import { Component, OnInit, OnDestroy, ViewChild, effect } from '@angular/core';
1616
import { IonTabs } from '@ionic/angular';
1717
import { BackButtonEvent } from '@ionic/core';
1818
import { Subscription } from 'rxjs';
@@ -40,6 +40,7 @@ import {
4040
MAIN_MENU_HANDLER_BADGE_UPDATED_EVENT,
4141
MAIN_MENU_VISIBILITY_UPDATED_EVENT,
4242
} from '@features/mainmenu/constants';
43+
import { CoreKeyboard } from '@singletons/keyboard';
4344

4445
const ANIMATION_DURATION = 500;
4546

@@ -109,6 +110,22 @@ export class CoreMainMenuPage implements OnInit, OnDestroy {
109110
this.isMainScreen = !this.mainTabs?.outlet.canGoBack();
110111
this.updateVisibility();
111112
});
113+
114+
if (CorePlatform.isIOS()) {
115+
effect(() => {
116+
const shown = CoreKeyboard.getKeyboardShownSignal();
117+
// In iOS, the resize event is triggered before the keyboard is opened/closed and not triggered again once done.
118+
// Init handlers again once keyboard is closed since the resize event doesn't have the updated height.
119+
if (!shown) {
120+
this.updateHandlers();
121+
122+
// If the device is slow it can take a bit more to update the window height. Retry in a few ms.
123+
setTimeout(() => {
124+
this.updateHandlers();
125+
}, 250);
126+
}
127+
});
128+
}
112129
}
113130

114131
/**
@@ -140,20 +157,6 @@ export class CoreMainMenuPage implements OnInit, OnDestroy {
140157
});
141158
document.addEventListener('ionBackButton', this.backButtonFunction);
142159

143-
if (CorePlatform.isIOS()) {
144-
// In iOS, the resize event is triggered before the keyboard is opened/closed and not triggered again once done.
145-
// Init handlers again once keyboard is closed since the resize event doesn't have the updated height.
146-
this.keyboardObserver = CoreEvents.on(CoreEvents.KEYBOARD_CHANGE, (kbHeight: number) => {
147-
if (kbHeight === 0) {
148-
this.updateHandlers();
149-
150-
// If the device is slow it can take a bit more to update the window height. Retry in a few ms.
151-
setTimeout(() => {
152-
this.updateHandlers();
153-
}, 250);
154-
}
155-
});
156-
}
157160
CoreEvents.trigger(CoreEvents.MAIN_HOME_LOADED);
158161
}
159162

src/core/initializers/subscribe-to-keyboard-events.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ export default function(): void {
2525
// Execute callbacks in the Angular zone, so change detection doesn't stop working.
2626
keyboard.onKeyboardShow().subscribe(data => zone.run(() => CoreKeyboard.onKeyboardShow(data.keyboardHeight)));
2727
keyboard.onKeyboardHide().subscribe(() => zone.run(() => CoreKeyboard.onKeyboardHide()));
28-
keyboard.onKeyboardWillShow().subscribe(() => zone.run(() => CoreKeyboard.onKeyboardWillShow()));
28+
keyboard.onKeyboardWillShow().subscribe((data) => zone.run(() => CoreKeyboard.onKeyboardWillShow(data.keyboardHeight)));
2929
keyboard.onKeyboardWillHide().subscribe(() => zone.run(() => CoreKeyboard.onKeyboardWillHide()));
3030
}

src/core/services/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export class CoreAppProvider {
9090
/**
9191
* Closes the keyboard.
9292
*
93-
* @deprecated sinde 4.5.0. Use CoreKeyboard.closeKeyboard instead.
93+
* @deprecated since 4.5.0. Use CoreKeyboard.closeKeyboard instead.
9494
*/
9595
closeKeyboard(): void {
9696
CoreKeyboard.close();

src/core/singletons/events.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ export class CoreEvents {
104104
static readonly IAB_MESSAGE = 'inappbrowser_message';
105105
static readonly APP_LAUNCHED_URL = 'app_launched_url'; // App opened with a certain URL (custom URL scheme).
106106
static readonly FILE_SHARED = 'file_shared';
107+
/**
108+
* @deprecated since 5.0.0. Use CoreKeyboard.getKeyboardShownSignal signal.
109+
*/
107110
static readonly KEYBOARD_CHANGE = 'keyboard_change';
108111
static readonly ORIENTATION_CHANGE = 'orientation_change';
109112
static readonly SEND_ON_ENTER_CHANGED = 'send_on_enter_changed';

src/core/singletons/keyboard.ts

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
import { effect, Signal, signal } from '@angular/core';
1516
import { CorePlatform } from '@services/platform';
1617
import { Keyboard } from '@singletons';
1718
import { CoreEvents } from '@singletons/events';
@@ -21,13 +22,16 @@ import { CoreEvents } from '@singletons/events';
2122
*/
2223
export class CoreKeyboard {
2324

24-
protected static isKeyboardShown = false;
25-
protected static keyboardOpening = false;
26-
protected static keyboardClosing = false;
25+
protected static isKeyboardShown = signal(false);
26+
protected static keyboardOpening = signal(false);
27+
protected static keyboardClosing = signal(false);
28+
protected static keyboardHeight = signal(0);
2729

2830
// Avoid creating singleton instances.
2931
private constructor() {
30-
// Nothing to do.
32+
effect(() => {
33+
document.body.classList.toggle('keyboard-is-open', CoreKeyboard.isKeyboardShown());
34+
});
3135
}
3236

3337
/**
@@ -49,53 +53,70 @@ export class CoreKeyboard {
4953
}
5054
}
5155

56+
static getKeyboardShownSignal(): Signal<boolean> {
57+
return CoreKeyboard.isKeyboardShown.asReadonly();
58+
}
59+
60+
static getKeyboardHeightSignal(): Signal<number> {
61+
return CoreKeyboard.keyboardHeight.asReadonly();
62+
}
63+
5264
/**
5365
* Notify that Keyboard has been shown.
5466
*
5567
* @param keyboardHeight Keyboard height.
5668
*/
5769
static onKeyboardShow(keyboardHeight: number): void {
58-
document.body.classList.add('keyboard-is-open');
59-
CoreKeyboard.setKeyboardShown(true);
6070
// Error on iOS calculating size.
61-
// More info: https://github.com/ionic-team/ionic-plugin-keyboard/issues/276 .
62-
CoreEvents.trigger(CoreEvents.KEYBOARD_CHANGE, keyboardHeight);
71+
// More info: https://github.com/ionic-team/ionic-plugin-keyboard/issues/276
72+
CoreKeyboard.setKeyboardShown(true, keyboardHeight);
6373
}
6474

6575
/**
6676
* Notify that Keyboard has been hidden.
6777
*/
6878
static onKeyboardHide(): void {
69-
document.body.classList.remove('keyboard-is-open');
70-
CoreKeyboard.setKeyboardShown(false);
71-
CoreEvents.trigger(CoreEvents.KEYBOARD_CHANGE, 0);
79+
CoreKeyboard.setKeyboardShown(false, 0);
7280
}
7381

7482
/**
7583
* Notify that Keyboard is about to be shown.
84+
*
85+
* @param keyboardHeight Keyboard height.
7686
*/
77-
static onKeyboardWillShow(): void {
78-
CoreKeyboard.keyboardOpening = true;
79-
CoreKeyboard.keyboardClosing = false;
87+
static onKeyboardWillShow(keyboardHeight?: number): void {
88+
CoreKeyboard.keyboardOpening.set(true);
89+
CoreKeyboard.keyboardClosing.set(false);
90+
91+
if (keyboardHeight !== undefined) {
92+
this.keyboardHeight.set(keyboardHeight);
93+
}
8094
}
8195

8296
/**
8397
* Notify that Keyboard is about to be hidden.
8498
*/
8599
static onKeyboardWillHide(): void {
86-
CoreKeyboard.keyboardOpening = false;
87-
CoreKeyboard.keyboardClosing = true;
100+
CoreKeyboard.keyboardOpening.set(false);
101+
CoreKeyboard.keyboardClosing.set(true);
102+
103+
this.keyboardHeight.set(0);
88104
}
89105

90106
/**
91107
* Set keyboard shown or hidden.
92108
*
93109
* @param shown Whether the keyboard is shown or hidden.
110+
* @param keyboardHeight Keyboard height.
94111
*/
95-
protected static setKeyboardShown(shown: boolean): void {
96-
CoreKeyboard.isKeyboardShown = shown;
97-
CoreKeyboard.keyboardOpening = false;
98-
CoreKeyboard.keyboardClosing = false;
112+
protected static setKeyboardShown(shown: boolean, keyboardHeight: number): void {
113+
CoreKeyboard.isKeyboardShown.set(shown);
114+
CoreKeyboard.keyboardOpening.set(false);
115+
CoreKeyboard.keyboardClosing.set(false);
116+
this.keyboardHeight.set(keyboardHeight);
117+
118+
// eslint-disable-next-line deprecation/deprecation
119+
CoreEvents.trigger(CoreEvents.KEYBOARD_CHANGE, keyboardHeight);
99120
}
100121

101122
/**
@@ -104,7 +125,7 @@ export class CoreKeyboard {
104125
* @returns Whether keyboard is closing (animating).
105126
*/
106127
static isKeyboardClosing(): boolean {
107-
return CoreKeyboard.keyboardClosing;
128+
return CoreKeyboard.keyboardClosing();
108129
}
109130

110131
/**
@@ -113,7 +134,7 @@ export class CoreKeyboard {
113134
* @returns Whether keyboard is opening (animating).
114135
*/
115136
static isKeyboardOpening(): boolean {
116-
return CoreKeyboard.keyboardOpening;
137+
return CoreKeyboard.keyboardOpening();
117138
}
118139

119140
/**
@@ -122,7 +143,7 @@ export class CoreKeyboard {
122143
* @returns Whether keyboard is visible.
123144
*/
124145
static isKeyboardVisible(): boolean {
125-
return CoreKeyboard.isKeyboardShown;
146+
return CoreKeyboard.isKeyboardShown();
126147
}
127148

128149
}

0 commit comments

Comments
 (0)