From d69a3c4d609be1ab8a8829075633e7cc4acd0d22 Mon Sep 17 00:00:00 2001 From: danielorihuela Date: Mon, 6 Jul 2020 23:47:08 +0200 Subject: [PATCH] feat(dialog): ios destructive style from options (#8676) --- nativescript-core/ui/dialogs/dialogs.d.ts | 5 + nativescript-core/ui/dialogs/dialogs.ios.ts | 305 ++++++++++++++------ 2 files changed, 223 insertions(+), 87 deletions(-) diff --git a/nativescript-core/ui/dialogs/dialogs.d.ts b/nativescript-core/ui/dialogs/dialogs.d.ts index c254148e23..3a7da8fde7 100644 --- a/nativescript-core/ui/dialogs/dialogs.d.ts +++ b/nativescript-core/ui/dialogs/dialogs.d.ts @@ -171,6 +171,11 @@ export interface ActionOptions extends CancelableOptions { * Gets or sets the list of available actions. */ actions?: Array; + + /** + * [iOS only] Gets or sets the indexes of destructive actions. + */ + destructiveActionsIndexes?: Array; } /** diff --git a/nativescript-core/ui/dialogs/dialogs.ios.ts b/nativescript-core/ui/dialogs/dialogs.ios.ts index 0e172c607a..0e535c5de0 100644 --- a/nativescript-core/ui/dialogs/dialogs.ios.ts +++ b/nativescript-core/ui/dialogs/dialogs.ios.ts @@ -1,35 +1,83 @@ /** * iOS specific dialogs functions implementation. */ -import { ios as iosView, traceCategories, traceWrite, traceMessageType } from "../core/view"; -import { ConfirmOptions, PromptOptions, PromptResult, LoginOptions, LoginResult, ActionOptions } from "."; -import { getCurrentPage, getLabelColor, getButtonColors, getTextFieldColor, isDialogOptions, inputType, capitalizationType, ALERT, OK, CONFIRM, CANCEL, PROMPT, parseLoginOptions } from "./dialogs-common"; +import { + ios as iosView, + traceCategories, + traceWrite, + traceMessageType, +} from "../core/view"; +import { + ConfirmOptions, + PromptOptions, + PromptResult, + LoginOptions, + LoginResult, + ActionOptions, +} from "."; +import { + getCurrentPage, + getLabelColor, + getButtonColors, + getTextFieldColor, + isDialogOptions, + inputType, + capitalizationType, + ALERT, + OK, + CONFIRM, + CANCEL, + PROMPT, + parseLoginOptions, +} from "./dialogs-common"; import { isString, isDefined, isFunction } from "../../utils/types"; import { getRootView, ios } from "../../application"; export * from "./dialogs-common"; -function addButtonsToAlertController(alertController: UIAlertController, options: ConfirmOptions, callback?: Function): void { +function addButtonsToAlertController( + alertController: UIAlertController, + options: ConfirmOptions, + callback?: Function +): void { if (!options) { return; } if (isString(options.cancelButtonText)) { - alertController.addAction(UIAlertAction.actionWithTitleStyleHandler(options.cancelButtonText, UIAlertActionStyle.Default, () => { - raiseCallback(callback, false); - })); + alertController.addAction( + UIAlertAction.actionWithTitleStyleHandler( + options.cancelButtonText, + UIAlertActionStyle.Default, + () => { + raiseCallback(callback, false); + } + ) + ); } if (isString(options.neutralButtonText)) { - alertController.addAction(UIAlertAction.actionWithTitleStyleHandler(options.neutralButtonText, UIAlertActionStyle.Default, () => { - raiseCallback(callback, undefined); - })); + alertController.addAction( + UIAlertAction.actionWithTitleStyleHandler( + options.neutralButtonText, + UIAlertActionStyle.Default, + () => { + raiseCallback(callback, undefined); + } + ) + ); } if (isString(options.okButtonText)) { - alertController.addAction(UIAlertAction.actionWithTitleStyleHandler(options.okButtonText, UIAlertActionStyle.Default, () => { - raiseCallback(callback, true); - })); + alertController.addAction( + UIAlertAction.actionWithTitleStyleHandler( + options.okButtonText, + UIAlertActionStyle.Default, + () => { + raiseCallback(callback, true); + } + ) + ); } } @@ -41,10 +89,18 @@ function raiseCallback(callback, result) { export function alert(arg: any): Promise { return new Promise((resolve, reject) => { try { - let options = !isDialogOptions(arg) ? { title: ALERT, okButtonText: OK, message: arg + "" } : arg; - let alertController = UIAlertController.alertControllerWithTitleMessagePreferredStyle(options.title, options.message, UIAlertControllerStyle.Alert); - - addButtonsToAlertController(alertController, options, () => { resolve(); }); + let options = !isDialogOptions(arg) + ? { title: ALERT, okButtonText: OK, message: arg + "" } + : arg; + let alertController = UIAlertController.alertControllerWithTitleMessagePreferredStyle( + options.title, + options.message, + UIAlertControllerStyle.Alert + ); + + addButtonsToAlertController(alertController, options, () => { + resolve(); + }); showUIAlertController(alertController); } catch (ex) { @@ -56,10 +112,23 @@ export function alert(arg: any): Promise { export function confirm(arg: any): Promise { return new Promise((resolve, reject) => { try { - let options = !isDialogOptions(arg) ? { title: CONFIRM, okButtonText: OK, cancelButtonText: CANCEL, message: arg + "" } : arg; - let alertController = UIAlertController.alertControllerWithTitleMessagePreferredStyle(options.title, options.message, UIAlertControllerStyle.Alert); - - addButtonsToAlertController(alertController, options, (r) => { resolve(r); }); + let options = !isDialogOptions(arg) + ? { + title: CONFIRM, + okButtonText: OK, + cancelButtonText: CANCEL, + message: arg + "", + } + : arg; + let alertController = UIAlertController.alertControllerWithTitleMessagePreferredStyle( + options.title, + options.message, + UIAlertControllerStyle.Alert + ); + + addButtonsToAlertController(alertController, options, (r) => { + resolve(r); + }); showUIAlertController(alertController); } catch (ex) { @@ -96,49 +165,64 @@ export function prompt(arg: any): Promise { return new Promise((resolve, reject) => { try { let textField: UITextField; - let alertController = UIAlertController.alertControllerWithTitleMessagePreferredStyle(options.title, options.message, UIAlertControllerStyle.Alert); - - alertController.addTextFieldWithConfigurationHandler((arg: UITextField) => { - arg.text = isString(options.defaultText) ? options.defaultText : ""; - arg.secureTextEntry = options && options.inputType === inputType.password; - - if (options && options.inputType === inputType.email) { - arg.keyboardType = UIKeyboardType.EmailAddress; - } else if (options && options.inputType === inputType.number) { - arg.keyboardType = UIKeyboardType.NumberPad; - } else if (options && options.inputType === inputType.decimal) { - arg.keyboardType = UIKeyboardType.DecimalPad; - } else if (options && options.inputType === inputType.phone) { - arg.keyboardType = UIKeyboardType.PhonePad; - } + let alertController = UIAlertController.alertControllerWithTitleMessagePreferredStyle( + options.title, + options.message, + UIAlertControllerStyle.Alert + ); + + alertController.addTextFieldWithConfigurationHandler( + (arg: UITextField) => { + arg.text = isString(options.defaultText) ? options.defaultText : ""; + arg.secureTextEntry = + options && options.inputType === inputType.password; + + if (options && options.inputType === inputType.email) { + arg.keyboardType = UIKeyboardType.EmailAddress; + } else if (options && options.inputType === inputType.number) { + arg.keyboardType = UIKeyboardType.NumberPad; + } else if (options && options.inputType === inputType.decimal) { + arg.keyboardType = UIKeyboardType.DecimalPad; + } else if (options && options.inputType === inputType.phone) { + arg.keyboardType = UIKeyboardType.PhonePad; + } - let color = getTextFieldColor(); - if (color) { - arg.textColor = arg.tintColor = color.ios; + let color = getTextFieldColor(); + if (color) { + arg.textColor = arg.tintColor = color.ios; + } } - }); + ); textField = alertController.textFields.firstObject; if (options) { switch (options.capitalizationType) { case capitalizationType.all: { - textField.autocapitalizationType = UITextAutocapitalizationType.AllCharacters; break; + textField.autocapitalizationType = + UITextAutocapitalizationType.AllCharacters; + break; } case capitalizationType.sentences: { - textField.autocapitalizationType = UITextAutocapitalizationType.Sentences; break; + textField.autocapitalizationType = + UITextAutocapitalizationType.Sentences; + break; } case capitalizationType.words: { - textField.autocapitalizationType = UITextAutocapitalizationType.Words; break; + textField.autocapitalizationType = + UITextAutocapitalizationType.Words; + break; } default: { - textField.autocapitalizationType = UITextAutocapitalizationType.None; + textField.autocapitalizationType = + UITextAutocapitalizationType.None; } } } - addButtonsToAlertController(alertController, options, - (r) => { resolve({ result: r, text: textField.text }); }); + addButtonsToAlertController(alertController, options, (r) => { + resolve({ result: r, text: textField.text }); + }); showUIAlertController(alertController); } catch (ex) { @@ -154,43 +238,49 @@ export function login(...args: any[]): Promise { try { let userNameTextField: UITextField; let passwordTextField: UITextField; - let alertController = UIAlertController.alertControllerWithTitleMessagePreferredStyle(options.title, options.message, UIAlertControllerStyle.Alert); + let alertController = UIAlertController.alertControllerWithTitleMessagePreferredStyle( + options.title, + options.message, + UIAlertControllerStyle.Alert + ); let textFieldColor = getTextFieldColor(); - alertController.addTextFieldWithConfigurationHandler((arg: UITextField) => { - arg.placeholder = "Login"; - arg.placeholder = options.userNameHint ? options.userNameHint : ""; - arg.text = isString(options.userName) ? options.userName : ""; + alertController.addTextFieldWithConfigurationHandler( + (arg: UITextField) => { + arg.placeholder = "Login"; + arg.placeholder = options.userNameHint ? options.userNameHint : ""; + arg.text = isString(options.userName) ? options.userName : ""; - if (textFieldColor) { - arg.textColor = arg.tintColor = textFieldColor.ios; + if (textFieldColor) { + arg.textColor = arg.tintColor = textFieldColor.ios; + } } - }); + ); - alertController.addTextFieldWithConfigurationHandler((arg: UITextField) => { - arg.placeholder = "Password"; - arg.secureTextEntry = true; - arg.placeholder = options.passwordHint ? options.passwordHint : ""; - arg.text = isString(options.password) ? options.password : ""; + alertController.addTextFieldWithConfigurationHandler( + (arg: UITextField) => { + arg.placeholder = "Password"; + arg.secureTextEntry = true; + arg.placeholder = options.passwordHint ? options.passwordHint : ""; + arg.text = isString(options.password) ? options.password : ""; - if (textFieldColor) { - arg.textColor = arg.tintColor = textFieldColor.ios; + if (textFieldColor) { + arg.textColor = arg.tintColor = textFieldColor.ios; + } } - }); + ); userNameTextField = alertController.textFields.firstObject; passwordTextField = alertController.textFields.lastObject; - addButtonsToAlertController(alertController, options, - (r) => { - resolve({ - result: r, - userName: - userNameTextField.text, - password: passwordTextField.text - }); + addButtonsToAlertController(alertController, options, (r) => { + resolve({ + result: r, + userName: userNameTextField.text, + password: passwordTextField.text, }); + }); showUIAlertController(alertController); } catch (ex) { @@ -201,20 +291,30 @@ export function login(...args: any[]): Promise { function showUIAlertController(alertController: UIAlertController) { let viewController = ios.rootController; - + while (viewController && viewController.presentedViewController) { viewController = viewController.presentedViewController; } if (!viewController) { - traceWrite(`No root controller found to open dialog.`, traceCategories.Error, traceMessageType.warn); - - return; + traceWrite( + `No root controller found to open dialog.`, + traceCategories.Error, + traceMessageType.warn + ); + + return; } if (alertController.popoverPresentationController) { - alertController.popoverPresentationController.sourceView = viewController.view; - alertController.popoverPresentationController.sourceRect = CGRectMake(viewController.view.bounds.size.width / 2.0, viewController.view.bounds.size.height / 2.0, 1.0, 1.0); + alertController.popoverPresentationController.sourceView = + viewController.view; + alertController.popoverPresentationController.sourceRect = CGRectMake( + viewController.view.bounds.size.width / 2.0, + viewController.view.bounds.size.height / 2.0, + 1.0, + 1.0 + ); alertController.popoverPresentationController.permittedArrowDirections = 0; } @@ -226,11 +326,17 @@ function showUIAlertController(alertController: UIAlertController) { let lblColor = getLabelColor(); if (lblColor) { if (alertController.title) { - let title = NSAttributedString.alloc().initWithStringAttributes(alertController.title, { [NSForegroundColorAttributeName]: lblColor.ios }); + let title = NSAttributedString.alloc().initWithStringAttributes( + alertController.title, + { [NSForegroundColorAttributeName]: lblColor.ios } + ); alertController.setValueForKey(title, "attributedTitle"); } if (alertController.message) { - let message = NSAttributedString.alloc().initWithStringAttributes(alertController.message, { [NSForegroundColorAttributeName]: lblColor.ios }); + let message = NSAttributedString.alloc().initWithStringAttributes( + alertController.message, + { [NSForegroundColorAttributeName]: lblColor.ios } + ); alertController.setValueForKey(message, "attributedMessage"); } } @@ -257,7 +363,11 @@ export function action(): Promise { options.cancelButtonText = arguments[1]; } } else if (arguments.length === 3) { - if (isString(arguments[0]) && isString(arguments[1]) && isDefined(arguments[2])) { + if ( + isString(arguments[0]) && + isString(arguments[1]) && + isDefined(arguments[2]) + ) { options = defaultOptions; options.message = arguments[0]; options.cancelButtonText = arguments[1]; @@ -269,27 +379,48 @@ export function action(): Promise { try { let i: number; let action: string; - let alertController = UIAlertController.alertControllerWithTitleMessagePreferredStyle(options.title, options.message, UIAlertControllerStyle.ActionSheet); + let alertController = UIAlertController.alertControllerWithTitleMessagePreferredStyle( + options.title, + options.message, + UIAlertControllerStyle.ActionSheet + ); if (options.actions) { for (i = 0; i < options.actions.length; i++) { action = options.actions[i]; if (isString(action)) { - alertController.addAction(UIAlertAction.actionWithTitleStyleHandler(action, UIAlertActionStyle.Default, (arg: UIAlertAction) => { - resolve(arg.title); - })); + const thisActionIsDestructive = + options.destructiveActionsIndexes && + options.destructiveActionsIndexes.indexOf(i) !== -1; + const dialogType = thisActionIsDestructive + ? UIAlertActionStyle.Destructive + : UIAlertActionStyle.Default; + alertController.addAction( + UIAlertAction.actionWithTitleStyleHandler( + action, + dialogType, + (arg: UIAlertAction) => { + resolve(arg.title); + } + ) + ); } } } if (isString(options.cancelButtonText)) { - alertController.addAction(UIAlertAction.actionWithTitleStyleHandler(options.cancelButtonText, UIAlertActionStyle.Cancel, (arg: UIAlertAction) => { - resolve(arg.title); - })); + alertController.addAction( + UIAlertAction.actionWithTitleStyleHandler( + options.cancelButtonText, + UIAlertActionStyle.Cancel, + (arg: UIAlertAction) => { + resolve(arg.title); + } + ) + ); } showUIAlertController(alertController); - } catch (ex) { reject(ex); }