mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
feat: activityBackPressed handling with OnBackPressedCallback
This commit is contained in:
@@ -24,7 +24,8 @@ import * as Utils from '../../../utils';
|
||||
import { SDK_VERSION } from '../../../utils/constants';
|
||||
import { BoxShadow } from '../../styling/box-shadow';
|
||||
import { NativeScriptAndroidView } from '../../utils';
|
||||
|
||||
import { Device } from '../../../platform';
|
||||
import { Frame } from '../../frame';
|
||||
export * from './view-common';
|
||||
// helpers (these are okay re-exported here)
|
||||
export * from './view-helper';
|
||||
@@ -52,6 +53,42 @@ const GRAVITY_FILL_VERTICAL = 112; // android.view.Gravity.FILL_VERTICAL
|
||||
|
||||
const modalMap = new Map<number, DialogOptions>();
|
||||
|
||||
let OnBackPressedCallback;
|
||||
if (parseInt(Device.sdkVersion) >= 33) {
|
||||
OnBackPressedCallback = (<any>androidx.activity.OnBackPressedCallback).extend({
|
||||
handleOnBackPressed() {
|
||||
const dialog = this['_dialog']?.get();
|
||||
if (!dialog) {
|
||||
// disable the callback and call super to avoid infinite loop
|
||||
this.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const view = dialog.fragment.owner;
|
||||
const args = <AndroidActivityBackPressedEventData>{
|
||||
eventName: 'activityBackPressed',
|
||||
object: view,
|
||||
activity: view._context,
|
||||
cancel: false,
|
||||
};
|
||||
|
||||
// Fist fire application.android global event
|
||||
Application.android.notify(args);
|
||||
if (args.cancel) {
|
||||
return;
|
||||
}
|
||||
|
||||
view.notify(args);
|
||||
|
||||
if (!args.cancel) {
|
||||
this.setEnabled(false);
|
||||
dialog.getOnBackPressedDispatcher().onBackPressed();
|
||||
this.setEnabled(true);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let TouchListener: TouchListener;
|
||||
let DialogFragment: DialogFragment;
|
||||
|
||||
@@ -115,13 +152,21 @@ function initializeDialogFragment() {
|
||||
}
|
||||
|
||||
@NativeClass
|
||||
class DialogImpl extends android.app.Dialog {
|
||||
class DialogImpl extends androidx.appcompat.app.AppCompatDialog {
|
||||
constructor(
|
||||
public fragment: DialogFragmentImpl,
|
||||
context: android.content.Context,
|
||||
themeResId: number,
|
||||
) {
|
||||
super(context, themeResId);
|
||||
// @ts-ignore
|
||||
|
||||
if (parseInt(Device.sdkVersion) >= 33 && OnBackPressedCallback) {
|
||||
const callback = new OnBackPressedCallback(true);
|
||||
callback['_dialog'] = new WeakRef(this);
|
||||
// @ts-ignore
|
||||
this.getOnBackPressedDispatcher().addCallback(this, callback);
|
||||
}
|
||||
|
||||
return global.__native(this);
|
||||
}
|
||||
@@ -132,6 +177,10 @@ function initializeDialogFragment() {
|
||||
}
|
||||
|
||||
public onBackPressed(): void {
|
||||
if (parseInt(Device.sdkVersion) >= 33) {
|
||||
super.onBackPressed();
|
||||
return;
|
||||
}
|
||||
const view = this.fragment.owner;
|
||||
const args = <AndroidActivityBackPressedEventData>{
|
||||
eventName: 'activityBackPressed',
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Page } from '../page';
|
||||
import { TransitionState } from './frame-common';
|
||||
|
||||
// Types.
|
||||
import { Application } from '../../application';
|
||||
import { Application, AndroidActivityBackPressedEventData } from '../../application';
|
||||
|
||||
import { Observable } from '../../data/observable';
|
||||
import { Trace } from '../../trace';
|
||||
@@ -19,6 +19,7 @@ import type { ExpandedEntry } from './fragment.transitions.android';
|
||||
import { ensureFragmentClass, fragmentClass } from './fragment';
|
||||
import { FragmentCallbacksImplementation } from './callbacks/fragment-callbacks';
|
||||
import { ActivityCallbacksImplementation } from './callbacks/activity-callbacks';
|
||||
import { Device } from '../../platform';
|
||||
|
||||
export * from './frame-common';
|
||||
export { setFragmentClass } from './fragment';
|
||||
@@ -782,8 +783,69 @@ export function getFrameByNumberId(frameId: number): Frame {
|
||||
return null;
|
||||
}
|
||||
|
||||
let OnBackPressedCallback;
|
||||
if (parseInt(Device.sdkVersion) >= 33) {
|
||||
OnBackPressedCallback = (<any>androidx.activity.OnBackPressedCallback).extend('com.tns.OnBackPressedCallback', {
|
||||
handleOnBackPressed() {
|
||||
if (Trace.isEnabled()) {
|
||||
Trace.write('NativeScriptActivity.onBackPressed;', Trace.categories.NativeLifecycle);
|
||||
}
|
||||
|
||||
const activity = this['_activity']?.get();
|
||||
if (!activity) {
|
||||
if (Trace.isEnabled()) {
|
||||
Trace.write('NativeScriptActivity.onBackPressed; Activity is null, calling super', Trace.categories.NativeLifecycle);
|
||||
}
|
||||
this.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const args = <AndroidActivityBackPressedEventData>{
|
||||
eventName: 'activityBackPressed',
|
||||
object: Application,
|
||||
android: Application.android,
|
||||
activity: activity,
|
||||
cancel: false,
|
||||
};
|
||||
Application.android.notify(args);
|
||||
if (args.cancel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = activity._rootView;
|
||||
let callSuper = false;
|
||||
|
||||
const viewArgs = <AndroidActivityBackPressedEventData>{
|
||||
eventName: 'activityBackPressed',
|
||||
object: view,
|
||||
activity: activity,
|
||||
cancel: false,
|
||||
};
|
||||
view?.notify(viewArgs);
|
||||
|
||||
// In the case of Frame, use this callback only if it was overridden, since the original will cause navigation issues
|
||||
if (!viewArgs.cancel && (view?.onBackPressed === Frame.prototype.onBackPressed || !view?.onBackPressed())) {
|
||||
callSuper = view instanceof Frame ? !Frame.goBack() : true;
|
||||
}
|
||||
|
||||
if (callSuper) {
|
||||
this.setEnabled(false);
|
||||
activity.getOnBackPressedDispatcher().onBackPressed();
|
||||
this.setEnabled(true);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function setActivityCallbacks(activity: androidx.appcompat.app.AppCompatActivity): void {
|
||||
activity[CALLBACKS] = new ActivityCallbacksImplementation();
|
||||
|
||||
if (OnBackPressedCallback && !activity['_onBackPressed']) {
|
||||
const callback = new OnBackPressedCallback(true);
|
||||
callback['_activity'] = new WeakRef(activity);
|
||||
activity['_onBackPressed'] = true;
|
||||
(activity as androidx.activity.ComponentActivity).getOnBackPressedDispatcher().addCallback(activity, callback);
|
||||
}
|
||||
}
|
||||
|
||||
export function setFragmentCallbacks(fragment: androidx.fragment.app.Fragment): void {
|
||||
|
||||
@@ -205,7 +205,7 @@ declare module androidx {
|
||||
|
||||
declare module androidx {
|
||||
export module activity {
|
||||
export class ComponentDialog implements androidx.activity.OnBackPressedDispatcherOwner {
|
||||
export class ComponentDialog extends android.app.Dialog implements androidx.activity.OnBackPressedDispatcherOwner {
|
||||
public static class: java.lang.Class<androidx.activity.ComponentDialog>;
|
||||
public onStart(): void;
|
||||
public constructor(context: globalAndroid.content.Context);
|
||||
|
||||
Reference in New Issue
Block a user