build: change package name to dev.nulldori.eamemu
This commit is contained in:
parent
2fc95d18c7
commit
eadd41f1d7
@ -98,14 +98,13 @@ android {
|
|||||||
ndkVersion rootProject.ext.ndkVersion
|
ndkVersion rootProject.ext.ndkVersion
|
||||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||||
|
|
||||||
namespace "tk.nulldori.eamemu"
|
namespace "dev.nulldori.eamemu"
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "tk.nulldori.eamemu"
|
applicationId "dev.nulldori.eamemu"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 220
|
versionCode 300
|
||||||
versionName "2.2.0"
|
versionName "3.0.0"
|
||||||
vectorDrawables.useSupportLibrary = true
|
|
||||||
}
|
}
|
||||||
splits {
|
splits {
|
||||||
abi {
|
abi {
|
||||||
@ -172,8 +171,6 @@ dependencies {
|
|||||||
implementation jscFlavor
|
implementation jscFlavor
|
||||||
}
|
}
|
||||||
|
|
||||||
// for react-native-fs
|
|
||||||
implementation project(':react-native-fs')
|
|
||||||
implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
||||||
* directory of this source tree.
|
* directory of this source tree.
|
||||||
*/
|
*/
|
||||||
package tk.nulldori.eamemu;
|
package dev.nulldori.eamemu;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import com.facebook.flipper.android.AndroidFlipperClient;
|
import com.facebook.flipper.android.AndroidFlipperClient;
|
||||||
import com.facebook.flipper.android.utils.FlipperUtils;
|
import com.facebook.flipper.android.utils.FlipperUtils;
|
@ -1,4 +1,4 @@
|
|||||||
package tk.nulldori.eamemu
|
package dev.nulldori.eamemu
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException
|
import java.io.UnsupportedEncodingException
|
||||||
import kotlin.experimental.xor
|
import kotlin.experimental.xor
|
@ -1,4 +1,4 @@
|
|||||||
package tk.nulldori.eamemu
|
package dev.nulldori.eamemu
|
||||||
|
|
||||||
class B(arg4: ByteArray) {
|
class B(arg4: ByteArray) {
|
||||||
private val k: IntArray
|
private val k: IntArray
|
@ -1,20 +1,10 @@
|
|||||||
package tk.nulldori.eamemu;
|
package dev.nulldori.eamemu;
|
||||||
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.facebook.react.bridge.NativeModule;
|
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
import com.facebook.react.bridge.LifecycleEventListener;
|
|
||||||
import com.facebook.react.bridge.ReactContext;
|
|
||||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||||
import com.facebook.react.bridge.ReactMethod;
|
import com.facebook.react.bridge.ReactMethod;
|
||||||
import com.facebook.react.bridge.Promise;
|
import com.facebook.react.bridge.Promise;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import tk.nulldori.eamemu.A;
|
|
||||||
|
|
||||||
public class CardConvModule extends ReactContextBaseJavaModule {
|
public class CardConvModule extends ReactContextBaseJavaModule {
|
||||||
private static ReactApplicationContext reactContext;
|
private static ReactApplicationContext reactContext;
|
||||||
private static A converter;
|
private static A converter;
|
@ -1,4 +1,4 @@
|
|||||||
package tk.nulldori.eamemu;
|
package dev.nulldori.eamemu;
|
||||||
|
|
||||||
import com.facebook.react.ReactPackage;
|
import com.facebook.react.ReactPackage;
|
||||||
import com.facebook.react.bridge.NativeModule;
|
import com.facebook.react.bridge.NativeModule;
|
@ -1,4 +1,4 @@
|
|||||||
package tk.nulldori.eamemu
|
package dev.nulldori.eamemu
|
||||||
|
|
||||||
object E {
|
object E {
|
||||||
fun a(arg4: CharSequence): ByteArray {
|
fun a(arg4: CharSequence): ByteArray {
|
@ -1,4 +1,4 @@
|
|||||||
package tk.nulldori.eamemu;
|
package dev.nulldori.eamemu;
|
||||||
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
@ -50,9 +50,9 @@ public class HcefModule extends ReactContextBaseJavaModule implements LifecycleE
|
|||||||
isHceFSupport = true;
|
isHceFSupport = true;
|
||||||
|
|
||||||
nfcAdapter = NfcAdapter.getDefaultAdapter(getReactApplicationContext());
|
nfcAdapter = NfcAdapter.getDefaultAdapter(getReactApplicationContext());
|
||||||
if(nfcAdapter != null){
|
if(nfcAdapter != null && nfcAdapter.isEnabled()){
|
||||||
nfcFCardEmulation = NfcFCardEmulation.getInstance(nfcAdapter);
|
nfcFCardEmulation = NfcFCardEmulation.getInstance(nfcAdapter);
|
||||||
componentName = new ComponentName("tk.nulldori.eamemu","tk.nulldori.eamemu.eAMEMuService");
|
componentName = new ComponentName("dev.nulldori.eamemu","dev.nulldori.eamemu.eAMEMuService");
|
||||||
if(nfcFCardEmulation != null){
|
if(nfcFCardEmulation != null){
|
||||||
nfcFCardEmulation.registerSystemCodeForService(componentName, "4000");
|
nfcFCardEmulation.registerSystemCodeForService(componentName, "4000");
|
||||||
isHceFEnabled = true;
|
isHceFEnabled = true;
|
||||||
@ -74,52 +74,23 @@ public class HcefModule extends ReactContextBaseJavaModule implements LifecycleE
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
void setSID(String sid, Promise promise){
|
void enableService(String sid, Promise promise){
|
||||||
if(nfcFCardEmulation == null || componentName == null){
|
if(nfcFCardEmulation == null || componentName == null){
|
||||||
promise.reject("NULL_ERROR", "nfcFCardEmulation or componentName is null");
|
promise.reject("NULL_ERROR", "nfcFCardEmulation or componentName is null");
|
||||||
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
sid = sid.toUpperCase();
|
if (!nfcFCardEmulation.setNfcid2ForService(componentName, sid)) {
|
||||||
|
promise.reject("SET_NFCID2_FAIL", "setNfcid2ForService returned false");
|
||||||
if(sid.length() != 16)
|
return ;
|
||||||
promise.reject("LENGTH_ERROR", "The length of sid must be 16");
|
|
||||||
if(sid.matches("[0-9a-fA-F]+") == false)
|
|
||||||
promise.reject("HEX_ERROR", "SID must be 16-digit hex number");
|
|
||||||
if(sid.substring(0,4).contentEquals("02FE") == false)
|
|
||||||
promise.reject("PREFIX_ERROR", "SID must be start with 02FE");
|
|
||||||
|
|
||||||
boolean result = nfcFCardEmulation.setNfcid2ForService(componentName, sid);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
promise.resolve(true);
|
|
||||||
} else {
|
|
||||||
promise.reject("FAIL", "setNfcid2ForService returned false");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
if (!nfcFCardEmulation.enableService(getCurrentActivity(), componentName)) {
|
||||||
void enableService(Promise promise){
|
|
||||||
if(nfcFCardEmulation == null || componentName == null){
|
|
||||||
promise.reject("NULL_ERROR", "nfcFCardEmulation or componentName is null");
|
|
||||||
}
|
|
||||||
|
|
||||||
String cardId = nfcFCardEmulation.getNfcid2ForService(componentName);
|
|
||||||
|
|
||||||
if(cardId.length() != 16)
|
|
||||||
promise.reject("LENGTH_ERROR", "The length of sid must be 16");
|
|
||||||
if(cardId.matches("[0-9a-fA-F]+") == false)
|
|
||||||
promise.reject("HEX_ERROR", "SID must be 16-digit hex number");
|
|
||||||
if(cardId.substring(0,4).contentEquals("02FE") == false)
|
|
||||||
promise.reject("PREFIX_ERROR", "SID must be start with 02FE");
|
|
||||||
|
|
||||||
boolean result = nfcFCardEmulation.enableService(getCurrentActivity(), componentName);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
nowUsing = true;
|
|
||||||
promise.resolve(true);
|
|
||||||
} else {
|
|
||||||
promise.reject("FAIL", "enableService returned false");
|
promise.reject("FAIL", "enableService returned false");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nowUsing = true;
|
||||||
|
promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
@ -128,14 +99,12 @@ public class HcefModule extends ReactContextBaseJavaModule implements LifecycleE
|
|||||||
promise.reject("NULL_ERROR", "nfcFCardEmulation or componentName is null");
|
promise.reject("NULL_ERROR", "nfcFCardEmulation or componentName is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean result = nfcFCardEmulation.disableService(getCurrentActivity());
|
if (!nfcFCardEmulation.disableService(getCurrentActivity())) {
|
||||||
|
|
||||||
if (result) {
|
|
||||||
nowUsing = false;
|
|
||||||
promise.resolve(true);
|
|
||||||
} else {
|
|
||||||
promise.reject("FAIL", "disableService returned false");
|
promise.reject("FAIL", "disableService returned false");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nowUsing = false;
|
||||||
|
promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -1,4 +1,4 @@
|
|||||||
package tk.nulldori.eamemu;
|
package dev.nulldori.eamemu;
|
||||||
|
|
||||||
import com.facebook.react.ReactPackage;
|
import com.facebook.react.ReactPackage;
|
||||||
import com.facebook.react.bridge.NativeModule;
|
import com.facebook.react.bridge.NativeModule;
|
@ -1,4 +1,4 @@
|
|||||||
package tk.nulldori.eamemu;
|
package dev.nulldori.eamemu;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import com.facebook.react.ReactActivity;
|
import com.facebook.react.ReactActivity;
|
@ -1,4 +1,4 @@
|
|||||||
package tk.nulldori.eamemu;
|
package dev.nulldori.eamemu;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import com.facebook.react.PackageList;
|
import com.facebook.react.PackageList;
|
||||||
@ -8,7 +8,7 @@ import com.facebook.react.ReactPackage;
|
|||||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
|
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
|
||||||
import com.facebook.react.defaults.DefaultReactNativeHost;
|
import com.facebook.react.defaults.DefaultReactNativeHost;
|
||||||
import com.facebook.soloader.SoLoader;
|
import com.facebook.soloader.SoLoader;
|
||||||
import com.rnfs.RNFSPackage;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class MainApplication extends Application implements ReactApplication {
|
public class MainApplication extends Application implements ReactApplication {
|
@ -1,4 +1,4 @@
|
|||||||
package tk.nulldori.eamemu;
|
package dev.nulldori.eamemu;
|
||||||
|
|
||||||
import android.nfc.cardemulation.HostNfcFService;
|
import android.nfc.cardemulation.HostNfcFService;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
@ -4,7 +4,7 @@
|
|||||||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
||||||
* directory of this source tree.
|
* directory of this source tree.
|
||||||
*/
|
*/
|
||||||
package com.rndiffapp;
|
package dev.nulldori.eamemu;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import com.facebook.react.ReactInstanceManager;
|
import com.facebook.react.ReactInstanceManager;
|
||||||
/**
|
/**
|
@ -1,604 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import {
|
|
||||||
View,
|
|
||||||
Text,
|
|
||||||
StatusBar,
|
|
||||||
SafeAreaView,
|
|
||||||
ScrollView,
|
|
||||||
TouchableOpacity,
|
|
||||||
Dimensions,
|
|
||||||
ImageBackground,
|
|
||||||
findNodeHandle,
|
|
||||||
Alert,
|
|
||||||
StyleSheet,
|
|
||||||
Image,
|
|
||||||
KeyboardAvoidingView,
|
|
||||||
TextInput,
|
|
||||||
} from 'react-native';
|
|
||||||
import update from 'react-addons-update';
|
|
||||||
import Icon from 'react-native-vector-icons/MaterialIcons';
|
|
||||||
import ImagePicker from 'react-native-image-crop-picker';
|
|
||||||
import CardConv from '../modules/CardConv';
|
|
||||||
import i18n from 'i18n-js';
|
|
||||||
|
|
||||||
class CardPreview extends React.Component {
|
|
||||||
render() {
|
|
||||||
let cardContent = (
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: 'rgba(0,0,0,0.3)',
|
|
||||||
borderRadius: 8,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View style={{ flex: 1 }}>
|
|
||||||
<TouchableOpacity style={{ flex: 1 }}>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: 20,
|
|
||||||
left: 20,
|
|
||||||
fontSize: 17,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
color: '#ffffff',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.props.name}
|
|
||||||
</Text>
|
|
||||||
<View style={{ flex: 1, justifyContent: 'center', paddingTop: 20 }}>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
paddingTop: 0,
|
|
||||||
textAlign: 'center',
|
|
||||||
alignSelf: 'center',
|
|
||||||
color: '#E0E0E0',
|
|
||||||
fontSize: 14,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.props.uid
|
|
||||||
? this.props.uid.substr(0, 4) +
|
|
||||||
'-' +
|
|
||||||
this.props.uid.substr(4, 4) +
|
|
||||||
'-' +
|
|
||||||
this.props.uid.substr(8, 4) +
|
|
||||||
'-' +
|
|
||||||
this.props.uid.substr(12, 4)
|
|
||||||
: ''}
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
paddingTop: 8,
|
|
||||||
textAlign: 'center',
|
|
||||||
alignSelf: 'center',
|
|
||||||
fontSize: 24,
|
|
||||||
color: '#FAFAFA',
|
|
||||||
fontWeight: '500',
|
|
||||||
letterSpacing: -0.5,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n.t('card_touch_to_enable')}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
<View style={{ height: 1, backgroundColor: '#FAFAFA' }} />
|
|
||||||
<View style={{ height: 48, flexDirection: 'row' }}>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text style={{ fontSize: 14, color: '#FAFAFA' }}>
|
|
||||||
{i18n.t('card_edit')}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<View style={{ width: 1, backgroundColor: '#FAFAFA' }} />
|
|
||||||
<TouchableOpacity
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text style={{ fontSize: 14, color: '#ffffff' }}>
|
|
||||||
{i18n.t('card_delete')}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
{
|
|
||||||
borderRadius: 8,
|
|
||||||
height: this.props.cardHeight,
|
|
||||||
marginTop: 16,
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{this.props.image ? (
|
|
||||||
<ImageBackground
|
|
||||||
source={{ uri: this.props.image }}
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
resizeMode: 'contain',
|
|
||||||
}}
|
|
||||||
blurRadius={2}
|
|
||||||
borderRadius={8}
|
|
||||||
>
|
|
||||||
{cardContent}
|
|
||||||
</ImageBackground>
|
|
||||||
) : (
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
resizeMode: 'contain',
|
|
||||||
backgroundColor: '#03A9F4',
|
|
||||||
}}
|
|
||||||
blurRadius={2}
|
|
||||||
borderRadius={8}
|
|
||||||
>
|
|
||||||
{cardContent}
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ETextInput extends React.Component {
|
|
||||||
state = {
|
|
||||||
focused: false,
|
|
||||||
value: this.props.value ?? '',
|
|
||||||
};
|
|
||||||
|
|
||||||
onFocusCallback() {
|
|
||||||
this.setState({ focused: true });
|
|
||||||
if (typeof this.props.onFocus === 'function') {
|
|
||||||
this.props.onFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onBlurCallback() {
|
|
||||||
this.setState({ focused: false });
|
|
||||||
if (typeof this.props.onBlur === 'function') {
|
|
||||||
this.props.onBlur();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onChangeTextCallback(text) {
|
|
||||||
if (typeof this.props.filter === 'function') {
|
|
||||||
text = this.props.filter(text);
|
|
||||||
}
|
|
||||||
if (typeof this.props.onChangeText === 'function') {
|
|
||||||
this.props.onChangeText(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
focus() {
|
|
||||||
this.textInput.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<View style={this.props.style}>
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
{
|
|
||||||
fontSize: 14,
|
|
||||||
color: this.props.error
|
|
||||||
? '#F44336'
|
|
||||||
: this.state.focused
|
|
||||||
? '#03A9F4'
|
|
||||||
: '#9E9E9E',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
this.props.titleStyle,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{this.props.title}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<TextInput
|
|
||||||
style={[{ fontSize: 17, paddingTop: 4 }, this.props.textStyle]}
|
|
||||||
value={this.props.value}
|
|
||||||
onFocus={() => this.onFocusCallback()}
|
|
||||||
onBlur={() => this.onBlurCallback()}
|
|
||||||
onChangeText={text => this.onChangeTextCallback(text)}
|
|
||||||
editable={this.props.editable}
|
|
||||||
maxLength={this.props.maxLength}
|
|
||||||
autoCapitalize={this.props.autoCapitalize}
|
|
||||||
ref={ref => (this.textInput = ref)}
|
|
||||||
/>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
paddingTop: 2,
|
|
||||||
height: this.state.focused ? 2 : 1,
|
|
||||||
backgroundColor: this.props.error
|
|
||||||
? '#F44336'
|
|
||||||
: this.state.focused
|
|
||||||
? '#03A9F4'
|
|
||||||
: '#9E9E9E',
|
|
||||||
opacity: this.props.editable ? 1 : 0.5,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CardEditScreen extends React.Component {
|
|
||||||
state = {
|
|
||||||
name: this.props.navigation.getParam('name', ''),
|
|
||||||
sidAll: this.props.navigation.getParam('sid', '02FE'),
|
|
||||||
sid2: '',
|
|
||||||
sid3: '',
|
|
||||||
sid4: '',
|
|
||||||
uid: '',
|
|
||||||
sidError: false,
|
|
||||||
|
|
||||||
image: this.props.navigation.getParam('image', ''),
|
|
||||||
index: this.props.navigation.getParam('index', null), // null 이면 카드 새로 생성
|
|
||||||
mode: '',
|
|
||||||
|
|
||||||
update: this.props.navigation.getParam('update', null),
|
|
||||||
|
|
||||||
cardFocused: 'false',
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount(): void {
|
|
||||||
let { height, width } = Dimensions.get('window');
|
|
||||||
|
|
||||||
function randomHex4Byte() {
|
|
||||||
let hexString = Math.min(
|
|
||||||
Math.floor(Math.random() * 65536),
|
|
||||||
65535,
|
|
||||||
).toString(16);
|
|
||||||
|
|
||||||
if (hexString.length < 4) {
|
|
||||||
hexString = '0'.repeat(4 - hexString.length) + hexString;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hexString.toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.index === null) {
|
|
||||||
this.setState(
|
|
||||||
{
|
|
||||||
mode: 'add',
|
|
||||||
sid2: randomHex4Byte(),
|
|
||||||
sid3: randomHex4Byte(),
|
|
||||||
sid4: randomHex4Byte(),
|
|
||||||
cardHeight: ((width - 48) * 53.98) / 85.6,
|
|
||||||
},
|
|
||||||
() => this.updateSID(),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.setState(
|
|
||||||
{
|
|
||||||
mode: 'edit',
|
|
||||||
sid2: this.state.sidAll.substr(4, 4),
|
|
||||||
sid3: this.state.sidAll.substr(8, 4),
|
|
||||||
sid4: this.state.sidAll.substr(12, 4),
|
|
||||||
cardHeight: ((width - 48) * 53.98) / 85.6,
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
this.updateSID();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.nameInput.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
makeSid() {
|
|
||||||
let sid = '02FE' + this.state.sid2 + this.state.sid3 + this.state.sid4;
|
|
||||||
sid = sid.toUpperCase();
|
|
||||||
if (sid.length !== 16) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
if (sid.replace(/[^0-9A-F]/g, '') !== sid) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return sid;
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateSID() {
|
|
||||||
if (this.makeSid() !== '') {
|
|
||||||
let uid = await CardConv.convertSID(this.makeSid());
|
|
||||||
this.setState({ uid: uid });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
saveCard() {
|
|
||||||
let sid = this.makeSid();
|
|
||||||
|
|
||||||
if (sid === '') {
|
|
||||||
this.setState({ sidError: true });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof this.state.update === 'function') {
|
|
||||||
this.state.update(
|
|
||||||
this.state.name,
|
|
||||||
sid,
|
|
||||||
this.state.index,
|
|
||||||
this.state.image,
|
|
||||||
this.props.navigation,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setRandomSid() {
|
|
||||||
function randomHex4Byte() {
|
|
||||||
let hexString = Math.min(
|
|
||||||
Math.floor(Math.random() * 65536),
|
|
||||||
65535,
|
|
||||||
).toString(16);
|
|
||||||
|
|
||||||
if (hexString.length < 4) {
|
|
||||||
hexString = '0'.repeat(4 - hexString.length) + hexString;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hexString.toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState(
|
|
||||||
{
|
|
||||||
sid2: randomHex4Byte(),
|
|
||||||
sid3: randomHex4Byte(),
|
|
||||||
sid4: randomHex4Byte(),
|
|
||||||
},
|
|
||||||
() => this.updateSID(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
selectPhoto() {
|
|
||||||
ImagePicker.openPicker({
|
|
||||||
cropping: true,
|
|
||||||
width: 856,
|
|
||||||
height: 540,
|
|
||||||
mediaType: 'photo',
|
|
||||||
}).then(res => {
|
|
||||||
if (res && res.path) {
|
|
||||||
this.setState({ image: res.path });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<SafeAreaView style={{ flex: 1, paddingTop: StatusBar.currentHeight }}>
|
|
||||||
<StatusBar
|
|
||||||
barStyle="dark-content"
|
|
||||||
translucent={true}
|
|
||||||
backgroundColor={'#ffffff'}
|
|
||||||
/>
|
|
||||||
<KeyboardAvoidingView style={{ flex: 1 }}>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
height: 48,
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
backgroundColor: '#ffffff',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
fontSize: 17,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
textAlignVertical: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.state.mode === 'add'
|
|
||||||
? i18n.t('header_add')
|
|
||||||
: i18n.t('header_edit')}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<TouchableOpacity
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
bottom: 0,
|
|
||||||
right: 16,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
}}
|
|
||||||
onPress={() => this.saveCard()}
|
|
||||||
>
|
|
||||||
<Icon name="save" size={26} color={'rgba(0,0,0,0.7)'} />
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<ScrollView
|
|
||||||
style={{ flex: 1, paddingHorizontal: 24, paddingTop: 16 }}
|
|
||||||
>
|
|
||||||
<ETextInput
|
|
||||||
title={i18n.t('edit_name')}
|
|
||||||
value={this.state.name}
|
|
||||||
onChangeText={text => this.setState({ name: text })}
|
|
||||||
ref={ref => (this.nameInput = ref)}
|
|
||||||
/>
|
|
||||||
<TouchableOpacity onPress={() => this.selectPhoto()}>
|
|
||||||
<ETextInput
|
|
||||||
style={{ marginTop: 24 }}
|
|
||||||
title={i18n.t('edit_background')}
|
|
||||||
value={
|
|
||||||
this.state.image
|
|
||||||
? i18n.t('edit_background_selected')
|
|
||||||
: i18n.t('edit_background_empty')
|
|
||||||
}
|
|
||||||
editable={false}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
|
|
||||||
<View style={{ marginTop: 24, flexDirection: 'row' }}>
|
|
||||||
<ETextInput
|
|
||||||
title={'SID'}
|
|
||||||
value={'02FE'}
|
|
||||||
onChangeText={text => this.setState({ sid: text })}
|
|
||||||
style={{ flex: 1 }}
|
|
||||||
editable={false}
|
|
||||||
error={this.state.sidError}
|
|
||||||
textStyle={{ textAlign: 'center' }}
|
|
||||||
titleStyle={
|
|
||||||
this.state.sidError !== true &&
|
|
||||||
this.state.sidFocus && { color: '#03A9F4' }
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
width: 20,
|
|
||||||
marginTop: 24,
|
|
||||||
alignSelf: 'center',
|
|
||||||
textAlign: 'center',
|
|
||||||
color: '#9E9E9E',
|
|
||||||
fontSize: 14,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
-
|
|
||||||
</Text>
|
|
||||||
<ETextInput
|
|
||||||
textStyle={{ textAlign: 'center' }}
|
|
||||||
value={this.state.sid2}
|
|
||||||
onChangeText={text => {
|
|
||||||
this.setState({ sid2: text }, () => this.updateSID());
|
|
||||||
if (text.length === 4) {
|
|
||||||
this.sid3Input.focus();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{ flex: 1 }}
|
|
||||||
maxLength={4}
|
|
||||||
error={this.state.sidError}
|
|
||||||
onFocus={() => this.setState({ sidFocus: true })}
|
|
||||||
onBlur={() => this.setState({ sidFocus: false })}
|
|
||||||
autoCapitalize={'characters'}
|
|
||||||
ref={ref => (this.sid2Input = ref)}
|
|
||||||
editable={false}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
width: 20,
|
|
||||||
marginTop: 24,
|
|
||||||
alignSelf: 'center',
|
|
||||||
textAlign: 'center',
|
|
||||||
color: '#9E9E9E',
|
|
||||||
fontSize: 14,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
-
|
|
||||||
</Text>
|
|
||||||
<ETextInput
|
|
||||||
textStyle={{ textAlign: 'center' }}
|
|
||||||
value={this.state.sid3}
|
|
||||||
onChangeText={text => {
|
|
||||||
this.setState({ sid3: text }, () => this.updateSID());
|
|
||||||
if (text.length === 4) {
|
|
||||||
this.sid4Input.focus();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{ flex: 1 }}
|
|
||||||
maxLength={4}
|
|
||||||
error={this.state.sidError}
|
|
||||||
onFocus={() => this.setState({ sidFocus: true })}
|
|
||||||
onBlur={() => this.setState({ sidFocus: false })}
|
|
||||||
autoCapitalize={'characters'}
|
|
||||||
ref={ref => (this.sid3Input = ref)}
|
|
||||||
editable={false}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
width: 20,
|
|
||||||
marginTop: 24,
|
|
||||||
alignSelf: 'center',
|
|
||||||
textAlign: 'center',
|
|
||||||
color: '#9E9E9E',
|
|
||||||
fontSize: 14,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
-
|
|
||||||
</Text>
|
|
||||||
<ETextInput
|
|
||||||
textStyle={{ textAlign: 'center' }}
|
|
||||||
value={this.state.sid4}
|
|
||||||
onChangeText={text => {
|
|
||||||
this.setState({ sid4: text }, () => this.updateSID());
|
|
||||||
this.updateSID();
|
|
||||||
}}
|
|
||||||
style={{ flex: 1 }}
|
|
||||||
error={this.state.sidError}
|
|
||||||
maxLength={4}
|
|
||||||
onFocus={() => this.setState({ sidFocus: true })}
|
|
||||||
onBlur={() => this.setState({ sidFocus: false })}
|
|
||||||
autoCapitalize={'characters'}
|
|
||||||
ref={ref => (this.sid4Input = ref)}
|
|
||||||
editable={false}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
marginTop: 8,
|
|
||||||
fontSize: 14,
|
|
||||||
letterSpacing: -0.4,
|
|
||||||
color: this.state.sidError ? '#F44336' : '#9E9E9E',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n.t('edit_sid_notice')}
|
|
||||||
</Text>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={{
|
|
||||||
marginTop: 24,
|
|
||||||
height: 48,
|
|
||||||
backgroundColor: '#03A9F4',
|
|
||||||
borderRadius: 8,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
}}
|
|
||||||
onPress={() => this.setRandomSid()}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
style={{ fontSize: 17, color: '#ffffff', fontWeight: '500' }}
|
|
||||||
>
|
|
||||||
{i18n.t('edit_random')}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
fontSize: 14,
|
|
||||||
color: '#9E9E9E',
|
|
||||||
marginTop: 20,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n.t('edit_preview')}
|
|
||||||
</Text>
|
|
||||||
<CardPreview
|
|
||||||
name={this.state.name}
|
|
||||||
uid={this.state.uid}
|
|
||||||
image={this.state.image}
|
|
||||||
cardHeight={this.state.cardHeight ?? 0}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<View style={{ height: 50 }} />
|
|
||||||
</ScrollView>
|
|
||||||
</KeyboardAvoidingView>
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CardEditScreen;
|
|
289
src/screens/CardEditScreen.tsx
Normal file
289
src/screens/CardEditScreen.tsx
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
ScrollView,
|
||||||
|
TouchableOpacity,
|
||||||
|
StyleSheet,
|
||||||
|
KeyboardAvoidingView,
|
||||||
|
TextInput,
|
||||||
|
TextInputProps,
|
||||||
|
ViewStyle,
|
||||||
|
TextInputFocusEventData,
|
||||||
|
NativeSyntheticEvent,
|
||||||
|
TextStyle,
|
||||||
|
} from 'react-native';
|
||||||
|
import CardConv from '../modules/CardConv';
|
||||||
|
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||||
|
import { RootStackParams } from '../../App';
|
||||||
|
import { Shadow } from 'react-native-shadow-2';
|
||||||
|
import CardView from '../components/Card';
|
||||||
|
import { addCard, updateCard } from '../data/cards';
|
||||||
|
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||||
|
import { Card } from '../types';
|
||||||
|
|
||||||
|
type TextFieldProps = TextInputProps & {
|
||||||
|
title: string;
|
||||||
|
containerStyle?: ViewStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateRandomCardNumber = () => {
|
||||||
|
const getRandom4Byte = () => {
|
||||||
|
return Math.trunc(Math.random() * 65536)
|
||||||
|
.toString(16)
|
||||||
|
.toUpperCase()
|
||||||
|
.padStart(4, '0');
|
||||||
|
};
|
||||||
|
|
||||||
|
return `02FE${getRandom4Byte()}${getRandom4Byte()}${getRandom4Byte()}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const FieldTitle = (props: { title: string; style?: TextStyle }) => {
|
||||||
|
return (
|
||||||
|
<Text style={[styles.textInputTitle, props.style]}>{props.title}</Text>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TextField = (props: TextFieldProps) => {
|
||||||
|
const { onFocus, onBlur, title, containerStyle, ...textInputProps } = props;
|
||||||
|
|
||||||
|
const [isFocused, setIsFocused] = useState<boolean>(false);
|
||||||
|
const onFocusCallback = useCallback(
|
||||||
|
(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||||
|
setIsFocused(true);
|
||||||
|
onFocus?.(event);
|
||||||
|
},
|
||||||
|
[onFocus],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onBlurCallback = useCallback(
|
||||||
|
(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||||
|
setIsFocused(false);
|
||||||
|
onBlur?.(event);
|
||||||
|
},
|
||||||
|
[onBlur],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={containerStyle}>
|
||||||
|
<FieldTitle
|
||||||
|
title={title}
|
||||||
|
style={isFocused ? styles.textInputTitleFocused : {}}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
onFocus={onFocusCallback}
|
||||||
|
onBlur={onBlurCallback}
|
||||||
|
{...textInputProps}
|
||||||
|
/>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.textInputBottomBorder,
|
||||||
|
isFocused ? styles.textInputBottomBorderFocused : {},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
type CardAddScreenProps = NativeStackScreenProps<RootStackParams, 'Add'>;
|
||||||
|
type CardEditScreenProps = NativeStackScreenProps<RootStackParams, 'Edit'>;
|
||||||
|
|
||||||
|
const CardEditScreen = (props: CardAddScreenProps | CardEditScreenProps) => {
|
||||||
|
const initialData = props.route.params?.card ?? undefined;
|
||||||
|
|
||||||
|
const [mode] = useState<'add' | 'edit'>(() => {
|
||||||
|
return initialData ? 'edit' : 'add';
|
||||||
|
});
|
||||||
|
|
||||||
|
const [cardName, setCardName] = useState<string>(initialData?.name ?? 'eAM');
|
||||||
|
const [cardNumber, setCardNumber] = useState<string>(() => {
|
||||||
|
return initialData?.sid ?? generateRandomCardNumber();
|
||||||
|
});
|
||||||
|
const uid = useQuery(['uid', cardNumber], () =>
|
||||||
|
CardConv.convertSID(cardNumber),
|
||||||
|
);
|
||||||
|
|
||||||
|
const styledUid = useMemo(() => {
|
||||||
|
if (!uid.isSuccess) {
|
||||||
|
return '카드번호를 불러오는 중...';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
uid.data.match(/[A-Za-z0-9]{4}/g)?.join(' - ') ??
|
||||||
|
'잘못된 카드 번호입니다.'
|
||||||
|
);
|
||||||
|
}, [uid]);
|
||||||
|
|
||||||
|
const onChangeCardName = useCallback((s: string) => {
|
||||||
|
setCardName(s);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const changeCardNumber = useCallback(() => {
|
||||||
|
setCardNumber(generateRandomCardNumber());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const addMutation = useMutation(
|
||||||
|
(card: Card) => {
|
||||||
|
return addCard(card);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess: async () => {
|
||||||
|
await queryClient.invalidateQueries('cards');
|
||||||
|
props.navigation.goBack();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const editMutation = useMutation(
|
||||||
|
({ index, card }: { index: number; card: Card }) => {
|
||||||
|
return updateCard(index, card);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess: async () => {
|
||||||
|
await queryClient.invalidateQueries('cards');
|
||||||
|
props.navigation.goBack();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const save = useCallback(() => {
|
||||||
|
const card = {
|
||||||
|
sid: cardNumber,
|
||||||
|
name: cardName,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mode === 'add') {
|
||||||
|
addMutation.mutate(card);
|
||||||
|
} else {
|
||||||
|
editMutation.mutate({ index: props.route.params!.index, card: card });
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
addMutation,
|
||||||
|
cardName,
|
||||||
|
cardNumber,
|
||||||
|
editMutation,
|
||||||
|
mode,
|
||||||
|
props.route.params,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<KeyboardAvoidingView style={styles.screen}>
|
||||||
|
<ScrollView
|
||||||
|
contentContainerStyle={styles.scrollView}
|
||||||
|
keyboardShouldPersistTaps="handled"
|
||||||
|
>
|
||||||
|
<View style={styles.cardPreviewContainer}>
|
||||||
|
<CardView
|
||||||
|
card={{
|
||||||
|
sid: cardNumber,
|
||||||
|
name: cardName,
|
||||||
|
}}
|
||||||
|
mainText={'카드 미리보기'}
|
||||||
|
index={0 /* dummy index */}
|
||||||
|
disabledMainButton={true}
|
||||||
|
hideBottomMenu={true}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={[styles.fieldItemContainer, { paddingTop: 0 }]}>
|
||||||
|
<TextField
|
||||||
|
title={'카드 이름'}
|
||||||
|
value={cardName}
|
||||||
|
onChangeText={onChangeCardName}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.fieldItemContainer}>
|
||||||
|
<TextField title={'카드 번호'} value={styledUid} editable={false} />
|
||||||
|
<Shadow
|
||||||
|
style={styles.buttonShadowStyle}
|
||||||
|
containerStyle={styles.cardNumberChangeButton}
|
||||||
|
distance={4}
|
||||||
|
>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.button]}
|
||||||
|
onPress={changeCardNumber}
|
||||||
|
disabled={!uid.isSuccess}
|
||||||
|
>
|
||||||
|
<Text style={styles.buttonText}>카드 번호 변경</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Shadow>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Shadow
|
||||||
|
style={styles.buttonShadowStyle}
|
||||||
|
containerStyle={[
|
||||||
|
styles.cardNumberChangeButton,
|
||||||
|
styles.saveButtonContainerStyle,
|
||||||
|
]}
|
||||||
|
distance={4}
|
||||||
|
>
|
||||||
|
<TouchableOpacity style={[styles.button]} onPress={save}>
|
||||||
|
<Text style={styles.buttonText}>저장</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Shadow>
|
||||||
|
</ScrollView>
|
||||||
|
</KeyboardAvoidingView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
screen: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
scrollView: {
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
cardPreviewContainer: {
|
||||||
|
paddingBottom: 32,
|
||||||
|
},
|
||||||
|
fieldItemContainer: {
|
||||||
|
paddingTop: 24,
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
fontSize: 16,
|
||||||
|
paddingTop: 4,
|
||||||
|
},
|
||||||
|
textInputTitle: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#9e9e9e',
|
||||||
|
},
|
||||||
|
textInputTitleFocused: {
|
||||||
|
color: 'skyblue',
|
||||||
|
},
|
||||||
|
textInputBottomBorder: {
|
||||||
|
paddingTop: 2,
|
||||||
|
backgroundColor: '#9e9e9e',
|
||||||
|
height: 1,
|
||||||
|
},
|
||||||
|
textInputBottomBorderFocused: {
|
||||||
|
backgroundColor: 'skyblue',
|
||||||
|
height: 2,
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
height: 48,
|
||||||
|
borderRadius: 8,
|
||||||
|
backgroundColor: 'skyblue',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
buttonShadowStyle: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
saveButtonContainerStyle: {
|
||||||
|
marginTop: 32,
|
||||||
|
},
|
||||||
|
cardNumberChangeButton: {
|
||||||
|
marginTop: 16,
|
||||||
|
},
|
||||||
|
cardImageSelectButton: {
|
||||||
|
marginTop: 8,
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
color: 'white',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default CardEditScreen;
|
Loading…
x
Reference in New Issue
Block a user