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
|
||||
end
|
||||
|
||||
pre_install do |installer|
|
||||
$RNMapboxMaps.pre_install(installer)
|
||||
... other pre install hooks
|
||||
end
|
||||
|
||||
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
|
||||
react_native_post_install(
|
||||
installer,
|
||||
|
|
|
@ -16,14 +16,18 @@
|
|||
"@react-navigation/native-stack": "^6.9.17",
|
||||
"@react-spring/native": "^9.7.3",
|
||||
"@reduxjs/toolkit": "^1.9.7",
|
||||
"@rnmapbox/maps": "^10.0.15",
|
||||
"@types/react-native-vector-icons": "^6.4.18",
|
||||
"geolib": "^3.3.4",
|
||||
"password-quality-calculator": "^1.0.4",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.72.7",
|
||||
"react-native-encrypted-storage": "^4.0.3",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-linear-gradient": "^2.8.3",
|
||||
"react-native-safe-area-context": "^4.7.4",
|
||||
"react-native-screens": "^3.27.0",
|
||||
"react-native-securerandom": "^1.0.1",
|
||||
"react-native-svg": "^13.4.0",
|
||||
"react-native-user-agent": "^2.3.1",
|
||||
"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": {
|
||||
"version": "2.0.0",
|
||||
"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==",
|
||||
"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": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
|
@ -8162,6 +8345,11 @@
|
|||
"@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": {
|
||||
"version": "4.1.9",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "1.5.1",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
|
@ -12763,6 +12961,28 @@
|
|||
"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": {
|
||||
"version": "2.0.5",
|
||||
"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": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
|
@ -18753,6 +18978,14 @@
|
|||
"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": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||
|
@ -18894,6 +19127,24 @@
|
|||
"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": {
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz",
|
||||
|
@ -18925,6 +19176,17 @@
|
|||
"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": {
|
||||
"version": "13.4.0",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"version": "1.0.2",
|
||||
"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-spring/native": "^9.7.3",
|
||||
"@reduxjs/toolkit": "^1.9.7",
|
||||
"@rnmapbox/maps": "^10.0.15",
|
||||
"@types/react-native-vector-icons": "^6.4.18",
|
||||
"geolib": "^3.3.4",
|
||||
"password-quality-calculator": "^1.0.4",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.72.7",
|
||||
"react-native-encrypted-storage": "^4.0.3",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-linear-gradient": "^2.8.3",
|
||||
"react-native-safe-area-context": "^4.7.4",
|
||||
"react-native-screens": "^3.27.0",
|
||||
"react-native-securerandom": "^1.0.1",
|
||||
"react-native-svg": "^13.4.0",
|
||||
"react-native-user-agent": "^2.3.1",
|
||||
"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
|
||||
|
||||
import {chatEntity, roomId} from '@configs/chat/types';
|
||||
import {User} from '@user/types';
|
||||
import {UserId} from './types';
|
||||
|
||||
import {getVersionByNum, VersionType} from '@helper/version';
|
||||
import configDarkTheme, {ThemeTokensType} from '@configs/colors';
|
||||
|
||||
import { PA_Point } from '@components/map/cluster/getData';
|
||||
|
||||
export const APP_VERSION = getVersionByNum(1);
|
||||
export const AppVarMaxBackups: number = 10;
|
||||
export const maxCachedUsers = 30;
|
||||
|
||||
export enum appStatus {
|
||||
IS_LOADING,
|
||||
|
@ -21,13 +28,23 @@ export enum connectionStatus {
|
|||
export interface NON_SAVE_VARS {
|
||||
currentAppVersion: VersionType;
|
||||
appStatus: appStatus;
|
||||
connectionStatus: connectionStatus;
|
||||
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 = {
|
||||
currentAppVersion: APP_VERSION,
|
||||
appStatus: appStatus.IS_LOADING,
|
||||
connectionStatus: connectionStatus.UNKNOWN,
|
||||
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 {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({
|
||||
name: 'non_save_vars',
|
||||
initialState: non_save_vars,
|
||||
|
@ -13,6 +18,45 @@ export const appNonSaveVariablesSlice = createSlice({
|
|||
setTheme: (state, action: PayloadAction<ThemeTokensType>) => {
|
||||
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 {
|
||||
dbek: number; //db encryption key
|
||||
version: VersionType;
|
||||
theme: ThemeMode;
|
||||
RegisterProcess: RegisterProcess;
|
||||
|
@ -55,6 +56,7 @@ export interface PREFERENCES_VARS {
|
|||
}
|
||||
|
||||
export const preferences_vars_default: PREFERENCES_VARS = {
|
||||
dbek: -5,
|
||||
version: APP_VERSION, //version of datatypes in storage
|
||||
theme: ThemeMode.Dark,
|
||||
RegisterProcess: {
|
||||
|
|
|
@ -43,6 +43,9 @@ export const appVariablesSlice = createSlice({
|
|||
setAccount: (state, action: PayloadAction<MyUserAccount>) => {
|
||||
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;
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import EncryptedStorage from 'react-native-encrypted-storage';
|
||||
|
||||
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> {
|
||||
|
|
|
@ -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 DBSchemas from './schemas';
|
||||
import {closeAllDatabases, databases, DBObject, getDatabase} from './getDB';
|
||||
import DBSchemas, {SkipDBSchemas} from './schemas';
|
||||
import {databaseConf, databaseNameSuffix, mergeDBName} from './types';
|
||||
|
||||
export const initDatabase = (): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
for (const key in DBSchemas) {
|
||||
const Schema = DBSchemas[key as keyof typeof DBSchemas];
|
||||
Realm.open({
|
||||
schema: [Schema.details],
|
||||
schemaVersion: Schema.version,
|
||||
path: Schema.filePath,
|
||||
});
|
||||
}
|
||||
resolve();
|
||||
}, 1000);
|
||||
export const initDatabases = (): Promise<void> => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
closeAllDatabases();
|
||||
|
||||
for (const key in DBSchemas) {
|
||||
const schema = DBSchemas[key as keyof typeof DBSchemas];
|
||||
const name = schema.details.name;
|
||||
|
||||
if (SkipDBSchemas.includes(name)) continue;
|
||||
|
||||
await initDatabase(schema);
|
||||
}
|
||||
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 DBSchemas from './schemas';
|
||||
import {databaseConf, databaseNames} from './types';
|
||||
|
||||
export const usersDBMigration: 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}`;
|
||||
}
|
||||
}*/
|
||||
export const DBMigration: {[key in databaseNames]: any} = {
|
||||
users: (Schema: typeof DBSchemas.users) => {
|
||||
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;
|
||||
},
|
||||
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 {
|
||||
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 type databaseConfType = typeof DBSchemas[keyof typeof 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: {
|
||||
tabName: 'Calendar',
|
||||
overview: 'Calendar',
|
||||
overview: 'Upcomming events',
|
||||
},
|
||||
map: {
|
||||
tabName: 'Map',
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { MyScreenContainer } from '@components/MyScreenContainer';
|
||||
import { Text } from '@gluestack-ui/themed';
|
||||
import {CalendarScreen} from '@pages/calendar/calendar';
|
||||
import {
|
||||
createNativeStackNavigator,
|
||||
NativeStackNavigationProp,
|
||||
|
@ -20,7 +19,9 @@ export type CalendarScreenNavigationProp =
|
|||
NativeStackNavigationProp<CalendarStackNavigatorParamList>;
|
||||
|
||||
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(
|
||||
(state: RootState) => state.nonSaveVariables.theme.colors,
|
||||
);
|
||||
|
@ -36,7 +37,7 @@ function CalendarTab() {
|
|||
<CalendarStack.Screen
|
||||
name="Overview"
|
||||
options={{
|
||||
title: lang.tabName,
|
||||
title: lang.overview,
|
||||
headerShown: true,
|
||||
headerShadowVisible: false,
|
||||
headerStyle: headerStyle,
|
||||
|
@ -47,12 +48,4 @@ function CalendarTab() {
|
|||
);
|
||||
}
|
||||
|
||||
function CalendarScreen() {
|
||||
return (
|
||||
<MyScreenContainer>
|
||||
<Text>Calendar</Text>
|
||||
</MyScreenContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export default CalendarTab;
|
||||
|
|
|
@ -8,6 +8,8 @@ import {RootState} from '@redux/store';
|
|||
import {View} from 'react-native';
|
||||
import {useSelector} from 'react-redux';
|
||||
|
||||
import {Map} from '@pages/map/map';
|
||||
|
||||
export const MapTabName = 'Map';
|
||||
|
||||
export type MapStackNavigatorParamList = {
|
||||
|
@ -44,11 +46,7 @@ function MapTab() {
|
|||
}
|
||||
|
||||
function MapScreen() {
|
||||
return (
|
||||
<MyScreenContainer>
|
||||
<Text>Jan dein Part</Text>
|
||||
</MyScreenContainer>
|
||||
);
|
||||
return <Map />;
|
||||
}
|
||||
|
||||
export default MapTab;
|
||||
|
|
|
@ -6,30 +6,89 @@ import {useSelector} from 'react-redux';
|
|||
import {RootState, store} from '@redux/store';
|
||||
import {useEffect} from 'react';
|
||||
|
||||
import imgSrc from '@img/maimg.png';
|
||||
import {placeholder} from '@lang/default';
|
||||
|
||||
import {initAppData} from '@helper/appData';
|
||||
import {appStatus} from '@configs/appNonSaveVar';
|
||||
import {appNonSaveVarActions} from '@configs/appNonSaveVarReducer';
|
||||
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);
|
||||
|
||||
function onAppStart() {
|
||||
initAppData().then(() => {
|
||||
BigDataManager.initDatabase()
|
||||
.then(() => {
|
||||
console.log('finish');
|
||||
setTimeout(() => {
|
||||
store.dispatch(
|
||||
appNonSaveVarActions.setAppStatus(appStatus.APP_RUNNING),
|
||||
);
|
||||
}, 0);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error("Database Error! Can't start App :(");
|
||||
export async function onAppStart() {
|
||||
await initAppData();
|
||||
|
||||
await initKey();
|
||||
|
||||
BigDataManager.initDatabase()
|
||||
.then(async () => {
|
||||
const keys = BigDataManager.databases.chatRoomInfos.keys;
|
||||
const entries =
|
||||
(await BigDataManager.databases.chatRoomInfos.getAllEntries()) || [];
|
||||
|
||||
entries.sort((a, b) =>
|
||||
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() {
|
||||
|
@ -72,12 +131,17 @@ function StartHelper() {
|
|||
});
|
||||
}, []);
|
||||
|
||||
useEffect(onAppStart, []);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
await onAppStart();
|
||||
})();
|
||||
}, []);
|
||||
|
||||
if (currentAppStatus === appStatus.APP_RUNNING) return null;
|
||||
|
||||
return (
|
||||
<SafeAreaView style={[{flex: 1, backgroundColor: currentTheme.backgroundDark400}]}>
|
||||
<SafeAreaView
|
||||
style={[{flex: 1, backgroundColor: currentTheme.backgroundDark400}]}>
|
||||
<Center height={'100%'}>
|
||||
<AnimationView
|
||||
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';
|
||||
import {saveVarChanges} from '@helper/appData';
|
||||
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';
|
||||
|
||||
function createNewMyUser(
|
||||
|
@ -33,13 +35,9 @@ function createNewMyUser(
|
|||
EMail,
|
||||
SessionId,
|
||||
WebSocketSessionId,
|
||||
lastUpdateTimestamp: createUserProp(
|
||||
SourceProp.offline,
|
||||
Math.floor(new Date().getTime() / 1000),
|
||||
),
|
||||
lastUpdateTimestamp: Math.floor(new Date().getTime() / 1000),
|
||||
ProfilePicture: {
|
||||
hq: createUserProp(SourceProp.offline),
|
||||
lq: createUserProp(SourceProp.offline),
|
||||
lq: createUserProp(SourceProp.online),
|
||||
},
|
||||
userSettings: {
|
||||
lang: store.getState().appVariables.lang.details.langCode,
|
||||
|
@ -47,9 +45,8 @@ function createNewMyUser(
|
|||
},
|
||||
};
|
||||
|
||||
console.log('SessionId', SessionId);
|
||||
|
||||
createMyUser(user);
|
||||
BigDataManager.initDatabase();
|
||||
|
||||
makeRequest({
|
||||
path: apiBackendRequest.APP_START,
|
||||
|
@ -70,7 +67,6 @@ function createNewMyUser(
|
|||
})
|
||||
.then(resp => {
|
||||
let user = {...getMyUser(UserId)};
|
||||
console.log(user);
|
||||
user.AccountName = createUserProp(
|
||||
SourceProp.offline,
|
||||
resp.response.AccountName,
|
||||
|
@ -125,6 +121,27 @@ function setMyUser(user: MyUserAccount) {
|
|||
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 {
|
||||
const preferences = store.getState().appVariables.preferences;
|
||||
let user = preferences.accounts[userId || preferences.selectedAccount];
|
||||
|
@ -133,11 +150,14 @@ function getSessionId(userId?: UserId): XAuthorization | undefined {
|
|||
|
||||
let SessionId = user.SessionId;
|
||||
|
||||
console.log(userId || preferences.selectedAccount);
|
||||
console.log(preferences.accounts[userId || preferences.selectedAccount]);
|
||||
|
||||
return SessionId;
|
||||
}
|
||||
|
||||
const MyUserManager = {createNewMyUser, getSessionId};
|
||||
const MyUserManager = {
|
||||
createNewMyUser,
|
||||
getSessionId,
|
||||
getSelectedUserId,
|
||||
logoutMyUser,
|
||||
getSelectedMyUserSelector,
|
||||
};
|
||||
export default MyUserManager;
|
||||
|
|
|
@ -1,5 +1,285 @@
|
|||
import {maxCachedUsers} from '@configs/appNonSaveVar';
|
||||
import {appNonSaveVarActions} from '@configs/appNonSaveVarReducer';
|
||||
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;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {ThemeMode} from '@configs/appVar';
|
||||
import {ThemeMode} from '@configs/colors';
|
||||
import {
|
||||
AccountName,
|
||||
EMail,
|
||||
|
@ -16,22 +16,24 @@ export enum SourceProp {
|
|||
cached = 1,
|
||||
}
|
||||
|
||||
interface BasicUserProp<T1> {
|
||||
export interface BasicUserProp<T1> {
|
||||
source: SourceProp;
|
||||
url?: string;
|
||||
data?: T1;
|
||||
}
|
||||
|
||||
export type ProfilePictureType = BasicUserProp<Blob | undefined>;
|
||||
|
||||
export interface ProfilePicture {
|
||||
lq: BasicUserProp<string>;
|
||||
hq: BasicUserProp<string>;
|
||||
lq: ProfilePictureType; //low quality
|
||||
hq?: ProfilePictureType; //high quality
|
||||
}
|
||||
|
||||
export interface User {
|
||||
UserId: UserId;
|
||||
|
||||
ProfilePicture: ProfilePicture;
|
||||
lastUpdateTimestamp: BasicUserProp<timestamp>;
|
||||
lastUpdateTimestamp: timestamp;
|
||||
AccountName: BasicUserProp<AccountName>;
|
||||
Username: BasicUserProp<Username>;
|
||||
Description: BasicUserProp<string>;
|
||||
|
|
Reference in New Issue