mirror of
https://github.com/status-im/react-native-dialogs.git
synced 2025-03-01 00:30:28 +00:00
Support regular RN color value, no more crashing after first callback is consumed. (#82)
* Update DialogAndroid.java Support regular RN color value, no more crashing after first callback is consumed. * new api in js * updated js * types fixing * fixed class name from MaterialDialog to AndroidDialog * Whops it should be DialogAndroid, not AndroidDialog * fix showProgress - plan to remove this, just testing * update readme * added mroe examples * assignDefaults example * alternative shorthand signatures * more readme * deprecate string as item, selctedIndex, selectedIndices. moved to object as item, with label * changes based on discusion with @vonovak * readme nits * readme nit * readme touchups * readme nit * testing and fixes per testing * .padStart is not same as prefix
This commit is contained in:
parent
a1d7ef121d
commit
5b55a623b8
550
DialogAndroid.js
550
DialogAndroid.js
@ -1,82 +1,494 @@
|
||||
/**
|
||||
* @providesModule DialogAndroid
|
||||
*/
|
||||
// @flow
|
||||
import { NativeModules } from 'react-native'
|
||||
import processColor from 'react-native/Libraries/StyleSheet/processColor'
|
||||
|
||||
'use strict';
|
||||
import type { ColorValue } from 'react-native/Libraries/StyleSheet/StyleSheetTypes'
|
||||
|
||||
var { NativeModules } = require('react-native');
|
||||
type IdKey = string | 'id';
|
||||
type LabelKey = string | 'label';
|
||||
type ListItem = { label:string, id?:any };
|
||||
|
||||
var callbackNames = [
|
||||
'onPositive',
|
||||
'onNegative',
|
||||
'onNeutral',
|
||||
'onAny',
|
||||
'itemsCallback',
|
||||
'itemsCallbackSingleChoice',
|
||||
'itemsCallbackMultiChoice',
|
||||
'showListener',
|
||||
'cancelListener',
|
||||
'dismissListener',
|
||||
];
|
||||
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
|
||||
|}
|
||||
|
||||
class DialogAndroid {
|
||||
constructor() {
|
||||
this.options = {};
|
||||
}
|
||||
type ListItemJustLabel = { label:string };
|
||||
type ListItemJustId = { id:string };
|
||||
type ListItemFull = { label:string, id:any };
|
||||
type ListItemBare = {};
|
||||
|
||||
set(obj) {
|
||||
Object.assign(this.options, obj);
|
||||
}
|
||||
type OptionsRadio = {|
|
||||
type: typeof ListType.listRadio,
|
||||
widgetColor?: ColorValue // radio color
|
||||
|}
|
||||
type OptionsCheckbox = {|
|
||||
type: typeof ListType.listCheckbox,
|
||||
neutralIsClear?: boolean,
|
||||
widgetColor?: ColorValue // checkbox color
|
||||
|}
|
||||
|
||||
show() {
|
||||
var finalOptions = Object.assign({}, this.options);
|
||||
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
|
||||
|}
|
||||
|
||||
var callbacks = {
|
||||
error: (err, op) => console.error(err, op),
|
||||
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
|
||||
|}
|
||||
|
||||
type Title = void | null | string;
|
||||
type Content = void | null | string;
|
||||
|
||||
|
||||
type NativeConfig = {|
|
||||
...OptionsCommon,
|
||||
items: string[],
|
||||
widgetColor?: ColorValue,
|
||||
selectedIndices?: number[],
|
||||
selectedIndex?: number[],
|
||||
progress?: {
|
||||
indeterminate: true,
|
||||
style?: 'horizontal'
|
||||
}
|
||||
|}
|
||||
|
||||
// Remove callbacks from the options, and store them separately
|
||||
callbackNames.forEach(cb => {
|
||||
if (cb in finalOptions) {
|
||||
callbacks[cb] = finalOptions[cb];
|
||||
finalOptions[cb] = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Handle special case of input separately
|
||||
if ('input' in finalOptions) {
|
||||
finalOptions.input = Object.assign({}, finalOptions.input);
|
||||
var inputCallback = finalOptions.input.callback || (x => console.log(x));
|
||||
finalOptions.input.callback = true;
|
||||
callbacks['input'] = inputCallback;
|
||||
}
|
||||
|
||||
// Parse the result form multiple choice dialog
|
||||
if ('itemsCallbackMultiChoice' in callbacks) {
|
||||
var originalCallback = callbacks.itemsCallbackMultiChoice;
|
||||
callbacks.itemsCallbackMultiChoice = selected => {
|
||||
var indices = selected.split(',').map(x => parseInt(x));
|
||||
var elements = indices.map(ind => (finalOptions.items || [])[ind]);
|
||||
if(indices.length === 1 && isNaN(indices[0])){
|
||||
indices=[] // the case of empty selection
|
||||
elements=[]
|
||||
function processColors(nativeConfig: {}) {
|
||||
for (const prop of Object.keys(nativeConfig)) {
|
||||
if (prop.endsWith('Color')) {
|
||||
nativeConfig[prop] = processColor(nativeConfig[prop]);
|
||||
}
|
||||
originalCallback(indices, elements);
|
||||
}
|
||||
}
|
||||
|
||||
var callbackFunc = (cb, ...rest) => callbacks[cb](...rest);
|
||||
|
||||
NativeModules.DialogAndroid.show(finalOptions, callbackFunc);
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
NativeModules.DialogAndroid.dismiss();
|
||||
}
|
||||
|
||||
list(options, cb){
|
||||
NativeModules.DialogAndroid.list(options, cb)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DialogAndroid;
|
||||
function pick(source, ...keys) {
|
||||
const target = {};
|
||||
for (const key of keys) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
static alert(title: Title, content: Content, options?: OptionsCommon = {}): Promise<
|
||||
{|
|
||||
action: typeof DialogAndroid.actionPositive | typeof DialogAndroid.actionNegative | typeof DialogAndroid.actionNeutral | typeof DialogAndroid.actionDismiss
|
||||
|}
|
||||
> {
|
||||
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': {
|
||||
const [ dialogAction ] = rest;
|
||||
switch (dialogAction) {
|
||||
case 0: return resolve({ action:DialogAndroid.actionPositive });
|
||||
case 1: return resolve({ action:DialogAndroid.actionNeutral });
|
||||
case 2: return resolve({ action:DialogAndroid.actionNegative });
|
||||
}
|
||||
}
|
||||
default: {
|
||||
return reject(`Unknown callback kind: "${kind}"`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static showPicker(title: Title, content: Content, options: OptionsPicker): Promise<
|
||||
{|
|
||||
action: typeof DialogAndroid.actionNegative | typeof DialogAndroid.actionNeutral | typeof DialogAndroid.actionDismiss
|
||||
|} | {|
|
||||
action: typeof DialogAndroid.actionSelect,
|
||||
selectedItem: ListItem
|
||||
|} | {|
|
||||
action: typeof DialogAndroid.actionSelect,
|
||||
selectedItems: ListItem[]
|
||||
|}
|
||||
> {
|
||||
// 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': {
|
||||
const selectedIndices = rest[0].split(',');
|
||||
|
||||
let selectedItems;
|
||||
if (selectedIndices.length === 1 && isNaN(selectedIndices[0])) {
|
||||
// the case of empty selection
|
||||
selectedItems = [];
|
||||
} else {
|
||||
selectedItems = selectedIndices.map(index => items[index]);
|
||||
}
|
||||
return resolve({ action:DialogAndroid.actionPositive, selectedItems });
|
||||
}
|
||||
case 'itemsCallback':
|
||||
case 'itemsCallbackSingleChoice': {
|
||||
const [ selectedIndex ] = rest;
|
||||
const selectedItem = items[selectedIndex];
|
||||
return resolve({ action:DialogAndroid.actionSelect, selectedItem });
|
||||
}
|
||||
case 'onAny': {
|
||||
const [ dialogAction ] = rest;
|
||||
switch (dialogAction) {
|
||||
case 0: return resolve({ action:DialogAndroid.actionPositive });
|
||||
case 1: return resolve({ action:DialogAndroid.actionNeutral });
|
||||
case 2: return resolve({ action:DialogAndroid.actionNegative });
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
if (content) nativeConfig.content = ' '.repeat(5) + 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 });
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
static prompt(title: Title, content: Content, options?: OptionsPrompt = {}): Promise<
|
||||
{|
|
||||
action: typeof DialogAndroid.actionNegative | typeof DialogAndroid.actionNeutral | typeof DialogAndroid.actionDismiss
|
||||
|} | {|
|
||||
action: typeof DialogAndroid.actionPositive,
|
||||
text: string
|
||||
|}
|
||||
> {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
const {
|
||||
keyboardType,
|
||||
defaultValue,
|
||||
placeholder,
|
||||
allowEmptyInput,
|
||||
minLength,
|
||||
maxLength,
|
||||
...finalOptions
|
||||
} = options;
|
||||
|
||||
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
|
||||
|
||||
const nativeConfig = {
|
||||
...DialogAndroid.defaults,
|
||||
input: inputConfig,
|
||||
...finalOptions,
|
||||
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 'onAny': {
|
||||
const [ dialogAction ] = rest;
|
||||
switch (dialogAction) {
|
||||
case 1: return resolve({ action:DialogAndroid.actionNeutral });
|
||||
case 2: return resolve({ action:DialogAndroid.actionNegative });
|
||||
}
|
||||
}
|
||||
case 'input': {
|
||||
const [ text ] = rest;
|
||||
return resolve({ action:DialogAndroid.actionPositive, text });
|
||||
}
|
||||
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}"`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default DialogAndroid
|
||||
|
704
README.md
704
README.md
@ -1,254 +1,524 @@
|
||||
[](https://www.npmjs.com/package/react-native-dialogs)
|
||||
[](https://www.npmjs.com/package/react-native-dialogs)
|
||||
# react-native-dialogs
|
||||
Material Design dialogs for React Native Android apps (wrapper over [afollestad/material-dialogs](https://github.com/afollestad/material-dialogs))
|
||||
## react-native-dialogs
|
||||
|
||||
<img src="https://pbs.twimg.com/media/CSww5lhUAAAE487.png" width="240" hspace="10"><img src="https://pbs.twimg.com/media/CSww5hBUYAA7Ijo.png" width="240" hspace="10"><img src="https://pbs.twimg.com/media/CSww5pMUcAEry95.png" width="227">
|
||||
An Android only module for Material Design dialogs. This is a wrapper over [afollestad/material-dialogs](https://github.com/afollestad/material-dialogs). This module is designed for Android only with no plans to support iOS.
|
||||
|
||||
### Table of Contents
|
||||
- [Installation](#installation)
|
||||
- [Manual Linking](#manual-linking)
|
||||
- [Usage](#usage)
|
||||
- [API](#api)
|
||||
- [Properties](#properties)
|
||||
- [`defaults`](#defaults)
|
||||
- [`actionDismiss`](#actiondismiss)
|
||||
- [`actionNegative`](#actionnegative)
|
||||
- [`actionNeutral`](#actionneutral)
|
||||
- [`actionPositive`](#actionpositive)
|
||||
- [`listPlain`](#listplain)
|
||||
- [`listRadio`](#listradio)
|
||||
- [`listCheckbox`](#listcheckbox)
|
||||
- [`progressHorizontal`](#progresshorizontal)
|
||||
- [Methods](#methods)
|
||||
- [`alert`](#alert)
|
||||
- [`assignDefaults`](#assigndefaults)
|
||||
- [`dismiss`](#dismiss)
|
||||
- [`prompt`](#prompt)
|
||||
- [`showPicker`](#showpicker)
|
||||
- [`showProgress`](#showprogress)
|
||||
- [Types](#types)
|
||||
- [Internal Types](#internal-types)
|
||||
- [`type ActionType`](#type-actiontype)
|
||||
- [`type ListItem`](#type-listitem)
|
||||
- [`type ListType`](#type-listtype)
|
||||
- [`type OptionsCommon`](#type-optionscommon)
|
||||
- [`type OptionsProgress`](#type-optionsprogress)
|
||||
- [`type OptionsPicker`](#type-optionspicker)
|
||||
- [`type OptionsPrompt`](#type-optionsprompt)
|
||||
- [`type ProgressStyle`](#type-progressstyle)
|
||||
- [Examples](#examples)
|
||||
- [Progress overlay](#progress-overlay)
|
||||
- [List of radio items dismissed on press](#list-of-radio-items-dismissed-on-press)
|
||||
- [Checklist with clear button](#checklist-with-clear-button)
|
||||
- [Prompt](#prompt)
|
||||
- [HTML](#html)
|
||||
- [assignDefaults](#assigndefaults)
|
||||
|
||||
### Installation
|
||||
|
||||
1. Install:
|
||||
- Using [npm](https://www.npmjs.com/#getting-started): `npm install react-native-dialogs --save`
|
||||
- Using [Yarn](https://yarnpkg.com/): `yarn add react-native-dialogs`
|
||||
|
||||
2. [Link](https://facebook.github.io/react-native/docs/linking-libraries-ios.html):
|
||||
- `react-native link react-native-dialogs`
|
||||
- Or if this fails, link manually using [these steps](#manual-linking)
|
||||
|
||||
3. Compile application using `react-native run-android`
|
||||
|
||||
#### Manual Linking
|
||||
Follow these steps if automatic linking (`react-native link`) failed.
|
||||
|
||||
1. Include this module in `android/settings.gradle`:
|
||||
|
||||
```
|
||||
...
|
||||
include ':autocompletetextview' // Add this
|
||||
project(':autocompletetextview').projectDir = file("../node_modules/autocompletetextview/android") // Add this
|
||||
|
||||
...
|
||||
include ':app'
|
||||
```
|
||||
|
||||
2. In `android/app/build.gradle`, add the dependency to your app build:
|
||||
|
||||
```
|
||||
dependencies {
|
||||
...
|
||||
compile project(':react-native-dialogs') // Add this
|
||||
}
|
||||
```
|
||||
|
||||
3. In `android/build.gradle`, it should already be there, but in case it is not, add Jitpack maven repository to download the library [afollestad/material-dialogs](https://github.com/afollestad/material-dialogs):
|
||||
|
||||
```
|
||||
allprojects {
|
||||
repositories {
|
||||
...
|
||||
jcenter() // Add this if it is not already here
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4. In `android/settings.gradle`:
|
||||
|
||||
```
|
||||
rootProject.name = ...
|
||||
...
|
||||
include ':react-native-dialogs' // Add this
|
||||
project(':react-native-dialogs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-dialogs/android') // Add this
|
||||
|
||||
...
|
||||
include ':app'
|
||||
```
|
||||
|
||||
5. Import and add package, in `android/app/src/main/.../MainApplication.java`:
|
||||
|
||||
```java
|
||||
...
|
||||
import android.app.Application;
|
||||
...
|
||||
|
||||
import com.aakashns.reactnativedialogs.ReactNativeDialogsPackage; // Add new import
|
||||
|
||||
...
|
||||
|
||||
public class MainApplication extends Application implements ReactApplication {
|
||||
...
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new MainReactPackage(),
|
||||
...
|
||||
new ReactNativeDialogsPackage() // Add the package here
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
1. Import it in your JS:
|
||||
|
||||
```js
|
||||
import DialogAndroid from 'react-native-dialogs';
|
||||
```
|
||||
|
||||
2. Call API:
|
||||
|
||||
```js
|
||||
class Blah extends Component {
|
||||
render() {
|
||||
return <Button title="Show DialogAndroid" onPress={this.showDialogAndroid} />
|
||||
}
|
||||
|
||||
showDialogAndroid = async () => {
|
||||
const { action } = await DialogAndroid.alert('Title', 'Message');
|
||||
switch (action) {
|
||||
case DialogAndroid.actionPositive:
|
||||
console.log('positive!')
|
||||
break;
|
||||
case DialogAndroid.actionNegative:
|
||||
console.log('negative!')
|
||||
break;
|
||||
case DialogAndroid.actionNeutral:
|
||||
console.log('netural!')
|
||||
break;
|
||||
case DialogAndroid.actionDismiss:
|
||||
console.log('dismissed!')
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
#### Properties
|
||||
|
||||
##### `defaults`
|
||||
|
||||
> {
|
||||
> positiveText: 'OK'
|
||||
> }
|
||||
|
||||
The default options to be used by all methods. To modify this, either directly manipulate with `DialogAndroid.defaults = { ... }` or use [`assignDefaults`](#assigndefaults)
|
||||
|
||||
##### `actionDismiss`
|
||||
|
||||
> static actionDismiss = "actionDismiss"
|
||||
|
||||
##### `actionNegative`
|
||||
|
||||
> static actionNegative = "actionNegative"
|
||||
|
||||
##### `actionNeutral`
|
||||
|
||||
> static actionNeutral = "actionNeutral"
|
||||
|
||||
##### `actionPositive`
|
||||
|
||||
> static actionPositive = "actionPositive"
|
||||
|
||||
##### `listPlain`
|
||||
|
||||
> static listPlain = "listPlain"
|
||||
|
||||
##### `listRadio`
|
||||
|
||||
> static listRadio = "listRadio"
|
||||
|
||||
##### `listCheckbox`
|
||||
|
||||
> static listCheckbox = "listCheckbox"
|
||||
|
||||
##### `progressHorizontal`
|
||||
|
||||
> static progressHorizontal = "progressHorizontal"
|
||||
|
||||
#### Methods
|
||||
##### `alert`
|
||||
|
||||
> static alert(
|
||||
> title: Title,
|
||||
> content: Content,
|
||||
> options: Options
|
||||
> ): Promise<{| action: "actionDismiss" | "actionNegative" | "actionNeutral" | "actionPositive" |}>
|
||||
|
||||
Shows a dialog.
|
||||
|
||||
| Parameter | Type | Default | Required | Description |
|
||||
|-----------|----------------------------------------|---------|----------|--------------------------------------------|
|
||||
| title | `string, null, void` | | | Title of dialog |
|
||||
| content | `string, null, void` | | | Message of dialog |
|
||||
| options | [`OptionsCommon`](#type-optionscommon) | | | See [`OptionsCommon`](#type-optionscommon) |
|
||||
|
||||
##### `assignDefaults`
|
||||
|
||||
> static assignDefaults({
|
||||
> [string]: value
|
||||
> ): void
|
||||
|
||||
Set default colors for example, so you don't have to provide it on every method call.
|
||||
|
||||
> {
|
||||
> positiveText: 'OK'
|
||||
> }
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
### Installation using RNPM
|
||||
##### `dismiss`
|
||||
|
||||
1 . `yarn add react-native-dialogs`
|
||||
> static dismiss(): void
|
||||
|
||||
or
|
||||
Hides the currently showing dialog.
|
||||
|
||||
`npm i react-native-dialogs --save`
|
||||
##### `prompt`
|
||||
|
||||
> static prompt(
|
||||
> title?: null | string,
|
||||
> content?: null | string,
|
||||
> options: OptionsPrompt
|
||||
> ): Promise<
|
||||
> {| action: "actionNegative" | "actionNeutral" | "actionDismiss" |} |
|
||||
> {| action: "actionPositive", text: string |}
|
||||
> >
|
||||
|
||||
Shows a dialog with a text input field.
|
||||
|
||||
2 . `react-native link react-native-dialogs`
|
||||
| Parameter | Type | Default | Required | Description |
|
||||
|-----------|----------------------------------------|---------|----------|--------------------------------------------|
|
||||
| title | `string, null, void` | | | Title of dialog |
|
||||
| content | `string, null, void` | | | Message of dialog |
|
||||
| options | [`OptionsPrompt`](#type-optionsprompt) | | | See [`OptionsPrompt`](#type-optionsprompt) |
|
||||
|
||||
In `android/app/build.gradle`, add a dependency to `':react-native-dialogs'` and URL of the Jitpack maven repository (to download the library https://github.com/afollestad/material-dialogs) :
|
||||
```
|
||||
repositories {
|
||||
maven { url "https://jitpack.io" }
|
||||
}
|
||||
##### `showPicker`
|
||||
|
||||
> static showProgress(
|
||||
> title?: null | string,
|
||||
> content?: null | string,
|
||||
> options: OptionsPicker
|
||||
> ): Promise<
|
||||
> {| action: "actionNegative" | "actionNeutral" | "actionDismiss" |} |
|
||||
> {| action: "actionSelect", selectedItem: ListItem |} |
|
||||
> {| action: "actionSelect", selectedItems: ListItem[] |}
|
||||
> >
|
||||
|
||||
Shows a regular alert, but also with items that can be selected.
|
||||
|
||||
| Parameter | Type | Default | Required | Description |
|
||||
|-----------|------------------------------------------|---------|----------|--------------------------------------------|
|
||||
| title | `string, null, void` | | | Title of dialog |
|
||||
| content | `string, null, void` | | | Message of dialog |
|
||||
| options | [`OptionsPicker`](#type-optionsprogress) | | | See [`OptionsPrompt`](#type-optionspicker) |
|
||||
|
||||
##### `showProgress`
|
||||
|
||||
> static showProgress(
|
||||
> content?: null | string,
|
||||
> options: OptionsProgress
|
||||
> ): Promise<{| action:"actionDismiss" |}>
|
||||
|
||||
Shows a progress dialog. By default no buttons are shown, and hardware back button does not close it. You must close it with `DialogAndroid.dismiss()`.
|
||||
|
||||
| Parameter | Type | Default | Required | Description |
|
||||
|-----------|--------------------------------------------|---------|----------|----------------------------------------------|
|
||||
| content | `string, null, void` | | | Message of dialog |
|
||||
| options | [`OptionsProgress`](#type-optionsprogress) | | | See [`OptionsPrompt`](#type-optionsprogress) |
|
||||
|
||||
### Types
|
||||
|
||||
[Flow](http://flow.org/) is used as the typing system.
|
||||
|
||||
#### Internal Types
|
||||
|
||||
##### `type ActionType`
|
||||
|
||||
> "actionDismiss" | "actionNegative" | "actionNeutral" | "actionPositive" | "actionSelect"
|
||||
|
||||
##### `type ListItem`
|
||||
|
||||
> { label:string } | { label:string, id:any } | {}
|
||||
|
||||
**Notes**
|
||||
|
||||
* If `label` key does not exist, specify which key should be used as the label with `labelKey` property of [`OptionsPicker`](#type-optionspicker).
|
||||
* `id` is only required if `selectedId`/`selectedIds` needs to be used.
|
||||
* If `id` key does not exist, specify which key should be used as the id with `idKey` property of [`OptionsPicker`](#type-optionspicker).
|
||||
|
||||
##### `type ListType`
|
||||
|
||||
> "listCheckbox" | "listPlain" | "listRadio"
|
||||
|
||||
##### `type OptionsCommon`
|
||||
|
||||
> {
|
||||
> cancelable?: boolean,
|
||||
> content?: string,
|
||||
> contentColor?: string,
|
||||
> contentIsHtml?: boolean,
|
||||
> forceStacking?: boolean
|
||||
> linkColor?: ColorValue,
|
||||
> negativeColor?: ColorValue,
|
||||
> negativeText?: string,
|
||||
> neutralColor?: ColorValue,
|
||||
> neutralText?: string,
|
||||
> positiveColor?: ColorValue,
|
||||
> positiveText?: string, // default "OK"
|
||||
> title?: string,
|
||||
> titleColor?: ColorValue,
|
||||
> }
|
||||
|
||||
| Key | Type | Default | Required | Description |
|
||||
|---------------|----------------------------------------------------------------------------|---------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| cancelable | `boolean` | | | If tapping outside of dialog area, or hardware back button, should dismiss dialog. |
|
||||
| content | `string` | | | Dialog message |
|
||||
| contentColor | [`ColorValue`](https://facebook.github.io/react-native/docs/colors.html) | | | Color of dialog message |
|
||||
| contentIsHtml | `boolean` | | | If dialog message should be parsed as html. (supported tags include: `<a>`, `<img>`, etc) |
|
||||
| forceStacking | `boolean` | | | If you have multiple action buttons that together are too wide to fit on one line, the dialog will stack the buttons to be vertically oriented. |
|
||||
| linkColor | [`ColorValue`](https://facebook.github.io/react-native/docs/colors.html) | | | If `contentIsHtml` is true, and `content` contains `<a>` tags, these are colored with this color |
|
||||
| negativeColor | [`ColorValue`](https://facebook.github.io/react-native/docs/colors.html) | | | |
|
||||
| negativeText | `string` | | | If falsy, button is not shown. |
|
||||
| neutralColor | [`ColorValue`](https://facebook.github.io/react-native/docs/colors.html) | | | |
|
||||
| neutralText | `string` | | | Shows button in far left with this string as label. If falsy, button is not shown. |
|
||||
| positiveColor | [`ColorValue`](https://facebook.github.io/react-native/docs/colors.html) | | | |
|
||||
| positiveText | `string` | | | If falsy, button is not shown. |
|
||||
| title | `string` | | | Title of dialog |
|
||||
| titleColor | [`ColorValue`](https://facebook.github.io/react-native/docs/colors.html) | | | Color of title |
|
||||
|
||||
##### `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'>
|
||||
> widgetColor?: ColorValue
|
||||
> }
|
||||
|
||||
| Key | Type | Default | Required | Description |
|
||||
|---------------|----------------------------------------------------------------------------|---------|----------|----------------------------------------------------------|
|
||||
| contentColor | [`OptionsCommon#contentColor`](#type-optionscommon) | | | See [`OptionsCommon#contentColor`](#type-optionscommon) |
|
||||
| contentIsHtml | [`OptionsCommon#contentIsHtml`](#type-optionscommon) | | | See [`OptionsCommon#contentIsHtml`](#type-optionscommon) |
|
||||
| linkColor | [`OptionsCommon#linkColor`](#type-optionscommon) | | | See [`OptionsCommon#linkColor`](#type-optionscommon) |
|
||||
| style | [`ProgressStyle`](#type-ProgressStyle) | | | See [`ProgressStyle`](#type-progressstyle) |
|
||||
| title | [`OptionsCommon#title`](#type-optionscommon) | | | See [`OptionsCommon#title`](#type-optionscommon) |
|
||||
| titleColor | [`OptionsCommon#titleColor`](#type-optionscommon) | | | See [`OptionsCommon#titleColor`](#type-optionscommon) |
|
||||
| widgetColor | [`ColorValue`](https://facebook.github.io/react-native/docs/colors.html) | | | Color of progress indicator |
|
||||
|
||||
##### `type OptionsPicker`
|
||||
|
||||
> {
|
||||
> ...OptionsCommon,
|
||||
> idKey?: string,
|
||||
> items: ListItem[],
|
||||
> labelKey?: string,
|
||||
> neutralIsClear?: boolean,
|
||||
> selectedId?: any,
|
||||
> selectedIds?: any[],
|
||||
> type?: string,
|
||||
> widgetColor?: ColorValue
|
||||
> }
|
||||
|
||||
| Key | Type | Default | Required | Description |
|
||||
|----------------|----------------------------------------------------------------------------|---------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| OptionsCommon | [`OptionsCommon`](#type-optionscommon) | | | See [`OptionsCommon`](#type-optionscommon) |
|
||||
| idKey | `string` | "id" | | |
|
||||
| items | [`ListItem`](#type-listitem)[] | | Yes | See [`ListItem`](#type-listitem) |
|
||||
| labelKey | `string` | "label" | | |
|
||||
| neutralIsClear | `boolean` | | | Pressing the neutral button causes the dialog to be closed and `selectedItems` to be an empty array. Only works if `neutralText` is also supplied. |
|
||||
| selectedId | `any` | | | The respective radio will be selected on dialog show. If no such id is found, then nothing is selected. Only applicable if `type` is `DialogAndroid.listRadio`. Requires that `items[]` contain key described by `idKey`. |
|
||||
| selectedIds | `any[]` | | | The respective checkbox will be selected on dialog show. If no such id is found, nothing is selected for that id. Only applicable if `type` is `DialogAndroid.listCheckbox`. Requires that `items[]` contain key described by `idKey`. |
|
||||
| type | [`ListType`](#type-listtype) | `DialogAndroid.listPlain` | | See [`ListType`](#type-listtype) |
|
||||
| widgetColor | [`ColorValue`](https://facebook.github.io/react-native/docs/colors.html) | | | Color of radio or checkbox |
|
||||
|
||||
##### `type OptionsPrompt`
|
||||
|
||||
> {
|
||||
> ...OptionsCommon,
|
||||
>
|
||||
> widgetColor?: ColorValue
|
||||
> }
|
||||
|
||||
| Key | Type | Default | Required | Description |
|
||||
|---------------|----------------------------------------------------------------------------|---------|----------|--------------------------------------------|
|
||||
| OptionsCommon | [`OptionsCommon`](#type-optionscommon) | | | See [`OptionsCommon`](#type-optionscommon) |
|
||||
| widgetColor | [`ColorValue`](https://facebook.github.io/react-native/docs/colors.html) | | | Color of field underline and cursor |
|
||||
|
||||
##### `type ProgressStyle`
|
||||
|
||||
> "progressHorizontal"
|
||||
|
||||
### Examples
|
||||
|
||||
#### Progress dialog
|
||||
|
||||
```js
|
||||
DialogAndroid.showProgress(null, 'Downloading...', {
|
||||
style: DialogAndroid.progressHorizontal
|
||||
});
|
||||
setTimeout(DialogAndroid.dismiss, 5000);
|
||||
```
|
||||
|
||||
### Manual installation
|
||||
#### List of radio items dismissed on press
|
||||
|
||||
Install the npm package [`react-native-dialogs`](https://www.npmjs.com/package/react-native-dialogs). Inside your React Native project, run ([example](https://github.com/aakashns/react-native-dialogs-example/commit/e6b83bf3d2238cf7e4ec3688519f38b2544ccad5)):
|
||||
```bash
|
||||
npm install --save react-native-dialogs
|
||||
```
|
||||
If we want the first press on an item to close and accept the dialog, we pass `null` to `positiveText`:
|
||||
|
||||
|
||||
In `android/app/build.gradle`, add a dependency to `':react-native-dialogs'` and URL of the Jitpack maven repository (to download the library https://github.com/afollestad/material-dialogs) :
|
||||
```
|
||||
repositories {
|
||||
maven { url "https://jitpack.io" }
|
||||
}
|
||||
|
||||
```
|
||||
The changes should look like [this](https://github.com/aakashns/react-native-dialogs-example/commit/b58086d8fb9ece99f0e678dd8bf0e689a856bd43).
|
||||
|
||||
You also need to update your ```settings.gradle``` and add:
|
||||
```
|
||||
include ':react-native-dialogs'
|
||||
project(':react-native-dialogs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-dialogs/android')
|
||||
```
|
||||
|
||||
update your ```app.gradle``` and add:
|
||||
```
|
||||
dependencies {
|
||||
compile project(':react-native-dialogs') // <-- Add this line
|
||||
compile "com.android.support:appcompat-v7:23.0.1"
|
||||
compile "com.facebook.react:react-native:+" // From node_modules
|
||||
//...
|
||||
```js
|
||||
const { selectedItem } = await DialogAndroid.alert('Title', null, {
|
||||
positiveText: null,
|
||||
items: [
|
||||
{ label:'Apple', id:'apple' },
|
||||
{ label:'Orange', id:'orange' },
|
||||
{ label:'Pear', id:'pear' }
|
||||
],
|
||||
selectedId: 'apple'
|
||||
});
|
||||
if (selectedItem) {
|
||||
console.log('You selected item:', item);
|
||||
}
|
||||
```
|
||||
|
||||
Next, you need to change the `MainApplication` of your app to register `ReactNativeDialogsPackage` :
|
||||
```java
|
||||
// ... Other imports
|
||||
import com.aakashns.reactnativedialogs.ReactNativeDialogsPackage; // <-- Add this import.
|
||||
|
||||
//...
|
||||
public class MainApplication extends ReactActivity {
|
||||
//...
|
||||
#### Checklist with clear button
|
||||
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new MainReactPackage(),
|
||||
new ReactNativeDialogsPackage() // <-- Add this package.
|
||||
);
|
||||
}
|
||||
}
|
||||
We can make the neutral button be a special button. Pressing it will clear the list and close the dialog.
|
||||
|
||||
```
|
||||
See [this changelog](https://github.com/aakashns/react-native-dialogs-example/commit/52cac27756963bcd2f4fdcd039e1a78028bb0abd) for reference(Earlier versions of React native used MainActivity instead of MainApplication).
|
||||
|
||||
Now you're finally ready to start using module in your React Native application. See [this changelog](https://github.com/aakashns/react-native-dialogs-example/commit/2d8e02c22275479d2fbbb89f99dcb846834bec9d) for an example that uses `DialogAndroid`.
|
||||
|
||||
Usage
|
||||
-----
|
||||
```javascript
|
||||
import DialogAndroid from 'react-native-dialogs';
|
||||
|
||||
let options = {
|
||||
title: 'Hello, World!',
|
||||
content: 'I\'m just simple Dialog',
|
||||
positiveText: 'OK',
|
||||
negativeText: 'Cancel'
|
||||
};
|
||||
|
||||
let showDialog = function () {
|
||||
var dialog = new DialogAndroid();
|
||||
dialog.set(options);
|
||||
dialog.show();
|
||||
```js
|
||||
const { selectedItems } = await DialogAndroid.alert('Title', null, {
|
||||
items: [
|
||||
{ label:'Apple', id:'apple' },
|
||||
{ label:'Orange', id:'orange' },
|
||||
{ label:'Pear', id:'pear' }
|
||||
],
|
||||
selectedIds: ['apple', 'orange'], // or if is not array of objects with "id" can use selectedIndices
|
||||
neutralIsClear: true,
|
||||
neutralText: 'Empty List'
|
||||
});
|
||||
if (selectedItems) {
|
||||
if (!selectedItems.length) {
|
||||
console.log('You emptied the list');
|
||||
} else {
|
||||
console.log('You selected items:', selectedItems);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Creation of a dialog works in 3 steps :
|
||||
1. Create a new dialog using `new DialogAndroid()`.
|
||||
2. Set some options using `dialog.set(options)`. `set` can be called multiple times, and options from multiple calls will be merged.
|
||||
3. Show the dialog using `dialog.show()`.
|
||||
4. (optional) dismiss the dialog with `dialog.dismiss()`.
|
||||
|
||||
This library is a thin wrapper over [afollestad/material-dialogs](https://github.com/afollestad/material-dialogs), which provides builders for showing Material Design dialogs in Android apps. The options provided to `set` map more or less directly to the methods provided in the original library. See [its documentation](https://github.com/afollestad/material-dialogs#basic-dialog) for reference.
|
||||
#### Prompt
|
||||
|
||||
The following options are currently supported (value type is `String` unless mentioned otherwise) :
|
||||
* [`title`](https://github.com/afollestad/material-dialogs#basic-dialog)
|
||||
* [`titleColor`](https://github.com/afollestad/material-dialogs#colors)
|
||||
* [`content`](https://github.com/afollestad/material-dialogs#basic-dialog)
|
||||
* [`contentColor`](https://github.com/afollestad/material-dialogs#colors)
|
||||
* [`positiveText`](https://github.com/afollestad/material-dialogs#basic-dialog)
|
||||
* [`positiveColor`](https://github.com/afollestad/material-dialogs#basic-dialog)
|
||||
* [`onPositive`](https://github.com/afollestad/material-dialogs#callbacks) (function with no arguments)
|
||||
* [`negativeText`](https://github.com/afollestad/material-dialogs#basic-dialog)
|
||||
* [`negativeColor`](https://github.com/afollestad/material-dialogs#basic-dialog)
|
||||
* [`onNegative`](https://github.com/afollestad/material-dialogs#callbacks) (function with no arguments)
|
||||
* [`neutralText`](https://github.com/afollestad/material-dialogs#neutral-action-button)
|
||||
* [`neutralColor`](https://github.com/afollestad/material-dialogs#neutral-action-button)
|
||||
* [`onNeutral`](https://github.com/afollestad/material-dialogs#callbacks) (function with no arguments)
|
||||
* [`onAny`](https://github.com/afollestad/material-dialogs#callbacks) (function with no arguments)
|
||||
* [`items`](https://github.com/afollestad/material-dialogs#list-dialogs) (array of strings)
|
||||
* [`itemsCallback`](https://github.com/afollestad/material-dialogs#list-dialogs) (function with 2 arguments : selectedIndex (int) and selectedItem (string))
|
||||
* [`itemsCallbackSingleChoice`](https://github.com/afollestad/material-dialogs#single-choice-list-dialogs) (function with 2 arguments : selectedIndex (int) and selectedItem (string))
|
||||
* [`selectedIndex`](https://github.com/afollestad/material-dialogs#single-choice-list-dialogs) (int) - set the preselected index for Single Choice List
|
||||
* [`itemsCallbackMultiChoice`](https://github.com/afollestad/material-dialogs#multi-choice-list-dialogs) (function with 2 arguments : selected indices (array of ints) and selected items (array of strings)
|
||||
* [`selectedIndices`](https://github.com/afollestad/material-dialogs#multi-choice-list-dialogs) (array of ints) - set the preselected indices for Multiple Choice List
|
||||
* [`widgetColor`](https://github.com/afollestad/material-dialogs#coloring-radio-buttons) - set the color of Radio Buttons and EditText
|
||||
* [`linkColor`](https://github.com/afollestad/material-dialogs#colors)
|
||||
* `multiChoiceClearButton` (boolean) - provide a 'Clear' button in Multiple Choice List
|
||||
* `autoDismiss` (boolean)
|
||||
* [`forceStacking`](https://github.com/afollestad/material-dialogs#stacked-action-buttons) (boolean)
|
||||
* [`alwaysCallSingleChoiceCallback`](https://github.com/afollestad/material-dialogs#single-choice-list-dialogs) (boolean)
|
||||
* [`alwaysCallMultiChoiceCallback`](https://github.com/afollestad/material-dialogs#multi-choice-list-dialogs) (boolean)
|
||||
* [`cancelable`](https://github.com/afollestad/material-dialogs#show-cancel-and-dismiss-callbacks) (boolean)
|
||||
* [`showListener`](https://github.com/afollestad/material-dialogs#show-cancel-and-dismiss-callbacks) (function)
|
||||
* [`cancelListener`](https://github.com/afollestad/material-dialogs#show-cancel-and-dismiss-callbacks) (function)
|
||||
* [`dismissListener`](https://github.com/afollestad/material-dialogs#show-cancel-and-dismiss-callbacks) (function)
|
||||
* [`input`](https://github.com/afollestad/material-dialogs#input-dialogs) - Object containing the following keys (all optional except callback) :
|
||||
* [`hint`](https://github.com/afollestad/material-dialogs#input-dialogs)
|
||||
* [`prefill`](https://github.com/afollestad/material-dialogs#input-dialogs)
|
||||
* [`allowEmptyInput`](https://github.com/afollestad/material-dialogs#input-dialogs) (boolean)
|
||||
* [`minLength`](https://github.com/afollestad/material-dialogs#limiting-input-length) (int)
|
||||
* [`maxLength`](https://github.com/afollestad/material-dialogs#limiting-input-length) (int)
|
||||
* [`type`](https://github.com/afollestad/material-dialogs#input-dialogs) (int)
|
||||
* [`callback`](https://github.com/afollestad/material-dialogs#input-dialogs) (function with 1 argument : user provided input)
|
||||
* [`alwaysCallInputCallback`](https://github.com/afollestad/material-dialogs#input-dialogs) (boolean)
|
||||
* [`progress`](https://github.com/afollestad/material-dialogs#progress-dialogs) - Object containing following keys
|
||||
* [`indeterminate`](https://github.com/afollestad/material-dialogs#indeterminate-progress-dialogs) (boolean) - must be true, determinate is not supported
|
||||
* [`style`](https://github.com/afollestad/material-dialogs#make-an-indeterminate-dialog-horizontal) - (string) either 'horizontal' or undefined
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Simple example project : https://github.com/aakashns/react-native-dialogs-example
|
||||
|
||||
Complex example project : [examples/ExampleApp](https://github.com/aakashns/react-native-dialogs/tree/54d1253213b1a6a453a3ffb1d2dcc65b8dc287fd/examples/ExampleApp)
|
||||
|
||||
Try out the following values for option (taken from [examples/ExampleApp/dialogData.js](https://github.com/aakashns/react-native-dialogs/tree/54d1253213b1a6a453a3ffb1d2dcc65b8dc287fd/examples/ExampleApp/dialogData.js)):
|
||||
|
||||
```javascript
|
||||
{
|
||||
"title": "Use Google's Location Services?",
|
||||
"content": "This app wants to access your location.",
|
||||
"positiveText": "Agree",
|
||||
"negativeText": "Disagree"
|
||||
```js
|
||||
const { action, text } = await DialogAndroid.prompt('Title', 'Message', {
|
||||
isHorizontal:true
|
||||
});
|
||||
if (action === DialogAndroid.actionPositive) {
|
||||
alert(`You submitted: ${text}`)
|
||||
}
|
||||
```
|
||||
|
||||
```javascript
|
||||
{
|
||||
"title": "Use Google's Location Services?",
|
||||
"content": "Let Google help apps determine location. This means sending anonymous location data to Google, even when no apps are running.",
|
||||
"positiveText": "Agree",
|
||||
"negativeText": "Disagree",
|
||||
"neutralText": "More Info",
|
||||
"onPositive": () => ToastAndroid.show("POSITIVE!", ToastAndroid.SHORT),
|
||||
"onNegative": () => ToastAndroid.show("NEGATIVE!", ToastAndroid.SHORT),
|
||||
"onNeutral": () => ToastAndroid.show("NEUTRAL!", ToastAndroid.SHORT),
|
||||
}
|
||||
#### HTML
|
||||
|
||||
```js
|
||||
DialogAndroid.alert('Title', `This is a link <a href="https://www.duckduckgo.com/">DuckDuckGo</a>`, {
|
||||
contentIsHtml: true
|
||||
});
|
||||
```
|
||||
|
||||
```javascript
|
||||
"data": {
|
||||
"items": [
|
||||
"Twitter",
|
||||
"Google+",
|
||||
"Instagram",
|
||||
"Facebook"
|
||||
],
|
||||
"title": "Social Networks",
|
||||
itemsCallback: (id, text) => ToastAndroid.show(id + ": " + text, ToastAndroid.SHORT);
|
||||
}
|
||||
```
|
||||
#### assignDefaults
|
||||
|
||||
```javascript
|
||||
"data": {
|
||||
"items": [
|
||||
"Twitter",
|
||||
"Google+",
|
||||
"Instagram",
|
||||
"Facebook"
|
||||
],
|
||||
"title": "Social Networks",
|
||||
itemsCallbackSingleChoice: (id, text) => ToastAndroid.show(id + ": " + text, ToastAndroid.SHORT);
|
||||
}
|
||||
```
|
||||
You can set some defaults so you don't have to change it everytime.
|
||||
|
||||
```javascript
|
||||
"data": {
|
||||
"items": [
|
||||
"Twitter",
|
||||
"Google+",
|
||||
"Instagram",
|
||||
"Facebook"
|
||||
],
|
||||
"title": "Social Networks",
|
||||
"positiveText": "Choose",
|
||||
itemsCallbackMultiChoice: (id, text) => ToastAndroid.show(id + ": " + text, ToastAndroid.SHORT);
|
||||
}
|
||||
```
|
||||
|
||||
Progress dialog colored blue, with no buttons, disables hardware back, and dismisses after 5 seconds:
|
||||
|
||||
```
|
||||
const dialog = new DialogAndroid();
|
||||
dialog.set({
|
||||
content: 'Downloading...',
|
||||
progress: {
|
||||
indeterminate: true,
|
||||
style: 'horizontal'
|
||||
},
|
||||
widgetColor: 'blue',
|
||||
cancelable: false
|
||||
})
|
||||
dialog.show();
|
||||
setTimeout(dialog.dismiss, 5000);
|
||||
```js
|
||||
DialogAndroid.assignDefaults({
|
||||
title: 'Default Title',
|
||||
contentColor: 'rgba(0, 0, 0, 0.2)',
|
||||
widgetColor: 'blue'
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
TODO
|
||||
Now any time you supply `undefined` to title, it will use the default assigned above.
|
||||
|
||||
```js
|
||||
DialogAndroid.alert(undefined, 'message here')
|
||||
```
|
||||
|
||||
This will show title "Default Title", with no negative button, and the color of the message will be 20% black. If you did `Dialog.showProgress`, the progress indicator would be blue. etc.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Upcoming Features
|
||||
-------
|
||||
TODO
|
||||
|
@ -2,7 +2,9 @@ package com.aakashns.reactnativedialogs.modules;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Color;
|
||||
import android.text.Html;
|
||||
import android.view.View;
|
||||
import android.os.Build;
|
||||
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.GravityEnum;
|
||||
@ -46,37 +48,48 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
builder.title(options.getString("title"));
|
||||
break;
|
||||
case "content":
|
||||
builder.content(options.getString("content"));
|
||||
if(options.hasKey("contentIsHtml") && options.getBoolean("contentIsHtml")) {
|
||||
// // i have no idea how to get this to work, it seems its all api level 24 stuff
|
||||
// // requires buildToolsVersion >= "24.0.1"
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
// builder.content(Html.fromHtml(options.getString("content"), Html.FROM_HTML_MODE_LEGACY | Html.FROM_HTML_MODE_COMPACT));
|
||||
// } else {
|
||||
// builder.content(Html.fromHtml(options.getString("content"), Html.FROM_HTML_MODE_COMPACT));
|
||||
// }
|
||||
builder.content(Html.fromHtml(options.getString("content")));
|
||||
} else {
|
||||
builder.content(options.getString("content"));
|
||||
}
|
||||
break;
|
||||
case "positiveText":
|
||||
builder.positiveText(options.getString("positiveText"));
|
||||
break;
|
||||
case "positiveColor":
|
||||
builder.positiveColor(Color.parseColor(options.getString("positiveColor")));
|
||||
builder.positiveColor(options.getInt("positiveColor"));
|
||||
break;
|
||||
case "negativeText":
|
||||
builder.negativeText(options.getString("negativeText"));
|
||||
break;
|
||||
case "negativeColor":
|
||||
builder.negativeColor(Color.parseColor(options.getString("negativeColor")));
|
||||
builder.negativeColor(options.getInt("negativeColor"));
|
||||
break;
|
||||
case "neutralText":
|
||||
builder.neutralText(options.getString("neutralText"));
|
||||
break;
|
||||
case "neutralColor":
|
||||
builder.neutralColor(Color.parseColor(options.getString("neutralColor")));
|
||||
builder.neutralColor(options.getInt("neutralColor"));
|
||||
break;
|
||||
case "titleColor":
|
||||
builder.titleColor(Color.parseColor(options.getString("titleColor")));
|
||||
builder.titleColor(options.getInt("titleColor"));
|
||||
break;
|
||||
case "widgetColor":
|
||||
builder.widgetColor(Color.parseColor(options.getString("widgetColor")));
|
||||
builder.widgetColor(options.getInt("widgetColor"));
|
||||
break;
|
||||
case "linkColor":
|
||||
builder.linkColor(Color.parseColor(options.getString("linkColor")));
|
||||
builder.linkColor(options.getInt("linkColor"));
|
||||
break;
|
||||
case "contentColor":
|
||||
builder.contentColor(Color.parseColor(options.getString("contentColor")));
|
||||
builder.contentColor(options.getInt("contentColor"));
|
||||
break;
|
||||
case "items":
|
||||
ReadableArray arr = options.getArray("items");
|
||||
@ -172,6 +185,7 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
|
||||
MaterialDialog.Builder mBuilder;
|
||||
MaterialDialog mDialog;
|
||||
private boolean mCallbackConsumed = false;
|
||||
|
||||
@ReactMethod
|
||||
public void show(ReadableMap options, final Callback callback) {
|
||||
@ -186,7 +200,10 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
mBuilder.onPositive(new MaterialDialog.SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
|
||||
callback.invoke("onPositive");
|
||||
if (!mCallbackConsumed) {
|
||||
mCallbackConsumed = true;
|
||||
callback.invoke("onPositive");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -195,7 +212,10 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
mBuilder.onNegative(new MaterialDialog.SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
|
||||
callback.invoke("onNegative");
|
||||
if (!mCallbackConsumed) {
|
||||
mCallbackConsumed = true;
|
||||
callback.invoke("onNegative");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -204,7 +224,10 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
mBuilder.onNeutral(new MaterialDialog.SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
|
||||
callback.invoke("onNeutral");
|
||||
if (!mCallbackConsumed) {
|
||||
mCallbackConsumed = true;
|
||||
callback.invoke("onNeutral");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -213,7 +236,16 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
mBuilder.onAny(new MaterialDialog.SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
|
||||
callback.invoke("onAny");
|
||||
if (!mCallbackConsumed) {
|
||||
mCallbackConsumed = true;
|
||||
if (dialogAction == DialogAction.POSITIVE) {
|
||||
callback.invoke("onAny", 0);
|
||||
} else if (dialogAction == DialogAction.NEUTRAL) {
|
||||
callback.invoke("onAny", 1);
|
||||
} else {
|
||||
callback.invoke("onAny", 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -223,7 +255,10 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
@Override
|
||||
public void onSelection(MaterialDialog materialDialog, View view, int i,
|
||||
CharSequence charSequence) {
|
||||
callback.invoke("itemsCallback", i, charSequence == null ? null : charSequence.toString());
|
||||
if (!mCallbackConsumed) {
|
||||
mCallbackConsumed = true;
|
||||
callback.invoke("itemsCallback", i, charSequence == null ? null : charSequence.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -237,8 +272,11 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
@Override
|
||||
public boolean onSelection(MaterialDialog materialDialog, View view, int i,
|
||||
CharSequence charSequence) {
|
||||
charSequence = charSequence == null ? "" : charSequence;
|
||||
callback.invoke("itemsCallbackSingleChoice", i, charSequence.toString());
|
||||
if (!mCallbackConsumed) {
|
||||
mCallbackConsumed = true;
|
||||
charSequence = charSequence == null ? "" : charSequence;
|
||||
callback.invoke("itemsCallbackSingleChoice", i, charSequence.toString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@ -270,7 +308,10 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
selected.append(integers[integers.length - 1]);
|
||||
}
|
||||
|
||||
callback.invoke("itemsCallbackMultiChoice", selected.toString());
|
||||
if (!mCallbackConsumed) {
|
||||
mCallbackConsumed = true;
|
||||
callback.invoke("itemsCallbackMultiChoice", selected.toString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@ -278,7 +319,7 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
// Provide a 'Clear' button to unselect all choices
|
||||
if (options.hasKey("multiChoiceClearButton") &&
|
||||
options.getBoolean("multiChoiceClearButton")) {
|
||||
mBuilder.neutralText("Clear").onNeutral(new MaterialDialog.SingleButtonCallback() {
|
||||
mBuilder.onNeutral(new MaterialDialog.SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
|
||||
materialDialog.clearSelectedIndices();
|
||||
@ -287,20 +328,25 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
}
|
||||
}
|
||||
|
||||
if (options.hasKey("showListener")) {
|
||||
mBuilder.showListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface dialog) {
|
||||
callback.invoke("showListener");
|
||||
}
|
||||
});
|
||||
}
|
||||
mBuilder.showListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface dialog) {
|
||||
// if (!mCallbackConsumed) {
|
||||
// mCallbackConsumed = true;
|
||||
// callback.invoke("showListener");
|
||||
// }
|
||||
mCallbackConsumed = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (options.hasKey("cancelListener")) {
|
||||
mBuilder.cancelListener(new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
callback.invoke("cancelListener");
|
||||
if (!mCallbackConsumed) {
|
||||
mCallbackConsumed = true;
|
||||
callback.invoke("cancelListener");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -309,7 +355,10 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
mBuilder.dismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
callback.invoke("dismissListener");
|
||||
if (!mCallbackConsumed) {
|
||||
mCallbackConsumed = true;
|
||||
callback.invoke("dismissListener");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -338,7 +387,10 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
mBuilder.input(hint, prefill, allowEmptyInput, new MaterialDialog.InputCallback() {
|
||||
@Override
|
||||
public void onInput(MaterialDialog materialDialog, CharSequence charSequence) {
|
||||
callback.invoke("input", charSequence.toString());
|
||||
if (!mCallbackConsumed) {
|
||||
mCallbackConsumed = true;
|
||||
callback.invoke("input", charSequence.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -369,7 +421,10 @@ public class DialogAndroid extends ReactContextBaseJavaModule {
|
||||
.adapter(simpleListAdapter, new MaterialDialog.ListCallback() {
|
||||
@Override
|
||||
public void onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
|
||||
callback.invoke(which, text);
|
||||
if (!mCallbackConsumed) {
|
||||
mCallbackConsumed = true;
|
||||
callback.invoke(which, text);
|
||||
}
|
||||
if (simple != null) {
|
||||
simple.dismiss();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user