commit
parent
ec243c5558
commit
0c25cc8e36
118
App.tsx
118
App.tsx
|
@ -1,118 +0,0 @@
|
||||||
/**
|
|
||||||
* Sample React Native App
|
|
||||||
* https://github.com/facebook/react-native
|
|
||||||
*
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import type {PropsWithChildren} from 'react';
|
|
||||||
import {
|
|
||||||
SafeAreaView,
|
|
||||||
ScrollView,
|
|
||||||
StatusBar,
|
|
||||||
StyleSheet,
|
|
||||||
Text,
|
|
||||||
useColorScheme,
|
|
||||||
View,
|
|
||||||
} from 'react-native';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Colors,
|
|
||||||
DebugInstructions,
|
|
||||||
Header,
|
|
||||||
LearnMoreLinks,
|
|
||||||
ReloadInstructions,
|
|
||||||
} from 'react-native/Libraries/NewAppScreen';
|
|
||||||
|
|
||||||
type SectionProps = PropsWithChildren<{
|
|
||||||
title: string;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
function Section({children, title}: SectionProps): JSX.Element {
|
|
||||||
const isDarkMode = useColorScheme() === 'dark';
|
|
||||||
return (
|
|
||||||
<View style={styles.sectionContainer}>
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
styles.sectionTitle,
|
|
||||||
{
|
|
||||||
color: isDarkMode ? Colors.white : Colors.black,
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
{title}
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
styles.sectionDescription,
|
|
||||||
{
|
|
||||||
color: isDarkMode ? Colors.light : Colors.dark,
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
{children}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function App(): JSX.Element {
|
|
||||||
const isDarkMode = useColorScheme() === 'dark';
|
|
||||||
|
|
||||||
const backgroundStyle = {
|
|
||||||
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SafeAreaView style={backgroundStyle}>
|
|
||||||
<StatusBar
|
|
||||||
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
|
|
||||||
backgroundColor={backgroundStyle.backgroundColor}
|
|
||||||
/>
|
|
||||||
<ScrollView
|
|
||||||
contentInsetAdjustmentBehavior="automatic"
|
|
||||||
style={backgroundStyle}>
|
|
||||||
<Header />
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
backgroundColor: isDarkMode ? Colors.black : Colors.white,
|
|
||||||
}}>
|
|
||||||
<Section title="Step One">
|
|
||||||
Edit <Text style={styles.highlight}>App.tsx</Text> to change this
|
|
||||||
screen and then come back to see your edits.
|
|
||||||
</Section>
|
|
||||||
<Section title="See Your Changes">
|
|
||||||
<ReloadInstructions />
|
|
||||||
</Section>
|
|
||||||
<Section title="Debug">
|
|
||||||
<DebugInstructions />
|
|
||||||
</Section>
|
|
||||||
<Section title="Learn More">
|
|
||||||
Read the docs to discover what to do next:
|
|
||||||
</Section>
|
|
||||||
<LearnMoreLinks />
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
sectionContainer: {
|
|
||||||
marginTop: 32,
|
|
||||||
paddingHorizontal: 24,
|
|
||||||
},
|
|
||||||
sectionTitle: {
|
|
||||||
fontSize: 24,
|
|
||||||
fontWeight: '600',
|
|
||||||
},
|
|
||||||
sectionDescription: {
|
|
||||||
marginTop: 8,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: '400',
|
|
||||||
},
|
|
||||||
highlight: {
|
|
||||||
fontWeight: '700',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default App;
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
machine api.mapbox.com
|
||||||
|
login mapbox
|
||||||
|
password sk.eyJ1IjoidGl0YW5pdW1iYWNoIiwiYSI6ImNscGlkb3I5MTBmbTYycm1oNDRmaWJrNTUifQ.Xp5gptRu3GcyAi8ihoOoIg
|
|
@ -50,7 +50,13 @@ target 'app' do
|
||||||
# Pods for testing
|
# Pods for testing
|
||||||
end
|
end
|
||||||
|
|
||||||
|
pre_install do |installer|
|
||||||
|
$RNMapboxMaps.pre_install(installer)
|
||||||
|
... other pre install hooks
|
||||||
|
end
|
||||||
|
|
||||||
post_install do |installer|
|
post_install do |installer|
|
||||||
|
$RNMapboxMaps.post_install(installer)
|
||||||
# https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
|
# https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
|
||||||
react_native_post_install(
|
react_native_post_install(
|
||||||
installer,
|
installer,
|
||||||
|
|
|
@ -16,14 +16,18 @@
|
||||||
"@react-navigation/native-stack": "^6.9.17",
|
"@react-navigation/native-stack": "^6.9.17",
|
||||||
"@react-spring/native": "^9.7.3",
|
"@react-spring/native": "^9.7.3",
|
||||||
"@reduxjs/toolkit": "^1.9.7",
|
"@reduxjs/toolkit": "^1.9.7",
|
||||||
|
"@rnmapbox/maps": "^10.0.15",
|
||||||
"@types/react-native-vector-icons": "^6.4.18",
|
"@types/react-native-vector-icons": "^6.4.18",
|
||||||
|
"geolib": "^3.3.4",
|
||||||
"password-quality-calculator": "^1.0.4",
|
"password-quality-calculator": "^1.0.4",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-native": "0.72.7",
|
"react-native": "0.72.7",
|
||||||
"react-native-encrypted-storage": "^4.0.3",
|
"react-native-encrypted-storage": "^4.0.3",
|
||||||
|
"react-native-fs": "^2.20.0",
|
||||||
"react-native-linear-gradient": "^2.8.3",
|
"react-native-linear-gradient": "^2.8.3",
|
||||||
"react-native-safe-area-context": "^4.7.4",
|
"react-native-safe-area-context": "^4.7.4",
|
||||||
"react-native-screens": "^3.27.0",
|
"react-native-screens": "^3.27.0",
|
||||||
|
"react-native-securerandom": "^1.0.1",
|
||||||
"react-native-svg": "^13.4.0",
|
"react-native-svg": "^13.4.0",
|
||||||
"react-native-user-agent": "^2.3.1",
|
"react-native-user-agent": "^2.3.1",
|
||||||
"react-native-vector-icons": "^10.0.2",
|
"react-native-vector-icons": "^10.0.2",
|
||||||
|
@ -8058,6 +8062,34 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@rnmapbox/maps": {
|
||||||
|
"version": "10.0.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rnmapbox/maps/-/maps-10.0.15.tgz",
|
||||||
|
"integrity": "sha512-2diBwMF+e7gR6keZ1AEI3xw8U7Cu9+xhv8ce75Bw7flg9aTk+d0KgWv4VDQn4wSphD23EroUgFprVymHvVzZGQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/along": "6.5.0",
|
||||||
|
"@turf/distance": "6.5.0",
|
||||||
|
"@turf/helpers": "6.5.0",
|
||||||
|
"@turf/length": "6.5.0",
|
||||||
|
"@turf/nearest-point-on-line": "6.5.0",
|
||||||
|
"@types/geojson": "^7946.0.7",
|
||||||
|
"debounce": "^1.2.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": ">=47.0.0",
|
||||||
|
"mapbox-gl": "^2.9.0",
|
||||||
|
"react": ">=16.6.1",
|
||||||
|
"react-native": ">=0.59.9"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"expo": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"mapbox-gl": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@segment/loosely-validate-event": {
|
"node_modules/@segment/loosely-validate-event": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz",
|
||||||
|
@ -8121,6 +8153,157 @@
|
||||||
"integrity": "sha512-F7IoHEqf741lut4Z2K+IkWQRvXAhBiZMeY5L7BysG7Z2Z3MlIyFR+AagD8jQ/CqC1vowGnRwfLjeuwIpaeoJxA==",
|
"integrity": "sha512-F7IoHEqf741lut4Z2K+IkWQRvXAhBiZMeY5L7BysG7Z2Z3MlIyFR+AagD8jQ/CqC1vowGnRwfLjeuwIpaeoJxA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@turf/along": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/along/-/along-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-LLyWQ0AARqJCmMcIEAXF4GEu8usmd4Kbz3qk1Oy5HoRNpZX47+i5exQtmIWKdqJ1MMhW26fCTXgpsEs5zgJ5gw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/bearing": "^6.5.0",
|
||||||
|
"@turf/destination": "^6.5.0",
|
||||||
|
"@turf/distance": "^6.5.0",
|
||||||
|
"@turf/helpers": "^6.5.0",
|
||||||
|
"@turf/invariant": "^6.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@turf/bbox": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/helpers": "^6.5.0",
|
||||||
|
"@turf/meta": "^6.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@turf/bearing": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/helpers": "^6.5.0",
|
||||||
|
"@turf/invariant": "^6.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@turf/destination": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/destination/-/destination-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/helpers": "^6.5.0",
|
||||||
|
"@turf/invariant": "^6.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@turf/distance": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/distance/-/distance-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/helpers": "^6.5.0",
|
||||||
|
"@turf/invariant": "^6.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@turf/helpers": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@turf/invariant": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/helpers": "^6.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@turf/length": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/length/-/length-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-5pL5/pnw52fck3oRsHDcSGrj9HibvtlrZ0QNy2OcW8qBFDNgZ4jtl6U7eATVoyWPKBHszW3dWETW+iLV7UARig==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/distance": "^6.5.0",
|
||||||
|
"@turf/helpers": "^6.5.0",
|
||||||
|
"@turf/meta": "^6.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@turf/line-intersect": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/line-intersect/-/line-intersect-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/helpers": "^6.5.0",
|
||||||
|
"@turf/invariant": "^6.5.0",
|
||||||
|
"@turf/line-segment": "^6.5.0",
|
||||||
|
"@turf/meta": "^6.5.0",
|
||||||
|
"geojson-rbush": "3.x"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@turf/line-segment": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/helpers": "^6.5.0",
|
||||||
|
"@turf/invariant": "^6.5.0",
|
||||||
|
"@turf/meta": "^6.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@turf/meta": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/helpers": "^6.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@turf/nearest-point-on-line": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/bearing": "^6.5.0",
|
||||||
|
"@turf/destination": "^6.5.0",
|
||||||
|
"@turf/distance": "^6.5.0",
|
||||||
|
"@turf/helpers": "^6.5.0",
|
||||||
|
"@turf/invariant": "^6.5.0",
|
||||||
|
"@turf/line-intersect": "^6.5.0",
|
||||||
|
"@turf/meta": "^6.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/turf"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||||
|
@ -8162,6 +8345,11 @@
|
||||||
"@babel/types": "^7.20.7"
|
"@babel/types": "^7.20.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/geojson": {
|
||||||
|
"version": "7946.0.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz",
|
||||||
|
"integrity": "sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ=="
|
||||||
|
},
|
||||||
"node_modules/@types/graceful-fs": {
|
"node_modules/@types/graceful-fs": {
|
||||||
"version": "4.1.9",
|
"version": "4.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
|
||||||
|
@ -9362,6 +9550,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/base-64": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="
|
||||||
|
},
|
||||||
"node_modules/base64-js": {
|
"node_modules/base64-js": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
|
@ -10506,6 +10699,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz",
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz",
|
||||||
"integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ=="
|
"integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/debounce": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug=="
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
|
@ -12763,6 +12961,28 @@
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/geojson-rbush": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==",
|
||||||
|
"dependencies": {
|
||||||
|
"@turf/bbox": "*",
|
||||||
|
"@turf/helpers": "6.x",
|
||||||
|
"@turf/meta": "6.x",
|
||||||
|
"@types/geojson": "7946.0.8",
|
||||||
|
"rbush": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/geojson-rbush/node_modules/@types/geojson": {
|
||||||
|
"version": "7946.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz",
|
||||||
|
"integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA=="
|
||||||
|
},
|
||||||
|
"node_modules/geolib": {
|
||||||
|
"version": "3.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/geolib/-/geolib-3.3.4.tgz",
|
||||||
|
"integrity": "sha512-EicrlLLL3S42gE9/wde+11uiaYAaeSVDwCUIv2uMIoRBfNJCn8EsSI+6nS3r4TCKDO6+RQNM9ayLq2at+oZQWQ=="
|
||||||
|
},
|
||||||
"node_modules/get-caller-file": {
|
"node_modules/get-caller-file": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
@ -18721,6 +18941,11 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/quickselect": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="
|
||||||
|
},
|
||||||
"node_modules/range-parser": {
|
"node_modules/range-parser": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
|
@ -18753,6 +18978,14 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rbush": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==",
|
||||||
|
"dependencies": {
|
||||||
|
"quickselect": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/rc": {
|
"node_modules/rc": {
|
||||||
"version": "1.2.8",
|
"version": "1.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||||
|
@ -18894,6 +19127,24 @@
|
||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-fs": {
|
||||||
|
"version": "2.20.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz",
|
||||||
|
"integrity": "sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"base-64": "^0.1.0",
|
||||||
|
"utf8": "^3.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native": "*",
|
||||||
|
"react-native-windows": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"react-native-windows": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native-linear-gradient": {
|
"node_modules/react-native-linear-gradient": {
|
||||||
"version": "2.8.3",
|
"version": "2.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz",
|
||||||
|
@ -18925,6 +19176,17 @@
|
||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-securerandom": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-securerandom/-/react-native-securerandom-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-ibuDnd3xi17HyD5CkilOXGPFpS9Z1oifjyHFwUl8NMzcQcpruM0ZX8ytr3A4rCeAsaBHjz69r78Xgd6vUswv1Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "*"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native-svg": {
|
"node_modules/react-native-svg": {
|
||||||
"version": "13.4.0",
|
"version": "13.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.4.0.tgz",
|
||||||
|
@ -21243,6 +21505,11 @@
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/utf8": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ=="
|
||||||
|
},
|
||||||
"node_modules/util-deprecate": {
|
"node_modules/util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
|
|
@ -18,14 +18,18 @@
|
||||||
"@react-navigation/native-stack": "^6.9.17",
|
"@react-navigation/native-stack": "^6.9.17",
|
||||||
"@react-spring/native": "^9.7.3",
|
"@react-spring/native": "^9.7.3",
|
||||||
"@reduxjs/toolkit": "^1.9.7",
|
"@reduxjs/toolkit": "^1.9.7",
|
||||||
|
"@rnmapbox/maps": "^10.0.15",
|
||||||
"@types/react-native-vector-icons": "^6.4.18",
|
"@types/react-native-vector-icons": "^6.4.18",
|
||||||
|
"geolib": "^3.3.4",
|
||||||
"password-quality-calculator": "^1.0.4",
|
"password-quality-calculator": "^1.0.4",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-native": "0.72.7",
|
"react-native": "0.72.7",
|
||||||
"react-native-encrypted-storage": "^4.0.3",
|
"react-native-encrypted-storage": "^4.0.3",
|
||||||
|
"react-native-fs": "^2.20.0",
|
||||||
"react-native-linear-gradient": "^2.8.3",
|
"react-native-linear-gradient": "^2.8.3",
|
||||||
"react-native-safe-area-context": "^4.7.4",
|
"react-native-safe-area-context": "^4.7.4",
|
||||||
"react-native-screens": "^3.27.0",
|
"react-native-screens": "^3.27.0",
|
||||||
|
"react-native-securerandom": "^1.0.1",
|
||||||
"react-native-svg": "^13.4.0",
|
"react-native-svg": "^13.4.0",
|
||||||
"react-native-user-agent": "^2.3.1",
|
"react-native-user-agent": "^2.3.1",
|
||||||
"react-native-vector-icons": "^10.0.2",
|
"react-native-vector-icons": "^10.0.2",
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import {appNonSaveVarActions} from '@configs/appNonSaveVarReducer';
|
||||||
|
import {initDatabase} from '@helper/storage/bdm/init';
|
||||||
|
import DBSchemas from '@helper/storage/bdm/schemas';
|
||||||
|
import BigDataManager from '@helper/storage/BigDataManager';
|
||||||
|
import {store} from '@redux/store';
|
||||||
|
import {chatEntity} from '@configs/chat/types';
|
||||||
|
|
||||||
|
async function initChatDatabase(chat: chatEntity) {
|
||||||
|
const keys = BigDataManager.databases.chatRoomInfos.keys;
|
||||||
|
|
||||||
|
await initDatabase(DBSchemas.chat, chat.roomId);
|
||||||
|
|
||||||
|
await BigDataManager.databases.chatRoomInfos.setEntry({
|
||||||
|
[keys.RoomId]: chat.roomId,
|
||||||
|
[keys.initSyncId]: chat.initSyncId,
|
||||||
|
[keys.syncId]: chat.syncId,
|
||||||
|
[keys.unreadMessages]: chat.unreadMessages,
|
||||||
|
[keys.users]: chat.users,
|
||||||
|
[keys.timestamp]: chat.timestamp,
|
||||||
|
});
|
||||||
|
addChatEntity(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addChatEntity(chat: chatEntity) {
|
||||||
|
store.dispatch(appNonSaveVarActions.setChatEntity(chat));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default initChatDatabase;
|
|
@ -0,0 +1,55 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {View, Text, Image, StyleSheet} from 'react-native';
|
||||||
|
import {PA_Point} from './cluster/getData';
|
||||||
|
import {MarkerView} from '@rnmapbox/maps';
|
||||||
|
|
||||||
|
import {useSelector} from 'react-redux';
|
||||||
|
import {RootState, store} from '@redux/store';
|
||||||
|
import CircleNumber from './cluster/Cluster';
|
||||||
|
import {EventMarker} from './EventMarker';
|
||||||
|
|
||||||
|
function DisplayMarkerList(props: {markers: PA_Point[]}) {
|
||||||
|
const eventMapMarkers = props.markers;
|
||||||
|
/*const eventMapMarkers = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.eventMapMarkers,
|
||||||
|
);*/
|
||||||
|
|
||||||
|
const colors = store.getState().nonSaveVariables.theme.colors;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{eventMapMarkers.map((marker: PA_Point) => {
|
||||||
|
return marker.type === 'event' ? (
|
||||||
|
<MarkerView
|
||||||
|
key={marker.id}
|
||||||
|
anchor={{x: 0.5, y: 1}}
|
||||||
|
coordinate={[marker.longitude, marker.latitude]}
|
||||||
|
allowOverlap={true}>
|
||||||
|
<EventMarker marker={marker} />
|
||||||
|
</MarkerView>
|
||||||
|
) : (
|
||||||
|
<MarkerView
|
||||||
|
key={marker.id}
|
||||||
|
anchor={{x: 0.5, y: 0.5}}
|
||||||
|
coordinate={[marker.longitude, marker.latitude]}
|
||||||
|
allowOverlap={true}>
|
||||||
|
<CircleNumber number={marker.cluster} />
|
||||||
|
</MarkerView>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
marker: {
|
||||||
|
padding: 5,
|
||||||
|
borderRadius: 5,
|
||||||
|
},
|
||||||
|
markerText: {
|
||||||
|
color: 'white',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default DisplayMarkerList;
|
|
@ -0,0 +1,130 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {Animated} from 'react-native';
|
||||||
|
|
||||||
|
import colors from '@configs/colors';
|
||||||
|
import {View, Image, Text, StyleSheet} from 'react-native';
|
||||||
|
import {PA_Point} from './cluster/getData';
|
||||||
|
import {store} from '@redux/store';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Avatar,
|
||||||
|
AvatarBadge,
|
||||||
|
AvatarFallbackText,
|
||||||
|
AvatarGroup,
|
||||||
|
AvatarImage,
|
||||||
|
} from '@gluestack-ui/themed';
|
||||||
|
|
||||||
|
import tate from '@assets/tate.jpg';
|
||||||
|
|
||||||
|
export function EventMarker(props: {marker: PA_Point}) {
|
||||||
|
const marker = props.marker;
|
||||||
|
const colors = store.getState().nonSaveVariables.theme.colors;
|
||||||
|
|
||||||
|
const fadeAnim = React.useRef(new Animated.Value(0)).current;
|
||||||
|
const fadeAnim2 = React.useRef(new Animated.Value(0.9)).current;
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
Animated.timing(fadeAnim, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 300,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start();
|
||||||
|
}, [fadeAnim]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
Animated.timing(fadeAnim2, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 500,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start();
|
||||||
|
}, [fadeAnim2]);
|
||||||
|
|
||||||
|
const avatars = [
|
||||||
|
{
|
||||||
|
src: 'https://image.stern.de/32707724/t/o5/v2/w1440/r1.7778/-/andrew-tate.jpg',
|
||||||
|
alt: 'Sandeep Srivastva',
|
||||||
|
color: '$emerald600',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'https://image.stern.de/32707724/t/o5/v2/w1440/r1.7778/-/andrew-tate.jpg',
|
||||||
|
alt: 'Arjun Kapoor',
|
||||||
|
color: '$cyan600',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'https://image.stern.de/32707724/t/o5/v2/w1440/r1.7778/-/andrew-tate.jpg',
|
||||||
|
alt: 'Ritik Sharma ',
|
||||||
|
color: '$indigo600',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'https://image.stern.de/32707724/t/o5/v2/w1440/r1.7778/-/andrew-tate.jpg',
|
||||||
|
alt: 'Akhil Sharma',
|
||||||
|
color: '$gray600',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'https://image.stern.de/32707724/t/o5/v2/w1440/r1.7778/-/andrew-tate.jpg',
|
||||||
|
alt: 'Rahul Sharma ',
|
||||||
|
color: '$red400',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const extraAvatars = avatars.slice(3);
|
||||||
|
const remainingCount = extraAvatars.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Animated.View
|
||||||
|
style={{
|
||||||
|
...styles.marker,
|
||||||
|
backgroundColor: colors.backgroundDark400,
|
||||||
|
opacity: fadeAnim,
|
||||||
|
transform: [{scale: fadeAnim2}],
|
||||||
|
}}>
|
||||||
|
<AvatarGroup>
|
||||||
|
{avatars.slice(0, 3).map((avatar, index) => {
|
||||||
|
return (
|
||||||
|
<Avatar
|
||||||
|
key={index}
|
||||||
|
size="sm"
|
||||||
|
borderColor="$black"
|
||||||
|
borderWidth="$2"
|
||||||
|
bg={avatar.color}
|
||||||
|
sx={{
|
||||||
|
_dark: {
|
||||||
|
borderColor: '$black',
|
||||||
|
},
|
||||||
|
}}>
|
||||||
|
<AvatarFallbackText>{avatar.alt}</AvatarFallbackText>
|
||||||
|
</Avatar>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<Avatar
|
||||||
|
size="sm"
|
||||||
|
borderColor="$white"
|
||||||
|
borderWidth="$2"
|
||||||
|
bg="$gray600"
|
||||||
|
sx={{
|
||||||
|
_dark: {
|
||||||
|
borderColor: '$black',
|
||||||
|
},
|
||||||
|
}}>
|
||||||
|
<AvatarFallbackText>{'+ ' + remainingCount + ''}</AvatarFallbackText>
|
||||||
|
</Avatar>
|
||||||
|
</AvatarGroup>
|
||||||
|
<Image
|
||||||
|
source={tate}
|
||||||
|
style={{width: 100, height: 100, alignSelf: 'center'}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Text style={styles.markerText}>{marker.type}</Text>
|
||||||
|
</Animated.View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
marker: {
|
||||||
|
padding: 5,
|
||||||
|
borderRadius: 5,
|
||||||
|
},
|
||||||
|
markerText: {
|
||||||
|
color: 'white',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,88 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {View, Text, StyleSheet, Animated} from 'react-native';
|
||||||
|
|
||||||
|
import {useSelector} from 'react-redux';
|
||||||
|
import {RootState, store} from '@redux/store';
|
||||||
|
|
||||||
|
const CircleNumber = ({number}: {number: number}) => {
|
||||||
|
/*const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);*/ //disabled for performance
|
||||||
|
|
||||||
|
const colors = store.getState().nonSaveVariables.theme.colors;
|
||||||
|
|
||||||
|
const fadeAnim = React.useRef(new Animated.Value(0)).current;
|
||||||
|
const fadeAnim2 = React.useRef(new Animated.Value(1.2)).current;
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
Animated.timing(fadeAnim, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 300,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start();
|
||||||
|
}, [fadeAnim]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
Animated.timing(fadeAnim2, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 500,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start();
|
||||||
|
}, [fadeAnim2]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Animated.View
|
||||||
|
style={{
|
||||||
|
...styles.container,
|
||||||
|
opacity: fadeAnim,
|
||||||
|
}}>
|
||||||
|
<Animated.View
|
||||||
|
style={{
|
||||||
|
...styles.outerCircle,
|
||||||
|
backgroundColor: colors.backgroundDark800 + '44',
|
||||||
|
|
||||||
|
transform: [{scale: fadeAnim2}],
|
||||||
|
}}>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
...styles.innerCircle,
|
||||||
|
backgroundColor: colors.backgroundDark400,
|
||||||
|
}}>
|
||||||
|
<Text style={{...styles.text, color: colors.textLight0}}>
|
||||||
|
{number}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</Animated.View>
|
||||||
|
</Animated.View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
width: 65 * 1.5,
|
||||||
|
height: 65 * 1.5,
|
||||||
|
},
|
||||||
|
outerCircle: {
|
||||||
|
width: 65,
|
||||||
|
height: 65,
|
||||||
|
borderRadius: 65 / 2,
|
||||||
|
//borderWidth: 2,
|
||||||
|
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
innerCircle: {
|
||||||
|
width: 45,
|
||||||
|
height: 45,
|
||||||
|
borderRadius: 25,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: 15,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default CircleNumber;
|
|
@ -0,0 +1,191 @@
|
||||||
|
import {Position} from '@rnmapbox/maps/src/types/Position';
|
||||||
|
import { getDistance } from 'geolib';
|
||||||
|
|
||||||
|
|
||||||
|
interface PA_Point_Cluster {
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
cluster: number;
|
||||||
|
type: 'cluster';
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PA_Point_Event {
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
type: 'event';
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PA_Point = PA_Point_Cluster | PA_Point_Event;
|
||||||
|
|
||||||
|
export type {PA_Point_Cluster, PA_Point_Event, PA_Point};
|
||||||
|
|
||||||
|
|
||||||
|
const createChecksum = (ids: (number | string)[]) => {
|
||||||
|
let checksum = 0;
|
||||||
|
for (const id of ids.sort()) {
|
||||||
|
const value = typeof id === 'string' ? parseInt(id, 36) : id;
|
||||||
|
checksum ^= value & 0xFFFF;
|
||||||
|
}
|
||||||
|
return checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
const clusterMarkers = (markers: PA_Point[], threshold: number) => {
|
||||||
|
const clusters = [];
|
||||||
|
|
||||||
|
for (const marker of markers) {
|
||||||
|
let added = false;
|
||||||
|
|
||||||
|
for (const cluster of clusters) {
|
||||||
|
const [center] = cluster;
|
||||||
|
const distance = Math.sqrt(
|
||||||
|
Math.pow(center.latitude - marker.latitude, 2) +
|
||||||
|
Math.pow(center.longitude - marker.longitude, 2),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (distance < threshold) {
|
||||||
|
cluster.push(marker);
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!added) {
|
||||||
|
clusters.push([marker]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert clusters to center points
|
||||||
|
const centerPoints = clusters.map(cluster => {
|
||||||
|
let isEvent = 0;
|
||||||
|
|
||||||
|
const latitudes = cluster.map(marker => marker.latitude);
|
||||||
|
const longitudes = cluster.map(marker => marker.longitude);
|
||||||
|
const centerLatitude =
|
||||||
|
latitudes.reduce((a, b) => a + b, 0) / latitudes.length;
|
||||||
|
const centerLongitude =
|
||||||
|
longitudes.reduce((a, b) => a + b, 0) / longitudes.length;
|
||||||
|
const sumValues = cluster.reduce((sum, marker) => {
|
||||||
|
if (marker.type === 'event') {
|
||||||
|
if(isEvent === 0)
|
||||||
|
isEvent = 1;
|
||||||
|
else if(isEvent === 1)
|
||||||
|
isEvent = -1;
|
||||||
|
|
||||||
|
return sum + 1};
|
||||||
|
|
||||||
|
isEvent = -1;
|
||||||
|
|
||||||
|
marker = marker as PA_Point_Cluster;
|
||||||
|
|
||||||
|
return sum + (marker.cluster || 0);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
if(isEvent === 1)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
latitude: centerLatitude,
|
||||||
|
longitude: centerLongitude,
|
||||||
|
type: 'event',
|
||||||
|
id: cluster[0].id,
|
||||||
|
} as PA_Point;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ids = cluster.map(marker => marker.id);
|
||||||
|
const idChecksum = createChecksum(ids);
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
latitude: centerLatitude,
|
||||||
|
longitude: centerLongitude,
|
||||||
|
type: 'cluster',
|
||||||
|
cluster: sumValues,
|
||||||
|
id: idChecksum.toString(),
|
||||||
|
} as PA_Point;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return centerPoints;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*const calculateThreshold = (bounds: [Position, Position]) => {
|
||||||
|
const latDiff = bounds[0][0] - bounds[1][0];
|
||||||
|
const lonDiff = bounds[0][1] - bounds[1][1];
|
||||||
|
const maxDiff = Math.max(latDiff, lonDiff);
|
||||||
|
const zoomLevel = Math.floor(Math.log2(360 / maxDiff));
|
||||||
|
return 1 / Math.pow(2, zoomLevel);
|
||||||
|
};*/
|
||||||
|
|
||||||
|
const calculateRadius = (bounds: [Position, Position]) => {
|
||||||
|
|
||||||
|
|
||||||
|
const distanceInMeters = getDistance(
|
||||||
|
{ latitude: bounds[0][0], longitude: bounds[0][1] },
|
||||||
|
{ latitude: bounds[1][0], longitude: bounds[1][1] }
|
||||||
|
);
|
||||||
|
return distanceInMeters/600000/(1.5/*android bug fix for roteration*/);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function getLocationData(
|
||||||
|
bounds: [Position, Position], zoomLevel: number
|
||||||
|
): Promise<{locations: PA_Point[]} | undefined> {
|
||||||
|
if (bounds === undefined) return Promise.resolve(undefined);
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
// Simulating an asynchronous operation, such as an API call
|
||||||
|
setTimeout(() => {
|
||||||
|
const rawData: {locations: PA_Point[]} = {
|
||||||
|
locations: [
|
||||||
|
/*{"latitude": 51.1657, "longitude": 10.4515, "cluster": 27, "type": "cluster", "id": "398742"},
|
||||||
|
{"latitude": 51.1045, "longitude": 13.2017, "cluster": 19, "type": "cluster", "id": "519274"},
|
||||||
|
{"latitude": 49.3988, "longitude": 8.6724, "cluster": 42, "type": "cluster", "id": "815926"},
|
||||||
|
{"latitude": 51.3404, "longitude": 12.3743, "cluster": 5, "type": "cluster", "id": "105473"},
|
||||||
|
{"latitude": 52.52, "longitude": 13.405, "cluster": 31, "type": "cluster", "id": "267351"},
|
||||||
|
{"latitude": 48.8566, "longitude": 9.2725, "cluster": 14, "type": "cluster", "id": "845723"},
|
||||||
|
{"latitude": 53.5511, "longitude": 9.9937, "cluster": 37, "type": "cluster", "id": "921864"},
|
||||||
|
{"latitude": 50.1109, "longitude": 8.6821, "cluster": 23, "type": "cluster", "id": "467132"},
|
||||||
|
{"latitude": 51.0493, "longitude": 13.7384, "cluster": 8, "type": "cluster", "id": "842906"},
|
||||||
|
{"latitude": 49.0069, "longitude": 8.4037, "cluster": 46, "type": "cluster", "id": "346708"},*/
|
||||||
|
{"latitude": 51.9674, "longitude": 7.6194, "type": "event", "id": 203867},
|
||||||
|
{"latitude": 50.7753, "longitude": 6.0839, "type": "event", "id": 501298},
|
||||||
|
{"latitude": 53.0793, "longitude": 8.8017, "type": "event", "id": 763159},
|
||||||
|
{"latitude": 48.7758, "longitude": 9.1829, "type": "event", "id": 917425},
|
||||||
|
{"latitude": 52.3759, "longitude": 9.732, "type": "event", "id": 635028},
|
||||||
|
{"latitude": 51.512, "longitude": 7.4653, "type": "event", "id": 841592},
|
||||||
|
{"latitude": 49.4875, "longitude": 8.466, "type": "event", "id": 180356},
|
||||||
|
{"latitude": 51.3611, "longitude": 7.0119, "type": "event", "id": 592874},
|
||||||
|
{"latitude": 54.3227, "longitude": 10.1356, "type": "event", "id": 384791},
|
||||||
|
{"latitude": 51.8049, "longitude": 10.3351, "type": "event", "id": 273495},
|
||||||
|
{"latitude": 50.3213, "longitude": 11.8676, "type": "event", "id": 699318},
|
||||||
|
{"latitude": 49.8765, "longitude": 6.6695, "type": "event", "id": 159627},
|
||||||
|
{"latitude": 52.2651, "longitude": 7.3085, "type": "event", "id": 903716},
|
||||||
|
{"latitude": 53.9638, "longitude": 12.413, "type": "event", "id": 487612},
|
||||||
|
{"latitude": 50.9321, "longitude": 9.1847, "type": "event", "id": 827464},
|
||||||
|
{"latitude": 52.4378, "longitude": 13.2847, "type": "event", "id": 931845},
|
||||||
|
{"latitude": 49.4644, "longitude": 11.0168, "type": "event", "id": 674132},
|
||||||
|
{"latitude": 51.1983, "longitude": 8.8998, "type": "event", "id": 298473}
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
console.log("got data");
|
||||||
|
|
||||||
|
const zoomLevelChanged = calculateRadius(bounds);
|
||||||
|
|
||||||
|
console.log(zoomLevelChanged);
|
||||||
|
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
locations: clusterMarkers(rawData.locations, zoomLevelChanged),//calculateThreshold(bounds)
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("clustered data");
|
||||||
|
|
||||||
|
resolve(data);
|
||||||
|
}, 120); // Simulating a delay of 1 second for the asynchronous operation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getLocationData;
|
|
@ -1,10 +1,17 @@
|
||||||
//these variables should not changed by the user and will not be saved in storage
|
//these variables should not changed by the user and will not be saved in storage
|
||||||
|
|
||||||
|
import {chatEntity, roomId} from '@configs/chat/types';
|
||||||
|
import {User} from '@user/types';
|
||||||
|
import {UserId} from './types';
|
||||||
|
|
||||||
import {getVersionByNum, VersionType} from '@helper/version';
|
import {getVersionByNum, VersionType} from '@helper/version';
|
||||||
import configDarkTheme, {ThemeTokensType} from '@configs/colors';
|
import configDarkTheme, {ThemeTokensType} from '@configs/colors';
|
||||||
|
|
||||||
|
import { PA_Point } from '@components/map/cluster/getData';
|
||||||
|
|
||||||
export const APP_VERSION = getVersionByNum(1);
|
export const APP_VERSION = getVersionByNum(1);
|
||||||
export const AppVarMaxBackups: number = 10;
|
export const AppVarMaxBackups: number = 10;
|
||||||
|
export const maxCachedUsers = 30;
|
||||||
|
|
||||||
export enum appStatus {
|
export enum appStatus {
|
||||||
IS_LOADING,
|
IS_LOADING,
|
||||||
|
@ -21,13 +28,23 @@ export enum connectionStatus {
|
||||||
export interface NON_SAVE_VARS {
|
export interface NON_SAVE_VARS {
|
||||||
currentAppVersion: VersionType;
|
currentAppVersion: VersionType;
|
||||||
appStatus: appStatus;
|
appStatus: appStatus;
|
||||||
connectionStatus: connectionStatus;
|
|
||||||
theme: ThemeTokensType;
|
theme: ThemeTokensType;
|
||||||
|
connectionStatus: connectionStatus;
|
||||||
|
cachedUsers: {[key: UserId]: User};
|
||||||
|
chats: {[key: roomId]: chatEntity};
|
||||||
|
chatActivity: roomId[];
|
||||||
|
selectedChat: roomId | 'none';
|
||||||
|
eventMapMarkers: PA_Point[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const non_save_vars: NON_SAVE_VARS = {
|
export const non_save_vars: NON_SAVE_VARS = {
|
||||||
currentAppVersion: APP_VERSION,
|
currentAppVersion: APP_VERSION,
|
||||||
appStatus: appStatus.IS_LOADING,
|
appStatus: appStatus.IS_LOADING,
|
||||||
connectionStatus: connectionStatus.UNKNOWN,
|
|
||||||
theme: configDarkTheme.tokens,
|
theme: configDarkTheme.tokens,
|
||||||
|
connectionStatus: connectionStatus.UNKNOWN,
|
||||||
|
cachedUsers: {},
|
||||||
|
chats: {},
|
||||||
|
chatActivity: [],
|
||||||
|
selectedChat: 'none',
|
||||||
|
eventMapMarkers: [],
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,11 @@ import type {PayloadAction} from '@reduxjs/toolkit';
|
||||||
import {appStatus, non_save_vars} from './appNonSaveVar';
|
import {appStatus, non_save_vars} from './appNonSaveVar';
|
||||||
import {ThemeTokensType} from '@configs/colors';
|
import {ThemeTokensType} from '@configs/colors';
|
||||||
|
|
||||||
|
import {chatEntity, roomId} from '@configs/chat/types';
|
||||||
|
import {User} from '@user/types';
|
||||||
|
import {UserId} from './types';
|
||||||
|
import {PA_Point} from '@components/map/cluster/getData';
|
||||||
|
|
||||||
export const appNonSaveVariablesSlice = createSlice({
|
export const appNonSaveVariablesSlice = createSlice({
|
||||||
name: 'non_save_vars',
|
name: 'non_save_vars',
|
||||||
initialState: non_save_vars,
|
initialState: non_save_vars,
|
||||||
|
@ -13,6 +18,45 @@ export const appNonSaveVariablesSlice = createSlice({
|
||||||
setTheme: (state, action: PayloadAction<ThemeTokensType>) => {
|
setTheme: (state, action: PayloadAction<ThemeTokensType>) => {
|
||||||
state.theme = action.payload;
|
state.theme = action.payload;
|
||||||
},
|
},
|
||||||
|
setCachedUser: (state, action: PayloadAction<User>) => {
|
||||||
|
state.cachedUsers[action.payload.UserId] = action.payload;
|
||||||
|
},
|
||||||
|
removeCachedUser: (state, action: PayloadAction<UserId>) => {
|
||||||
|
delete state.cachedUsers[action.payload];
|
||||||
|
},
|
||||||
|
setSelectedChat: (state, action: PayloadAction<roomId>) => {
|
||||||
|
state.selectedChat = action.payload;
|
||||||
|
},
|
||||||
|
setChatEntity: (state, action: PayloadAction<chatEntity>) => {
|
||||||
|
const roomId = action.payload.roomId;
|
||||||
|
|
||||||
|
state.chats[roomId] = action.payload;
|
||||||
|
|
||||||
|
if (state.chatActivity.includes(roomId) === false)
|
||||||
|
state.chatActivity.unshift(roomId);
|
||||||
|
},
|
||||||
|
changeChatEntity: (state, action: PayloadAction<chatEntity>) => {
|
||||||
|
const roomId = action.payload.roomId;
|
||||||
|
|
||||||
|
state.chats[roomId] = action.payload;
|
||||||
|
|
||||||
|
if (state.chatActivity.includes(roomId) === false)
|
||||||
|
state.chatActivity.unshift(roomId);
|
||||||
|
|
||||||
|
state.chatActivity.sort(function (x, y) {
|
||||||
|
return x === roomId ? -1 : y === roomId ? 1 : 0;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
removeChatEntity: (state, action: PayloadAction<roomId>) => {
|
||||||
|
delete state.chats[action.payload];
|
||||||
|
|
||||||
|
state.chatActivity = state.chatActivity.filter(function (ele) {
|
||||||
|
return ele !== action.payload;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setMapMarkers: (state, action: PayloadAction<PA_Point[]>) => {
|
||||||
|
state.eventMapMarkers = action.payload;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ export interface RegisterProcess {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PREFERENCES_VARS {
|
export interface PREFERENCES_VARS {
|
||||||
|
dbek: number; //db encryption key
|
||||||
version: VersionType;
|
version: VersionType;
|
||||||
theme: ThemeMode;
|
theme: ThemeMode;
|
||||||
RegisterProcess: RegisterProcess;
|
RegisterProcess: RegisterProcess;
|
||||||
|
@ -55,6 +56,7 @@ export interface PREFERENCES_VARS {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const preferences_vars_default: PREFERENCES_VARS = {
|
export const preferences_vars_default: PREFERENCES_VARS = {
|
||||||
|
dbek: -5,
|
||||||
version: APP_VERSION, //version of datatypes in storage
|
version: APP_VERSION, //version of datatypes in storage
|
||||||
theme: ThemeMode.Dark,
|
theme: ThemeMode.Dark,
|
||||||
RegisterProcess: {
|
RegisterProcess: {
|
||||||
|
|
|
@ -43,6 +43,9 @@ export const appVariablesSlice = createSlice({
|
||||||
setAccount: (state, action: PayloadAction<MyUserAccount>) => {
|
setAccount: (state, action: PayloadAction<MyUserAccount>) => {
|
||||||
state.preferences.accounts[action.payload.UserId] = action.payload;
|
state.preferences.accounts[action.payload.UserId] = action.payload;
|
||||||
},
|
},
|
||||||
|
setDBEK: (state, action: PayloadAction<number>) => {
|
||||||
|
state.preferences.dbek = action.payload;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
import {timestamp, UserId} from '@configs/types';
|
||||||
|
import DBSchemas from '@helper/storage/bdm/schemas';
|
||||||
|
import LangFormat from '@lang/default';
|
||||||
|
import {timeStamp} from 'console';
|
||||||
|
|
||||||
|
export enum chatTags {
|
||||||
|
GROUP = 0,
|
||||||
|
FRIEND = 1,
|
||||||
|
GOOD_FRIEND = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface tagUIType {
|
||||||
|
name: string;
|
||||||
|
background: string;
|
||||||
|
textColor?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface tagUITypeFinal extends tagUIType {
|
||||||
|
textColor: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tagUI: {[key in chatTags]: tagUIType} = {
|
||||||
|
[chatTags.GROUP]: {
|
||||||
|
name: 'Group',
|
||||||
|
background: '#37f',
|
||||||
|
},
|
||||||
|
[chatTags.FRIEND]: {
|
||||||
|
name: 'Friend',
|
||||||
|
background: 'lime.300',
|
||||||
|
textColor: '#111',
|
||||||
|
},
|
||||||
|
[chatTags.GOOD_FRIEND]: {
|
||||||
|
name: 'Good friend',
|
||||||
|
background: 'lime.600',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/*export function getTagUI(tagKey: chatTags, lang?: LangFormat): tagUITypeFinal {
|
||||||
|
let tag = tagUI[tagKey];
|
||||||
|
|
||||||
|
tag.textColor = tag.textColor || '#fff';
|
||||||
|
|
||||||
|
if (lang !== undefined && lang.chat.tags.names[tagKey] !== undefined) {
|
||||||
|
tag.name = lang.chat.tags.names[tagKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag as tagUITypeFinal;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
export type roomId = string;
|
||||||
|
type syncId = number;
|
||||||
|
|
||||||
|
export interface chatEntity {
|
||||||
|
roomId: roomId;
|
||||||
|
|
||||||
|
syncId: syncId;
|
||||||
|
initSyncId: syncId;
|
||||||
|
timestamp: timestamp;
|
||||||
|
|
||||||
|
users: [UserId, ...UserId[]];
|
||||||
|
title?: string;
|
||||||
|
unreadMessages: number;
|
||||||
|
|
||||||
|
tags: chatTags[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertDatabaseChat(
|
||||||
|
chat: typeof DBSchemas.chatRoomInfos.defaultProps,
|
||||||
|
): chatEntity | undefined {
|
||||||
|
const keys = DBSchemas.chatRoomInfos.keys;
|
||||||
|
|
||||||
|
if (chat[keys.users].length === 0) return undefined;
|
||||||
|
|
||||||
|
const newChat: chatEntity = {
|
||||||
|
initSyncId: chat[keys.initSyncId],
|
||||||
|
roomId: chat[keys.RoomId],
|
||||||
|
syncId: chat[keys.syncId],
|
||||||
|
tags: [],
|
||||||
|
unreadMessages: chat[keys.unreadMessages],
|
||||||
|
timestamp: chat[keys.timestamp],
|
||||||
|
//@ts-ignore
|
||||||
|
users: [...chat[keys.users]],
|
||||||
|
//title: chat[keys.title]
|
||||||
|
};
|
||||||
|
|
||||||
|
return newChat;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertChatDatabase(
|
||||||
|
chat: chatEntity,
|
||||||
|
): typeof DBSchemas.chatRoomInfos.defaultProps {
|
||||||
|
const keys = DBSchemas.chatRoomInfos.keys;
|
||||||
|
|
||||||
|
const newChat: typeof DBSchemas.chatRoomInfos.defaultProps = {
|
||||||
|
[keys.initSyncId]: chat.initSyncId,
|
||||||
|
[keys.RoomId]: chat.roomId,
|
||||||
|
[keys.syncId]: chat.syncId,
|
||||||
|
|
||||||
|
[keys.unreadMessages]: chat.unreadMessages,
|
||||||
|
[keys.timestamp]: chat.timestamp,
|
||||||
|
//@ts-ignore
|
||||||
|
[keys.users]: chat.users,
|
||||||
|
//title: chat[keys.title]
|
||||||
|
};
|
||||||
|
|
||||||
|
return newChat;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export {generateSecureRandom} from 'react-native-securerandom';
|
|
@ -1,4 +1,13 @@
|
||||||
import {initDatabase} from './bdm/init';
|
import {initDatabases} from './bdm/init';
|
||||||
|
import {setEntry} from './bdm/set';
|
||||||
|
import {getEntry} from './bdm/get';
|
||||||
|
import DBSchemas from './bdm/schemas';
|
||||||
|
import {databaseNames, possibleDBKeys} from './bdm/types';
|
||||||
|
|
||||||
const BigDataManager = {initDatabase};
|
const BigDataManager = {
|
||||||
|
initDatabase: initDatabases,
|
||||||
|
setEntry,
|
||||||
|
getEntry,
|
||||||
|
databases: DBSchemas,
|
||||||
|
};
|
||||||
export default BigDataManager;
|
export default BigDataManager;
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import EncryptedStorage from 'react-native-encrypted-storage';
|
import EncryptedStorage from 'react-native-encrypted-storage';
|
||||||
|
|
||||||
export async function getData(key: string): Promise<string | null> {
|
export async function getData(key: string): Promise<string | null> {
|
||||||
return EncryptedStorage.getItem(key);
|
return new Promise((resolve, reject) => {
|
||||||
|
EncryptedStorage.getItem(key).then(value => {
|
||||||
|
if (value === undefined) resolve(null);
|
||||||
|
else resolve(value);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setData(key: string, value: string): Promise<void> {
|
export async function setData(key: string, value: string): Promise<void> {
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
import {appVarActions} from '@configs/appVarReducer';
|
||||||
|
import {saveVarChanges} from '@helper/appData';
|
||||||
|
import {store} from '@redux/store';
|
||||||
|
import {generateSecureRandom} from '@helper/secureRandom';
|
||||||
|
import {getData, setData} from '../appData';
|
||||||
|
|
||||||
|
import {Buffer} from 'buffer';
|
||||||
|
|
||||||
|
type encryptType = Uint8Array | undefined;
|
||||||
|
let dbEncryption: encryptType;
|
||||||
|
|
||||||
|
export function initKey(): Promise<Uint8Array> {
|
||||||
|
return new Promise(async resolve => {
|
||||||
|
let dbekIndex = store.getState().appVariables.preferences.dbek;
|
||||||
|
|
||||||
|
if (dbekIndex === undefined || dbekIndex < 0) {
|
||||||
|
dbekIndex = Math.round(Math.random() * 1000000);
|
||||||
|
|
||||||
|
store.dispatch(appVarActions.setDBEK(dbekIndex));
|
||||||
|
saveVarChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
let dbekEncoded = await getData('dbek' + dbekIndex);
|
||||||
|
|
||||||
|
if (dbekEncoded === null) {
|
||||||
|
dbEncryption = await generateSecureRandom(64);
|
||||||
|
|
||||||
|
console.log(dbEncryption);
|
||||||
|
|
||||||
|
let buf = Buffer.from(dbEncryption).toString('base64');
|
||||||
|
|
||||||
|
await setData('dbek' + dbekIndex, buf);
|
||||||
|
} else {
|
||||||
|
dbEncryption = new Uint8Array(Buffer.from(dbekEncoded, 'base64'));
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('dbekIndex', dbekIndex);
|
||||||
|
resolve(dbEncryption);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getKey(): encryptType {
|
||||||
|
return dbEncryption;
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
import {getDatabase} from './getDB';
|
||||||
|
import {databaseConf, mergeDBName, possibleDBKeys} from './types';
|
||||||
|
|
||||||
|
export interface filterParam {
|
||||||
|
type: 'name';
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getEntry = async <T2 extends databaseConf<T, any>, T>(
|
||||||
|
schema: T2,
|
||||||
|
key: possibleDBKeys,
|
||||||
|
suffix?: string,
|
||||||
|
): Promise<null | T> => {
|
||||||
|
const nameObj = {name: schema.details.name, suffix};
|
||||||
|
const dbName = mergeDBName(nameObj);
|
||||||
|
|
||||||
|
const realm = await getDatabase(nameObj);
|
||||||
|
|
||||||
|
const val = realm.objectForPrimaryKey<typeof schema.details.properties>(
|
||||||
|
nameObj.name,
|
||||||
|
key,
|
||||||
|
);
|
||||||
|
|
||||||
|
return val as T;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAllEntries = async <T2 extends databaseConf<T, any>, T>(
|
||||||
|
schema: T2,
|
||||||
|
filter?: filterParam,
|
||||||
|
suffix?: string,
|
||||||
|
): Promise<null | T[]> => {
|
||||||
|
const nameObj = {name: schema.details.name, suffix};
|
||||||
|
const dbName = mergeDBName(nameObj);
|
||||||
|
|
||||||
|
const realm = await getDatabase(nameObj);
|
||||||
|
|
||||||
|
const val = realm.objects<typeof schema.details.properties>(nameObj.name);
|
||||||
|
|
||||||
|
return [...val] as T[];
|
||||||
|
};
|
|
@ -0,0 +1,115 @@
|
||||||
|
import {timestamp} from '@configs/types';
|
||||||
|
import MyUserManager from '@user/MyUserManager';
|
||||||
|
import Realm from 'realm';
|
||||||
|
Realm.flags.THROW_ON_GLOBAL_REALM = true;
|
||||||
|
import {getKey} from './encryption';
|
||||||
|
import {
|
||||||
|
databaseConf,
|
||||||
|
databaseNames,
|
||||||
|
databaseNameSuffix,
|
||||||
|
mergeDBName,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
|
import RNFS from 'react-native-fs';
|
||||||
|
import {databaseConfType} from './schemas';
|
||||||
|
|
||||||
|
const closeTimeout = 5; // in seconds // when DB read/writes is too long in idle it will be closed
|
||||||
|
|
||||||
|
type DBType = Realm;
|
||||||
|
|
||||||
|
export interface DBObject {
|
||||||
|
name: string;
|
||||||
|
schema: databaseConfType;
|
||||||
|
db: DBType | undefined;
|
||||||
|
lastUsedTimestamp?: timestamp; // when timeout is undefined then db is closed
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DBs = {[key: string]: DBObject};
|
||||||
|
export let databases: DBs = {};
|
||||||
|
|
||||||
|
function getTime() {
|
||||||
|
return Math.floor(new Date().getTime() / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
const curTime = getTime();
|
||||||
|
|
||||||
|
for (let name in databases) {
|
||||||
|
let dbObj = databases[name];
|
||||||
|
|
||||||
|
if (
|
||||||
|
dbObj.lastUsedTimestamp !== undefined &&
|
||||||
|
dbObj.lastUsedTimestamp + closeTimeout < curTime
|
||||||
|
) {
|
||||||
|
dbObj.db?.close();
|
||||||
|
dbObj.lastUsedTimestamp = undefined;
|
||||||
|
//console.log('Database not used. Closing ' + dbObj.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
export function closeAllDatabases() {
|
||||||
|
for (let name in databases) {
|
||||||
|
let dbObj = databases[name];
|
||||||
|
|
||||||
|
if (dbObj.lastUsedTimestamp !== undefined) {
|
||||||
|
dbObj.db?.close();
|
||||||
|
dbObj.lastUsedTimestamp = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function openMyDatabase(
|
||||||
|
schema: databaseConfType,
|
||||||
|
nameObj: databaseNameSuffix,
|
||||||
|
): Promise<DBType> {
|
||||||
|
const folderPath = MyUserManager.getSelectedUserId();
|
||||||
|
const path =
|
||||||
|
folderPath +
|
||||||
|
'/' +
|
||||||
|
schema.filePath +
|
||||||
|
(nameObj.suffix !== undefined ? '_' + nameObj.suffix : '');
|
||||||
|
|
||||||
|
const folderExists = await RNFS.exists(
|
||||||
|
RNFS.DocumentDirectoryPath + '/' + folderPath,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (folderExists === false) {
|
||||||
|
await RNFS.mkdir(RNFS.DocumentDirectoryPath + '/' + folderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('schema.details', schema.details);
|
||||||
|
|
||||||
|
const realm = await Realm.open({
|
||||||
|
schema: [schema.details as any],
|
||||||
|
schemaVersion: schema.version,
|
||||||
|
path,
|
||||||
|
encryptionKey: getKey(),
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('path', path);
|
||||||
|
return realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getDatabase(
|
||||||
|
_name: databaseNameSuffix,
|
||||||
|
init?: boolean,
|
||||||
|
): Promise<DBType> {
|
||||||
|
const name = mergeDBName(_name);
|
||||||
|
let dbObj = databases[name];
|
||||||
|
|
||||||
|
if (dbObj !== undefined) {
|
||||||
|
if (dbObj.lastUsedTimestamp !== undefined && dbObj.db !== undefined) {
|
||||||
|
dbObj.lastUsedTimestamp = getTime();
|
||||||
|
return dbObj.db;
|
||||||
|
} else {
|
||||||
|
dbObj.lastUsedTimestamp = undefined;
|
||||||
|
const db = await openMyDatabase(dbObj.schema, _name);
|
||||||
|
dbObj.lastUsedTimestamp = getTime();
|
||||||
|
dbObj.db = db;
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw "Database '" + name + "' is not initialized";
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +1,42 @@
|
||||||
import Realm from 'realm';
|
import {closeAllDatabases, databases, DBObject, getDatabase} from './getDB';
|
||||||
import DBSchemas from './schemas';
|
import DBSchemas, {SkipDBSchemas} from './schemas';
|
||||||
|
import {databaseConf, databaseNameSuffix, mergeDBName} from './types';
|
||||||
|
|
||||||
export const initDatabase = (): Promise<void> => {
|
export const initDatabases = (): Promise<void> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
setTimeout(() => {
|
closeAllDatabases();
|
||||||
for (const key in DBSchemas) {
|
|
||||||
const Schema = DBSchemas[key as keyof typeof DBSchemas];
|
for (const key in DBSchemas) {
|
||||||
Realm.open({
|
const schema = DBSchemas[key as keyof typeof DBSchemas];
|
||||||
schema: [Schema.details],
|
const name = schema.details.name;
|
||||||
schemaVersion: Schema.version,
|
|
||||||
path: Schema.filePath,
|
if (SkipDBSchemas.includes(name)) continue;
|
||||||
});
|
|
||||||
}
|
await initDatabase(schema);
|
||||||
resolve();
|
}
|
||||||
}, 1000);
|
resolve();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const initDatabase = async (
|
||||||
|
schema: (typeof DBSchemas)[keyof typeof DBSchemas],
|
||||||
|
fileSuffix?: string,
|
||||||
|
): Promise<string> => {
|
||||||
|
const _nameObj: databaseNameSuffix = {
|
||||||
|
name: schema.details.name,
|
||||||
|
suffix: fileSuffix,
|
||||||
|
};
|
||||||
|
console.log('initDatabase', _nameObj);
|
||||||
|
const name = mergeDBName(_nameObj);
|
||||||
|
|
||||||
|
let dbObj: DBObject = {
|
||||||
|
schema: schema,
|
||||||
|
name,
|
||||||
|
db: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
databases[name] = dbObj;
|
||||||
|
|
||||||
|
await getDatabase(_nameObj, true); // init Database
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
|
|
@ -1,15 +1,45 @@
|
||||||
import {MigrationCallback} from 'realm';
|
import {MigrationCallback} from 'realm';
|
||||||
|
import DBSchemas from './schemas';
|
||||||
|
import {databaseConf, databaseNames} from './types';
|
||||||
|
|
||||||
export const usersDBMigration: MigrationCallback = (oldRealm, newRealm) => {
|
export const DBMigration: {[key in databaseNames]: any} = {
|
||||||
/*// only apply this change if upgrading to schemaVersion 2
|
users: (Schema: typeof DBSchemas.users) => {
|
||||||
if (oldRealm.schemaVersion < 2) {
|
const callback: MigrationCallback = (oldRealm, newRealm) => {
|
||||||
const oldObjects = oldRealm.objects('Person');
|
/*// only apply this change if upgrading to schemaVersion 2
|
||||||
const newObjects = newRealm.objects('Person');
|
if (oldRealm.schemaVersion < 2) {
|
||||||
// loop through all objects and set the fullName property in the new schema
|
const oldObjects = oldRealm.objects('Person');
|
||||||
for (const objectIndex in oldObjects) {
|
const newObjects = newRealm.objects('Person');
|
||||||
const oldObject = oldObjects[objectIndex];
|
// loop through all objects and set the fullName property in the new schema
|
||||||
const newObject = newObjects[objectIndex];
|
for (const objectIndex in oldObjects) {
|
||||||
newObject.fullName = `${oldObject.firstName} ${oldObject.lastName}`;
|
const oldObject = oldObjects[objectIndex];
|
||||||
}
|
const newObject = newObjects[objectIndex];
|
||||||
}*/
|
newObject.fullName = `${oldObject.firstName} ${oldObject.lastName}`;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
};
|
||||||
|
|
||||||
|
return callback;
|
||||||
|
},
|
||||||
|
chat: (Schema: typeof DBSchemas.chat) => {
|
||||||
|
const callback: MigrationCallback = (oldRealm, newRealm) => {
|
||||||
|
/*// only apply this change if upgrading to schemaVersion 2
|
||||||
|
if (oldRealm.schemaVersion < 2) {
|
||||||
|
const oldObjects = oldRealm.objects('Person');
|
||||||
|
const newObjects = newRealm.objects('Person');
|
||||||
|
// loop through all objects and set the fullName property in the new schema
|
||||||
|
for (const objectIndex in oldObjects) {
|
||||||
|
const oldObject = oldObjects[objectIndex];
|
||||||
|
const newObject = newObjects[objectIndex];
|
||||||
|
newObject.fullName = `${oldObject.firstName} ${oldObject.lastName}`;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
};
|
||||||
|
|
||||||
|
return callback;
|
||||||
|
},
|
||||||
|
chatRoomInfos: (Schema: typeof DBSchemas.chatRoomInfos) => {
|
||||||
|
const callback: MigrationCallback = (oldRealm, newRealm) => {};
|
||||||
|
|
||||||
|
return callback;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,46 +1,9 @@
|
||||||
import {usersDBMigration} from './migration';
|
import chat from './schemas/chat';
|
||||||
|
import users from './schemas/users';
|
||||||
|
import chatRoomInfos from './schemas/chatRoomInfos';
|
||||||
|
|
||||||
type databaseNames = 'users' | 'chat';
|
const DBSchemas = {users, chat, chatRoomInfos};
|
||||||
|
export const SkipDBSchemas = [chat.details.name];
|
||||||
|
|
||||||
interface databaseConf {
|
export type databaseConfType = typeof DBSchemas[keyof typeof DBSchemas];
|
||||||
filePath: string;
|
|
||||||
version: number;
|
|
||||||
migration?: any;
|
|
||||||
details: {
|
|
||||||
name: databaseNames;
|
|
||||||
properties: any;
|
|
||||||
primaryKey: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const users: databaseConf = {
|
|
||||||
filePath: 'users',
|
|
||||||
version: 1,
|
|
||||||
migration: usersDBMigration,
|
|
||||||
details: {
|
|
||||||
name: 'users',
|
|
||||||
properties: {
|
|
||||||
UserId: 'string',
|
|
||||||
AccountName: 'string',
|
|
||||||
Username: 'string',
|
|
||||||
},
|
|
||||||
primaryKey: 'UserId',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const chat: databaseConf = {
|
|
||||||
filePath: 'chat',
|
|
||||||
version: 1,
|
|
||||||
//migration: chatDBMigration,
|
|
||||||
details: {
|
|
||||||
name: 'chat',
|
|
||||||
properties: {
|
|
||||||
UserId: 'string',
|
|
||||||
msg: 'string',
|
|
||||||
},
|
|
||||||
primaryKey: 'UserId',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const DBSchemas = {users, chat};
|
|
||||||
export default DBSchemas;
|
export default DBSchemas;
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
import {filterParam, getAllEntries, getEntry} from '../get';
|
||||||
|
import {DBMigration} from '../migration';
|
||||||
|
import {setEntry} from '../set';
|
||||||
|
|
||||||
|
import {databaseConf, possibleDBKeys} from '../types';
|
||||||
|
|
||||||
|
enum keys {
|
||||||
|
syncID = "a",
|
||||||
|
UserId = 'b',
|
||||||
|
data = 'c',
|
||||||
|
massageType = "d",
|
||||||
|
created_at = "e",
|
||||||
|
received_by_server = "f",
|
||||||
|
received_by_target_clients = "g",
|
||||||
|
reply = "h",
|
||||||
|
reactions = "i",
|
||||||
|
hasRead = "j",
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = 'chat';
|
||||||
|
const primaryKey: keyof typeof propsDefault = keys.UserId;
|
||||||
|
|
||||||
|
const propsType: {[key in keyof typeof propsDefault]: string} = {
|
||||||
|
|
||||||
|
[keys.syncID]: "int",
|
||||||
|
[keys.UserId]: 'string',
|
||||||
|
[keys.data]: 'data',
|
||||||
|
[keys.massageType]: "int",
|
||||||
|
[keys.created_at]: "int",
|
||||||
|
[keys.received_by_server]: "int",
|
||||||
|
[keys.received_by_target_clients]: "int",
|
||||||
|
[keys.reply]: "int",
|
||||||
|
[keys.reactions]: "i",
|
||||||
|
[keys.hasRead]: "j",
|
||||||
|
};
|
||||||
|
|
||||||
|
const propsDefault = {
|
||||||
|
[keys.syncID]: "a",
|
||||||
|
[keys.UserId]: 'b',
|
||||||
|
[keys.data]: 'c',
|
||||||
|
[keys.massageType]: "d",
|
||||||
|
[keys.created_at]: "e",
|
||||||
|
[keys.received_by_server]: "f",
|
||||||
|
[keys.received_by_target_clients]: "g",
|
||||||
|
[keys.reply]: "h",
|
||||||
|
[keys.reactions]: "i",
|
||||||
|
[keys.hasRead]: "j",
|
||||||
|
};
|
||||||
|
|
||||||
|
const thisSchema: databaseConf<typeof propsDefault, typeof keys> = {
|
||||||
|
filePath: name,
|
||||||
|
version: 1,
|
||||||
|
keys,
|
||||||
|
migration: () => {
|
||||||
|
return DBMigration[name](thisSchema);
|
||||||
|
},
|
||||||
|
setEntry: (val: typeof thisSchema.defaultProps, suffix?: string) => {
|
||||||
|
return setEntry<typeof thisSchema, typeof thisSchema.defaultProps>(
|
||||||
|
thisSchema,
|
||||||
|
val,
|
||||||
|
suffix,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getEntry: (key: possibleDBKeys, suffix?: string) => {
|
||||||
|
return getEntry<typeof thisSchema, typeof thisSchema.defaultProps>(
|
||||||
|
thisSchema,
|
||||||
|
key,
|
||||||
|
suffix,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getAllEntries: (filter?: filterParam, suffix?: string) => {
|
||||||
|
return getAllEntries<typeof thisSchema, typeof thisSchema.defaultProps>(
|
||||||
|
thisSchema,
|
||||||
|
filter,
|
||||||
|
suffix,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
defaultProps: propsDefault,
|
||||||
|
details: {
|
||||||
|
name,
|
||||||
|
properties: propsType,
|
||||||
|
primaryKey,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default thisSchema;
|
|
@ -0,0 +1,73 @@
|
||||||
|
import {filterParam, getAllEntries, getEntry} from '../get';
|
||||||
|
import {DBMigration} from '../migration';
|
||||||
|
import {setEntry} from '../set';
|
||||||
|
|
||||||
|
import {databaseConf, possibleDBKeys} from '../types';
|
||||||
|
|
||||||
|
enum keys {
|
||||||
|
RoomId = 'a',
|
||||||
|
syncId = 'b',
|
||||||
|
initSyncId = 'c',
|
||||||
|
unreadMessages = 'd',
|
||||||
|
users = 'e',
|
||||||
|
timestamp = 'f',
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = 'chatRoomInfos';
|
||||||
|
const primaryKey: keyof typeof propsDefault = keys.RoomId;
|
||||||
|
|
||||||
|
const propsType: {[key in keyof typeof propsDefault]: string} = {
|
||||||
|
[keys.RoomId]: 'string',
|
||||||
|
[keys.syncId]: 'int',
|
||||||
|
[keys.initSyncId]: 'int',
|
||||||
|
[keys.unreadMessages]: 'int',
|
||||||
|
[keys.users]: 'string[]',
|
||||||
|
[keys.timestamp]: 'int',
|
||||||
|
};
|
||||||
|
|
||||||
|
const propsDefault = {
|
||||||
|
[keys.RoomId]: '',
|
||||||
|
[keys.syncId]: 0,
|
||||||
|
[keys.initSyncId]: 0,
|
||||||
|
[keys.unreadMessages]: 0,
|
||||||
|
[keys.users]: ['none'],
|
||||||
|
[keys.timestamp]: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const thisSchema: databaseConf<typeof propsDefault, typeof keys> = {
|
||||||
|
filePath: name,
|
||||||
|
version: 1,
|
||||||
|
keys,
|
||||||
|
migration: () => {
|
||||||
|
return DBMigration[name](thisSchema);
|
||||||
|
},
|
||||||
|
setEntry: (val: typeof thisSchema.defaultProps, suffix?: string) => {
|
||||||
|
return setEntry<typeof thisSchema, typeof thisSchema.defaultProps>(
|
||||||
|
thisSchema,
|
||||||
|
val,
|
||||||
|
suffix,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getEntry: (key: possibleDBKeys, suffix?: string) => {
|
||||||
|
return getEntry<typeof thisSchema, typeof thisSchema.defaultProps>(
|
||||||
|
thisSchema,
|
||||||
|
key,
|
||||||
|
suffix,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getAllEntries: (filter?: filterParam, suffix?: string) => {
|
||||||
|
return getAllEntries<typeof thisSchema, typeof thisSchema.defaultProps>(
|
||||||
|
thisSchema,
|
||||||
|
filter,
|
||||||
|
suffix,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
defaultProps: propsDefault,
|
||||||
|
details: {
|
||||||
|
name,
|
||||||
|
properties: propsType,
|
||||||
|
primaryKey,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default thisSchema;
|
|
@ -0,0 +1,93 @@
|
||||||
|
import {filterParam, getAllEntries, getEntry} from '../get';
|
||||||
|
import {DBMigration} from '../migration';
|
||||||
|
import {setEntry} from '../set';
|
||||||
|
|
||||||
|
import {databaseConf, possibleDBKeys} from '../types';
|
||||||
|
|
||||||
|
enum keys {
|
||||||
|
UserId = 'a',
|
||||||
|
AccountName = 'b',
|
||||||
|
Username = 'c',
|
||||||
|
Description = 'd',
|
||||||
|
FollowersCount = 'e',
|
||||||
|
FollowingCount = 'f',
|
||||||
|
lastUpdateTimestamp = 'g',
|
||||||
|
ProfilePicture = 'h',
|
||||||
|
ProfilePictureBinaryLQ = 'i',
|
||||||
|
ProfilePictureBinaryHQ = 'j',
|
||||||
|
|
||||||
|
XpLevel = 'k',
|
||||||
|
XpPoints = 'l',
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = 'users';
|
||||||
|
const primaryKey: keyof typeof propsDefault = keys.UserId;
|
||||||
|
|
||||||
|
const propsType: {[key in keyof typeof propsDefault]: string} = {
|
||||||
|
[keys.UserId]: 'string',
|
||||||
|
[keys.AccountName]: 'string',
|
||||||
|
[keys.Username]: 'string',
|
||||||
|
[keys.Description]: 'string',
|
||||||
|
[keys.FollowersCount]: 'int',
|
||||||
|
[keys.FollowingCount]: 'int',
|
||||||
|
[keys.lastUpdateTimestamp]: 'int',
|
||||||
|
[keys.ProfilePicture]: 'string', //URL
|
||||||
|
[keys.ProfilePictureBinaryLQ]: 'data',
|
||||||
|
[keys.ProfilePictureBinaryHQ]: 'data',
|
||||||
|
|
||||||
|
[keys.XpLevel]: 'int',
|
||||||
|
[keys.XpPoints]: 'int',
|
||||||
|
};
|
||||||
|
|
||||||
|
const propsDefault = {
|
||||||
|
[keys.UserId]: '',
|
||||||
|
[keys.AccountName]: '',
|
||||||
|
[keys.Username]: '',
|
||||||
|
[keys.Description]: '',
|
||||||
|
[keys.FollowersCount]: 0,
|
||||||
|
[keys.FollowingCount]: 0,
|
||||||
|
[keys.lastUpdateTimestamp]: 0,
|
||||||
|
[keys.ProfilePicture]: '', //URL
|
||||||
|
[keys.ProfilePictureBinaryLQ]: new ArrayBuffer(0),
|
||||||
|
[keys.ProfilePictureBinaryHQ]: new ArrayBuffer(0),
|
||||||
|
[keys.XpLevel]: 0,
|
||||||
|
[keys.XpPoints]: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const thisSchema: databaseConf<typeof propsDefault, typeof keys> = {
|
||||||
|
filePath: name,
|
||||||
|
version: 1,
|
||||||
|
keys,
|
||||||
|
migration: () => {
|
||||||
|
return DBMigration[name](thisSchema);
|
||||||
|
},
|
||||||
|
setEntry: (val: typeof thisSchema.defaultProps, suffix?: string) => {
|
||||||
|
return setEntry<typeof thisSchema, typeof thisSchema.defaultProps>(
|
||||||
|
thisSchema,
|
||||||
|
val,
|
||||||
|
suffix,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getEntry: (key: possibleDBKeys, suffix?: string) => {
|
||||||
|
return getEntry<typeof thisSchema, typeof thisSchema.defaultProps>(
|
||||||
|
thisSchema,
|
||||||
|
key,
|
||||||
|
suffix,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getAllEntries: (filter?: filterParam, suffix?: string) => {
|
||||||
|
return getAllEntries<typeof thisSchema, typeof thisSchema.defaultProps>(
|
||||||
|
thisSchema,
|
||||||
|
filter,
|
||||||
|
suffix,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
defaultProps: propsDefault,
|
||||||
|
details: {
|
||||||
|
name,
|
||||||
|
properties: propsType,
|
||||||
|
primaryKey,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default thisSchema;
|
|
@ -0,0 +1,19 @@
|
||||||
|
import {getDatabase} from './getDB';
|
||||||
|
import {databaseConf, mergeDBName} from './types';
|
||||||
|
|
||||||
|
import Realm from 'realm';
|
||||||
|
|
||||||
|
export const setEntry = async <T2 extends databaseConf<T, any>, T>(
|
||||||
|
schema: T2,
|
||||||
|
value: T,
|
||||||
|
suffix?: string,
|
||||||
|
) => {
|
||||||
|
const nameObj = {name: schema.details.name, suffix};
|
||||||
|
const dbName = mergeDBName(nameObj);
|
||||||
|
|
||||||
|
const realm = await getDatabase(nameObj);
|
||||||
|
|
||||||
|
realm.write(() => {
|
||||||
|
realm.create(nameObj.name, value as any, Realm.UpdateMode.Modified);
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,44 @@
|
||||||
|
import MyUserManager from '@user/MyUserManager';
|
||||||
|
import {filterParam} from './get';
|
||||||
|
|
||||||
|
export type databaseNames = 'users' | 'chat' | 'chatRoomInfos';
|
||||||
|
export type possibleDBKeys = string;
|
||||||
|
|
||||||
|
export interface databaseConf<props, enums> {
|
||||||
|
filePath: string;
|
||||||
|
version: number;
|
||||||
|
migration?: any;
|
||||||
|
keys: enums;
|
||||||
|
getEntry: (key: possibleDBKeys, suffix?: string) => Promise<props | null>;
|
||||||
|
getAllEntries: (
|
||||||
|
filter?: filterParam,
|
||||||
|
suffix?: string,
|
||||||
|
) => Promise<props[] | null>;
|
||||||
|
setEntry: (val: props, suffix?: string) => Promise<void>;
|
||||||
|
defaultProps: props;
|
||||||
|
details: {
|
||||||
|
name: databaseNames;
|
||||||
|
properties: {[key in keyof props]: string};
|
||||||
|
primaryKey: keyof props;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface databaseNameSuffix {
|
||||||
|
name: databaseNames;
|
||||||
|
suffix?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mergeDBName(nameObj: databaseNameSuffix, web?: 'web'): string {
|
||||||
|
if (web === 'web') {
|
||||||
|
return nameObj.suffix === undefined
|
||||||
|
? nameObj.name + '-' + MyUserManager.getSelectedUserId()
|
||||||
|
: nameObj.name +
|
||||||
|
'-' +
|
||||||
|
MyUserManager.getSelectedUserId() +
|
||||||
|
('_' + nameObj.suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nameObj.suffix === undefined
|
||||||
|
? nameObj.name
|
||||||
|
: nameObj.name + nameObj.suffix;
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ export const lang: LangFormat = {
|
||||||
},
|
},
|
||||||
calendar: {
|
calendar: {
|
||||||
tabName: 'Calendar',
|
tabName: 'Calendar',
|
||||||
overview: 'Calendar',
|
overview: 'Upcomming events',
|
||||||
},
|
},
|
||||||
map: {
|
map: {
|
||||||
tabName: 'Map',
|
tabName: 'Map',
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { MyScreenContainer } from '@components/MyScreenContainer';
|
import {CalendarScreen} from '@pages/calendar/calendar';
|
||||||
import { Text } from '@gluestack-ui/themed';
|
|
||||||
import {
|
import {
|
||||||
createNativeStackNavigator,
|
createNativeStackNavigator,
|
||||||
NativeStackNavigationProp,
|
NativeStackNavigationProp,
|
||||||
|
@ -20,7 +19,9 @@ export type CalendarScreenNavigationProp =
|
||||||
NativeStackNavigationProp<CalendarStackNavigatorParamList>;
|
NativeStackNavigationProp<CalendarStackNavigatorParamList>;
|
||||||
|
|
||||||
function CalendarTab() {
|
function CalendarTab() {
|
||||||
const lang = useSelector((state: RootState) => state.appVariables.lang.navigation.home.calendar);
|
const lang = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.lang.navigation.home.calendar,
|
||||||
|
);
|
||||||
const currentTheme = useSelector(
|
const currentTheme = useSelector(
|
||||||
(state: RootState) => state.nonSaveVariables.theme.colors,
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
);
|
);
|
||||||
|
@ -36,7 +37,7 @@ function CalendarTab() {
|
||||||
<CalendarStack.Screen
|
<CalendarStack.Screen
|
||||||
name="Overview"
|
name="Overview"
|
||||||
options={{
|
options={{
|
||||||
title: lang.tabName,
|
title: lang.overview,
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
headerShadowVisible: false,
|
headerShadowVisible: false,
|
||||||
headerStyle: headerStyle,
|
headerStyle: headerStyle,
|
||||||
|
@ -47,12 +48,4 @@ function CalendarTab() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CalendarScreen() {
|
|
||||||
return (
|
|
||||||
<MyScreenContainer>
|
|
||||||
<Text>Calendar</Text>
|
|
||||||
</MyScreenContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CalendarTab;
|
export default CalendarTab;
|
||||||
|
|
|
@ -8,6 +8,8 @@ import {RootState} from '@redux/store';
|
||||||
import {View} from 'react-native';
|
import {View} from 'react-native';
|
||||||
import {useSelector} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
|
import {Map} from '@pages/map/map';
|
||||||
|
|
||||||
export const MapTabName = 'Map';
|
export const MapTabName = 'Map';
|
||||||
|
|
||||||
export type MapStackNavigatorParamList = {
|
export type MapStackNavigatorParamList = {
|
||||||
|
@ -44,11 +46,7 @@ function MapTab() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function MapScreen() {
|
function MapScreen() {
|
||||||
return (
|
return <Map />;
|
||||||
<MyScreenContainer>
|
|
||||||
<Text>Jan dein Part</Text>
|
|
||||||
</MyScreenContainer>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MapTab;
|
export default MapTab;
|
||||||
|
|
|
@ -6,30 +6,89 @@ import {useSelector} from 'react-redux';
|
||||||
import {RootState, store} from '@redux/store';
|
import {RootState, store} from '@redux/store';
|
||||||
import {useEffect} from 'react';
|
import {useEffect} from 'react';
|
||||||
|
|
||||||
|
import imgSrc from '@img/maimg.png';
|
||||||
|
import {placeholder} from '@lang/default';
|
||||||
|
|
||||||
import {initAppData} from '@helper/appData';
|
import {initAppData} from '@helper/appData';
|
||||||
import {appStatus} from '@configs/appNonSaveVar';
|
import {appStatus} from '@configs/appNonSaveVar';
|
||||||
import {appNonSaveVarActions} from '@configs/appNonSaveVarReducer';
|
import {appNonSaveVarActions} from '@configs/appNonSaveVarReducer';
|
||||||
import BigDataManager from '@helper/storage/BigDataManager';
|
import BigDataManager from '@helper/storage/BigDataManager';
|
||||||
|
import {initKey} from '@helper/storage/bdm/encryption';
|
||||||
|
import UserManager from '@user/UserManager';
|
||||||
|
import MyUserManager from '@user/MyUserManager';
|
||||||
|
import DBSchemas from '@helper/storage/bdm/schemas';
|
||||||
|
import {chatTags, convertDatabaseChat} from '@configs/chat/types';
|
||||||
|
import {addChatEntity} from '@components/chat/initChatDatabase';
|
||||||
|
import {initDatabase} from '@helper/storage/bdm/init';
|
||||||
|
|
||||||
const AnimationView = animated(View);
|
const AnimationView = animated(View);
|
||||||
|
|
||||||
function onAppStart() {
|
export async function onAppStart() {
|
||||||
initAppData().then(() => {
|
await initAppData();
|
||||||
BigDataManager.initDatabase()
|
|
||||||
.then(() => {
|
await initKey();
|
||||||
console.log('finish');
|
|
||||||
setTimeout(() => {
|
BigDataManager.initDatabase()
|
||||||
store.dispatch(
|
.then(async () => {
|
||||||
appNonSaveVarActions.setAppStatus(appStatus.APP_RUNNING),
|
const keys = BigDataManager.databases.chatRoomInfos.keys;
|
||||||
);
|
const entries =
|
||||||
}, 0);
|
(await BigDataManager.databases.chatRoomInfos.getAllEntries()) || [];
|
||||||
})
|
|
||||||
.catch(err => {
|
entries.sort((a, b) =>
|
||||||
console.error("Database Error! Can't start App :(");
|
a[keys.timestamp] > b[keys.timestamp]
|
||||||
|
? 1
|
||||||
|
: b[keys.timestamp] > a[keys.timestamp]
|
||||||
|
? -1
|
||||||
|
: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let i = 0; i < entries.length; i++) {
|
||||||
|
console.log(entries[i]);
|
||||||
|
const chat = convertDatabaseChat(entries[i]);
|
||||||
|
if (chat === undefined) continue;
|
||||||
|
|
||||||
|
await initDatabase(DBSchemas.chat, chat.roomId);
|
||||||
|
|
||||||
|
addChatEntity(chat);
|
||||||
|
|
||||||
|
/*if (chat.roomId === 'test') {
|
||||||
|
const chatDBKeys = BigDataManager.databases.chat.keys;
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
await BigDataManager.databases.chat.setEntry(
|
||||||
|
{
|
||||||
|
[chatDBKeys.UserId]: MyUserManager.getSelectedUserId(),
|
||||||
|
[chatDBKeys.data]: 'heyho',
|
||||||
|
},
|
||||||
|
chat.roomId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('finish');
|
||||||
|
const usrDBKeys = BigDataManager.databases.users.keys;
|
||||||
|
await BigDataManager.databases.users.setEntry({
|
||||||
|
[usrDBKeys.UserId]: 'test',
|
||||||
|
[usrDBKeys.AccountName]: '#845613',
|
||||||
|
[usrDBKeys.Username]: 'TestGroupVirtual',
|
||||||
|
[usrDBKeys.Description]: 'This is a test account that is not real. ^^',
|
||||||
|
[usrDBKeys.FollowersCount]: 2,
|
||||||
|
[usrDBKeys.FollowingCount]: 24,
|
||||||
|
[usrDBKeys.lastUpdateTimestamp]: 412341234,
|
||||||
|
[usrDBKeys.ProfilePicture]: '',
|
||||||
|
[usrDBKeys.ProfilePictureBinaryHQ]: new ArrayBuffer(0),
|
||||||
|
[usrDBKeys.ProfilePictureBinaryLQ]: new ArrayBuffer(0),
|
||||||
|
[usrDBKeys.XpLevel]: 0,
|
||||||
|
[usrDBKeys.XpPoints]: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
//store.dispatch(actions.loadPreferences(appVar));
|
store.dispatch(appNonSaveVarActions.setAppStatus(appStatus.APP_RUNNING));
|
||||||
});
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error("Database Error! Can't start App :(", err);
|
||||||
|
});
|
||||||
|
|
||||||
|
//store.dispatch(actions.loadPreferences(appVar));
|
||||||
}
|
}
|
||||||
|
|
||||||
function StartHelper() {
|
function StartHelper() {
|
||||||
|
@ -72,12 +131,17 @@ function StartHelper() {
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(onAppStart, []);
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await onAppStart();
|
||||||
|
})();
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (currentAppStatus === appStatus.APP_RUNNING) return null;
|
if (currentAppStatus === appStatus.APP_RUNNING) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={[{flex: 1, backgroundColor: currentTheme.backgroundDark400}]}>
|
<SafeAreaView
|
||||||
|
style={[{flex: 1, backgroundColor: currentTheme.backgroundDark400}]}>
|
||||||
<Center height={'100%'}>
|
<Center height={'100%'}>
|
||||||
<AnimationView
|
<AnimationView
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import {MyScreenContainer} from '@components/MyScreenContainer';
|
||||||
|
import {Text} from '@gluestack-ui/themed';
|
||||||
|
import {RootState} from '@redux/store';
|
||||||
|
import {View} from 'react-native';
|
||||||
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
|
const events = [
|
||||||
|
{
|
||||||
|
title: 'Bootshaus',
|
||||||
|
description: '01.12.2023 20:00 Uhr',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Bootshaus',
|
||||||
|
description: '01.12.2023 20:00 Uhr',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function CalendarScreen() {
|
||||||
|
const currentTheme = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyScreenContainer>
|
||||||
|
<Text>Calendar</Text>
|
||||||
|
|
||||||
|
<View style={{}}></View>
|
||||||
|
</MyScreenContainer>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
import {StyleSheet, View, Text, Image} from 'react-native';
|
||||||
|
import Mapbox, {MarkerView} from '@rnmapbox/maps';
|
||||||
|
|
||||||
|
import React, {useState} from 'react'; // Add useState import
|
||||||
|
|
||||||
|
import DisplayMarkerList from '@components/map/DisplayMarkerList';
|
||||||
|
|
||||||
|
import getLocationData, {PA_Point} from '@components/map/cluster/getData';
|
||||||
|
import {store} from '@redux/store';
|
||||||
|
import {appNonSaveVarActions} from '@configs/appNonSaveVarReducer';
|
||||||
|
import {Position} from '@rnmapbox/maps/src/types/Position';
|
||||||
|
|
||||||
|
import {Dimensions} from 'react-native';
|
||||||
|
|
||||||
|
Mapbox.setAccessToken(
|
||||||
|
'pk.eyJ1IjoidGl0YW5pdW1iYWNoIiwiYSI6ImNscGgzZGJxMDAwbHQyaXA2N3BtOWUxbWkifQ.x-f8JJxwQHWmPFI3P6Qn-w',
|
||||||
|
);
|
||||||
|
|
||||||
|
let lastCameraChange = 0;
|
||||||
|
let isRerenderData = 0;
|
||||||
|
|
||||||
|
export const Map = () => {
|
||||||
|
const mapRef = React.useRef<Mapbox.MapView | null>(null);
|
||||||
|
const [mapMarkers, setMapMarkers] = useState<PA_Point[]>([]); // Add useState for visibleBounds
|
||||||
|
const [lastDataRerender, setLastDataRerender] = useState(0); // Add useState for visibleBounds
|
||||||
|
|
||||||
|
const getVisibleBounds = async () => {
|
||||||
|
// return when lastDataRerender is 300ms ago
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
if (now - lastDataRerender < 2000) return;
|
||||||
|
|
||||||
|
isRerenderData = now;
|
||||||
|
|
||||||
|
console.log('----1');
|
||||||
|
|
||||||
|
if (mapRef.current) {
|
||||||
|
const visibleBounds = await (
|
||||||
|
mapRef.current as Mapbox.MapView
|
||||||
|
).getVisibleBounds();
|
||||||
|
|
||||||
|
/* const deviceWidth = Dimensions.get('window').width;
|
||||||
|
const deviceHeight = Dimensions.get('window').height;
|
||||||
|
|
||||||
|
const visibleBounds: [Position, Position] = [
|
||||||
|
await mapRef.current.getCoordinateFromView([100, 100]),
|
||||||
|
await mapRef.current.getCoordinateFromView([100, 200]),
|
||||||
|
];
|
||||||
|
|
||||||
|
//log visibleBounds
|
||||||
|
console.log(visibleBounds);
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const zoomLevel = await (mapRef.current as Mapbox.MapView).getZoom();
|
||||||
|
|
||||||
|
console.log('----2', Date.now() - now + 'ms');
|
||||||
|
|
||||||
|
//console.log(visibleBounds);
|
||||||
|
let markerData = (await getLocationData(visibleBounds, 0))?.locations;
|
||||||
|
|
||||||
|
console.log('----3', Date.now() - now + 'ms');
|
||||||
|
|
||||||
|
//store.dispatch(appNonSaveVarActions.setMapMarkers(markerData || []));
|
||||||
|
setMapMarkers(markerData || []);
|
||||||
|
|
||||||
|
console.log('----4', Date.now() - now + 'ms');
|
||||||
|
}
|
||||||
|
|
||||||
|
isRerenderData = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
function onCameraChanged() {
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
if (now - lastCameraChange > 500) {
|
||||||
|
lastCameraChange = now;
|
||||||
|
setTimeout(getVisibleBounds, 500);
|
||||||
|
console.log('------------5', Date.now() - now + 'ms');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMapMoveFinished() {
|
||||||
|
getVisibleBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
let intervalId: NodeJS.Timeout;
|
||||||
|
|
||||||
|
if (mapRef.current !== null) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const executeInterval = async () => {
|
||||||
|
await getVisibleBounds();
|
||||||
|
intervalId = setTimeout(executeInterval, 50000);
|
||||||
|
};
|
||||||
|
|
||||||
|
executeInterval();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.page}>
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Mapbox.MapView
|
||||||
|
ref={mapRef}
|
||||||
|
onMapIdle={onMapMoveFinished}
|
||||||
|
onCameraChanged={onCameraChanged}
|
||||||
|
style={styles.map}
|
||||||
|
compassEnabled={true}
|
||||||
|
scaleBarEnabled={false}
|
||||||
|
//attributionPosition={{bottom: 75, left: 100}}
|
||||||
|
//logoPosition={{bottom: 75, left: 10}}
|
||||||
|
attributionPosition={{top: 10, left: 100}}
|
||||||
|
logoPosition={{top: 10, left: 10}}
|
||||||
|
styleURL="mapbox://styles/titaniumbach/clpij5uoo00o301pg2dj23j0m"
|
||||||
|
projection="globe">
|
||||||
|
<DisplayMarkerList markers={mapMarkers} />
|
||||||
|
</Mapbox.MapView>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
page: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
map: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
});
|
|
@ -9,7 +9,9 @@ import {
|
||||||
} from '@configs/types';
|
} from '@configs/types';
|
||||||
import {saveVarChanges} from '@helper/appData';
|
import {saveVarChanges} from '@helper/appData';
|
||||||
import {apiBackendRequest, makeRequest} from '@helper/request';
|
import {apiBackendRequest, makeRequest} from '@helper/request';
|
||||||
import {store} from '@redux/store';
|
import BigDataManager from '@helper/storage/BigDataManager';
|
||||||
|
import {RootState, store} from '@redux/store';
|
||||||
|
import {useSelector} from 'react-redux';
|
||||||
import {MyUserAccount, createUserProp, SourceProp} from './types';
|
import {MyUserAccount, createUserProp, SourceProp} from './types';
|
||||||
|
|
||||||
function createNewMyUser(
|
function createNewMyUser(
|
||||||
|
@ -33,13 +35,9 @@ function createNewMyUser(
|
||||||
EMail,
|
EMail,
|
||||||
SessionId,
|
SessionId,
|
||||||
WebSocketSessionId,
|
WebSocketSessionId,
|
||||||
lastUpdateTimestamp: createUserProp(
|
lastUpdateTimestamp: Math.floor(new Date().getTime() / 1000),
|
||||||
SourceProp.offline,
|
|
||||||
Math.floor(new Date().getTime() / 1000),
|
|
||||||
),
|
|
||||||
ProfilePicture: {
|
ProfilePicture: {
|
||||||
hq: createUserProp(SourceProp.offline),
|
lq: createUserProp(SourceProp.online),
|
||||||
lq: createUserProp(SourceProp.offline),
|
|
||||||
},
|
},
|
||||||
userSettings: {
|
userSettings: {
|
||||||
lang: store.getState().appVariables.lang.details.langCode,
|
lang: store.getState().appVariables.lang.details.langCode,
|
||||||
|
@ -47,9 +45,8 @@ function createNewMyUser(
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('SessionId', SessionId);
|
|
||||||
|
|
||||||
createMyUser(user);
|
createMyUser(user);
|
||||||
|
BigDataManager.initDatabase();
|
||||||
|
|
||||||
makeRequest({
|
makeRequest({
|
||||||
path: apiBackendRequest.APP_START,
|
path: apiBackendRequest.APP_START,
|
||||||
|
@ -70,7 +67,6 @@ function createNewMyUser(
|
||||||
})
|
})
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
let user = {...getMyUser(UserId)};
|
let user = {...getMyUser(UserId)};
|
||||||
console.log(user);
|
|
||||||
user.AccountName = createUserProp(
|
user.AccountName = createUserProp(
|
||||||
SourceProp.offline,
|
SourceProp.offline,
|
||||||
resp.response.AccountName,
|
resp.response.AccountName,
|
||||||
|
@ -125,6 +121,27 @@ function setMyUser(user: MyUserAccount) {
|
||||||
saveVarChanges();
|
saveVarChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function logoutMyUser() {
|
||||||
|
store.dispatch(appVarActions.setCurrentAccount('none'));
|
||||||
|
saveVarChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedUserId(): UserId {
|
||||||
|
return store.getState().appVariables.preferences.selectedAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedMyUserSelector(): MyUserAccount | undefined {
|
||||||
|
const myUserId = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.preferences.selectedAccount,
|
||||||
|
);
|
||||||
|
|
||||||
|
const myUser = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.preferences.accounts[myUserId],
|
||||||
|
);
|
||||||
|
|
||||||
|
return myUser;
|
||||||
|
}
|
||||||
|
|
||||||
function getSessionId(userId?: UserId): XAuthorization | undefined {
|
function getSessionId(userId?: UserId): XAuthorization | undefined {
|
||||||
const preferences = store.getState().appVariables.preferences;
|
const preferences = store.getState().appVariables.preferences;
|
||||||
let user = preferences.accounts[userId || preferences.selectedAccount];
|
let user = preferences.accounts[userId || preferences.selectedAccount];
|
||||||
|
@ -133,11 +150,14 @@ function getSessionId(userId?: UserId): XAuthorization | undefined {
|
||||||
|
|
||||||
let SessionId = user.SessionId;
|
let SessionId = user.SessionId;
|
||||||
|
|
||||||
console.log(userId || preferences.selectedAccount);
|
|
||||||
console.log(preferences.accounts[userId || preferences.selectedAccount]);
|
|
||||||
|
|
||||||
return SessionId;
|
return SessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MyUserManager = {createNewMyUser, getSessionId};
|
const MyUserManager = {
|
||||||
|
createNewMyUser,
|
||||||
|
getSessionId,
|
||||||
|
getSelectedUserId,
|
||||||
|
logoutMyUser,
|
||||||
|
getSelectedMyUserSelector,
|
||||||
|
};
|
||||||
export default MyUserManager;
|
export default MyUserManager;
|
||||||
|
|
|
@ -1,5 +1,285 @@
|
||||||
|
import {maxCachedUsers} from '@configs/appNonSaveVar';
|
||||||
|
import {appNonSaveVarActions} from '@configs/appNonSaveVarReducer';
|
||||||
import {UserId, XAuthorization} from '@configs/types';
|
import {UserId, XAuthorization} from '@configs/types';
|
||||||
import {store} from '@redux/store';
|
import {makeRequest, apiBackendRequest} from '@helper/request';
|
||||||
|
import BigDataManager from '@helper/storage/BigDataManager';
|
||||||
|
import {RootState, store} from '@redux/store';
|
||||||
|
import {useSelector} from 'react-redux';
|
||||||
|
import {
|
||||||
|
BasicUserProp,
|
||||||
|
createUserProp,
|
||||||
|
ProfilePicture,
|
||||||
|
ProfilePictureType,
|
||||||
|
SourceProp,
|
||||||
|
User,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
const UserManager = {};
|
let cachedUserList: UserId[] = [];
|
||||||
|
|
||||||
|
async function getUser(
|
||||||
|
UserId: UserId,
|
||||||
|
save?: boolean,
|
||||||
|
): Promise<User | undefined> {
|
||||||
|
if (UserId === 'none') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let user: User | undefined;
|
||||||
|
|
||||||
|
let state = store.getState();
|
||||||
|
let userIsInCache = false;
|
||||||
|
|
||||||
|
{
|
||||||
|
const usr = state.nonSaveVariables.cachedUsers[UserId];
|
||||||
|
if (usr !== undefined) {
|
||||||
|
user = usr;
|
||||||
|
userIsInCache = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UserId === state.appVariables.preferences.selectedAccount) {
|
||||||
|
const usr = state.appVariables.preferences.accounts[UserId];
|
||||||
|
|
||||||
|
if (usr !== undefined) {
|
||||||
|
user = {
|
||||||
|
AccountName: usr.AccountName,
|
||||||
|
Description: usr.Description,
|
||||||
|
FollowersCount: usr.FollowersCount,
|
||||||
|
FollowingCount: usr.FollowingCount,
|
||||||
|
lastUpdateTimestamp: usr.lastUpdateTimestamp,
|
||||||
|
ProfilePicture: usr.ProfilePicture,
|
||||||
|
UserId,
|
||||||
|
Username: usr.Username,
|
||||||
|
XpLevel: usr.XpLevel,
|
||||||
|
XpPoints: usr.XpPoints,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user === undefined) {
|
||||||
|
const usrDBKeys = BigDataManager.databases.users.keys;
|
||||||
|
const usr = await BigDataManager.databases.users.getEntry(UserId);
|
||||||
|
|
||||||
|
if (usr !== undefined && usr !== null) {
|
||||||
|
let ProfilePicture = {
|
||||||
|
lq:
|
||||||
|
usr[usrDBKeys.ProfilePictureBinaryLQ].byteLength !== 0
|
||||||
|
? createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
new Blob([usr[usrDBKeys.ProfilePictureBinaryLQ]]),
|
||||||
|
)
|
||||||
|
: createUserProp(
|
||||||
|
SourceProp.online,
|
||||||
|
undefined,
|
||||||
|
usr[usrDBKeys.ProfilePicture],
|
||||||
|
),
|
||||||
|
hq:
|
||||||
|
usr[usrDBKeys.ProfilePictureBinaryHQ].byteLength !== 0
|
||||||
|
? createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
new Blob([usr[usrDBKeys.ProfilePictureBinaryHQ]]),
|
||||||
|
)
|
||||||
|
: createUserProp(
|
||||||
|
SourceProp.online,
|
||||||
|
undefined,
|
||||||
|
usr[usrDBKeys.ProfilePicture],
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
user = {
|
||||||
|
AccountName: createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
usr[usrDBKeys.AccountName],
|
||||||
|
),
|
||||||
|
Description: createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
usr[usrDBKeys.Description],
|
||||||
|
),
|
||||||
|
FollowersCount: createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
usr[usrDBKeys.FollowersCount],
|
||||||
|
),
|
||||||
|
FollowingCount: createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
usr[usrDBKeys.FollowingCount],
|
||||||
|
),
|
||||||
|
lastUpdateTimestamp: usr[usrDBKeys.lastUpdateTimestamp],
|
||||||
|
ProfilePicture,
|
||||||
|
UserId,
|
||||||
|
Username: createUserProp(SourceProp.offline, usr[usrDBKeys.Username]),
|
||||||
|
XpLevel: createUserProp(SourceProp.offline, usr[usrDBKeys.XpLevel]),
|
||||||
|
XpPoints: createUserProp(SourceProp.offline, usr[usrDBKeys.XpPoints]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user === undefined) {
|
||||||
|
try {
|
||||||
|
const resp = await makeRequest({
|
||||||
|
path: apiBackendRequest.GET_USER_PROFILE,
|
||||||
|
requestGET: {':userId': UserId},
|
||||||
|
response: {
|
||||||
|
AccountName: '',
|
||||||
|
Description: '',
|
||||||
|
FollowersCount: 0,
|
||||||
|
FollowingCount: 0,
|
||||||
|
Username: '',
|
||||||
|
XpLevel: 0,
|
||||||
|
XpPoints: 0,
|
||||||
|
AvatarUrl: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
user = {
|
||||||
|
AccountName: createUserProp(
|
||||||
|
SourceProp.cached,
|
||||||
|
resp.response.AccountName,
|
||||||
|
),
|
||||||
|
Description: createUserProp(
|
||||||
|
SourceProp.cached,
|
||||||
|
resp.response.Description,
|
||||||
|
),
|
||||||
|
FollowersCount: createUserProp(
|
||||||
|
SourceProp.cached,
|
||||||
|
resp.response.FollowersCount,
|
||||||
|
),
|
||||||
|
FollowingCount: createUserProp(
|
||||||
|
SourceProp.cached,
|
||||||
|
resp.response.FollowingCount,
|
||||||
|
),
|
||||||
|
lastUpdateTimestamp: Math.floor(new Date().getTime() / 1000),
|
||||||
|
ProfilePicture: {
|
||||||
|
lq: createUserProp(
|
||||||
|
SourceProp.online,
|
||||||
|
undefined,
|
||||||
|
resp.response.AvatarUrl,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
UserId,
|
||||||
|
Username: createUserProp(SourceProp.offline, resp.response.Username),
|
||||||
|
XpLevel: createUserProp(SourceProp.cached, resp.response.XpLevel),
|
||||||
|
XpPoints: createUserProp(SourceProp.cached, resp.response.XpPoints),
|
||||||
|
};
|
||||||
|
|
||||||
|
//BigDataManager.setEntry('users', user);
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(error.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userIsInCache === false && user !== undefined) {
|
||||||
|
console.log('save in cache');
|
||||||
|
store.dispatch(appNonSaveVarActions.setCachedUser(user));
|
||||||
|
cachedUserList.push(user.UserId);
|
||||||
|
|
||||||
|
if (cachedUserList.length > maxCachedUsers) {
|
||||||
|
let usrId = cachedUserList[0];
|
||||||
|
cachedUserList.shift();
|
||||||
|
console.log('usrId', usrId);
|
||||||
|
|
||||||
|
store.dispatch(appNonSaveVarActions.removeCachedUser(usrId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GetParam {
|
||||||
|
CACHE = 0,
|
||||||
|
SAVE,
|
||||||
|
}
|
||||||
|
|
||||||
|
let getUserList: {[key: UserId]: GetParam} = {};
|
||||||
|
|
||||||
|
async function refreshUsers() {
|
||||||
|
for (let UserId in getUserList) {
|
||||||
|
const param = getUserList[UserId];
|
||||||
|
delete getUserList[UserId];
|
||||||
|
|
||||||
|
await getUser(UserId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(refreshUsers, 500);
|
||||||
|
|
||||||
|
function addUserToGetQueue(UserId: UserId, param: GetParam) {
|
||||||
|
if (getUserList[UserId] === undefined) {
|
||||||
|
getUserList[UserId] = param;
|
||||||
|
} else if (getUserList[UserId] < param) {
|
||||||
|
getUserList[UserId] = param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUserSelector(UserId: UserId) {
|
||||||
|
addUserToGetQueue(UserId, GetParam.CACHE);
|
||||||
|
|
||||||
|
const myUser = useSelector(
|
||||||
|
(state: RootState) => state.nonSaveVariables.cachedUsers[UserId],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (myUser === undefined) {
|
||||||
|
return initUndefinedUser(UserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return myUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUserSelectorPicture(UserId: UserId): ProfilePicture {
|
||||||
|
addUserToGetQueue(UserId, GetParam.CACHE);
|
||||||
|
|
||||||
|
const myUser = useSelector(
|
||||||
|
(state: RootState) =>
|
||||||
|
state.nonSaveVariables.cachedUsers[UserId]?.ProfilePicture,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (myUser === undefined) {
|
||||||
|
return {
|
||||||
|
lq: createUserProp(SourceProp.online),
|
||||||
|
hq: createUserProp(SourceProp.online),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return myUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUserSelectorAccountName(UserId: UserId): BasicUserProp<string> {
|
||||||
|
addUserToGetQueue(UserId, GetParam.CACHE);
|
||||||
|
|
||||||
|
const myUser = useSelector(
|
||||||
|
(state: RootState) =>
|
||||||
|
state.nonSaveVariables.cachedUsers[UserId]?.AccountName,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (myUser === undefined) {
|
||||||
|
return createUserProp(SourceProp.online);
|
||||||
|
}
|
||||||
|
|
||||||
|
return myUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initUndefinedUser(UserId: UserId): User {
|
||||||
|
return {
|
||||||
|
AccountName: createUserProp(SourceProp.online),
|
||||||
|
Description: createUserProp(SourceProp.online),
|
||||||
|
FollowersCount: createUserProp(SourceProp.online),
|
||||||
|
FollowingCount: createUserProp(SourceProp.online),
|
||||||
|
lastUpdateTimestamp: 0,
|
||||||
|
ProfilePicture: {
|
||||||
|
lq: createUserProp(SourceProp.online),
|
||||||
|
hq: createUserProp(SourceProp.online),
|
||||||
|
},
|
||||||
|
UserId,
|
||||||
|
Username: createUserProp(SourceProp.online),
|
||||||
|
XpLevel: createUserProp(SourceProp.online),
|
||||||
|
XpPoints: createUserProp(SourceProp.online),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserManager = {
|
||||||
|
getUser,
|
||||||
|
getUserSelector,
|
||||||
|
getUserSelectorPicture,
|
||||||
|
getUserSelectorAccountName,
|
||||||
|
initUndefinedUser,
|
||||||
|
};
|
||||||
export default UserManager;
|
export default UserManager;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {ThemeMode} from '@configs/appVar';
|
import {ThemeMode} from '@configs/colors';
|
||||||
import {
|
import {
|
||||||
AccountName,
|
AccountName,
|
||||||
EMail,
|
EMail,
|
||||||
|
@ -16,22 +16,24 @@ export enum SourceProp {
|
||||||
cached = 1,
|
cached = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BasicUserProp<T1> {
|
export interface BasicUserProp<T1> {
|
||||||
source: SourceProp;
|
source: SourceProp;
|
||||||
url?: string;
|
url?: string;
|
||||||
data?: T1;
|
data?: T1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ProfilePictureType = BasicUserProp<Blob | undefined>;
|
||||||
|
|
||||||
export interface ProfilePicture {
|
export interface ProfilePicture {
|
||||||
lq: BasicUserProp<string>;
|
lq: ProfilePictureType; //low quality
|
||||||
hq: BasicUserProp<string>;
|
hq?: ProfilePictureType; //high quality
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
UserId: UserId;
|
UserId: UserId;
|
||||||
|
|
||||||
ProfilePicture: ProfilePicture;
|
ProfilePicture: ProfilePicture;
|
||||||
lastUpdateTimestamp: BasicUserProp<timestamp>;
|
lastUpdateTimestamp: timestamp;
|
||||||
AccountName: BasicUserProp<AccountName>;
|
AccountName: BasicUserProp<AccountName>;
|
||||||
Username: BasicUserProp<Username>;
|
Username: BasicUserProp<Username>;
|
||||||
Description: BasicUserProp<string>;
|
Description: BasicUserProp<string>;
|
||||||
|
|
Reference in New Issue