moonyeju
2023-11-14
[FIX] api key 변경, color.js 로 관리 변경
@d7c9c2b565e8bd7819d19dedd57f5aa0b6555098
--- android/app/_BUCK
+++ android/app/_BUCK
... | ... | @@ -35,12 +35,12 @@ |
35 | 35 |
|
36 | 36 |
android_build_config( |
37 | 37 |
name = "build_config", |
38 |
- package = "com.aitron", |
|
38 |
+ package = "com.navi", |
|
39 | 39 |
) |
40 | 40 |
|
41 | 41 |
android_resource( |
42 | 42 |
name = "res", |
43 |
- package = "com.aitron", |
|
43 |
+ package = "com.navi", |
|
44 | 44 |
res = "src/main/res", |
45 | 45 |
) |
46 | 46 |
|
--- android/app/build.gradle
+++ android/app/build.gradle
... | ... | @@ -136,7 +136,7 @@ |
136 | 136 |
compileSdkVersion rootProject.ext.compileSdkVersion |
137 | 137 |
|
138 | 138 |
defaultConfig { |
139 |
- applicationId "com.aitron" |
|
139 |
+ applicationId "com.navi" |
|
140 | 140 |
minSdkVersion rootProject.ext.minSdkVersion |
141 | 141 |
targetSdkVersion rootProject.ext.targetSdkVersion |
142 | 142 |
versionCode 1 |
--- android/app/src/debug/java/com/trafficagent2/ReactNativeFlipper.java
+++ android/app/src/debug/java/com/trafficagent2/ReactNativeFlipper.java
... | ... | @@ -4,7 +4,7 @@ |
4 | 4 |
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root |
5 | 5 |
* directory of this source tree. |
6 | 6 |
*/ |
7 |
-package com.aitron; |
|
7 |
+package com.navi; |
|
8 | 8 |
|
9 | 9 |
import android.content.Context; |
10 | 10 |
import com.facebook.flipper.android.AndroidFlipperClient; |
--- android/app/src/main/AndroidManifest.xml
+++ android/app/src/main/AndroidManifest.xml
... | ... | @@ -1,5 +1,5 @@ |
1 | 1 |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
2 |
- package="com.aitron"> |
|
2 |
+ package="com.navi"> |
|
3 | 3 |
|
4 | 4 |
<uses-permission android:name="android.permission.INTERNET" /> |
5 | 5 |
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> |
... | ... | @@ -21,7 +21,7 @@ |
21 | 21 |
android:theme="@style/AppTheme"> |
22 | 22 |
<meta-data |
23 | 23 |
android:name="com.google.android.geo.API_KEY" |
24 |
- android:value="AIzaSyASJSJyYRgXN-z1_6aWMtpiaSvP8PdZ4DE"/> |
|
24 |
+ android:value="AIzaSyA8wcPd6wSOnA_kLVk7YxXbPmgkzoLVOEQ"/> |
|
25 | 25 |
|
26 | 26 |
<!-- You will also only need to add this uses-libray tag --> |
27 | 27 |
<uses-library android:name="org.apache.http.legacy" android:required="false"/> |
--- android/app/src/main/java/com/aitron/MainActivity.java
+++ android/app/src/main/java/com/aitron/MainActivity.java
... | ... | @@ -1,4 +1,4 @@ |
1 |
-package com.aitron; |
|
1 |
+package com.navi; |
|
2 | 2 |
|
3 | 3 |
import com.facebook.react.ReactActivity; |
4 | 4 |
import com.facebook.react.ReactActivityDelegate; |
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 |
*/ |
14 | 14 |
@Override |
15 | 15 |
protected String getMainComponentName() { |
16 |
- return "aitron"; |
|
16 |
+ return "navi"; |
|
17 | 17 |
} |
18 | 18 |
|
19 | 19 |
/** |
--- android/app/src/main/java/com/aitron/MainApplication.java
+++ android/app/src/main/java/com/aitron/MainApplication.java
... | ... | @@ -1,4 +1,4 @@ |
1 |
-package com.aitron; |
|
1 |
+package com.navi; |
|
2 | 2 |
|
3 | 3 |
|
4 | 4 |
|
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 |
import com.facebook.react.ReactPackage; |
12 | 12 |
import com.facebook.react.config.ReactFeatureFlags; |
13 | 13 |
import com.facebook.soloader.SoLoader; |
14 |
-import com.aitron.newarchitecture.MainApplicationReactNativeHost; |
|
14 |
+import com.navi.newarchitecture.MainApplicationReactNativeHost; |
|
15 | 15 |
import java.lang.reflect.InvocationTargetException; |
16 | 16 |
import java.util.List; |
17 | 17 |
import com.zaguiini.RNPureJwt.RNPureJwtPackage; |
... | ... | @@ -76,7 +76,7 @@ |
76 | 76 |
We use reflection here to pick up the class that initializes Flipper, |
77 | 77 |
since Flipper library is not available in release mode |
78 | 78 |
*/ |
79 |
- Class<?> aClass = Class.forName("com.aitron.ReactNativeFlipper"); |
|
79 |
+ Class<?> aClass = Class.forName("com.navi.ReactNativeFlipper"); |
|
80 | 80 |
aClass |
81 | 81 |
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) |
82 | 82 |
.invoke(null, context, reactInstanceManager); |
--- android/app/src/main/java/com/aitron/newarchitecture/MainApplicationReactNativeHost.java
+++ android/app/src/main/java/com/aitron/newarchitecture/MainApplicationReactNativeHost.java
... | ... | @@ -1,4 +1,4 @@ |
1 |
-package com.aitron.newarchitecture; |
|
1 |
+package com.navi.newarchitecture; |
|
2 | 2 |
|
3 | 3 |
import android.app.Application; |
4 | 4 |
import androidx.annotation.NonNull; |
... | ... | @@ -19,9 +19,9 @@ |
19 | 19 |
import com.facebook.react.fabric.FabricJSIModuleProvider; |
20 | 20 |
import com.facebook.react.fabric.ReactNativeConfig; |
21 | 21 |
import com.facebook.react.uimanager.ViewManagerRegistry; |
22 |
-import com.aitron.BuildConfig; |
|
23 |
-import com.aitron.newarchitecture.components.MainComponentsRegistry; |
|
24 |
-import com.aitron.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate; |
|
22 |
+import com.navi.BuildConfig; |
|
23 |
+import com.navi.newarchitecture.components.MainComponentsRegistry; |
|
24 |
+import com.navi.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate; |
|
25 | 25 |
import java.util.ArrayList; |
26 | 26 |
import java.util.List; |
27 | 27 |
|
--- android/app/src/main/java/com/aitron/newarchitecture/components/MainComponentsRegistry.java
+++ android/app/src/main/java/com/aitron/newarchitecture/components/MainComponentsRegistry.java
... | ... | @@ -1,4 +1,4 @@ |
1 |
-package com.aitron.newarchitecture.components; |
|
1 |
+package com.navi.newarchitecture.components; |
|
2 | 2 |
|
3 | 3 |
import com.facebook.jni.HybridData; |
4 | 4 |
import com.facebook.proguard.annotations.DoNotStrip; |
--- android/app/src/main/java/com/aitron/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java
+++ android/app/src/main/java/com/aitron/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java
... | ... | @@ -1,4 +1,4 @@ |
1 |
-package com.aitron.newarchitecture.modules; |
|
1 |
+package com.navi.newarchitecture.modules; |
|
2 | 2 |
|
3 | 3 |
import com.facebook.jni.HybridData; |
4 | 4 |
import com.facebook.react.ReactPackage; |
... | ... | @@ -41,7 +41,7 @@ |
41 | 41 |
if (!sIsSoLibraryLoaded) { |
42 | 42 |
// If you change the name of your application .so file in the Android.mk file, |
43 | 43 |
// make sure you update the name here as well. |
44 |
- SoLoader.loadLibrary("aitron_appmodules"); |
|
44 |
+ SoLoader.loadLibrary("navi_appmodules"); |
|
45 | 45 |
sIsSoLibraryLoaded = true; |
46 | 46 |
} |
47 | 47 |
} |
--- android/app/src/main/jni/CMakeLists.txt
+++ android/app/src/main/jni/CMakeLists.txt
... | ... | @@ -1,7 +1,7 @@ |
1 | 1 |
cmake_minimum_required(VERSION 3.13) |
2 | 2 |
|
3 | 3 |
# Define the library name here. |
4 |
-project(aitron_appmodules) |
|
4 |
+project(navi_appmodules) |
|
5 | 5 |
|
6 | 6 |
# This file includes all the necessary to let you build your application with the New Architecture. |
7 | 7 |
include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake) |
--- android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h
+++ android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 |
public: |
15 | 15 |
// Adapt it to the package you used for your Java class. |
16 | 16 |
static constexpr auto kJavaDescriptor = |
17 |
- "Lcom/aitron/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; |
|
17 |
+ "Lcom/navi/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; |
|
18 | 18 |
|
19 | 19 |
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>); |
20 | 20 |
|
--- android/app/src/main/jni/MainComponentsRegistry.h
+++ android/app/src/main/jni/MainComponentsRegistry.h
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 |
public: |
14 | 14 |
// Adapt it to the package you used for your Java class. |
15 | 15 |
constexpr static auto kJavaDescriptor = |
16 |
- "Lcom/aitron/newarchitecture/components/MainComponentsRegistry;"; |
|
16 |
+ "Lcom/navi/newarchitecture/components/MainComponentsRegistry;"; |
|
17 | 17 |
|
18 | 18 |
static void registerNatives(); |
19 | 19 |
|
--- android/app/src/main/res/values/strings.xml
+++ android/app/src/main/res/values/strings.xml
... | ... | @@ -1,3 +1,3 @@ |
1 | 1 |
<resources> |
2 |
- <string name="app_name">AITRON</string> |
|
2 |
+ <string name="app_name">navi</string> |
|
3 | 3 |
</resources> |
--- android/settings.gradle
+++ android/settings.gradle
... | ... | @@ -1,4 +1,4 @@ |
1 |
-rootProject.name = 'aitron' |
|
1 |
+rootProject.name = 'navi' |
|
2 | 2 |
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) |
3 | 3 |
include ':app' |
4 | 4 |
include ':react-native-pure-jwt' |
--- app.json
+++ app.json
... | ... | @@ -1,4 +1,4 @@ |
1 | 1 |
{ |
2 |
- "name": "aitron", |
|
3 |
- "displayName": "AITRON" |
|
2 |
+ "name": "navi", |
|
3 |
+ "displayName": "navi" |
|
4 | 4 |
}(파일 끝에 줄바꿈 문자 없음) |
--- package-lock.json
+++ package-lock.json
... | ... | @@ -1,11 +1,11 @@ |
1 | 1 |
{ |
2 |
- "name": "aitron", |
|
2 |
+ "name": "navi", |
|
3 | 3 |
"version": "0.0.1", |
4 | 4 |
"lockfileVersion": 2, |
5 | 5 |
"requires": true, |
6 | 6 |
"packages": { |
7 | 7 |
"": { |
8 |
- "name": "aitron", |
|
8 |
+ "name": "navi", |
|
9 | 9 |
"version": "0.0.1", |
10 | 10 |
"dependencies": { |
11 | 11 |
"@gorhom/bottom-sheet": "^4.4.5", |
... | ... | @@ -33,6 +33,7 @@ |
33 | 33 |
"react-native-leaflet-view": "^0.1.2", |
34 | 34 |
"react-native-linear-gradient": "^2.8.2", |
35 | 35 |
"react-native-maps": "^1.3.2", |
36 |
+ "react-native-modal": "^13.0.1", |
|
36 | 37 |
"react-native-openlayers": "^0.1.1-pre", |
37 | 38 |
"react-native-paper": "^4.12.5", |
38 | 39 |
"react-native-pure-jwt": "^3.0.1", |
... | ... | @@ -13558,6 +13559,14 @@ |
13558 | 13559 |
"react": "18.1.0" |
13559 | 13560 |
} |
13560 | 13561 |
}, |
13562 |
+ "node_modules/react-native-animatable": { |
|
13563 |
+ "version": "1.3.3", |
|
13564 |
+ "resolved": "https://registry.npmjs.org/react-native-animatable/-/react-native-animatable-1.3.3.tgz", |
|
13565 |
+ "integrity": "sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w==", |
|
13566 |
+ "dependencies": { |
|
13567 |
+ "prop-types": "^15.7.2" |
|
13568 |
+ } |
|
13569 |
+ }, |
|
13561 | 13570 |
"node_modules/react-native-camera": { |
13562 | 13571 |
"version": "4.2.1", |
13563 | 13572 |
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-4.2.1.tgz", |
... | ... | @@ -13751,6 +13760,19 @@ |
13751 | 13760 |
"react-native-web": { |
13752 | 13761 |
"optional": true |
13753 | 13762 |
} |
13763 |
+ } |
|
13764 |
+ }, |
|
13765 |
+ "node_modules/react-native-modal": { |
|
13766 |
+ "version": "13.0.1", |
|
13767 |
+ "resolved": "https://registry.npmjs.org/react-native-modal/-/react-native-modal-13.0.1.tgz", |
|
13768 |
+ "integrity": "sha512-UB+mjmUtf+miaG/sDhOikRfBOv0gJdBU2ZE1HtFWp6UixW9jCk/bhGdHUgmZljbPpp0RaO/6YiMmQSSK3kkMaw==", |
|
13769 |
+ "dependencies": { |
|
13770 |
+ "prop-types": "^15.6.2", |
|
13771 |
+ "react-native-animatable": "1.3.3" |
|
13772 |
+ }, |
|
13773 |
+ "peerDependencies": { |
|
13774 |
+ "react": "*", |
|
13775 |
+ "react-native": ">=0.65.0" |
|
13754 | 13776 |
} |
13755 | 13777 |
}, |
13756 | 13778 |
"node_modules/react-native-openlayers": { |
... | ... | @@ -28035,6 +28057,14 @@ |
28035 | 28057 |
} |
28036 | 28058 |
} |
28037 | 28059 |
}, |
28060 |
+ "react-native-animatable": { |
|
28061 |
+ "version": "1.3.3", |
|
28062 |
+ "resolved": "https://registry.npmjs.org/react-native-animatable/-/react-native-animatable-1.3.3.tgz", |
|
28063 |
+ "integrity": "sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w==", |
|
28064 |
+ "requires": { |
|
28065 |
+ "prop-types": "^15.7.2" |
|
28066 |
+ } |
|
28067 |
+ }, |
|
28038 | 28068 |
"react-native-camera": { |
28039 | 28069 |
"version": "4.2.1", |
28040 | 28070 |
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-4.2.1.tgz", |
... | ... | @@ -28173,6 +28203,15 @@ |
28173 | 28203 |
"@types/geojson": "^7946.0.8" |
28174 | 28204 |
} |
28175 | 28205 |
}, |
28206 |
+ "react-native-modal": { |
|
28207 |
+ "version": "13.0.1", |
|
28208 |
+ "resolved": "https://registry.npmjs.org/react-native-modal/-/react-native-modal-13.0.1.tgz", |
|
28209 |
+ "integrity": "sha512-UB+mjmUtf+miaG/sDhOikRfBOv0gJdBU2ZE1HtFWp6UixW9jCk/bhGdHUgmZljbPpp0RaO/6YiMmQSSK3kkMaw==", |
|
28210 |
+ "requires": { |
|
28211 |
+ "prop-types": "^15.6.2", |
|
28212 |
+ "react-native-animatable": "1.3.3" |
|
28213 |
+ } |
|
28214 |
+ }, |
|
28176 | 28215 |
"react-native-openlayers": { |
28177 | 28216 |
"version": "0.1.1-pre", |
28178 | 28217 |
"resolved": "https://registry.npmjs.org/react-native-openlayers/-/react-native-openlayers-0.1.1-pre.tgz", |
--- package.json
+++ package.json
... | ... | @@ -1,5 +1,5 @@ |
1 | 1 |
{ |
2 |
- "name": "aitron", |
|
2 |
+ "name": "navi", |
|
3 | 3 |
"version": "0.0.1", |
4 | 4 |
"private": true, |
5 | 5 |
"scripts": { |
... | ... | @@ -35,6 +35,7 @@ |
35 | 35 |
"react-native-leaflet-view": "^0.1.2", |
36 | 36 |
"react-native-linear-gradient": "^2.8.2", |
37 | 37 |
"react-native-maps": "^1.3.2", |
38 |
+ "react-native-modal": "^13.0.1", |
|
38 | 39 |
"react-native-openlayers": "^0.1.1-pre", |
39 | 40 |
"react-native-paper": "^4.12.5", |
40 | 41 |
"react-native-pure-jwt": "^3.0.1", |
+++ src/color.js
... | ... | @@ -0,0 +1,6 @@ |
1 | +export const GRAY = '#cccccc'; | |
2 | +export const LIGHTGRAY = '#dddddd'; | |
3 | +export const BLACK = '#000000'; | |
4 | +export const RED = '#ff0000'; | |
5 | +export const WHITE = '#ffffff'; | |
6 | +export const PRIMERY = '#16A695'; |
--- src/component/Action.js
+++ src/component/Action.js
... | ... | @@ -1,12 +1,19 @@ |
1 |
-import React, {useCallback, useRef} from 'react'; |
|
1 |
+import React, {useCallback, useRef, useState} from 'react'; |
|
2 | 2 |
import {useCameraDevices, Camera} from 'react-native-vision-camera'; |
3 | 3 |
import RNFS from 'react-native-fs'; |
4 | 4 |
import {url} from '../url'; |
5 |
+import ModalComponent from './ModalComponent'; |
|
5 | 6 |
|
6 | 7 |
export default function Action() { |
7 | 8 |
const devices = useCameraDevices(); |
8 | 9 |
const device = devices.back; |
9 | 10 |
const camera = useRef(null); |
11 |
+ const [isModalVisible, setModalVisible] = useState(false); |
|
12 |
+ |
|
13 |
+ const toggleModal = () => { |
|
14 |
+ setModalVisible(!isModalVisible); |
|
15 |
+ }; |
|
16 |
+ |
|
10 | 17 |
const requestCameraPermission = useCallback(async () => { |
11 | 18 |
const permission = await Camera.requestCameraPermission(); |
12 | 19 |
if (permission === 'denied') await Linking.openSettings(); |
... | ... | @@ -80,8 +87,7 @@ |
80 | 87 |
throw 'no data'; |
81 | 88 |
} |
82 | 89 |
onUploadFile(node); |
83 |
- Alert.alert('안개 발생 알람', '전방에 안개가 발생하였습니다.'); |
|
84 |
- |
|
90 |
+ toggleModal(); |
|
85 | 91 |
// 분석 결과 node remove 요청 |
86 | 92 |
return fetch(`${url}/trip/remove`, { |
87 | 93 |
method: 'POST', |
... | ... | @@ -116,5 +122,15 @@ |
116 | 122 |
|
117 | 123 |
if (device == null) return <Text>device == null</Text>; |
118 | 124 |
|
119 |
- return <Camera ref={camera} device={device} isActive={true} photo={true} />; |
|
125 |
+ return ( |
|
126 |
+ <View> |
|
127 |
+ <Camera ref={camera} device={device} isActive={true} photo={true} /> |
|
128 |
+ <ModalComponent |
|
129 |
+ isVisible={isModalVisible} |
|
130 |
+ toggleModal={toggleModal} |
|
131 |
+ alertTitle="안개 발생 알람" |
|
132 |
+ alertMessage="전방에 안개가 발생하였습니다." |
|
133 |
+ /> |
|
134 |
+ </View> |
|
135 |
+ ); |
|
120 | 136 |
} |
--- src/component/Checkbox.js
+++ src/component/Checkbox.js
... | ... | @@ -1,15 +1,16 @@ |
1 | 1 |
import React, {useState} from 'react'; |
2 | 2 |
import {View, StyleSheet, Text} from 'react-native'; |
3 | 3 |
import CheckBox from '@react-native-community/checkbox'; |
4 |
+import {BLACK, PRIMERY} from '../color'; |
|
4 | 5 |
|
5 |
-export default function Checkbox({ value, onValueChange, text }) { |
|
6 |
+export default function Checkbox({value, onValueChange, text}) { |
|
6 | 7 |
return ( |
7 | 8 |
<View style={styles.checkboxContainer}> |
8 | 9 |
<CheckBox |
9 | 10 |
disabled={false} |
10 | 11 |
value={value} |
11 | 12 |
onValueChange={onValueChange} |
12 |
- tintColors={{true: '#357af9'}} |
|
13 |
+ tintColors={{true: PRIMERY}} |
|
13 | 14 |
/> |
14 | 15 |
<Text numberOfLines={2} style={styles.checkText}> |
15 | 16 |
{text} |
... | ... | @@ -27,7 +28,7 @@ |
27 | 28 |
}, |
28 | 29 |
checkText: { |
29 | 30 |
fontSize: 13, |
30 |
- color:"#323232", |
|
31 |
- width: '95%' |
|
31 |
+ color: BLACK, |
|
32 |
+ width: '95%', |
|
32 | 33 |
}, |
33 | 34 |
}); |
--- src/component/CustomDrawer.js
+++ src/component/CustomDrawer.js
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 |
<View style={{flex: 1}}> |
12 | 12 |
<DrawerContentScrollView {...props}> |
13 | 13 |
<View style={styles.infoStyle}> |
14 |
- <Text style={styles.infoText}>AITRON 님</Text> |
|
14 |
+ <Text style={styles.infoText}>navi 님</Text> |
|
15 | 15 |
</View> |
16 | 16 |
<DrawerItemList {...props} /> |
17 | 17 |
</DrawerContentScrollView> |
--- src/component/DriveStatus.js
+++ src/component/DriveStatus.js
... | ... | @@ -1,8 +1,9 @@ |
1 | 1 |
import React from 'react'; |
2 | 2 |
import {View, StyleSheet, Text} from 'react-native'; |
3 | 3 |
import Icon from 'react-native-vector-icons/FontAwesome5'; |
4 |
+import {GRAY, WHITE} from '../color'; |
|
4 | 5 |
|
5 |
-export default function DriveStatus({distance,onPress}) { |
|
6 |
+export default function DriveStatus({distance, onPress}) { |
|
6 | 7 |
//남은 키로수 |
7 | 8 |
return ( |
8 | 9 |
<View style={styles.driveStatus}> |
... | ... | @@ -10,12 +11,7 @@ |
10 | 11 |
<Text style={styles.driveStatusText}>{distance}km</Text> |
11 | 12 |
</View> |
12 | 13 |
<View style={styles.driveStatusIcon}> |
13 |
- <Icon |
|
14 |
- name="ellipsis-v" |
|
15 |
- size={20} |
|
16 |
- color="#cccccc" |
|
17 |
- onPress={onPress} |
|
18 |
- /> |
|
14 |
+ <Icon name="ellipsis-v" size={20} color={GRAY} onPress={onPress} /> |
|
19 | 15 |
</View> |
20 | 16 |
</View> |
21 | 17 |
); |
... | ... | @@ -24,10 +20,10 @@ |
24 | 20 |
const styles = StyleSheet.create({ |
25 | 21 |
driveStatus: { |
26 | 22 |
paddingVertical: 20, |
27 |
- paddingHorizontal:16, |
|
28 |
- borderTopColor: '#cccccc', |
|
23 |
+ paddingHorizontal: 16, |
|
24 |
+ borderTopColor: GRAY, |
|
29 | 25 |
borderTopWidth: 2, |
30 |
- backgroundColor: '#ffffff', |
|
26 |
+ backgroundColor: WHITE, |
|
31 | 27 |
flexDirection: 'row', |
32 | 28 |
justifyContent: 'space-between', |
33 | 29 |
}, |
... | ... | @@ -36,7 +32,7 @@ |
36 | 32 |
fontWeight: 'bold', |
37 | 33 |
}, |
38 | 34 |
driveStatusTextBox: { |
39 |
- flex:30, |
|
35 |
+ flex: 30, |
|
40 | 36 |
}, |
41 | 37 |
driveStatusIcon: { |
42 | 38 |
flex: 1, |
--- src/component/Input.js
+++ src/component/Input.js
... | ... | @@ -1,22 +1,22 @@ |
1 | 1 |
import React from 'react'; |
2 | 2 |
import {StyleSheet, TextInput, View} from 'react-native'; |
3 |
- |
|
3 |
+import {BLACK, LIGHTGRAY, WHITE} from '../color'; |
|
4 | 4 |
|
5 | 5 |
export default function Input({ |
6 | 6 |
onChangeText, |
7 | 7 |
placeholder, |
8 | 8 |
secureTextEntry, |
9 | 9 |
visible, |
10 |
- title |
|
10 |
+ title, |
|
11 | 11 |
}) { |
12 | 12 |
return ( |
13 | 13 |
<View> |
14 | 14 |
<TextInput |
15 |
- title ={title} |
|
15 |
+ title={title} |
|
16 | 16 |
style={styles.input} |
17 | 17 |
onChangeText={onChangeText} |
18 | 18 |
placeholder={placeholder} |
19 |
- placeholderTextColor={'#dddddd'} |
|
19 |
+ placeholderTextColor={LIGHTGRAY} |
|
20 | 20 |
secureTextEntry={secureTextEntry} |
21 | 21 |
/> |
22 | 22 |
</View> |
... | ... | @@ -28,8 +28,8 @@ |
28 | 28 |
marginBottom: 10, |
29 | 29 |
padding: 10, |
30 | 30 |
borderWidth: 1, |
31 |
- borderColor: '#dddddd', |
|
32 |
- backgroundColor: '#ffffff', |
|
33 |
- color: '#323232' |
|
31 |
+ borderColor: LIGHTGRAY, |
|
32 |
+ backgroundColor: WHITE, |
|
33 |
+ color: BLACK, |
|
34 | 34 |
}, |
35 | 35 |
}); |
--- src/component/Logo.js
+++ src/component/Logo.js
... | ... | @@ -1,5 +1,6 @@ |
1 | 1 |
import React from 'react'; |
2 |
-import { View, Text, StyleSheet } from 'react-native'; |
|
2 |
+import {View, Text, StyleSheet} from 'react-native'; |
|
3 |
+import {BLACK, PRIMERY} from '../color'; |
|
3 | 4 |
|
4 | 5 |
export default function Logo() { |
5 | 6 |
return ( |
... | ... | @@ -15,12 +16,12 @@ |
15 | 16 |
const styles = StyleSheet.create({ |
16 | 17 |
logoText: { |
17 | 18 |
fontSize: 50, |
18 |
- color: '#333333', |
|
19 |
+ color: BLACK, |
|
19 | 20 |
fontWeight: 'bold', |
20 | 21 |
textAlign: 'center', |
21 | 22 |
marginBottom: 30, |
22 | 23 |
}, |
23 | 24 |
logoPoint: { |
24 |
- color: '#3872ef', |
|
25 |
+ color: PRIMERY, |
|
25 | 26 |
}, |
26 | 27 |
}); |
--- src/component/Map.js
+++ src/component/Map.js
... | ... | @@ -1,8 +1,10 @@ |
1 | 1 |
import React, {useEffect, useState} from 'react'; |
2 |
-import {View, StyleSheet} from 'react-native'; |
|
2 |
+import {View, StyleSheet, Keyboard} from 'react-native'; |
|
3 | 3 |
import MapView, {Marker, PROVIDER_GOOGLE} from 'react-native-maps'; |
4 | 4 |
import {url} from '../url'; |
5 | 5 |
import Button from './Button'; |
6 |
+import Search from './Search'; |
|
7 |
+import {BLACK, PRIMERY, RED, WHITE} from '../color'; |
|
6 | 8 |
|
7 | 9 |
export default function Map({ |
8 | 10 |
lat, |
... | ... | @@ -12,7 +14,8 @@ |
12 | 14 |
longDelta, |
13 | 15 |
children, |
14 | 16 |
}) { |
15 |
- const [potholeLocation, setPotholeLocation] = useState(); |
|
17 |
+ const [actionLocation, setActionLocation] = useState(); |
|
18 |
+ const [searchAction, setSearchAction] = useState(655); |
|
16 | 19 |
|
17 | 20 |
const sendPostRequest = async () => { |
18 | 21 |
try { |
... | ... | @@ -24,8 +27,8 @@ |
24 | 27 |
}); |
25 | 28 |
if (response.ok) { |
26 | 29 |
const data = await response.json(); |
27 |
- console.log('data ' + data); |
|
28 |
- setPotholeLocation( |
|
30 |
+ console.log('data', data); |
|
31 |
+ setActionLocation( |
|
29 | 32 |
data.report.map(item => { |
30 | 33 |
return { |
31 | 34 |
latitude: item[0], |
... | ... | @@ -40,11 +43,31 @@ |
40 | 43 |
console.error('An error occurred:', error); |
41 | 44 |
} |
42 | 45 |
}; |
43 |
- //화면이 처음 렌더링될 때 sendPostRequest 호출 |
|
46 |
+ |
|
44 | 47 |
useEffect(() => { |
45 |
- console.log('loc ' + lat + ' ' + long); |
|
46 |
- // sendPostRequest(); |
|
47 |
- }, []); // 두 번째 매개변수로 빈 배열을 전달하여 화면이 처음 렌더링될 때 한 번만 실행 |
|
48 |
+ console.log('searchAction changed:', searchAction); |
|
49 |
+ }, [searchAction]); |
|
50 |
+ |
|
51 |
+ useEffect(() => { |
|
52 |
+ const keyboardDidShowListener = Keyboard.addListener( |
|
53 |
+ 'keyboardDidShow', |
|
54 |
+ () => { |
|
55 |
+ setSearchAction(405); |
|
56 |
+ }, |
|
57 |
+ ); |
|
58 |
+ |
|
59 |
+ const keyboardDidHideListener = Keyboard.addListener( |
|
60 |
+ 'keyboardDidHide', |
|
61 |
+ () => { |
|
62 |
+ setSearchAction(655); |
|
63 |
+ }, |
|
64 |
+ ); |
|
65 |
+ |
|
66 |
+ return () => { |
|
67 |
+ keyboardDidShowListener.remove(); |
|
68 |
+ keyboardDidHideListener.remove(); |
|
69 |
+ }; |
|
70 |
+ }, []); |
|
48 | 71 |
|
49 | 72 |
return ( |
50 | 73 |
<View style={styles.mapStyle}> |
... | ... | @@ -59,36 +82,56 @@ |
59 | 82 |
}} |
60 | 83 |
showsUserLocation={showsUserLocation}> |
61 | 84 |
{children} |
62 |
- {potholeLocation && |
|
63 |
- potholeLocation.length > 0 && |
|
64 |
- potholeLocation.map((loc, index) => ( |
|
85 |
+ {actionLocation && |
|
86 |
+ actionLocation.length > 0 && |
|
87 |
+ actionLocation.map((loc, index) => ( |
|
65 | 88 |
<Marker |
66 | 89 |
key={index} // 각 Marker에 고유한 키를 할당 |
67 | 90 |
coordinate={loc} |
68 |
- pinColor={'#ff0000'} |
|
91 |
+ pinColor={RED} |
|
69 | 92 |
title="action Location" |
70 | 93 |
/> |
71 | 94 |
))} |
72 | 95 |
</MapView> |
73 | 96 |
<View style={styles.buttonstyle}> |
74 |
- <Button |
|
75 |
- title={'마커 표시'} |
|
76 |
- onPress={sendPostRequest} |
|
77 |
- color={'#ffffff'} |
|
78 |
- width={'100%'} |
|
79 |
- textAlign={'center'} |
|
80 |
- padding={10} |
|
81 |
- backgroundColor={'#357af9'} |
|
82 |
- /> |
|
97 |
+ <View style={[styles.searchContainer, {bottom: searchAction}]}> |
|
98 |
+ <Search placeholder={'도착지를 입력하세요'} /> |
|
99 |
+ </View> |
|
100 |
+ <View style={styles.markerButtonStyle}> |
|
101 |
+ <Button |
|
102 |
+ title={'마커 표시'} |
|
103 |
+ onPress={sendPostRequest} |
|
104 |
+ color={WHITE} |
|
105 |
+ width={180} |
|
106 |
+ textAlign={'center'} |
|
107 |
+ padding={10} |
|
108 |
+ backgroundColor={PRIMERY} |
|
109 |
+ /> |
|
110 |
+ </View> |
|
83 | 111 |
</View> |
84 | 112 |
</View> |
85 | 113 |
); |
86 | 114 |
} |
87 | 115 |
|
88 | 116 |
const styles = StyleSheet.create({ |
117 |
+ markerButtonStyle: { |
|
118 |
+ position: 'absolute', |
|
119 |
+ bottom: 7, |
|
120 |
+ left: -5, |
|
121 |
+ }, |
|
89 | 122 |
mapStyle: { |
90 | 123 |
flex: 1, |
91 | 124 |
}, |
125 |
+ searchContainer: { |
|
126 |
+ position: 'absolute', |
|
127 |
+ // bottom: 655, |
|
128 |
+ left: -15, |
|
129 |
+ flexDirection: 'row', |
|
130 |
+ width: '94%', |
|
131 |
+ justifyContent: 'space-between', |
|
132 |
+ alignItems: 'center', |
|
133 |
+ paddingHorizontal: 7, |
|
134 |
+ }, |
|
92 | 135 |
buttonstyle: { |
93 | 136 |
marginHorizontal: 15, |
94 | 137 |
}, |
+++ src/component/ModalComponent.js
... | ... | @@ -0,0 +1,49 @@ |
1 | +import React, {useEffect} from 'react'; | |
2 | +import {View, Text} from 'react-native'; | |
3 | +import Modal from 'react-native-modal'; | |
4 | +import {BLACK, RED} from '../color'; | |
5 | + | |
6 | +const ModalComponent = ({isVisible, toggleModal, alertTitle, alertMessage}) => { | |
7 | + useEffect(() => { | |
8 | + if (isVisible) { | |
9 | + const timeoutId = setTimeout(() => { | |
10 | + toggleModal(); | |
11 | + }, 2000); | |
12 | + | |
13 | + // 컴포넌트가 언마운트될 때 clearTimeout | |
14 | + return () => clearTimeout(timeoutId); | |
15 | + } | |
16 | + }, [isVisible, toggleModal]); | |
17 | + | |
18 | + return ( | |
19 | + <Modal | |
20 | + isVisible={isVisible} | |
21 | + style={{ | |
22 | + position: 'absolute', | |
23 | + bottom: 40, | |
24 | + left: 0, | |
25 | + width: '90%', | |
26 | + borderColor: RED, | |
27 | + borderWidth: 2, | |
28 | + borderRadius: 10, | |
29 | + overflow: 'hidden', | |
30 | + }} | |
31 | + backdropOpacity={0}> | |
32 | + <View | |
33 | + style={{ | |
34 | + backgroundColor: 'white', | |
35 | + padding: 22, | |
36 | + borderRadius: 10, | |
37 | + alignItems: 'center', | |
38 | + justifyContent: 'center', | |
39 | + }}> | |
40 | + <Text style={{color: RED, fontSize: 20}}>{alertTitle}</Text> | |
41 | + <Text style={{color: BLACK, fontSize: 15, marginTop: 5}}> | |
42 | + {alertMessage} 안전운행하세요. | |
43 | + </Text> | |
44 | + </View> | |
45 | + </Modal> | |
46 | + ); | |
47 | +}; | |
48 | + | |
49 | +export default ModalComponent; |
+++ src/component/Search.js
... | ... | @@ -0,0 +1,73 @@ |
1 | +import React, {useContext, useState} from 'react'; | |
2 | +import {View, StyleSheet, Alert, Dimensions, TextInput} from 'react-native'; | |
3 | +import {IconButton} from 'react-native-paper'; | |
4 | +import {useNavigation} from '@react-navigation/native'; | |
5 | +import {MapContext} from './../context/MapContext'; | |
6 | +import {GRAY, PRIMERY} from '../color'; | |
7 | + | |
8 | +const {width: windowWidth} = Dimensions.get('window'); | |
9 | + | |
10 | +export default function Search({placeholder, ref}) { | |
11 | + const navigation = useNavigation(); | |
12 | + const {setSearchQuery, onQuery} = useContext(MapContext); | |
13 | + const [inputText, setInputText] = useState(''); | |
14 | + | |
15 | + const onSubmitEditing = async () => { | |
16 | + console.log(inputText); | |
17 | + try { | |
18 | + const nodes = await onQuery(inputText); | |
19 | + if (nodes.length) { | |
20 | + navigation.navigate('DestinationList'); | |
21 | + } else { | |
22 | + throw Error(); | |
23 | + } | |
24 | + } catch (err) { | |
25 | + setSearchQuery(null); | |
26 | + Alert.alert('알림', '목적지를 정확히 입력해주세요.'); | |
27 | + navigation.navigate('Main'); | |
28 | + } | |
29 | + }; | |
30 | + | |
31 | + return ( | |
32 | + <View style={styles.inputContainer}> | |
33 | + <TextInput | |
34 | + style={styles.input} | |
35 | + placeholder={placeholder} | |
36 | + placeholderTextColor={GRAY} | |
37 | + ref={ref} | |
38 | + value={inputText} | |
39 | + onChangeText={text => setInputText(text)} | |
40 | + onSubmitEditing={onSubmitEditing} | |
41 | + /> | |
42 | + <IconButton | |
43 | + icon="magnify" | |
44 | + size={27} | |
45 | + color={PRIMERY} | |
46 | + onPress={onSubmitEditing} | |
47 | + /> | |
48 | + </View> | |
49 | + ); | |
50 | +} | |
51 | + | |
52 | +const styles = StyleSheet.create({ | |
53 | + inputContainer: { | |
54 | + // marginLeft: 8, | |
55 | + paddingLeft: 20, | |
56 | + paddingRight: 10, | |
57 | + flex: 1, | |
58 | + flexDirection: 'row', | |
59 | + alignItems: 'center', | |
60 | + width: windowWidth * 0.9, | |
61 | + borderWidth: 1.5, | |
62 | + borderRadius: 40, | |
63 | + borderColor: PRIMERY, | |
64 | + backgroundColor: 'white', | |
65 | + elevation: 10, | |
66 | + }, | |
67 | + input: { | |
68 | + marginVertical: 2, | |
69 | + marginHorizontal: 15, | |
70 | + borderRadius: 40, | |
71 | + flex: 1, | |
72 | + }, | |
73 | +}); |
+++ src/resoureces/files/images/login_logo.png
Binary file is not shown |
+++ src/resoureces/files/images/splash_screen.png
Binary file is not shown |
--- src/resoureces/styles/GlobalStyles.js
+++ src/resoureces/styles/GlobalStyles.js
... | ... | @@ -1,10 +1,12 @@ |
1 |
+import {BLACK, PRIMERY, WHITE} from '../../color'; |
|
2 |
+ |
|
1 | 3 |
export const container = { |
2 | 4 |
flex: 1, |
3 | 5 |
paddingHorizontal: 16, |
4 | 6 |
paddingVertical: 50, |
5 | 7 |
justifyContent: 'center', |
6 |
- backgroundColor: '#ffffff', |
|
7 |
- color: '#323232' |
|
8 |
+ backgroundColor: WHITE, |
|
9 |
+ color: BLACK, |
|
8 | 10 |
}; |
9 | 11 |
|
10 | 12 |
export const ItemFlex = { |
... | ... | @@ -17,27 +19,25 @@ |
17 | 19 |
export const direction = { |
18 | 20 |
flexDirection: 'row', |
19 | 21 |
justifyContent: 'space-between', |
20 |
- alignItems:"center" |
|
22 |
+ alignItems: 'center', |
|
21 | 23 |
}; |
22 | 24 |
|
23 | 25 |
export const pageTitleBox = { |
24 | 26 |
paddingVertical: 20, |
25 |
- // borderBottomWidth: 1, |
|
26 |
- // borderBottomColor: '#0028af', |
|
27 |
- backgroundColor: '#357af9', |
|
27 |
+ backgroundColor: PRIMERY, |
|
28 | 28 |
}; |
29 | 29 |
export const pageTitle = { |
30 | 30 |
fontSize: 18, |
31 | 31 |
fontWeight: 'bold', |
32 | 32 |
textAlign: 'center', |
33 |
- color:"#FFFFFF" |
|
33 |
+ color: WHITE, |
|
34 | 34 |
}; |
35 | 35 |
export const marginBottom = { |
36 |
- marginBottom:20 |
|
36 |
+ marginBottom: 20, |
|
37 | 37 |
}; |
38 | 38 |
|
39 | 39 |
export const textColor = { |
40 |
- color:"#333333" |
|
40 |
+ color: BLACK, |
|
41 | 41 |
}; |
42 | 42 |
|
43 | 43 |
export const padding = { |
+++ src/screens/DestinationList.js
... | ... | @@ -0,0 +1,65 @@ |
1 | +import React, {useContext} from 'react'; | |
2 | +import {View, Text, StyleSheet} from 'react-native'; | |
3 | +import Map from '../component/Map'; | |
4 | +import BottomDrop from './../component/BottomDrop'; | |
5 | +import Button from './../component/Button'; | |
6 | +import { | |
7 | + pageTitle, | |
8 | + directionAlign, | |
9 | + pageTitleBox, | |
10 | +} from './../resoureces/styles/GlobalStyles'; | |
11 | +import {MapContext} from './../context/MapContext'; | |
12 | +import {Polyline, Marker} from 'react-native-maps'; | |
13 | +import EndPointMarker from '../resoureces/files/images/end_point.png'; | |
14 | +import {PRIMERY} from '../color'; | |
15 | + | |
16 | +export default function DestinationList({navigation}) { | |
17 | + const {searchQuery, nodes} = useContext(MapContext); | |
18 | + console.log('List', nodes.length); | |
19 | + //node 중심 좌표 구하기 | |
20 | + const nodesCenterLength = Math.ceil(nodes.length / 2); | |
21 | + const nodesCenterPoint = nodes[nodesCenterLength]; | |
22 | + console.log('nodesCenterPoint', nodesCenterPoint); | |
23 | + | |
24 | + //node 마지막 좌표 구하기 | |
25 | + const nodesEndPoint = nodes.slice(-1); | |
26 | + const resultEndPoint = nodesEndPoint[0]; | |
27 | + | |
28 | + return ( | |
29 | + <View style={styles.container}> | |
30 | + <View style={pageTitleBox}> | |
31 | + <Text style={pageTitle}>{searchQuery}</Text> | |
32 | + </View> | |
33 | + <Map | |
34 | + lat={nodesCenterPoint.latitude} | |
35 | + long={nodesCenterPoint.longitude} | |
36 | + latDelta={0.3} | |
37 | + longDelta={0.3} | |
38 | + showsUserLocation={true}> | |
39 | + <Marker coordinate={resultEndPoint} image={EndPointMarker} /> | |
40 | + <Polyline coordinates={nodes} strokeWidth={10} strokeColor={PRIMERY} /> | |
41 | + </Map> | |
42 | + <BottomDrop> | |
43 | + <View style={directionAlign}> | |
44 | + <Text style={{flex: 9}}>{searchQuery}</Text> | |
45 | + <Button | |
46 | + title={'운행 시작'} | |
47 | + padding={10} | |
48 | + color={'white'} | |
49 | + backgroundColor={PRIMERY} | |
50 | + onPress={() => { | |
51 | + navigation.navigate('Driving'); | |
52 | + }} | |
53 | + /> | |
54 | + </View> | |
55 | + </BottomDrop> | |
56 | + </View> | |
57 | + ); | |
58 | +} | |
59 | + | |
60 | +const styles = StyleSheet.create({ | |
61 | + container: { | |
62 | + flex: 1, | |
63 | + backgroundColor: 'white', | |
64 | + }, | |
65 | +}); |
+++ src/screens/Driving.js
... | ... | @@ -0,0 +1,103 @@ |
1 | +import React, {useRef, useCallback, useMemo, useContext} from 'react'; | |
2 | +import {View, StyleSheet, Text} from 'react-native'; | |
3 | +import {Polyline, Marker} from 'react-native-maps'; | |
4 | +import {BottomSheetModal, BottomSheetModalProvider} from '@gorhom/bottom-sheet'; | |
5 | +import {MapContext} from '../context/MapContext'; | |
6 | +import Map from '../component/Map'; | |
7 | +import DriveStatus from './../component/DriveStatus'; | |
8 | +import Button from '../component/Button'; | |
9 | +import CurrentMarker from '../resoureces/files/images/current_location.png'; | |
10 | +import {pageTitle, marginBottom} from '../resoureces/styles/GlobalStyles'; | |
11 | +import Camera from '../component/Photo'; | |
12 | +import {PRIMERY, WHITE} from '../color'; | |
13 | + | |
14 | +export default function Driving({navigation}) { | |
15 | + const {nodes, location, km, setSearchQuery, setNodes} = | |
16 | + useContext(MapContext); | |
17 | + //node 마지막 좌표 구하기 | |
18 | + const nodesEndPoint = nodes.slice(-1); | |
19 | + const resultEndPoint = nodesEndPoint[0]; | |
20 | + | |
21 | + //바텀시트 | |
22 | + const bottomSheetModalRef = useRef(null); | |
23 | + const snapPoints = useMemo(() => ['25%'], []); | |
24 | + // callbacks | |
25 | + const handleSheetChanges = useCallback(index => { | |
26 | + console.log('handleSheetChanges', index); | |
27 | + }, []); | |
28 | + const handlePresentModalPress = useCallback(() => { | |
29 | + bottomSheetModalRef.current?.present(); | |
30 | + }, []); | |
31 | + const handleClosePress = useCallback(() => { | |
32 | + setSearchQuery(null); | |
33 | + setNodes([]); | |
34 | + bottomSheetModalRef.current?.close(); | |
35 | + navigation.navigate('Main'); | |
36 | + }, []); | |
37 | + | |
38 | + return ( | |
39 | + <BottomSheetModalProvider> | |
40 | + <View style={styles.container}> | |
41 | + <Map | |
42 | + lat={location.latitude} | |
43 | + long={location.longitude} | |
44 | + latDelta={0.001} | |
45 | + longDelta={0.001} | |
46 | + followsUserLocation={true}> | |
47 | + <Marker | |
48 | + coordinate={location} | |
49 | + width={50} | |
50 | + height={50} | |
51 | + image={CurrentMarker} | |
52 | + /> | |
53 | + <Marker coordinate={resultEndPoint} /> | |
54 | + <Polyline | |
55 | + coordinates={nodes} | |
56 | + strokeWidth={10} | |
57 | + strokeColor={PRIMERY} | |
58 | + /> | |
59 | + </Map> | |
60 | + <Camera /> | |
61 | + <DriveStatus distance={km} onPress={handlePresentModalPress} /> | |
62 | + <BottomSheetModal | |
63 | + ref={bottomSheetModalRef} | |
64 | + index={0} | |
65 | + snapPoints={snapPoints} | |
66 | + onChange={handleSheetChanges}> | |
67 | + <View style={styles.contentContainer}> | |
68 | + <Text style={[pageTitle, marginBottom]}> | |
69 | + 운행을 종료 하시겠습니까? | |
70 | + </Text> | |
71 | + <Button | |
72 | + title={'운행종료'} | |
73 | + padding={10} | |
74 | + backgroundColor={PRIMERY} | |
75 | + color={WHITE} | |
76 | + width={'100%'} | |
77 | + textAlign={'center'} | |
78 | + onPress={handleClosePress} | |
79 | + /> | |
80 | + </View> | |
81 | + </BottomSheetModal> | |
82 | + </View> | |
83 | + </BottomSheetModalProvider> | |
84 | + ); | |
85 | +} | |
86 | + | |
87 | +const styles = StyleSheet.create({ | |
88 | + container: { | |
89 | + flex: 1, | |
90 | + justifyContent: 'center', | |
91 | + backgroundColor: 'grey', | |
92 | + }, | |
93 | + contentContainer: { | |
94 | + flex: 1, | |
95 | + alignItems: 'center', | |
96 | + padding: 16, | |
97 | + }, | |
98 | + image: { | |
99 | + width: '100%', | |
100 | + height: '100%', | |
101 | + flex: 1, | |
102 | + }, | |
103 | +}); |
--- src/screens/Login.js
+++ src/screens/Login.js
... | ... | @@ -9,6 +9,7 @@ |
9 | 9 |
} from './../resoureces/styles/GlobalStyles'; |
10 | 10 |
import {AuthContext} from './../context/AuthContext'; |
11 | 11 |
import LinearGradient from 'react-native-linear-gradient'; |
12 |
+import {BLACK, PRIMERY, WHITE} from '../color'; |
|
12 | 13 |
|
13 | 14 |
export default function Login({navigation}) { |
14 | 15 |
const {onClickLogin} = useContext(AuthContext); |
... | ... | @@ -17,14 +18,10 @@ |
17 | 18 |
|
18 | 19 |
return ( |
19 | 20 |
<View style={{flex: 1}}> |
20 |
- {/* <View style={pageTitleBox}> |
|
21 |
- <Text style={pageTitle}>로그인</Text> |
|
22 |
- </View> */} |
|
23 | 21 |
<View style={container}> |
24 |
- {/* <ScrollView> */} |
|
25 | 22 |
<View style={styles.loginLogo}> |
26 | 23 |
<Image |
27 |
- source={require('../resoureces/files/images/login_logo_2.png')} |
|
24 |
+ source={require('../resoureces/files/images/login_logo.png')} |
|
28 | 25 |
style={styles.image1} |
29 | 26 |
/> |
30 | 27 |
</View> |
... | ... | @@ -46,46 +43,16 @@ |
46 | 43 |
<View style={styles.buttonContainer}> |
47 | 44 |
<Button |
48 | 45 |
title={'로그인'} |
49 |
- backgroundColor={'#357af9'} |
|
46 |
+ backgroundColor={PRIMERY} |
|
50 | 47 |
padding={10} |
51 | 48 |
marginBottom={10} |
52 |
- color={'#ffffff'} |
|
49 |
+ color={WHITE} |
|
53 | 50 |
textAlign={'center'} |
54 | 51 |
onPress={() => { |
55 | 52 |
onClickLogin(inputId, inputPw); |
56 | 53 |
}} |
57 | 54 |
/> |
58 |
- {/* <Button |
|
59 |
- title={'회원가입'} |
|
60 |
- backgroundColor={'#0028af'} |
|
61 |
- padding={10} |
|
62 |
- marginBottom={10} |
|
63 |
- color={'#ffffff'} |
|
64 |
- textAlign={'center'} |
|
65 |
- onPress={() => { |
|
66 |
- navigation.navigate('Agreement'); |
|
67 |
- }} |
|
68 |
- /> */} |
|
69 | 55 |
</View> |
70 |
- {/* <View style={styles.buttonContainer}> |
|
71 |
- <Button |
|
72 |
- title={'아이디찾기'} |
|
73 |
- onPress={() => { |
|
74 |
- navigation.navigate('FindID'); |
|
75 |
- }} |
|
76 |
- color={'#323232'} |
|
77 |
- padding={10} |
|
78 |
- /> |
|
79 |
- <Button |
|
80 |
- title={'비밀번호찾기'} |
|
81 |
- onPress={() => { |
|
82 |
- navigation.navigate('FindPassword'); |
|
83 |
- }} |
|
84 |
- color={'#323232'} |
|
85 |
- padding={10} |
|
86 |
- /> |
|
87 |
- </View> */} |
|
88 |
- {/* </ScrollView> */} |
|
89 | 56 |
</View> |
90 | 57 |
</View> |
91 | 58 |
); |
... | ... | @@ -101,7 +68,7 @@ |
101 | 68 |
flex: 1, |
102 | 69 |
}, |
103 | 70 |
image1: { |
104 |
- width: '70%', |
|
71 |
+ width: '110%', |
|
105 | 72 |
resizeMode: 'contain', |
106 | 73 |
}, |
107 | 74 |
}); |
--- src/screens/Main.js
+++ src/screens/Main.js
... | ... | @@ -12,6 +12,8 @@ |
12 | 12 |
import {useCameraDevices, Camera} from 'react-native-vision-camera'; |
13 | 13 |
import RNFS from 'react-native-fs'; |
14 | 14 |
import {url} from '../url'; |
15 |
+import {PRIMERY, RED, WHITE} from '../color'; |
|
16 |
+import ModalComponent from '../component/ModalComponent'; |
|
15 | 17 |
|
16 | 18 |
export default function Main({navigation}) { |
17 | 19 |
const {onQuery, searchQuery, location, nodes} = useContext(MapContext); |
... | ... | @@ -24,6 +26,11 @@ |
24 | 26 |
const device = devices.back; |
25 | 27 |
const camera = useRef(null); |
26 | 28 |
let timerId; |
29 |
+ const [isModalVisible, setModalVisible] = useState(false); |
|
30 |
+ |
|
31 |
+ const toggleModal = () => { |
|
32 |
+ setModalVisible(!isModalVisible); |
|
33 |
+ }; |
|
27 | 34 |
|
28 | 35 |
const requestCameraPermission = useCallback(async () => { |
29 | 36 |
const permission = await Camera.requestCameraPermission(); |
... | ... | @@ -142,10 +149,7 @@ |
142 | 149 |
if (node === null || rain !== 'rain') { |
143 | 150 |
throw new Error('No data or not fog'); |
144 | 151 |
} |
145 |
- Alert.alert( |
|
146 |
- '폭우 발생 알람', |
|
147 |
- '전방에 폭우가 발생하였습니다. 감속하십시오', |
|
148 |
- ); |
|
152 |
+ toggleModal(); |
|
149 | 153 |
}) |
150 | 154 |
.catch(error => { |
151 | 155 |
console.error('Error during file upload or image analysis:', error); |
... | ... | @@ -167,12 +171,13 @@ |
167 | 171 |
<View style={styles.container}> |
168 | 172 |
<Button |
169 | 173 |
title={isDrivingStarted ? '운행 종료' : '운행 시작'} |
170 |
- onPress={handleStartDriving} |
|
171 |
- color={'#ffffff'} |
|
172 |
- width={'100%'} |
|
174 |
+ // onPress={handleStartDriving} |
|
175 |
+ onPress={toggleModal} |
|
176 |
+ color={WHITE} |
|
177 |
+ width={180} |
|
173 | 178 |
textAlign={'center'} |
174 | 179 |
padding={10} |
175 |
- backgroundColor={isDrivingStarted ? '#0028af' : '#357af9'} |
|
180 |
+ backgroundColor={isDrivingStarted ? RED : PRIMERY} |
|
176 | 181 |
/> |
177 | 182 |
{devicesLoaded && shouldLog && ( |
178 | 183 |
<Camera ref={camera} device={device} isActive={true} photo={true} /> |
... | ... | @@ -191,15 +196,24 @@ |
191 | 196 |
</View> |
192 | 197 |
)} |
193 | 198 |
</View> |
199 |
+ <ModalComponent |
|
200 |
+ isVisible={isModalVisible} |
|
201 |
+ toggleModal={toggleModal} |
|
202 |
+ alertTitle="폭우 발생 알람" |
|
203 |
+ alertMessage="폭우가 발생하였습니다." |
|
204 |
+ /> |
|
194 | 205 |
</View> |
195 | 206 |
); |
196 | 207 |
} |
197 | 208 |
|
198 | 209 |
const styles = StyleSheet.create({ |
199 | 210 |
container: { |
200 |
- margin: 16, |
|
211 |
+ marginLeft: 16, |
|
201 | 212 |
justifyContent: 'center', |
202 | 213 |
alignItems: 'center', |
214 |
+ position: 'absolute', |
|
215 |
+ bottom: 7, |
|
216 |
+ right: 10, |
|
203 | 217 |
}, |
204 | 218 |
infoContainer: { |
205 | 219 |
marginTop: 16, |
--- src/screens/StartLoading.js
+++ src/screens/StartLoading.js
... | ... | @@ -1,6 +1,7 @@ |
1 | 1 |
import React from 'react'; |
2 | 2 |
import {StyleSheet, Image, View, Text} from 'react-native'; |
3 | 3 |
import {container} from './../resoureces/styles/GlobalStyles'; |
4 |
+import {BLACK, PRIMERY} from '../color'; |
|
4 | 5 |
|
5 | 6 |
export default function StartLoading() { |
6 | 7 |
return ( |
... | ... | @@ -11,7 +12,7 @@ |
11 | 12 |
<View style={styles.container}> |
12 | 13 |
<View style={styles.splashLogo}> |
13 | 14 |
<Image |
14 |
- source={require('../resoureces/files/images/splash_logo_2.png')} |
|
15 |
+ source={require('../resoureces/files/images/splash_screen.png')} |
|
15 | 16 |
style={styles.image1} |
16 | 17 |
/> |
17 | 18 |
</View> |
... | ... | @@ -25,8 +26,8 @@ |
25 | 26 |
paddingHorizontal: 16, |
26 | 27 |
paddingVertical: 50, |
27 | 28 |
justifyContent: 'center', |
28 |
- backgroundColor: '#357af9', |
|
29 |
- color: '#323232', |
|
29 |
+ backgroundColor: PRIMERY, |
|
30 |
+ color: BLACK, |
|
30 | 31 |
}, |
31 | 32 |
splashLogo: { |
32 | 33 |
flex: 3, |
... | ... | @@ -39,7 +40,7 @@ |
39 | 40 |
alignItems: 'center', |
40 | 41 |
}, |
41 | 42 |
image1: { |
42 |
- width: '100%', |
|
43 |
+ width: '120%', |
|
43 | 44 |
resizeMode: 'contain', |
44 | 45 |
}, |
45 | 46 |
image2: { |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?