8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @ -57,3 +57,11 @@ buck-out/ | ||||
| 
 | ||||
| # CocoaPods | ||||
| /ios/Pods/ | ||||
| 
 | ||||
| # Rust | ||||
| /target/ | ||||
| /cms/target/ | ||||
| /cms/cms_macro/target/ | ||||
| 
 | ||||
| # Environment | ||||
| *.env | ||||
|  | ||||
							
								
								
									
										2423
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										5
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,5 @@ | ||||
| [workspace] | ||||
| 
 | ||||
| members = [ | ||||
|     "cms", | ||||
| ] | ||||
| @ -4,6 +4,7 @@ import android.app.Application; | ||||
| import android.content.Context; | ||||
| import com.facebook.react.PackageList; | ||||
| import com.facebook.react.ReactApplication; | ||||
| import com.zoontek.rnlocalize.RNLocalizePackage; | ||||
| import com.reactnativecommunity.webview.RNCWebViewPackage; | ||||
| import com.reactnativecommunity.webview.RNCWebViewPackage; | ||||
| import com.oblador.vectoricons.VectorIconsPackage; | ||||
|  | ||||
| @ -1,4 +1,6 @@ | ||||
| rootProject.name = 'blazerapp' | ||||
| include ':react-native-localize' | ||||
| project(':react-native-localize').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-localize/android') | ||||
| include ':react-native-webview' | ||||
| project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android') | ||||
| include ':react-native-webview' | ||||
|  | ||||
| @ -22,49 +22,108 @@ import styles from './styles/liststyles' | ||||
| import { url } from './resources/fetchInfo.json' | ||||
| import { SearchBar } from 'react-native-elements'; | ||||
| import Icon from 'react-native-vector-icons/AntDesign' | ||||
| import AsyncStorage from '@react-native-community/async-storage' | ||||
| import Ionicons from 'react-native-vector-icons/Ionicons'; | ||||
| import AsyncStorage from '@react-native-async-storage/async-storage' | ||||
| import LinearGradient from 'react-native-linear-gradient'; | ||||
| import I18n from './i18n'; | ||||
| 
 | ||||
| const STORAGE_KEY = "teacherAnnouncements" | ||||
| 
 | ||||
| const getCurrentDate=()=>{ | ||||
| 	var date = new Date().getDate(); | ||||
| 	var month = new Date().getMonth(); | ||||
| 	var year = new Date().getFullYear(); | ||||
| 
 | ||||
| 	return new Date(year, month, date); | ||||
| } | ||||
| 
 | ||||
| const Announcement = ({item}) => { | ||||
| 	const date = new Date | ||||
| 	const dateStr = `${date.getMonth()+1}/${date.getDate()}/${date.getFullYear()}` | ||||
| 	const dateInfo = dateStr===item.item.date&&item.item.time!==undefined?item.item.time:item.item.date; | ||||
| 	const todayDate = getCurrentDate() | ||||
| 	const itemDate = new Date(item.item.date) | ||||
| 	const dateInfo = todayDate.getTime()===itemDate.getTime()&&item.item.time!==undefined?item.item.time:(item.item.date+", " + item.item.time) | ||||
| 	return ( | ||||
| 		<View style={styles.item1}> | ||||
| 			<View style = {{display: 'flex', flexDirection: 'row', justifyContent: 'space-between'}}> | ||||
| 				<View style = {{width: '75%'}}> | ||||
| 					<Text style={styles.title3}>{item.item.message}</Text> | ||||
| 				</View> | ||||
| 				<View style = {{display: 'flex', flexDirection: 'row'}}> | ||||
| 					{dateInfo!==undefined?<Text style={{fontSize: 16, alignSelf: 'center'}}>{dateInfo}</Text>:<></>} | ||||
| 		<View style={{borderWidth: 1, borderColor: '#323232', padding: '2%', marginHorizontal: '2%', marginBottom: '2%', borderRadius: 12}}> | ||||
| 			<View style = {{display: 'flex', flexDirection: 'column', justifyContent: 'space-between'}}> | ||||
| 				<View style = {{width: '100%'}}> | ||||
| 					<Text style={styles.title}>{item.item.message}</Text> | ||||
| 				</View> | ||||
| 				{dateInfo!==undefined?<Text style={{fontSize: 12, fontWeight: '200'}}>{dateInfo}</Text>:<></>} | ||||
| 			</View> | ||||
| 			 | ||||
| 		</View> | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| export const TeacherList = ({route}) => { | ||||
| function NewTeacherList(props) { | ||||
| 	return ( | ||||
| 		<View style={{}}> | ||||
| 			<FlatList | ||||
| 				data={route.params.data} | ||||
| 				renderItem={item=><Announcement item={item}/>} | ||||
| 				keyExtractor={item=>JSON.stringify(item)} | ||||
| 			/> | ||||
| 		</View> | ||||
| 	  <View> | ||||
| 		<LinearGradient start={{x: 0.25, y: .5}} end={{x: 1, y: 1}} colors={['#FF8484', '#FF1111']} style={{backgroundColor: 'red', width: '20%', padding: '2%', borderTopRightRadius: 20, borderBottomRightRadius: 20, marginVertical: '2%'}}> | ||||
| 		  <Text style={[styles.title, {color: 'white', fontWeight: 'bold'}]}>{I18n.t('dates.'+props.name)}</Text> | ||||
| 		</LinearGradient> | ||||
| 		<FlatList | ||||
| 		  data={props.list} | ||||
| 		  renderItem={item=><Announcement item={item}/>}  | ||||
| 		  keyExtractor={item=>JSON.stringify(item)} | ||||
| 		/> | ||||
| 	  </View> | ||||
| 	) | ||||
|   } | ||||
| 
 | ||||
| export const TeacherList = ({route}) => { | ||||
| 	const todayDate = getCurrentDate() | ||||
| 	const weekPastDate = new Date(); | ||||
| 	var pastDate = weekPastDate.getDate() - 7; | ||||
| 	weekPastDate.setDate(pastDate); | ||||
| 	const weekFutureDate = new Date(); | ||||
| 	var futureDate = weekFutureDate.getDate() + 7; | ||||
| 	weekFutureDate.setDate(futureDate); | ||||
| 	const today = [] | ||||
| 	const past = [] | ||||
| 	const future = [] | ||||
| 	var todayBoolean = true | ||||
| 	var pastBoolean = true | ||||
| 	var futureBoolean = true | ||||
| 	 | ||||
| 	for (var i = 0; i < route.params.data.length; i++) { | ||||
| 		const itemDate = new Date(route.params.data[i].date) | ||||
| 		if (itemDate.getTime() == todayDate.getTime()) { | ||||
| 			today.push(route.params.data[i]) | ||||
| 		} | ||||
| 		else if (itemDate.getTime() > todayDate.getTime() && itemDate.getTime() <= weekFutureDate.getTime()) { | ||||
| 			future.push(route.params.data[i]) | ||||
| 		} | ||||
| 		//else if (itemDate >= weekPastDate && itemDate < todayDate) {
 | ||||
| 		else if (itemDate.getTime() < todayDate.getTime()) { | ||||
| 			past.push(route.params.data[i]) | ||||
| 		} | ||||
| 	} | ||||
| 	if (today.length === 0) todayBoolean = false | ||||
| 	if (past.length === 0) pastBoolean = false | ||||
| 	if (future.length === 0) futureBoolean = false | ||||
| 	var noAnn = (todayBoolean||pastBoolean||futureBoolean) | ||||
| 
 | ||||
| 	return ( | ||||
| 		<ScrollView style={{flex:1, backgroundColor: 'white'}}> | ||||
| 			{todayBoolean?<NewTeacherList name = 'today' list = {today} />:<></>} | ||||
| 			{pastBoolean?<NewTeacherList name = 'past' list = {past} />:<></>} | ||||
| 			{futureBoolean?<NewTeacherList name = 'future' list = {future} />:<></>} | ||||
| 			{!noAnn?<Text style={{textAlign: 'center', fontSize: 20, paddingTop: '2%'}}>{I18n.t('announcements.noAnnouncements')}</Text>:<></>} | ||||
| 		</ScrollView> | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| function TeacherButton(props) { | ||||
| 	const [color, setColor] = useState(props.color?props.color:'lightgrey') | ||||
| 	return ( | ||||
| 		<View style={[styles.item1,{flexDirection:'row'}]}> | ||||
| 		  <TouchableOpacity style={{flex:1, justifyContent: 'center'}} onPress={()=>{props.navigation.navigate('TeacherList',{data:props.data,name:props.name})}} activeOpacity={0.8}> | ||||
| 			<Text style={styles.title3}>{props.name}</Text> | ||||
| 		<View> | ||||
| 			<TouchableOpacity style={styles.listItem} onPress={()=>{props.navigation.navigate('TeacherList',{data:props.data,name:props.name})}} activeOpacity={0.8}> | ||||
| 				<View style={styles.container2}> | ||||
| 					<Ionicons name="megaphone-outline" size={36} color={'#323232'}style={{marginRight: 15}}/> | ||||
| 					<View style={styles.accordian}> | ||||
| 						<Text style={[styles.title, {alignSelf:'center'}]}>{props.name}</Text> | ||||
| 						{props.icon?<Icon name="pushpino" size={24} color={color} onPress={()=>{setColor(color=='red'?'lightgrey':'red');props.addFavorite(props.name)}}/>:<></>} | ||||
| 					</View> | ||||
| 				</View> | ||||
| 		  </TouchableOpacity> | ||||
| 		  {props.icon?<Icon.Button color={color} name="star" size={30} style={{alignSelf:'center'}} backgroundColor="white" onPress={()=>{setColor(color=='#dba309'?'lightgrey':'#dba309');props.addFavorite(props.name)}}/>:<></>} | ||||
| 		</View> | ||||
| 	) | ||||
| } | ||||
| @ -124,14 +183,14 @@ class Announcements extends React.Component { | ||||
| 	 | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<View style={[styles.container]}> | ||||
| 			<ScrollView style={styles.moreDefault}> | ||||
| 				<TeacherButton data={this.state.data.filter(x=>x.teacher==null||x.teacher.trim()==='')} name="No Teacher" navigation={this.props.navigation} /> | ||||
| 				<FlatList | ||||
| 					data={this.state.favoriteNames.concat(this.state.teacherNames.filter(x=>this.state.favoriteNames.map(({name})=>name).indexOf(x.name) < 0))} | ||||
| 					renderItem={({item})=><TeacherButton color={this.state.favoriteNames.indexOf(item) >= 0?'#dba309':'lightgrey'} item={item} data={this.state.data.filter(x=>x.teacher===item.name)} name={item.name} navigation={this.props.navigation} icon={true} addFavorite={this.addFavorite}/>} | ||||
| 					renderItem={({item})=><TeacherButton color={this.state.favoriteNames.indexOf(item) >= 0?'red':'lightgrey'} item={item} data={this.state.data.filter(x=>x.teacher===item.name)} name={item.name} navigation={this.props.navigation} icon={true} addFavorite={this.addFavorite}/>} | ||||
| 					keyExtractor={(item,index)=>item.name+index} | ||||
| 				/> | ||||
| 			</View> | ||||
| 			</ScrollView> | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
|  | ||||
							
								
								
									
										23
									
								
								app/App.js
									
									
									
									
									
								
							
							
						
						| @ -27,25 +27,18 @@ import Staff from './Staff' | ||||
| import OpeningPage from './OpeningPage'; | ||||
| import OpenPage from './OpenPage'; | ||||
| import Ionicons from 'react-native-vector-icons/Ionicons'; | ||||
| import I18n from './i18n'; | ||||
| import AsyncStorage from '@react-native-community/async-storage' | ||||
| import I18n from './i18n.js' | ||||
| import AsyncStorage from '@react-native-async-storage/async-storage' | ||||
| 
 | ||||
| const Tab = createBottomTabNavigator(); | ||||
| 
 | ||||
| 
 | ||||
| AsyncStorage.getItem('language') | ||||
|   .then((token) => {  | ||||
| 	console.log("lang: " + token); | ||||
| 	I18n.locale = token; | ||||
|   }); | ||||
| 
 | ||||
| AsyncStorage.getItem('announcementNotifs') | ||||
| 	.then((token) => {  | ||||
| 	console.log("announcementNotifs: " + token); | ||||
| 	}); | ||||
| AsyncStorage.getItem('eventNotifs') | ||||
| 	.then((token) => {  | ||||
| 	console.log("eventNotifs: " + token); | ||||
| 	}); | ||||
| 
 | ||||
| class App extends React.Component { | ||||
| 	state = { | ||||
| @ -86,11 +79,11 @@ class App extends React.Component { | ||||
| 						fontSize:16 | ||||
| 					}}} | ||||
| 				>	 | ||||
| 					<Tab.Screen name={I18n.t('app.home')} component={Home}/> | ||||
| 					<Tab.Screen name={I18n.t('app.calendar')} component={Calendar}/> | ||||
| 					<Tab.Screen name={I18n.t('app.clubs')} component={Clubs}/> | ||||
| 					<Tab.Screen name={I18n.t('app.staff')} component={Staff}/> | ||||
| 					<Tab.Screen name={I18n.t('app.more')} component={More}/> | ||||
| 					<Tab.Screen name={I18n.t("app.home")} component={Home}/> | ||||
| 					<Tab.Screen name={I18n.t("app.calendar")} component={Calendar}/> | ||||
| 					<Tab.Screen name={I18n.t("app.clubs")} component={Clubs}/> | ||||
| 					<Tab.Screen name={I18n.t("app.staff")} component={Staff}/> | ||||
| 					<Tab.Screen name={I18n.t("app.more")} component={More}/> | ||||
| 				</Tab.Navigator> | ||||
| 				: <OpenPage />} | ||||
| 			</NavigationContainer> | ||||
|  | ||||
							
								
								
									
										245
									
								
								app/Calendar.js
									
									
									
									
									
								
							
							
						
						| @ -14,85 +14,142 @@ import { | ||||
| import {	  | ||||
|   ReloadInstructions, | ||||
| } from 'react-native/Libraries/NewAppScreen'; | ||||
| 
 | ||||
| import Ionicons from 'react-native-vector-icons/Ionicons'; | ||||
| import Icon from 'react-native-vector-icons/AntDesign' | ||||
| import LinearGradient from 'react-native-linear-gradient'; | ||||
| import I18n from './i18n'; | ||||
| import { NavigationContainer } from '@react-navigation/native' | ||||
| import { createStackNavigator } from '@react-navigation/stack' | ||||
| import styles from './styles/liststyles' | ||||
| import { url } from './resources/fetchInfo.json' | ||||
| import morestyles from './styles/morestyles' | ||||
| import I18n from './i18n.js' | ||||
| 
 | ||||
| const Stack = createStackNavigator(); | ||||
| 
 | ||||
| const getCurrentDate=()=>{ | ||||
|   var date = new Date().getDate(); | ||||
|   var month = new Date().getMonth() + 1; | ||||
|   var year = new Date().getFullYear(); | ||||
| 
 | ||||
|   return year + ',' + month + ',' + date; | ||||
|   return new Date(year, month, date); | ||||
| } | ||||
| const getWeekDate=()=>{ | ||||
|   var date = new Date().getDate()-8; | ||||
|   var month = new Date().getMonth()+1; | ||||
|   var year = new Date().getFullYear(); | ||||
| 
 | ||||
|   return year + ',' + month + ',' + date; | ||||
| } | ||||
| 
 | ||||
| const Event = ({item}) => { | ||||
| 	const [visible, setVisible] = useState(false) | ||||
|   const today = new Date(getCurrentDate()) | ||||
|   const itemDate = new Date(item.item.date) | ||||
|   const week = new Date(getWeekDate()) | ||||
| 	const extra = ( | ||||
| 		<> | ||||
| 			<Text style={{fontSize:20, paddingHorizontal: '1%'}}>{item.item.text}</Text> | ||||
|       <View style={{display: 'flex', flexDirection: 'row', alignItems: 'center'}}> | ||||
|         <View style={{width: '10%', display: 'flex', justifyContent: 'center'}}> | ||||
|           <Image source={require('./assets/location.png')} style={{height: 22, width: 22}}/> | ||||
|         </View> | ||||
|         <View style={{width: '90%'}}> | ||||
|           <Text style={{fontSize:20}}>{item.item.location}</Text> | ||||
|         </View> | ||||
|          | ||||
| export const EventInfo = ({route}) => { | ||||
|   const item = route.params; | ||||
|   const itemDate = new Date(item.date) | ||||
|   const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] | ||||
|   const months = ['January','February','March','April','May','June','July','August','September','October','November','December',] | ||||
|   const dayOfWeek = days[itemDate.getDay()] | ||||
|   const month = months[itemDate.getMonth()] | ||||
|   const date = itemDate.getDate() | ||||
|    | ||||
|   return ( | ||||
|     <ScrollView style = {{backgroundColor: 'white', flex:1, padding: '5%', paddingRight: '10%'}}> | ||||
|       <View style={{marginBottom: '7%'}}> | ||||
|         <Text style={[styles.title, {fontWeight: 'bold', marginBottom: '2%'}]}>{I18n.t('calendar.info')}</Text> | ||||
|         <Text style={[styles.title, {fontWeight: '200'}]}>{item.text}</Text> | ||||
|       </View> | ||||
| 			 | ||||
| 		</> | ||||
|       <View style={{}}> | ||||
|         <View style={{display: 'flex', flexDirection: 'row', marginBottom: '5%'}}> | ||||
|           <Ionicons name='location-outline' size={28} color={'#323232'}style={{marginRight: 15, alignSelf: 'center'}}/> | ||||
|           <View style={{display: 'flex', marginLeft: -15, paddingHorizontal: '5%'}}> | ||||
|             <Text style={{fontSize: 16}}>{I18n.t('calendar.location')}</Text> | ||||
|             <Text style={[styles.title, {fontSize: 16, fontWeight: '200'}]}>{item.location}</Text> | ||||
|           </View> | ||||
|         </View> | ||||
|         <View style={{display: 'flex', flexDirection: 'row', marginBottom: '5%'}}> | ||||
|           <Ionicons name='time-outline' size={28} color={'#323232'}style={{marginRight: 15, alignSelf: 'center'}}/> | ||||
|           <View style={{display: 'flex', marginLeft: -15, paddingHorizontal: '5%'}}> | ||||
|             <Text style={{fontSize: 16}}>{I18n.t('calendar.date')}</Text> | ||||
|             <Text style={[styles.title, {fontSize: 16, fontWeight: '200'}]}>{dayOfWeek}, {month} {date}</Text> | ||||
|           </View> | ||||
|         </View> | ||||
|         <View style={{display: 'flex', flexDirection: 'row'}}> | ||||
|           <Ionicons name='person-circle-outline' size={28} color={'#323232'}style={{marginRight: 15, alignSelf: 'center'}}/> | ||||
|           <View style={{display: 'flex', marginLeft: -15, paddingHorizontal: '5%'}}> | ||||
|             <Text style={{fontSize: 16}}>{I18n.t('calendar.organizer')}</Text> | ||||
|             <Text style={[styles.title, {fontSize: 16, fontWeight: '200'}]}>{item.name}</Text> | ||||
|             <Text style={[styles.title, {fontSize: 16, fontWeight: '200', textDecorationLine: 'underline'}]}>{item.emails}</Text> | ||||
|           </View> | ||||
|         </View> | ||||
|       </View> | ||||
|     </ScrollView> | ||||
|   ) | ||||
| } | ||||
| const Event = (props) => { | ||||
|   const item = props.item | ||||
|   const date = item.item.date.split('-') | ||||
| 
 | ||||
|   if (itemDate.getTime() >= today.getTime()) { | ||||
|     return ( | ||||
|       <TouchableOpacity style={styles.item1} onPress={()=>setVisible(!visible)} activeOpacity={0.8}> | ||||
|         <View style = {{display: 'flex', flexDirection: 'row', alignContent: 'center', justifyContent: 'space-between'}}> | ||||
|         <View style = {{display: 'flex', flexDirection: 'row', alignContent: 'center', width: '60%'}}> | ||||
|           <Image source ={require('./assets/calendar.png')}  style = {{height: 40, width: 40, marginRight: 15}}/> | ||||
|           <Text style={styles.title3}>{item.item.title}</Text> | ||||
|   return ( | ||||
|     <View> | ||||
|       <TouchableOpacity style={[styles.listItem, {padding: '2%'}]} onPress={()=>props.navigation.navigate('EventInfo', {data:props.data, title: item.item.title,text:item.item.text,location:item.item.location,date:item.item.date, name:item.item.name, emails: item.item.emails})} activeOpacity={0.8}> | ||||
|         <View style = {[styles.container2, {justifyContent: 'space-between'}]}> | ||||
|           <View style={{display: 'flex', flexDirection: 'row'}}> | ||||
|             <Ionicons name='calendar' size={32} color={'#323232'} style={{marginRight: 15}}/> | ||||
|             <View style = {{display: 'flex', alignContent: 'center', width: '80%'}}> | ||||
|               <Text style={styles.title}>{item.item.title}</Text> | ||||
|               <View style={{paddingBottom: '2%'}}><Text style = {{fontSize: 12, fontWeight: '200'}}>{`${date[1]}/${date[2]}/${date[0]}`}</Text></View> | ||||
|             </View> | ||||
|           </View> | ||||
|           <Image source = {require('./assets/forward.png')} style={{tintColor: '#b2b2b2'}}/> | ||||
|         </View> | ||||
|         <View style = {{display: 'flex', flexDirection: 'row', alignContent: 'center'}}> | ||||
|           <Text style = {{fontSize: 16, alignSelf: 'center'}}>{item.item.date}</Text> | ||||
|         </View> | ||||
|       </View> | ||||
|         {visible?extra:<></>} | ||||
| 		  </TouchableOpacity> | ||||
|     ) | ||||
|   } | ||||
|   else if (itemDate.getTime() >= week.getTime()){ | ||||
|     return ( | ||||
| 		<TouchableOpacity style={{backgroundColor: '#e3e3e3', padding: 15, borderBottomWidth: 1, borderColor: 'black', width: '100%',}} onPress={()=>setVisible(!visible)} activeOpacity={0.8}> | ||||
| 			<View style = {{display: 'flex', flexDirection: 'row', alignContent: 'center', justifyContent: 'space-between'}}> | ||||
|         <View style = {{display: 'flex', flexDirection: 'row', alignContent: 'center', width: '60%'}}> | ||||
|           <Image source ={require('./assets/calendar.png')}  style = {{height: 40, width: 40, marginRight: 15}}/> | ||||
|           <Text style={styles.title3}>{item.item.title}</Text> | ||||
|         </View> | ||||
|         <View style = {{display: 'flex', flexDirection: 'row', alignContent: 'center'}}> | ||||
|           <Text style = {{fontSize: 16, alignSelf: 'center'}}>{item.item.date}</Text> | ||||
|         </View> | ||||
|       </View> | ||||
| 			{visible?extra:<></>} | ||||
| 		</TouchableOpacity> | ||||
| 	  ) | ||||
|   } | ||||
|   else { | ||||
|     return ( | ||||
|       null | ||||
|     ) | ||||
|   } | ||||
|       </TouchableOpacity> | ||||
|     </View>     | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| const background = (<LinearGradient | ||||
|   colors={['#f99', 'white']} | ||||
|   style = {{flex:1,borderBottomColor:'black',borderBottomWidth:0.5}} | ||||
|   />) | ||||
| 
 | ||||
| function CalendarEvents () { | ||||
|   return ( | ||||
|     <NavigationContainer independent={true}> | ||||
|       <Stack.Navigator> | ||||
|         <Stack.Screen  | ||||
|           name = {I18n.t('calendar.calendar')} | ||||
|           component = {Calendar} | ||||
|           options={({ | ||||
|             headerShown: true, | ||||
|             headerTitleStyle:morestyles.headerTitle, | ||||
|             headerBackground: ()=>background, | ||||
|             //headerLeft: null,
 | ||||
|             headerTitleAlign: 'center', | ||||
|             headerBackTitleVisible:false, | ||||
|             headerTintColor: 'black' | ||||
|           })} | ||||
|         /> | ||||
|         <Stack.Screen  | ||||
|           name = "EventInfo" | ||||
|           component = {EventInfo} | ||||
|           options={({route})=>({ | ||||
|             title:route.params.title, | ||||
|             headerTitleStyle:morestyles.headerTitle, | ||||
|             headerBackground: ()=>background, | ||||
|             //headerLeft: null,
 | ||||
|             headerTitleAlign: 'center', | ||||
|             headerBackTitleVisible:false, | ||||
|             headerTintColor: 'black' | ||||
|           })} | ||||
|         /> | ||||
|       </Stack.Navigator> | ||||
|     </NavigationContainer> | ||||
|   )  | ||||
| } | ||||
| 
 | ||||
| function NewCalendarCategory (props) { | ||||
|   return ( | ||||
|     <View> | ||||
|       <LinearGradient start={{x: 0.25, y: .5}} end={{x: 1, y: 1}} colors={['#FF8484', '#FF1111']} style={{backgroundColor: 'red', width: '20%', padding: '2%', borderTopRightRadius: 20, borderBottomRightRadius: 20, marginVertical: '2%'}}> | ||||
|         <Text style={[styles.title, {color: 'white', fontWeight: 'bold'}]}>{I18n.t('dates.'+props.name)}</Text> | ||||
|       </LinearGradient> | ||||
|       <FlatList | ||||
|         data={props.list} | ||||
|         renderItem={item=><Event item={item} name={props.itemname} navigation={props.navigation}/>}  | ||||
|         keyExtractor={item=>JSON.stringify(item)} | ||||
|       /> | ||||
|     </View> | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| class Calendar extends React.Component { | ||||
| @ -124,32 +181,54 @@ class Calendar extends React.Component { | ||||
| 		  }) | ||||
| 		  .then((json) => { | ||||
| 			const data = JSON.parse(json).data | ||||
| 			data.sort((a,b)=>new Date(b.date).getTime()-new Date(a.date).getTime()) | ||||
|       data.sort((a,b)=>new Date(b.date).getTime()-new Date(a.date).getTime()) | ||||
|       console.log(data); | ||||
| 			this.setState({data: data}); | ||||
| 		  }) | ||||
| 		  .catch((error) => console.error(error)) | ||||
| 	} | ||||
| 
 | ||||
| 	render() { | ||||
|     const todayDate = getCurrentDate() | ||||
|     const weekPastDate = new Date(); | ||||
|     var pastDate = weekPastDate.getDate() - 7; | ||||
|     weekPastDate.setDate(pastDate); | ||||
|     const weekFutureDate = new Date(); | ||||
|     var futureDate = weekFutureDate.getDate() + 7; | ||||
|     weekFutureDate.setDate(futureDate); | ||||
|     const today = [] | ||||
|     const past = [] | ||||
|     const future = [] | ||||
|     var todayBoolean = true | ||||
|     var pastBoolean = true | ||||
|     var futureBoolean = true | ||||
|      | ||||
|     for (var i =0; i < this.state.data.length; i++) { | ||||
|       const itemDate = new Date(this.state.data[i].date) | ||||
|       if (itemDate == todayDate) { | ||||
|         today.push(this.state.data[i]) | ||||
|       } | ||||
|       else if (itemDate > todayDate && itemDate <= weekFutureDate) { | ||||
|         future.push(this.state.data[i]) | ||||
|       } | ||||
|       //else if (itemDate >= weekPastDate && itemDate < todayDate) {
 | ||||
|       else if (itemDate < todayDate) { | ||||
|         past.push(this.state.data[i]) | ||||
|       } | ||||
|     } | ||||
|     if (today.length === 0) todayBoolean = false | ||||
|     if (past.length === 0) pastBoolean = false | ||||
|     if (future.length === 0) futureBoolean = false | ||||
|     var noAnn = (todayBoolean||pastBoolean||futureBoolean) | ||||
| 		return ( | ||||
| 			<View> | ||||
|         <View style = {{height: 90, display: 'flex'}}> | ||||
|           <LinearGradient | ||||
|             colors={['#f99', 'white']} | ||||
|             style = {{height: '100%', borderBottomColor:'black', borderBottomWidth:0.5, display: 'flex', justifyContent: 'flex-end', paddingBottom: '2.5%'}} | ||||
|           > | ||||
|             <Text style = {{fontSize: 24, fontWeight: 'bold', alignSelf: 'center'}}>{I18n.t('calendar.calendarEvents')}</Text> | ||||
|           </LinearGradient> | ||||
|           | ||||
|         </View> | ||||
| 				<FlatList | ||||
| 					data={this.state.data} | ||||
| 					renderItem={item=><Event item={item}/>} | ||||
| 					keyExtractor={item=>JSON.stringify(item)} | ||||
| 				/> | ||||
| 			</View> | ||||
| 			<ScrollView style={{flex:1, backgroundColor: 'white'}}> | ||||
|         {todayBoolean?<NewCalendarCategory name = 'today' list = {today} navigation={this.props.navigation} />: <></>} | ||||
|         {pastBoolean?<NewCalendarCategory name = 'past' list = {past} navigation={this.props.navigation} />: <></>} | ||||
|         {futureBoolean?<NewCalendarCategory name = 'future' list = {future} navigation={this.props.navigation} />: <></>} | ||||
|         {!noAnn?<Text style={{textAlign: 'center', fontSize: 20, paddingTop: '2%'}}>{I18n.t('calendar.noEvents')}</Text>:<></>} | ||||
|       </ScrollView> | ||||
| 		) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export default Calendar; | ||||
| export default CalendarEvents; | ||||
| @ -7,6 +7,9 @@ import { | ||||
|   Text, | ||||
|   StatusBar, | ||||
|   Linking, | ||||
|   Animated, | ||||
|   TouchableOpacity, | ||||
|   Image | ||||
| } from 'react-native'; | ||||
| 
 | ||||
| import { | ||||
| @ -18,12 +21,14 @@ import { | ||||
| } from 'react-native/Libraries/NewAppScreen'; | ||||
| import styles from './styles/liststyles'; | ||||
| import { url } from './resources/fetchInfo.json' | ||||
| import I18n from 'i18n-js'; | ||||
| 
 | ||||
| class ChallengeWeek extends React.Component { | ||||
| 	constructor(props) { | ||||
| 		super(props) | ||||
| 		this.state = { | ||||
| 			isLoading: true | ||||
| 			isLoading: true, | ||||
| 			flip: true | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| @ -37,17 +42,70 @@ class ChallengeWeek extends React.Component { | ||||
| 		}).then((json) => { | ||||
| 			this.setState({data: JSON.parse(json),isLoading:false}); | ||||
| 		}).catch((error) => console.error(error)) | ||||
| 
 | ||||
| 		/*this.animatedValue=new Animated.Value(0); | ||||
| 		this.value=0; | ||||
| 		this.animatedValue.addListener(({value}) => { | ||||
| 			this.value=value; | ||||
| 		}) | ||||
| 		this.frontInterpolate = this.animatedValue.interpolate({ | ||||
| 			inputRange:[0,180], | ||||
| 			outputRange:['0deg', '180deg'], | ||||
| 		}) | ||||
| 		this.backInterpolate = this.animatedValue.interpolate({ | ||||
| 			inputRange:[0,180], | ||||
| 			outputRange: ['180deg','360deg'] | ||||
| 		})*/ | ||||
| 	} | ||||
| 
 | ||||
| 	/*flipCard() { | ||||
| 		if (this.value >= 90) { | ||||
| 			Animated.spring(this.animatedValue, { | ||||
| 				toValue:0, | ||||
| 				friction:8, | ||||
| 				tension: 10 | ||||
| 			}).start(); | ||||
| 		} | ||||
| 		else { | ||||
| 			Animated.spring(this.animatedValue, { | ||||
| 				toValue:180, | ||||
| 				friction: 8, | ||||
| 				tension: 10 | ||||
| 			}).start(); | ||||
| 		} | ||||
| 		this.setState({flip:!this.state.flip}) | ||||
| 	}*/ | ||||
| 	 | ||||
| 	render() { | ||||
| 		{/*const frontAnimatedStyle = { | ||||
| 			transform: [ | ||||
| 				{rotateY:this.frontInterpolate} | ||||
| 			] | ||||
| 		} | ||||
| 		const backAnimatedStyle = { | ||||
| 			transform: [ | ||||
| 				{rotateY:this.backInterpolate} | ||||
| 			] | ||||
| 		} | ||||
| 		var styling={} | ||||
| 		var styling2={} | ||||
| 		if (this.state.flip) { | ||||
| 			styling=({height: '100%', width: '100%', backgroundColor: 'white', borderRadius: 20, textAlign: 'center', display: 'flex', alignContent: 'center', padding: '5%', paddingTop: '15%', borderColor: 'red', borderWidth: 1}) | ||||
| 			styling2=({display:'none'}) | ||||
| 		} | ||||
| 		else { | ||||
| 			styling=({display:'none'}) | ||||
| 			styling2=({height: '100%', width: '100%', backgroundColor: 'white', borderRadius: 20, textAlign: 'center', display: 'flex', alignContent: 'center', padding: '5%', paddingTop: '15%', borderColor: 'red', borderWidth: 1}) | ||||
| 		}*/} | ||||
| 		 | ||||
| 		if (this.state.isLoading) { | ||||
| 			return <View/> | ||||
| 		} else { | ||||
| 			return ( | ||||
| 				<View style={{alignItems:'center',paddingTop:'5%',paddingiorizontal:'10%', height: '100%', backgroundColor: 'white'}}> | ||||
| 					<Text style={{fontSize: 32, fontWeight: 'bold', marginBottom: '10%', color: 'red'}}>{this.state.data.title}</Text> | ||||
| 					<Text style={{textAlign:'center', fontSize: 24, marginBottom: '5%'}}>{this.state.data.text}</Text> | ||||
| 					<Text style={{textAlign:'center', fontSize: 20, textDecorationLine: 'underline', textDecorationStyle: "solid", textDecorationColor: "#000",}} onPress={() => Linking.openURL(this.state.data.link)}>{this.state.data.link}</Text> | ||||
| 				<View style={{alignItems:'center',paddingiorizontal:'10%', height: '100%', backgroundColor: 'white', justifyContent: 'center', padding: '2%'}}> | ||||
| 					<Text style={{fontSize: 32, fontWeight: 'bold', marginBottom: '10%', color: 'red', textAlign: 'center'}}>{this.state.data.title}</Text> | ||||
| 					<Text style={{textAlign:'center', fontSize: 24, marginBottom: '5%', textAlign: 'center', fontWeight: '200'}}>{this.state.data.text}</Text> | ||||
| 					<Text style={{textAlign:'center', fontSize: 20, textDecorationLine: 'underline', textDecorationStyle: "solid", textDecorationColor: "#000"}} onPress={() => Linking.openURL(this.state.data.link)}>{I18n.t("challenge.link")}</Text> | ||||
| 				</View> | ||||
| 			) | ||||
| 		} | ||||
|  | ||||
							
								
								
									
										67
									
								
								app/Clubs.js
									
									
									
									
									
								
							
							
						
						| @ -29,50 +29,50 @@ import morestyles from './styles/morestyles' | ||||
| import { url } from './resources/fetchInfo.json' | ||||
| import LinearGradient from 'react-native-linear-gradient'; | ||||
| import I18n from './i18n'; | ||||
| import Ionicons from 'react-native-vector-icons/Ionicons'; | ||||
| 
 | ||||
| const Stack = createStackNavigator(); | ||||
| 
 | ||||
| export const ClubInfo = ({route}) => { | ||||
|   const item = route.params; | ||||
|   return ( | ||||
|     <View style = {{padding: 10, backgroundColor: 'white', height: '100%'}}> | ||||
|       <View style ={[styles.infoContainer, {flexDirection: 'row', alignItems: 'center'}]}> | ||||
|         <View style={{width: '17%', display: 'flex', justifyContent: 'center'}}> | ||||
|           <Image source ={require('./assets/time.png')} style={{width: 50, height: 50}}/> | ||||
|         </View> | ||||
|         <View style={{width: '83%'}}> | ||||
|           <Text style = {{fontSize:20}}>{item.meeting}</Text> | ||||
|     <ScrollView style = {{backgroundColor: 'white', flex:1, padding: '5%', paddingRight: '10%'}}> | ||||
|       <View style={{display: 'flex', flexDirection: 'row', marginBottom: '5%'}}> | ||||
|         <Ionicons name='location-outline' size={28} color={'#323232'}style={{marginRight: 15, alignSelf: 'center'}}/> | ||||
|         <View style={{display: 'flex', marginLeft: -15, paddingHorizontal: '5%'}}> | ||||
|           <Text style={{fontSize: 16}}>Meeting Location </Text> | ||||
|           <Text style={[styles.title, styles.linktext, {fontSize: 16, fontWeight: '200'}]} onPress={() => Linking.openURL(item.link)}>{item.link}</Text> | ||||
|         </View> | ||||
|       </View> | ||||
|       <View style ={[styles.infoContainer, {flexDirection: 'row', alignItems: 'center'}]}> | ||||
|         <View style={{width: '17%', display: 'flex', justifyContent: 'center'}}> | ||||
|           <Image source ={require('./assets/zoom.png')} style={{width: 50, height: 50}}/> | ||||
|         </View> | ||||
|         <View style={{width: '83%'}}> | ||||
|           <Text style = {[styles.linktext,{fontSize:20}]} onPress={() => Linking.openURL(item.link)}>{item.link}</Text> | ||||
|       <View style={{display: 'flex', flexDirection: 'row', marginBottom: '5%'}}> | ||||
|         <Ionicons name='time-outline' size={28} color={'#323232'}style={{marginRight: 15, alignSelf: 'center'}}/> | ||||
|         <View style={{display: 'flex'}}> | ||||
|           <Text style={{fontSize: 16}}>Meeting Date</Text> | ||||
|           <Text style={[styles.title, {fontSize: 16, fontWeight: '200'}]}>{item.meeting}</Text> | ||||
|         </View> | ||||
|       </View> | ||||
| 			<View style ={[styles.infoContainer, {flexDirection: 'row', alignItems: 'center'}]}> | ||||
|         <View style={{width: '17%', display: 'flex', justifyContent: 'center'}}> | ||||
|           <Image source ={require('./assets/sponsor.png')} style={{width: 50, height: 50}}/> | ||||
|         </View> | ||||
|         <View style={{width: '83%'}}> | ||||
|           <Text style = {{fontSize:20}}>{item.sponsor}</Text> | ||||
|       <View style={{display: 'flex', flexDirection: 'row'}}> | ||||
|         <Ionicons name='person-circle-outline' size={28} color={'#323232'}style={{marginRight: 15, alignSelf: 'center'}}/> | ||||
|         <View style={{display: 'flex'}}> | ||||
|           <Text style={{fontSize: 16}}>Sponsor</Text> | ||||
|           <Text style={[styles.title, {fontSize: 16, fontWeight: '200'}]}>{item.sponsor}</Text> | ||||
|         </View> | ||||
|       </View> | ||||
|     </View> | ||||
|     </ScrollView> | ||||
|   ) | ||||
| } | ||||
| function ClubElement (props) { | ||||
|   const item = props.item; | ||||
|   return( | ||||
| 	<View> | ||||
|       <TouchableOpacity style={styles.item1} onPress={()=>props.navigation.navigate('ClubInfo', {data:props.data,name:props.name,meeting:item.meeting,link:item.link,sponsor:item.sponsor})} activeOpacity={0.8}> | ||||
|         <View style = {{display: 'flex', flexDirection: 'row', alignItems: 'center'}}> | ||||
|           <Image source = {require('./assets/clubs.png')} style = {{height: 40, width: 40, marginRight: 10}}/> | ||||
|           <Text style={styles.title3}>{props.item.name}</Text> | ||||
|       <TouchableOpacity style={[styles.listItem]} onPress={()=>props.navigation.navigate('ClubInfo', {data:props.data,name:props.name,meeting:item.meeting,link:item.link,sponsor:item.sponsor})} activeOpacity={0.8}> | ||||
|         <View style = {[styles.container2, {justifyContent: 'space-between'}]}> | ||||
|           <View style={{display: 'flex', flexDirection: 'row'}}>  | ||||
|             <Ionicons name = "ios-people-circle-outline" size={36} color={'#323232'} style={{marginRight: 15}} /> | ||||
|             <Text style={[styles.title, {alignSelf:'center'}]}>{props.item.name}</Text> | ||||
|           </View> | ||||
|           <Image source = {require('./assets/forward.png')} style={{tintColor: '#b2b2b2'}}/> | ||||
|         </View> | ||||
|          | ||||
|       </TouchableOpacity> | ||||
| 	</View> | ||||
|   ) | ||||
| @ -91,7 +91,14 @@ function Club () { | ||||
|           name = "Clubs" | ||||
|           component = {Clubs} | ||||
|           options={({ | ||||
|             headerShown: false | ||||
|             headerShown: true, | ||||
|             headerTitleStyle:morestyles.headerTitle, | ||||
|             headerBackground: ()=>background, | ||||
|             //headerleft: null,
 | ||||
|             headerTitleAlign: 'center', | ||||
|             headerBackTitleVisible:false, | ||||
|             headerTintColor: 'black', | ||||
|             title:I18n.t('app.clubs'), | ||||
|           })} | ||||
|         /> | ||||
|         <Stack.Screen  | ||||
| @ -100,7 +107,10 @@ function Club () { | ||||
|           options={({route})=>({ | ||||
|             title:route.params.name, | ||||
|             headerTitleStyle:[morestyles.headerTitle,{alignSelf:'center'}], | ||||
|             headerBackground: ()=>background | ||||
|             headerBackground: ()=>background, | ||||
|             headerBackTitleVisible:false, | ||||
|             headerTintColor: 'black', | ||||
|             headerTitleAlign: 'center', | ||||
|           })} | ||||
|         /> | ||||
|       </Stack.Navigator> | ||||
| @ -157,7 +167,7 @@ class Clubs extends React.Component { | ||||
|     const { data , dataSearch,search} = this.state; | ||||
| 
 | ||||
|     return ( | ||||
|       <SafeAreaView style={styles.container}> | ||||
|       <SafeAreaView style={styles.moreDefault}> | ||||
|         <SearchBar | ||||
|         lightTheme | ||||
|         placeholder={I18n.t('clubs.searchClubs')} | ||||
| @ -170,7 +180,6 @@ class Clubs extends React.Component { | ||||
|         renderItem={({item}) => <ClubElement item={item} name={item.name} navigation={this.props.navigation}/>} | ||||
|         keyExtractor={item => JSON.stringify(item)} | ||||
|       /> | ||||
|        | ||||
|     </SafeAreaView> | ||||
|      | ||||
|     ); | ||||
|  | ||||
							
								
								
									
										623
									
								
								app/Home.js
									
									
									
									
									
								
							
							
						
						| @ -1,36 +0,0 @@ | ||||
| import React, { useState } from 'react'; | ||||
| import { | ||||
|   SafeAreaView, | ||||
|   StyleSheet, | ||||
|   ScrollView, | ||||
|   View, | ||||
|   Text, | ||||
|   StatusBar, | ||||
|   Modal, | ||||
|   TouchableHighlight, | ||||
|   Image, | ||||
| } from 'react-native'; | ||||
| 
 | ||||
| import { | ||||
|   Header, | ||||
|   LearnMoreLinks, | ||||
|   Colors, | ||||
|   DebugInstructions, | ||||
|   ReloadInstructions, | ||||
| } from 'react-native/Libraries/NewAppScreen'; | ||||
| import styles from './styles/morestyles' | ||||
| 
 | ||||
| const Images = { | ||||
|     sslopps: require('./assets/sslopps.png'), | ||||
|     lunch: require('./assets/lunch.png'), | ||||
|     settings:require('./assets/settings.png'), | ||||
|     challenge:require('./assets/challenge.png'), | ||||
|     student:require('./assets/student.png'), | ||||
|     announcements:require('./assets/announcements.png'), | ||||
|     resources:require('./assets/resources.png'), | ||||
|     polls:require('./assets/polls.png'), | ||||
|     notifs:require('./assets/notifs.png'), | ||||
|     lang:require('./assets/lang.png'), | ||||
| } | ||||
| 
 | ||||
| export default Images; | ||||
| @ -2,13 +2,13 @@ import React, { Component } from 'react'; | ||||
| import { DevSettings } from 'react-native'; | ||||
| import { Platform, StyleSheet, TouchableOpacity, Text, ScrollView, View } from 'react-native'; | ||||
| import I18n from './i18n'; | ||||
| import AsyncStorage from '@react-native-community/async-storage' | ||||
| import AsyncStorage from '@react-native-async-storage/async-storage' | ||||
| 
 | ||||
| const STORAGE_KEY = "language" | ||||
| 
 | ||||
| const language = [ | ||||
|       {lang: <Text>{I18n.t('language.English')}</Text>, code: "en"}, | ||||
|       {lang: <Text>{I18n.t('language.Spanish')}</Text>, code: "es"}, | ||||
|       {lang: <Text>English</Text>, code: "en-US"}, | ||||
|       {lang: <Text>Spanish</Text>, code: "es-US"}, | ||||
|     ] | ||||
| 
 | ||||
| export default class extends Component { | ||||
|  | ||||
| @ -7,7 +7,20 @@ export default { | ||||
|         Hobbies: "Hobbies", | ||||
|         Achievements: "Achievements", | ||||
|         Messages: "Messages", | ||||
|         Announcements: "Announcements" | ||||
|         Announcements: "Announcements", | ||||
|         noAnnouncements: "No Announcements", | ||||
|         lunch: "Lunch Events", | ||||
|         news: "News", | ||||
|         shortcut: "Shortcut: ", | ||||
|         seeLunch: "See Lunch Events", | ||||
|         noNews: "No news for today", | ||||
|         noAnnouncements: "No announcements for today", | ||||
|         moreOn: "More on" | ||||
|     }, | ||||
|     dates: { | ||||
|         today: "Today", | ||||
|         past: "Past", | ||||
|         future: "Future" | ||||
|     }, | ||||
|     app: { | ||||
|         home: "Home", | ||||
| @ -17,7 +30,12 @@ export default { | ||||
|         more: "More" | ||||
|     }, | ||||
|     calendar: { | ||||
|         calendarEvents: "Calendar Events" | ||||
|         calendar: "Calendar", | ||||
|         info: "Info", | ||||
|         location: "Location", | ||||
|         date: "Date", | ||||
|         organizer: "Organizer", | ||||
|         noEvents: "No Events" | ||||
|     }, | ||||
|     clubs: { | ||||
|         searchClubs: "Search Clubs" | ||||
| @ -25,12 +43,27 @@ export default { | ||||
|     staff: { | ||||
|         searchStaff: "Search Staff" | ||||
|     }, | ||||
|     announcements: { | ||||
|         noAnnouncements: "No Announcements" | ||||
|     }, | ||||
|     student: { | ||||
|         Grade: "Grade", | ||||
|         Hobbies: "Hobbies", | ||||
|         Achievements: "Achievements", | ||||
|         Messages: "Messages", | ||||
|     }, | ||||
|     lunch: { | ||||
|         information: "Information", | ||||
|         location: "Location" | ||||
|     }, | ||||
|     ssl: { | ||||
|         information: "Information", | ||||
|         sponsor: "Sponsor", | ||||
|         location: "Location" | ||||
|     }, | ||||
|     challenge: { | ||||
|         link: "Link" | ||||
|     }, | ||||
|     polls: { | ||||
|         textInPoll: "Press the image to take the poll!" | ||||
|     }, | ||||
| @ -38,7 +71,7 @@ export default { | ||||
|         Announcements: "Announcements", | ||||
|         Resources: "Resources", | ||||
|         SOTW: "Student of the Week", | ||||
|         lunch: "LunchEvents", | ||||
|         lunch: "Lunch Events", | ||||
|         ssl: "SSL Opportunities", | ||||
|         COTW: "Challenge of the Week", | ||||
|         Polls: "Polls", | ||||
|  | ||||
| @ -7,7 +7,20 @@ export default { | ||||
|         Hobbies: "El pasatiempo", | ||||
|         Achievements: "Logros", | ||||
|         Messages: "Mensajes", | ||||
|         Announcements: "Anuncios" | ||||
|         Announcements: "Anuncios", | ||||
|         noAnnouncements: "ESNo Announcements", | ||||
|         lunch: "Eventos de almuerzo", | ||||
|         news: "ESNews", | ||||
|         shortcut: "ESShortcut: ", | ||||
|         seeLunch: "ESSee Lunch Events", | ||||
|         noNews: "ESNo news for today", | ||||
|         noAnnouncements: "ESNo announcements for today", | ||||
|         moreOn: "ESMore on" | ||||
|     }, | ||||
|     dates: { | ||||
|         today: "ESToday", | ||||
|         past: "ESPast", | ||||
|         future: "ESFuture" | ||||
|     }, | ||||
|     app: { | ||||
|         home: "Casa", | ||||
| @ -17,7 +30,12 @@ export default { | ||||
|         more: "Más" | ||||
|     }, | ||||
|     calendar: { | ||||
|         calendarEvents: "Eventos del calendario" | ||||
|         calendar: "ESCalendar", | ||||
|         info: "ESInfo", | ||||
|         location: "ESLocation", | ||||
|         date: "ESDate", | ||||
|         organizer: "ESOrganizer", | ||||
|         noEvents: "ESNo Events" | ||||
|     }, | ||||
|     clubs: { | ||||
|         searchClubs: "Buscar clubes" | ||||
| @ -25,12 +43,27 @@ export default { | ||||
|     staff: { | ||||
|         searchStaff: "Personal de búsqueda" | ||||
|     }, | ||||
|     announcements: { | ||||
|         noAnnouncements: "ESNo Announcements" | ||||
|     }, | ||||
|     student: { | ||||
|         Grade: "El año", | ||||
|         Hobbies: "El pasatiempo", | ||||
|         Achievements: "Logros", | ||||
|         Messages: "Mensajes", | ||||
|     }, | ||||
|     lunch: { | ||||
|         information: "ESInformation", | ||||
|         location: "ESLocation" | ||||
|     }, | ||||
|     ssl: { | ||||
|         information: "ESInformation", | ||||
|         sponsor: "ESSponsor", | ||||
|         location: "ESLocation" | ||||
|     }, | ||||
|     challenge: { | ||||
|         link: "ESLink" | ||||
|     }, | ||||
|     polls: { | ||||
|         textInPoll: "¡Pulsa la imagen para realizar la encuesta!'" | ||||
|     }, | ||||
|  | ||||
| @ -9,6 +9,7 @@ import { | ||||
|   FlatList, | ||||
|   TouchableOpacity, | ||||
|   Image, | ||||
|   Dimensions | ||||
| } from 'react-native'; | ||||
| 
 | ||||
| import { | ||||
| @ -22,9 +23,12 @@ import { NavigationContainer } from '@react-navigation/native' | ||||
| import { createStackNavigator } from '@react-navigation/stack' | ||||
| import styles from './styles/liststyles' | ||||
| import { url } from './resources/fetchInfo.json' | ||||
| import LinearGradient from 'react-native-linear-gradient'; | ||||
| import Ionicons from 'react-native-vector-icons/Ionicons'; | ||||
| import I18n from 'i18n-js'; | ||||
| const Stack = createStackNavigator(); | ||||
| 
 | ||||
| export const LunchInfo = ({route}) => { | ||||
| {/*export const LunchInfo = ({route}) => { | ||||
|     const item = route.params; | ||||
|     return ( | ||||
|       <View style = {{padding: 10, backgroundColor: 'white', height: '100%'}}> | ||||
| @ -46,17 +50,22 @@ export const LunchInfo = ({route}) => { | ||||
|         </View> | ||||
|       </View> | ||||
|     ) | ||||
| } | ||||
| }*/} | ||||
| 
 | ||||
| function LunchEvent (props) { | ||||
|     const item = props.item | ||||
|     const [expand, setExpand] = useState(false); | ||||
|     return( | ||||
|         <View> | ||||
|             <TouchableOpacity style={styles.item1} onPress={()=>props.navigation.navigate('LunchInfo', {data:props.data,name:item.title,text:item.text,loc:item.loc})} activeOpacity={0.8}> | ||||
|             <View style = {{display: 'flex', flexDirection: 'row', alignItems: 'center'}}> | ||||
|                 <Image source = {require('./assets/lunch.png')} style = {{height: 40, width: 40, marginRight: 10}}/> | ||||
|                 <Text style={styles.title3}>{item.title}</Text> | ||||
|             </View> | ||||
|             <TouchableOpacity style={styles.listItem} onPress={()=>setExpand(!expand)}> | ||||
|                 <View style={styles.container2}> | ||||
|                     <Ionicons name="fast-food-outline" size={36} color={'#323232'} style={{marginRight: 15}} /> | ||||
|                     <View style = {styles.accordian}> | ||||
|                         <Text style={styles.title}>{item.title}</Text> | ||||
|                         {expand?<LinearGradient start={{x: 0, y: 0.25}} end={{x: .5, y: 1}} colors={['red', '#FF7373']} style={{borderRadius: 24, alignSelf: 'center'}}><Image source = {require('./assets/collapse.png')} style={{tintColor: 'white'}}/></LinearGradient>:<Image source = {require('./assets/expand.png')} style={{tintColor: '#b2b2b2', alignSelf: 'center'}}/>} | ||||
|                     </View> | ||||
|                 </View> | ||||
|                 {expand?<View style={{marginLeft: 50}}><Text style={styles.accordianHeader}>{I18n.t('lunch.information')}</Text><Text style={styles.accordianText}>{item.text}</Text><Text style={styles.accordianHeader}>{'\n'}{I18n.t('lunch.location')}</Text><Text style={[styles.accordianText, {paddingBottom: '4%'}]}>{item.loc}</Text></View>:<></>} | ||||
|             </TouchableOpacity> | ||||
|         </View> | ||||
|     ) | ||||
| @ -89,13 +98,13 @@ class LunchEvents extends React.Component { | ||||
|      | ||||
|     render() { | ||||
|         return ( | ||||
|             <View style={styles.container}> | ||||
|             <ScrollView style={styles.moreDefault}> | ||||
|                 <FlatList | ||||
|                     data={this.state.data} | ||||
|                     renderItem={({item}) => <LunchEvent item={item} name={this.props.title} navigation={this.props.navigation}/>} | ||||
|                     keyExtractor={item=>JSON.stringify(item)} | ||||
|                 /> | ||||
|             </View> | ||||
|             </ScrollView> | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										193
									
								
								app/More.js
									
									
									
									
									
								
							
							
						
						| @ -9,6 +9,7 @@ import { | ||||
|   FlatList, | ||||
|   TouchableOpacity, | ||||
|   Image, | ||||
|   Dimensions | ||||
| } from 'react-native'; | ||||
| 
 | ||||
| import { | ||||
| @ -20,7 +21,7 @@ import { | ||||
| } from 'react-native/Libraries/NewAppScreen'; | ||||
| 
 | ||||
| import { NavigationContainer } from '@react-navigation/native' | ||||
| import { createStackNavigator } from '@react-navigation/stack' | ||||
| import { createStackNavigator, HeaderBackButton } from '@react-navigation/stack' | ||||
| 
 | ||||
| import styles from './styles/morestyles' | ||||
| import Announcements, {TeacherList} from './Announcements' | ||||
| @ -29,10 +30,10 @@ import StudentWeek from './StudentWeek' | ||||
| import SSLOps, {SSLInfo} from './SSLOps' | ||||
| import LunchEvents, {LunchInfo} from './LunchEvents' | ||||
| import ChallengeWeek from './ChallengeWeek' | ||||
| import Settings from './Settings' | ||||
| import Poll from './Poll' | ||||
| import Images from './Images' | ||||
| import Language from './Language' | ||||
| import LinearGradient from 'react-native-linear-gradient' | ||||
| import Ionicons from 'react-native-vector-icons/Ionicons'; | ||||
| import I18n from './i18n'; | ||||
| 
 | ||||
| const Stack = createStackNavigator() | ||||
| @ -45,23 +46,27 @@ class MoreSwitch extends React.Component { | ||||
| 	 | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<View style={{flex:1,backgroundColor:'red'}}> | ||||
| 			<View style={{flex:1,backgroundColor:'white', paddingHorizontal: '5%'}}> | ||||
| 				<FlatList | ||||
| 					data={[ | ||||
| 						{name:'Announcements',key:"announce", img:Images.announcements}, | ||||
| 						{name:"Resources",key:"resources", img:Images.resources}, | ||||
| 						{name:"SOTW",key:"studentweek", img:Images.student}, | ||||
| 						{name:"lunch",key:"lunchevent", img:Images.lunch}, | ||||
| 						{name:"ssl",key:"sslopps", img:Images.sslopps}, | ||||
| 						{name:"COTW",key:"challengeweek", img:Images.challenge}, | ||||
| 						{name:"Polls", key:"polls", img: Images.polls}, | ||||
| 						{name:"Settings", key:"settings", img: Images.settings}, | ||||
| 						{name:I18n.t("more.Announcements"),key:"announce", img:"megaphone-outline"}, | ||||
| 						{name:I18n.t("more.Resources"),key:"resources", img:"newspaper-outline"}, | ||||
| 						{name:I18n.t("more.SOTW"),key:"studentweek", img:"ribbon-outline"}, | ||||
| 						{name:I18n.t("more.lunch"),key:"lunchevent", img:"fast-food-outline"}, | ||||
| 						{name:I18n.t("more.ssl"),key:"sslopps", img:"school-outline"}, | ||||
| 						{name:I18n.t("more.COTW"),key:"challengeweek", img:"golf-outline"}, | ||||
| 						{name:I18n.t("more.Polls"), key:"polls", img: "stats-chart-outline"}, | ||||
| 						{name:I18n.t("more.Settings"), key:"settings", img: "settings-outline"}, | ||||
| 					]} | ||||
| 					renderItem={({item})=> | ||||
| 						 | ||||
| 						<TouchableOpacity style={styles.moreitem} onPress={()=>this.props.navigation.navigate(item.key)}> | ||||
| 							<Image source = {item.img} style = {{height: 40, width: 40, marginRight: 10, tintColor: '#e3e3e3'}}/> | ||||
| 							<Text style={styles.moretext}>{I18n.t('more.'+item.name)}</Text> | ||||
| 							<Ionicons name={item.img} size={36} color={'#323232'}style={{marginRight: 15}}/> | ||||
| 							<View style={{display: 'flex', flexDirection: 'row', justifyContent: 'space-between', width: '85%'}}> | ||||
| 								<Text style={styles.moretext}>{item.name}</Text> | ||||
| 								<Image source = {require('./assets/forward.png')} style={{tintColor: '#b2b2b2'}}/> | ||||
| 							</View> | ||||
| 							 | ||||
| 						</TouchableOpacity> | ||||
| 					} | ||||
| 				/> | ||||
| @ -70,6 +75,35 @@ class MoreSwitch extends React.Component { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| class SettingSwitch extends React.Component { | ||||
| 	constructor(props) { | ||||
| 		super(props) | ||||
| 		this.props = props | ||||
| 	} | ||||
| 	 | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<View style={{flex:1,backgroundColor:'white', paddingHorizontal: '5%'}}> | ||||
| 				<FlatList | ||||
| 					data={[ | ||||
| 						{name:"Language",key:"language", img:'language-outline'} | ||||
| 					]} | ||||
| 					renderItem={({item})=> | ||||
| 						<TouchableOpacity style={styles.moreitem} onPress={()=>this.props.navigation.navigate(item.key)}> | ||||
| 							<Ionicons name={item.img} size={36} color={'#323232'}style={{marginRight: 15}}/> | ||||
| 							<View style={{display: 'flex', flexDirection: 'row', justifyContent: 'space-between', width: '85%'}}> | ||||
| 								<Text style={styles.moretext}>{I18n.t('settings.' + item.key)}</Text> | ||||
| 								<Image source = {require('./assets/forward.png')} style={{tintColor: '#b2b2b2'}}/> | ||||
| 							</View> | ||||
| 						</TouchableOpacity> | ||||
| 					} | ||||
| 				/> | ||||
| 			</View> | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| const background = (<LinearGradient | ||||
|                     colors={['#f99', 'white']} | ||||
|                     style = {{flex:1,borderBottomColor:'black',borderBottomWidth:0.5}} | ||||
| @ -84,119 +118,140 @@ class More extends React.Component { | ||||
| 						name="Chooser"  | ||||
| 						component={MoreSwitch} | ||||
| 						options={{ | ||||
| 							title:I18n.t('more.More'), | ||||
| 							title:I18n.t("more.More"), | ||||
| 							headerTitleStyle:styles.headerTitle, | ||||
| 							headerBackground: ()=>background | ||||
| 							headerBackground: ()=>background, | ||||
| 							headerTitleAlign: 'center' | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="announce"  | ||||
| 						component={Announcements} | ||||
| 						options={{ | ||||
| 							title:I18n.t('more.Announcements'), | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center'}], | ||||
| 							headerLeft:null, | ||||
| 							headerBackground: ()=>background | ||||
| 							title:I18n.t("more.Announcements"), | ||||
| 							headerTitleStyle:[styles.headerTitle], | ||||
| 							headerBackground: ()=>background, | ||||
| 							headerTitleAlign: 'center', | ||||
| 							headerBackTitleVisible:false, | ||||
| 							headerTintColor: 'black' | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="resources"  | ||||
| 						component={Resources} | ||||
| 						options={{ | ||||
| 							title:I18n.t('more.Resources'), | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center'}], | ||||
| 							headerLeft:null, | ||||
| 							headerBackground: ()=>background | ||||
| 							title:I18n.t("more.Resources"), | ||||
| 							headerTitleStyle:styles.headerTitle, | ||||
| 							//headerLeft:null,
 | ||||
| 							headerBackground: ()=>background, | ||||
| 							headerTitleAlign: 'center', | ||||
| 							headerBackTitleVisible:false, | ||||
| 							headerTintColor: 'black' | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="studentweek"  | ||||
| 						component={StudentWeek} | ||||
| 						options={{ | ||||
| 							title:I18n.t('more.SOTW'), | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center'}], | ||||
| 							headerLeft:null, | ||||
| 							headerBackground: ()=>background | ||||
| 							title:I18n.t("more.SOTW"), | ||||
| 							headerTitleStyle:styles.headerTitle, | ||||
| 							//headerLeft:null,
 | ||||
| 							headerBackground: ()=>background, | ||||
| 							headerTitleAlign: 'center', | ||||
| 							headerBackTitleVisible:false, | ||||
| 							headerTintColor: 'black' | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="lunchevent"  | ||||
| 						component={LunchEvents} | ||||
| 						options={{ | ||||
| 							title:I18n.t('more.lunch'), | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center'}], | ||||
| 							headerLeft:null, | ||||
| 							headerBackground: ()=>background | ||||
| 							title:I18n.t("more.lunch"), | ||||
| 							headerTitleStyle:styles.headerTitle, | ||||
| 							//headerLeft:null,
 | ||||
| 							headerBackground: ()=>background, | ||||
| 							headerTitleAlign: 'center', | ||||
| 							headerBackTitleVisible:false, | ||||
| 							headerTintColor: 'black' | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="sslopps"  | ||||
| 						component={SSLOps} | ||||
| 						options={{ | ||||
| 							title:I18n.t('more.ssl'), | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center'}], | ||||
| 							headerLeft:null, | ||||
| 							headerBackground: ()=>background | ||||
| 							title:I18n.t("more.ssl"), | ||||
| 							headerTitleStyle:styles.headerTitle, | ||||
| 							//headerLeft:null,
 | ||||
| 							headerBackground: ()=>background, | ||||
| 							headerTitleAlign: 'center', | ||||
| 							headerBackTitleVisible:false, | ||||
| 							headerTintColor: 'black' | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="challengeweek"  | ||||
| 						component={ChallengeWeek} | ||||
| 						options={{ | ||||
| 							title:I18n.t('more.COTW'), | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center'}], | ||||
| 							headerLeft:null, | ||||
| 							headerBackground: ()=>background | ||||
| 							title:I18n.t("more.COTW"), | ||||
| 							headerTitleStyle:styles.headerTitle, | ||||
| 							//headerLeft:null,
 | ||||
| 							headerBackground: ()=>background, | ||||
| 							headerTitleAlign: 'center', | ||||
| 							headerBackTitleVisible:false, | ||||
| 							headerTintColor: 'black' | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="polls"  | ||||
| 						component={Poll} | ||||
| 						options={{ | ||||
| 							title:I18n.t('more.Polls'), | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center'}], | ||||
| 							headerLeft:null, | ||||
| 							headerBackground: ()=>background | ||||
| 							title:I18n.t("more.Polls"), | ||||
| 							headerTitleStyle:styles.headerTitle, | ||||
| 							//headerLeft:null,
 | ||||
| 							headerBackground: ()=>background, | ||||
| 							headerTitleAlign: 'center', | ||||
| 							headerBackTitleVisible:false, | ||||
| 							headerTintColor: 'black' | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="settings"  | ||||
| 						component={Settings} | ||||
| 						component={SettingSwitch} | ||||
| 						options={{ | ||||
| 							title:I18n.t('more.Settings'), | ||||
| 							title:I18n.t("more.Settings"), | ||||
| 							headerTitleStyle:[styles.headerTitle], | ||||
| 							//headerLeft:null,
 | ||||
| 							headerBackground: ()=>background, | ||||
| 							headerBackTitleVisible:false, | ||||
| 							headerTintColor: 'black', | ||||
| 							headerTitleAlign: 'center' | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="language"  | ||||
| 						component={Language} | ||||
| 						options={{ | ||||
| 							title:I18n.t("settings.language"), | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center'}], | ||||
| 							headerLeft:null, | ||||
| 							headerBackground: ()=>background | ||||
| 							headerBackground: ()=>background, | ||||
| 							//headerLeft: null,
 | ||||
| 							headerBackTitleVisible:false, | ||||
| 							headerTintColor: 'black', | ||||
| 							headerTitleAlign: 'center' | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="TeacherList"  | ||||
| 						component={TeacherList} | ||||
| 						options={({route})=>({ | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center',fontSize:Math.min(24,24*23/route.params.name.length)}], | ||||
| 							headerTitleStyle:[styles.headerTitle], | ||||
| 							title:route.params.name, | ||||
| 							headerRight:()=>(<></>), | ||||
| 							headerBackground: ()=>background | ||||
| 						})} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="LunchInfo"  | ||||
| 						component={LunchInfo} | ||||
| 						options={({route})=>({ | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center',fontSize:Math.min(24,24*23/route.params.name.length)}], | ||||
| 							title:route.params.name, | ||||
| 							headerRight:()=>(<></>), | ||||
| 							headerBackground: ()=>background | ||||
| 						})} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="SSLInfo"  | ||||
| 						component={SSLInfo} | ||||
| 						options={({route})=>({ | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center',fontSize:Math.min(24,24*23/route.params.name.length)}], | ||||
| 							title:route.params.name, | ||||
| 							headerBackground: ()=>background, | ||||
| 							headerRight:()=>(<></>) | ||||
| 							headerBackTitleVisible:false, | ||||
| 							headerTintColor: 'black', | ||||
| 							headerTitleAlign: 'center' | ||||
| 							//headerLeft: null,
 | ||||
| 						})} | ||||
| 					/> | ||||
| 				</Stack.Navigator> | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import React, { Component, useState } from 'react'; | ||||
| /*import React, { Component, useState } from 'react'; | ||||
| import {  | ||||
|     Platform,  | ||||
|     StyleSheet,  | ||||
| @ -119,4 +119,4 @@ class Notifications extends Component { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export default Notifications | ||||
| export default Notifications*/ | ||||
							
								
								
									
										44
									
								
								app/Poll.js
									
									
									
									
									
								
							
							
						
						| @ -1,4 +1,4 @@ | ||||
| import React from 'react'; | ||||
| /*import React from 'react'; | ||||
| import { | ||||
|   SafeAreaView, | ||||
|   StyleSheet, | ||||
| @ -21,7 +21,7 @@ import {WebView} from 'react-native-webview'; | ||||
| import LinearGradient from 'react-native-linear-gradient'; | ||||
| import { Linking } from 'react-native'; | ||||
| import { url } from './resources/fetchInfo.json' | ||||
| import I18n from './i18n'; | ||||
| //import I18n from './i18n';
 | ||||
| 
 | ||||
| class Poll extends React.Component { | ||||
| 
 | ||||
| @ -47,7 +47,7 @@ componentDidMount() { | ||||
|     }) | ||||
|     .catch((error) => console.error(error)) | ||||
| }*/ | ||||
| 
 | ||||
| /* | ||||
| 	render() { | ||||
| 		return ( | ||||
|       <View style = {{backgroundColor: 'white'}}> | ||||
| @ -55,11 +55,47 @@ componentDidMount() { | ||||
|           <TouchableOpacity  onPress={()=>Linking.openURL("https://google.com")}> | ||||
|             <Image source={require('./assets/polls.png')} style={{marginTop: 50, height: 300, width: 300, tintColor: 'red'}}/> | ||||
|           </TouchableOpacity> | ||||
|           <Text style ={{fontSize: 20, marginTop: 30}}>{I18n.t('polls.textInPoll')}</Text> | ||||
|           <Text style ={{fontSize: 20, marginTop: 30}}>Take A Poll!</Text> | ||||
|         </View> | ||||
|       </View> | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| export default Poll;*/ | ||||
| import React from 'react'; | ||||
| import { | ||||
|   SafeAreaView, | ||||
|   StyleSheet, | ||||
|   ScrollView, | ||||
|   View, | ||||
|   Text, | ||||
|   StatusBar, | ||||
| } from 'react-native'; | ||||
| 
 | ||||
| import { | ||||
|   Header, | ||||
|   LearnMoreLinks, | ||||
|   Colors, | ||||
|   DebugInstructions, | ||||
|   ReloadInstructions, | ||||
| } from 'react-native/Libraries/NewAppScreen'; | ||||
| import {WebView} from 'react-native-webview'; | ||||
| class Poll extends React.Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<WebView | ||||
|         source = {{uri: 'https://docs.google.com/forms/d/e/1FAIpQLSfR0XP2yo3TV3egz7aMok56wnP9kG4FQt2v3rHrrayf8uC7Vw/viewform?usp=sf_link'}} | ||||
|         javaScriptEnabled={true} | ||||
|         domStorageEnabled={true} | ||||
|         startInLoadingState={true} | ||||
|         style={{marginTop: 0}} | ||||
|         cacheEnabled={true} | ||||
|          | ||||
|       /> | ||||
|        | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| export default Poll; | ||||
| @ -8,7 +8,8 @@ import { | ||||
|   StatusBar, | ||||
|   Linking, | ||||
|   Image, | ||||
|   TouchableOpacity | ||||
|   TouchableOpacity, | ||||
|   Dimensions | ||||
| } from 'react-native'; | ||||
| 
 | ||||
| import { | ||||
| @ -20,27 +21,37 @@ import { | ||||
| } from 'react-native/Libraries/NewAppScreen'; | ||||
| import styles from './styles/morestyles'; | ||||
| 
 | ||||
| const windowWidth = Dimensions.get('window').width*.80/3.5; | ||||
| 
 | ||||
| function ResourceLink(props) {  | ||||
| 	return ( | ||||
| 		<TouchableOpacity style={styles.resourceContainer} onPress={() => Linking.openURL(props.url)}> | ||||
|           <Image source={props.img} style={styles.image}/> | ||||
| 		      <View style={styles.textContainer}> | ||||
|             <Text style={styles.resourceText}>{props.name}</Text>  | ||||
|           </View>		   | ||||
|         </TouchableOpacity> | ||||
| 		<TouchableOpacity style={styles.resourceContainer, {paddingHorizontal: '5%', paddingBottom: '5%'}} onPress={() => Linking.openURL(props.url)}> | ||||
|       <View style={{display: 'flex', textAlign: 'center', width: windowWidth}}> | ||||
|         <View style={{aspectRatio: 1}}> | ||||
|           <Image source={props.img} style={{width: '100%', height: '100%', borderRadius: 30}}/> | ||||
|         </View> | ||||
|         <Text style={{color: 'black', alignSelf: 'center', textAlign: 'center', marginTop: '2%', fontSize: 16}}>{props.name}</Text> | ||||
|       </View> | ||||
|     </TouchableOpacity> | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| class Resources extends React.Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<ScrollView style = {{backgroundColor: 'white'}}> | ||||
| 				<ResourceLink url='https://classroom.mcpsmd.org/' img={require('./assets/canvaslogo.png')} name='MyMCPS Classroom'/> | ||||
| 				<ResourceLink url='https://md-mcps-psv.edupoint.com/Home_PXP2.aspx' img={require('./assets/studentvue.jpg')} name='StudentVUE'/> | ||||
| 				<ResourceLink url='https://student.naviance.com/mbhs' img={require('./assets/naviance.png')} name='Naviance'/> | ||||
| 				<ResourceLink url='https://blairblazersathletics.com/' img={require('./assets/athletics.jpg')} name='Blair Athletics'/> | ||||
| 				<ResourceLink url='https://classroom.google.com/u/0/h' img={require('./assets/googleclassroom.jpg')} name='Google Classroom'/> | ||||
| 			</ScrollView> | ||||
|       <ScrollView style = {{backgroundColor: 'white'}}> | ||||
|         <View style = {{display: 'flex', flexDirection: 'row', flexWrap: 'wrap', paddingVertical: '5%'}}> | ||||
|           <ResourceLink url='https://classroom.mcpsmd.org/' img={require('./assets/canvas.jpeg')} name='MyMCPS Classroom'/> | ||||
|           <ResourceLink url='https://md-mcps-psv.edupoint.com/Home_PXP2.aspx' img={require('./assets/studentvue.png')} name='StudentVUE'/> | ||||
|           <ResourceLink url='https://student.naviance.com/mbhs' img={require('./assets/naviance.png')} name='Naviance'/> | ||||
|           <ResourceLink url='https://classroom.google.com/u/0/h' img={require('./assets/gc.png')} name='Google Classroom'/> | ||||
|           <ResourceLink url='https://mbhs.edu/' img={require('./assets/blair_logo.png')} name='MBHS'/> | ||||
|           <ResourceLink url='https://sites.google.com/mcpsmd.net/mbhs-schoolcounseling-team/home/mbhs-school-counseling-team' img={require('./assets/counselor.jpeg')} name='Counseling Team'/> | ||||
|           <ResourceLink url='http://bnconline.net/c/infoflow/' img={require('./assets/infoflow.jpeg')} name='Infoflow'/> | ||||
|           <ResourceLink url='https://silverchips.mbhs.edu/' img={require('./assets/sco.jpeg')} name='Silver Chips Online'/> | ||||
| 			  </View> | ||||
|       </ScrollView> | ||||
| 			 | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -9,6 +9,7 @@ import { | ||||
|   FlatList, | ||||
|   TouchableOpacity, | ||||
|   Image, | ||||
|   Dimensions | ||||
| } from 'react-native'; | ||||
| 
 | ||||
| import { | ||||
| @ -22,11 +23,13 @@ import { NavigationContainer } from '@react-navigation/native' | ||||
| import { createStackNavigator } from '@react-navigation/stack' | ||||
| import styles from './styles/liststyles'; | ||||
| import { url } from './resources/fetchInfo.json'; | ||||
| import LinearGradient from 'react-native-linear-gradient'; | ||||
| import Ionicons from 'react-native-vector-icons/Ionicons'; | ||||
| import I18n from './i18n'; | ||||
| 
 | ||||
| const Stack = createStackNavigator(); | ||||
| 
 | ||||
| export const SSLInfo = ({route}) => { | ||||
| {/*export const SSLInfo = ({route}) => { | ||||
| 	const item = route.params; | ||||
| 	console | ||||
| 	return ( | ||||
| @ -57,17 +60,22 @@ export const SSLInfo = ({route}) => { | ||||
| 			</View> | ||||
| 		</View> | ||||
| 	) | ||||
|   } | ||||
|   }*/} | ||||
| 
 | ||||
| function SSLElement (props) { | ||||
| 	const item = props.item; | ||||
| 	const [expand, setExpand] = useState(false); | ||||
| 	return( | ||||
| 		<View> | ||||
| 			<TouchableOpacity style={styles.item1} onPress={()=>props.navigation.navigate('SSLInfo', {data: props.data, name: item.item.title, text: item.item.text, loc:item.item.loc, teacher: item.item.teacher})} activeOpacity={0.8}> | ||||
| 				<View style = {{display: 'flex', flexDirection: 'row', alignItems: 'center'}}> | ||||
| 					<Image source = {require('./assets/sslopps.png')} style = {{height: 40, width: 40, marginRight: 10}}/> | ||||
| 					<Text style={styles.title3}>{item.item.title}</Text> | ||||
| 			<TouchableOpacity style={styles.listItem} onPress={()=>setExpand(!expand)}> | ||||
| 				<View style = {styles.container2}> | ||||
| 					<Ionicons name="school-outline" size={36} color={'#323232'} style={{marginRight: 15}} /> | ||||
| 					<View style = {styles.accordian}> | ||||
|                         <Text style={styles.title}>{item.item.title}</Text> | ||||
|                         {expand?<LinearGradient start={{x: 0, y: 0.25}} end={{x: .5, y: 1}} colors={['red', '#FF7373']} style={{borderRadius: 24, alignSelf: 'center'}}><Image source = {require('./assets/collapse.png')} style={{tintColor: 'white'}}/></LinearGradient>:<Image source = {require('./assets/expand.png')} style={{tintColor: '#b2b2b2', alignSelf: 'center'}}/>} | ||||
|                     </View> | ||||
| 				</View> | ||||
| 				{expand?<View style={{marginLeft: 50}}><Text style={styles.accordianHeader}>{I18n.t('ssl.information')}</Text><Text style={styles.accordianText}>{item.item.text}</Text><Text style={styles.accordianHeader}>{'\n'}{I18n.t('ssl.sponsor')}</Text><Text style={styles.accordianText}>{item.item.teacher}</Text><Text style={styles.accordianHeader}>{'\n'}{I18n.t('ssl.location')}</Text><Text style={[styles.accordianText, {paddingBottom: '4%'}]}>{item.item.loc}</Text></View>:<></>} | ||||
| 			</TouchableOpacity> | ||||
| 		</View> | ||||
|     ) | ||||
| @ -100,13 +108,14 @@ class SSLOps extends React.Component { | ||||
| 	 | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<View style={styles.container}> | ||||
| 			<ScrollView style={styles.moreDefault}> | ||||
| 				<FlatList | ||||
| 					data={this.state.data} | ||||
| 					renderItem={item=><SSLElement item={item} name={item.title} navigation={this.props.navigation}/>} | ||||
| 					keyExtractor={item=>JSON.stringify(item)} | ||||
| 				/> | ||||
| 			</View> | ||||
| 			</ScrollView> | ||||
| 			 | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
|  | ||||
							
								
								
									
										106
									
								
								app/Settings.js
									
									
									
									
									
								
							
							
						
						| @ -1,106 +0,0 @@ | ||||
| import React from 'react'; | ||||
| import { | ||||
|   SafeAreaView, | ||||
|   StyleSheet, | ||||
|   ScrollView, | ||||
|   View, | ||||
|   Text, | ||||
|   StatusBar, | ||||
|   Modal, | ||||
|   TouchableHighlight, | ||||
|   Image, | ||||
|   FlatList, | ||||
|   TouchableOpacity, | ||||
| } from 'react-native'; | ||||
| 
 | ||||
| import { | ||||
|   Header, | ||||
|   LearnMoreLinks, | ||||
|   Colors, | ||||
|   DebugInstructions, | ||||
|   ReloadInstructions, | ||||
| } from 'react-native/Libraries/NewAppScreen'; | ||||
| 
 | ||||
| import styles from './styles/morestyles' | ||||
| import LinearGradient from 'react-native-linear-gradient' | ||||
| import Images from './Images' | ||||
| import { NavigationContainer } from '@react-navigation/native' | ||||
| import { createStackNavigator } from '@react-navigation/stack' | ||||
| import I18n from './i18n'; | ||||
| import Language from './Language' | ||||
| import Notifications from './Notifications' | ||||
| 
 | ||||
| const Stack = createStackNavigator() | ||||
| 
 | ||||
| class SettingSwitch extends React.Component { | ||||
| 	constructor(props) { | ||||
| 		super(props) | ||||
| 		this.props = props | ||||
| 	} | ||||
| 	 | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<View style={{flex:1,backgroundColor:'red'}}> | ||||
| 				<FlatList | ||||
| 					data={[ | ||||
| 						{name:"Language",key:"language", img:Images.lang}, | ||||
| 						{name:"Notifications",key:"notifications", img:Images.notifs}, | ||||
| 					]} | ||||
| 					renderItem={({item})=> | ||||
| 						<TouchableOpacity style={styles.moreitem} onPress={()=>this.props.navigation.navigate(item.key)}> | ||||
| 							<Image source = {item.img} style = {{height: 40, width: 40, marginRight: 10, tintColor: '#e3e3e3'}}/> | ||||
| 							<Text style={styles.moretext}>{I18n.t('settings.' + item.key)}</Text> | ||||
| 						</TouchableOpacity> | ||||
| 					} | ||||
| 				/> | ||||
| 			</View> | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| const background = (<LinearGradient | ||||
|                     colors={['#f99', 'white']} | ||||
|                     style = {{flex:1,borderBottomColor:'black',borderBottomWidth:0.5}} | ||||
|                     />) | ||||
| 
 | ||||
| class Settings extends React.Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<NavigationContainer independent={true}> | ||||
| 				<Stack.Navigator> | ||||
| 					<Stack.Screen  | ||||
| 						name="Chooser"  | ||||
| 						component={SettingSwitch} | ||||
| 						options={{ | ||||
| 							title:'Settings', | ||||
| 							headerTitleStyle:styles.headerTitle, | ||||
| 							headerBackground: ()=>background | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="language"  | ||||
| 						component={Language} | ||||
| 						options={{ | ||||
| 							title:'Language', | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center'}], | ||||
| 							headerLeft:null, | ||||
| 							headerBackground: ()=>background | ||||
| 						}} | ||||
| 					/> | ||||
| 					<Stack.Screen  | ||||
| 						name="notifications"  | ||||
| 						component={Notifications} | ||||
| 						options={{ | ||||
| 							title:'Notifications', | ||||
| 							headerTitleStyle:[styles.headerTitle,{alignSelf:'center'}], | ||||
| 							headerLeft:null, | ||||
| 							headerBackground: ()=>background | ||||
| 						}} | ||||
| 					/> | ||||
| 				</Stack.Navigator> | ||||
| 			</NavigationContainer> | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| export default Settings; | ||||
							
								
								
									
										147
									
								
								app/Staff.js
									
									
									
									
									
								
							
							
						
						| @ -10,6 +10,7 @@ import { | ||||
|   FlatList, | ||||
|   TouchableOpacity, | ||||
|   Image, | ||||
|   TouchableHighlight, | ||||
|   Linking | ||||
| } from 'react-native'; | ||||
| 
 | ||||
| @ -20,43 +21,135 @@ import { | ||||
|   DebugInstructions, | ||||
|   ReloadInstructions, | ||||
| } from 'react-native/Libraries/NewAppScreen'; | ||||
| import { NavigationContainer } from '@react-navigation/native' | ||||
| import { createStackNavigator } from '@react-navigation/stack' | ||||
| import { SearchBar } from 'react-native-elements'; | ||||
| import styles from './styles/liststyles' | ||||
| import morestyles from './styles/morestyles' | ||||
| import { url } from './resources/fetchInfo.json' | ||||
| import LinearGradient from 'react-native-linear-gradient'; | ||||
| import Ionicons from 'react-native-vector-icons/Ionicons'; | ||||
| import I18n from './i18n'; | ||||
| 
 | ||||
| const StaffElement = ({item}) => { | ||||
|   const [visible, setVisible] = useState(false) | ||||
|   const extra = ( | ||||
|     [ | ||||
|       ...item.item.emails.map(email=>( | ||||
|       <View style={{display: 'flex', flexDirection: 'row', alignItems: 'center', marginTop: '2%', paddingHorizontal: '1%'}}> | ||||
|         <View style={{width: '10%', display: 'flex', justifyContent: 'center'}}> | ||||
|           <Image source={require('./assets/email.png')}  style={{height: 22, width: 22}}/> | ||||
|         </View> | ||||
|         <View style={{width: '90%'}}> | ||||
|           <Text key={email}><Text style={styles.linktext} onPress={()=>Linking.openURL("mailto:"+email)}><Text></Text>{email}</Text></Text> | ||||
| const Stack = createStackNavigator(); | ||||
| 
 | ||||
| export const StaffInfo = ({route}) => { | ||||
|   const item = route.params; | ||||
| 
 | ||||
|   console.log(item); | ||||
| 
 | ||||
|   return ( | ||||
|     /*<View style = {{padding: 10, backgroundColor: 'white', height: '100%'}}> | ||||
|       {item.emails.map(email => | ||||
|         <View style ={[styles.infoContainer, {flexDirection: 'row', alignItems: 'center'}]}> | ||||
|           <View style={{display: 'flex', justifyContent: 'center'}}> | ||||
|             <Ionicons name='mail-outline' size={28} style={{marginRight: 15}}/> | ||||
|           </View> | ||||
|           <View style={{}}> | ||||
|             <Text style = {{fontSize:16}}>{email}</Text> | ||||
|           </View> | ||||
|         </View> | ||||
|       )} | ||||
|     </View>*/ | ||||
|     <ScrollView style={{paddingTop:'5%',paddingHorizontal:'10%', backgroundColor: 'white', height: '100%'}}> | ||||
|       <View style={{backgroundColor: 'white',borderRadius: 150, height: 300, width: 300, alignSelf: 'center', shadowColor: 'red', shadowOffset: {width: 0, height: 2}, shadowOpacity: 0.5, shadowRadius: 7}}> | ||||
|         <Image style={{resizeMode: 'cover',borderRadius: 150, height: 300, width: 300, alignSelf: 'center'}} source = {{/* CHANGE */}} />  | ||||
|       </View> | ||||
|       )) | ||||
|     ] | ||||
|       <Text style={{fontSize:28,marginTop:'5%',textAlign:'center'}}>{item.name}</Text> | ||||
|       <Text style={{fontSize:20,textAlign:'center', fontWeight: '200'}}>{item.position || ""}</Text> | ||||
|        | ||||
|       {item.emails && | ||||
|         <View style={{display: 'flex', padding:'2%', borderRadius: 8, marginTop:'5%'}}> | ||||
|           <View style={{display:'flex', flexDirection: 'row'}}> | ||||
|             <Ionicons name='mail-outline' size={28} style={{marginRight: 15}}/> | ||||
|             <View style = {{display: 'flex', flexDirection: 'row', width: '85%', justifyContent: 'space-between', paddingHorizontal:'2%',}}> | ||||
|               <Text style={{fontSize: 20,  alignSelf: 'center'}}>{"Email"}</Text> | ||||
|             </View> | ||||
|           </View> | ||||
|           <Text style = {{marginLeft: 50, paddingHorizontal: '2%', paddingBottom: '2%'}}> | ||||
|             {item.emails.map(email => | ||||
|               <Text key={email}>{email}</Text> | ||||
|             )} | ||||
|           </Text> | ||||
|         </View> | ||||
|       } | ||||
|        | ||||
|       {item.phone && | ||||
|         <View style={{display: 'flex', padding:'2%', borderRadius: 8, marginTop:'5%'}}> | ||||
|           <View style={{display:'flex', flexDirection: 'row'}}> | ||||
|             <Ionicons name='call-outline' size={28} style={{marginRight: 15}}/> | ||||
|             <View style = {{display: 'flex', flexDirection: 'row', width: '85%', justifyContent: 'space-between', paddingHorizontal:'2%',}}> | ||||
|               <Text style={{fontSize: 20,  alignSelf: 'center'}}>{"Phone"}</Text> | ||||
|             </View> | ||||
|           </View> | ||||
|           <Text style = {{marginLeft: 50, paddingHorizontal: '2%', paddingBottom: '2%'}}> | ||||
|           {item.phone.map(num => | ||||
|             <Text key={num}>{num}</Text> | ||||
|           )} | ||||
|           </Text> | ||||
|         </View> | ||||
|       } | ||||
|     </ScrollView> | ||||
|   ) | ||||
|   //const extra = [...item.item.emails.map(email=>(<Text key={email}>{'\n'}Email: <Text style={styles.linktext} onPress={()=>Linking.openURL("mailto:"+email)}>{email}</Text></Text>))]
 | ||||
| } | ||||
| function StaffElement (props) { | ||||
|   const item = props.item; | ||||
|   return( | ||||
| 	<View> | ||||
| 	  <TouchableOpacity style={styles.item1} onPress={()=>setVisible(!visible)} activeOpacity={0.8}> | ||||
|     <View style = {{display: 'flex', flexDirection: 'row', alignItems: 'center'}}> | ||||
|       <Image source = {require('./assets/staff.png')} style = {{height: 40, width: 40, marginRight: 10}}/> | ||||
|       <Text style={styles.title3}>{item.item.name}</Text> | ||||
|     </View> | ||||
| 		{visible?extra:<></>} | ||||
| 	  </TouchableOpacity> | ||||
|       <TouchableOpacity style={[styles.listItem]} onPress={()=>props.navigation.navigate('StaffInfo', {data:props.data,name:props.name,emails:item.emails})} activeOpacity={0.8}> | ||||
|         <View style = {[styles.container2, {justifyContent: 'space-between'}]}> | ||||
|           <View style={{display: 'flex', flexDirection: 'row'}}>  | ||||
|             <Ionicons name = "ios-nutrition-outline" size={36} color={'#323232'} style={{marginRight: 15}} /> | ||||
|             <Text style={[styles.title, {alignSelf:'center'}]}>{props.item.name}</Text> | ||||
|           </View> | ||||
|           <Image source = {require('./assets/forward.png')} style={{tintColor: '#b2b2b2'}}/> | ||||
|         </View> | ||||
|       </TouchableOpacity> | ||||
| 	</View> | ||||
|   ) | ||||
| } | ||||
| class Staff extends React.Component { | ||||
| 
 | ||||
|    | ||||
| const background = (<LinearGradient | ||||
|   colors={['#f99', 'white']} | ||||
|   style = {{flex:1,borderBottomColor:'black',borderBottomWidth:0.5}} | ||||
|   />) | ||||
| 
 | ||||
| function Staff () { | ||||
|   return ( | ||||
|     <NavigationContainer independent={true}> | ||||
|       <Stack.Navigator> | ||||
|         <Stack.Screen  | ||||
|           name = "Staff" | ||||
|           component = {Staffs} | ||||
|           options={({ | ||||
|             headerShown: true, | ||||
|             headerTitleStyle:morestyles.headerTitle, | ||||
|             headerBackground: ()=>background, | ||||
|             //headerleft: null,
 | ||||
|             title:I18n.t('app.staff'), | ||||
|             headerBackTitleVisible:false, | ||||
|             headerTintColor: 'black', | ||||
|             headerTitleAlign: 'center' | ||||
|           })} | ||||
|         /> | ||||
|         <Stack.Screen  | ||||
|           name = "StaffInfo" | ||||
|           component = {StaffInfo} | ||||
|           options={({route})=>({ | ||||
|             title:route.params.name, | ||||
|             headerTitleStyle:[morestyles.headerTitle,{alignSelf:'center'}], | ||||
|             headerBackground: ()=>background, | ||||
|             headerBackTitleVisible:false, | ||||
|             headerTintColor: 'black', | ||||
|             headerTitleAlign: 'center', | ||||
|           })} | ||||
|         /> | ||||
|       </Stack.Navigator> | ||||
|     </NavigationContainer> | ||||
|   )  | ||||
| } | ||||
| 
 | ||||
| class Staffs extends React.Component { | ||||
| 	constructor(props) { | ||||
|     super(props); | ||||
| 
 | ||||
| @ -95,7 +188,7 @@ class Staff extends React.Component { | ||||
|   updateSearch = (search) => { | ||||
|     this.setState({ search:search }); | ||||
| 	const searchPool = search.startsWith(this.state.search)?this.state.dataSearch:this.state.data; | ||||
|     const ds = searchPool.filter((thing)=>{return thing.name.toLowerCase().split(' ').some(x=>x.startsWith(search.toLowerCase()))}) | ||||
|     const ds = searchPool.filter((thing)=>{return thing.name.toLowerCase().startsWith(search.toLowerCase())}) | ||||
|     this.setState({dataSearch: ds}) | ||||
|   }; | ||||
|   clearSearch  = (search)=>{ | ||||
| @ -104,8 +197,9 @@ class Staff extends React.Component { | ||||
|   } | ||||
|   render() { | ||||
|     const { data , dataSearch,search} = this.state; | ||||
| 
 | ||||
|     return ( | ||||
|       <SafeAreaView style={styles.container}> | ||||
|       <SafeAreaView style={styles.moreDefault}> | ||||
|         <SearchBar | ||||
|         lightTheme | ||||
|         placeholder={I18n.t('staff.searchStaff')} | ||||
| @ -115,10 +209,11 @@ class Staff extends React.Component { | ||||
|         value={this.state.search}/> | ||||
|       <FlatList | ||||
|         data={dataSearch} | ||||
|         renderItem={item => <StaffElement item={item}/>} | ||||
|         renderItem={({item}) => <StaffElement item={item} name={item.name} navigation={this.props.navigation}/>} | ||||
|         keyExtractor={item => JSON.stringify(item)} | ||||
|       /> | ||||
|     </SafeAreaView> | ||||
|      | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import React from 'react'; | ||||
| import React, { useState } from 'react'; | ||||
| import { | ||||
|   SafeAreaView, | ||||
|   StyleSheet, | ||||
| @ -7,6 +7,7 @@ import { | ||||
|   Text, | ||||
|   StatusBar, | ||||
|   Image, | ||||
|   TouchableOpacity | ||||
| } from 'react-native'; | ||||
| 
 | ||||
| import { | ||||
| @ -18,14 +19,35 @@ import { | ||||
| } from 'react-native/Libraries/NewAppScreen'; | ||||
| import I18n from './i18n'; | ||||
| import { url } from './resources/fetchInfo.json' | ||||
| import LinearGradient from 'react-native-linear-gradient'; | ||||
| 
 | ||||
| class StudentWeek extends React.Component { | ||||
| 	constructor(props) { | ||||
| 		super(props) | ||||
| 		this.state = { | ||||
| 			isLoading: true | ||||
| 			isLoading: true, | ||||
| 			hobbyExpanded: false, | ||||
| 			achievementExpanded: false, | ||||
| 			messageExpanded: false, | ||||
| 			hobbyArrow:require('./assets/expand.png'), | ||||
| 			achievementArrow:require('./assets/expand.png'), | ||||
| 			messageArrow:require('./assets/expand.png') | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	clickHobby() { | ||||
| 		if (!this.state.hobbyExpanded) this.setState({hobbyExpanded:true, hobbyArrow: require('./assets/collapse.png')}); | ||||
| 		else this.setState({hobbyExpanded: false,hobbyArrow:require('./assets/expand.png')}); | ||||
| 	} | ||||
| 	clickAchievements() { | ||||
| 		if (!this.state.achievementExpanded) this.setState({achievementExpanded:true, achievementArrow: require('./assets/collapse.png')}); | ||||
| 		else this.setState({achievementExpanded: false, achievementArrow:require('./assets/expand.png')}); | ||||
| 	} | ||||
| 	clickMessages() { | ||||
| 		if (!this.state.messageExpanded) this.setState({messageExpanded:true, messageArrow: require('./assets/collapse.png')}); | ||||
| 		else this.setState({messageExpanded: false, messageArrow:require('./assets/expand.png')}); | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
| 	componentDidMount() { | ||||
| 		fetch(`${url}/api/en/student`,{ | ||||
| @ -44,35 +66,53 @@ class StudentWeek extends React.Component { | ||||
| 			return <View/> | ||||
| 		} else { | ||||
| 			const iconURI = this.state.data.icon !== undefined?`data:image/png;charset=utf-8;base64,${this.state.data.icon}`:''; | ||||
| 			const hobbyText = (<Text style = {{marginLeft: 50, paddingHorizontal: '2%', paddingBottom: '2%'}}>{this.state.data.hobbies}</Text>) | ||||
| 			const achievementText = (<Text style = {{marginLeft: 50, paddingHorizontal: '2%', paddingBottom: '2%'}}>{this.state.data.achievements}</Text>) | ||||
| 			const messageText = (<Text style = {{marginLeft: 50, paddingHorizontal: '2%', paddingBottom: '2%'}}>{this.state.data.messages}</Text>) | ||||
| 			return ( | ||||
| 				<View style={{paddingTop:'5%',paddingHorizontal:'10%', backgroundColor: 'white', height: '100%'}}> | ||||
| 					<View style = {{display: 'flex', flexDirection: 'row', justifyContent: 'space-between'}}> | ||||
| 						<View> | ||||
| 							<Text style={{fontSize:28,marginBottom:'10%',textAlign:'center'}}>{this.state.data.name}</Text>	 | ||||
| 							<Text style={{fontSize:20}}>{'\t'}{I18n.t('student.Grade')} {this.state.data.year}</Text> | ||||
| 						</View> | ||||
| 						<View style = {{height: 150, width: 150}}> | ||||
| 							<Image style = {{height: '100%', width:'100%', borderRadius: 6}}source={{iconURI}} /> | ||||
| 				<ScrollView style={{paddingTop:'5%',paddingHorizontal:'10%', backgroundColor: 'white', height: '100%'}}> | ||||
| 					<View style={{backgroundColor: 'white',borderRadius: 150, height: 300, width: 300, alignSelf: 'center', shadowColor: 'red', shadowOffset: {width: 0, height: 2}, shadowOpacity: 0.5, shadowRadius: 7}}> | ||||
| 						<Image style={{resizeMode: 'cover',borderRadius: 150, height: 300, width: 300, alignSelf: 'center'}} source = {{iconURI}} />  | ||||
| 					</View> | ||||
| 					<Text style={{fontSize:28,marginTop:'5%',textAlign:'center'}}>{this.state.data.name}</Text> | ||||
| 					<Text style={{fontSize:20,textAlign:'center', fontWeight: '200'}}>{I18n.t('student.Grade')} {this.state.data.year}</Text> | ||||
| 					<View> | ||||
| 						<View style={{display: 'flex', padding:'2%', borderRadius: 8, marginTop:'5%'}}> | ||||
| 							<TouchableOpacity onPress = {this.clickHobby.bind(this)}> | ||||
| 								<View style={{display:'flex', flexDirection: 'row'}}> | ||||
| 									<Image source = {require('./assets/hobbies.png')} /> | ||||
| 									<View style = {{display: 'flex', flexDirection: 'row', width: '85%', justifyContent: 'space-between', paddingHorizontal:'2%',}}> | ||||
| 										<Text style={{fontSize: 20,  alignSelf: 'center'}}>{I18n.t('student.Hobbies')}</Text> | ||||
| 										{this.state.hobbyExpanded?<LinearGradient start={{x: 0, y: 0.25}} end={{x: .5, y: 1}} colors={['red', '#FF7373']} style={{borderRadius: 24, alignSelf: 'center'}}><Image source = {require('./assets/collapse.png')} style={{tintColor: 'white'}}/></LinearGradient>:<Image source = {require('./assets/expand.png')} style={{tintColor: '#b2b2b2', alignSelf: 'center'}}/>} | ||||
| 									</View> | ||||
| 								</View> | ||||
| 								{this.state.hobbyExpanded?hobbyText:<></>} | ||||
| 							</TouchableOpacity> | ||||
| 							<TouchableOpacity onPress = {this.clickAchievements.bind(this)}> | ||||
| 								<View style={{display: 'flex', borderTopWidth: 1, borderTopColor: '#8D8D8D', shadowColor: 'black', flexDirection: 'row'}}> | ||||
| 									<Image source = {require('./assets/achievements.png')} /> | ||||
| 									<View style = {{display: 'flex', flexDirection: 'row', width: '85%', justifyContent: 'space-between', paddingHorizontal:'2%',}}> | ||||
| 										<Text style={{fontSize: 20, alignSelf: 'center'}}>{I18n.t('student.Achievements')}</Text> | ||||
| 										{this.state.achievementExpanded?<LinearGradient start={{x: 0, y: 0.25}} end={{x: .5, y: 1}} colors={['red', '#FF7373']} style={{borderRadius: 24, alignSelf: 'center'}}><Image source = {require('./assets/collapse.png')} style={{tintColor: 'white'}}/></LinearGradient>:<Image source = {require('./assets/expand.png')} style={{tintColor: '#b2b2b2', alignSelf: 'center'}}/>} | ||||
| 									</View> | ||||
| 								</View> | ||||
| 								{this.state.achievementExpanded?achievementText:<></>} | ||||
| 							</TouchableOpacity> | ||||
| 							<TouchableOpacity onPress = {this.clickMessages.bind(this)}> | ||||
| 								<View style={{display: 'flex', borderTopWidth: 1, borderTopColor: '#8D8D8D', shadowColor: 'black', flexDirection: 'row'}}> | ||||
| 									<Image source = {require('./assets/message.png')} /> | ||||
| 									<View style = {{display: 'flex', flexDirection: 'row', width: '85%', justifyContent: 'space-between', paddingHorizontal:'2%',}}> | ||||
| 										<Text style={{fontSize: 20, alignSelf: 'center'}}>{I18n.t('student.Messages')}</Text> | ||||
| 										{this.state.messageExpanded?<LinearGradient start={{x: 0, y: 0.25}} end={{x: .5, y: 1}} colors={['red', '#FF7373']} style={{borderRadius: 24, alignSelf: 'center'}}><Image source = {require('./assets/collapse.png')} style={{tintColor: 'white'}}/></LinearGradient>:<Image source = {require('./assets/expand.png')} style={{tintColor: '#b2b2b2', alignSelf: 'center'}}/>} | ||||
| 									</View> | ||||
| 								</View> | ||||
| 								{this.state.messageExpanded?messageText:<></>} | ||||
| 							</TouchableOpacity> | ||||
| 						</View> | ||||
| 						 | ||||
| 					</View> | ||||
| 					 | ||||
| 					<View style = {{paddingTop:'10%', height: '55%', display: 'flex', flexDirection: 'column', justifyContent: 'space-between'}}> | ||||
| 						<View> | ||||
| 							<Text style={{fontSize: 20, fontWeight: 'bold'}}>{"\n"}{I18n.t('student.Hobbies')}</Text> | ||||
| 							<Text style={{fontSize: 20}}>{'\t'}{this.state.data.hobbies}</Text> | ||||
| 						</View> | ||||
| 						<View> | ||||
| 							<Text style={{fontSize: 20, fontWeight: 'bold'}}>{"\n"}{I18n.t('student.Achievements')} </Text> | ||||
| 							<Text style={{fontSize: 20}}>{'\t'}{this.state.data.achievements}</Text> | ||||
| 						</View> | ||||
| 						<View> | ||||
| 							<Text style={{fontSize: 20, fontWeight: 'bold'}}>{"\n"}{I18n.t('student.Messages')}</Text> | ||||
| 							<Text style={{fontSize: 20}}>{'\t'}{this.state.data.messages}</Text> | ||||
| 						</View> | ||||
| 					</View> | ||||
| 					 | ||||
| 				</View> | ||||
| 				</ScrollView> | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								app/assets/achievements.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.1 KiB | 
| Before Width: | Height: | Size: 5.3 KiB | 
| Before Width: | Height: | Size: 28 KiB | 
| Before Width: | Height: | Size: 6.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/assets/canvas.jpeg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 14 KiB | 
| Before Width: | Height: | Size: 86 KiB | 
| Before Width: | Height: | Size: 5.1 KiB | 
| Before Width: | Height: | Size: 7.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/assets/collapse.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 183 B | 
							
								
								
									
										
											BIN
										
									
								
								app/assets/counselor.jpeg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 19 KiB | 
| Before Width: | Height: | Size: 6.5 KiB | 
| Before Width: | Height: | Size: 7.6 KiB | 
| Before Width: | Height: | Size: 7.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/assets/expand.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 186 B | 
							
								
								
									
										
											BIN
										
									
								
								app/assets/forward.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 167 B | 
							
								
								
									
										
											BIN
										
									
								
								app/assets/gc.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 21 KiB | 
| Before Width: | Height: | Size: 27 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/assets/hobbies.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/assets/infoflow.jpeg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 13 KiB | 
| Before Width: | Height: | Size: 5.7 KiB | 
| Before Width: | Height: | Size: 5.6 KiB | 
| Before Width: | Height: | Size: 5.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/assets/message.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.1 KiB | 
| Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 15 KiB | 
| Before Width: | Height: | Size: 5.2 KiB | 
| Before Width: | Height: | Size: 4.4 KiB | 
| Before Width: | Height: | Size: 5.2 KiB | 
| Before Width: | Height: | Size: 38 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/assets/sco.jpeg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 10 KiB | 
| Before Width: | Height: | Size: 6.2 KiB | 
| Before Width: | Height: | Size: 5.5 KiB | 
| Before Width: | Height: | Size: 5.8 KiB | 
| Before Width: | Height: | Size: 6.0 KiB | 
| Before Width: | Height: | Size: 6.5 KiB | 
| Before Width: | Height: | Size: 40 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/assets/studentvue.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 58 KiB | 
| Before Width: | Height: | Size: 5.4 KiB | 
| Before Width: | Height: | Size: 5.8 KiB | 
| Before Width: | Height: | Size: 5.0 KiB | 
							
								
								
									
										16
									
								
								app/i18n.js
									
									
									
									
									
								
							
							
						
						| @ -1,12 +1,18 @@ | ||||
| 'use strict'; | ||||
| import I18n from 'react-native-i18n'; | ||||
| import en from './Languages/en' | ||||
| import es from './Languages/es' | ||||
| import I18n from "i18n-js"; | ||||
| import * as RNLocalize from "react-native-localize"; | ||||
| import en from "./Languages/en.js"; | ||||
| import es from "./Languages/es.js"; | ||||
| 
 | ||||
| const locales = RNLocalize.getLocales(); | ||||
| 
 | ||||
| if (Array.isArray(locales)) { | ||||
|   I18n.locale = locales[0].languageTag; | ||||
| } | ||||
| 
 | ||||
| I18n.fallbacks = true; | ||||
| I18n.translations = { | ||||
|   en, | ||||
|   es, | ||||
|   es | ||||
| }; | ||||
| 
 | ||||
| export default I18n; | ||||
| @ -1 +1 @@ | ||||
| {"url":"http://127.0.0.1:5000"} | ||||
| {"url":"https://blazerappcms.ml/"} | ||||
| @ -1,9 +1,9 @@ | ||||
| import {StyleSheet, StatusBar} from 'react-native'; | ||||
| import {StyleSheet, StatusBar, Dimensions} from 'react-native'; | ||||
| 
 | ||||
| const styles = StyleSheet.create({ | ||||
|   container: { | ||||
|     flex: 1, | ||||
|     marginTop: StatusBar.currentHeight || 0 | ||||
|     marginTop: /*StatusBar.currentHeight ||*/ 0 | ||||
|   }, | ||||
|   item: { | ||||
|     backgroundColor: 'white', | ||||
| @ -11,6 +11,43 @@ const styles = StyleSheet.create({ | ||||
|     borderBottomWidth: 1.5, | ||||
|     borderColor: 'black' | ||||
|   }, | ||||
|   moreDefault: { | ||||
|     flex: 1, | ||||
|     backgroundColor:'white',  | ||||
|     paddingHorizontal: '5%' | ||||
|   }, | ||||
|   listItem: { | ||||
|     display: 'flex',  | ||||
|     borderBottomColor:'#D5D5D5', | ||||
|     borderBottomWidth:.5 | ||||
|   }, | ||||
|   container2: { | ||||
|     display: 'flex',  | ||||
|     flexDirection: 'row',  | ||||
|     height: Dimensions.get('window').height*0.075, | ||||
|     alignItems: 'center' | ||||
|   }, | ||||
|   sideImage: { | ||||
|     height: 40, | ||||
|     width: 40,  | ||||
|     marginRight: 10, | ||||
|     tintColor: '#323232' | ||||
|   }, | ||||
|   accordian: { | ||||
|     display: 'flex', | ||||
|     flexDirection: 'row', | ||||
|     justifyContent: 'space-between', | ||||
|     width: '85%' | ||||
|   }, | ||||
| 	accordianHeader: { | ||||
| 		paddingBottom: '2%', | ||||
| 		fontSize:16 | ||||
| 	}, | ||||
|   accordianText: { | ||||
|     paddingBottom: '2%', | ||||
| 		fontSize:16, | ||||
|     fontWeight: '200', | ||||
|   }, | ||||
|   item1: { | ||||
|     backgroundColor: 'white', | ||||
|     padding: 15, | ||||
|  | ||||
| @ -5,9 +5,9 @@ console.log(Dimensions.get('window')) | ||||
| 
 | ||||
| const styles=StyleSheet.create({ | ||||
| 	moreitem: { | ||||
| 		backgroundColor:'red', | ||||
| 		borderBottomColor:'white', | ||||
| 		borderBottomWidth:0.5, | ||||
| 		backgroundColor:'white', | ||||
| 		borderBottomColor:'#D5D5D5', | ||||
| 		borderBottomWidth:.5, | ||||
| 		height: Dimensions.get('window').height*0.075, | ||||
| 		paddingLeft: '3%', | ||||
| 		fontSize: 32, | ||||
| @ -16,35 +16,17 @@ const styles=StyleSheet.create({ | ||||
| 		alignItems: 'center', | ||||
| 	}, | ||||
| 	moretext: { | ||||
| 		color:'#e3e3e3', | ||||
| 		fontSize:22, | ||||
| 		fontSize:20, | ||||
| 	}, | ||||
| 	headerTitle: { | ||||
| 		fontWeight: 'bold', | ||||
| 		fontSize:24, | ||||
| 		alignSelf: 'center' | ||||
| 	}, | ||||
| 	resourceContainer: { | ||||
| 		alignItems: 'center', | ||||
|     	marginTop: '3%', | ||||
| 	}, | ||||
| 	image: { | ||||
| 		height: 100, | ||||
| 		width: 400, | ||||
| 		borderTopRightRadius: 16, | ||||
| 		borderTopLeftRadius: 16, | ||||
| 	}, | ||||
| 	textContainer: { | ||||
| 		backgroundColor: 'black', | ||||
| 		width: 400, | ||||
| 		borderBottomLeftRadius: 16, | ||||
| 		borderBottomRightRadius: 16, | ||||
| 	}, | ||||
| 	resourceText: { | ||||
| 		fontWeight: 'bold', | ||||
| 		color: 'white', | ||||
| 		fontSize:32, | ||||
| 		textAlign:'center', | ||||
| 	}, | ||||
| 	openPage: { | ||||
| 		display: 'flex', | ||||
| 		flexDirection: 'column', | ||||
|  | ||||
							
								
								
									
										41
									
								
								cms/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,41 @@ | ||||
| [package] | ||||
| name = "cms" | ||||
| version = "0.1.0" | ||||
| edition = "2018" | ||||
| 
 | ||||
| [dependencies] | ||||
| rocket = "0.4.10" | ||||
| dotenv = "0.15.0" | ||||
| clap = "2.33.3" | ||||
| ansi_term = "0.12.1" | ||||
| chrono = "0.4.19" | ||||
| diesel_migrations = "1.4.0" | ||||
| url = "2.2.2" | ||||
| oauth2 = "4.1.0" | ||||
| serde_json = "1.0.66" | ||||
| base64 = "0.13.0" | ||||
| quote = "1.0.9" | ||||
| 
 | ||||
| [dependencies.reqwest] | ||||
| version = "0.11.4" | ||||
| features = ["blocking", "json"] | ||||
| 
 | ||||
| [dependencies.diesel] | ||||
| version = "1.4.4" | ||||
| features = ["postgres", "extras"] | ||||
| 
 | ||||
| [dependencies.rocket_contrib] | ||||
| version = "0.4.10" | ||||
| default-features = false | ||||
| features = ["handlebars_templates", "diesel_postgres_pool", "json"] | ||||
| 
 | ||||
| [dependencies.serde] | ||||
| version = "1.0.126" | ||||
| features = ["derive"] | ||||
| 
 | ||||
| [dependencies.rand] | ||||
| version = "0.8.4" | ||||
| features = ["getrandom"] | ||||
| 
 | ||||
| [dependencies.cms_macro] | ||||
| path = "cms_macro" | ||||
							
								
								
									
										10
									
								
								cms/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,10 @@ | ||||
| FROM rustlang/rust:nightly AS build | ||||
| COPY / /build | ||||
| WORKDIR /build | ||||
| RUN cargo build --release | ||||
| 
 | ||||
| FROM ubuntu:20.04 AS release | ||||
| WORKDIR /root | ||||
| COPY --from=build /build/target/release/cms ./cms | ||||
| CMD [ "./cms" ] | ||||
| 
 | ||||
							
								
								
									
										17
									
								
								cms/cms_macro/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,17 @@ | ||||
| [package] | ||||
| name = "cms_macro" | ||||
| version = "0.1.0" | ||||
| edition = "2018" | ||||
| 
 | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [lib] | ||||
| proc-macro=true | ||||
| 
 | ||||
| [dependencies] | ||||
| quote = "1.0.9" | ||||
| proc-macro2 = "1.0.28" | ||||
| 
 | ||||
| [dependencies.diesel] | ||||
| version = "1.4.4" | ||||
| features = ["postgres", "extras"] | ||||
							
								
								
									
										327
									
								
								cms/cms_macro/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,327 @@ | ||||
| extern crate proc_macro; | ||||
| #[macro_use] | ||||
| extern crate quote; | ||||
| 
 | ||||
| use proc_macro2::*; | ||||
| use std::fmt::Debug; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| struct Row(Ident, Ident, Ident, Ident); | ||||
| 
 | ||||
| fn api_route_inner(item: TokenStream) -> TokenStream { | ||||
|     let iterator = item.into_iter().clone().collect::<Vec<TokenTree>>(); | ||||
|     let name = iterator[0].clone(); | ||||
|     let name_literal = &iterator[0].clone().to_string(); | ||||
|     let name_dir = format!("/{}", name_literal); | ||||
|     let name_add = format!("/{}/add", name_literal); | ||||
|     let name_upd = format!("/{}/upd", name_literal); | ||||
|     let name_del = format!("/{}/del", name_literal); | ||||
|     let name_api = format!("/<lang>/{}", name_literal); | ||||
|     let name_redir = format!("/ui/{}", name_literal); | ||||
| 
 | ||||
|     let value_group = iterator[1].clone(); | ||||
| 
 | ||||
|     let (delim, stream) = match value_group { | ||||
|         TokenTree::Group(g) => (g.delimiter(), g.stream()), | ||||
|         n => panic!("Incorrect syntax at brace => {:?}", n), | ||||
|     }; | ||||
| 
 | ||||
|     assert_eq!(delim, Delimiter::Brace); | ||||
|     let splitted = &mut stream.into_iter().clone().collect::<Vec<TokenTree>>()[..] | ||||
|         .split(|token| { | ||||
|             if let TokenTree::Punct(p) = token.clone() { | ||||
|                 p.as_char() == ',' && p.spacing() == Spacing::Alone | ||||
|             } else { | ||||
|                 false | ||||
|             } | ||||
|         }) | ||||
|         .map(Vec::from) | ||||
|         .collect::<Vec<Vec<TokenTree>>>(); | ||||
| 
 | ||||
|     splitted.pop(); | ||||
| 
 | ||||
|     let mut rows: Vec<Row> = vec![]; | ||||
| 
 | ||||
|     for vecs in splitted.into_iter() { | ||||
|         let mut vals_iter = vecs.split(|token| { | ||||
|             if let TokenTree::Punct(p) = token.clone() { | ||||
|                 p.as_char() == ':' && p.spacing() == Spacing::Alone | ||||
|             } else { | ||||
|                 false | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         let name = vals_iter.next().unwrap().to_vec(); | ||||
|         let vals = vals_iter.next().unwrap().to_vec(); | ||||
|         let (brack, val_stream) = match vals.get(0).unwrap() { | ||||
|             TokenTree::Group(g) => (g.delimiter(), g.stream()), | ||||
|             n => panic!("Incorrect syntax at parenthesis => {:?}", n), | ||||
|         }; | ||||
|         assert_eq!(brack, Delimiter::Parenthesis); | ||||
|         assert_eq!(name.len(), 1); | ||||
|         let name = match name.get(0).unwrap() { | ||||
|             TokenTree::Ident(g) => g, | ||||
|             n => panic!("Incorrect syntax at name => {:?}", n), | ||||
|         }; | ||||
| 
 | ||||
|         let vals = &val_stream.into_iter().clone().collect::<Vec<TokenTree>>()[..] | ||||
|             .split(|token| { | ||||
|                 if let TokenTree::Punct(p) = token.clone() { | ||||
|                     p.as_char() == ',' && p.spacing() == Spacing::Alone | ||||
|                 } else { | ||||
|                     false | ||||
|                 } | ||||
|             }) | ||||
|             .map(|x| match x.to_vec().get(0).unwrap().clone() { | ||||
|                 TokenTree::Ident(i) => i, | ||||
|                 n => panic!("Incorrect syntax at group => {:?}", n), | ||||
|             }) | ||||
|             .collect::<Vec<Ident>>(); | ||||
|         rows.push(Row( | ||||
|             name.clone(), | ||||
|             vals.get(0).unwrap().clone(), | ||||
|             vals.get(1).unwrap().clone(), | ||||
|             vals.get(2).unwrap().clone(), | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     let names_vec = rows | ||||
|         .iter() | ||||
|         .map(|x| TokenTree::Ident(x.0.clone())) | ||||
|         .collect::<Vec<TokenTree>>(); | ||||
| 
 | ||||
|     let schema_value = rows | ||||
|         .iter() | ||||
|         .map(|x| TokenTree::Ident(x.1.clone())) | ||||
|         .collect::<Vec<TokenTree>>(); | ||||
| 
 | ||||
|     let get_value = rows | ||||
|         .iter() | ||||
|         .map(|x| TokenTree::Ident(x.2.clone())) | ||||
|         .collect::<Vec<TokenTree>>(); | ||||
| 
 | ||||
|     let put_value = rows | ||||
|         .iter() | ||||
|         .map(|x| TokenTree::Ident(x.3.clone())) | ||||
|         .collect::<Vec<TokenTree>>(); | ||||
| 
 | ||||
|     let impl_value = rows | ||||
|         .iter() | ||||
|         .map(|x| { | ||||
|             if x.2.to_string() == x.3.to_string() { | ||||
|                 let s = x.0.clone(); | ||||
|                 quote! { | ||||
|                     #s: self.#s, | ||||
|                 } | ||||
|             } else { | ||||
|                 let s = x.0.clone(); | ||||
|                 quote! { | ||||
|                     #s: *self.#s, | ||||
|                 } | ||||
|             } | ||||
|         }) | ||||
|         .collect::<Vec<TokenStream>>() | ||||
|         .into_iter() | ||||
|         .map(|x| x.into_iter().collect::<Vec<TokenTree>>()) | ||||
|         .flatten() | ||||
|         .collect::<Vec<TokenTree>>(); | ||||
| 
 | ||||
|     let impls = quote! { | ||||
| 
 | ||||
|         impl Post { | ||||
|             fn convert(self) -> Create { | ||||
|                 Create { | ||||
|                     lang: self.lang, | ||||
|                     #(#impl_value)* | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         impl Update { | ||||
|             fn convert(self) -> Create { | ||||
|                 Create { | ||||
|                     lang: self.lang, | ||||
|                     #(#impl_value)* | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     let schema = quote! { | ||||
| 
 | ||||
|         pub mod schema { | ||||
|             table! { | ||||
|                 use diesel::sql_types::*; | ||||
| 
 | ||||
|                 #name (id) { | ||||
|                     id -> Integer, | ||||
|                     lang -> Text, | ||||
|                     #(#names_vec -> #schema_value,) | ||||
|                     * | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     let structs = quote! { | ||||
| 
 | ||||
|         use schema::#name; | ||||
| 
 | ||||
|         #[derive(Debug, Clone, Queryable, Serialize)] | ||||
|         pub struct Get { | ||||
|             pub id: i32, | ||||
|             pub lang: String, | ||||
|             #(pub #names_vec: #get_value), | ||||
|             * | ||||
|         } | ||||
| 
 | ||||
|         #[derive(Debug, AsChangeset, Insertable)] | ||||
|         #[table_name = #name_literal] | ||||
|         pub struct Create { | ||||
|             pub lang: String, | ||||
|             #(pub #names_vec: #get_value), | ||||
|             * | ||||
|         } | ||||
| 
 | ||||
|         #[derive(Debug, FromForm)] | ||||
|         pub struct Post { | ||||
|             pub lang: String, | ||||
|             #(pub #names_vec: #put_value), | ||||
|             * | ||||
|         } | ||||
| 
 | ||||
|         #[derive(Debug, FromForm)] | ||||
|         pub struct Update { | ||||
|             pub id: i32, | ||||
|             pub lang: String, | ||||
|             #(pub #names_vec: #put_value), | ||||
|             * | ||||
|         } | ||||
| 
 | ||||
|         #[derive(Debug, FromForm)] | ||||
|         pub struct Delete { | ||||
|             pub id: i32, | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     let imports = quote! { | ||||
|         use crate::data::{defs::*, Lang}; | ||||
|         use crate::auth::Token; | ||||
|         use ::chrono::naive::*; | ||||
|         use ::diesel::{prelude::*, Insertable, Queryable}; | ||||
|         use ::rocket::{http::Status, request::Form, response::Redirect, State}; | ||||
|         use ::rocket_contrib::{json::Json, templates::Template}; | ||||
|         use ::serde::Serialize; | ||||
|         use ::std::{collections::*, sync::Mutex}; | ||||
|     }; | ||||
| 
 | ||||
|     let endpoints = quote! { | ||||
| 
 | ||||
|         pub fn create(conn: &PgConnection, create: Create) -> Result<Get, diesel::result::Error> { | ||||
|             diesel::insert_into(#name::table) | ||||
|                 .values(&create) | ||||
|                 .get_result(conn) | ||||
|         } | ||||
| 
 | ||||
|         pub fn get(conn: &PgConnection, lg: Lang) -> Result<Vec<Get>, diesel::result::Error> { | ||||
|             use schema::#name::dsl::*; | ||||
| 
 | ||||
|             #name.filter(lang.eq(lg.0)).load::<Get>(conn) | ||||
|         } | ||||
| 
 | ||||
|         pub fn get_all(conn: &PgConnection) -> Result<Vec<Get>, diesel::result::Error> { | ||||
|             use schema::#name::dsl::*; | ||||
|             #name.load::<Get>(conn) | ||||
|         } | ||||
| 
 | ||||
|         pub fn update( | ||||
|             conn: &PgConnection, | ||||
|             idn: i32, | ||||
|             create: Create, | ||||
|         ) -> Result<Get, diesel::result::Error> { | ||||
|             use schema::#name::dsl::*; | ||||
|             diesel::update(#name.find(idn)) | ||||
|                 .set(&create) | ||||
|                 .get_result::<Get>(conn) | ||||
|         } | ||||
| 
 | ||||
|         pub fn delete(conn: &PgConnection, idn: i32) -> Result<usize, diesel::result::Error> { | ||||
|             use schema::#name::dsl::*; | ||||
|             diesel::delete(#name.find(idn)).execute(conn) | ||||
|         } | ||||
| 
 | ||||
|         #[get(#name_api)] | ||||
|         pub fn api(pg: State<Mutex<PgConnection>>, lang: Lang) -> Result<Json<Vec<Get>>, Status> { | ||||
|             Ok(Json( | ||||
|                 get(&*(pg.lock().unwrap()), lang).map_err(|_| Status::InternalServerError)?, | ||||
|             )) | ||||
|         } | ||||
| 
 | ||||
|         #[post(#name_add, data = "<form>")] | ||||
|         pub fn add(_token: Token, pg: State<Mutex<PgConnection>>, form: Form<Post>) -> Result<Redirect, Status> { | ||||
|             match create(&*(pg.lock().unwrap()), form.into_inner().convert()) { | ||||
|                 Ok(_) => Ok(Redirect::to(#name_redir)), | ||||
|                 Err(_) => Err(Status::InternalServerError), | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #[post(#name_del, data = "<form>")] | ||||
|         pub fn del(_token: Token, pg: State<Mutex<PgConnection>>, form: Form<Delete>) -> Result<Redirect, Status> { | ||||
|             match delete(&*(pg.lock().unwrap()), form.id) { | ||||
|                 Ok(_) => Ok(Redirect::to(#name_redir)), | ||||
|                 Err(_) => Err(Status::InternalServerError), | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #[post(#name_upd, data = "<form>")] | ||||
|         pub fn upd(_token: Token, pg: State<Mutex<PgConnection>>, form: Form<Update>) -> Result<Redirect, Status> { | ||||
|             match update(&*(pg.lock().unwrap()), form.id, form.into_inner().convert()) { | ||||
|                 Ok(_) => Ok(Redirect::to(#name_redir)), | ||||
|                 Err(_) => Err(Status::InternalServerError), | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #[get(#name_dir)] | ||||
|         pub fn ui(_token: Token, pg: State<Mutex<PgConnection>>) -> Result<Template, Status> { | ||||
|             let ctx = get_all(&*(pg.lock().unwrap())) | ||||
|                 .map_err(|_| Status::InternalServerError)? | ||||
|                 .iter() | ||||
|                 .map(|x| (x.id, x.clone())) | ||||
|                 .collect::<HashMap<i32, Get>>(); | ||||
|             Ok(Template::render(#name_literal, &ctx)) | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     let tok = quote! { | ||||
|         pub mod #name { | ||||
|             #imports | ||||
|             #schema | ||||
|             #structs | ||||
|             #impls | ||||
|             #endpoints | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     tok.into() | ||||
| } | ||||
| 
 | ||||
| #[proc_macro] | ||||
| pub fn api_route(item: proc_macro::TokenStream) -> proc_macro::TokenStream { | ||||
|     api_route_inner(TokenStream::from(item)).into() | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| pub fn test() { | ||||
|     let val = quote! { | ||||
|         events { | ||||
|             title: (Text, String, String), | ||||
|             location: (Text, String, String), | ||||
|             text: (Text, String, String), | ||||
|             event_date: (Text, NaiveDate, DateForm), | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     let macr = api_route_inner(val); | ||||
| 
 | ||||
|     println!("{}", macr); | ||||
| } | ||||
							
								
								
									
										0
									
								
								cms/migrations/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										3
									
								
								cms/migrations/setup/down.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,3 @@ | ||||
| DROP TABLE auth_val; | ||||
| 
 | ||||
| DROP TABLE events; | ||||
							
								
								
									
										15
									
								
								cms/migrations/setup/up.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,15 @@ | ||||
| CREATE TABLE auth_val ( | ||||
|     id SERIAL PRIMARY KEY, | ||||
|     email VARCHAR | ||||
| ); | ||||
| 
 | ||||
| INSERT INTO auth_val(email) VALUES('hkailadka88@gmail.com'); | ||||
| 
 | ||||
| CREATE TABLE events ( | ||||
|     id SERIAL PRIMARY KEY, | ||||
|     lang VARCHAR, | ||||
|     title VARCHAR NOT NULL, | ||||
|     text VARCHAR, | ||||
|     location VARCHAR NOT NULL, | ||||
|     event_date DATE | ||||
| ); | ||||
							
								
								
									
										209
									
								
								cms/src/auth.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,209 @@ | ||||
| use diesel::{prelude::*, Queryable}; | ||||
| use oauth2::{ | ||||
|     basic::BasicClient, reqwest::http_client, AuthUrl, AuthorizationCode, ClientId, ClientSecret, | ||||
|     CsrfToken, RedirectUrl, RevocationUrl, Scope, TokenResponse, TokenUrl, | ||||
| }; | ||||
| use reqwest::blocking::Client; | ||||
| use rocket::{ | ||||
|     http::{Cookie, Cookies, SameSite, Status}, | ||||
|     request, | ||||
|     request::FromRequest, | ||||
|     response::Redirect, | ||||
|     Outcome, Request, State, | ||||
| }; | ||||
| use serde::Serialize; | ||||
| use serde_json::Value; | ||||
| use std::{fmt::Debug, sync::Mutex}; | ||||
| 
 | ||||
| mod schema { | ||||
|     table! { | ||||
|         use diesel::sql_types::*; | ||||
| 
 | ||||
|         auth_val (id) { | ||||
|             id -> Integer, | ||||
|             email -> Text, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct Host(String); | ||||
| pub struct Token(String); | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct Settings { | ||||
|     pub id: String, | ||||
|     pub secret: String, | ||||
|     pub auth_url: AuthUrl, | ||||
|     pub token_url: TokenUrl, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Queryable, Serialize)] | ||||
| struct Auth { | ||||
|     pub id: i32, | ||||
|     pub email: String, | ||||
| } | ||||
| 
 | ||||
| fn get_auth(conn: &PgConnection) -> Result<Vec<Auth>, diesel::result::Error> { | ||||
|     use schema::auth_val::dsl::*; | ||||
|     auth_val.load::<Auth>(conn) | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'r> FromRequest<'a, 'r> for Host { | ||||
|     type Error = (); | ||||
| 
 | ||||
|     fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { | ||||
|         let host = request.headers().get_one("Host"); | ||||
|         match host { | ||||
|             Some(host) => Outcome::Success(Host(host.to_string())), | ||||
|             None => Outcome::Failure((Status::Unauthorized, ())), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'r> FromRequest<'a, 'r> for Token { | ||||
|     type Error = Redirect; | ||||
| 
 | ||||
|     fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { | ||||
|         match request.cookies().get("token") { | ||||
|             Some(token) => { | ||||
|                 let resp: Value = Client::new() | ||||
|                     .get("https://www.googleapis.com/userinfo/v2/me") | ||||
|                     .bearer_auth(token.name_value().1) | ||||
|                     .send() | ||||
|                     .unwrap() | ||||
|                     .json() | ||||
|                     .unwrap(); | ||||
| 
 | ||||
|                 if resp["error"] != Value::Null { | ||||
|                     return Outcome::Forward(()); | ||||
|                 } else { | ||||
|                     let email = resp["email"].clone(); | ||||
|                     let pg = request.guard::<State<Mutex<PgConnection>>>().unwrap(); | ||||
|                     let diesel_op = get_auth(&*(pg.lock().unwrap())); | ||||
|                     let auths: Vec<String> = match diesel_op { | ||||
|                         Ok(n) => n.into_iter().map(|x| x.email).collect::<Vec<String>>(), | ||||
|                         Err(_) => vec![], | ||||
|                     }; | ||||
| 
 | ||||
|                     if auths.into_iter().any(|x| x == email.as_str().unwrap_or("")) { | ||||
|                         return Outcome::Success(Token(String::from(email.as_str().unwrap_or("")))); | ||||
|                     } else { | ||||
|                         return Outcome::Forward(()); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             None => Outcome::Forward(()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[get("/oauth")] | ||||
| pub fn oauth( | ||||
|     mut cookies: Cookies, | ||||
|     settings: State<Settings>, | ||||
|     host: Host, | ||||
| ) -> Result<Redirect, Status> { | ||||
|     let client = get_client(settings.inner().clone(), host); | ||||
|     let csrf_token = CsrfToken::new_random(); | ||||
|     let csrf: String = csrf_token.secret().into(); | ||||
|     cookies.add(Cookie::new("state", csrf)); | ||||
|     let (authorize_url, _csrf_state) = client | ||||
|         .authorize_url(|| csrf_token.clone()) | ||||
|         .add_scope(Scope::new( | ||||
|             "https://www.googleapis.com/auth/userinfo.email".to_owned(), | ||||
|         )) | ||||
|         .url(); | ||||
|     let auth = authorize_url.to_string(); | ||||
|     Ok(Redirect::to(auth)) | ||||
| } | ||||
| 
 | ||||
| #[get("/logout")] | ||||
| pub fn logout(mut cookies: Cookies) -> Redirect { | ||||
|     match cookies.get("token") { | ||||
|         Some(_) => { | ||||
|             cookies.remove(Cookie::named("token")); | ||||
|             Redirect::to("/") | ||||
|         } | ||||
|         None => Redirect::to("/"), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[get("/callback?<state>&<code>")] | ||||
| pub fn callback( | ||||
|     state: String, | ||||
|     code: String, | ||||
|     pg: State<Mutex<PgConnection>>, | ||||
|     mut cookies: Cookies, | ||||
|     host: Host, | ||||
|     sa: State<Settings>, | ||||
| ) -> Result<Redirect, Status> { | ||||
|     let sc = cookies.get("state"); | ||||
|     match sc { | ||||
|         Some(c) => { | ||||
|             if state != c.value() { | ||||
|                 return Err(Status::Forbidden); | ||||
|             } else { | ||||
|                 cookies.remove(Cookie::named("state")); | ||||
|                 let client = get_client(sa.inner().clone(), host); | ||||
|                 let token_result = client | ||||
|                     .exchange_code(AuthorizationCode::new(code)) | ||||
|                     .request(http_client); | ||||
|                 match token_result { | ||||
|                     Ok(n) => { | ||||
|                         let secret = n.access_token().secret(); | ||||
| 
 | ||||
|                         let resp: Value = Client::new() | ||||
|                             .get("https://www.googleapis.com/userinfo/v2/me") | ||||
|                             .bearer_auth(secret) | ||||
|                             .send() | ||||
|                             .unwrap() | ||||
|                             .json() | ||||
|                             .unwrap(); | ||||
|                         if resp["error"] != Value::Null { | ||||
|                             return Err(Status::BadRequest); | ||||
|                         } else { | ||||
|                             let email = resp["email"].clone(); | ||||
|                             let diesel_op = get_auth(&*(pg.lock().unwrap())); | ||||
|                             let auths: Vec<String> = match diesel_op { | ||||
|                                 Ok(n) => n.into_iter().map(|x| x.email).collect::<Vec<String>>(), | ||||
|                                 Err(_) => vec![], | ||||
|                             }; | ||||
|                             if auths.into_iter().any(|x| x == email.as_str().unwrap_or("")) { | ||||
|                                 let mut cook = Cookie::new("token", secret.to_string()); | ||||
|                                 cook.set_same_site(SameSite::Strict); | ||||
|                                 cook.set_http_only(true); | ||||
|                                 cook.set_secure(true); | ||||
|                                 cookies.add(cook); | ||||
|                                 return Ok(Redirect::to("/")); | ||||
|                             } else { | ||||
|                                 return Err(Status::Forbidden); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     Err(_) => return Err(Status::InternalServerError), | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         None => Err(Status::BadRequest), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn get_client(settings: Settings, host: Host) -> BasicClient { | ||||
|     let gcid = ClientId::new(settings.id); | ||||
| 
 | ||||
|     let gcs = ClientSecret::new(settings.secret); | ||||
| 
 | ||||
|     let auth_url = settings.auth_url; | ||||
|     let token_url = settings.token_url; | ||||
| 
 | ||||
|     let base: String = host.0.to_owned(); | ||||
| 
 | ||||
|     BasicClient::new(gcid, Some(gcs), auth_url, Some(token_url)) | ||||
|         .set_redirect_uri( | ||||
|             RedirectUrl::new(format!("http://{}/callback", base)).expect("Invalid redirect URL"), | ||||
|         ) | ||||
|         .set_revocation_uri( | ||||
|             RevocationUrl::new("https://oauth2.googleapis.com/revoke".to_owned()) | ||||
|                 .expect("Invalid revocation endpoint URL"), | ||||
|         ) | ||||
| } | ||||
							
								
								
									
										78
									
								
								cms/src/data/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,78 @@ | ||||
| use rocket::{ | ||||
|     http::{RawStr, Status}, | ||||
|     request::FromParam, | ||||
| }; | ||||
| use std::borrow::Cow; | ||||
| 
 | ||||
| use cms_macro::api_route; | ||||
| 
 | ||||
| pub struct Lang<'a>(Cow<'a, str>); | ||||
| 
 | ||||
| fn valid_lang(lang: &str) -> bool { | ||||
|     lang.chars().all(|c| (c >= 'a' && c <= 'z')) && lang.chars().count() == 2 | ||||
| } | ||||
| 
 | ||||
| impl<'a> FromParam<'a> for Lang<'a> { | ||||
|     type Error = Status; | ||||
|     fn from_param(param: &'a RawStr) -> Result<Lang<'a>, Status> { | ||||
|         match valid_lang(param) { | ||||
|             true => Ok(Lang(Cow::Borrowed(param))), | ||||
|             false => Err(Status::InternalServerError), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub mod defs { | ||||
|     use chrono::naive::NaiveDate; | ||||
|     use rocket::{http::RawStr, request::FromFormValue}; | ||||
|     use std::ops::Deref; | ||||
| 
 | ||||
|     #[derive(Debug)] | ||||
|     pub struct DateForm(NaiveDate); | ||||
| 
 | ||||
|     impl Deref for DateForm { | ||||
|         type Target = NaiveDate; | ||||
| 
 | ||||
|         fn deref(&self) -> &NaiveDate { | ||||
|             &self.0 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     impl<'v> FromFormValue<'v> for DateForm { | ||||
|         type Error = (); | ||||
| 
 | ||||
|         fn from_form_value(value: &'v RawStr) -> Result<DateForm, ()> { | ||||
|             let value_uri = match value.url_decode() { | ||||
|                 Ok(n) => n, | ||||
|                 Err(_) => return Err(()), | ||||
|             }; | ||||
|             let naivedate = NaiveDate::parse_from_str(&value_uri[..], "%m/%d/%Y"); | ||||
|             match naivedate { | ||||
|                 Ok(n) => Ok(DateForm(n)), | ||||
|                 Err(_) => Err(()), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| api_route! { | ||||
|     events { | ||||
|         title: (Text, String, String), | ||||
|         location: (Text, String, String), | ||||
|         text: (Text, String, String), | ||||
|         event_date: (Date, NaiveDate, DateForm), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| api_route! { | ||||
|     teachers { | ||||
|         name: (Text, String, String), | ||||
|         emails: (Array<Text>, Vec<String>, Vec<String>), | ||||
|     } | ||||
| } | ||||
| */ | ||||
| //TODO: fix value parsing to read a TokenStream until the `,` to allow for containerized types in
 | ||||
| //the macro
 | ||||
| 
 | ||||
							
								
								
									
										158
									
								
								cms/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,158 @@ | ||||
| #![feature(decl_macro)] | ||||
| #[macro_use] | ||||
| extern crate diesel; | ||||
| #[macro_use] | ||||
| extern crate diesel_migrations; | ||||
| #[macro_use] | ||||
| extern crate rocket; | ||||
| 
 | ||||
| mod auth; | ||||
| mod data; | ||||
| mod secret; | ||||
| mod utils; | ||||
| 
 | ||||
| use auth::Settings; | ||||
| use clap::{App, Arg}; | ||||
| use diesel::prelude::*; | ||||
| use dotenv::dotenv; | ||||
| use oauth2::{AuthUrl, TokenUrl}; | ||||
| use rocket::{ | ||||
|     config::{Config, Environment}, | ||||
|     Rocket, | ||||
| }; | ||||
| use rocket_contrib::templates::Template; | ||||
| use std::{ | ||||
|     collections::*, | ||||
|     env, | ||||
|     net::IpAddr, | ||||
|     path::{Path, PathBuf}, | ||||
|     sync::Mutex, | ||||
| }; | ||||
| use utils::{db_conn, exit_with_error}; | ||||
| use rocket::response::Redirect; | ||||
| use auth::Token; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #[get("/")] | ||||
| fn home(_token: Token) -> Template { | ||||
|     let context: HashMap<&str, &str> = HashMap::new(); | ||||
|     Template::render("home", &context) | ||||
| } | ||||
| 
 | ||||
| #[get("/", rank=2)] | ||||
| fn home_not_logged_in() -> Redirect { | ||||
|     Redirect::to(uri!(login)) | ||||
| } | ||||
| 
 | ||||
| #[get("/login")] | ||||
| fn login() -> Template { | ||||
|     let context: HashMap<&str, &str> = [("oauth", "/oauth")].iter().cloned().collect(); | ||||
|     Template::render("login", &context) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #[get("/static/<path..>")] | ||||
| fn static_files(path: PathBuf) -> Option<rocket::response::NamedFile> { | ||||
|     rocket::response::NamedFile::open(Path::new("cms/static/").join(path)).ok() | ||||
| } | ||||
| 
 | ||||
| fn rocket(port: u16, address: String, env: Environment, pg: PgConnection, sa: Settings) -> Rocket { | ||||
|     let mut config = Config::build(env) | ||||
|         .port(port) | ||||
|         .address(address) | ||||
|         .secret_key(secret::create_secret()) | ||||
|         .unwrap(); | ||||
|     let mut extras = HashMap::new(); | ||||
|     extras.insert("template_dir".to_string(), "cms/templates/".into()); | ||||
|     config.set_extras(extras); | ||||
|     rocket::custom(config) | ||||
|         .attach(Template::fairing()) | ||||
|         .manage(Mutex::new(pg)) | ||||
|         .manage(sa) | ||||
|         .mount( | ||||
|             "/", | ||||
|             routes![home, home_not_logged_in, login, auth::callback, auth::oauth, static_files], | ||||
|         ) | ||||
|         .mount("/api", routes![data::events::api]) | ||||
|         .mount( | ||||
|             "/ui", | ||||
|             routes![ | ||||
|                 data::events::ui, | ||||
|                 data::events::add, | ||||
|                 data::events::del, | ||||
|                 data::events::upd | ||||
|             ], | ||||
|         ) | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
|     dotenv().ok(); | ||||
| 
 | ||||
|     let gcid = env::var("BLAZERCMS_CLIENT_ID") | ||||
|         .unwrap_or_else(|_| exit_with_error("BLAZERCMS_CLIENT_ID must be set")); | ||||
| 
 | ||||
|     let gcs = env::var("BLAZERCMS_SECRET") | ||||
|         .unwrap_or_else(|_| exit_with_error("BLAZERCMS_SECRET must be set")); | ||||
| 
 | ||||
|     let auth_url = AuthUrl::new("https://accounts.google.com/o/oauth2/v2/auth".to_owned()) | ||||
|         .expect("Invalid authorization endpoint."); | ||||
| 
 | ||||
|     let token_url = TokenUrl::new("https://www.googleapis.com/oauth2/v3/token".to_owned()) | ||||
|         .expect("Invalid token endpoint. "); | ||||
| 
 | ||||
|     let postgres = db_conn(); | ||||
| 
 | ||||
|     let matches = App::new("blazercms") | ||||
|         .version("1.0") | ||||
|         .arg( | ||||
|             Arg::with_name("port") | ||||
|                 .short("p") | ||||
|                 .long("port") | ||||
|                 .default_value("8080"), | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name("prod") | ||||
|                 .short("r") | ||||
|                 .long("prod") | ||||
|                 .takes_value(false), | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name("addr") | ||||
|                 .short("a") | ||||
|                 .long("addr") | ||||
|                 .default_value("127.0.0.1"), | ||||
|         ) | ||||
|         .get_matches(); | ||||
| 
 | ||||
|     let port = matches | ||||
|         .value_of("port") | ||||
|         .unwrap() | ||||
|         .parse::<u16>() | ||||
|         .unwrap_or_else(|_| exit_with_error("Port must be an integer! ")); | ||||
| 
 | ||||
|     let addr = matches | ||||
|         .value_of("addr") | ||||
|         .unwrap() | ||||
|         .parse::<IpAddr>() | ||||
|         .unwrap_or_else(|_| exit_with_error("Address must be a valid IP Address! ")) | ||||
|         .to_string(); | ||||
| 
 | ||||
|     let env; | ||||
|     if matches.is_present("prod") { | ||||
|         env = Environment::Production; | ||||
|     } else { | ||||
|         env = Environment::Development; | ||||
|     } | ||||
| 
 | ||||
|     let auth_settings = Settings { | ||||
|         id: gcid, | ||||
|         secret: gcs, | ||||
|         auth_url: auth_url, | ||||
|         token_url: token_url, | ||||
|     }; | ||||
| 
 | ||||
|     let err = rocket(port, addr, env, postgres, auth_settings).launch(); | ||||
|     exit_with_error(&format!("Error: {}", err)); | ||||
| } | ||||
							
								
								
									
										7
									
								
								cms/src/secret.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,7 @@ | ||||
| use rand::{rngs::OsRng, RngCore}; | ||||
| 
 | ||||
| pub fn create_secret() -> String { | ||||
|     let mut secret = [0u8; 32]; | ||||
|     OsRng.fill_bytes(&mut secret); | ||||
|     base64::encode(&secret) | ||||
| } | ||||
							
								
								
									
										21
									
								
								cms/src/utils.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,21 @@ | ||||
| use ansi_term::Colour::Red; | ||||
| use diesel::{pg::PgConnection, prelude::*}; | ||||
| use std::env; | ||||
| 
 | ||||
| pub fn exit_with_error(msg: &str) -> ! { | ||||
|     eprintln!("{}", Red.paint(msg)); | ||||
|     std::process::exit(1); | ||||
| } | ||||
| 
 | ||||
| pub fn db_conn() -> PgConnection { | ||||
|     embed_migrations!("migrations"); | ||||
| 
 | ||||
|     let database_url = env::var("BLAZERCMS_DATABASE_URL") | ||||
|         .unwrap_or_else(|_| exit_with_error("BLAZERCMS_DATABASE_URL must be set")); | ||||
| 
 | ||||
|     let db = PgConnection::establish(&database_url) | ||||
|         .unwrap_or_else(|_| exit_with_error("Error connecting to database. ")); | ||||
| 
 | ||||
|     embedded_migrations::run(&db).unwrap_or_else(|_| exit_with_error("Error migrating database. ")); | ||||
|     db | ||||
| } | ||||
							
								
								
									
										3
									
								
								cms/static/style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,3 @@ | ||||
| body { | ||||
|     background-color: lightblue; | ||||
| } | ||||
							
								
								
									
										25
									
								
								cms/templates/events.html.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,25 @@ | ||||
| <!-- vim: set ft=html: --> | ||||
| 
 | ||||
| <html> | ||||
|     <head> | ||||
|         <link rel="stylesheet" href="/static/style.css"> | ||||
|     </head> | ||||
|     <body> | ||||
|         <p>{{6.title}}</p> | ||||
|         <br> | ||||
|         <form action="events/add" method="post"> | ||||
|             <input type="text", id="lang", name="lang"> | ||||
|             <input type="text", id="title", name="title"> | ||||
|             <input type="text", id="location", name="location"> | ||||
|             <input type="text", id="text", name="text"> | ||||
|             <input type="text", id="event_date", name="event_date"> | ||||
|             <input type="submit", value="Submit"> | ||||
|         </form> | ||||
|         <form action="events/del" method="post"> | ||||
|             <input type="number", id="id", name="id"> | ||||
|             <input type="submit", value="Submit"> | ||||
|         </form> | ||||
| 
 | ||||
|     </body> | ||||
|     </head> | ||||
| </html> | ||||
							
								
								
									
										9
									
								
								cms/templates/home.html.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,9 @@ | ||||
| {{! vim: set ft=html: }} | ||||
| 
 | ||||
| <html> | ||||
|     <head> | ||||
|     </head> | ||||
|     <body> | ||||
|         <a href="/ui/events">Events</a> | ||||
|     </body> | ||||
| </html> | ||||
							
								
								
									
										10
									
								
								cms/templates/login.html.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,10 @@ | ||||
| <!-- vim: set ft=html: --> | ||||
| 
 | ||||
| <html> | ||||
|     <head> | ||||
|     </head> | ||||
|     <body> | ||||
|         <a href={{oauth}}>Login</a> | ||||
|     </body> | ||||
|     </head> | ||||
| </html> | ||||
							
								
								
									
										19
									
								
								docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,19 @@ | ||||
| version: "3.9" | ||||
| services: | ||||
| 
 | ||||
|   postgres: | ||||
|     image: "postgres:alpine" | ||||
|     environment: | ||||
|       POSTGRES_PASSWORD: ${BLAZERCMS_POSTGRES} | ||||
|     ports: | ||||
|       - "5432:5432" | ||||
|   web: | ||||
|     build: cms/ | ||||
|     ports: | ||||
|       - "8080:8080" | ||||
|     depends_on: | ||||
|       - postgres | ||||
|     environment: | ||||
|       BLAZERCMS_DATABASE_URL: ${BLAZERCMS_DATABASE_URL} | ||||
|       BLAZERCMS_CLIENT_ID: ${BLAZERCMS_CLIENT_ID} | ||||
|       BLAZERCMS_SECRET: ${BLAZERCMS_SECRET} | ||||
							
								
								
									
										11
									
								
								ios/Podfile
									
									
									
									
									
								
							
							
						
						| @ -15,19 +15,26 @@ target 'blazerapp' do | ||||
|   pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons' | ||||
| 
 | ||||
| 
 | ||||
|   pod 'RNLocalize', :path => '../node_modules/react-native-localize' | ||||
| 
 | ||||
|   target 'blazerappTests' do | ||||
|     inherit! :complete | ||||
|     # Pods for testing | ||||
|   end | ||||
| 
 | ||||
|   # Enables Flipper. | ||||
|   # | ||||
|   # Note that if you have use_frameworks! enabled, Flipper will not work and | ||||
|   # you should disable these next few lines. | ||||
|   use_flipper! | ||||
|   use_flipper!({'Flipper' => '0.87.0' , 'Flipper-Folly' => '2.5.3' , 'Flipper-RSocket' => '1.3.1' }) | ||||
|   post_install do |installer| | ||||
|     flipper_post_install(installer) | ||||
|     installer.pods_project.targets.each do |target| | ||||
|       target.build_configurations.each do |config| | ||||
|        config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' | ||||
|       end | ||||
|      end | ||||
|   end | ||||
|    | ||||
| end | ||||
| 
 | ||||
| target 'blazerapp-tvOS' do | ||||
|  | ||||
							
								
								
									
										532
									
								
								ios/Podfile.lock
									
									
									
									
									
								
							
							
						
						| @ -3,60 +3,70 @@ PODS: | ||||
|   - BVLinearGradient (2.5.6): | ||||
|     - React | ||||
|   - CocoaAsyncSocket (7.6.5) | ||||
|   - CocoaLibEvent (1.0.0) | ||||
|   - DoubleConversion (1.1.6) | ||||
|   - FBLazyVector (0.63.2) | ||||
|   - FBReactNativeSpec (0.63.2): | ||||
|   - FBLazyVector (0.63.4) | ||||
|   - FBReactNativeSpec (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - RCTRequired (= 0.63.2) | ||||
|     - RCTTypeSafety (= 0.63.2) | ||||
|     - React-Core (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.2) | ||||
|   - Flipper (0.41.5): | ||||
|     - Flipper-Folly (~> 2.2) | ||||
|     - Flipper-RSocket (~> 1.1) | ||||
|     - RCTRequired (= 0.63.4) | ||||
|     - RCTTypeSafety (= 0.63.4) | ||||
|     - React-Core (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.4) | ||||
|   - Flipper (0.87.0): | ||||
|     - Flipper-Folly (~> 2.5) | ||||
|     - Flipper-RSocket (~> 1.3) | ||||
|   - Flipper-DoubleConversion (1.1.7) | ||||
|   - Flipper-Folly (2.2.0): | ||||
|   - Flipper-Folly (2.5.3): | ||||
|     - boost-for-react-native | ||||
|     - CocoaLibEvent (~> 1.0) | ||||
|     - Flipper-DoubleConversion | ||||
|     - Flipper-Glog | ||||
|     - OpenSSL-Universal (= 1.0.2.19) | ||||
|     - libevent (~> 2.1.12) | ||||
|     - OpenSSL-Universal (= 1.1.180) | ||||
|   - Flipper-Glog (0.3.6) | ||||
|   - Flipper-PeerTalk (0.0.4) | ||||
|   - Flipper-RSocket (1.1.0): | ||||
|     - Flipper-Folly (~> 2.2) | ||||
|   - FlipperKit (0.41.5): | ||||
|     - FlipperKit/Core (= 0.41.5) | ||||
|   - FlipperKit/Core (0.41.5): | ||||
|     - Flipper (~> 0.41.5) | ||||
|   - Flipper-RSocket (1.3.1): | ||||
|     - Flipper-Folly (~> 2.5) | ||||
|   - FlipperKit (0.87.0): | ||||
|     - FlipperKit/Core (= 0.87.0) | ||||
|   - FlipperKit/Core (0.87.0): | ||||
|     - Flipper (~> 0.87.0) | ||||
|     - FlipperKit/CppBridge | ||||
|     - FlipperKit/FBCxxFollyDynamicConvert | ||||
|     - FlipperKit/FBDefines | ||||
|     - FlipperKit/FKPortForwarding | ||||
|   - FlipperKit/CppBridge (0.41.5): | ||||
|     - Flipper (~> 0.41.5) | ||||
|   - FlipperKit/FBCxxFollyDynamicConvert (0.41.5): | ||||
|     - Flipper-Folly (~> 2.2) | ||||
|   - FlipperKit/FBDefines (0.41.5) | ||||
|   - FlipperKit/FKPortForwarding (0.41.5): | ||||
|   - FlipperKit/CppBridge (0.87.0): | ||||
|     - Flipper (~> 0.87.0) | ||||
|   - FlipperKit/FBCxxFollyDynamicConvert (0.87.0): | ||||
|     - Flipper-Folly (~> 2.5) | ||||
|   - FlipperKit/FBDefines (0.87.0) | ||||
|   - FlipperKit/FKPortForwarding (0.87.0): | ||||
|     - CocoaAsyncSocket (~> 7.6) | ||||
|     - Flipper-PeerTalk (~> 0.0.4) | ||||
|   - FlipperKit/FlipperKitHighlightOverlay (0.41.5) | ||||
|   - FlipperKit/FlipperKitLayoutPlugin (0.41.5): | ||||
|   - FlipperKit/FlipperKitHighlightOverlay (0.87.0) | ||||
|   - FlipperKit/FlipperKitLayoutHelpers (0.87.0): | ||||
|     - FlipperKit/Core | ||||
|     - FlipperKit/FlipperKitHighlightOverlay | ||||
|     - FlipperKit/FlipperKitLayoutTextSearchable | ||||
|   - FlipperKit/FlipperKitLayoutIOSDescriptors (0.87.0): | ||||
|     - FlipperKit/Core | ||||
|     - FlipperKit/FlipperKitHighlightOverlay | ||||
|     - FlipperKit/FlipperKitLayoutHelpers | ||||
|     - YogaKit (~> 1.18) | ||||
|   - FlipperKit/FlipperKitLayoutTextSearchable (0.41.5) | ||||
|   - FlipperKit/FlipperKitNetworkPlugin (0.41.5): | ||||
|   - FlipperKit/FlipperKitLayoutPlugin (0.87.0): | ||||
|     - FlipperKit/Core | ||||
|   - FlipperKit/FlipperKitReactPlugin (0.41.5): | ||||
|     - FlipperKit/FlipperKitHighlightOverlay | ||||
|     - FlipperKit/FlipperKitLayoutHelpers | ||||
|     - FlipperKit/FlipperKitLayoutIOSDescriptors | ||||
|     - FlipperKit/FlipperKitLayoutTextSearchable | ||||
|     - YogaKit (~> 1.18) | ||||
|   - FlipperKit/FlipperKitLayoutTextSearchable (0.87.0) | ||||
|   - FlipperKit/FlipperKitNetworkPlugin (0.87.0): | ||||
|     - FlipperKit/Core | ||||
|   - FlipperKit/FlipperKitUserDefaultsPlugin (0.41.5): | ||||
|   - FlipperKit/FlipperKitReactPlugin (0.87.0): | ||||
|     - FlipperKit/Core | ||||
|   - FlipperKit/SKIOSNetworkPlugin (0.41.5): | ||||
|   - FlipperKit/FlipperKitUserDefaultsPlugin (0.87.0): | ||||
|     - FlipperKit/Core | ||||
|   - FlipperKit/SKIOSNetworkPlugin (0.87.0): | ||||
|     - FlipperKit/Core | ||||
|     - FlipperKit/FlipperKitNetworkPlugin | ||||
|   - Folly (2020.01.13.00): | ||||
| @ -69,254 +79,252 @@ PODS: | ||||
|     - DoubleConversion | ||||
|     - glog | ||||
|   - glog (0.3.5) | ||||
|   - OpenSSL-Universal (1.0.2.19): | ||||
|     - OpenSSL-Universal/Static (= 1.0.2.19) | ||||
|   - OpenSSL-Universal/Static (1.0.2.19) | ||||
|   - RCTRequired (0.63.2) | ||||
|   - RCTTypeSafety (0.63.2): | ||||
|     - FBLazyVector (= 0.63.2) | ||||
|   - libevent (2.1.12) | ||||
|   - OpenSSL-Universal (1.1.180) | ||||
|   - RCTRequired (0.63.4) | ||||
|   - RCTTypeSafety (0.63.4): | ||||
|     - FBLazyVector (= 0.63.4) | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - RCTRequired (= 0.63.2) | ||||
|     - React-Core (= 0.63.2) | ||||
|   - React (0.63.2): | ||||
|     - React-Core (= 0.63.2) | ||||
|     - React-Core/DevSupport (= 0.63.2) | ||||
|     - React-Core/RCTWebSocket (= 0.63.2) | ||||
|     - React-RCTActionSheet (= 0.63.2) | ||||
|     - React-RCTAnimation (= 0.63.2) | ||||
|     - React-RCTBlob (= 0.63.2) | ||||
|     - React-RCTImage (= 0.63.2) | ||||
|     - React-RCTLinking (= 0.63.2) | ||||
|     - React-RCTNetwork (= 0.63.2) | ||||
|     - React-RCTSettings (= 0.63.2) | ||||
|     - React-RCTText (= 0.63.2) | ||||
|     - React-RCTVibration (= 0.63.2) | ||||
|   - React-callinvoker (0.63.2) | ||||
|   - React-Core (0.63.2): | ||||
|     - RCTRequired (= 0.63.4) | ||||
|     - React-Core (= 0.63.4) | ||||
|   - React (0.63.4): | ||||
|     - React-Core (= 0.63.4) | ||||
|     - React-Core/DevSupport (= 0.63.4) | ||||
|     - React-Core/RCTWebSocket (= 0.63.4) | ||||
|     - React-RCTActionSheet (= 0.63.4) | ||||
|     - React-RCTAnimation (= 0.63.4) | ||||
|     - React-RCTBlob (= 0.63.4) | ||||
|     - React-RCTImage (= 0.63.4) | ||||
|     - React-RCTLinking (= 0.63.4) | ||||
|     - React-RCTNetwork (= 0.63.4) | ||||
|     - React-RCTSettings (= 0.63.4) | ||||
|     - React-RCTText (= 0.63.4) | ||||
|     - React-RCTVibration (= 0.63.4) | ||||
|   - React-callinvoker (0.63.4) | ||||
|   - React-Core (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-Core/Default (= 0.63.4) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/CoreModulesHeaders (0.63.2): | ||||
|   - React-Core/CoreModulesHeaders (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/Default (0.63.2): | ||||
|   - React-Core/Default (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/DevSupport (0.63.2): | ||||
|   - React-Core/DevSupport (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default (= 0.63.2) | ||||
|     - React-Core/RCTWebSocket (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-jsinspector (= 0.63.2) | ||||
|     - React-Core/Default (= 0.63.4) | ||||
|     - React-Core/RCTWebSocket (= 0.63.4) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - React-jsinspector (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/RCTActionSheetHeaders (0.63.2): | ||||
|   - React-Core/RCTActionSheetHeaders (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/RCTAnimationHeaders (0.63.2): | ||||
|   - React-Core/RCTAnimationHeaders (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/RCTBlobHeaders (0.63.2): | ||||
|   - React-Core/RCTBlobHeaders (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/RCTImageHeaders (0.63.2): | ||||
|   - React-Core/RCTImageHeaders (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/RCTLinkingHeaders (0.63.2): | ||||
|   - React-Core/RCTLinkingHeaders (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/RCTNetworkHeaders (0.63.2): | ||||
|   - React-Core/RCTNetworkHeaders (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/RCTSettingsHeaders (0.63.2): | ||||
|   - React-Core/RCTSettingsHeaders (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/RCTTextHeaders (0.63.2): | ||||
|   - React-Core/RCTTextHeaders (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/RCTVibrationHeaders (0.63.2): | ||||
|   - React-Core/RCTVibrationHeaders (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-Core/RCTWebSocket (0.63.2): | ||||
|   - React-Core/RCTWebSocket (0.63.4): | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-Core/Default (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-jsiexecutor (= 0.63.2) | ||||
|     - React-Core/Default (= 0.63.4) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-jsiexecutor (= 0.63.4) | ||||
|     - Yoga | ||||
|   - React-CoreModules (0.63.2): | ||||
|     - FBReactNativeSpec (= 0.63.2) | ||||
|   - React-CoreModules (0.63.4): | ||||
|     - FBReactNativeSpec (= 0.63.4) | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - RCTTypeSafety (= 0.63.2) | ||||
|     - React-Core/CoreModulesHeaders (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-RCTImage (= 0.63.2) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.2) | ||||
|   - React-cxxreact (0.63.2): | ||||
|     - RCTTypeSafety (= 0.63.4) | ||||
|     - React-Core/CoreModulesHeaders (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-RCTImage (= 0.63.4) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.4) | ||||
|   - React-cxxreact (0.63.4): | ||||
|     - boost-for-react-native (= 1.63.0) | ||||
|     - DoubleConversion | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-callinvoker (= 0.63.2) | ||||
|     - React-jsinspector (= 0.63.2) | ||||
|   - React-jsi (0.63.2): | ||||
|     - React-callinvoker (= 0.63.4) | ||||
|     - React-jsinspector (= 0.63.4) | ||||
|   - React-jsi (0.63.4): | ||||
|     - boost-for-react-native (= 1.63.0) | ||||
|     - DoubleConversion | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-jsi/Default (= 0.63.2) | ||||
|   - React-jsi/Default (0.63.2): | ||||
|     - React-jsi/Default (= 0.63.4) | ||||
|   - React-jsi/Default (0.63.4): | ||||
|     - boost-for-react-native (= 1.63.0) | ||||
|     - DoubleConversion | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|   - React-jsiexecutor (0.63.2): | ||||
|   - React-jsiexecutor (0.63.4): | ||||
|     - DoubleConversion | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|   - React-jsinspector (0.63.2) | ||||
|   - react-native-safe-area-context (3.1.4): | ||||
|     - React | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|   - React-jsinspector (0.63.4) | ||||
|   - react-native-safe-area-context (3.2.0): | ||||
|     - React-Core | ||||
|   - react-native-splash-screen (3.2.0): | ||||
|     - React | ||||
|   - react-native-webview (11.0.2): | ||||
|   - react-native-webview (11.6.4): | ||||
|     - React-Core | ||||
|   - React-RCTActionSheet (0.63.2): | ||||
|     - React-Core/RCTActionSheetHeaders (= 0.63.2) | ||||
|   - React-RCTAnimation (0.63.2): | ||||
|     - FBReactNativeSpec (= 0.63.2) | ||||
|   - React-RCTActionSheet (0.63.4): | ||||
|     - React-Core/RCTActionSheetHeaders (= 0.63.4) | ||||
|   - React-RCTAnimation (0.63.4): | ||||
|     - FBReactNativeSpec (= 0.63.4) | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - RCTTypeSafety (= 0.63.2) | ||||
|     - React-Core/RCTAnimationHeaders (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.2) | ||||
|   - React-RCTBlob (0.63.2): | ||||
|     - FBReactNativeSpec (= 0.63.2) | ||||
|     - RCTTypeSafety (= 0.63.4) | ||||
|     - React-Core/RCTAnimationHeaders (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.4) | ||||
|   - React-RCTBlob (0.63.4): | ||||
|     - FBReactNativeSpec (= 0.63.4) | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - React-Core/RCTBlobHeaders (= 0.63.2) | ||||
|     - React-Core/RCTWebSocket (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-RCTNetwork (= 0.63.2) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.2) | ||||
|   - React-RCTImage (0.63.2): | ||||
|     - FBReactNativeSpec (= 0.63.2) | ||||
|     - React-Core/RCTBlobHeaders (= 0.63.4) | ||||
|     - React-Core/RCTWebSocket (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-RCTNetwork (= 0.63.4) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.4) | ||||
|   - React-RCTImage (0.63.4): | ||||
|     - FBReactNativeSpec (= 0.63.4) | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - RCTTypeSafety (= 0.63.2) | ||||
|     - React-Core/RCTImageHeaders (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - React-RCTNetwork (= 0.63.2) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.2) | ||||
|   - React-RCTLinking (0.63.2): | ||||
|     - FBReactNativeSpec (= 0.63.2) | ||||
|     - React-Core/RCTLinkingHeaders (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.2) | ||||
|   - React-RCTNetwork (0.63.2): | ||||
|     - FBReactNativeSpec (= 0.63.2) | ||||
|     - RCTTypeSafety (= 0.63.4) | ||||
|     - React-Core/RCTImageHeaders (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - React-RCTNetwork (= 0.63.4) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.4) | ||||
|   - React-RCTLinking (0.63.4): | ||||
|     - FBReactNativeSpec (= 0.63.4) | ||||
|     - React-Core/RCTLinkingHeaders (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.4) | ||||
|   - React-RCTNetwork (0.63.4): | ||||
|     - FBReactNativeSpec (= 0.63.4) | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - RCTTypeSafety (= 0.63.2) | ||||
|     - React-Core/RCTNetworkHeaders (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.2) | ||||
|   - React-RCTSettings (0.63.2): | ||||
|     - FBReactNativeSpec (= 0.63.2) | ||||
|     - RCTTypeSafety (= 0.63.4) | ||||
|     - React-Core/RCTNetworkHeaders (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.4) | ||||
|   - React-RCTSettings (0.63.4): | ||||
|     - FBReactNativeSpec (= 0.63.4) | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - RCTTypeSafety (= 0.63.2) | ||||
|     - React-Core/RCTSettingsHeaders (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.2) | ||||
|   - React-RCTText (0.63.2): | ||||
|     - React-Core/RCTTextHeaders (= 0.63.2) | ||||
|   - React-RCTVibration (0.63.2): | ||||
|     - FBReactNativeSpec (= 0.63.2) | ||||
|     - RCTTypeSafety (= 0.63.4) | ||||
|     - React-Core/RCTSettingsHeaders (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.4) | ||||
|   - React-RCTText (0.63.4): | ||||
|     - React-Core/RCTTextHeaders (= 0.63.4) | ||||
|   - React-RCTVibration (0.63.4): | ||||
|     - FBReactNativeSpec (= 0.63.4) | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - React-Core/RCTVibrationHeaders (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.2) | ||||
|   - ReactCommon/turbomodule/core (0.63.2): | ||||
|     - React-Core/RCTVibrationHeaders (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|     - ReactCommon/turbomodule/core (= 0.63.4) | ||||
|   - ReactCommon/turbomodule/core (0.63.4): | ||||
|     - DoubleConversion | ||||
|     - Folly (= 2020.01.13.00) | ||||
|     - glog | ||||
|     - React-callinvoker (= 0.63.2) | ||||
|     - React-Core (= 0.63.2) | ||||
|     - React-cxxreact (= 0.63.2) | ||||
|     - React-jsi (= 0.63.2) | ||||
|   - RNCAsyncStorage (1.13.0): | ||||
|     - React-callinvoker (= 0.63.4) | ||||
|     - React-Core (= 0.63.4) | ||||
|     - React-cxxreact (= 0.63.4) | ||||
|     - React-jsi (= 0.63.4) | ||||
|   - RNCAsyncStorage (1.15.5): | ||||
|     - React-Core | ||||
|   - RNCMaskedView (0.1.11): | ||||
|     - React | ||||
|   - RNCMaskedView (0.1.10): | ||||
|     - React | ||||
|   - RNGestureHandler (1.7.0): | ||||
|     - React | ||||
|   - RNI18n (2.0.15): | ||||
|     - React | ||||
|   - RNReanimated (1.10.2): | ||||
|     - React | ||||
|   - RNScreens (2.10.1): | ||||
|     - React | ||||
|   - RNVectorIcons (7.0.0): | ||||
|   - RNGestureHandler (1.10.3): | ||||
|     - React-Core | ||||
|   - RNLocalize (2.1.1): | ||||
|     - React-Core | ||||
|   - RNScreens (3.4.0): | ||||
|     - React-Core | ||||
|     - React-RCTImage | ||||
|   - RNVectorIcons (7.1.0): | ||||
|     - React | ||||
|   - Yoga (1.14.0) | ||||
|   - YogaKit (1.18.1): | ||||
| @ -327,25 +335,25 @@ DEPENDENCIES: | ||||
|   - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) | ||||
|   - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) | ||||
|   - FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`) | ||||
|   - Flipper (~> 0.41.1) | ||||
|   - Flipper (= 0.87.0) | ||||
|   - Flipper-DoubleConversion (= 1.1.7) | ||||
|   - Flipper-Folly (~> 2.2) | ||||
|   - Flipper-Folly (= 2.5.3) | ||||
|   - Flipper-Glog (= 0.3.6) | ||||
|   - Flipper-PeerTalk (~> 0.0.4) | ||||
|   - Flipper-RSocket (~> 1.1) | ||||
|   - FlipperKit (~> 0.41.1) | ||||
|   - FlipperKit/Core (~> 0.41.1) | ||||
|   - FlipperKit/CppBridge (~> 0.41.1) | ||||
|   - FlipperKit/FBCxxFollyDynamicConvert (~> 0.41.1) | ||||
|   - FlipperKit/FBDefines (~> 0.41.1) | ||||
|   - FlipperKit/FKPortForwarding (~> 0.41.1) | ||||
|   - FlipperKit/FlipperKitHighlightOverlay (~> 0.41.1) | ||||
|   - FlipperKit/FlipperKitLayoutPlugin (~> 0.41.1) | ||||
|   - FlipperKit/FlipperKitLayoutTextSearchable (~> 0.41.1) | ||||
|   - FlipperKit/FlipperKitNetworkPlugin (~> 0.41.1) | ||||
|   - FlipperKit/FlipperKitReactPlugin (~> 0.41.1) | ||||
|   - FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.41.1) | ||||
|   - FlipperKit/SKIOSNetworkPlugin (~> 0.41.1) | ||||
|   - Flipper-RSocket (= 1.3.1) | ||||
|   - FlipperKit (= 0.87.0) | ||||
|   - FlipperKit/Core (= 0.87.0) | ||||
|   - FlipperKit/CppBridge (= 0.87.0) | ||||
|   - FlipperKit/FBCxxFollyDynamicConvert (= 0.87.0) | ||||
|   - FlipperKit/FBDefines (= 0.87.0) | ||||
|   - FlipperKit/FKPortForwarding (= 0.87.0) | ||||
|   - FlipperKit/FlipperKitHighlightOverlay (= 0.87.0) | ||||
|   - FlipperKit/FlipperKitLayoutPlugin (= 0.87.0) | ||||
|   - FlipperKit/FlipperKitLayoutTextSearchable (= 0.87.0) | ||||
|   - FlipperKit/FlipperKitNetworkPlugin (= 0.87.0) | ||||
|   - FlipperKit/FlipperKitReactPlugin (= 0.87.0) | ||||
|   - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.87.0) | ||||
|   - FlipperKit/SKIOSNetworkPlugin (= 0.87.0) | ||||
|   - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) | ||||
|   - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) | ||||
|   - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) | ||||
| @ -373,11 +381,10 @@ DEPENDENCIES: | ||||
|   - React-RCTText (from `../node_modules/react-native/Libraries/Text`) | ||||
|   - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) | ||||
|   - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) | ||||
|   - "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)" | ||||
|   - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" | ||||
|   - "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)" | ||||
|   - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) | ||||
|   - RNI18n (from `../node_modules/react-native-i18n`) | ||||
|   - RNReanimated (from `../node_modules/react-native-reanimated`) | ||||
|   - RNLocalize (from `../node_modules/react-native-localize`) | ||||
|   - RNScreens (from `../node_modules/react-native-screens`) | ||||
|   - RNVectorIcons (from `../node_modules/react-native-vector-icons`) | ||||
|   - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) | ||||
| @ -386,7 +393,6 @@ SPEC REPOS: | ||||
|   trunk: | ||||
|     - boost-for-react-native | ||||
|     - CocoaAsyncSocket | ||||
|     - CocoaLibEvent | ||||
|     - Flipper | ||||
|     - Flipper-DoubleConversion | ||||
|     - Flipper-Folly | ||||
| @ -394,6 +400,7 @@ SPEC REPOS: | ||||
|     - Flipper-PeerTalk | ||||
|     - Flipper-RSocket | ||||
|     - FlipperKit | ||||
|     - libevent | ||||
|     - OpenSSL-Universal | ||||
|     - YogaKit | ||||
| 
 | ||||
| @ -457,15 +464,13 @@ EXTERNAL SOURCES: | ||||
|   ReactCommon: | ||||
|     :path: "../node_modules/react-native/ReactCommon" | ||||
|   RNCAsyncStorage: | ||||
|     :path: "../node_modules/@react-native-community/async-storage" | ||||
|     :path: "../node_modules/@react-native-async-storage/async-storage" | ||||
|   RNCMaskedView: | ||||
|     :path: "../node_modules/@react-native-community/masked-view" | ||||
|   RNGestureHandler: | ||||
|     :path: "../node_modules/react-native-gesture-handler" | ||||
|   RNI18n: | ||||
|     :path: "../node_modules/react-native-i18n" | ||||
|   RNReanimated: | ||||
|     :path: "../node_modules/react-native-reanimated" | ||||
|   RNLocalize: | ||||
|     :path: "../node_modules/react-native-localize" | ||||
|   RNScreens: | ||||
|     :path: "../node_modules/react-native-screens" | ||||
|   RNVectorIcons: | ||||
| @ -477,53 +482,52 @@ SPEC CHECKSUMS: | ||||
|   boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c | ||||
|   BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872 | ||||
|   CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 | ||||
|   CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f | ||||
|   DoubleConversion: cde416483dac037923206447da6e1454df403714 | ||||
|   FBLazyVector: 3ef4a7f62e7db01092f9d517d2ebc0d0677c4a37 | ||||
|   FBReactNativeSpec: dc7fa9088f0f2a998503a352b0554d69a4391c5a | ||||
|   Flipper: 33585e2d9810fe5528346be33bcf71b37bb7ae13 | ||||
|   FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e | ||||
|   FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e | ||||
|   Flipper: 1bd2db48dcc31e4b167b9a33ec1df01c2ded4893 | ||||
|   Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 | ||||
|   Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3 | ||||
|   Flipper-Folly: 755929a4f851b2fb2c347d533a23f191b008554c | ||||
|   Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6 | ||||
|   Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 | ||||
|   Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7 | ||||
|   FlipperKit: bc68102cd4952a258a23c9c1b316c7bec1fecf83 | ||||
|   Flipper-RSocket: 127954abe8b162fcaf68d2134d34dc2bd7076154 | ||||
|   FlipperKit: 651f50a42eb95c01b3e89a60996dd6aded529eeb | ||||
|   Folly: b73c3869541e86821df3c387eb0af5f65addfab4 | ||||
|   glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3 | ||||
|   OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 | ||||
|   RCTRequired: f13f25e7b12f925f1f6a6a8c69d929a03c0129fe | ||||
|   RCTTypeSafety: 44982c5c8e43ff4141eb519a8ddc88059acd1f3a | ||||
|   React: e1c65dd41cb9db13b99f24608e47dd595f28ca9a | ||||
|   React-callinvoker: 552a6a6bc8b3bb794cf108ad59e5a9e2e3b4fc98 | ||||
|   React-Core: 9d341e725dc9cd2f49e4c49ad1fc4e8776aa2639 | ||||
|   React-CoreModules: 5335e168165da7f7083ce7147768d36d3e292318 | ||||
|   React-cxxreact: d3261ec5f7d11743fbf21e263a34ea51d1f13ebc | ||||
|   React-jsi: 54245e1d5f4b690dec614a73a3795964eeef13a8 | ||||
|   React-jsiexecutor: 8ca588cc921e70590820ce72b8789b02c67cce38 | ||||
|   React-jsinspector: b14e62ebe7a66e9231e9581279909f2fc3db6606 | ||||
|   react-native-safe-area-context: 0ed9288ed4409beabb0817b54efc047286fc84da | ||||
|   libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 | ||||
|   OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b | ||||
|   RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e | ||||
|   RCTTypeSafety: 8c9c544ecbf20337d069e4ae7fd9a377aadf504b | ||||
|   React: b0a957a2c44da4113b0c4c9853d8387f8e64e615 | ||||
|   React-callinvoker: c3f44dd3cb195b6aa46621fff95ded79d59043fe | ||||
|   React-Core: d3b2a1ac9a2c13c3bcde712d9281fc1c8a5b315b | ||||
|   React-CoreModules: 0581ff36cb797da0943d424f69e7098e43e9be60 | ||||
|   React-cxxreact: c1480d4fda5720086c90df537ee7d285d4c57ac3 | ||||
|   React-jsi: a0418934cf48f25b485631deb27c64dc40fb4c31 | ||||
|   React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949 | ||||
|   React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a | ||||
|   react-native-safe-area-context: f0906bf8bc9835ac9a9d3f97e8bde2a997d8da79 | ||||
|   react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 | ||||
|   react-native-webview: b2542d6fd424bcc3e3b2ec5f854f0abb4ec86c87 | ||||
|   React-RCTActionSheet: 910163b6b09685a35c4ebbc52b66d1bfbbe39fc5 | ||||
|   React-RCTAnimation: 9a883bbe1e9d2e158d4fb53765ed64c8dc2200c6 | ||||
|   React-RCTBlob: 39cf0ece1927996c4466510e25d2105f67010e13 | ||||
|   React-RCTImage: de355d738727b09ad3692f2a979affbd54b5f378 | ||||
|   React-RCTLinking: 8122f221d395a63364b2c0078ce284214bd04575 | ||||
|   React-RCTNetwork: 8f96c7b49ea6a0f28f98258f347b6ad218bc0830 | ||||
|   React-RCTSettings: 8a49622aff9c1925f5455fa340b6fe4853d64ab6 | ||||
|   React-RCTText: 1b6773e776e4b33f90468c20fe3b16ca3e224bb8 | ||||
|   React-RCTVibration: 4d2e726957f4087449739b595f107c0d4b6c2d2d | ||||
|   ReactCommon: a0a1edbebcac5e91338371b72ffc66aa822792ce | ||||
|   RNCAsyncStorage: b34c5db7bd4b2ef9a7ced5b59b1e6a0c5c6eb24e | ||||
|   RNCMaskedView: f5c7d14d6847b7b44853f7acb6284c1da30a3459 | ||||
|   RNGestureHandler: b6b359bb800ae399a9c8b27032bdbf7c18f08a08 | ||||
|   RNI18n: e2f7e76389fcc6e84f2c8733ea89b92502351fd8 | ||||
|   RNReanimated: 7de2dca51deacff78bb880f63c1389a24311b376 | ||||
|   RNScreens: b748efec66e095134c7166ca333b628cd7e6f3e2 | ||||
|   RNVectorIcons: da6fe858f5a65d7bbc3379540a889b0b12aa5976 | ||||
|   Yoga: 7740b94929bbacbddda59bf115b5317e9a161598 | ||||
|   react-native-webview: 1a19adb5578cdf7f005b7961dcc50c1c6b70f41b | ||||
|   React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336 | ||||
|   React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b | ||||
|   React-RCTBlob: a97d378b527740cc667e03ebfa183a75231ab0f0 | ||||
|   React-RCTImage: c1b1f2d3f43a4a528c8946d6092384b5c880d2f0 | ||||
|   React-RCTLinking: 35ae4ab9dc0410d1fcbdce4d7623194a27214fb2 | ||||
|   React-RCTNetwork: 29ec2696f8d8cfff7331fac83d3e893c95ef43ae | ||||
|   React-RCTSettings: 60f0691bba2074ef394f95d4c2265ec284e0a46a | ||||
|   React-RCTText: 5c51df3f08cb9dedc6e790161195d12bac06101c | ||||
|   React-RCTVibration: ae4f914cfe8de7d4de95ae1ea6cc8f6315d73d9d | ||||
|   ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b | ||||
|   RNCAsyncStorage: 56a3355a10b5d660c48c6e37325ac85ebfd09885 | ||||
|   RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489 | ||||
|   RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211 | ||||
|   RNLocalize: 82a569022724d35461e2dc5b5d015a13c3ca995b | ||||
|   RNScreens: 21b73c94c9117e1110a79ee0ee80c93ccefed8ce | ||||
|   RNVectorIcons: bc69e6a278b14842063605de32bec61f0b251a59 | ||||
|   Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6 | ||||
|   YogaKit: f782866e155069a2cca2517aafea43200b01fd5a | ||||
| 
 | ||||
| PODFILE CHECKSUM: 06472af1eb4acd0770fd4d29e23ee525801f7cd1 | ||||
| PODFILE CHECKSUM: 685f7c9567d158eb76c7fbd85c7248da2f22d7c8 | ||||
| 
 | ||||
| COCOAPODS: 1.9.3 | ||||
| COCOAPODS: 1.10.1 | ||||
|  | ||||
| @ -249,6 +249,7 @@ | ||||
| 				00E356EB1AD99517003FC87E /* Frameworks */, | ||||
| 				00E356EC1AD99517003FC87E /* Resources */, | ||||
| 				7BC6AD0A9D3DE575F2E558E1 /* [CP] Copy Pods Resources */, | ||||
| 				8EEC6804BF6C2BF286A5F7D9 /* [CP] Embed Pods Frameworks */, | ||||
| 			); | ||||
| 			buildRules = ( | ||||
| 			); | ||||
| @ -271,6 +272,7 @@ | ||||
| 				13B07F8E1A680F5B00A75B9A /* Resources */, | ||||
| 				00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, | ||||
| 				D2DD3F2F99A693C12757405F /* [CP] Copy Pods Resources */, | ||||
| 				2E1AEAA3F8B118A5A91DE143 /* [CP] Embed Pods Frameworks */, | ||||
| 			); | ||||
| 			buildRules = ( | ||||
| 			); | ||||
| @ -326,7 +328,7 @@ | ||||
| 		83CBB9F71A601CBA00E9B192 /* Project object */ = { | ||||
| 			isa = PBXProject; | ||||
| 			attributes = { | ||||
| 				LastUpgradeCheck = 1130; | ||||
| 				LastUpgradeCheck = 1240; | ||||
| 				TargetAttributes = { | ||||
| 					00E356ED1AD99517003FC87E = { | ||||
| 						CreatedOnToolsVersion = 6.2; | ||||
| @ -474,6 +476,24 @@ | ||||
| 			shellPath = /bin/sh; | ||||
| 			shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; | ||||
| 		}; | ||||
| 		2E1AEAA3F8B118A5A91DE143 /* [CP] Embed Pods Frameworks */ = { | ||||
| 			isa = PBXShellScriptBuildPhase; | ||||
| 			buildActionMask = 2147483647; | ||||
| 			files = ( | ||||
| 			); | ||||
| 			inputPaths = ( | ||||
| 				"${PODS_ROOT}/Target Support Files/Pods-blazerapp/Pods-blazerapp-frameworks.sh", | ||||
| 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL/OpenSSL.framework/OpenSSL", | ||||
| 			); | ||||
| 			name = "[CP] Embed Pods Frameworks"; | ||||
| 			outputPaths = ( | ||||
| 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", | ||||
| 			); | ||||
| 			runOnlyForDeploymentPostprocessing = 0; | ||||
| 			shellPath = /bin/sh; | ||||
| 			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-blazerapp/Pods-blazerapp-frameworks.sh\"\n"; | ||||
| 			showEnvVarsInLog = 0; | ||||
| 		}; | ||||
| 		7BC6AD0A9D3DE575F2E558E1 /* [CP] Copy Pods Resources */ = { | ||||
| 			isa = PBXShellScriptBuildPhase; | ||||
| 			buildActionMask = 2147483647; | ||||
| @ -524,6 +544,24 @@ | ||||
| 			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-blazerapp-blazerappTests/Pods-blazerapp-blazerappTests-resources.sh\"\n"; | ||||
| 			showEnvVarsInLog = 0; | ||||
| 		}; | ||||
| 		8EEC6804BF6C2BF286A5F7D9 /* [CP] Embed Pods Frameworks */ = { | ||||
| 			isa = PBXShellScriptBuildPhase; | ||||
| 			buildActionMask = 2147483647; | ||||
| 			files = ( | ||||
| 			); | ||||
| 			inputPaths = ( | ||||
| 				"${PODS_ROOT}/Target Support Files/Pods-blazerapp-blazerappTests/Pods-blazerapp-blazerappTests-frameworks.sh", | ||||
| 				"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL/OpenSSL.framework/OpenSSL", | ||||
| 			); | ||||
| 			name = "[CP] Embed Pods Frameworks"; | ||||
| 			outputPaths = ( | ||||
| 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", | ||||
| 			); | ||||
| 			runOnlyForDeploymentPostprocessing = 0; | ||||
| 			shellPath = /bin/sh; | ||||
| 			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-blazerapp-blazerappTests/Pods-blazerapp-blazerappTests-frameworks.sh\"\n"; | ||||
| 			showEnvVarsInLog = 0; | ||||
| 		}; | ||||
| 		93A4E96E8852D8799C8883AB /* [CP] Check Pods Manifest.lock */ = { | ||||
| 			isa = PBXShellScriptBuildPhase; | ||||
| 			buildActionMask = 2147483647; | ||||
| @ -719,7 +757,7 @@ | ||||
| 					"$(inherited)", | ||||
| 				); | ||||
| 				INFOPLIST_FILE = blazerappTests/Info.plist; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 10.0; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 12.0; | ||||
| 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; | ||||
| 				OTHER_LDFLAGS = ( | ||||
| 					"-ObjC", | ||||
| @ -739,7 +777,7 @@ | ||||
| 				BUNDLE_LOADER = "$(TEST_HOST)"; | ||||
| 				COPY_PHASE_STRIP = NO; | ||||
| 				INFOPLIST_FILE = blazerappTests/Info.plist; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 10.0; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 12.0; | ||||
| 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; | ||||
| 				OTHER_LDFLAGS = ( | ||||
| 					"-ObjC", | ||||
| @ -761,7 +799,7 @@ | ||||
| 				CURRENT_PROJECT_VERSION = 1; | ||||
| 				ENABLE_BITCODE = NO; | ||||
| 				INFOPLIST_FILE = blazerapp/Info.plist; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 11.0; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 12.0; | ||||
| 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; | ||||
| 				OTHER_LDFLAGS = ( | ||||
| 					"$(inherited)", | ||||
| @ -784,7 +822,7 @@ | ||||
| 				CLANG_ENABLE_MODULES = YES; | ||||
| 				CURRENT_PROJECT_VERSION = 1; | ||||
| 				INFOPLIST_FILE = blazerapp/Info.plist; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 11.0; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 12.0; | ||||
| 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; | ||||
| 				OTHER_LDFLAGS = ( | ||||
| 					"$(inherited)", | ||||
| @ -822,7 +860,7 @@ | ||||
| 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||
| 				SDKROOT = appletvos; | ||||
| 				TARGETED_DEVICE_FAMILY = 3; | ||||
| 				TVOS_DEPLOYMENT_TARGET = 11.0; | ||||
| 				TVOS_DEPLOYMENT_TARGET = 12.0; | ||||
| 			}; | ||||
| 			name = Debug; | ||||
| 		}; | ||||
| @ -850,7 +888,7 @@ | ||||
| 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||
| 				SDKROOT = appletvos; | ||||
| 				TARGETED_DEVICE_FAMILY = 3; | ||||
| 				TVOS_DEPLOYMENT_TARGET = 11.0; | ||||
| 				TVOS_DEPLOYMENT_TARGET = 12.0; | ||||
| 			}; | ||||
| 			name = Release; | ||||
| 		}; | ||||
| @ -877,7 +915,7 @@ | ||||
| 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||
| 				SDKROOT = appletvos; | ||||
| 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/blazerapp-tvOS.app/blazerapp-tvOS"; | ||||
| 				TVOS_DEPLOYMENT_TARGET = 10.1; | ||||
| 				TVOS_DEPLOYMENT_TARGET = 12.0; | ||||
| 			}; | ||||
| 			name = Debug; | ||||
| 		}; | ||||
| @ -904,7 +942,7 @@ | ||||
| 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||
| 				SDKROOT = appletvos; | ||||
| 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/blazerapp-tvOS.app/blazerapp-tvOS"; | ||||
| 				TVOS_DEPLOYMENT_TARGET = 10.1; | ||||
| 				TVOS_DEPLOYMENT_TARGET = 12.0; | ||||
| 			}; | ||||
| 			name = Release; | ||||
| 		}; | ||||
| @ -931,6 +969,7 @@ | ||||
| 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | ||||
| 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | ||||
| 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | ||||
| 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; | ||||
| 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | ||||
| 				CLANG_WARN_STRICT_PROTOTYPES = YES; | ||||
| 				CLANG_WARN_SUSPICIOUS_MOVE = YES; | ||||
| @ -955,7 +994,7 @@ | ||||
| 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||||
| 				GCC_WARN_UNUSED_FUNCTION = YES; | ||||
| 				GCC_WARN_UNUSED_VARIABLE = YES; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 11.0; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 12.0; | ||||
| 				LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; | ||||
| 				LIBRARY_SEARCH_PATHS = ( | ||||
| 					"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", | ||||
| @ -991,6 +1030,7 @@ | ||||
| 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | ||||
| 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | ||||
| 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | ||||
| 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; | ||||
| 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | ||||
| 				CLANG_WARN_STRICT_PROTOTYPES = YES; | ||||
| 				CLANG_WARN_SUSPICIOUS_MOVE = YES; | ||||
| @ -1008,7 +1048,7 @@ | ||||
| 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||||
| 				GCC_WARN_UNUSED_FUNCTION = YES; | ||||
| 				GCC_WARN_UNUSED_VARIABLE = YES; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 11.0; | ||||
| 				IPHONEOS_DEPLOYMENT_TARGET = 12.0; | ||||
| 				LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; | ||||
| 				LIBRARY_SEARCH_PATHS = ( | ||||
| 					"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <Scheme | ||||
|    LastUpgradeVersion = "1130" | ||||
|    LastUpgradeVersion = "1250" | ||||
|    version = "1.3"> | ||||
|    <BuildAction | ||||
|       parallelizeBuildables = "YES" | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <Scheme | ||||
|    LastUpgradeVersion = "1130" | ||||
|    LastUpgradeVersion = "1250" | ||||
|    version = "1.3"> | ||||
|    <BuildAction | ||||
|       parallelizeBuildables = "YES" | ||||
|  | ||||
| @ -2,37 +2,52 @@ | ||||
|   "images" : [ | ||||
|     { | ||||
|       "idiom" : "iphone", | ||||
|       "size" : "29x29", | ||||
|       "scale" : "2x" | ||||
|       "scale" : "2x", | ||||
|       "size" : "20x20" | ||||
|     }, | ||||
|     { | ||||
|       "idiom" : "iphone", | ||||
|       "size" : "29x29", | ||||
|       "scale" : "3x" | ||||
|       "scale" : "3x", | ||||
|       "size" : "20x20" | ||||
|     }, | ||||
|     { | ||||
|       "idiom" : "iphone", | ||||
|       "size" : "40x40", | ||||
|       "scale" : "2x" | ||||
|       "scale" : "2x", | ||||
|       "size" : "29x29" | ||||
|     }, | ||||
|     { | ||||
|       "idiom" : "iphone", | ||||
|       "size" : "40x40", | ||||
|       "scale" : "3x" | ||||
|       "scale" : "3x", | ||||
|       "size" : "29x29" | ||||
|     }, | ||||
|     { | ||||
|       "idiom" : "iphone", | ||||
|       "size" : "60x60", | ||||
|       "scale" : "2x" | ||||
|       "scale" : "2x", | ||||
|       "size" : "40x40" | ||||
|     }, | ||||
|     { | ||||
|       "idiom" : "iphone", | ||||
|       "size" : "60x60", | ||||
|       "scale" : "3x" | ||||
|       "scale" : "3x", | ||||
|       "size" : "40x40" | ||||
|     }, | ||||
|     { | ||||
|       "idiom" : "iphone", | ||||
|       "scale" : "2x", | ||||
|       "size" : "60x60" | ||||
|     }, | ||||
|     { | ||||
|       "idiom" : "iphone", | ||||
|       "scale" : "3x", | ||||
|       "size" : "60x60" | ||||
|     }, | ||||
|     { | ||||
|       "idiom" : "ios-marketing", | ||||
|       "scale" : "1x", | ||||
|       "size" : "1024x1024" | ||||
|     } | ||||
|   ], | ||||
|   "info" : { | ||||
|     "version" : 1, | ||||
|     "author" : "xcode" | ||||
|     "author" : "xcode", | ||||
|     "version" : 1 | ||||
|   } | ||||
| } | ||||
| } | ||||
|  | ||||
							
								
								
									
										26389
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
							
								
								
									
										22
									
								
								package.json
									
									
									
									
									
								
							
							
						
						| @ -11,27 +11,27 @@ | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@k3rn31p4nic/google-translate-api": "github:k3rn31p4nic/google-translate-api", | ||||
|     "@react-native-community/async-storage": "github:react-native-community/async-storage", | ||||
|     "@react-native-community/masked-view": "^0.1.10", | ||||
|     "@react-native-async-storage/async-storage": "^1.15.5", | ||||
|     "@react-native-community/masked-view": "^0.1.11", | ||||
|     "@react-navigation/bottom-tabs": "^5.8.0", | ||||
|     "@react-navigation/native": "^5.7.3", | ||||
|     "@react-navigation/native": "^5.9.4", | ||||
|     "@react-navigation/stack": "^5.9.0", | ||||
|     "@vitalets/google-translate-api": "^4.0.0", | ||||
|     "events": "^3.2.0", | ||||
|     "i18next": "^19.8.4", | ||||
|     "i18next-react-native-language-detector": "^1.0.2", | ||||
|     "i18n-js": "^3.8.0", | ||||
|     "i18next": "^20.3.3", | ||||
|     "lodash.memoize": "^4.1.2", | ||||
|     "querystring": "^0.2.0", | ||||
|     "react": "16.13.1", | ||||
|     "react-i18next": "^11.8.5", | ||||
|     "react-i18next": "^11.11.3", | ||||
|     "react-native": "^0.63.2", | ||||
|     "react-native-elements": "^2.2.0", | ||||
|     "react-native-gesture-handler": "^1.7.0", | ||||
|     "react-native-i18n": "^2.0.15", | ||||
|     "react-native-gesture-handler": "^1.10.3", | ||||
|     "react-native-linear-gradient": "^2.5.6", | ||||
|     "react-native-locale-detector": "^1.0.1", | ||||
|     "react-native-reanimated": "^1.10.2", | ||||
|     "react-native-safe-area-context": "^3.1.4", | ||||
|     "react-native-screens": "^2.10.1", | ||||
|     "react-native-localize": "^2.1.1", | ||||
|     "react-native-safe-area-context": "^3.2.0", | ||||
|     "react-native-screens": "^3.4.0", | ||||
|     "react-native-splash-screen": "^3.2.0", | ||||
|     "react-native-vector-icons": "^7.0.0", | ||||
|     "react-native-webview": "^11.0.2", | ||||
|  | ||||
							
								
								
									
										2
									
								
								rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,2 @@ | ||||
| imports_granularity="Crate" | ||||
| reorder_imports = true | ||||