Best JavaScript code snippet using storybook-root
App.js
Source:App.js
1import React from 'react';2import {View, TextInput, ImageBackground, TouchableOpacity, Image, StyleSheet, ScrollView, Text, Keyboard, FlatList, AppState, AsyncStorage, Modal, Picker, Dimensions, Alert, PermissionsAndroid } from 'react-native';3import generator from './src/generator.js' 4import {Mutex} from 'async-mutex'5import MultiSelect from 'react-native-multiple-select';6import uuid from 'react-native-uuid'7import fs from 'react-native-fs'8import DocumentPicker from 'react-native-document-picker';9export default class App extends React.Component {10 11 12// ==================================================================13// Rendering14 // This is a 1 page app, the main screen is a parchment-like background with 3 buttons at the top, a scrollable menu on the left, and a text area on the right:15 // Generate button: Makes a new NPC and displays the full text on screen. Has a right portion of button that can be clicked instead of the main generate button to make a STRONG NPC16 // Settings button: A modal displaying checkable-settings for the NPC Generator. Displays when user clicks the gear button and goes away when they click outside the modal17 // Delete button: Red X that removes the currently-displayed character from the character list, and switches to displaying another 18 // Scrollable menu: List of NPC names in front of crests, corresponding to our characters array. when one is clicked, it displays in the text area 19 // Text area: Displays the current NPC info, editable 20 render() {21 return (22 <ImageBackground 23 source={require('./src/Parchment.png')}24 style={this.styles.background}>25 26 {this.state.messages.intro && this.state.loaded && <View style={this.styles.overlay} />}27 28 <Modal29 animationType="fade"30 transparent={true}31 visible={this.state.settingsVisible}32 onRequestClose={()=>{}}>33 34 <TouchableOpacity 35 style={this.styles.modalBackground} 36 onPress={()=>this.showSettings(false)}37 activeOpacity={0.5} />38 39 <ImageBackground40 source={require('./src/plaque.jpg')}41 imageStyle={this.styles.modalImage}42 style={this.styles.modalContent}>43 44 <ScrollView style={this.styles.modalScroll}>45 46 <View style={this.styles.modalSettingContainer}>47 <Text style={this.styles.modalSettingLabel}>Level</Text>48 <Picker49 selectedValue={this.state[this.state.settingsPage].Level}50 style={this.styles.modalSettingPickerThin}51 onValueChange={(itemValue, itemIndex) => this.setSetting("Level", itemValue, this.state.settingsPage)}52 mode="dropdown" >53 54 <Picker.Item label="0" value={0} />55 <Picker.Item label="1" value={1} />56 <Picker.Item label="2" value={2} />57 <Picker.Item label="3" value={3} />58 <Picker.Item label="4" value={4} />59 </Picker>60 </View>61 62 <View style={[this.styles.modalSettingContainer, this.state[this.state.settingsPage].Level > 0 ? this.styles.hidden : this.styles.visible]}>63 <Text style={this.styles.modalSettingLabel}>Level 0 NPCs have no class!</Text>64 </View>65 66 <View style={[this.styles.modalSettingContainer, this.state[this.state.settingsPage].Level > 0 ? this.styles.visible : this.styles.hidden]}>67 <Text style={this.styles.modalSettingLabel}>Class</Text>68 <Picker69 selectedValue={this.state[this.state.settingsPage].Class}70 style={this.styles.modalSettingPicker}71 onValueChange={(itemValue, itemIndex) => this.setSetting("Class", itemValue, this.state.settingsPage)}72 mode="dropdown" >73 <Picker.Item label="Any" value="Any" />74 {this.state.customTraits.classes.map(clas => {75 return (76 <Picker.Item label={clas.Name} value={clas.id} />77 );78 })}79 <Picker.Item label="Artificer" value="artificer" />80 <Picker.Item label="Barbarian" value="barbarian" />81 <Picker.Item label="Bard" value="bard" />82 <Picker.Item label="Cleric" value="cleric" />83 <Picker.Item label="Druid" value="druid" />84 <Picker.Item label="Fighter" value="fighter" />85 <Picker.Item label="Monk" value="monk" />86 <Picker.Item label="Paladin" value="paladin" />87 <Picker.Item label="Ranger" value="ranger" />88 <Picker.Item label="Rogue" value="rogue" />89 <Picker.Item label="Sorcerer" value="sorcerer" />90 <Picker.Item label="Warlock" value="warlock" />91 <Picker.Item label="Wizard" value="wizard" />92 </Picker>93 </View>94 95 <View style={this.styles.modalSettingContainer}>96 <Text style={this.styles.modalSettingLabel}>Race</Text>97 <Picker98 selectedValue={this.state[this.state.settingsPage].Race}99 style={this.styles.modalSettingPicker}100 onValueChange={(itemValue, itemIndex) => this.setSetting("Race", itemValue, this.state.settingsPage)}101 mode="dropdown" >102 103 <Picker.Item label="Any" value="Any" />104 {this.state.customTraits.races.map(race => {105 return (106 <Picker.Item label={race.Name} value={race.id} />107 );108 })}109 <Picker.Item label="Dragonborn" value="dragonborn" />110 <Picker.Item label="Dwarf" value="dwarf" />111 <Picker.Item label="Elf" value="elf" />112 <Picker.Item label="Gnome" value="gnome" />113 <Picker.Item label="Half-Elf" value="half-elf" />114 <Picker.Item label="Halfling" value="halfling" />115 <Picker.Item label="Half-Orc" value="half-orc" />116 <Picker.Item label="Human" value="human" />117 <Picker.Item label="Seafolk" value="seafolk" />118 <Picker.Item label="Tabaxi" value="tabaxi" />119 <Picker.Item label="Tiefling" value="tiefling" />120 </Picker>121 </View>122 123 <View style={this.styles.modalSettingContainer}>124 <Text style={this.styles.modalSettingLabel}>User{"\n"}Content</Text>125 <Picker126 selectedValue={this.state[this.state.settingsPage].customRate}127 style={this.styles.modalSettingPicker}128 onValueChange={(itemValue, itemIndex) => this.setSetting("customRate", itemValue, this.state.settingsPage)}129 mode="dropdown" >130 <Picker.Item label="Not included" value="none" />131 <Picker.Item label="Normal rate" value="normal" />132 <Picker.Item label="Frequently appears" value="frequent" />133 </Picker>134 </View>135 136 <View style={this.styles.modalSettingContainer}>137 <Text style={this.styles.modalSettingLabel}>Equipment</Text>138 <Picker139 selectedValue={this.state[this.state.settingsPage].Equipment}140 style={this.styles.modalSettingPickerThin}141 onValueChange={(itemValue, itemIndex) => this.setSetting("Equipment", itemValue, this.state.settingsPage)}142 mode="dropdown" >143 <Picker.Item label="0" value={0} />144 <Picker.Item label="1" value={1} />145 <Picker.Item label="2" value={2} />146 <Picker.Item label="3" value={3} />147 <Picker.Item label="4" value={4} />148 <Picker.Item label="5" value={5} />149 <Picker.Item label="6" value={6} />150 </Picker>151 </View>152 153 <View style={this.styles.modalSettingContainer}>154 <Text style={this.styles.modalSettingLabel}>Personality</Text>155 <Picker156 selectedValue={this.state[this.state.settingsPage].Personality}157 style={this.styles.modalSettingPickerThin}158 onValueChange={(itemValue, itemIndex) => this.setSetting("Personality", itemValue, this.state.settingsPage)}159 mode="dropdown" >160 <Picker.Item label="0" value={0} />161 <Picker.Item label="1" value={1} />162 <Picker.Item label="2" value={2} />163 <Picker.Item label="3" value={3} />164 <Picker.Item label="4" value={4} />165 <Picker.Item label="5" value={5} />166 </Picker>167 </View>168 169 <View style={this.styles.modalSettingContainer}>170 <Text style={this.styles.modalSettingLabel}>Appearance</Text>171 <Picker172 selectedValue={this.state[this.state.settingsPage].Appearance}173 style={this.styles.modalSettingPickerThin}174 onValueChange={(itemValue, itemIndex) => this.setSetting("Appearance", itemValue, this.state.settingsPage)}175 mode="dropdown" >176 177 <Picker.Item label="0" value={0} />178 <Picker.Item label="1" value={1} />179 <Picker.Item label="2" value={2} />180 <Picker.Item label="3" value={3} />181 <Picker.Item label="4" value={4} />182 <Picker.Item label="5" value={5} />183 </Picker>184 </View>185 186 187 </ScrollView>188 </ImageBackground>189 190 </Modal>191 <Modal192 animationType="fade"193 transparent={true}194 visible={this.state.customizeVisible}195 onRequestClose={()=>{}}>196 197 <TouchableOpacity 198 style={this.styles.modalBackground} 199 onPress={()=>this.showCustomize(false)}200 activeOpacity={0.5} />201 202 <ImageBackground203 source={require('./src/plaque.jpg')}204 imageStyle={this.styles.modalImage}205 style={this.styles.modalContent}>206 207 {this.state.customizePage == 'default' &&208 <ScrollView style={this.styles.modalScroll}>209 <TouchableOpacity210 activeOpacity={0.5}211 onPress={() => this.setState({customizePage: 'classes'})}>212 <ImageBackground213 source={require('./src/eye.png')}214 imageStyle={this.styles.modalImage}215 style={this.styles.eyeButton}>216 <Text style={this.styles.modalSettingLabel}>Classes</Text>217 </ImageBackground>218 </TouchableOpacity>219 <TouchableOpacity220 activeOpacity={0.5}221 onPress={() => this.setState({customizePage: 'abilities'})}>222 <ImageBackground223 source={require('./src/eye.png')}224 imageStyle={this.styles.modalImage}225 style={this.styles.eyeButton}>226 <Text style={this.styles.modalSettingLabel}>Abilities</Text>227 </ImageBackground>228 </TouchableOpacity>229 <TouchableOpacity230 activeOpacity={0.5}231 onPress={() => this.setState({customizePage: 'races'})}>232 <ImageBackground233 source={require('./src/eye.png')}234 imageStyle={this.styles.modalImage}235 style={this.styles.eyeButton}>236 <Text style={this.styles.modalSettingLabel}>Races</Text>237 </ImageBackground>238 </TouchableOpacity>239 <TouchableOpacity240 activeOpacity={0.5}241 onPress={() => this.setState({customizePage: 'equipment'})}>242 <ImageBackground243 source={require('./src/eye.png')}244 imageStyle={this.styles.modalImage}245 style={this.styles.eyeButton}>246 <Text style={this.styles.modalSettingLabel}>Equipment</Text>247 </ImageBackground>248 </TouchableOpacity>249 <TouchableOpacity250 activeOpacity={0.5}251 onPress={() => this.setState({customizePage: 'appearences'})}>252 <ImageBackground253 source={require('./src/eye.png')}254 imageStyle={this.styles.modalImage}255 style={this.styles.eyeButton}>256 <Text style={this.styles.modalSettingLabel}>Appearences</Text>257 </ImageBackground>258 </TouchableOpacity>259 <TouchableOpacity260 activeOpacity={0.5}261 onPress={() => this.setState({customizePage: 'personalities'})}>262 <ImageBackground263 source={require('./src/eye.png')}264 imageStyle={this.styles.modalImage}265 style={this.styles.eyeButton}>266 <Text style={this.styles.modalSettingLabel}>Personalities</Text>267 </ImageBackground>268 </TouchableOpacity>269 <TouchableOpacity270 activeOpacity={0.5}271 onPress={() => this.setState({customizePage: 'accents'})}>272 <ImageBackground273 source={require('./src/eye.png')}274 imageStyle={this.styles.modalImage}275 style={this.styles.eyeButton}>276 <Text style={this.styles.modalSettingLabel}>Accents</Text>277 </ImageBackground>278 </TouchableOpacity>279 <TouchableOpacity280 style={{marginTop: 50}}281 activeOpacity={0.5}282 onPress={this.exportContent}>283 <ImageBackground284 source={require('./src/eye_red.png')}285 imageStyle={this.styles.modalImage}286 style={this.styles.eyeButton}>287 <Text style={this.styles.modalSettingLabel}>Export Content</Text>288 </ImageBackground>289 </TouchableOpacity>290 <TouchableOpacity291 activeOpacity={0.5}292 onPress={this.importContent}>293 <ImageBackground294 source={require('./src/eye_red.png')}295 imageStyle={this.styles.modalImage}296 style={this.styles.eyeButton}>297 <Text style={this.styles.modalSettingLabel}>Import Content</Text>298 </ImageBackground>299 </TouchableOpacity>300 </ScrollView>301 }302 {this.state.customizePage == 'personalities' && 303 <View style={this.styles.modalScroll}>304 <TouchableOpacity305 activeOpacity={0.5}306 style={this.styles.backButton}307 onPress={() => this.setState({customizePage: 'default'})}>308 <Text style={this.styles.modalSettingButton}>Back</Text>309 </TouchableOpacity>310 <TouchableOpacity311 activeOpacity={0.5}312 onPress={() => this.setState({customizePage: 'editPersonality', validate: false, newTrait: {Name: ""}, modifyingTrait: -1})}>313 <ImageBackground314 source={require('./src/eye_red.png')}315 imageStyle={this.styles.modalImage}316 style={this.styles.eyeButton}>317 <Text style={this.styles.modalSettingLabel}>New</Text>318 </ImageBackground>319 </TouchableOpacity>320 <FlatList321 data={this.state.customTraits.personalities}322 keyExtractor={this._keyCustomTraits}323 renderItem={this._renderCustomTraits}324 style={this.styles.existingTraits}325 extraData={this.state.customTraits}326 windowSize={5}327 getItemLayout={this._getCustomItemLayout}328 />329 </View>330 }331 {this.state.customizePage == 'editPersonality' &&332 <ScrollView style={this.styles.modalScroll}>333 <TouchableOpacity334 activeOpacity={0.5}335 style={this.styles.backButton}336 onPress={() => this.setState({customizePage: 'personalities', modifyingTrait: -1, newTrait: {}})}>337 <Text style={this.styles.modalSettingButton}>Back</Text>338 </TouchableOpacity> 339 <View style={this.styles.customizeSettingContainer}>340 <Text style={this.styles.modalSettingLabel}>Name</Text>341 <TextInput342 style={[this.styles.customizeTextInput, this.state.validate && !this.state.newTrait.Name ? this.styles.redOutline : {}]}343 value={this.state.newTrait.Name}344 onChangeText={(value) => this.setSetting('Name', value, 'newTrait')}345 multiline={false}346 underlineColorAndroid='transparent'347 />348 </View>349 <View style={this.styles.modalSettingContainer}>350 <TouchableOpacity351 activeOpacity={0.5}352 style={this.styles.saveButton}353 onPress={this.saveTrait}>354 <Text style={this.styles.modalSettingButton}>Save</Text>355 </TouchableOpacity>356 <TouchableOpacity357 activeOpacity={0.5}358 style={[this.styles.deleteButton, this.state.modifyingTrait > -1 ? this.styles.visible : this.styles.hidden]}359 onPress={this.deleteTrait}>360 <Text style={this.styles.modalSettingButtonRed}>Delete</Text>361 </TouchableOpacity>362 </View>363 </ScrollView>364 }365 {this.state.customizePage == 'appearences' && 366 <View style={this.styles.modalScroll}>367 <TouchableOpacity368 activeOpacity={0.5}369 style={this.styles.backButton}370 onPress={() => this.setState({customizePage: 'default'})}>371 <Text style={this.styles.modalSettingButton}>Back</Text>372 </TouchableOpacity>373 <TouchableOpacity374 activeOpacity={0.5}375 onPress={() => this.setState({customizePage: 'editAppearence', validate: false, newTrait: {Name: ""}, modifyingTrait: -1})}>376 <ImageBackground377 source={require('./src/eye_red.png')}378 imageStyle={this.styles.modalImage}379 style={this.styles.eyeButton}>380 <Text style={this.styles.modalSettingLabel}>New</Text>381 </ImageBackground>382 </TouchableOpacity>383 <FlatList384 data={this.state.customTraits.appearences}385 keyExtractor={this._keyCustomTraits}386 renderItem={this._renderCustomTraits}387 style={this.styles.existingTraits}388 extraData={this.state.customTraits}389 windowSize={5}390 getItemLayout={this._getCustomItemLayout}391 />392 </View>393 }394 {this.state.customizePage == 'editAppearence' &&395 <ScrollView style={this.styles.modalScroll}>396 <TouchableOpacity397 activeOpacity={0.5}398 style={this.styles.backButton}399 onPress={() => this.setState({customizePage: 'appearences', modifyingTrait: -1, newTrait: {}})}>400 <Text style={this.styles.modalSettingButton}>Back</Text>401 </TouchableOpacity> 402 <View style={this.styles.customizeSettingContainer}>403 <Text style={this.styles.modalSettingLabel}>Name</Text>404 <TextInput405 style={[this.styles.customizeTextInput, this.state.validate && !this.state.newTrait.Name ? this.styles.redOutline : {}]}406 value={this.state.newTrait.Name}407 onChangeText={(value) => this.setSetting('Name', value, 'newTrait')}408 multiline={false}409 underlineColorAndroid='transparent'410 />411 </View>412 <View style={this.styles.modalSettingContainer}>413 <TouchableOpacity414 activeOpacity={0.5}415 style={this.styles.saveButton}416 onPress={this.saveTrait}>417 <Text style={this.styles.modalSettingButton}>Save</Text>418 </TouchableOpacity>419 <TouchableOpacity420 activeOpacity={0.5}421 style={[this.styles.deleteButton, this.state.modifyingTrait > -1 ? this.styles.visible : this.styles.hidden]}422 onPress={this.deleteTrait}>423 <Text style={this.styles.modalSettingButtonRed}>Delete</Text>424 </TouchableOpacity>425 </View>426 </ScrollView>427 }428 429 {this.state.customizePage == 'accents' &&430 <View style={this.styles.modalScroll}>431 <TouchableOpacity432 activeOpacity={0.5}433 style={this.styles.backButton}434 onPress={() => this.setState({customizePage: 'default'})}>435 <Text style={this.styles.modalSettingButton}>Back</Text>436 </TouchableOpacity>437 <TouchableOpacity438 activeOpacity={0.5}439 onPress={() => this.setState({customizePage: 'editAccent', validate: false, newTrait: {Name: ""}, modifyingTrait: -1})}>440 <ImageBackground441 source={require('./src/eye_red.png')}442 imageStyle={this.styles.modalImage}443 style={this.styles.eyeButton}>444 <Text style={this.styles.modalSettingLabel}>New</Text>445 </ImageBackground>446 </TouchableOpacity>447 <FlatList448 data={this.state.customTraits.accents}449 keyExtractor={this._keyCustomTraits}450 renderItem={this._renderCustomTraits}451 style={this.styles.existingTraits}452 extraData={this.state.customTraits}453 windowSize={5}454 getItemLayout={this._getCustomItemLayout}455 />456 </View>457 }458 {this.state.customizePage == 'editAccent' &&459 <ScrollView style={this.styles.modalScroll}>460 <TouchableOpacity461 activeOpacity={0.5}462 style={this.styles.backButton}463 onPress={() => this.setState({customizePage: 'accents', modifyingTrait: -1, newTrait: {}})}>464 <Text style={this.styles.modalSettingButton}>Back</Text>465 </TouchableOpacity> 466 <View style={this.styles.customizeSettingContainer}>467 <Text style={this.styles.modalSettingLabel}>Name</Text>468 <TextInput469 style={[this.styles.customizeTextInput, this.state.validate && !this.state.newTrait.Name ? this.styles.redOutline : {}]}470 value={this.state.newTrait.Name}471 onChangeText={(value) => this.setSetting('Name', value, 'newTrait')}472 multiline={false}473 underlineColorAndroid='transparent'474 />475 </View>476 <View style={this.styles.modalSettingContainer}>477 <TouchableOpacity478 activeOpacity={0.5}479 style={this.styles.saveButton}480 onPress={this.saveTrait}>481 <Text style={this.styles.modalSettingButton}>Save</Text>482 </TouchableOpacity>483 <TouchableOpacity484 activeOpacity={0.5}485 style={[this.styles.deleteButton, this.state.modifyingTrait > -1 ? this.styles.visible : this.styles.hidden]}486 onPress={this.deleteTrait}>487 <Text style={this.styles.modalSettingButtonRed}>Delete</Text>488 </TouchableOpacity>489 </View>490 </ScrollView>491 }492 493 {this.state.customizePage == 'abilities' &&494 <View style={this.styles.modalScroll}>495 <TouchableOpacity496 activeOpacity={0.5}497 style={this.styles.backButton}498 onPress={() => this.setState({customizePage: 'default'})}>499 <Text style={this.styles.modalSettingButton}>Back</Text>500 </TouchableOpacity>501 <TouchableOpacity502 activeOpacity={0.5}503 onPress={() => this.setState({customizePage: 'editAbility', validate: false, newTrait: {Name: "", description: "", classReq: [], levelReq: 0}, modifyingTrait: -1})}>504 <ImageBackground505 source={require('./src/eye_red.png')}506 imageStyle={this.styles.modalImage}507 style={this.styles.eyeButton}>508 <Text style={this.styles.modalSettingLabel}>New</Text>509 </ImageBackground>510 </TouchableOpacity>511 <FlatList512 data={this.state.customTraits.abilities}513 keyExtractor={this._keyCustomTraits}514 renderItem={this._renderCustomTraits}515 style={this.styles.existingTraits}516 extraData={this.state.customTraits}517 windowSize={5}518 getItemLayout={this._getCustomItemLayout}519 />520 </View>521 }522 {this.state.customizePage == 'editAbility' &&523 <ScrollView style={this.styles.modalScroll} ref={component => this.cusAbiScroll = component}>524 <TouchableOpacity525 activeOpacity={0.5}526 style={this.styles.backButton}527 onPress={() => this.setState({customizePage: 'abilities', modifyingTrait: -1, newTrait: {}})}>528 <Text style={this.styles.modalSettingButton}>Back</Text>529 </TouchableOpacity>530 <View style={this.styles.customizeSettingContainer}>531 <Text style={this.styles.modalSettingLabel}>Name</Text>532 <TextInput533 style={[this.styles.customizeTextInput, this.state.validate && !this.state.newTrait.Name ? this.styles.redOutline : {}]}534 value={this.state.newTrait.Name}535 onChangeText={(value) => this.setSetting('Name', value, 'newTrait')}536 multiline={false}537 underlineColorAndroid='transparent'538 />539 </View>540 <View style={this.styles.customizeSettingContainer}>541 <Text style={this.styles.modalSettingLabel}>Description</Text>542 <TextInput543 style={this.styles.customizeTextInput}544 value={this.state.newTrait.description}545 onChangeText={(value) => this.setSetting('description', value, 'newTrait')}546 multiline={false}547 underlineColorAndroid='transparent'548 />549 </View>550 <View style={this.styles.modalSettingContainer}>551 <Text style={this.styles.modalSettingLabel}>Min Lvl</Text>552 <Picker553 selectedValue={this.state.newTrait.levelReq}554 style={this.styles.modalSettingPickerThin}555 onValueChange={(itemValue, itemIndex) => this.setSetting("levelReq", itemValue, 'newTrait')}556 mode="dropdown" >557 <Picker.Item label="0" value={0} />558 <Picker.Item label="1" value={1} />559 <Picker.Item label="2" value={2} />560 <Picker.Item label="3" value={3} />561 <Picker.Item label="4" value={4} />562 </Picker>563 </View>564 {/* Read README.txt to modify MultiSelect if you just installed node_modules */}565 <MultiSelect566 hideTags567 items={this.getAllClassesForReq().map(clas => { return {Name: clas.Name, id: clas.Properties[0]}})}568 uniqueKey="id"569 onSelectedItemsChange={ selectedItems => this.setState({ newTrait: {...this.state.newTrait, classReq: selectedItems} }) }570 selectedItems={this.state.newTrait.classReq}571 selectText="Class Specific"572 displayKey="Name"573 submitButtonText="Done"574 styleDropdownMenuSubsection = {this.styles.multiSelectBackground}575 styleTextDropdown={this.styles.multiSelectText}576 styleTextDropdownSelected={this.styles.multiSelectTextSmall}577 searchInputStyle={this.styles.multiSelectSearch}578 />579 <View style={this.styles.modalSettingContainer}>580 <TouchableOpacity581 activeOpacity={0.5}582 style={this.styles.saveButton}583 onPress={this.saveTrait}>584 <Text style={this.styles.modalSettingButton}>Save</Text>585 </TouchableOpacity>586 <TouchableOpacity587 activeOpacity={0.5}588 style={[this.styles.deleteButton, this.state.modifyingTrait > -1 ? this.styles.visible : this.styles.hidden]}589 onPress={this.deleteTrait}>590 <Text style={this.styles.modalSettingButtonRed}>Delete</Text>591 </TouchableOpacity>592 </View>593 </ScrollView>594 }595 596 597 {this.state.customizePage == 'equipment' &&598 <View style={this.styles.modalScroll}>599 <TouchableOpacity600 activeOpacity={0.5}601 style={this.styles.backButton}602 onPress={() => this.setState({customizePage: 'default'})}>603 <Text style={this.styles.modalSettingButton}>Back</Text>604 </TouchableOpacity>605 <TouchableOpacity606 activeOpacity={0.5}607 onPress={() => this.setState({customizePage: 'editEquipment', validate: false, newTrait: {Name: "", description: "", classReq: [], levelReq: 0}, modifyingTrait: -1})}>608 <ImageBackground609 source={require('./src/eye_red.png')}610 imageStyle={this.styles.modalImage}611 style={this.styles.eyeButton}>612 <Text style={this.styles.modalSettingLabel}>New</Text>613 </ImageBackground>614 </TouchableOpacity>615 <FlatList616 data={this.state.customTraits.equipment}617 keyExtractor={this._keyCustomTraits}618 renderItem={this._renderCustomTraits}619 style={this.styles.existingTraits}620 extraData={this.state.customTraits}621 windowSize={5}622 getItemLayout={this._getCustomItemLayout}623 />624 </View>625 }626 {this.state.customizePage == 'editEquipment' &&627 <ScrollView style={this.styles.modalScroll} ref={component => this.cusEquScroll = component}>628 <TouchableOpacity629 activeOpacity={0.5}630 style={this.styles.backButton}631 onPress={() => this.setState({customizePage: 'equipment', modifyingTrait: -1, newTrait: {}})}>632 <Text style={this.styles.modalSettingButton}>Back</Text>633 </TouchableOpacity>634 <View style={this.styles.customizeSettingContainer}>635 <Text style={this.styles.modalSettingLabel}>Name</Text>636 <TextInput637 style={[this.styles.customizeTextInput, this.state.validate && !this.state.newTrait.Name ? this.styles.redOutline : {}]}638 value={this.state.newTrait.Name}639 onChangeText={(value) => this.setSetting('Name', value, 'newTrait')}640 multiline={false}641 underlineColorAndroid='transparent'642 />643 </View>644 <View style={this.styles.customizeSettingContainer}>645 <Text style={this.styles.modalSettingLabel}>Description</Text>646 <TextInput647 style={this.styles.customizeTextInput}648 value={this.state.newTrait.description}649 onChangeText={(value) => this.setSetting('description', value, 'newTrait')}650 multiline={false}651 underlineColorAndroid='transparent'652 />653 </View>654 <View style={this.styles.modalSettingContainer}>655 <Text style={this.styles.modalSettingLabel}>Min Lvl</Text>656 <Picker657 selectedValue={this.state.newTrait.levelReq}658 style={this.styles.modalSettingPickerThin}659 onValueChange={(itemValue, itemIndex) => this.setSetting("levelReq", itemValue, 'newTrait')}660 mode="dropdown" >661 <Picker.Item label="0" value={0} />662 <Picker.Item label="1" value={1} />663 <Picker.Item label="2" value={2} />664 <Picker.Item label="3" value={3} />665 <Picker.Item label="4" value={4} />666 </Picker>667 </View>668 {/* Read README.txt to modify MultiSelect if you just installed node_modules */}669 <MultiSelect670 hideTags671 items={this.getAllClassesForReq().map(clas => { return {Name: clas.Name, id: clas.Properties[0]}})}672 uniqueKey="id"673 onSelectedItemsChange={ selectedItems => this.setState({ newTrait: {...this.state.newTrait, classReq: selectedItems} }) }674 selectedItems={this.state.newTrait.classReq}675 selectText="Class Specific"676 displayKey="Name"677 submitButtonText="Done"678 styleDropdownMenuSubsection = {this.styles.multiSelectBackground}679 styleTextDropdown={this.styles.multiSelectText}680 styleTextDropdownSelected={this.styles.multiSelectTextSmall}681 />682 <View style={this.styles.modalSettingContainer}>683 <TouchableOpacity684 activeOpacity={0.5}685 style={this.styles.saveButton}686 onPress={this.saveTrait}>687 <Text style={this.styles.modalSettingButton}>Save</Text>688 </TouchableOpacity>689 <TouchableOpacity690 activeOpacity={0.5}691 style={[this.styles.deleteButton, this.state.modifyingTrait > -1 ? this.styles.visible : this.styles.hidden]}692 onPress={this.deleteTrait}>693 <Text style={this.styles.modalSettingButtonRed}>Delete</Text>694 </TouchableOpacity>695 </View>696 </ScrollView>697 }698 699 {this.state.customizePage == 'races' &&700 <View style={this.styles.modalScroll}>701 <TouchableOpacity702 activeOpacity={0.5}703 style={this.styles.backButton}704 onPress={() => this.setState({customizePage: 'default'})}>705 <Text style={this.styles.modalSettingButton}>Back</Text>706 </TouchableOpacity>707 <TouchableOpacity708 activeOpacity={0.5}709 onPress={() => this.setState({customizePage: 'editRace', validate: false, newTrait: {Name: "", ability: "", primaryStat: "", secondaryStat: ""}, modifyingTrait: -1})}>710 <ImageBackground711 source={require('./src/eye_red.png')}712 imageStyle={this.styles.modalImage}713 style={this.styles.eyeButton}>714 <Text style={this.styles.modalSettingLabel}>New</Text>715 </ImageBackground>716 </TouchableOpacity>717 <FlatList718 data={this.state.customTraits.races}719 keyExtractor={this._keyCustomTraits}720 renderItem={this._renderCustomTraits}721 style={this.styles.existingTraits}722 extraData={this.state.customTraits}723 windowSize={5}724 getItemLayout={this._getCustomItemLayout}725 />726 </View>727 }728 {this.state.customizePage == 'editRace' &&729 <ScrollView style={this.styles.modalScroll} ref={component => this.cusRacScroll = component}>730 <TouchableOpacity731 activeOpacity={0.5}732 style={this.styles.backButton}733 onPress={() => this.setState({customizePage: 'races', modifyingTrait: -1, newTrait: {}})}>734 <Text style={this.styles.modalSettingButton}>Back</Text>735 </TouchableOpacity>736 <View style={this.styles.customizeSettingContainer}>737 <Text style={this.styles.modalSettingLabel}>Name</Text>738 <TextInput739 style={[this.styles.customizeTextInput, this.state.validate && !this.state.newTrait.Name ? this.styles.redOutline : {}]}740 value={this.state.newTrait.Name}741 onChangeText={(value) => this.setSetting('Name', value, 'newTrait')}742 multiline={false}743 underlineColorAndroid='transparent'744 />745 </View>746 <View style={this.styles.customizeSettingContainer}>747 <Text style={this.styles.modalSettingLabel}>Ability</Text>748 <View style={this.styles.customizeTextInputLargeFrame}>749 <TextInput750 style={this.styles.customizeTextInputLarge}751 value={this.state.newTrait.ability}752 onChangeText={(value) => this.setSetting('ability', value, 'newTrait')}753 multiline={true}754 underlineColorAndroid='transparent'755 />756 </View>757 </View>758 <View style={this.styles.modalSettingContainer}>759 <Text style={this.styles.modalSettingLabel}>Stat +2</Text>760 <View style={this.state.validate && !this.state.newTrait.primaryStat ? this.styles.redOutline : this.styles.transOutline}>761 <Picker762 selectedValue={this.state.newTrait.primaryStat}763 style={this.styles.modalSettingPickerMed}764 onValueChange={(itemValue, itemIndex) => this.setSetting("primaryStat", itemValue, 'newTrait')}765 mode="dropdown" >766 <Picker.Item label="Pick" value="" />767 <Picker.Item label="STR" value="S" />768 <Picker.Item label="CON" value="E" />769 <Picker.Item label="DEX" value="D" />770 <Picker.Item label="WIS" value="W" />771 <Picker.Item label="INT" value="I" />772 <Picker.Item label="CHA" value="C" />773 </Picker>774 </View>775 </View>776 <View style={this.styles.modalSettingContainer}>777 <Text style={this.styles.modalSettingLabel}>Stat +1</Text>778 <View style={this.state.validate && !this.state.newTrait.secondaryStat ? this.styles.redOutline : this.styles.transOutline}>779 <Picker780 selectedValue={this.state.newTrait.secondaryStat}781 style={this.styles.modalSettingPickerMed}782 onValueChange={(itemValue, itemIndex) => this.setSetting("secondaryStat", itemValue, 'newTrait')}783 mode="dropdown" >784 <Picker.Item label="Pick" value="" />785 <Picker.Item label="STR" value="S" />786 <Picker.Item label="CON" value="E" />787 <Picker.Item label="DEX" value="D" />788 <Picker.Item label="WIS" value="W" />789 <Picker.Item label="INT" value="I" />790 <Picker.Item label="CHA" value="C" />791 </Picker>792 </View>793 </View>794 <View style={this.styles.modalSettingContainer}>795 <TouchableOpacity796 activeOpacity={0.5}797 style={this.styles.saveButton}798 onPress={this.saveTrait}>799 <Text style={this.styles.modalSettingButton}>Save</Text>800 </TouchableOpacity>801 <TouchableOpacity802 activeOpacity={0.5}803 style={[this.styles.deleteButton, this.state.modifyingTrait > -1 ? this.styles.visible : this.styles.hidden]}804 onPress={this.deleteTrait}>805 <Text style={this.styles.modalSettingButtonRed}>Delete</Text>806 </TouchableOpacity>807 </View>808 </ScrollView>809 }810 811 {this.state.customizePage == 'classes' &&812 <View style={this.styles.modalScroll}>813 <TouchableOpacity814 activeOpacity={0.5}815 style={this.styles.backButton}816 onPress={() => this.setState({customizePage: 'default'})}>817 <Text style={this.styles.modalSettingButton}>Back</Text>818 </TouchableOpacity>819 <TouchableOpacity820 activeOpacity={0.5}821 onPress={() => this.setState({customizePage: 'editClass', validate: false, newTrait: {Name: "", hp: "", primaryStat: "", secondaryStat: "", ability: "", weapon: "", armor: "", base: ""}, modifyingTrait: -1})}>822 <ImageBackground823 source={require('./src/eye_red.png')}824 imageStyle={this.styles.modalImage}825 style={this.styles.eyeButton}>826 <Text style={this.styles.modalSettingLabel}>New</Text>827 </ImageBackground>828 </TouchableOpacity>829 <FlatList830 data={this.state.customTraits.classes}831 keyExtractor={this._keyCustomTraits}832 renderItem={this._renderCustomTraits}833 style={this.styles.existingTraits}834 extraData={this.state.customTraits}835 windowSize={5}836 getItemLayout={this._getCustomItemLayout}837 />838 </View>839 }840 {this.state.customizePage == 'editClass' &&841 <ScrollView style={this.styles.modalScroll} ref={component => this.cusClaScroll = component}>842 <TouchableOpacity843 activeOpacity={0.5}844 style={this.styles.backButton}845 onPress={() => this.setState({customizePage: 'classes', modifyingTrait: -1, newTrait: {}})}>846 <Text style={this.styles.modalSettingButton}>Back</Text>847 </TouchableOpacity>848 <View style={this.styles.customizeSettingContainer}>849 <Text style={this.styles.modalSettingLabel}>Name</Text>850 <TextInput851 style={[this.styles.customizeTextInput, this.state.validate && !this.state.newTrait.Name ? this.styles.redOutline : {}]}852 value={this.state.newTrait.Name}853 onChangeText={(value) => this.setSetting('Name', value, 'newTrait')}854 multiline={false}855 underlineColorAndroid='transparent'856 />857 </View>858 <View style={this.styles.customizeSettingContainer}>859 <Text style={this.styles.modalSettingLabel}>Default Ability</Text>860 <View style={this.styles.customizeTextInputLargeFrame}>861 <TextInput862 style={this.styles.customizeTextInputLarge}863 value={this.state.newTrait.ability}864 onChangeText={(value) => {865 this.warnChangingDependents();866 this.setSetting('ability', value, 'newTrait');867 }}868 multiline={true}869 underlineColorAndroid='transparent'870 />871 </View>872 </View>873 <View style={this.styles.modalSettingContainer}>874 <Text style={this.styles.modalSettingLabel}>Base</Text>875 <Picker876 selectedValue={this.state.newTrait.base}877 style={this.styles.modalSettingPicker}878 onValueChange={(itemValue, itemIndex) => {879 this.useBaseFirstTime()880 if (!this.checkCircularDepndency(itemValue)){881 this.warnChangingDependents()882 this.setSetting("base", itemValue, 'newTrait', () => {883 this.setClassDefaults(itemValue)884 })885 }886 }}887 mode="dropdown" >888 <Picker.Item label="None" value="" />889 {this.state.customTraits.classes.filter((clas, index) => 890 { 891 return this.state.modifyingTrait == -1 || this.state.modifyingTrait != index 892 })893 .map((clas, index) => {894 return (895 <Picker.Item label={clas.Name} value={clas.id} />896 );897 })}898 <Picker.Item label="Artificer" value="artificer" />899 <Picker.Item label="Barbarian" value="barbarian" />900 <Picker.Item label="Bard" value="bard" />901 <Picker.Item label="Cleric" value="cleric" />902 <Picker.Item label="Druid" value="druid" />903 <Picker.Item label="Fighter" value="fighter" />904 <Picker.Item label="Monk" value="monk" />905 <Picker.Item label="Paladin" value="paladin" />906 <Picker.Item label="Ranger" value="ranger" />907 <Picker.Item label="Rogue" value="rogue" />908 <Picker.Item label="Sorcerer" value="sorcerer" />909 <Picker.Item label="Warlock" value="warlock" />910 <Picker.Item label="Wizard" value="wizard" />911 </Picker>912 </View>913 <View style={this.styles.modalSettingContainer}>914 <Text style={this.styles.modalSettingLabel}>Main Stat</Text>915 <View style={this.state.validate && !this.state.newTrait.primaryStat ? this.styles.redOutline : this.styles.transOutline}>916 <Picker917 selectedValue={this.state.newTrait.primaryStat}918 style={this.styles.modalSettingPickerMed}919 onValueChange={(itemValue, itemIndex) => this.setSetting("primaryStat", itemValue, 'newTrait')}920 mode="dropdown" >921 <Picker.Item label="Pick" value="" />922 <Picker.Item label="STR" value="S" />923 <Picker.Item label="CON" value="E" />924 <Picker.Item label="DEX" value="D" />925 <Picker.Item label="WIS" value="W" />926 <Picker.Item label="INT" value="I" />927 <Picker.Item label="CHA" value="C" />928 </Picker>929 </View>930 </View>931 <View style={this.styles.modalSettingContainer}>932 <Text style={this.styles.modalSettingLabel}>2nd Stat</Text>933 <View style={this.state.validate && !this.state.newTrait.secondaryStat ? this.styles.redOutline : this.styles.transOutline}>934 <Picker935 selectedValue={this.state.newTrait.secondaryStat}936 style={this.styles.modalSettingPickerMed}937 onValueChange={(itemValue, itemIndex) => this.setSetting("secondaryStat", itemValue, 'newTrait')}938 mode="dropdown" >939 <Picker.Item label="Pick" value="" />940 <Picker.Item label="STR" value="S" />941 <Picker.Item label="CON" value="E" />942 <Picker.Item label="DEX" value="D" />943 <Picker.Item label="WIS" value="W" />944 <Picker.Item label="INT" value="I" />945 <Picker.Item label="CHA" value="C" />946 </Picker>947 </View>948 </View>949 <View style={this.styles.modalSettingContainer}>950 <Text style={this.styles.modalSettingLabel}>Weapon</Text>951 <View style={this.state.validate && !this.state.newTrait.weapon ? this.styles.redOutline : this.styles.transOutline}>952 <Picker953 selectedValue={this.state.newTrait.weapon}954 style={this.styles.modalSettingPickerMed}955 onValueChange={(itemValue, itemIndex) => this.setSetting("weapon", itemValue, 'newTrait')}956 mode="dropdown" >957 <Picker.Item label="Pick" value="" />958 <Picker.Item label="None" value="none" />959 <Picker.Item label="One-handed Melee" value="one-melee" />960 <Picker.Item label="Two-handed Melee" value="two-melee" />961 <Picker.Item label="Finesse Melee" value="finesse-melee" />962 <Picker.Item label="Bows" value="bows" />963 <Picker.Item label="Magic" value="magic" />964 <Picker.Item label="Instruments" value="instrument" />965 </Picker>966 </View>967 </View>968 <View style={this.styles.modalSettingContainer}>969 <Text style={this.styles.modalSettingLabel}>Armor</Text>970 <View style={this.state.validate && !this.state.newTrait.armor ? this.styles.redOutline : this.styles.transOutline}>971 <Picker972 selectedValue={this.state.newTrait.armor}973 style={this.styles.modalSettingPickerMed}974 onValueChange={(itemValue, itemIndex) => this.setSetting("armor", itemValue, 'newTrait')}975 mode="dropdown" >976 <Picker.Item label="Pick" value="" />977 <Picker.Item label="None" value="none" />978 <Picker.Item label="Light" value="light" />979 <Picker.Item label="Medium" value="medium" />980 <Picker.Item label="Heavy" value="heavy" />981 </Picker>982 </View>983 </View>984 <View style={this.styles.modalSettingContainer}>985 <Text style={this.styles.modalSettingLabel}>Hit Die</Text>986 <View style={this.state.validate && !this.state.newTrait.hp ? this.styles.redOutline : this.styles.transOutline}>987 <Picker988 selectedValue={this.state.newTrait.hp}989 style={this.styles.modalSettingPickerMed}990 onValueChange={(itemValue, itemIndex) => this.setSetting("hp", itemValue, 'newTrait')}991 mode="dropdown" >992 <Picker.Item label="Pick" value="" />993 <Picker.Item label="d6" value="d6" />994 <Picker.Item label="d8" value="d8" />995 <Picker.Item label="d10" value="d10" />996 <Picker.Item label="d12" value="d12" />997 </Picker>998 </View>999 </View>1000 <View style={this.styles.modalSettingContainer}>1001 <TouchableOpacity1002 activeOpacity={0.5}1003 style={this.styles.saveButton}1004 onPress={this.saveTrait}>1005 <Text style={this.styles.modalSettingButton}>Save</Text>1006 </TouchableOpacity>1007 <TouchableOpacity1008 activeOpacity={0.5}1009 style={[this.styles.deleteButton, this.state.modifyingTrait > -1 ? this.styles.visible : this.styles.hidden]}1010 onPress={() => {1011 if (this.tryToDeleteClass()) this.deleteTrait()1012 }}>1013 <Text style={this.styles.modalSettingButtonRed}>Delete</Text>1014 </TouchableOpacity>1015 </View>1016 </ScrollView>1017 }1018 </ImageBackground>1019 </Modal>1020 1021 <View style={this.styles.topBar}>1022 1023 <View style={[this.styles.cornerContainer, this.state.introStep === 2 ? this.styles.overOverlay : {}]}>1024 <TouchableOpacity onPress={this.deleteCharacter}>1025 <Image1026 source={require('./src/shieldX.png')}1027 style={this.styles.smallButton}1028 />1029 </TouchableOpacity>1030 </View>1031 1032 <View style={this.styles.bigButtonContainer}>1033 <TouchableOpacity onPress={() => this.newCharacter("settingsNew")} style={this.state.introStep === 0 ? this.styles.overOverlay : {}}>1034 <Image1035 source={require('./src/signNewSolo.png')}1036 style={this.styles.bigButtonLeft}1037 />1038 </TouchableOpacity>1039 <TouchableOpacity onPress={()=>this.showSettings(true)} style={this.state.introStep === 3 ? this.styles.overOverlay : {}}>1040 <Image1041 source={require('./src/signSmall.png')}1042 style={this.styles.bigButtonRight}1043 />1044 </TouchableOpacity>1045 </View>1046 1047 1048 <View style={[this.styles.cornerContainer, this.state.introStep === 4 ? this.styles.overOverlay : {}]}>1049 <TouchableOpacity onPress={()=>this.showCustomize(true)}>1050 <Image1051 source={require('./src/shieldGear.png')}1052 style={this.styles.smallButton}1053 />1054 </TouchableOpacity>1055 </View>1056 1057 </View>1058 1059 <View style={this.styles.belowTopBar}>1060 <FlatList1061 data={this.state.characters}1062 extraData={this.state.index}1063 keyExtractor={this._keyCharacterShield}1064 renderItem={this._renderCharacterShield}1065 getItemLayout={this._getItemLayout}1066 windowSize={5}1067 ref={component => this._listScroll = component}1068 style={[this.styles.leftBar, this.state.introStep === 1 ? this.styles.overOverlay : {}]}1069 />1070 1071 <ScrollView 1072 ref={component => this._textScroll = component}1073 style={[this.styles.rightText, this.state.messages.intro ? this.styles.overOverlay : {}]}>1074 <View style={this.keyboardPadding()}>1075 {this.state.messages.intro && this.state.loaded &&1076 <Text style={this.styles.introText} >1077 {this.getIntroText()}1078 </Text>1079 }1080 {this.state.showText && !this.state.messages.intro &&1081 <TextInput1082 style={this.styles.textArea}1083 value={this.state.charText}1084 onChangeText={(value) => this.setState({ charText: value })}1085 multiline={true}1086 ref={component => this._text = component}1087 underlineColorAndroid='transparent'1088 />1089 }1090 </View>1091 </ScrollView>1092 1093 </View>1094 1095 </ImageBackground>1096 );1097 }1098 1099 //helper function for rendering list of characters1100 _renderCharacterShield = ({item, index}) => {1101 var crestSrc = require('./src/crest.png');1102 if(index == this.state.index) crestSrc = require('./src/crestHighlight.png');1103 1104 return (1105 <FlatListItem myIndex={index} stateIndex={this.state.index}>1106 <TouchableOpacity1107 onPress={() => this.showCharacter(index, true)}1108 style={this.styles.listButton}1109 shouldRasterizeIOS={true}>1110 <ImageBackground1111 source={crestSrc}1112 imageStyle={this.styles.listImage}1113 style={this.styles.listBackground}>1114 1115 <Text 1116 style={this.styles.listText}1117 numberOfLines={3}1118 textBreakStrategy='simple'>1119 {this.getDisplayName(item)}1120 </Text>1121 1122 </ImageBackground>1123 </TouchableOpacity>1124 </FlatListItem>1125 );1126 }1127 _getItemLayout = (data, index) => (1128 {length: 105, offset: 105 * index, index}1129 );1130 _getCustomItemLayout = (data, index) => (1131 {length: 70, offset: 70 * index, index}1132 );1133 1134 //helper function for getting keys for character list1135 _keyCharacterShield = (item, index) => {1136 return item;1137 }1138 //helper function for rendering list of custom traits1139 _renderCustomTraits = ({item, index}) => { 1140 return (1141 <FlatListItemTraits>1142 <TouchableOpacity1143 activeOpacity={0.5}1144 onPress={() => this.editTrait(item, index)}>1145 <ImageBackground1146 source={require('./src/eye.png')}1147 imageStyle={this.styles.modalImage}1148 style={this.styles.eyeButton}>1149 <Text style={this.styles.modalSettingLabel}>{item.Name || item}</Text>1150 </ImageBackground>1151 </TouchableOpacity>1152 </FlatListItemTraits>1153 );1154 }1155 1156 //helper function for getting keys for custom traits list1157 // assumes all custom traits have a Name prop1158 _keyCustomTraits = (item, index) => {1159 let str = item1160 if (item.id) str = item.id1161 else if (item.Name) str = item.Name1162 return str1163 }1164 1165 //helper function for displaying name1166 getDisplayName(string) {1167 //get the first line of the text, then split on Name:1168 var nameArr = string.split('\n')[0].split('Name:');1169 //if there was a Name:1170 if(nameArr.length > 1){1171 //skip over it to index 1, get rid of white space around the actual name, only take the first name, trim again to be safe, take first 10 letters1172 return nameArr[1].trim().split(' ')[0].trim().slice(0, 10);1173 }1174 //if not1175 else{1176 //get rid of white space around the actual name, only take the first name, trim again to be safe, take first 10 letters1177 return nameArr[0].trim().split(' ')[0].trim().slice(0, 10);1178 }1179 };1180 1181 //helper function to provide padding when keyboard is shown 1182 keyboardPadding(){1183 if(this.state.keyboardShowing) return {paddingBottom:this.state.keyboardHeight};1184 else return {};1185 }1186 1187 1188 1189 1190 1191// ==================================================================1192// Functions1193 // charText represents the current character displayed on screen 1194 // index represents the index that character is in characters1195 // characters represents the list of all characters we have displayed in the left list1196 // showText is a hack because of a React Native bug, it's used to hide the TextInput when there are no characters1197 // settingsVisible controls the settings modal's visibility1198 // settings is an object containing attributes past to the generator which controls whether certain races, classes, etc are available. 1199 constructor(){1200 super();1201 this.state = {1202 charText: "",1203 index: -1,1204 characters: [],1205 showText: false,1206 settingsVisible: false,1207 customizeVisible: false, 1208 messages: {1209 baseWarning: true,1210 classWarning: true,1211 intro: true,1212 },1213 loaded: false,1214 introStep: 0,1215 validate: false,1216 modifyingTrait: -1,1217 customizePage: 'default',1218 newTrait: {},1219 customTraits: {1220 personalities: [], // Name1221 accents: [], // Name1222 appearences: [], // Name1223 equipment: [], // Name, description (optional), class req (optional, checklist, pulls from customs too)1224 abilities: [], // Name, description (optional), class req (optional, checklist, pulls from customs too)1225 races: [], // Name, stat buff major (dropdown), stat buff minor (dropdown), ability (string)1226 classes: [], // Name, stat req major (dropdown), stat req minor (dropdown), ability (string), weapon (dropdown), armor (dropdown)1227 },1228 settingsPage: "settingsNew",1229 settingsNew: {1230 Class: "Any",1231 Race: "Any",1232 Equipment: 3,1233 Level: 0,1234 Personality: 2,1235 Appearance: 2,1236 customRate: 'normal'1237 },1238 settingsPlus: {1239 Class: "Any",1240 Race: "Any",1241 Equipment: 4,1242 Level: 1,1243 Personality: 2,1244 Appearance: 2,1245 customRate: 'normal'1246 },1247 keyboardShowing: false,1248 keyboardHeight: 01249 };1250 1251 this.newCharacter = this.newCharacter.bind(this);1252 this.showCharacter = this.showCharacter.bind(this);1253 this.deleteCharacter = this.deleteCharacter.bind(this);1254 this.showSettings = this.showSettings.bind(this);1255 this.setSetting = this.setSetting.bind(this);1256 this.showCustomize = this.showCustomize.bind(this);1257 this.saveTrait = this.saveTrait.bind(this);1258 this.deleteTrait = this.deleteTrait.bind(this);1259 this.tryToDeleteClass = this.tryToDeleteClass.bind(this)1260 this.getAllClasses = this.getAllClasses.bind(this);1261 this.getAllClassesForReq = this.getAllClassesForReq.bind(this)1262 this.saveClassFirstTime = this.saveClassFirstTime.bind(this)1263 this.useBaseFirstTime = this.useBaseFirstTime.bind(this)1264 this.getIntroText = this.getIntroText.bind(this)1265 this.warnChangingDependents = this.warnChangingDependents.bind(this)1266 this.updateClassBase = this.updateClassBase.bind(this)1267 this.getClassAsNewTrait = this.getClassAsNewTrait.bind(this)1268 this.getNewClass = this.getNewClass.bind(this)1269 this.setClassDefaults = this.setClassDefaults.bind(this)1270 this.exportContent = this.exportContent.bind(this)1271 this.importContent = this.importContent.bind(this)1272 AsyncStorage.getItem("characters", (error, result) => {1273 if(result && !error) this.setState({characters: JSON.parse(result), showText: true});1274 });1275 AsyncStorage.getItem("traits", (error, result) => {1276 if(result && !error) this.setState({customTraits: JSON.parse(result)});1277 });1278 AsyncStorage.getItem("messages", (error, result) => {1279 if(result && !error) this.setState({messages: JSON.parse(result)});1280 this.setState({loaded: true})1281 });1282 AsyncStorage.getItem("settings", (error, result) => {1283 if(result && !error) this.setState({settingsNew: JSON.parse(result)});1284 });1285 }1286 1287 //only 1 function may run at once1288 mutex = new Mutex();1289 1290 // simple, generate a character at the given level, add them to our list, display them1291 newCharacter(settingsPage) {1292 if(!this.mutex.isLocked()){1293 this.mutex.acquire().then(release=>{1294 if (this.state.messages.intro) {1295 if (this.state.introStep == 0) this.setState({introStep: this.state.introStep + 1});1296 else return release()1297 }1298 this.saveCharacter();1299 // generate given our options1300 var newChar = generator(this.state[settingsPage], this.state.customTraits);1301 var newArray = this.state.characters.concat(newChar);1302 1303 this.setState({1304 charText: newChar,1305 characters: newArray,1306 index: newArray.length-1,1307 showText: true1308 });1309 1310 this.refreshText();1311 setTimeout(()=>{1312 this._listScroll.scrollToEnd({animated:false});1313 release();1314 }, 50);1315 });1316 }1317 }1318 1319 // switch to displaying the character at the provided index1320 showCharacter(index, save) {1321 if(!this.mutex.isLocked()){1322 this.mutex.acquire().then(release=>{1323 if (this.state.messages.intro) {1324 if (this.state.introStep === 1) this.setState({introStep: this.state.introStep + 1});1325 else return release()1326 }1327 if(save){1328 this.saveCharacter();1329 }1330 var newChar = this.state.characters[index];1331 1332 this.setState({1333 charText: newChar,1334 index: index1335 }, ()=>{1336 1337 this.refreshText();1338 release();1339 });1340 });1341 }1342 }1343 1344 // remove the currently displayed character from the list 1345 // then, check if there's a character after it in the list and display that1346 // if not, check to see if there's a character before it in the list and display that1347 // if not, reset display to nothing and index to -11348 deleteCharacter() {1349 if(!this.mutex.isLocked()){1350 this.mutex.acquire().then(release=>{1351 if (this.state.messages.intro) {1352 if (this.state.introStep == 2) this.setState({introStep: this.state.introStep + 1});1353 else return release()1354 if (this.state.characters.length > 1) return release()1355 }1356 // do nothing if list is empty1357 if(this.state.index != -1){1358 1359 // remove element without mutating characters using this hack1360 var newArray = this.state.characters.slice();1361 newArray.splice(this.state.index, 1);1362 1363 // update1364 this.setState({1365 characters: newArray1366 }, ()=>{1367 1368 // check after it1369 if(this.state.characters.length > this.state.index){1370 release();1371 this.showCharacter(this.state.index, false);1372 }1373 1374 else{1375 // check before it1376 if(this.state.index-1 >= 0){1377 release();1378 this.showCharacter(this.state.index-1, false);1379 }1380 1381 // reset1382 else{1383 // For some reason clearing the text of the textInput causes insane lag spikes. No clue why, so I hack around it1384 this.setState({1385 showText: false1386 }, ()=> {1387 this.state.charText = "";1388 this.state.index = -1;1389 this.refreshText();1390 release();1391 });1392 }1393 }1394 });1395 }1396 1397 // list is empty1398 else{1399 release();1400 }1401 });1402 }1403 1404 }1405 1406 // record any changes the user made to a character before displaying another1407 saveCharacter() {1408 if(this.state.index != -1){1409 this.state.characters[this.state.index] = this.state.charText;1410 }1411 }1412 1413 // move scrollview to the top and remove focus/keyboard1414 refreshText() {1415 if(this._text){1416 this._textScroll.scrollTo({y: 0, animated: false});1417 this._text.blur()1418 }1419 }1420 1421 1422 // displys the settings modal when the user clicks the gear icon1423 showSettings(show) {1424 if (this.state.messages.intro) {1425 if (this.state.introStep == 3) this.setState({introStep: this.state.introStep + 1});1426 return1427 }1428 this.setState({settingsVisible: show});1429 }1430 1431 1432 // displys the settings modal when the user clicks the gear icon1433 showCustomize(show) {1434 if (this.state.messages.intro) {1435 if (this.state.introStep == 4) this.setState({messages: {...this.state.messages, intro: false}});1436 return1437 }1438 this.setState({customizeVisible: show});1439 }1440 1441 1442 // sets the given setting to the given value1443 // note this could cause loss of data if multiple setStates are stacked, but that's almost impossible for our application1444 setSetting(name, value, whichSetting, callback){1445 this.setState({1446 [whichSetting]: {1447 ...this.state[whichSetting],1448 [name]: value1449 }1450 }, callback);1451 }1452 1453 1454 //when the app is suspended/closed, save all data1455 _handleAppStateChange = (nextAppState) => {1456 if (nextAppState.match(/inactive|background/)){1457 this.saveCharacter();1458 AsyncStorage.setItem("characters", JSON.stringify(this.state.characters));1459 AsyncStorage.setItem("traits", JSON.stringify(this.state.customTraits));1460 AsyncStorage.setItem("messages", JSON.stringify(this.state.messages));1461 AsyncStorage.setItem("settings", JSON.stringify(this.state.settingsNew));1462 }1463 } 1464 1465 _keyboardDidShow = (e) => {1466 this.setState({keyboardShowing: true, keyboardHeight:e.endCoordinates.height})1467 }1468 _keyboardDidHide = () => {1469 this.saveCharacter()1470 this.setState({keyboardShowing: false})1471 }1472 componentDidMount() {1473 AppState.addEventListener('change', this._handleAppStateChange);1474 this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);1475 this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);1476 }1477 componentWillUnmount() {1478 AppState.removeEventListener('change', this._handleAppStateChange);1479 this.keyboardDidShowListener.remove();1480 this.keyboardDidHideListener.remove();1481 }1482 getCheckbox(bool){1483 var checkBox = require('./src/empty_checkbox.png');1484 if(bool) checkBox = require('./src/full_checkbox.png');1485 1486 return checkBox;1487 }1488 useBaseFirstTime () {1489 if (this.state.messages.baseWarning) {1490 this.setState({messages: {...this.state.messages, baseWarning: false}})1491 Alert.alert(1492 "Base Class",1493 "Custom classes inherit all of the base class's abilities. While this gives a nice fleshed-out class to go off of, it can also \"drown out\" your own custom abilities for this class!",1494 [1495 { text: "OK", onPress: () => {}}1496 ],1497 { cancelable: true }1498 );1499 }1500 }1501 warnChangingDependents () {1502 let dependents = this.getDependents(this.state.newTrait.id)1503 if (dependents.length > 0) {1504 Alert.alert(1505 "Dependent Classes",1506 "One or more classes are based on this class. This will affect them if you save.",1507 [1508 { text: "OK", onPress: () => {}}1509 ],1510 { cancelable: true }1511 );1512 }1513 }1514 // does not check for dependents of dependents1515 getDependents (id) {1516 let dependents = []1517 for (let clas of this.state.customTraits.classes) {1518 if (clas.base) {1519 if (clas.base == id) dependents.push(clas)1520 }1521 }1522 return dependents1523 }1524 checkCircularDepndency (newBase) {1525 let circularDependence = this.checkCircDepRecursive(this.state.newTrait.id, newBase)1526 if (circularDependence) {1527 Alert.alert(1528 "Circular Dependency",1529 "The class you are trying to base off of is either directly or indirectly based off this one. You cannot make circular dependencies.",1530 [1531 { text: "OK", onPress: () => {}}1532 ],1533 { cancelable: true }1534 );1535 return true1536 }1537 else {1538 return false1539 }1540 }1541 // id wants to rely on newBase. does newBase rely on id?1542 checkCircDepRecursive (id, newBase) {1543 if (!id || !newBase) return false1544 else {1545 // find the new base1546 for (let clas of this.state.customTraits.classes) {1547 if (clas.id == newBase) {1548 // found it1549 if (clas.base == id) {1550 // exit condition, newBase relies on id1551 return true1552 }1553 else if (clas.base) {1554 // newbase doesnt rely on id, but it does rely on another class. does that class rely on id?1555 if (this.checkCircDepRecursive(id, clas.base)) {1556 // yup, newBase is indirectly based on id1557 return true1558 }1559 }1560 }1561 }1562 return false1563 }1564 }1565 saveClassFirstTime () {1566 if (this.state.messages.classWarning) {1567 this.setState({messages: {...this.state.messages, classWarning: false}})1568 Alert.alert(1569 "Custom Class",1570 "Congrats on making your first class! You should now navigate to the custom abilities section to create class-specific abilities for this class!",1571 [1572 { text: "OK", onPress: () => {}}1573 ],1574 { cancelable: true }1575 );1576 }1577 }1578 saveTrait () {1579 // generate a unique id to represent this trait. this will be used to ensure its not duplicated in a character1580 // as well as allows other traits to rely on it 1581 let id = uuid.v4()1582 if (this.state.customizePage === "editPersonality") {1583 //validate1584 if (!this.state.newTrait.Name) {1585 this.setState({validate: true})1586 return1587 }1588 //this means we're editing a trait, remove the old one1589 if (this.state.modifyingTrait > -1) {1590 // preserve the id1591 id = this.state.newTrait.id1592 this.state.customTraits.personalities.splice(this.state.modifyingTrait, 1)1593 }1594 //add the new trait/version1595 this.state.customTraits.personalities.unshift({1596 Reroll: 0,1597 Description: this.state.newTrait.Name,1598 Properties: [id],1599 Incompatible: [id],1600 Name: this.state.newTrait.Name,1601 id,1602 })1603 let traitsClone = {1604 ...this.state.customTraits1605 }1606 //go back in modal1607 this.setState({customizePage: "personalities", newTrait: {}, modifyingTrait: -1, customTraits: traitsClone})1608 }1609 if (this.state.customizePage === "editAppearence") {1610 //validate1611 if (!this.state.newTrait.Name) {1612 this.setState({validate: true})1613 return1614 }1615 //this means we're editing a trait, remove the old one1616 if (this.state.modifyingTrait > -1) {1617 // preserve the id1618 id = this.state.newTrait.id1619 this.state.customTraits.appearences.splice(this.state.modifyingTrait, 1)1620 }1621 //add the new trait/version1622 this.state.customTraits.appearences.unshift({1623 Reroll: 0,1624 Description: this.state.newTrait.Name,1625 Properties: [id],1626 Incompatible: [id],1627 Name: this.state.newTrait.Name,1628 id,1629 })1630 let traitsClone = {1631 ...this.state.customTraits1632 }1633 //go back in modal1634 this.setState({customizePage: "appearences", newTrait: {}, modifyingTrait: -1, customTraits: traitsClone})1635 }1636 if (this.state.customizePage === "editAccent") {1637 //validate1638 if (!this.state.newTrait.Name) {1639 this.setState({validate: true})1640 return1641 }1642 //this means we're editing a trait, remove the old one1643 if (this.state.modifyingTrait > -1) this.state.customTraits.accents.splice(this.state.modifyingTrait, 1)1644 //add the new trait/version1645 this.state.customTraits.accents.unshift(this.state.newTrait.Name)1646 let traitsClone = {1647 ...this.state.customTraits1648 }1649 //go back in modal1650 this.setState({customizePage: "accents", newTrait: {}, modifyingTrait: -1, customTraits: traitsClone})1651 }1652 if (this.state.customizePage === "editAbility") {1653 //validate1654 if (!this.state.newTrait.Name) {1655 this.cusAbiScroll.scrollTo({y: 0, animated: true})1656 this.setState({validate: true})1657 return1658 }1659 //this means we're editing a trait, remove the old one1660 if (this.state.modifyingTrait > -1) {1661 // preserve the id1662 id = this.state.newTrait.id1663 this.state.customTraits.abilities.splice(this.state.modifyingTrait, 1)1664 }1665 let description = this.state.newTrait.Name + (this.state.newTrait.description ? ": " + this.state.newTrait.description : "")1666 let requirements = {1667 Level: this.state.newTrait.levelReq,1668 Properties: this.state.newTrait.classReq,1669 }1670 //add the new trait/version1671 this.state.customTraits.abilities.unshift({1672 Reroll: 0,1673 Description: description,1674 Properties: [id],1675 Incompatible: [id],1676 Name: this.state.newTrait.Name,1677 Requirements: requirements,1678 id,1679 })1680 let traitsClone = {1681 ...this.state.customTraits1682 }1683 //go back in modal1684 this.setState({customizePage: "abilities", newTrait: {}, modifyingTrait: -1, customTraits: traitsClone})1685 }1686 if (this.state.customizePage === "editEquipment") {1687 //validate1688 if (!this.state.newTrait.Name) {1689 this.cusEquScroll.scrollTo({y: 0, animated: true})1690 this.setState({validate: true})1691 return1692 }1693 //this means we're editing a trait, remove the old one1694 if (this.state.modifyingTrait > -1) {1695 // preserve the id1696 id = this.state.newTrait.id1697 this.state.customTraits.equipment.splice(this.state.modifyingTrait, 1)1698 }1699 let description = this.state.newTrait.Name + (this.state.newTrait.description ? ": " + this.state.newTrait.description : "")1700 let requirements = {1701 Level: this.state.newTrait.levelReq,1702 Properties: this.state.newTrait.classReq,1703 }1704 //add the new trait/version1705 // for some reason equipment does incompatible differently1706 this.state.customTraits.equipment.unshift({1707 Reroll: 0,1708 Description: description,1709 Incompatible: description,1710 Name: this.state.newTrait.Name,1711 Requirements: requirements,1712 id,1713 })1714 let traitsClone = {1715 ...this.state.customTraits1716 }1717 //go back in modal1718 this.setState({customizePage: "equipment", newTrait: {}, modifyingTrait: -1, customTraits: traitsClone})1719 }1720 if (this.state.customizePage === "editRace") {1721 //validate1722 if (!this.state.newTrait.Name || !this.state.newTrait.primaryStat || !this.state.newTrait.secondaryStat) {1723 if (!this.state.newTrait.Name) {1724 this.cusRacScroll.scrollTo({y: 0, animated: true})1725 }1726 this.setState({validate: true})1727 return1728 }1729 //this means we're editing a trait, remove the old one1730 if (this.state.modifyingTrait > -1) {1731 // preserve the id1732 id = this.state.newTrait.id1733 this.state.customTraits.races.splice(this.state.modifyingTrait, 1)1734 }1735 let Stats = {1736 [this.state.newTrait.primaryStat]: 2,1737 [this.state.newTrait.secondaryStat]: 1,1738 }1739 let Abilities = []1740 if (this.state.newTrait.ability) {1741 Abilities = this.state.newTrait.ability.split("\n")1742 }1743 // add the new trait/version1744 this.state.customTraits.races.unshift({1745 Reroll: 0,1746 Abilities,1747 Name: this.state.newTrait.Name,1748 Properties: [id],1749 primaryStat: this.state.newTrait.primaryStat,1750 secondaryStat: this.state.newTrait.secondaryStat,1751 Stats,1752 id,1753 })1754 let traitsClone = {1755 ...this.state.customTraits1756 }1757 //go back in modal1758 this.setState({customizePage: "races", newTrait: {}, modifyingTrait: -1, customTraits: traitsClone})1759 }1760 if (this.state.customizePage === "editClass") {1761 //validate1762 if (!this.state.newTrait.Name || !this.state.newTrait.primaryStat || !this.state.newTrait.secondaryStat1763 || !this.state.newTrait.weapon || !this.state.newTrait.armor || !this.state.newTrait.hp) {1764 if (!this.state.newTrait.Name) {1765 this.cusClaScroll.scrollTo({y: 0, animated: true})1766 }1767 this.setState({validate: true})1768 return1769 }1770 this.saveClassFirstTime()1771 //this means we're editing a trait, remove the old one1772 if (this.state.modifyingTrait > -1) {1773 // id is preserved by getNewClass1774 this.state.customTraits.classes.splice(this.state.modifyingTrait, 1)1775 }1776 else {1777 // add new id1778 this.state.newTrait.id = id1779 }1780 this.state.customTraits.classes.unshift(this.getNewClass(this.state.newTrait))1781 let traitsClone = {1782 ...this.state.customTraits1783 }1784 // this will get erased by setState so we need to preserve it for updating dependencies1785 let preserveId = this.state.newTrait.id1786 //go back in modal1787 this.setState({customizePage: "classes", newTrait: {}, modifyingTrait: -1, customTraits: traitsClone}, () => {1788 // after state has been set, go through all dependents and update them1789 for (let clas of this.getDependents(preserveId)) {1790 this.updateClassBase(clas)1791 }1792 })1793 }1794 }1795 // creates a new class given the trait blueprint. similar to other traits in saveTrait but we reuse this code for updating class dependencies1796 getNewClass (trait) {1797 let Stat_Requirements = {1798 [trait.secondaryStat]: 12,1799 [trait.primaryStat]: 14,1800 }1801 // we use additional abilities instead of abilities because we want all listed, not just 11802 let AdditionalAbilities = []1803 if (trait.ability) {1804 AdditionalAbilities = trait.ability.split("\n")1805 }1806 // now we need to create lists of weapons/armor based on user selection1807 let Equipment1808 let EquipmentSecond1809 switch (trait.weapon) {1810 case "none":1811 Equipment = []1812 break1813 case "one-melee":1814 Equipment = ["Mace (1d6)","Light Hammer (1d4)","Flail (1d8)","Handaxe (1d6)", "War Pick (1d8)", "Javelin (1d6)", "Morningstar (1d8)"]1815 break1816 case "two-melee":1817 Equipment = ["Battleaxe (1d8/1d10)","Greatclub (1d8)","Longsword (1d8/1d10)","Warhammer (1d8/1d10)", "Greataxe (1d12)", "Greatsword (2d6)", "Halberd (1d10)", "Maul (2d6)", "Pike (1d10)"]1818 break1819 case "finesse-melee":1820 Equipment = ["Dagger x2 (1d4 Finesse)", "Shortsword (1d6 Finesse)", "Rapier (1d8 Finesse)", "Scimitar (1d6 Finesse)", "Whip (1d4 Finesse Reach)"]1821 break1822 case "bows":1823 Equipment = ["Shortbow (1d6)","Longbow (1d8)", "Light Crossbow (1d8)", "Heavy Crossbow (1d10)"]1824 break1825 case "magic":1826 Equipment = ["Magic Missile Wand (2) (2x 1d4+1 Auto-hit)", "Alchemist's Fire Guiding Flask (2) (range spell attack, 1d4 per turn until put out (DC 10 DEX action)", "Frost Staff (ranged spell attack, 1d8)", "Staff of Fear (3) (spell save, fear for 2 turns)", "Shocking Wand (ranged spell attack, 3d2)", "Wand of Jitters (ranged spell attack, disarm and knock prone)"]1827 break1828 case "instrument":1829 Equipment = ["Tamborine", "Lute", "Flute", "Pan Flute", "Fiddle", "Recorder", "Ocarina", "Drum", "Bagpipes", "Lyre", "Dulcimer", "Horn", "Shawm", "Viol"]1830 break1831 }1832 switch (trait.armor) {1833 case "none":1834 EquipmentSecond = ["Silk Robes", "Tunic", "Rags", "Cloak", "Shirtless", "Tight Clothes", "Pelt Coat"]1835 break1836 case "light":1837 EquipmentSecond = ["Leather Armor","Padded Armor","Studded Leather Armor"]1838 break1839 case "medium":1840 EquipmentSecond = ["Scale Mail Armor","Hide Armor","Chain Shirt Armor","Breastplate Armor","Half Plate Armor"]1841 break1842 case "heavy":1843 EquipmentSecond = ["Ring Mail Armor", "Chain Mail Armor", "Splint Armor", "Plate Armor"]1844 break1845 }1846 // if we have a base class, add it as a property and include its default abilities1847 let props = []1848 let Abilities = []1849 if (trait.base) {1850 let basedClass = this.getAllClasses().find(x => x.Properties[0] == trait.base)1851 Abilities = [...basedClass.Abilities]1852 props = [...basedClass.Properties]1853 if (basedClass.AdditionalAbilities) {1854 AdditionalAbilities = AdditionalAbilities.concat(basedClass.AdditionalAbilities)1855 }1856 }1857 // add the new trait/version1858 return {1859 Reroll: 0,1860 Abilities,1861 AdditionalAbilities,1862 Name: trait.Name,1863 Properties: [trait.id, ...props],1864 primaryStat: trait.primaryStat,1865 secondaryStat: trait.secondaryStat,1866 weapon: trait.weapon,1867 armor: trait.armor,1868 Equipment,1869 EquipmentSecond,1870 Stat_Requirements,1871 ability: trait.ability,1872 id: trait.id,1873 base: trait.base,1874 hp: trait.hp,1875 }1876 }1877 deleteTrait () {1878 let page1879 if (this.state.customizePage === "editPersonality") {1880 this.state.customTraits.personalities.splice(this.state.modifyingTrait, 1)1881 page = "personalities"1882 }1883 if (this.state.customizePage === "editAccent") {1884 this.state.customTraits.accents.splice(this.state.modifyingTrait, 1)1885 page = "accents"1886 }1887 if (this.state.customizePage === "editAppearence") {1888 this.state.customTraits.appearences.splice(this.state.modifyingTrait, 1)1889 page = "appearences"1890 }1891 if (this.state.customizePage === "editAbility") {1892 this.state.customTraits.abilities.splice(this.state.modifyingTrait, 1)1893 page = "abilities"1894 }1895 if (this.state.customizePage === "editEquipment") {1896 this.state.customTraits.equipment.splice(this.state.modifyingTrait, 1)1897 page = "equipment"1898 }1899 if (this.state.customizePage === "editRace") {1900 // clear this race on the settings screen if its selected1901 let id = this.state.newTrait.id1902 if (this.state.settingsNew.Race === id) {1903 this.state.settingsNew.Race = "Any"1904 }1905 this.state.customTraits.races.splice(this.state.modifyingTrait, 1)1906 page = "races"1907 }1908 if (this.state.customizePage === "editClass") {1909 // clear this class on the settings screen if its selected1910 let id = this.state.newTrait.id1911 if (this.state.settingsNew.Class === id) {1912 this.state.settingsNew.Class = "Any"1913 }1914 this.state.customTraits.classes.splice(this.state.modifyingTrait, 1)1915 page = "classes"1916 }1917 let traitsClone = {1918 ...this.state.customTraits1919 }1920 //go back in modal1921 this.setState({customizePage: page, newTrait: {}, modifyingTrait: -1, customTraits: traitsClone})1922 }1923 tryToDeleteClass () {1924 // no dependents, go ahead1925 let dependents = this.getDependents(this.state.newTrait.id)1926 if (dependents.length === 0) return true1927 else {1928 Alert.alert(1929 "Delete base class",1930 "Other classes are based on this class. They will be based on no class if this is deleted, which is fine if you want. Are you sure you want to delete this class?",1931 [1932 { text: "Yes", onPress: () => {1933 // go through all dependents and make them based on no class1934 for (let clas of dependents) {1935 this.updateClassBase(clas, "")1936 }1937 // delete the class1938 this.deleteTrait()1939 }},1940 { text: "No", onPress: () => {}}1941 ],1942 { cancelable: false }1943 );1944 }1945 }1946 updateClassBase (clas, newBase) {1947 // strip the class down so we can rebuild its1948 let classBlueprint = this.getClassAsNewTrait(clas)1949 if (newBase !== undefined) classBlueprint.base = newBase1950 // rebuild it, updating the base (new or not) in the proces1951 let updatedClass = this.getNewClass(classBlueprint)1952 // save the class in-place in our classes array1953 for (let index in this.state.customTraits.classes) {1954 let curClass = this.state.customTraits.classes[index]1955 if (curClass.id == updatedClass.id) {1956 // yes this is the improper way to set state, but its ok here since nothing in the UI needs updating in response to this (because our sub-menus don't render until they're clicked)1957 this.state.customTraits.classes[index] = updatedClass1958 }1959 }1960 // repeat this for our dependents1961 for (let clas of this.getDependents(updatedClass.id)) {1962 this.updateClassBase(clas)1963 }1964 }1965 editTrait (item, index) {1966 // remember index so we can update it1967 this.setState({modifyingTrait: index})1968 // convert generator-usable trait into editable trait1969 if (this.state.customizePage === 'personalities') {1970 this.setState({1971 validate: true,1972 newTrait: {1973 Name: item.Name,1974 id: item.id,1975 },1976 customizePage: "editPersonality"1977 })1978 }1979 if (this.state.customizePage === 'appearences') {1980 this.setState({1981 validate: true,1982 newTrait: {1983 Name: item.Name,1984 id: item.id,1985 },1986 customizePage: "editAppearence"1987 })1988 }1989 if (this.state.customizePage === 'accents') {1990 this.setState({1991 validate: true,1992 newTrait: {1993 Name: item,1994 id: item.id,1995 },1996 customizePage: "editAccent"1997 })1998 }1999 if (this.state.customizePage === 'abilities') {2000 let desc = ""2001 if (item.Description.length > item.Name.length) {2002 desc = item.Description.substr(item.Name.length + 2)2003 }2004 this.setState({2005 validate: true,2006 newTrait: {2007 Name: item.Name,2008 description: desc,2009 classReq: item.Requirements.Properties,2010 levelReq: item.Requirements.Level,2011 id: item.id,2012 },2013 customizePage: "editAbility"2014 })2015 }2016 if (this.state.customizePage === 'equipment') {2017 let desc = ""2018 if (item.Description.length > item.Name.length) {2019 desc = item.Description.substr(item.Name.length + 2)2020 }2021 this.setState({2022 validate: true,2023 newTrait: {2024 Name: item.Name,2025 description: desc,2026 classReq: item.Requirements.Properties,2027 levelReq: item.Requirements.Level,2028 id: item.id,2029 },2030 customizePage: "editEquipment"2031 })2032 }2033 if (this.state.customizePage === 'races') {2034 this.setState({2035 validate: true,2036 newTrait: {2037 Name: item.Name,2038 ability: item.Abilities.join('\n'),2039 primaryStat: item.primaryStat,2040 secondaryStat: item.secondaryStat,2041 id: item.id,2042 },2043 customizePage: "editRace"2044 })2045 }2046 if (this.state.customizePage === 'classes') {2047 this.setState({2048 validate: true,2049 newTrait: this.getClassAsNewTrait(item),2050 customizePage: "editClass"2051 })2052 }2053 }2054 getClassAsNewTrait (item) {2055 return {2056 Name: item.Name,2057 ability: item.ability,2058 primaryStat: item.primaryStat,2059 secondaryStat: item.secondaryStat,2060 weapon: item.weapon,2061 armor: item.armor,2062 base: item.base,2063 id: item.id,2064 hp: item.hp,2065 }2066 }2067 // if user changes the base of a class, set the defaults for all their attributes2068 setClassDefaults (baseId) {2069 let baseClass = this.getAllClasses().find(x => x.Properties[0] == baseId)2070 let trait = {...this.state.newTrait}2071 if (baseClass.hp) trait.hp = baseClass.hp2072 else {2073 if (baseClass.Properties.includes("wizard")) trait.hp = "d6"2074 if (baseClass.Properties.includes("sorcerer")) trait.hp = "d6"2075 if (baseClass.Properties.includes("bard")) trait.hp = "d8"2076 if (baseClass.Properties.includes("cleric")) trait.hp = "d8"2077 if (baseClass.Properties.includes("druid")) trait.hp = "d8"2078 if (baseClass.Properties.includes("warlock")) trait.hp = "d8"2079 if (baseClass.Properties.includes("monk")) trait.hp = "d8"2080 if (baseClass.Properties.includes("artificer")) trait.hp = "d8"2081 if (baseClass.Properties.includes("rogue")) trait.hp = "d8"2082 if (baseClass.Properties.includes("ranger")) trait.hp = "d10"2083 if (baseClass.Properties.includes("fighter")) trait.hp = "d10"2084 if (baseClass.Properties.includes("paladin")) trait.hp = "d10"2085 if (baseClass.Properties.includes("barbarian")) trait.hp = "d12"2086 }2087 if (baseClass.armor) trait.armor = baseClass.armor2088 else {2089 if (baseClass.Properties.includes("wizard")) trait.armor = "none"2090 if (baseClass.Properties.includes("sorcerer")) trait.armor = "none"2091 if (baseClass.Properties.includes("bard")) trait.armor = "light"2092 if (baseClass.Properties.includes("cleric")) trait.armor = "medium"2093 if (baseClass.Properties.includes("druid")) trait.armor = "medium"2094 if (baseClass.Properties.includes("warlock")) trait.armor = "light"2095 if (baseClass.Properties.includes("monk")) trait.armor = "none"2096 if (baseClass.Properties.includes("artificer")) trait.armor = "medium"2097 if (baseClass.Properties.includes("rogue")) trait.armor = "light"2098 if (baseClass.Properties.includes("ranger")) trait.armor = "medium"2099 if (baseClass.Properties.includes("fighter")) trait.armor = "heavy"2100 if (baseClass.Properties.includes("paladin")) trait.armor = "heavy"2101 if (baseClass.Properties.includes("barbarian")) trait.armor = "none"2102 }2103 if (baseClass.weapon) trait.weapon = baseClass.weapon2104 else {2105 if (baseClass.Properties.includes("wizard")) trait.weapon = "magic"2106 if (baseClass.Properties.includes("sorcerer")) trait.weapon = "magic"2107 if (baseClass.Properties.includes("bard")) trait.weapon = "instrument"2108 if (baseClass.Properties.includes("cleric")) trait.weapon = "one-melee"2109 if (baseClass.Properties.includes("druid")) trait.weapon = "none"2110 if (baseClass.Properties.includes("warlock")) trait.weapon = "one-melee"2111 if (baseClass.Properties.includes("monk")) trait.weapon = "none"2112 if (baseClass.Properties.includes("artificer")) trait.weapon = "magic"2113 if (baseClass.Properties.includes("rogue")) trait.weapon = "finesse-melee"2114 if (baseClass.Properties.includes("ranger")) trait.weapon = "bows"2115 if (baseClass.Properties.includes("fighter")) trait.weapon = "two-melee"2116 if (baseClass.Properties.includes("paladin")) trait.weapon = "two-melee"2117 if (baseClass.Properties.includes("barbarian")) trait.weapon = "two-melee"2118 }2119 if (baseClass.weapon) trait.primaryStat = baseClass.primaryStat2120 else {2121 if (baseClass.Properties.includes("wizard")) trait.primaryStat = "I"2122 if (baseClass.Properties.includes("sorcerer")) trait.primaryStat = "C"2123 if (baseClass.Properties.includes("bard")) trait.primaryStat = "C"2124 if (baseClass.Properties.includes("cleric")) trait.primaryStat = "W"2125 if (baseClass.Properties.includes("druid")) trait.primaryStat = "W"2126 if (baseClass.Properties.includes("warlock")) trait.primaryStat = "C"2127 if (baseClass.Properties.includes("monk")) trait.primaryStat = "D"2128 if (baseClass.Properties.includes("artificer")) trait.primaryStat = "I"2129 if (baseClass.Properties.includes("rogue")) trait.primaryStat = "D"2130 if (baseClass.Properties.includes("ranger")) trait.primaryStat = "D"2131 if (baseClass.Properties.includes("fighter")) trait.primaryStat = "S"2132 if (baseClass.Properties.includes("paladin")) trait.primaryStat = "S"2133 if (baseClass.Properties.includes("barbarian")) trait.primaryStat = "S"2134 }2135 if (baseClass.weapon) trait.secondaryStat = baseClass.secondaryStat2136 else {2137 if (baseClass.Properties.includes("wizard")) trait.secondaryStat = "W"2138 if (baseClass.Properties.includes("sorcerer")) trait.secondaryStat = "E"2139 if (baseClass.Properties.includes("bard")) trait.secondaryStat = "D"2140 if (baseClass.Properties.includes("cleric")) trait.secondaryStat = "S"2141 if (baseClass.Properties.includes("druid")) trait.secondaryStat = "I"2142 if (baseClass.Properties.includes("warlock")) trait.secondaryStat = "S"2143 if (baseClass.Properties.includes("monk")) trait.secondaryStat = "W"2144 if (baseClass.Properties.includes("artificer")) trait.secondaryStat = "E"2145 if (baseClass.Properties.includes("rogue")) trait.secondaryStat = "I"2146 if (baseClass.Properties.includes("ranger")) trait.secondaryStat = "W"2147 if (baseClass.Properties.includes("fighter")) trait.secondaryStat = "E"2148 if (baseClass.Properties.includes("paladin")) trait.secondaryStat = "C"2149 if (baseClass.Properties.includes("barbarian")) trait.secondaryStat = "E"2150 }2151 this.setState({newTrait: trait})2152 }2153 getAllClasses () {2154 let classes = this.state.customTraits.classes.concat(require('./src/Class.js').placeholder)2155 classes = classes.filter(x => x.Name !== "None")2156 return classes2157 }2158 // this is basically getAllClasses but it also appends any deleted classes that the current ability/equipment being modified had previously selected as a required class2159 getAllClassesForReq () {2160 let classes = this.getAllClasses()2161 for (let item of this.state.newTrait.classReq) {2162 let found = false2163 for (let clas of classes) {2164 if (clas.Properties[0] === item) found = true2165 }2166 if (!found) classes.unshift({Name:"!Class Deleted!", Properties: [item]})2167 }2168 return classes2169 }2170 getIntroText () {2171 if (this.state.introStep === 0) return "Click here to create a new NPC"2172 if (this.state.introStep === 1) return "Click here to select an NPC. This does nothing right now, but normally you see NPC data here where this text is, which you can tap to edit."2173 if (this.state.introStep === 2) return "Click here to delete the currently selected NPC"2174 if (this.state.introStep === 3) return "Clicking here allows you to adjust new NPC settings."2175 if (this.state.introStep === 4) return "Clicking here allows you to add your own content! Create classes, personalities, equipment, etc which will be used when generating new NPCs!"2176 }2177 async exportContent () {2178 try {2179 const granted = await PermissionsAndroid.request(2180 PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE2181 );2182 if (granted === PermissionsAndroid.RESULTS.GRANTED) {2183 const dir = fs.DownloadDirectoryPath; // TODO make this usable for ios https://github.com/itinance/react-native-fs2184 const NEW_FILE_PATH = dir + '/NPCG';2185 await fs.writeFile(NEW_FILE_PATH, JSON.stringify({characters: this.state.characters, customTraits: this.state.customTraits}));2186 Alert.alert(2187 "Success",2188 "All data exported to file 'NPCG' in your Downloads folder. When moving to a new phone, select this file with 'import content' to keep all your data!",2189 [2190 { text: "OK", onPress: () => {}}2191 ],2192 { cancelable: true }2193 );2194 } else {2195 // permission denied2196 }2197 } 2198 catch (err) {2199 Alert.alert(2200 "Error",2201 "An error has occured: "+err,2202 [2203 { text: "OK", onPress: () => {}}2204 ],2205 { cancelable: true }2206 );2207 }2208 }2209 async importContent () {2210 try {2211 const res = await DocumentPicker.pick({ type: [DocumentPicker.types.allFiles] })2212 let contents = JSON.parse(await fs.readFile(res.uri, 'utf8'))2213 if (!contents || !contents.characters || !contents.customTraits) throw new Error("")2214 let dupObj = {duplicates: false}2215 let characters = this.concatWithoutDuplicates(this.state.characters, contents.characters, dupObj)2216 let customTraits = {2217 personalities: this.concatWithoutDuplicates(this.state.customTraits.personalities, contents.customTraits.personalities, dupObj),2218 accents: this.concatWithoutDuplicates(this.state.customTraits.accents, contents.customTraits.accents, dupObj),2219 appearences: this.concatWithoutDuplicates(this.state.customTraits.appearences, contents.customTraits.appearences, dupObj),2220 equipment: this.concatWithoutDuplicates(this.state.customTraits.equipment, contents.customTraits.equipment, dupObj),2221 abilities: this.concatWithoutDuplicates(this.state.customTraits.abilities, contents.customTraits.abilities, dupObj),2222 races: this.concatWithoutDuplicates(this.state.customTraits.races, contents.customTraits.races, dupObj),2223 classes: this.concatWithoutDuplicates(this.state.customTraits.classes, contents.customTraits.classes, dupObj),2224 }2225 this.setState({characters, customTraits, showText: true})2226 Alert.alert(2227 dupObj.duplicates ? "Warning" : "Success",2228 dupObj.duplicates ? 2229 "Content imported successfully, however duplicate content was detected. Duplicates were not be imported." :2230 "Content imported successfully!",2231 [2232 { text: "OK", onPress: () => {}}2233 ],2234 { cancelable: true }2235 );2236 } 2237 catch (err) {2238 if (!DocumentPicker.isCancel(err)) {2239 Alert.alert(2240 "Error",2241 "Invalid file. Please select an 'NPCG' file exported by this app.",2242 [2243 { text: "OK", onPress: () => {}}2244 ],2245 { cancelable: true }2246 );2247 }2248 }2249 }2250 concatWithoutDuplicates (list, newList, dupObj) {2251 for (let newItem of newList) {2252 let isDuplicate = false2253 for (let item of list) {2254 // see if any items have the same id2255 if (item.id) {2256 if (newItem.id == item.id) {2257 dupObj.duplicates = true2258 isDuplicate = true2259 }2260 }2261 // if they dont use ids, just check if theyre the same (both are a string)2262 else {2263 if (newItem == item) {2264 dupObj.duplicates = true2265 isDuplicate = true2266 }2267 }2268 }2269 if (!isDuplicate) list.push(newItem)2270 }2271 return list2272 }2273 2274 2275 2276// ==================================================================2277// Styles2278 d = Dimensions.get("window")2279 styles = StyleSheet.create({2280 background: {2281 width: this.d.width,2282 height: this.d.height,2283 flexDirection: 'column'2284 },2285 2286 //2287 topBar: {2288 flexDirection: 'row', 2289 width: '100%',2290 },2291 2292 cornerContainer: {2293 width: '20%',2294 justifyContent: 'center',2295 alignItems: 'center'2296 },2297 2298 //X and gear icon2299 smallButton: {2300 width: 70,2301 height: 70,2302 marginTop: 40,2303 marginRight: 'auto',2304 marginLeft: 'auto',2305 resizeMode: 'contain',2306 },2307 2308 //full new+ sign2309 bigButtonContainer: {2310 flexDirection: 'row', 2311 width: '60%',2312 justifyContent: 'center',2313 },2314 2315 //left side of new+ sign 2316 bigButtonLeft: {2317 width: 147,2318 height: 140,2319 resizeMode: 'contain',2320 },2321 2322 //right side of new+ sign2323 bigButtonRight: {2324 width: 53,2325 height: 120,2326 resizeMode: 'contain',2327 },2328 2329 belowTopBar: {2330 width: '100%',2331 height: this.d.height - 140,2332 flexDirection: 'row',2333 paddingBottom: 502334 },2335 2336 rightText: {2337 width: '80%'2338 },2339 2340 //where the curChar text is displayed and edited 2341 textArea: {2342 width: '100%', 2343 height: '100%', 2344 paddingRight: 25,2345 paddingLeft: 25,2346 paddingTop: 25,2347 margin: 0,2348 fontSize: 16,2349 },2350 customizeTextInput: {2351 width: '100%', 2352 height: 50,2353 fontSize: 16,2354 borderWidth: 1,2355 borderColor: '#ffffff',2356 color: '#ffffff',2357 },2358 customizeTextInputLarge: {2359 width: '100%', 2360 height: '100%',2361 fontSize: 16,2362 color: '#ffffff',2363 textAlignVertical: 'top'2364 },2365 customizeTextInputLargeFrame: {2366 width: '100%', 2367 height: 80,2368 fontSize: 16,2369 borderWidth: 1,2370 borderColor: '#ffffff',2371 paddingLeft: 5,2372 paddingRight: 5,2373 },2374 2375 leftBar: {2376 flexDirection: 'column', 2377 width: '20%'2378 },2379 2380 existingTraits: {2381 flexDirection: 'column', 2382 width: '100%',2383 height: 2002384 },2385 listButton: {2386 width: 80,2387 height: 80,2388 marginTop: 25,2389 marginRight: 'auto',2390 marginLeft: 'auto',2391 },2392 listImage: {2393 resizeMode: 'contain',2394 },2395 2396 listBackground: {2397 width: '100%',2398 height: '100%',2399 justifyContent: 'center',2400 alignItems: 'center'2401 },2402 2403 listText: {2404 width: 42,2405 fontSize: 16,2406 paddingBottom: 10,2407 textShadowColor: '#990000',2408 textShadowOffset: {width: 2, height: 2},2409 color: '#ffffff',2410 textAlign: 'center',2411 },2412 2413 modalBackground: {2414 width: '100%',2415 height: '100%',2416 backgroundColor : '#000000',2417 opacity: 0.52418 },2419 2420 modalContent: {2421 width: 250,2422 height: 375,2423 left: '50%',2424 marginLeft: -125,2425 top: '50%',2426 marginTop: -187.5,2427 position: 'absolute',2428 },2429 2430 modalImage: {2431 resizeMode: 'stretch',2432 },2433 2434 modalScroll: {2435 width: '100%',2436 marginBottom: 25,2437 marginTop: 27,2438 paddingLeft: 23,2439 paddingRight: 23,2440 },2441 2442 modalSettingsNewPlus: {2443 marginTop: 27,2444 paddingLeft: 23,2445 paddingRight: 23,2446 paddingBottom: 5,2447 width: '100%',2448 justifyContent: 'space-around',2449 flexDirection: 'row', 2450 alignItems: 'center' 2451 },2452 2453 modalSettingsNew: {2454 width: 100, 2455 resizeMode: 'contain'2456 },2457 2458 modalSettingsPlus: {2459 width: 33,2460 resizeMode: 'contain'2461 },2462 2463 modalSettingContainer: {2464 paddingTop: 10,2465 paddingBottom: 5,2466 width: '100%',2467 justifyContent: 'space-between',2468 flexDirection: 'row', 2469 overflow: 'hidden'2470 },2471 2472 customizeSettingContainer: {2473 paddingTop: 10,2474 paddingBottom: 5,2475 width: '100%',2476 flexDirection: 'column', 2477 overflow: 'hidden'2478 },2479 2480 eyeButton: {2481 margin: 10,2482 paddingRight: 15,2483 width: '100%',2484 height: 50,2485 alignItems: 'center',2486 justifyContent: 'center',2487 overflow: 'hidden'2488 },2489 visible: {2490 display: 'flex'2491 },2492 hidden: {2493 display: 'none'2494 },2495 2496 modalSettingLabel: {2497 fontSize: 20,2498 textShadowColor: '#990000',2499 textShadowOffset: {width: 2, height: 2},2500 color: '#ffffff',2501 },2502 backButton: {2503 width: 100,2504 paddingLeft: 10,2505 paddingTop: 8,2506 marginBottom: 10,2507 },2508 saveButton: {2509 width: 100,2510 paddingLeft: 10,2511 paddingTop: 5,2512 marginBottom: 5,2513 },2514 deleteButton: {2515 width: 70,2516 paddingTop: 5,2517 marginBottom: 5,2518 },2519 2520 modalSettingButton: {2521 fontSize: 20,2522 textShadowColor: '#990000',2523 textShadowOffset: {width: 2, height: 2},2524 color: '#ffffff',2525 textDecorationLine: 'underline'2526 },2527 modalSettingButtonRed: {2528 fontSize: 20,2529 color: '#a21414',2530 fontWeight: 'bold',2531 textDecorationLine: 'underline'2532 },2533 2534 modalSettingPicker: {2535 width: 120,2536 margin: 0,2537 padding: 0,2538 marginTop: -13,2539 height: 50,2540 color: '#ffffff',2541 transform: [2542 { scaleX: 1.25 }, 2543 { scaleY: 1.25 },2544 ]2545 },2546 2547 modalSettingPickerMed: {2548 width: 100,2549 margin: 0,2550 padding: 0,2551 marginTop: -13,2552 height: 50,2553 color: '#ffffff',2554 transform: [2555 { scaleX: 1.25 }, 2556 { scaleY: 1.25 },2557 ],2558 },2559 2560 modalSettingPickerThin: {2561 width: 80,2562 margin: 0,2563 padding: 0,2564 marginTop: -13,2565 height: 50,2566 color: '#ffffff',2567 transform: [2568 { scaleX: 1.25 }, 2569 { scaleY: 1.25 },2570 ]2571 },2572 modalSettingCheckbox: {2573 width: 30,2574 height: 30,2575 resizeMode: 'stretch',2576 opacity: 12577 },2578 multiSelectBackground: {2579 backgroundColor: 'transparent'2580 },2581 multiSelectText: {2582 color: '#ffffff',2583 fontSize: 20,2584 },2585 multiSelectTextSmall: {2586 color: '#ffffff',2587 fontSize: 14,2588 },2589 multiSelectSearch: {2590 display: 'none'2591 },2592 redOutline: {2593 borderWidth: 2,2594 borderColor: '#a21414',2595 },2596 transOutline: {2597 margin: 2,2598 },2599 overlay: {2600 position: 'absolute',2601 width: '100%',2602 height: '100%', 2603 opacity: 0.8,2604 backgroundColor: 'black',2605 zIndex: 1000,2606 elevation: 52607 },2608 overOverlay: {2609 zIndex: 100000,2610 elevation: 102611 },2612 introText: {2613 color: '#ffffff',2614 fontSize: 30,2615 padding: 20,2616 }2617 });2618 2619 2620}2621 class FlatListItem extends React.Component {2622 render() {2623 return (2624 <View>2625 {this.props.children}2626 </View>2627 )2628 }2629 2630 shouldComponentUpdate(nextProps, nextState) {2631 // change if:2632 // im currently not selected but going to be,2633 // im currently selected but not going to be,2634 // my index is changing2635 if((nextProps.stateIndex == nextProps.myIndex) && (this.props.stateIndex != this.props.myIndex) ||2636 ((this.props.stateIndex == this.props.myIndex) && (this.props.myIndex != nextProps.stateIndex)) ||2637 (this.props.myIndex != nextProps.myIndex)){2638 return true;2639 }2640 return false;2641 }2642}2643class FlatListItemTraits extends React.PureComponent {2644 render() {2645 return (2646 <View>2647 {this.props.children}2648 </View>2649 )2650 }2651}2652 2653 2654 2655 /* Unused functionality2656 2657 2658 <View style={this.styles.modalHeaderContainer}>2659 <Text style={this.styles.modalHeaderLabel}>Class</Text>2660 <TouchableOpacity onPress={()=>this.toggleGroupSetting("Class")} activeOpacity={0.5}>2661 <Image style={this.styles.modalHeaderInput} source={this.getCheckbox("Class")}></Image>2662 </TouchableOpacity>2663 </View>2664 2665 {this.getToggleOption("Artificer")}2666 {this.getToggleOption("Barbarian")}2667 {this.getToggleOption("Bard")}2668 {this.getToggleOption("Cleric")}2669 {this.getToggleOption("Druid")}2670 {this.getToggleOption("Fighter")}2671 {this.getToggleOption("Monk")}2672 {this.getToggleOption("Paladin")}2673 {this.getToggleOption("Ranger")}2674 {this.getToggleOption("Rogue")}2675 {this.getToggleOption("Sorcerer")}2676 {this.getToggleOption("Warlock")}2677 {this.getToggleOption("Wizard")}2678 2679 2680 2681 2682 2683 2684 //helper function for determining whether to show checked or unchecked box in modal options2685 getCheckbox(name){2686 var checkBox = require('./src/empty_checkbox.png');2687 if(this.state.settings[name]) checkBox = require('./src/full_checkbox.png');2688 2689 return checkBox;2690 }2691 2692 //helper function for getting a standard toggle setting option. Assumes this.state.settings[name] is a boolean2693 getToggleOption(name){2694 return (2695 <View style={this.styles.modalOptionContainer}>2696 <Text style={this.styles.modalOptionLabel}>{name}</Text>2697 <TouchableOpacity onPress={()=>this.toggleSetting(name)} activeOpacity={0.5}>2698 <Image style={this.styles.modalOptionInput} source={this.getCheckbox(name)} />2699 </TouchableOpacity>2700 </View>2701 );2702 }2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 // toggles the given option in our settings object2718 // note this could cause loss of data if multiple setStates are stacked, but that's almost impossible for our application2719 toggleSetting(name){2720 this.setState({2721 settings: {2722 ...this.state.settings,2723 [name]: !this.state.settings[name]2724 }2725 });2726 }2727 2728 // toggles the given option in our settings object2729 // note this could cause loss of data if multiple setStates are stacked, but that's almost impossible for our application2730 toggleGroupSetting(name){2731 2732 if(name == "Class"){2733 var setThem = !this.state.settings.Class;2734 2735 this.setState({2736 settings: {2737 ...this.state.settings,2738 Class: setThem,2739 Artificer: setThem,2740 Barbarian: setThem,2741 Bard: setThem,2742 Cleric: setThem,2743 Druid: setThem,2744 Fighter: setThem,2745 Monk: setThem,2746 Paladin: setThem,2747 Ranger: setThem,2748 Rogue: setThem,2749 Sorcerer: setThem,2750 Warlock: setThem,2751 Wizard: setThem,2752 }2753 });2754 }2755 2756 }2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 modalHeaderContainer: {2768 paddingTop: 15,2769 width: '100%',2770 justifyContent: 'space-between',2771 flexDirection: 'row', 2772 },2773 2774 modalHeaderLabel: {2775 fontSize: 20,2776 textShadowColor: '#990000',2777 textShadowOffset: {width: 2, height: 2},2778 color: '#ffffff',2779 },2780 2781 modalHeaderInput: {2782 width: 30,2783 height: 30,2784 resizeMode: 'stretch'2785 },2786 2787 modalOptionContainer: {2788 width: '100%',2789 justifyContent: 'space-between',2790 flexDirection: 'row', 2791 },2792 2793 modalOptionLabel: {2794 fontSize: 16,2795 paddingLeft: 20,2796 textShadowColor: '#990000',2797 textShadowOffset: {width: 2, height: 2},2798 color: '#ffffff',2799 },2800 2801 modalOptionInput: {2802 width: 30,2803 height: 30,2804 resizeMode: 'stretch',2805 opacity: 12806 },2807 ...
prefs.js
Source:prefs.js
1const ExtensionUtils = imports.misc.extensionUtils;2const Me = ExtensionUtils.getCurrentExtension();3const { GeneralPage } = Me.imports.settings.generalPage;4const { CustomizePage } = Me.imports.settings.customizePage;5const { BehaviorPage } = Me.imports.settings.behaviorPage;6const { AboutPage } = Me.imports.settings.aboutPage;7function init() {8 ExtensionUtils.initTranslations();9}10function fillPreferencesWindow(window) {11 const settings = ExtensionUtils.getSettings();12 // enable search13 window.set_search_enabled(true);14 // resize the window15 window.set_size_request(16 window.default_width + 50,17 window.default_height + 15018 );19 // create pages20 window.add(new GeneralPage(settings));21 window.add(new CustomizePage(settings));22 window.add(new BehaviorPage(settings));23 window.add(new AboutPage());...
customize.page.spec.ts
Source:customize.page.spec.ts
1import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';2import { IonicModule } from '@ionic/angular';3import { CustomizePage } from './customize.page';4describe('CustomizePage', () => {5 let component: CustomizePage;6 let fixture: ComponentFixture<CustomizePage>;7 beforeEach(waitForAsync(() => {8 TestBed.configureTestingModule({9 declarations: [ CustomizePage ],10 imports: [IonicModule.forRoot()]11 }).compileComponents();12 fixture = TestBed.createComponent(CustomizePage);13 component = fixture.componentInstance;14 fixture.detectChanges();15 }));16 it('should create', () => {17 expect(component).toBeTruthy();18 });...
Using AI Code Generation
1import { customizePage } from '../storybook-root-provider';2customizePage({3});4export const toStorybook = () => <Button label="Hello Button" />;5toStorybook.story = {6};7import { addons } from '@storybook/addons';8import { themes } from '@storybook/theming';9export const customizePage = ({ title, url, goFullScreen, showStoriesPanel, showAddonPanel, showSearchBox, addonPanelInRight, sidebarAnimations, enableShortcuts, isToolshown, theme, selectedPanel, initialActive, panelPosition, sidebar, showNav, showPanel, panel, selectedPanel: selectedPanelName, }) => {10 addons.setConfig({11 });12};13export default customizePage;
Using AI Code Generation
1import { customizePage } from 'storybook-root-provider'2import { withA11y } from '@storybook/addon-a11y'3customizePage({4})5import './test.js'6import { addDecorator } from '@storybook/react'7import { withA11y } from '@storybook/addon-a11y'8addDecorator(withA11y)9import { storiesOf } from '@storybook/react';10import { withKnobs, text, select, boolean } from '@storybook/addon-knobs';11import { withInfo } from '@storybook/addon-info';12import Button from './Button';13const stories = storiesOf('Button', module);14stories.addDecorator(withKnobs);15stories.add(16 withInfo(`17 `)(() => {18 const label = text('Label', 'Button');19 const type = select('Type', ['primary', 'secondary'], 'primary');20 const disabled = boolean('Disabled', false);21 return <Button label={label} type={type} disabled={disabled} />;22 })23);24stories.add(25 withInfo(`26 `)(() => {27 const label = text('Label', 'Button');28 const type = select('Type', ['primary', 'secondary'], 'primary');29 const disabled = boolean('Disabled', true);30 const loading = boolean('Loading', true);31 return <Button label={label} type={type} disabled={disabled} loading={loading} />;32 })33);
Using AI Code Generation
1import {customizePage} from 'storybook-root';2customizePage({3});4import {addDecorator} from '@storybook/react';5import {withThemes} from 'storybook-addon-styled-component-theme';6import {themes} from 'storybook-root';7addDecorator(withThemes(themes));8import {addons} from '@storybook/addons';9import {themes} from 'storybook-root';10addons.setConfig({11});12import {addDecorator} from '@storybook/react';13import {withThemes} from 'storybook-addon-styled-component-theme';14import {themes} from 'storybook-root';15addDecorator(withThemes(themes));16import {addons} from '@storybook/addons';17import {themes} from 'storybook-root';18addons.setConfig({19});20import {addDecorator} from '@storybook/react';21import {withThemes} from 'storybook-addon-styled-component-theme';22import {themes} from 'storybook-root';23addDecorator(withThemes(themes));24import {addons} from '@storybook/addons';25import {themes} from 'storybook-root';26addons.setConfig({27});28import {addDecorator} from '@storybook/react';29import {withThemes} from 'storybook-addon-styled-component-theme';30import {themes} from 'storybook-root';31addDecorator(withThemes(themes));32import {addons} from '@storybook/addons';33import {themes} from 'storybook-root';34addons.setConfig({35});36import {addDecorator} from '@storybook/react';37import {withThemes} from 'storybook-addon-styled-component-theme';38import {themes} from 'storybook-root';39addDecorator(withThemes(themes));40import {addons} from '@storybook/addons';41import {themes} from 'storybook-root';42addons.setConfig({43});44import {addDecorator} from '@storybook/react';45import {withThemes} from 'storybook-addon-styled-component-theme';46import {themes} from '
Using AI Code Generation
1import { customizePage } from 'storybook-root-provider';2import { MyComponent } from '../src/MyComponent';3customizePage({4});5import { customizePage } from 'storybook-root-provider';6customizePage({7});8import { customizePage } from 'storybook-root-provider';9customizePage({10});
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!