React Native Expoで位置情報アプリを作る Part 4
2021-05-17
Building a geolocation app with React Native Expo. Part 4
前回の続きです。リリースした新作アプリFind Good Oneの仕組みやコードを書きます。
ログインとサインアップ機能の実装
ログイン画面
Firebaseの基本通りの実装です。
src\scenes\login\Login.js
import React, { useState } from 'react'
import { Text, View, StatusBar, Image, TextInput, TouchableOpacity, Platform } from 'react-native'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
import styles from './styles'
import { firebase } from '../../../firebase'
import Spinner from 'react-native-loading-spinner-overlay'
import { ConfirmDialog } from 'react-native-simple-dialogs'
export default function Login({navigation}) {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [spinner, setSpinner] = useState(false)
const [dialog, setDialog] = useState(true)
const onFooterLinkPress = () => {
navigation.navigate('Registration')
}
const onLoginPress = () => {
setSpinner(true)
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then((response) => {
const uid = response.user.uid
const usersRef = firebase.firestore().collection('users')
usersRef
.doc(uid)
.get()
.then(firestoreDocument => {
if (!firestoreDocument.exists) {
setSpinner(false)
alert("User does not exist anymore.")
return;
}
})
.catch(error => {
setSpinner(false)
alert(error)
});
})
.catch(error => {
setSpinner(false)
alert(error)
})
}
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
{Platform.OS != 'ios'?
<ConfirmDialog
visible={dialog}
title="Find Good Oneは位置情報を使用します"
positiveButton={{
title: 'OK',
onPress: () => setDialog(false)
}}
>
<View>
<Text>このアプリは、アプリが閉じているか使用されていない場合でも、宝箱を探す機能、宝箱を設置する機能を有効にするために位置情報を収集します</Text>
</View>
</ConfirmDialog>:null
}
<KeyboardAwareScrollView
style={{ flex: 1, width: '100%' }}
keyboardShouldPersistTaps="always">
<Image
style={styles.logo}
source={require('../../../assets/images/logo-lg.png')}
/>
<TextInput
style={styles.input}
placeholder='E-mail'
placeholderTextColor="#aaaaaa"
onChangeText={(text) => setEmail(text)}
value={email}
underlineColorAndroid="transparent"
autoCapitalize="none"
/>
<TextInput
style={styles.input}
placeholderTextColor="#aaaaaa"
secureTextEntry
placeholder='Password'
onChangeText={(text) => setPassword(text)}
value={password}
underlineColorAndroid="transparent"
autoCapitalize="none"
/>
<TouchableOpacity
style={styles.button}
onPress={() => onLoginPress()}>
<Text style={styles.buttonTitle}>Log in</Text>
</TouchableOpacity>
<View style={styles.footerView}>
<Text style={styles.footerText}>Don't have an account? <Text onPress={onFooterLinkPress} style={styles.footerLink}>Sign up</Text></Text>
</View>
</KeyboardAwareScrollView>
<Spinner
visible={spinner}
textStyle={{ color: "#fff" }}
overlayColor="rgba(0,0,0,0.5)"
/>
</View>
)
}
Google Playの審査を通すために実装した位置情報取得のためのポップアップ部分です。
const [dialog, setDialog] = useState(true) // ポップアップの表示非表示制御用のフックを定義。起動時に表示するので初期値はtrue
{Platform.OS != 'ios'? // プラットフォームを判定、iOSじゃないとき(Androidのとき)だけ表示する
<ConfirmDialog
visible={dialog}
title="Find Good Oneは位置情報を使用します"
positiveButton={{
title: 'OK',
onPress: () => setDialog(false) // OKを押したらfalseをセットしてポップアップを閉じる
}}
>
<View>
<Text>このアプリは、アプリが閉じているか使用されていない場合でも、宝箱を探す機能、宝箱を設置する機能を有効にするために位置情報を収集します</Text>
</View>
</ConfirmDialog>:null // 条件に一致しないとき(iOSのとき)は表示する必要ないのでnull
}
ログイン時にローディングスピナーを表示します。
const [spinner, setSpinner] = useState(false)
<Spinner
visible={spinner}
textStyle={{ color: "#fff" }}
overlayColor="rgba(0,0,0,0.5)"
/>
サインアップ画面
サインアップ画面です。メールアドレスでログインします。メールアドレスの存在確認はしていません。存在しないメールアドレスでも登録できます。
src\scenes\registration\Registration.js
import React, { useState } from 'react'
import { Image, Text, TextInput, TouchableOpacity, View, Linking, StatusBar } from 'react-native'
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
import styles from './styles';
import { firebase } from '../../../firebase'
import Spinner from 'react-native-loading-spinner-overlay'
export default function Registration({navigation}) {
const [fullName, setFullName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [spinner, setSpinner] = useState(false)
const onFooterLinkPress = () => {
navigation.navigate('Login')
}
const onRegisterPress = () => {
if (password !== confirmPassword) {
alert("Passwords don't match.")
return
}
setSpinner(true)
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((response) => {
const uid = response.user.uid
const data = {
id: uid,
email,
fullName,
avatar: 'https://firebasestorage.googleapis.com/v0/b/maptrap.appspot.com/o/logo.jpg?alt=media&token=761783a0-6e90-4b9f-a46d-c753523e9f25',
};
const usersRef = firebase.firestore().collection('users')
const usersRef2 = firebase.firestore().collection('users2')
usersRef2
.doc(email)
.set(data)
usersRef
.doc(uid)
.set(data)
.then(() => {
navigation.navigate('Home', {user: data})
})
.catch((error) => {
setSpinner(false)
alert(error)
});
})
.catch((error) => {
setSpinner(false)
alert(error)
});
}
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
<KeyboardAwareScrollView
style={{ flex: 1, width: '100%' }}
keyboardShouldPersistTaps="always">
<Image
style={styles.logo}
source={require('../../../assets/images/logo-lg.png')}
/>
<TextInput
style={styles.input}
placeholder='Your Name'
placeholderTextColor="#aaaaaa"
onChangeText={(text) => setFullName(text)}
value={fullName}
underlineColorAndroid="transparent"
autoCapitalize="none"
/>
<TextInput
style={styles.input}
placeholder='E-mail'
placeholderTextColor="#aaaaaa"
onChangeText={(text) => setEmail(text)}
value={email}
underlineColorAndroid="transparent"
autoCapitalize="none"
/>
<TextInput
style={styles.input}
placeholderTextColor="#aaaaaa"
secureTextEntry
placeholder='Password'
onChangeText={(text) => setPassword(text)}
value={password}
underlineColorAndroid="transparent"
autoCapitalize="none"
/>
<TextInput
style={styles.input}
placeholderTextColor="#aaaaaa"
secureTextEntry
placeholder='Confirm Password'
onChangeText={(text) => setConfirmPassword(text)}
value={confirmPassword}
underlineColorAndroid="transparent"
autoCapitalize="none"
/>
<TouchableOpacity
style={styles.button}
onPress={() => onRegisterPress()}>
<Text style={styles.buttonTitle}>Agree and Create account</Text>
</TouchableOpacity>
<View style={styles.footerView}>
<Text style={styles.footerText}>Already got an account? <Text onPress={onFooterLinkPress} style={styles.footerLink}>Log in</Text></Text>
</View>
<Text style={styles.link} onPress={ ()=>{ Linking.openURL('https://findgoodone.ml')}}>Require agree EULA</Text>
<Text style={styles.contact}>findgoodone.staff@gmail.com</Text>
</KeyboardAwareScrollView>
<Spinner
visible={spinner}
textStyle={{ color: "#fff" }}
overlayColor="rgba(0,0,0,0.5)"
/>
</View>
)
}
まとめ
PINE proのときとほぼ同じでした。