Skip to content

Commit

Permalink
MOBILE-4653 keyboard: Change keyboard events to signals
Browse files Browse the repository at this point in the history
  • Loading branch information
crazyserver committed Jan 29, 2025
1 parent 7620864 commit ac9e39e
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
OnDestroy,
Optional,
AfterViewInit,
effect,
} from '@angular/core';
import { FormControl } from '@angular/forms';
import { IonTextarea, IonContent } from '@ionic/angular';
Expand All @@ -48,6 +49,7 @@ import { CoreSwiper } from '@singletons/swiper';
import { CoreWait } from '@singletons/wait';
import { toBoolean } from '@/core/transforms/boolean';
import { CoreQRScan } from '@services/qrscan';
import { CoreKeyboard } from '@singletons/keyboard';

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

protected valueChangeSubscription?: Subscription;
protected keyboardObserver?: CoreEventObserver;
protected resetObserver?: CoreEventObserver;
protected labelObserver?: MutationObserver;
protected contentObserver?: MutationObserver;
Expand Down Expand Up @@ -176,6 +177,14 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
this.contentChanged = new EventEmitter<string>();
this.element = elementRef.nativeElement;
this.pageInstance = 'app_' + Date.now(); // Generate a "unique" ID based on timestamp.

effect(() => {
CoreKeyboard.getKeyboardShownSignal();

// Opening or closing the keyboard also calls the resize function, but sometimes the resize is called too soon.
// Check the height again, now the window height should have been updated.
this.maximizeEditorSize();
});
}

/**
Expand Down Expand Up @@ -306,12 +315,6 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
}, 50);

document.addEventListener('selectionchange', this.selectionChangeFunction);

this.keyboardObserver = CoreEvents.on(CoreEvents.KEYBOARD_CHANGE, () => {
// Opening or closing the keyboard also calls the resize function, but sometimes the resize is called too soon.
// Check the height again, now the window height should have been updated.
this.maximizeEditorSize();
});
}

/**
Expand Down Expand Up @@ -1082,7 +1085,6 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
clearTimeout(this.hideMessageTimeout);

this.resetObserver?.off();
this.keyboardObserver?.off();
this.resizeListener?.off();

this.labelObserver?.disconnect();
Expand Down
33 changes: 18 additions & 15 deletions src/core/features/mainmenu/pages/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Component, OnInit, OnDestroy, ViewChild, effect } from '@angular/core';
import { IonTabs } from '@ionic/angular';
import { BackButtonEvent } from '@ionic/core';
import { Subscription } from 'rxjs';
Expand Down Expand Up @@ -40,6 +40,7 @@ import {
MAIN_MENU_HANDLER_BADGE_UPDATED_EVENT,
MAIN_MENU_VISIBILITY_UPDATED_EVENT,
} from '@features/mainmenu/constants';
import { CoreKeyboard } from '@singletons/keyboard';

const ANIMATION_DURATION = 500;

Expand Down Expand Up @@ -109,6 +110,22 @@ export class CoreMainMenuPage implements OnInit, OnDestroy {
this.isMainScreen = !this.mainTabs?.outlet.canGoBack();
this.updateVisibility();
});

if (CorePlatform.isIOS()) {
effect(() => {
const shown = CoreKeyboard.getKeyboardShownSignal();
// In iOS, the resize event is triggered before the keyboard is opened/closed and not triggered again once done.
// Init handlers again once keyboard is closed since the resize event doesn't have the updated height.
if (!shown) {
this.updateHandlers();

// If the device is slow it can take a bit more to update the window height. Retry in a few ms.
setTimeout(() => {
this.updateHandlers();
}, 250);
}
});
}
}

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

if (CorePlatform.isIOS()) {
// In iOS, the resize event is triggered before the keyboard is opened/closed and not triggered again once done.
// Init handlers again once keyboard is closed since the resize event doesn't have the updated height.
this.keyboardObserver = CoreEvents.on(CoreEvents.KEYBOARD_CHANGE, (kbHeight: number) => {
if (kbHeight === 0) {
this.updateHandlers();

// If the device is slow it can take a bit more to update the window height. Retry in a few ms.
setTimeout(() => {
this.updateHandlers();
}, 250);
}
});
}
CoreEvents.trigger(CoreEvents.MAIN_HOME_LOADED);
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/initializers/subscribe-to-keyboard-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ export default function(): void {
// Execute callbacks in the Angular zone, so change detection doesn't stop working.
keyboard.onKeyboardShow().subscribe(data => zone.run(() => CoreKeyboard.onKeyboardShow(data.keyboardHeight)));
keyboard.onKeyboardHide().subscribe(() => zone.run(() => CoreKeyboard.onKeyboardHide()));
keyboard.onKeyboardWillShow().subscribe(() => zone.run(() => CoreKeyboard.onKeyboardWillShow()));
keyboard.onKeyboardWillShow().subscribe((data) => zone.run(() => CoreKeyboard.onKeyboardWillShow(data.keyboardHeight)));
keyboard.onKeyboardWillHide().subscribe(() => zone.run(() => CoreKeyboard.onKeyboardWillHide()));
}
2 changes: 1 addition & 1 deletion src/core/services/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export class CoreAppProvider {
/**
* Closes the keyboard.
*
* @deprecated sinde 4.5.0. Use CoreKeyboard.closeKeyboard instead.
* @deprecated since 4.5.0. Use CoreKeyboard.closeKeyboard instead.
*/
closeKeyboard(): void {
CoreKeyboard.close();
Expand Down
3 changes: 3 additions & 0 deletions src/core/singletons/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ export class CoreEvents {
static readonly IAB_MESSAGE = 'inappbrowser_message';
static readonly APP_LAUNCHED_URL = 'app_launched_url'; // App opened with a certain URL (custom URL scheme).
static readonly FILE_SHARED = 'file_shared';
/**
* @deprecated since 5.0.0. Use CoreKeyboard.getKeyboardShownSignal signal.
*/
static readonly KEYBOARD_CHANGE = 'keyboard_change';
static readonly ORIENTATION_CHANGE = 'orientation_change';
static readonly SEND_ON_ENTER_CHANGED = 'send_on_enter_changed';
Expand Down
67 changes: 44 additions & 23 deletions src/core/singletons/keyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { effect, Signal, signal } from '@angular/core';
import { CorePlatform } from '@services/platform';
import { Keyboard } from '@singletons';
import { CoreEvents } from '@singletons/events';
Expand All @@ -21,13 +22,16 @@ import { CoreEvents } from '@singletons/events';
*/
export class CoreKeyboard {

protected static isKeyboardShown = false;
protected static keyboardOpening = false;
protected static keyboardClosing = false;
protected static isKeyboardShown = signal(false);
protected static keyboardOpening = signal(false);
protected static keyboardClosing = signal(false);
protected static keyboardHeight = signal(0);

// Avoid creating singleton instances.
private constructor() {
// Nothing to do.
effect(() => {
document.body.classList.toggle('keyboard-is-open', CoreKeyboard.isKeyboardShown());
});
}

/**
Expand All @@ -49,53 +53,70 @@ export class CoreKeyboard {
}
}

static getKeyboardShownSignal(): Signal<boolean> {
return CoreKeyboard.isKeyboardShown.asReadonly();
}

static getKeyboardHeightSignal(): Signal<number> {
return CoreKeyboard.keyboardHeight.asReadonly();
}

/**
* Notify that Keyboard has been shown.
*
* @param keyboardHeight Keyboard height.
*/
static onKeyboardShow(keyboardHeight: number): void {
document.body.classList.add('keyboard-is-open');
CoreKeyboard.setKeyboardShown(true);
// Error on iOS calculating size.
// More info: https://github.com/ionic-team/ionic-plugin-keyboard/issues/276 .
CoreEvents.trigger(CoreEvents.KEYBOARD_CHANGE, keyboardHeight);
// More info: https://github.com/ionic-team/ionic-plugin-keyboard/issues/276
CoreKeyboard.setKeyboardShown(true, keyboardHeight);
}

/**
* Notify that Keyboard has been hidden.
*/
static onKeyboardHide(): void {
document.body.classList.remove('keyboard-is-open');
CoreKeyboard.setKeyboardShown(false);
CoreEvents.trigger(CoreEvents.KEYBOARD_CHANGE, 0);
CoreKeyboard.setKeyboardShown(false, 0);
}

/**
* Notify that Keyboard is about to be shown.
*
* @param keyboardHeight Keyboard height.
*/
static onKeyboardWillShow(): void {
CoreKeyboard.keyboardOpening = true;
CoreKeyboard.keyboardClosing = false;
static onKeyboardWillShow(keyboardHeight?: number): void {
CoreKeyboard.keyboardOpening.set(true);
CoreKeyboard.keyboardClosing.set(false);

if (keyboardHeight !== undefined) {
this.keyboardHeight.set(keyboardHeight);
}
}

/**
* Notify that Keyboard is about to be hidden.
*/
static onKeyboardWillHide(): void {
CoreKeyboard.keyboardOpening = false;
CoreKeyboard.keyboardClosing = true;
CoreKeyboard.keyboardOpening.set(false);
CoreKeyboard.keyboardClosing.set(true);

this.keyboardHeight.set(0);
}

/**
* Set keyboard shown or hidden.
*
* @param shown Whether the keyboard is shown or hidden.
* @param keyboardHeight Keyboard height.
*/
protected static setKeyboardShown(shown: boolean): void {
CoreKeyboard.isKeyboardShown = shown;
CoreKeyboard.keyboardOpening = false;
CoreKeyboard.keyboardClosing = false;
protected static setKeyboardShown(shown: boolean, keyboardHeight: number): void {
CoreKeyboard.isKeyboardShown.set(shown);
CoreKeyboard.keyboardOpening.set(false);
CoreKeyboard.keyboardClosing.set(false);
this.keyboardHeight.set(keyboardHeight);

// eslint-disable-next-line deprecation/deprecation
CoreEvents.trigger(CoreEvents.KEYBOARD_CHANGE, keyboardHeight);
}

/**
Expand All @@ -104,7 +125,7 @@ export class CoreKeyboard {
* @returns Whether keyboard is closing (animating).
*/
static isKeyboardClosing(): boolean {
return CoreKeyboard.keyboardClosing;
return CoreKeyboard.keyboardClosing();
}

/**
Expand All @@ -113,7 +134,7 @@ export class CoreKeyboard {
* @returns Whether keyboard is opening (animating).
*/
static isKeyboardOpening(): boolean {
return CoreKeyboard.keyboardOpening;
return CoreKeyboard.keyboardOpening();
}

/**
Expand All @@ -122,7 +143,7 @@ export class CoreKeyboard {
* @returns Whether keyboard is visible.
*/
static isKeyboardVisible(): boolean {
return CoreKeyboard.isKeyboardShown;
return CoreKeyboard.isKeyboardShown();
}

}

0 comments on commit ac9e39e

Please sign in to comment.