2018-05-15 17:59:36 +00:00
// @flow
import { NativeModules } from 'react-native'
import processColor from 'react-native/Libraries/StyleSheet/processColor'
2015-11-01 17:28:44 +00:00
2018-05-15 17:59:36 +00:00
import type { ColorValue } from 'react-native/Libraries/StyleSheet/StyleSheetTypes'
type IdKey = string | 'id' ;
type LabelKey = string | 'label' ;
type ListItem = { label : string , id ? : any } ;
2018-05-31 05:10:29 +00:00
type OptionsAlert = { |
... OptionsCheckbox ,
... OptionsCommon
| }
type OptionsCheckbox = { |
checkboxLabel ? : string ,
checkboxDefaultValue ? : boolean
| }
2018-05-15 17:59:36 +00:00
type OptionsCommon = { |
title ? : null | string ,
titleColor ? : ColorValue ,
content ? : null | string ,
contentIsHtml ? : boolean ,
contentColor ? : string ,
positiveText ? : string , // default "OK"
negativeText ? : string ,
neutralText ? : string ,
positiveColor ? : ColorValue ,
negativeColor ? : ColorValue ,
neutralColor ? : ColorValue ,
cancelable ? : boolean ,
linkColor ? : ColorValue , // applies if contentIsHtml is true, and there are <a> elements in content string
forceStacking ? : boolean
| }
type ListItemJustLabel = { label : string } ;
type ListItemJustId = { id : string } ;
type ListItemFull = { label : string , id : any } ;
type ListItemBare = { } ;
type OptionsRadio = { |
type : typeof ListType . listRadio ,
widgetColor ? : ColorValue // radio color
| }
type OptionsCheckbox = { |
type : typeof ListType . listCheckbox ,
neutralIsClear ? : boolean ,
widgetColor ? : ColorValue // checkbox color
| }
type OptionsPicker = { |
... OptionsCommon ,
type ? : typeof ListType . listPlain ,
items : ListItemJustLabel [ ] ,
| } | { |
... OptionsCommon ,
type ? : typeof ListType . listPlain ,
items : ListItemBare [ ] ,
labelKey : string
| } | { |
// radio - no preselected
... OptionsCommon ,
... OptionsRadio ,
items : ListItemJustLabel [ ] ,
| } | { |
// radio - no preselected
... OptionsCommon ,
... OptionsRadio ,
items : ListItemBare [ ] ,
labelKey : string
| } | { |
// radio - preselected - ListItemFull
... OptionsCommon ,
... OptionsRadio ,
items : ListItemFull [ ] ,
selectedId : any
| } | { |
// radio - preselected - ListItemJustlabel
... OptionsCommon ,
... OptionsRadio ,
items : ListItemJustLabel [ ] ,
idKey : string ,
selectedId : any
| } | { |
// radio - preselected - ListItemJustId
... OptionsCommon ,
... OptionsRadio ,
items : ListItemJustId [ ] ,
labelKey : string ,
selectedId : any
| } | { |
// radio - preselected - ListItemBare
... OptionsCommon ,
... OptionsRadio ,
items : ListItemBare [ ] ,
idKey : string ,
labelKey : string ,
selectedId : any
| } | { |
// checklist - no preselected - ListItemJustLabel
... OptionsCommon ,
... OptionsCheckbox ,
items : ListItemJustLabel [ ]
| } | { |
// checklist - no preselected - ListItemBare
... OptionsCommon ,
... OptionsCheckbox ,
items : ListItemBare [ ] ,
labelKey : string
| } | { |
// checklist - preselected - ListItemFull
... OptionsCommon ,
... OptionsCheckbox ,
items : ListItemFull [ ] ,
selectedIds : any [ ]
| } | { |
// checklist - preselected - ListItemJustlabel
... OptionsCommon ,
... OptionsCheckbox ,
items : ListItemJustLabel [ ] ,
idKey : string ,
selectedIds : any
| } | { |
// checklist - preselected - ListItemJustId
... OptionsCommon ,
... OptionsCheckbox ,
items : ListItemJustId [ ] ,
labelKey : string ,
selectedIds : any
| } | { |
// checklist - preselected - ListItemBare
... OptionsCommon ,
... OptionsCheckbox ,
items : ListItemBare [ ] ,
idKey : string ,
labelKey : string ,
selectedIds : any
| }
type ListType =
| typeof DialogAndroid . listCheckbox
| typeof DialogAndroid . listPlain
| typeof DialogAndroid . listRadio ;
type ActionType =
| typeof DialogAndroid . actionDismiss
| typeof DialogAndroid . actionNegative
| typeof DialogAndroid . actionNeutral
| typeof DialogAndroid . actionPositive
| typeof DialogAndroid . actionSelect ;
type Options = OptionsCommon | OptionsPicker | OptionsProgress | OptionsPrompt ;
type OptionsProgress = { |
contentColor ? : $PropertyType < OptionsCommon , 'contentColor' > ,
contentIsHtml ? : $PropertyType < OptionsCommon , 'contentIsHtml' > ,
linkColor ? : $PropertyType < OptionsCommon , 'linkColor' > ,
style ? : ProgressStyle ,
title ? : $PropertyType < OptionsCommon , 'title' > ,
titleColor ? : $PropertyType < OptionsCommon , 'titleColor' > ,
widgetColor ? : $PropertyType < OptionsCommon , 'widgetColor' >
| }
type ProgressStyle = typeof DialogAndroid . progressHorizontal ;
type OptionsPrompt = { |
... OptionsCommon ,
keyboardType ? : 'numeric' | 'numbers-and-punctuation' | 'numeric-password' | 'email-address' | 'password' | 'phone-pad' | 'decimal-pad' ,
defaultValue ? : string ,
placeholder ? : string ,
allowEmptyInput ? : boolean ,
minLength ? : number ,
maxLength ? : number
| }
2015-11-01 17:28:44 +00:00
2018-05-15 17:59:36 +00:00
type Title = void | null | string ;
type Content = void | null | string ;
2015-11-01 17:28:44 +00:00
2018-05-15 17:59:36 +00:00
type NativeConfig = { |
... OptionsCommon ,
items : string [ ] ,
widgetColor ? : ColorValue ,
selectedIndices ? : number [ ] ,
selectedIndex ? : number [ ] ,
progress ? : {
indeterminate : true ,
style ? : 'horizontal'
2015-11-01 17:28:44 +00:00
}
2018-05-15 17:59:36 +00:00
| }
2015-11-01 17:28:44 +00:00
2018-05-15 17:59:36 +00:00
function processColors ( nativeConfig : { } ) {
for ( const prop of Object . keys ( nativeConfig ) ) {
if ( prop . endsWith ( 'Color' ) ) {
nativeConfig [ prop ] = processColor ( nativeConfig [ prop ] ) ;
}
2015-11-01 17:28:44 +00:00
}
2018-05-15 17:59:36 +00:00
}
2015-11-01 17:28:44 +00:00
2018-05-15 17:59:36 +00:00
function pick ( source , ... keys ) {
const target = { } ;
for ( const key of keys ) {
if ( source . hasOwnProperty ( key ) ) {
target [ key ] = source [ key ] ;
2016-06-17 09:25:31 +00:00
}
2015-11-01 17:28:44 +00:00
}
2018-05-15 17:59:36 +00:00
return target ;
}
class DialogAndroid {
static listPlain = 'listPlain'
static listRadio = 'listRadio'
static listCheckbox = 'listCheckbox'
static actionDismiss = 'actionDismiss'
static actionNegative = 'actionNegative'
static actionNeutral = 'actionNeutral'
static actionPositive = 'actionPositive'
static actionSelect = 'actionSelect'
static progressHorizontal = 'progressHorizontal'
static defaults = {
positiveText : 'OK'
}
static dismiss ( ) : void {
NativeModules . DialogAndroid . dismiss ( ) ;
}
static assignDefaults ( defaults : { title ? : Title , content ? : Content , ... Options } ) : void {
Object . assign ( DialogAndroid . defaults , defaults ) ;
}
2018-05-31 05:10:29 +00:00
static alert ( title : Title , content : Content , options ? : OptionsAlert = { } ) : Promise <
{ | action : typeof DialogAndroid . actionPositive | typeof DialogAndroid . actionNegative | typeof DialogAndroid . actionNeutral | typeof DialogAndroid . actionDismiss | } |
{ | action : typeof DialogAndroid . actionPositive | typeof DialogAndroid . actionNegative | typeof DialogAndroid . actionNeutral , checked : boolean | }
2018-05-15 17:59:36 +00:00
> {
return new Promise ( ( resolve , reject ) => {
const nativeConfig : NativeConfig = {
... DialogAndroid . defaults ,
... options ,
onAny : true ,
dismissListener : true
} ;
if ( title ) nativeConfig . title = title ;
if ( content ) nativeConfig . content = content ;
processColors ( nativeConfig ) ;
NativeModules . DialogAndroid . show ( nativeConfig , ( kind : string , ... rest ) => {
switch ( kind ) {
case 'error' : {
const [ error , nativeConfig ] = rest ;
return reject ( ` DialogAndroid ${ error } . nativeConfig: ${ nativeConfig } ` ) ;
}
case 'dismissListener' : {
return resolve ( { action : DialogAndroid . actionDismiss } ) ;
}
case 'onAny' : {
2018-05-31 05:10:29 +00:00
const [ dialogAction , checked ] = rest ;
2018-05-15 17:59:36 +00:00
switch ( dialogAction ) {
2018-05-31 05:10:29 +00:00
case 0 : return resolve ( { action : DialogAndroid . actionPositive , ... getChecked ( nativeConfig , checked ) } ) ;
case 1 : return resolve ( { action : DialogAndroid . actionNeutral , ... getChecked ( nativeConfig , checked ) } ) ;
case 2 : return resolve ( { action : DialogAndroid . actionNegative , ... getChecked ( nativeConfig , checked ) } ) ;
2018-05-15 17:59:36 +00:00
}
}
default : {
return reject ( ` Unknown callback kind: " ${ kind } " ` ) ;
}
}
} ) ;
} ) ;
}
static showPicker ( title : Title , content : Content , options : OptionsPicker ) : Promise <
2018-05-31 05:10:29 +00:00
{ | action : typeof DialogAndroid . actionNegative | typeof DialogAndroid . actionNeutral | typeof DialogAndroid . actionDismiss | } |
{ | action : typeof DialogAndroid . actionNegative | typeof DialogAndroid . actionNeutral , checked : boolean | } |
{ | action : typeof DialogAndroid . actionSelect , selectedItem : ListItem | } |
{ | action : typeof DialogAndroid . actionSelect , selectedItem : ListItem , checked : boolean | } |
{ | action : typeof DialogAndroid . actionSelect , selectedItems : ListItem [ ] | } |
{ | action : typeof DialogAndroid . actionSelect , selectedItems : ListItem [ ] , checked : boolean | }
2018-05-15 17:59:36 +00:00
> {
// options is required, must defined items
return new Promise ( ( resolve , reject ) => {
const {
idKey = 'id' ,
items ,
labelKey = 'label' ,
type ,
neutralIsClear ,
selectedId ,
selectedIds ,
... filteredOptions
} = options ;
const nativeConfig : NativeConfig = {
... DialogAndroid . defaults ,
... filteredOptions ,
onAny : true ,
dismissListener : true
} ;
if ( title ) nativeConfig . title = title ;
if ( content ) nativeConfig . content = content ;
if ( items ) {
nativeConfig . items = items . map ( item => item [ labelKey ] ) ;
switch ( type ) {
case DialogAndroid . listCheckbox : {
nativeConfig . itemsCallbackMultiChoice = true ;
if ( selectedIds ) {
nativeConfig . selectedIndices = selectedIds . map ( id => items . findIndex ( item => item [ idKey ] === id ) ) ;
}
break ;
}
case DialogAndroid . listRadio : {
nativeConfig . itemsCallbackSingleChoice = true ;
if ( selectedId !== undefined ) {
nativeConfig . selectedIndex = items . findIndex ( item => item [ idKey ] === selectedId ) ;
}
break ;
}
default :
nativeConfig . itemsCallback = true ;
}
}
if ( neutralIsClear ) nativeConfig . multiChoiceClearButton = true ;
processColors ( nativeConfig ) ;
NativeModules . DialogAndroid . show ( nativeConfig , ( kind : string , ... rest ) => {
switch ( kind ) {
case 'error' : {
const [ error , nativeConfig ] = rest ;
return reject ( ` DialogAndroid ${ error } . nativeConfig: ${ nativeConfig } ` ) ;
}
case 'itemsCallbackMultiChoice' : {
2018-05-31 05:10:29 +00:00
const [ selectedIndicesString , checked ] = rest ; // blank string when nothing selected
2018-05-16 19:26:58 +00:00
const selectedItems = selectedIndicesString === '' ? [ ] : selectedIndicesString . split ( ',' ) . map ( index => items [ index ] ) ;
2018-05-31 05:10:29 +00:00
return resolve ( { action : DialogAndroid . actionPositive , selectedItems , ... getChecked ( nativeConfig , checked ) } ) ;
2018-05-15 17:59:36 +00:00
}
case 'itemsCallback' :
case 'itemsCallbackSingleChoice' : {
2018-05-31 05:10:29 +00:00
const [ selectedIndex , checked ] = rest ;
2018-05-15 17:59:36 +00:00
const selectedItem = items [ selectedIndex ] ;
2018-05-31 05:10:29 +00:00
return resolve ( { action : DialogAndroid . actionSelect , selectedItem , ... getChecked ( nativeConfig , checked ) } ) ;
2018-05-15 17:59:36 +00:00
}
case 'onAny' : {
2018-05-31 05:10:29 +00:00
const [ dialogAction , checked ] = rest ;
2018-05-15 17:59:36 +00:00
switch ( dialogAction ) {
2018-05-31 05:10:29 +00:00
case 0 : return resolve ( { action : DialogAndroid . actionPositive , ... getChecked ( nativeConfig , checked ) } ) ;
case 1 : return resolve ( { action : DialogAndroid . actionNeutral , ... getChecked ( nativeConfig , checked ) } ) ;
case 2 : return resolve ( { action : DialogAndroid . actionNegative , ... getChecked ( nativeConfig , checked ) } ) ;
2018-05-15 17:59:36 +00:00
}
}
case 'dismissListener' : {
return resolve ( { action : DialogAndroid . actionDismiss } ) ;
}
default : {
return reject ( ` Unknown callback kind: " ${ kind } " ` ) ;
}
}
} ) ;
} )
}
static showProgress ( content : string , options ? : OptionsProgress = { } ) : Promise <
{ |
action : typeof DialogAndroid . actionDismiss
| }
> {
return new Promise ( ( resolve , reject ) => {
const defaults = pick ( DialogAndroid . defaults ,
'contentColor' ,
'contentIsHtml' ,
'linkColor' ,
'title' ,
'widgetColor' ,
'titleColor'
)
const {
style ,
... finalOptions
} = options ;
const nativeConfig = {
... defaults ,
progress : {
indeterminate : true ,
style : style === DialogAndroid . progressHorizontal ? 'horizontal' : undefined
} ,
cancelable : false ,
... finalOptions ,
dismissListener : true
}
2018-05-16 19:26:58 +00:00
if ( content ) nativeConfig . content = content ;
if ( content && style !== DialogAndroid . progressHorizontal ) nativeConfig . content = ' ' + content ;
2018-05-15 17:59:36 +00:00
processColors ( nativeConfig ) ;
NativeModules . DialogAndroid . show ( nativeConfig , ( kind : string , ... rest ) => {
switch ( kind ) {
case 'error' : {
const [ error , nativeConfig ] = rest ;
return reject ( ` DialogAndroid ${ error } . nativeConfig: ${ nativeConfig } ` ) ;
}
case 'dismissListener' : {
return resolve ( { action : DialogAndroid . actionDismiss } ) ;
}
}
} ) ;
} )
}
static prompt ( title : Title , content : Content , options ? : OptionsPrompt = { } ) : Promise <
2018-05-31 05:10:29 +00:00
{ | action : typeof DialogAndroid . actionNegative | typeof DialogAndroid . actionNeutral | typeof DialogAndroid . actionDismiss | } |
{ | action : typeof DialogAndroid . actionNegative | typeof DialogAndroid . actionNeutral , checked : boolean | } |
{ | action : typeof DialogAndroid . actionPositive , text : string | } |
{ | action : typeof DialogAndroid . actionPositive , text : string , checked : boolean | }
2018-05-15 17:59:36 +00:00
> {
return new Promise ( ( resolve , reject ) => {
2015-11-01 17:28:44 +00:00
2018-05-15 17:59:36 +00:00
const {
keyboardType ,
defaultValue ,
placeholder ,
allowEmptyInput ,
minLength ,
maxLength ,
... finalOptions
} = options ;
2015-11-01 17:28:44 +00:00
2018-05-15 17:59:36 +00:00
const inputConfig = { } ;
if ( defaultValue ) inputConfig . prefill = defaultValue ;
if ( placeholder ) inputConfig . hint = placeholder ;
if ( allowEmptyInput !== undefined ) inputConfig . allowEmptyInput = allowEmptyInput ;
if ( minLength ) inputConfig . minLength = minLength ;
if ( maxLength ) inputConfig . maxLength = maxLength ;
// if (keyboardType) inputConfig.keyboardType = keyboardType; // TODO: support this on native side - https://github.com/aakashns/react-native-dialogs/pull/55
2016-01-06 03:56:22 +00:00
2018-05-15 17:59:36 +00:00
const nativeConfig = {
... DialogAndroid . defaults ,
input : inputConfig ,
... finalOptions ,
onAny : true ,
dismissListener : true
}
if ( title ) nativeConfig . title = title ;
if ( content ) nativeConfig . content = content ;
2016-03-11 22:54:44 +00:00
2018-05-15 17:59:36 +00:00
processColors ( nativeConfig ) ;
NativeModules . DialogAndroid . show ( nativeConfig , ( kind : string , ... rest ) => {
switch ( kind ) {
case 'error' : {
const [ error , nativeConfig ] = rest ;
return reject ( ` DialogAndroid ${ error } . nativeConfig: ${ nativeConfig } ` ) ;
}
case 'onAny' : {
2018-05-31 05:10:29 +00:00
const [ dialogAction , checked ] = rest ;
2018-05-15 17:59:36 +00:00
switch ( dialogAction ) {
2018-05-31 05:10:29 +00:00
case 1 : return resolve ( { action : DialogAndroid . actionNeutral , ... getChecked ( nativeConfig , checked ) } ) ;
case 2 : return resolve ( { action : DialogAndroid . actionNegative , ... getChecked ( nativeConfig , checked ) } ) ;
2018-05-15 17:59:36 +00:00
}
}
case 'input' : {
2018-05-31 05:10:29 +00:00
const [ text , checked ] = rest ;
return resolve ( { action : DialogAndroid . actionPositive , text , ... getChecked ( nativeConfig , checked ) } ) ;
2018-05-15 17:59:36 +00:00
}
case 'dismissListener' : {
return resolve ( { action : DialogAndroid . actionDismiss } ) ;
}
case 'cancelListener' : {
// fires when input text field is there and hit back or in back to dismiss
return resolve ( { action : DialogAndroid . actionDismiss } ) ;
}
default : {
return reject ( ` Unknown callback kind: " ${ kind } " ` ) ;
}
}
} ) ;
} )
}
2015-11-01 17:28:44 +00:00
}
2018-05-31 05:10:29 +00:00
function getChecked ( nativeConfig , checked ) {
return nativeConfig . checkboxLabel ? { checked } : { } ;
}
2018-05-15 17:59:36 +00:00
export default DialogAndroid