mirror of
https://github.com/status-im/status-mobile.git
synced 2025-01-24 15:38:56 +00:00
/location command
This commit is contained in:
parent
5c15df9b64
commit
5051d1ce9e
@ -41,7 +41,8 @@
|
||||
"instabug-reactnative",
|
||||
"nfc-react-native",
|
||||
"react-native-http-bridge",
|
||||
"emojilib"
|
||||
"emojilib",
|
||||
"react-native-mapbox-gl"
|
||||
],
|
||||
"imageDirs": [
|
||||
"images"
|
||||
|
@ -107,6 +107,7 @@ android {
|
||||
applicationId "im.status.ethereum"
|
||||
minSdkVersion 18
|
||||
targetSdkVersion 23
|
||||
multiDexEnabled true
|
||||
versionCode getVersionCode()
|
||||
versionName getVersionName()
|
||||
ndk {
|
||||
@ -115,6 +116,7 @@ android {
|
||||
}
|
||||
dexOptions {
|
||||
jumboMode true
|
||||
javaMaxHeapSize "4g"
|
||||
}
|
||||
signingConfigs {
|
||||
release {
|
||||
@ -180,6 +182,7 @@ dependencies {
|
||||
compile project(':react-native-fs')
|
||||
compile project(':react-native-image-crop-picker')
|
||||
compile project(':react-native-webview-bridge')
|
||||
compile project(':reactnativemapboxgl')
|
||||
compile 'testfairy:testfairy-android-sdk:1.+@aar'
|
||||
|
||||
compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"])
|
||||
|
@ -52,6 +52,7 @@
|
||||
android:enabled="true"
|
||||
android:exported="true"/>
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
|
||||
<service android:name="com.mapbox.mapboxsdk.telemetry.TelemetryService"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
@ -24,6 +24,7 @@ import fr.bamlab.rnimageresizer.ImageResizerPackage;
|
||||
import im.status.ethereum.module.StatusPackage;
|
||||
import io.realm.react.RealmReactPackage;
|
||||
import me.alwx.HttpServer.HttpServerReactPackage;
|
||||
import com.mapbox.reactnativemapboxgl.ReactNativeMapboxGLPackage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -58,7 +59,8 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
new ReactNativeDialogsPackage(),
|
||||
new ImageResizerPackage(),
|
||||
new PickerPackage(),
|
||||
new WebViewBridgePackage(BuildConfig.DEBUG)
|
||||
new WebViewBridgePackage(BuildConfig.DEBUG),
|
||||
new ReactNativeMapboxGLPackage()
|
||||
));
|
||||
|
||||
if (!BuildConfig.DEBUG) {
|
||||
|
@ -40,4 +40,7 @@ include ':react-native-image-crop-picker'
|
||||
project(':react-native-image-crop-picker').projectDir = new File(settingsDir, '../node_modules/react-native-image-crop-picker/android')
|
||||
|
||||
include ':react-native-webview-bridge'
|
||||
project(':react-native-webview-bridge').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview-bridge/android')
|
||||
project(':react-native-webview-bridge').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview-bridge/android')
|
||||
|
||||
include ':reactnativemapboxgl'
|
||||
project(':reactnativemapboxgl').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-mapbox-gl/android')
|
||||
|
@ -1,44 +1,91 @@
|
||||
function locationsSuggestions (params) {
|
||||
var result = {title: "Send location"};
|
||||
var seqArg = params["seq-arg"] ? params["seq-arg"] : "";
|
||||
|
||||
if (seqArg === "Dropped pin")
|
||||
{
|
||||
result.showBack = true;
|
||||
result.height = "max";
|
||||
result.markup = ['view', {},
|
||||
['dropped-pin']];
|
||||
}
|
||||
else if (seqArg != "")
|
||||
{
|
||||
result.showBack = true;
|
||||
result.markup = ['scroll-view', {keyboardShouldPersistTaps: "always"},
|
||||
['view', {},
|
||||
['places-search']]];
|
||||
}
|
||||
else
|
||||
{
|
||||
result.markup = ['scroll-view', {keyboardShouldPersistTaps: "always"},
|
||||
['view', {},
|
||||
['current-location-map'],
|
||||
['current-location'],
|
||||
['separator'],
|
||||
['places-nearby']]];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
status.command({
|
||||
name: "location",
|
||||
icon: "location",
|
||||
title: I18n.t('location_title'),
|
||||
description: I18n.t('location_description'),
|
||||
color: "#a187d5",
|
||||
sequentialParams: true,
|
||||
registeredOnly: true,
|
||||
hideSendButton: true,
|
||||
params: [{
|
||||
name: "address",
|
||||
type: status.types.TEXT,
|
||||
placeholder: I18n.t('location_address')
|
||||
placeholder: I18n.t('location_address'),
|
||||
suggestions: locationsSuggestions
|
||||
}],
|
||||
preview: function (params) {
|
||||
var address = params.address.split("&");
|
||||
var text = status.components.text(
|
||||
{
|
||||
style: {
|
||||
marginTop: 5,
|
||||
marginTop: 0,
|
||||
marginHorizontal: 0,
|
||||
fontSize: 14,
|
||||
fontSize: 15,
|
||||
lineHeight: 23,
|
||||
fontFamily: "font",
|
||||
color: "black"
|
||||
}
|
||||
}, params.address);
|
||||
var uri = "https://maps.googleapis.com/maps/api/staticmap?center="
|
||||
+ params.address
|
||||
+ "&size=100x100&maptype=roadmap&key=AIzaSyBNsj1qoQEYPb3IllmWMAscuXW0eeuYqAA&language=en"
|
||||
+ "&markers=size:mid%7Ccolor:0xff0000%7Clabel:%7C"
|
||||
+ params.address;
|
||||
}, address[0]);
|
||||
var uri = "https://api.mapbox.com/styles/v1/mapbox/streets-v10/static/" +
|
||||
address[1] + "," + address[2] + ",10,20" +
|
||||
"/175x58?access_token=pk.eyJ1Ijoic3RhdHVzaW0iLCJhIjoiY2oydmtnZjRrMDA3czMzcW9kemR4N2lxayJ9.Rz8L6xdHBjfO8cR3CDf3Cw";
|
||||
|
||||
var image = status.components.image(
|
||||
{
|
||||
source: {uri: uri},
|
||||
style: {
|
||||
width: 100,
|
||||
height: 100
|
||||
borderRadius: 5
|
||||
marginTop: 12
|
||||
height: 58
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return {markup: status.components.view({}, [text, image])};
|
||||
return {markup: ['view', {},
|
||||
text,
|
||||
['view', {},
|
||||
image,
|
||||
['view', {style: {position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
justifyContent: "center",
|
||||
alignItems: "center"}},
|
||||
['view', {style: {borderColor: "#628fe3",
|
||||
backgroundColor: "#FFFFFF",
|
||||
borderWidth: 4,
|
||||
borderRadius: 8,
|
||||
height: 15,
|
||||
width: 15}}]]]]};
|
||||
},
|
||||
shortPreview: function (params) {
|
||||
return {
|
||||
@ -48,4 +95,4 @@ status.command({
|
||||
)
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
@ -1,8 +1,9 @@
|
||||
I18n.translations = {
|
||||
en: {
|
||||
location_title: 'Location',
|
||||
location_suggestions_title: 'Send location',
|
||||
location_description: 'Share your location',
|
||||
location_address: 'Address'
|
||||
location_address: 'address'
|
||||
},
|
||||
ru: {
|
||||
location_title: 'Местоположение',
|
||||
|
1
ios/Mapbox.framework
Symbolic link
1
ios/Mapbox.framework
Symbolic link
@ -0,0 +1 @@
|
||||
../node_modules/react-native-mapbox-gl/ios/Mapbox.framework
|
@ -7,24 +7,24 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
|
||||
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
|
||||
00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
|
||||
00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
|
||||
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
|
||||
00C302E51ABCBA2D00DB3ED1 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
|
||||
00C302E71ABCBA2D00DB3ED1 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
|
||||
00C302E81ABCBA2D00DB3ED1 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
|
||||
00C302E91ABCBA2D00DB3ED1 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
|
||||
00C302EA1ABCBA2D00DB3ED1 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
|
||||
00E356F31AD99517003FC87E /* StatusImTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* StatusImTests.m */; };
|
||||
0F942CF509F74CCDB5CB35B0 /* MaterialIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 54E2B86FB12D4CC49DA05C69 /* MaterialIcons.ttf */; };
|
||||
133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
|
||||
139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
|
||||
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
|
||||
133E29F31AD74F7200F7D852 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
|
||||
139105C61AF99C1200B5F7CC /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
|
||||
139FDEF61B0652A700C62182 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
|
||||
146834051AC3E58100842450 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
|
||||
2028DFF91D4275B600227DCD /* SF-UI-Display-Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = 2028DFF51D4275B600227DCD /* SF-UI-Display-Medium.otf */; };
|
||||
2028DFFA1D4275B600227DCD /* SF-UI-Display-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 2028DFF61D4275B600227DCD /* SF-UI-Display-Regular.otf */; };
|
||||
2028DFFB1D4275B600227DCD /* SF-UI-Display-Semibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 2028DFF71D4275B600227DCD /* SF-UI-Display-Semibold.otf */; };
|
||||
2028DFFC1D4275B600227DCD /* SF-UI-Display-Thin.otf in Resources */ = {isa = PBXBuildFile; fileRef = 2028DFF81D4275B600227DCD /* SF-UI-Display-Thin.otf */; };
|
||||
20AB9EC61D47CC0300E7FD9C /* libRCTStatus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 201067C41D4789F700FA83B6 /* libRCTStatus.a */; };
|
||||
20AB9EC61D47CC0300E7FD9C /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 201067C41D4789F700FA83B6 /* libRCTStatus.a */; };
|
||||
20B6B6841D92C42600CC5C6A /* RSKImageCropper.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20B6B6831D92C42600CC5C6A /* RSKImageCropper.framework */; };
|
||||
20B6B6851D92C42600CC5C6A /* RSKImageCropper.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 20B6B6831D92C42600CC5C6A /* RSKImageCropper.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
20B6B6871D92C42600CC5C6A /* QBImagePicker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20B6B6861D92C42600CC5C6A /* QBImagePicker.framework */; };
|
||||
@ -41,24 +41,27 @@
|
||||
74242ACAF37A48D0BFACDE82 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2756305FAFF144C4A6B0A039 /* Zocial.ttf */; };
|
||||
81C6E6AE0AA739BE9D87C1D0 /* libPods-StatusImTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FC1CBCFE6C906043D6CCEEE1 /* libPods-StatusImTests.a */; };
|
||||
82E689BAF9FB43C8AC6FF1CA /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = CEB0E2659D1A4F5FA842057A /* EvilIcons.ttf */; };
|
||||
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
|
||||
832341BD1AAA6AB300B99B32 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
|
||||
8E55E6877F950B81C8D711C5 /* libPods-StatusIm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 101A4045637A2ADF57D28EF5 /* libPods-StatusIm.a */; };
|
||||
9E0B01A11DDC5DA7002B0359 /* SF-UI-Text-Light.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9E0B01A01DDC5DA7002B0359 /* SF-UI-Text-Light.otf */; };
|
||||
9E3AB6D01D87DB2B008846B4 /* libReact-Native-Webview-Bridge.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E3AB6C61D87DA2B008846B4 /* libReact-Native-Webview-Bridge.a */; };
|
||||
9E7C64731E03FDDE004C7042 /* libRCTCamera.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20B7D1151D3F74CD00B70F14 /* libRCTCamera.a */; };
|
||||
9E7C64991E03FDE5004C7042 /* libRCTContacts.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20B7D10A1D3F74CD00B70F14 /* libRCTContacts.a */; };
|
||||
9E3AB6D01D87DB2B008846B4 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E3AB6C61D87DA2B008846B4 /* libReact-Native-Webview-Bridge.a */; };
|
||||
9E7C64731E03FDDE004C7042 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 20B7D1151D3F74CD00B70F14 /* libRCTCamera.a */; };
|
||||
9E7C64991E03FDE5004C7042 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 20B7D10A1D3F74CD00B70F14 /* libRCTContacts.a */; };
|
||||
9ED2F45E1D9D535A00B36508 /* SF-UI-Text-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9ED2F45D1D9D52DD00B36508 /* SF-UI-Text-Regular.otf */; };
|
||||
9ED2F45F1D9D535A00B36508 /* SF-UI-Text-Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9ED2F45C1D9D52C100B36508 /* SF-UI-Text-Medium.otf */; };
|
||||
9ED2F4611D9D579900B36508 /* SF-UI-Text-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9ED2F4601D9D577B00B36508 /* SF-UI-Text-Bold.otf */; };
|
||||
9EE89E271E03FCB7007D3C25 /* libSplashScreen.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B24FC7F21DE718EF00D694FF /* libSplashScreen.a */; };
|
||||
9EE89E2D1E03FD9F007D3C25 /* libimageCropPicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20A5C9531D927137002C4965 /* libimageCropPicker.a */; };
|
||||
9EE470511ED0079E0048FD10 /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE470501ED0079E0048FD10 /* Mapbox.framework */; };
|
||||
9EE470521ED0079E0048FD10 /* Mapbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE470501ED0079E0048FD10 /* Mapbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
9EE470541ED007E10048FD10 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE4702F1ED0071A0048FD10 /* libRCTMapboxGL.a */; };
|
||||
9EE89E271E03FCB7007D3C25 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = B24FC7F21DE718EF00D694FF /* libSplashScreen.a */; };
|
||||
9EE89E2D1E03FD9F007D3C25 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 20A5C9531D927137002C4965 /* libimageCropPicker.a */; };
|
||||
A6AF670051B842249D520C7B /* Foundation.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7ED174A34D7D42358313368B /* Foundation.ttf */; };
|
||||
AE97D4B08C9F4821B8E9C50B /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 359B076A658B4FBAB5128B03 /* Ionicons.ttf */; };
|
||||
B23B48FF1E76917B006D4535 /* RobotoMono-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B23B48FE1E76917B006D4535 /* RobotoMono-Medium.ttf */; };
|
||||
B24FC7FD1DE7195700D694FF /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B24FC7FC1DE7195700D694FF /* Social.framework */; };
|
||||
B24FC7FF1DE7195F00D694FF /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B24FC7FE1DE7195F00D694FF /* MessageUI.framework */; };
|
||||
B2A5F45C1DEC36BB00174F4D /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B2A5F4381DEC36B200174F4D /* libRCTAnimation.a */; };
|
||||
B2DEA0D01E49E33300FA28D6 /* libRCTHttpServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B2DEA0B11E49E32000FA28D6 /* libRCTHttpServer.a */; };
|
||||
B2A5F45C1DEC36BB00174F4D /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = B2A5F4381DEC36B200174F4D /* libRCTAnimation.a */; };
|
||||
B2DEA0D01E49E33300FA28D6 /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = B2DEA0B11E49E32000FA28D6 /* libRCTHttpServer.a */; };
|
||||
B2F2D1BC1D9D531B00B7B453 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B2F2D1BB1D9D531B00B7B453 /* Images.xcassets */; };
|
||||
BA68A2377A20496EA737000D /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E586E1B0E544F64AA9F5BD1 /* libz.tbd */; };
|
||||
C3EE9AEA6F77464588FBAA64 /* FontAwesome.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7B5870D9ED504F32B6A09C35 /* FontAwesome.ttf */; };
|
||||
@ -309,6 +312,20 @@
|
||||
remoteGlobalIDString = 0974579A1D2A440A000D9368;
|
||||
remoteInfo = RCTWKWebView;
|
||||
};
|
||||
9EE4702E1ED0071A0048FD10 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 9EE4701B1ED007190048FD10 /* RCTMapboxGL.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = C5DBB3401AF2EF2B00E611A9;
|
||||
remoteInfo = RCTMapboxGL;
|
||||
};
|
||||
9EE470301ED0071A0048FD10 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 9EE4701B1ED007190048FD10 /* RCTMapboxGL.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = C5DBB34B1AF2EF2B00E611A9;
|
||||
remoteInfo = RCTMapboxGLTests;
|
||||
};
|
||||
B24FC7F11DE718EF00D694FF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 3A7EB0491DD9CABC00A4FCC8 /* SplashScreen.xcodeproj */;
|
||||
@ -397,6 +414,7 @@
|
||||
files = (
|
||||
20B6B6851D92C42600CC5C6A /* RSKImageCropper.framework in Embed Frameworks */,
|
||||
20B6B6881D92C42600CC5C6A /* QBImagePicker.framework in Embed Frameworks */,
|
||||
9EE470521ED0079E0048FD10 /* Mapbox.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -467,6 +485,8 @@
|
||||
9ED2F45C1D9D52C100B36508 /* SF-UI-Text-Medium.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-UI-Text-Medium.otf"; sourceTree = "<group>"; };
|
||||
9ED2F45D1D9D52DD00B36508 /* SF-UI-Text-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-UI-Text-Regular.otf"; sourceTree = "<group>"; };
|
||||
9ED2F4601D9D577B00B36508 /* SF-UI-Text-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-UI-Text-Bold.otf"; sourceTree = "<group>"; };
|
||||
9EE4701B1ED007190048FD10 /* RCTMapboxGL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTMapboxGL.xcodeproj; path = "../node_modules/react-native-mapbox-gl/ios/RCTMapboxGL.xcodeproj"; sourceTree = "<group>"; };
|
||||
9EE470501ED0079E0048FD10 /* Mapbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Mapbox.framework; sourceTree = "<group>"; };
|
||||
9F1854E6D9654226B1FC8308 /* RCTCamera.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTCamera.xcodeproj; path = "../node_modules/react-native-camera/ios/RCTCamera.xcodeproj"; sourceTree = "<group>"; };
|
||||
ACA66A8F16CD2FE21F38738B /* Pods-StatusIm.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-StatusIm.debug.xcconfig"; path = "Pods/Target Support Files/Pods-StatusIm/Pods-StatusIm.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B23B48FE1E76917B006D4535 /* RobotoMono-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "RobotoMono-Medium.ttf"; sourceTree = "<group>"; };
|
||||
@ -501,29 +521,29 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B2DEA0D01E49E33300FA28D6 /* libRCTHttpServer.a in Frameworks */,
|
||||
9EE89E271E03FCB7007D3C25 /* libSplashScreen.a in Frameworks */,
|
||||
B2A5F45C1DEC36BB00174F4D /* libRCTAnimation.a in Frameworks */,
|
||||
B2DEA0D01E49E33300FA28D6 /* ReferenceProxy in Frameworks */,
|
||||
9EE89E271E03FCB7007D3C25 /* ReferenceProxy in Frameworks */,
|
||||
B2A5F45C1DEC36BB00174F4D /* ReferenceProxy in Frameworks */,
|
||||
B24FC7FF1DE7195F00D694FF /* MessageUI.framework in Frameworks */,
|
||||
B24FC7FD1DE7195700D694FF /* Social.framework in Frameworks */,
|
||||
9EE89E2D1E03FD9F007D3C25 /* libimageCropPicker.a in Frameworks */,
|
||||
9E3AB6D01D87DB2B008846B4 /* libReact-Native-Webview-Bridge.a in Frameworks */,
|
||||
9EE89E2D1E03FD9F007D3C25 /* ReferenceProxy in Frameworks */,
|
||||
9E3AB6D01D87DB2B008846B4 /* ReferenceProxy in Frameworks */,
|
||||
20B6B6841D92C42600CC5C6A /* RSKImageCropper.framework in Frameworks */,
|
||||
CE4E31B31D8695250033ED64 /* Statusgo.framework in Frameworks */,
|
||||
20AB9EC61D47CC0300E7FD9C /* libRCTStatus.a in Frameworks */,
|
||||
20AB9EC61D47CC0300E7FD9C /* ReferenceProxy in Frameworks */,
|
||||
20B6B6871D92C42600CC5C6A /* QBImagePicker.framework in Frameworks */,
|
||||
146834051AC3E58100842450 /* libReact.a in Frameworks */,
|
||||
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
|
||||
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
|
||||
00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,
|
||||
133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */,
|
||||
00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */,
|
||||
139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */,
|
||||
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
|
||||
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
|
||||
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
|
||||
9E7C64731E03FDDE004C7042 /* libRCTCamera.a in Frameworks */,
|
||||
9E7C64991E03FDE5004C7042 /* libRCTContacts.a in Frameworks */,
|
||||
146834051AC3E58100842450 /* ReferenceProxy in Frameworks */,
|
||||
00C302E51ABCBA2D00DB3ED1 /* ReferenceProxy in Frameworks */,
|
||||
00C302E71ABCBA2D00DB3ED1 /* ReferenceProxy in Frameworks */,
|
||||
00C302E81ABCBA2D00DB3ED1 /* ReferenceProxy in Frameworks */,
|
||||
133E29F31AD74F7200F7D852 /* ReferenceProxy in Frameworks */,
|
||||
00C302E91ABCBA2D00DB3ED1 /* ReferenceProxy in Frameworks */,
|
||||
139105C61AF99C1200B5F7CC /* ReferenceProxy in Frameworks */,
|
||||
832341BD1AAA6AB300B99B32 /* ReferenceProxy in Frameworks */,
|
||||
00C302EA1ABCBA2D00DB3ED1 /* ReferenceProxy in Frameworks */,
|
||||
139FDEF61B0652A700C62182 /* ReferenceProxy in Frameworks */,
|
||||
9E7C64731E03FDDE004C7042 /* ReferenceProxy in Frameworks */,
|
||||
9E7C64991E03FDE5004C7042 /* ReferenceProxy in Frameworks */,
|
||||
FD4F213C3873473CB703B1D2 /* libRNFS.a in Frameworks */,
|
||||
213311F38CA74CE280FD09AD /* libRNI18n.a in Frameworks */,
|
||||
4D3D740D5EFA4F8592B048D7 /* libBVLinearGradient.a in Frameworks */,
|
||||
@ -537,6 +557,9 @@
|
||||
E0AD9E8F495A4907B65104BF /* libRCTImageResizer.a in Frameworks */,
|
||||
5F8585D411844E5981B94F40 /* libRNInstabug.a in Frameworks */,
|
||||
8E55E6877F950B81C8D711C5 /* libPods-StatusIm.a in Frameworks */,
|
||||
EC8998BFE2C04023A860C065 /* libRNNetworkInfo.a in Frameworks */,
|
||||
9EE470511ED0079E0048FD10 /* Mapbox.framework in Frameworks */,
|
||||
9EE470541ED007E10048FD10 /* ReferenceProxy in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -846,6 +869,8 @@
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9EE470501ED0079E0048FD10 /* Mapbox.framework */,
|
||||
9EE4701B1ED007190048FD10 /* RCTMapboxGL.xcodeproj */,
|
||||
20B6B6861D92C42600CC5C6A /* QBImagePicker.framework */,
|
||||
20B6B6831D92C42600CC5C6A /* RSKImageCropper.framework */,
|
||||
13B07FAE1A68108700A75B9A /* StatusIm */,
|
||||
@ -893,6 +918,15 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EE4701C1ED007190048FD10 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9EE4702F1ED0071A0048FD10 /* libRCTMapboxGL.a */,
|
||||
9EE470311ED0071A0048FD10 /* RCTMapboxGLTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A97BA941B2FB44B4B66EE6D3 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -979,6 +1013,7 @@
|
||||
9E71BA90038083A3D24E18E9 /* [CP] Embed Pods Frameworks */,
|
||||
E883D1F9B22B8292CC879292 /* [CP] Copy Pods Resources */,
|
||||
E3914A731DF919ED00EBB515 /* Run Script */,
|
||||
9EE470531ED007A80048FD10 /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -1065,6 +1100,10 @@
|
||||
ProductGroup = 78C398B11ACF4ADC00677621 /* Products */;
|
||||
ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 9EE4701C1ED007190048FD10 /* Products */;
|
||||
ProjectRef = 9EE4701B1ED007190048FD10 /* RCTMapboxGL.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */;
|
||||
ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
|
||||
@ -1378,6 +1417,20 @@
|
||||
remoteRef = 9EC013781E06FB1900155B5C /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
9EE4702F1ED0071A0048FD10 /* libRCTMapboxGL.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRCTMapboxGL.a;
|
||||
remoteRef = 9EE4702E1ED0071A0048FD10 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
9EE470311ED0071A0048FD10 /* RCTMapboxGLTests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = RCTMapboxGLTests.xctest;
|
||||
remoteRef = 9EE470301ED0071A0048FD10 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
B24FC7F21DE718EF00D694FF /* libSplashScreen.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
@ -1583,6 +1636,19 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-StatusIm/Pods-StatusIm-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9EE470531ED007A80048FD10 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mapbox.framework/strip-frameworks.sh\"";
|
||||
};
|
||||
E3914A731DF919ED00EBB515 /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -1736,6 +1802,7 @@
|
||||
"$(PROJECT_DIR)/../modules/react-native-status/ios/RCTStatus",
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Pods/**",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -1784,6 +1851,7 @@
|
||||
"$(PROJECT_DIR)/../modules/react-native-status/ios/RCTStatus",
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Pods/**",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -64,6 +64,7 @@
|
||||
"react-native-invertible-scroll-view": "^1.0.0",
|
||||
"react-native-level-fs": "^2.0.1",
|
||||
"react-native-linear-gradient": "2.0.0",
|
||||
"react-native-mapbox-gl": "github:mapbox/react-native-mapbox-gl#master",
|
||||
"react-native-orientation": "github:youennPennarun/react-native-orientation",
|
||||
"react-native-popup-menu": "^0.7.1",
|
||||
"react-native-qrcode": "^0.2.2",
|
||||
|
@ -5,10 +5,11 @@
|
||||
./node_modules/.bin/rn-nodeify --install "assert,zlib,buffer,inherits,console,constants,crypto,dns,domain,events,http,https,os,path,process,punycode,querystring,fs,stream,string_decoder,timers,tty,url,util,net,vm" --hack;
|
||||
npm install --save react@16.0.0-alpha.6;
|
||||
npm install --save react-native-tcp@3.2.1;
|
||||
ln -s ../node_modules/react-native-mapbox-gl/ios/Mapbox.framework ios;
|
||||
|
||||
# symlink for re-natal
|
||||
if ! [ -f re-natal ]; then
|
||||
ln -s ./node_modules/re-natal/index.js re-natal;
|
||||
else
|
||||
echo "re-natal exists"
|
||||
fi
|
||||
fi
|
||||
|
@ -40,6 +40,7 @@ Command.prototype.create = function (com) {
|
||||
this.request = com.request;
|
||||
this["execute-immediately?"] = com.executeImmediately;
|
||||
this["sequential-params"] = com.sequentialParams;
|
||||
this["hide-send-button"] = com.hideSendButton;
|
||||
this.addToCatalog();
|
||||
|
||||
return this;
|
||||
@ -186,6 +187,30 @@ function chooseContact(titleText, botDbKey, argumentIndex) {
|
||||
}];
|
||||
}
|
||||
|
||||
function droppedPin() {
|
||||
return ['dropped-pin'];
|
||||
}
|
||||
|
||||
function placesSearch() {
|
||||
return ['places-search'];
|
||||
}
|
||||
|
||||
function currentLocationMap() {
|
||||
return ['current-location-map'];
|
||||
}
|
||||
|
||||
function currentLocation() {
|
||||
return ['current-location'];
|
||||
}
|
||||
|
||||
function placesNearby() {
|
||||
return ['places-nearby'];
|
||||
}
|
||||
|
||||
function separator() {
|
||||
return ['separator'];
|
||||
}
|
||||
|
||||
var status = {
|
||||
command: function (h) {
|
||||
var command = new Command();
|
||||
@ -245,7 +270,13 @@ var status = {
|
||||
bridgedWebView: bridgedWebView,
|
||||
chooseContact: chooseContact,
|
||||
subscribe: subscribe,
|
||||
dispatch: dispatch
|
||||
dispatch: dispatch,
|
||||
droppedPin: droppedPin,
|
||||
placesSearch: placesSearch,
|
||||
currentLocationMap: currentLocationMap,
|
||||
currentLocation: currentLocation,
|
||||
placesNearby: placesNearby,
|
||||
separator: separator
|
||||
},
|
||||
showSuggestions: function (view) {
|
||||
statusSignals.showSuggestions(JSON.stringify(view));
|
||||
|
@ -26,13 +26,13 @@
|
||||
|
||||
;; TODO(alwx): need to understand the need in this
|
||||
#_(if-let [{command :command} (input-model/selected-chat-command db chat-id text)]
|
||||
(let [{old-args :args} (input-model/selected-chat-command db chat-id)
|
||||
text-splitted (input-model/split-command-args text)
|
||||
new-input-text (input-model/make-input-text text-splitted old-args)]
|
||||
(assoc-in db [:chats chat-id :input-text] new-input-text))
|
||||
(->> text
|
||||
(input-model/text->emoji)
|
||||
(assoc-in db [:chats chat-id :input-text]))))))
|
||||
(let [{old-args :args} (input-model/selected-chat-command db chat-id)
|
||||
text-splitted (input-model/split-command-args text)
|
||||
new-input-text (input-model/make-input-text text-splitted old-args)]
|
||||
(assoc-in db [:chats chat-id :input-text] new-input-text))
|
||||
(->> text
|
||||
(input-model/text->emoji)
|
||||
(assoc-in db [:chats chat-id :input-text]))))))
|
||||
|
||||
(handlers/register-handler
|
||||
:add-to-chat-input-text
|
||||
@ -108,6 +108,16 @@
|
||||
(catch :default e
|
||||
(log/debug "Cannot focus the reference"))))))
|
||||
|
||||
(handlers/register-handler
|
||||
:chat-input-blur
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-chat-id chat-ui-props] :as db} [_ ref]]
|
||||
(try
|
||||
(when-let [ref (get-in chat-ui-props [current-chat-id ref])]
|
||||
(.blur ref))
|
||||
(catch :default e
|
||||
(log/debug "Cannot blur the reference"))))))
|
||||
|
||||
(handlers/register-handler
|
||||
:update-suggestions
|
||||
(fn [{:keys [current-chat-id] :as db} [_ chat-id text]]
|
||||
@ -146,9 +156,11 @@
|
||||
args (-> (get-in db [:chats current-chat-id :input-text])
|
||||
(input-model/split-command-args)
|
||||
(rest))
|
||||
seq-arg (get-in db [:chats current-chat-id :seq-argument-input-text])
|
||||
to (get-in db [:contacts current-chat-id :address])
|
||||
params {:parameters {:args args
|
||||
:bot-db bot-db}
|
||||
params {:parameters {:args args
|
||||
:bot-db bot-db
|
||||
:seq-arg seq-arg}
|
||||
:context (merge {:data data
|
||||
:from current-account-id
|
||||
:to to}
|
||||
@ -382,16 +394,23 @@
|
||||
:select-prev-argument
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [chat-ui-props current-chat-id] :as db} _]
|
||||
(let [arg-pos (input-model/argument-position db current-chat-id)]
|
||||
(when (pos? arg-pos)
|
||||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
new-sel (->> (input-model/split-command-args input-text)
|
||||
(take (inc arg-pos))
|
||||
(input-model/join-command-args)
|
||||
(count))
|
||||
ref (get-in chat-ui-props [current-chat-id :input-ref])]
|
||||
(.setNativeProps ref (clj->js {:selection {:start new-sel :end new-sel}}))
|
||||
(dispatch [:update-text-selection new-sel])))))))
|
||||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
command (input-model/selected-chat-command db current-chat-id input-text)]
|
||||
(if (get-in command [:command :sequential-params])
|
||||
(do
|
||||
(dispatch [:set-command-argument [0 "" false]])
|
||||
(dispatch [:set-chat-seq-arg-input-text ""])
|
||||
(dispatch [:load-chat-parameter-box (:command command)]))
|
||||
(let [arg-pos (input-model/argument-position db current-chat-id)]
|
||||
(when (pos? arg-pos)
|
||||
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||
new-sel (->> (input-model/split-command-args input-text)
|
||||
(take (inc arg-pos))
|
||||
(input-model/join-command-args)
|
||||
(count))
|
||||
ref (get-in chat-ui-props [current-chat-id :input-ref])]
|
||||
(.setNativeProps ref (clj->js {:selection {:start new-sel :end new-sel}}))
|
||||
(dispatch [:update-text-selection new-sel])))))))))
|
||||
|
||||
(handlers/register-handler
|
||||
:select-next-argument
|
||||
|
91
src/status_im/chat/views/geolocation/styles.cljs
Normal file
91
src/status_im/chat/views/geolocation/styles.cljs
Normal file
@ -0,0 +1,91 @@
|
||||
(ns status-im.chat.views.geolocation.styles
|
||||
(:require [status-im.components.styles :as common]))
|
||||
|
||||
(defn place-item-container [address]
|
||||
{:height (if address 74 52)
|
||||
:justify-content :center})
|
||||
|
||||
(def place-item-title-container
|
||||
{:flex-direction :row
|
||||
:align-items :center})
|
||||
|
||||
(defn place-item-circle-icon [pin-style]
|
||||
(merge {:border-color common/color-light-blue
|
||||
:border-width 3
|
||||
:border-radius 7
|
||||
:height 13
|
||||
:width 13}
|
||||
pin-style))
|
||||
|
||||
(def black-pin
|
||||
{:border-color common/color-black})
|
||||
|
||||
(def place-item-title
|
||||
{:font-size 15
|
||||
:padding-left 9
|
||||
:padding-right 16
|
||||
:color common/color-black
|
||||
:line-height 23})
|
||||
|
||||
(def place-item-address
|
||||
{:font-size 15
|
||||
:padding-left 22
|
||||
:padding-right 16
|
||||
:color common/color-black
|
||||
:line-height 23})
|
||||
|
||||
(def map-activity-indicator-container
|
||||
{:align-items :center
|
||||
:justify-content :center
|
||||
:height 100})
|
||||
|
||||
(def map-view
|
||||
{:height 100})
|
||||
|
||||
(def location-container
|
||||
{:margin-top 11
|
||||
:margin-horizontal 16})
|
||||
|
||||
(def location-container-title
|
||||
{:font-size 14
|
||||
:color common/color-gray4
|
||||
:letter-spacing -0.2})
|
||||
|
||||
(def location-container-title-count
|
||||
(merge location-container-title
|
||||
{:opacity 0.5}))
|
||||
|
||||
(def separator
|
||||
{:height 1
|
||||
:opacity 0.5
|
||||
:background-color "#c1c7cbb7"})
|
||||
|
||||
(def item-separator
|
||||
(merge separator
|
||||
{:margin-left 22}))
|
||||
|
||||
(def pin-container
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:pointer-events :none})
|
||||
|
||||
(def pin-component
|
||||
{:align-items :center})
|
||||
|
||||
(def pin-circle
|
||||
{:border-color common/color-black
|
||||
:background-color common/color-white
|
||||
:border-width 3
|
||||
:border-radius 7
|
||||
:height 13
|
||||
:width 13})
|
||||
|
||||
(def pin-leg
|
||||
{:height 7
|
||||
:width 2
|
||||
:background-color common/color-black})
|
173
src/status_im/chat/views/geolocation/views.cljs
Normal file
173
src/status_im/chat/views/geolocation/views.cljs
Normal file
@ -0,0 +1,173 @@
|
||||
(ns status-im.chat.views.geolocation.views
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]]
|
||||
[reagent.ratom :refer [reaction]])
|
||||
(:require [status-im.components.react :refer [view image text touchable-highlight]]
|
||||
[reagent.core :as r]
|
||||
[goog.string :as gstr]
|
||||
[status-im.utils.utils :refer [http-get]]
|
||||
[status-im.utils.types :refer [json->clj]]
|
||||
[status-im.chat.views.geolocation.styles :as st]
|
||||
[status-im.components.mapbox :refer [mapview]]
|
||||
[re-frame.core :refer [dispatch subscribe]]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.components.react :as components]))
|
||||
|
||||
(def mapbox-api "https://api.mapbox.com/geocoding/v5/mapbox.places/")
|
||||
(def access-token "pk.eyJ1Ijoic3RhdHVzaW0iLCJhIjoiY2oydmtnZjRrMDA3czMzcW9kemR4N2lxayJ9.Rz8L6xdHBjfO8cR3CDf3Cw")
|
||||
|
||||
(defn get-places [coords cur-loc-geocoded & [poi?]]
|
||||
(let [{:keys [latitude longitude]} coords]
|
||||
(when (and latitude longitude)
|
||||
(http-get (str mapbox-api longitude "," latitude
|
||||
".json?" (when poi? "types=poi&") "access_token=" access-token)
|
||||
#(reset! cur-loc-geocoded (json->clj %))
|
||||
#(reset! cur-loc-geocoded nil))
|
||||
true)))
|
||||
|
||||
(defn place-item [{:keys [title address pin-style] [latitude longitude] :center}]
|
||||
[touchable-highlight {:on-press #(do
|
||||
(dispatch [:set-command-argument [0
|
||||
(str (or address title)
|
||||
"&" latitude
|
||||
"&" longitude)
|
||||
false]])
|
||||
(dispatch [:send-seq-argument]))}
|
||||
[view (st/place-item-container address)
|
||||
[view st/place-item-title-container
|
||||
[view (st/place-item-circle-icon pin-style)]
|
||||
[text {:style st/place-item-title
|
||||
:number-of-lines 1
|
||||
:font :medium}
|
||||
title]]
|
||||
(when address
|
||||
[text {:style st/place-item-address
|
||||
:number-of-lines 1}
|
||||
address])]])
|
||||
|
||||
(defview current-location-map-view []
|
||||
(letsubs [geolocation [:get :geolocation]
|
||||
command [:selected-chat-command]]
|
||||
{:component-will-mount #(dispatch [:request-geolocation-update])
|
||||
:component-did-mount (fn [_] (js/setTimeout #(dispatch [:chat-input-focus :seq-input-ref]) 400))}
|
||||
(let [coord (select-keys (:coords geolocation) [:latitude :longitude])]
|
||||
[view
|
||||
(if (not (empty? coord))
|
||||
[view
|
||||
[mapview {:onTap #(do
|
||||
(dispatch [:set-command-argument [0 "Dropped pin" false]])
|
||||
(dispatch [:set-chat-seq-arg-input-text "Dropped pin"])
|
||||
(dispatch [:chat-input-blur :seq-input-ref])
|
||||
(dispatch [:load-chat-parameter-box (:command command)]))
|
||||
:initialCenterCoordinate coord
|
||||
:showsUserLocation true
|
||||
:initialZoomLevel 10
|
||||
:logoIsHidden true
|
||||
:rotateEnabled false
|
||||
:scrollEnabled false
|
||||
:zoomEnabled false
|
||||
:pitchEnabled false
|
||||
:style st/map-view}]]
|
||||
[view st/map-activity-indicator-container
|
||||
[components/activity-indicator {:animating true}]])])))
|
||||
|
||||
(defn current-location-view []
|
||||
(let [geolocation (subscribe [:get :geolocation])
|
||||
cur-loc-geocoded (r/atom nil)
|
||||
result (reaction (when @geolocation (get-places (:coords @geolocation) cur-loc-geocoded)))]
|
||||
(r/create-class
|
||||
{:component-will-mount #(dispatch [:request-geolocation-update])
|
||||
:render
|
||||
(fn []
|
||||
(let [_ @result]
|
||||
(when (and @cur-loc-geocoded (> (count (:features @cur-loc-geocoded)) 0))
|
||||
[view st/location-container
|
||||
[text {:style st/location-container-title}
|
||||
(label :t/your-current-location)]
|
||||
(let [{:keys [place_name center] :as feature} (get-in @cur-loc-geocoded [:features 0])]
|
||||
[place-item {:title (:text feature) :address place_name :center center}])])))})))
|
||||
|
||||
(defn places-nearby-view []
|
||||
(let [geolocation (subscribe [:get :geolocation])
|
||||
cur-loc-geocoded (r/atom nil)
|
||||
result (reaction (when @geolocation (get-places (:coords @geolocation) cur-loc-geocoded true)))]
|
||||
(r/create-class
|
||||
{:component-will-mount #(dispatch [:request-geolocation-update])
|
||||
:render
|
||||
(fn []
|
||||
(let [_ @result]
|
||||
(when (and @cur-loc-geocoded (> (count (:features @cur-loc-geocoded)) 0))
|
||||
[view st/location-container
|
||||
[text {:style st/location-container-title}
|
||||
(label :t/places-nearby)]
|
||||
(doall
|
||||
(map (fn [{:keys [text place_name center] :as feature}]
|
||||
^{:key feature}
|
||||
[view
|
||||
[place-item {:title text :address place_name :center center}]
|
||||
(when (not= feature (last (:features @cur-loc-geocoded)))
|
||||
[view st/item-separator])])
|
||||
(:features @cur-loc-geocoded)))])))})))
|
||||
|
||||
(defn places-search []
|
||||
(let [seq-arg-input-text (subscribe [:chat :seq-argument-input-text])
|
||||
places (r/atom nil)
|
||||
result (reaction (http-get (str mapbox-api @seq-arg-input-text
|
||||
".json?access_token=" access-token)
|
||||
#(reset! places (json->clj %))
|
||||
#(reset! places nil)))]
|
||||
(fn []
|
||||
(let [_ @result]
|
||||
(when @places
|
||||
(let [features-count (count (:features @places))]
|
||||
[view st/location-container
|
||||
[text {:style st/location-container-title}
|
||||
(label :t/search-results) " " [text {:style st/location-container-title-count} features-count]]
|
||||
(doall
|
||||
(map (fn [{:keys [place_name center] :as feature}]
|
||||
^{:key feature}
|
||||
[view
|
||||
[place-item {:title place_name :center center}]
|
||||
(when (not= feature (last (:features @places)))
|
||||
[view st/item-separator])])
|
||||
(:features @places)))]))))))
|
||||
|
||||
(defn dropped-pin []
|
||||
(let [geolocation @(subscribe [:get :geolocation])
|
||||
pin-location (r/atom nil)
|
||||
pin-geolocation (r/atom nil)
|
||||
pin-nearby (r/atom nil)
|
||||
result (reaction (when @pin-location (get-places @pin-location pin-geolocation)))
|
||||
result2 (reaction (when @pin-location (get-places @pin-location pin-nearby true)))]
|
||||
(fn []
|
||||
(let [_ @result _ @result2]
|
||||
[view
|
||||
[view
|
||||
[mapview {:initial-center-coordinate (select-keys (:coords geolocation) [:latitude :longitude])
|
||||
:initialZoomLevel 10
|
||||
:onRegionDidChange #(reset! pin-location (js->clj % :keywordize-keys true))
|
||||
:logoIsHidden true
|
||||
:style {:height 265}}]
|
||||
[view st/pin-container
|
||||
[view st/pin-component
|
||||
[view st/pin-circle]
|
||||
[view st/pin-leg]]]]
|
||||
(when (and @pin-geolocation (> (count (:features @pin-geolocation)) 0))
|
||||
[view
|
||||
[view st/location-container
|
||||
[text {:style st/location-container-title}
|
||||
(label :t/dropped-pin)]
|
||||
(let [{:keys [place_name center] :as feature} (get-in @pin-geolocation [:features 0])]
|
||||
[place-item {:title place_name :pin-style st/black-pin :center center}])]
|
||||
[view st/separator]])
|
||||
(when (and @pin-nearby (> (count (:features @pin-nearby)) 0))
|
||||
[view st/location-container
|
||||
[text {:style st/location-container-title}
|
||||
(label :t/places-nearby)]
|
||||
(doall
|
||||
(map (fn [{:keys [text place_name center] :as feature}]
|
||||
^{:key feature}
|
||||
[view
|
||||
[place-item {:title text :address place_name :center center}]
|
||||
(when (not= feature (last (:features @pin-nearby)))
|
||||
[view st/item-separator])])
|
||||
(:features @pin-nearby)))])]))))
|
@ -167,13 +167,15 @@
|
||||
:style (style/seq-input-text command-width)
|
||||
:default-value (or @seq-arg-input-text "")
|
||||
:on-change-text #(do (dispatch [:set-chat-seq-arg-input-text %])
|
||||
(dispatch [:load-chat-parameter-box (:command @command)])
|
||||
(dispatch [:set-chat-ui-props {:validation-messages nil}]))
|
||||
:placeholder placeholder
|
||||
:blur-on-submit false
|
||||
:editable (not @sending-in-progress?)
|
||||
:on-focus #(dispatch [:set-chat-ui-props {:show-emoji? false}])
|
||||
:on-submit-editing (fn []
|
||||
(when-not (str/blank? @seq-arg-input-text)
|
||||
(when-not (or (str/blank? @seq-arg-input-text)
|
||||
(get-in @command [:command :hide-send-button]))
|
||||
(dispatch [:send-seq-argument]))
|
||||
(js/setTimeout
|
||||
#(dispatch [:chat-input-focus :seq-input-ref])
|
||||
@ -222,7 +224,8 @@
|
||||
input-text [:chat :input-text]
|
||||
seq-arg-input-text [:chat :seq-argument-input-text]
|
||||
result-box [:chat-ui-props :result-box]]
|
||||
(let [single-line-input? (:singleLineInput result-box)]
|
||||
(let [single-line-input? (:singleLineInput result-box)
|
||||
{:keys [hide-send-button sequential-params]} (:command selected-command)]
|
||||
[view style/input-container
|
||||
[input-view {:anim-margin anim-margin
|
||||
:single-line-input? single-line-input?}]
|
||||
@ -230,8 +233,9 @@
|
||||
[input-actions/input-actions-view]
|
||||
(when (and (not (str/blank? input-text))
|
||||
(or (not selected-command)
|
||||
(some #{:complete :less-than-needed} [command-completion])))
|
||||
[touchable-highlight {:on-press #(if (get-in selected-command [:command :sequential-params])
|
||||
(some #{:complete :less-than-needed} [command-completion]))
|
||||
(not hide-send-button))
|
||||
[touchable-highlight {:on-press #(if sequential-params
|
||||
(do
|
||||
(when-not (str/blank? seq-arg-input-text)
|
||||
(dispatch [:send-seq-argument]))
|
||||
|
@ -16,7 +16,7 @@
|
||||
dismiss-keyboard!]]
|
||||
[status-im.components.animation :as anim]
|
||||
[status-im.chat.constants :as chat-consts]
|
||||
[status-im.components.list-selection :refer [share browse]]
|
||||
[status-im.components.list-selection :refer [share browse share-or-open-map]]
|
||||
[status-im.chat.views.message.request-message :refer [message-content-command-request]]
|
||||
[status-im.chat.styles.message.message :as st]
|
||||
[status-im.chat.styles.message.command-pill :as pill-st]
|
||||
@ -139,11 +139,12 @@
|
||||
{:keys [name type]
|
||||
icon-path :icon} command]
|
||||
[view st/content-command-view
|
||||
[view st/command-container
|
||||
[view (pill-st/pill command)
|
||||
[text {:style pill-st/pill-text
|
||||
:font :default}
|
||||
(str (if (= :command type) chat-consts/command-char "?") name)]]]
|
||||
(when (:color command)
|
||||
[view st/command-container
|
||||
[view (pill-st/pill command)
|
||||
[text {:style pill-st/pill-text
|
||||
:font :default}
|
||||
(str (if (= :command type) chat-consts/command-char "?") name)]]])
|
||||
(when icon-path
|
||||
[view st/command-image-view
|
||||
[icon icon-path st/command-image]])
|
||||
@ -402,8 +403,12 @@
|
||||
(fn [{:keys [outgoing group-chat content-type content] :as message}]
|
||||
[message-container message
|
||||
[touchable-highlight {:on-press #(when platform/ios? (dismiss-keyboard!))
|
||||
:on-long-press (when (= content-type text-content-type)
|
||||
#(share content (label :t/message)))}
|
||||
:on-long-press #(cond (= content-type text-content-type)
|
||||
(share content (label :t/message))
|
||||
(and (= content-type content-type-command) (= "location" (:content-command content)))
|
||||
(let [params (str/split (get-in content [:params "address"]) #"&")
|
||||
latlong (rest params)]
|
||||
(share-or-open-map (first params) (first latlong) (second latlong))))}
|
||||
[view
|
||||
(let [incoming-group (and group-chat (not outgoing))]
|
||||
[message-content message-body (merge message
|
||||
|
@ -38,12 +38,12 @@
|
||||
|
||||
(defn suggestions-handler!
|
||||
[{:keys [contacts chats] :as db} [{:keys [chat-id default-db command parameter-index result]}]]
|
||||
(let [{:keys [markup] :as returned} (get-in result [:result :returned])
|
||||
(let [{:keys [markup height] :as returned} (get-in result [:result :returned])
|
||||
contains-markup? (contains? returned :markup)
|
||||
path (if command
|
||||
[:chats chat-id :parameter-boxes (:name command) parameter-index]
|
||||
[:chats chat-id :parameter-boxes :message])]
|
||||
(dispatch [:choose-predefined-expandable-height :parameter-box :default])
|
||||
(dispatch [:choose-predefined-expandable-height :parameter-box (or (keyword height) :default)])
|
||||
(when (and contains-markup? (not= (get-in db path) markup))
|
||||
(dispatch [:set-in path returned])
|
||||
(when default-db
|
||||
|
@ -140,16 +140,16 @@
|
||||
commands' (filter-commands account chat commands)
|
||||
responses' (filter-commands account chat responses)
|
||||
global-command (:global commands')
|
||||
commands'' (apply dissoc commands' [:init :global])
|
||||
commands'' (each-merge (apply dissoc commands' [:init :global])
|
||||
{:type :command
|
||||
:owner-id id})
|
||||
mailman-commands (get-mailmans-commands db)]
|
||||
(cond-> db
|
||||
|
||||
true
|
||||
(update-in [:contacts id] assoc
|
||||
:commands-loaded? true
|
||||
:commands (-> (merge mailman-commands commands'')
|
||||
(each-merge {:type :command
|
||||
:owner-id id}))
|
||||
:commands (merge mailman-commands commands'')
|
||||
:responses (each-merge responses' {:type :response
|
||||
:owner-id id})
|
||||
:subscriptions subscriptions)
|
||||
|
@ -1,12 +1,13 @@
|
||||
(ns status-im.commands.utils
|
||||
(:require [clojure.set :as set]
|
||||
[clojure.walk :as w]
|
||||
[re-frame.core :refer [dispatch trim-v debug]]
|
||||
[re-frame.core :refer [dispatch trim-v]]
|
||||
[status-im.components.react :as components]
|
||||
[status-im.chat.views.input.web-view :as chat-web-view]
|
||||
[status-im.chat.views.input.validation-messages :as chat-validation-messages]
|
||||
[status-im.chat.views.choosers.choose-contact :as choose-contact]
|
||||
[status-im.components.qr-code :as qr]
|
||||
[status-im.chat.views.geolocation.views :as geolocation]
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
@ -14,21 +15,30 @@
|
||||
(when-not (= json "undefined")
|
||||
(js->clj (.parse js/JSON json) :keywordize-keys true)))
|
||||
|
||||
(defn parameter-box-separator []
|
||||
[components/view {:height 1 :background-color "#c1c7cbb7" :opacity 0.5}])
|
||||
|
||||
(def elements
|
||||
{:view components/view
|
||||
:text components/text
|
||||
:text-input components/text-input
|
||||
:image components/image
|
||||
:qr-code qr/qr-code
|
||||
:linking components/linking
|
||||
:slider components/slider
|
||||
:scroll-view components/scroll-view
|
||||
:web-view components/web-view
|
||||
:touchable components/touchable-highlight
|
||||
:activity-indicator components/activity-indicator
|
||||
:bridged-web-view chat-web-view/bridged-web-view
|
||||
:validation-message chat-validation-messages/validation-message
|
||||
:choose-contact choose-contact/choose-contact-view})
|
||||
{:view components/view
|
||||
:text components/text
|
||||
:text-input components/text-input
|
||||
:image components/image
|
||||
:qr-code qr/qr-code
|
||||
:linking components/linking
|
||||
:slider components/slider
|
||||
:scroll-view components/scroll-view
|
||||
:web-view components/web-view
|
||||
:touchable components/touchable-highlight
|
||||
:activity-indicator components/activity-indicator
|
||||
:bridged-web-view chat-web-view/bridged-web-view
|
||||
:validation-message chat-validation-messages/validation-message
|
||||
:choose-contact choose-contact/choose-contact-view
|
||||
:separator parameter-box-separator
|
||||
:current-location-map geolocation/current-location-map-view
|
||||
:current-location geolocation/current-location-view
|
||||
:places-nearby geolocation/places-nearby-view
|
||||
:places-search geolocation/places-search
|
||||
:dropped-pin geolocation/dropped-pin})
|
||||
|
||||
(defn get-element [n]
|
||||
(elements (keyword (.toLowerCase n))))
|
||||
@ -40,7 +50,7 @@
|
||||
#(dispatch [:suggestions-event! (update event 0 keyword) %])))
|
||||
|
||||
(defn check-events [m]
|
||||
(let [ks (set (keys m))
|
||||
(let [ks (set (keys m))
|
||||
evs (set/intersection ks events)]
|
||||
(reduce #(update %1 %2 wrap-event) m evs)))
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
[status-im.components.react :refer [copy-to-clipboard
|
||||
sharing
|
||||
linking]]
|
||||
[status-im.utils.platform :refer [platform-specific]]
|
||||
[status-im.utils.platform :refer [platform-specific ios?]]
|
||||
[status-im.i18n :refer [label]]))
|
||||
|
||||
(defn open-share [content]
|
||||
@ -44,3 +44,18 @@
|
||||
:default))
|
||||
:cancel-text (label :t/browsing-cancel)})))
|
||||
|
||||
(defn share-or-open-map [address lat lng]
|
||||
(let [list-selection-fn (:list-selection-fn platform-specific)]
|
||||
(list-selection-fn {:title (label :t/location)
|
||||
:options [{:text (label :t/sharing-copy-to-clipboard-address)}
|
||||
{:text (label :t/sharing-copy-to-clipboard-coordinates)}
|
||||
{:text (label :t/open-map)}]
|
||||
:callback (fn [index]
|
||||
(case index
|
||||
0 (copy-to-clipboard address)
|
||||
1 (copy-to-clipboard (str lng "," lat))
|
||||
2 (.openURL linking (if ios?
|
||||
(str "http://maps.apple.com/?ll=" lng "," lat)
|
||||
(str "geo:" lng "," lat)))
|
||||
:default))
|
||||
:cancel-text (label :t/cancel)})))
|
||||
|
23
src/status_im/components/mapbox.cljs
Normal file
23
src/status_im/components/mapbox.cljs
Normal file
@ -0,0 +1,23 @@
|
||||
(ns status-im.components.mapbox
|
||||
(:require [reagent.core :as r]
|
||||
[status-im.components.styles :as common]
|
||||
[status-im.i18n :refer [label]]
|
||||
[status-im.utils.platform :refer [platform-specific ios?]]
|
||||
[re-frame.core :refer [dispatch]]
|
||||
[status-im.components.react :refer [view touchable-highlight text]]))
|
||||
|
||||
(def react-native-mapbox-gl (js/require "react-native-mapbox-gl"))
|
||||
|
||||
(defn get-property [name]
|
||||
(aget react-native-mapbox-gl name))
|
||||
|
||||
(defn adapt-class [class]
|
||||
(when class
|
||||
(r/adapt-react-class class)))
|
||||
|
||||
(defn get-class [name]
|
||||
(adapt-class (get-property name)))
|
||||
|
||||
(.setAccessToken react-native-mapbox-gl "pk.eyJ1Ijoic3RhdHVzaW0iLCJhIjoiY2oydmtnZjRrMDA3czMzcW9kemR4N2lxayJ9.Rz8L6xdHBjfO8cR3CDf3Cw")
|
||||
|
||||
(def mapview (get-class "MapView"))
|
@ -260,9 +260,9 @@
|
||||
:bot-url bot-url
|
||||
:global-command global-command
|
||||
:dapp-hash dapp-hash}]
|
||||
(dispatch [:add-contacts [contact]])
|
||||
(when bot-url
|
||||
(dispatch [:load-commands! id']))))))))))
|
||||
(dispatch [:add-contacts [contact]])))
|
||||
(when bot-url
|
||||
(dispatch [:load-commands! id']))))))))
|
||||
|
||||
|
||||
(register-handler :add-contacts
|
||||
|
@ -199,6 +199,32 @@
|
||||
then
|
||||
else))))
|
||||
|
||||
(register-handler :request-geolocation-update
|
||||
(u/side-effect!
|
||||
(fn [_ _]
|
||||
(dispatch [:request-permissions [:geolocation]
|
||||
(fn []
|
||||
(let [watch-id (atom nil)]
|
||||
(.getCurrentPosition
|
||||
navigator.geolocation
|
||||
#(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])
|
||||
#(dispatch [:update-geolocation (js->clj % :keywordize-keys true)])
|
||||
(clj->js {:enableHighAccuracy true :timeout 20000 :maximumAge 1000}))
|
||||
(when p/android?
|
||||
(reset! watch-id
|
||||
(.watchPosition
|
||||
navigator.geolocation
|
||||
#(do
|
||||
(.clearWatch
|
||||
navigator.geolocation
|
||||
@watch-id)
|
||||
(dispatch [:update-geolocation (js->clj % :keywordize-keys true)]))))
|
||||
(dispatch [:set-in [:debug :watch-id] @watch-id]))))]))))
|
||||
|
||||
(register-handler :update-geolocation
|
||||
(fn [db [_ geolocation]]
|
||||
(assoc db :geolocation geolocation)))
|
||||
|
||||
;; -- User data --------------------------------------------------------------
|
||||
(register-handler :load-user-phone-number
|
||||
(fn [db [_]]
|
||||
|
@ -211,6 +211,16 @@
|
||||
:chat-send-eth-to "{{amount}} ETH to {{chat-name}}"
|
||||
:chat-send-eth-from "{{amount}} ETH from {{chat-name}}"
|
||||
|
||||
;location command
|
||||
:your-current-location "Your current location"
|
||||
:places-nearby "Places nearby"
|
||||
:search-results "Search results"
|
||||
:dropped-pin "Dropped pin"
|
||||
:location "Location"
|
||||
:open-map "Open Map"
|
||||
:sharing-copy-to-clipboard-address "Copy the Address"
|
||||
:sharing-copy-to-clipboard-coordinates "Copy coordinates"
|
||||
|
||||
;new-group
|
||||
:group-chat-name "Chat name"
|
||||
:empty-group-chat-name "Please enter a name"
|
||||
|
@ -34,7 +34,7 @@
|
||||
[form `(deref ~sym)]))
|
||||
pairs))]))
|
||||
|
||||
(defmacro letsubs [args body])
|
||||
(defmacro letsubs [args & body])
|
||||
|
||||
(defmacro defview
|
||||
[n params & rest-body]
|
||||
|
Loading…
x
Reference in New Issue
Block a user