import { getColorStateList } from '@nativescript-community/ui-material-core/android/utils' ; import { TextField } from '@nativescript-community/ui-material-textfield' ; import { ActionOptions , Application , Builder , CSSUtils , ConfirmOptions , DialogOptions , DialogStrings , LoginResult , PromptResult , StackLayout , Utils , View , capitalizationType , fromObject , inputType } from '@nativescript/core' ; import { ad } from '@nativescript/core/utils' ; import { LoginOptions , MDCAlertControlerOptions , PromptOptions } from './dialogs' ; import { isDialogOptions } from './dialogs-common' ; export { capitalizationType , inputType } ; function isString ( value ) { return typeof value === 'string' ; } let DialogInterface ; let MaterialAlertDialogBuilder ; function createAlertDialogBuilder ( options ? ) { const activity = Application . android . foregroundActivity || ( Application . android . startActivity as globalAndroid . app . Activity ) ; if ( ! MaterialAlertDialogBuilder ) { MaterialAlertDialogBuilder = com . google . android . material . dialog . MaterialAlertDialogBuilder ; } const builder = new MaterialAlertDialogBuilder ( activity ) ; builder . setTitle ( options && isString ( options . title ) ? options . title : null ) ; builder . setMessage ( options && isString ( options . message ) ? options . message : null ) ; if ( options . titleIcon ) { builder . setIcon ( new android . graphics . drawable . BitmapDrawable ( options . titleIcon . android ) ) ; } if ( options && options . cancelable === false ) { builder . setCancelable ( false ) ; if ( ! DialogInterface ) { DialogInterface = android . content . DialogInterface ; } builder . setOnKeyListener ( new DialogInterface . OnKeyListener ( { onKey ( dialog , keyCode , event ) { return keyCode === android . view . KeyEvent . KEYCODE_BACK ; } } ) ) ; } if ( options . customTitleView ) { builder . setCustomTitle ( options . customTitleView . nativeViewProtected ) ; } if ( options . view ) { const view = options . view instanceof View ? options . view : Builder . createViewFromEntry ( { moduleName : options . view as string } ) ; view . cssClasses . add ( CSSUtils . MODAL_ROOT_VIEW_CSS_CLASS ) ; const modalRootViewCssClasses = CSSUtils . getSystemCssClasses ( ) ; modalRootViewCssClasses . forEach ( ( c ) => view . cssClasses . add ( c ) ) ; ( builder as any ) . _currentModalCustomView = view ; view . _setupAsRootView ( activity ) ; view . _isAddedToNativeVisualTree = true ; view . callLoaded ( ) ; const frame = new android . widget . FrameLayout ( activity ) ; frame . addView ( view . nativeViewProtected ) ; builder . setView ( frame ) ; } return builder ; } function showDialog ( dlg , options ) { if ( options . titleColor ) { const textViewId = dlg . getContext ( ) . getResources ( ) . getIdentifier ( 'android:id/alertTitle' , null , null ) ; if ( textViewId ) { const tv = dlg . findViewById ( textViewId ) as android . widget . TextView ; if ( tv ) { tv . setTextColor ( options . titleColor . android ) ; } } if ( options . messageColor ) { const messageTextViewId = dlg . getContext ( ) . getResources ( ) . getIdentifier ( 'android:id/message' , null , null ) ; if ( messageTextViewId ) { const messageTextView = dlg . findViewById ( messageTextViewId ) as android . widget . TextView ; if ( messageTextView ) { messageTextView . setTextColor ( options . messageColor . android ) ; } } } } if ( options . buttonInkColor || options . buttonTitleColor ) { dlg . create ( ) ; const buttons = [ ] ; for ( let i = - 1 ; i > - 4 ; i -- ) { buttons . push ( dlg . getButton ( i ) as com . google . android . material . button . MaterialButton ) ; } const nInkColor = options . buttonInkColor && getColorStateList ( options . buttonInkColor . android ) ; const nTitleColor = options . buttonTitleColor && getColorStateList ( options . buttonTitleColor . android ) ; buttons . forEach ( ( button ) => { if ( button ) { if ( nInkColor ) { button . setRippleColor ( nInkColor ) ; } if ( nTitleColor ) { button . setTextColor ( nTitleColor ) ; button . setIconTint ( nTitleColor ) ; } } } ) ; } dlg . show ( ) ; return dlg ; } function prepareAndCreateAlertDialog ( builder , options , callback ? , validationArgs ? ) { let onDoneCalled = false ; const onDone = function ( result , dialog ? ) { if ( options && options . shouldResolveOnAction && ! options . shouldResolveOnAction ( validationArgs ? validationArgs ( result ) : result ) ) { return ; } if ( onDoneCalled ) { return ; } const imm = ad . getApplicationContext ( ) . getSystemService ( android . content . Context . INPUT_METHOD_SERVICE ) ; imm . toggleSoftInput ( android . view . inputmethod . InputMethodManager . HIDE_IMPLICIT_ONLY , 0 ) ; onDoneCalled = true ; if ( options . view instanceof View ) { Utils . android . dismissSoftInput ( options . view . nativeView ) ; } if ( dialog ) { dialog . cancel ( ) ; } callback && callback ( result ) ; } ; if ( ! DialogInterface ) { DialogInterface = android . content . DialogInterface ; } builder . setOnDismissListener ( new DialogInterface . OnDismissListener ( { onDismiss ( ) { onDone ( false ) ; if ( ( builder as any ) . _currentModalCustomView ) { const view = ( builder as any ) . _currentModalCustomView ; view . callUnloaded ( ) ; view . _tearDownUI ( true ) ; view . _isAddedToNativeVisualTree = false ; ( builder as any ) . _currentModalCustomView = null ; } } } ) ) ; const dlg = builder . create ( ) ; if ( ! options ) { return dlg ; } if ( ( builder as any ) . _currentModalCustomView ) { const view = ( builder as any ) . _currentModalCustomView as View ; const context = options . context || { } ; context . closeCallback = function ( ... originalArgs ) { dlg . dismiss ( ) ; if ( callback ) { callback . apply ( this , originalArgs ) ; } } ; view . bindingContext = fromObject ( context ) ; } if ( options . okButtonText ) { if ( ! DialogInterface ) { DialogInterface = android . content . DialogInterface ; } dlg . setButton ( DialogInterface . BUTTON_POSITIVE , options . okButtonText , null , new android . content . DialogInterface . OnClickListener ( { onClick ( dialog , id ) { onDone ( true , dialog ) ; } } ) ) ; } if ( options . cancelButtonText ) { if ( ! DialogInterface ) { DialogInterface = android . content . DialogInterface ; } dlg . setButton ( DialogInterface . BUTTON_NEGATIVE , options . cancelButtonText , null , new DialogInterface . OnClickListener ( { onClick ( dialog , id ) { onDone ( false , dialog ) ; } } ) ) ; } if ( options . neutralButtonText ) { if ( ! DialogInterface ) { DialogInterface = android . content . DialogInterface ; } dlg . setButton ( DialogInterface . BUTTON_NEUTRAL , options . neutralButtonText , null , new DialogInterface . OnClickListener ( { onClick ( dialog , id ) { onDone ( undefined , dialog ) ; } } ) ) ; } return dlg ; } export function alert ( arg ) { return new Promise < void > ( ( resolve , reject ) => { try { const defaultOptions = { okButtonText : DialogStrings . OK } ; const options = ! isDialogOptions ( arg ) ? Object . assign ( defaultOptions , { message : arg + '' } ) : Object . assign ( defaultOptions , arg ) ; const alert = createAlertDialogBuilder ( options ) ; const dlg = prepareAndCreateAlertDialog ( alert , options , resolve ) ; showDialog ( dlg , options ) ; } catch ( ex ) { console . error ( ex ) ; reject ( ex ) ; } } ) ; } export class AlertDialog { dialog : androidx . appcompat . app . AlertDialog ; constructor ( private options ) { } onCloseListeners : any [ ] = [ ] ; onClosed ( ) { this . onCloseListeners . forEach ( ( l ) => l ( ) ) ; this . onCloseListeners = [ ] ; } show ( onClosed ? ) { if ( ! this . dialog ) { const alert = createAlertDialogBuilder ( this . options ) ; this . dialog = alert . create ( ) ; this . dialog = prepareAndCreateAlertDialog ( alert , this . options , ( ) => { this . onClosed ( ) ; onClosed ?. ( ) ; } ) ; showDialog ( this . dialog , this . options ) ; } } async hide ( ) { if ( this . dialog ) { return new Promise ( ( resolve ) => { this . onCloseListeners . push ( resolve ) ; this . dialog . cancel ( ) ; this . dialog = null ; } ) ; } } } export function confirm ( arg ) { return new Promise < boolean > ( ( resolve , reject ) => { try { const defaultOptions = { okButtonText : DialogStrings . OK , cancelButtonText : DialogStrings . CANCEL } ; const options = Object . assign ( defaultOptions , ! isDialogOptions ( arg ) ? { message : arg + '' } : arg ) ; const alert = createAlertDialogBuilder ( options ) ; const dlg = prepareAndCreateAlertDialog ( alert , options , resolve ) ; showDialog ( dlg , options ) ; } catch ( ex ) { console . error ( ex ) ; reject ( ex ) ; } } ) ; } export function prompt ( arg ) { let options ; const defaultOptions = { okButtonText : DialogStrings . OK , cancelButtonText : DialogStrings . CANCEL , inputType : inputType . text } ; if ( arguments . length === 1 ) { if ( isString ( arg ) ) { options = defaultOptions ; options . message = arg ; } else { options = Object . assign ( defaultOptions , arg ) ; } } else if ( arguments . length === 2 ) { if ( isString ( arguments [ 0 ] ) && isString ( arguments [ 1 ] ) ) { options = defaultOptions ; options . message = arguments [ 0 ] ; options . defaultText = arguments [ 1 ] ; } } return new Promise < PromptResult > ( ( resolve , reject ) => { try { const stackLayout = new StackLayout ( ) ; stackLayout . padding = 4 ; const textField = new TextField ( ) ; textField . hint = options . hintText ; if ( options ) { if ( options . textFieldProperties ) { Object . assign ( textField , options . textFieldProperties ) ; } if ( options . defaultText ) { textField . text = options . defaultText ; } if ( options . defaultText ) { textField . hint = options . hintText ; } if ( options . helperText ) { textField . helper = options . helperText ; } if ( options . inputType === inputType . password ) { textField . secure = true ; } else if ( options . inputType === inputType . email ) { textField . keyboardType = 'email' ; } else if ( options . inputType === inputType . number ) { textField . keyboardType = 'number' ; } else if ( options . inputType === inputType . phone ) { textField . keyboardType = 'phone' ; } switch ( options . capitalizationType ) { case capitalizationType . all : { textField . autocapitalizationType = 'allcharacters' ; break ; } case capitalizationType . sentences : { textField . autocapitalizationType = 'sentences' ; break ; } case capitalizationType . words : { textField . autocapitalizationType = 'words' ; break ; } } } stackLayout . addChild ( textField ) ; options . view = stackLayout ; const alert = createAlertDialogBuilder ( options ) ; const dlg = prepareAndCreateAlertDialog ( alert , options , function ( r ) { resolve ( { result : r , text : textField . text } ) ; } , ( r ) => ( { result : r , text : textField . text } ) ) ; showDialog ( dlg , options ) ; if ( options . autoFocus ) { textField . requestFocus ( ) ; } } catch ( ex ) { console . error ( ex ) ; reject ( ex ) ; } } ) ; } export function login ( arg ) { let options ; const defaultOptions = { okButtonText : DialogStrings . OK , cancelButtonText : DialogStrings . CANCEL } ; if ( arguments . length === 1 ) { if ( isString ( arguments [ 0 ] ) ) { options = defaultOptions ; options . message = arguments [ 0 ] ; } else { options = Object . assign ( defaultOptions , arguments [ 0 ] ) ; } } else if ( arguments . length === 2 ) { if ( isString ( arguments [ 0 ] ) && isString ( arguments [ 1 ] ) ) { options = defaultOptions ; options . message = arguments [ 0 ] ; options . userName = arguments [ 1 ] ; } } else if ( arguments . length === 3 ) { if ( isString ( arguments [ 0 ] ) && isString ( arguments [ 1 ] ) && isString ( arguments [ 2 ] ) ) { options = defaultOptions ; options . message = arguments [ 0 ] ; options . userName = arguments [ 1 ] ; options . password = arguments [ 2 ] ; } } return new Promise < LoginResult > ( ( resolve , reject ) => { try { const stackLayout = new StackLayout ( ) ; stackLayout . padding = 4 ; const userNameTextField = new TextField ( ) ; const passwordTextField = new TextField ( ) ; userNameTextField . hint = options . userNameHint || 'Username' ; userNameTextField . text = options . userName ; passwordTextField . hint = options . passwordHint || 'Password' ; passwordTextField . text = options . password ; passwordTextField . secure = true ; if ( options . usernameTextFieldProperties ) { Object . assign ( userNameTextField , options . usernameTextFieldProperties ) ; } if ( options . passwordTextFieldProperties ) { Object . assign ( passwordTextField , options . passwordTextFieldProperties ) ; } stackLayout . addChild ( userNameTextField ) ; stackLayout . addChild ( passwordTextField ) ; options . view = stackLayout ; const alert = createAlertDialogBuilder ( options ) ; if ( options . beforeShow ) { options . beforeShow ( options , userNameTextField , passwordTextField ) ; } const dlg = prepareAndCreateAlertDialog ( alert , options , function ( r ) { resolve ( { result : r , userName : userNameTextField . text , password : passwordTextField . text } ) ; } , ( r ) => ( { result : r , userName : userNameTextField . text , password : passwordTextField . text } ) ) ; showDialog ( dlg , options ) ; if ( options . autoFocus ) { userNameTextField . requestFocus ( ) ; } } catch ( ex ) { console . error ( ex ) ; reject ( ex ) ; } } ) ; } export function action ( arg ) { let options ; const defaultOptions = { title : null , cancelButtonText : DialogStrings . CANCEL } ; if ( arguments . length === 1 ) { if ( isString ( arguments [ 0 ] ) ) { options = defaultOptions ; options . message = arguments [ 0 ] ; } else { options = Object . assign ( defaultOptions , arguments [ 0 ] ) ; } } else if ( arguments . length === 2 ) { if ( isString ( arguments [ 0 ] ) && isString ( arguments [ 1 ] ) ) { options = defaultOptions ; options . message = arguments [ 0 ] ; options . cancelButtonText = arguments [ 1 ] ; } } else if ( arguments . length === 3 ) { if ( isString ( arguments [ 0 ] ) && isString ( arguments [ 1 ] ) && typeof arguments [ 2 ] !== 'undefined' ) { options = defaultOptions ; options . message = arguments [ 0 ] ; options . cancelButtonText = arguments [ 1 ] ; options . actions = arguments [ 2 ] ; } } return new Promise < string > ( ( resolve , reject ) => { try { const activity = Application . android . foregroundActivity || ( Application . android . startActivity as globalAndroid . app . Activity ) ; if ( ! MaterialAlertDialogBuilder ) { MaterialAlertDialogBuilder = com . google . android . material . dialog . MaterialAlertDialogBuilder ; } const alert = new MaterialAlertDialogBuilder ( activity ) ; const message = options && isString ( options . message ) ? options . message : '' ; const title = options && isString ( options . title ) ? options . title : '' ; if ( options && options . cancelable === false ) { alert . setCancelable ( false ) ; } if ( title ) { alert . setTitle ( title ) ; if ( ! options . actions ) { alert . setMessage ( message ) ; } } else { alert . setTitle ( message ) ; } if ( options . actions ) { if ( ! DialogInterface ) { DialogInterface = android . content . DialogInterface ; } alert . setItems ( options . actions , new DialogInterface . OnClickListener ( { onClick ( dialog , which ) { resolve ( options . actions [ which ] ) ; } } ) ) ; } const dlg = prepareAndCreateAlertDialog ( alert , options , function ( r ) { if ( r === false || r === undefined ) { resolve ( options . cancelButtonText ) ; } resolve ( r ) ; } ) ; showDialog ( dlg , options ) ; } catch ( ex ) { console . error ( ex ) ; reject ( ex ) ; } } ) ; }