/send and /request commands; commands in group chats and fixes for parameter and result boxes
|
@ -180,6 +180,7 @@ dependencies {
|
||||||
compile project(':react-native-fs')
|
compile project(':react-native-fs')
|
||||||
compile project(':react-native-image-crop-picker')
|
compile project(':react-native-image-crop-picker')
|
||||||
compile project(':react-native-webview-bridge')
|
compile project(':react-native-webview-bridge')
|
||||||
|
compile 'testfairy:testfairy-android-sdk:1.+@aar'
|
||||||
|
|
||||||
compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"])
|
compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"])
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import com.facebook.react.ReactActivity;
|
import com.facebook.react.ReactActivity;
|
||||||
import com.cboy.rn.splashscreen.SplashScreen;
|
import com.cboy.rn.splashscreen.SplashScreen;
|
||||||
|
import com.testfairy.TestFairy;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ public class MainActivity extends ReactActivity {
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
SplashScreen.show(this);
|
SplashScreen.show(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
TestFairy.begin(this, "33e4bd97daaaacf3b1b6425096fb65186248fe44");
|
||||||
|
|
||||||
if (!RootUtil.isDeviceRooted()) {
|
if (!RootUtil.isDeviceRooted()) {
|
||||||
configureStatus();
|
configureStatus();
|
||||||
|
|
After Width: | Height: | Size: 555 B |
After Width: | Height: | Size: 372 B |
After Width: | Height: | Size: 555 B |
After Width: | Height: | Size: 747 B |
|
@ -486,7 +486,7 @@ var faucets = [
|
||||||
function faucetSuggestions(params) {
|
function faucetSuggestions(params) {
|
||||||
var suggestions = faucets.map(function (entry) {
|
var suggestions = faucets.map(function (entry) {
|
||||||
return status.components.touchable(
|
return status.components.touchable(
|
||||||
{onPress: status.components.dispatch([status.events.SET_COMMAND_ARGUMENT, [0, entry.url]])},
|
{onPress: status.components.dispatch([status.events.SET_COMMAND_ARGUMENT, [0, entry.url, false]])},
|
||||||
status.components.view(
|
status.components.view(
|
||||||
suggestionContainerStyle,
|
suggestionContainerStyle,
|
||||||
[status.components.view(
|
[status.components.view(
|
||||||
|
@ -561,7 +561,7 @@ status.command({
|
||||||
function debugSuggestions(params) {
|
function debugSuggestions(params) {
|
||||||
var suggestions = ["On", "Off"].map(function (entry) {
|
var suggestions = ["On", "Off"].map(function (entry) {
|
||||||
return status.components.touchable(
|
return status.components.touchable(
|
||||||
{onPress: status.components.dispatch([status.events.SET_COMMAND_ARGUMENT, [0, entry]])},
|
{onPress: status.components.dispatch([status.events.SET_COMMAND_ARGUMENT, [0, entry, false]])},
|
||||||
status.components.view(
|
status.components.view(
|
||||||
suggestionContainerStyle,
|
suggestionContainerStyle,
|
||||||
[status.components.view(
|
[status.components.view(
|
||||||
|
|
|
@ -1,5 +1,271 @@
|
||||||
|
function calculateFee(n, tx) {
|
||||||
|
var estimatedGas = 21000;
|
||||||
|
if (tx !== null) {
|
||||||
|
estimatedGas = web3.eth.estimateGas(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
var gasMultiplicator = Math.pow(1.4, n).toFixed(3);
|
||||||
|
return web3.fromWei(web3.eth.gasPrice * gasMultiplicator * estimatedGas, "ether");
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateGasPrice(n) {
|
||||||
|
var gasMultiplicator = Math.pow(1.4, n).toFixed(3);
|
||||||
|
return web3.eth.gasPrice * gasMultiplicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
status.defineSubscription(
|
||||||
|
"calculatedFee",
|
||||||
|
{value: ["sliderValue"], tx: ["transaction"]},
|
||||||
|
function (params) {
|
||||||
|
return calculateFee(params.value, params.tx);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function getFeeExplanation(n) {
|
||||||
|
return I18n.t('send_explanation') + I18n.t('send_explanation_' + (n + 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
status.defineSubscription(
|
||||||
|
"feeExplanation",
|
||||||
|
{value: ["sliderValue"]},
|
||||||
|
function(params) {
|
||||||
|
return getFeeExplanation(params.value);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function amountParameterBox(params, context) {
|
||||||
|
if (!params["bot-db"]) {
|
||||||
|
params["bot-db"] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
var contactAddress;
|
||||||
|
if (params["bot-db"]["public"] && params["bot-db"]["public"]["recipient"]) {
|
||||||
|
contactAddress = params["bot-db"]["public"]["recipient"]["address"];
|
||||||
|
} else {
|
||||||
|
contactAddress = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var txData;
|
||||||
|
var amount;
|
||||||
|
try {
|
||||||
|
amount = params.args[1];
|
||||||
|
txData = {
|
||||||
|
to: contactAddress,
|
||||||
|
value: web3.toWei(amount) || 0
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
amount = null;
|
||||||
|
txData = {
|
||||||
|
to: contactAddress,
|
||||||
|
value: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var sliderValue = params["bot-db"]["sliderValue"] || 0;
|
||||||
|
|
||||||
|
status.setDefaultDb({
|
||||||
|
transaction: txData,
|
||||||
|
calculatedFee: calculateFee(sliderValue, txData),
|
||||||
|
feeExplanation: getFeeExplanation(sliderValue),
|
||||||
|
sliderValue: sliderValue
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: I18n.t('send_title'),
|
||||||
|
showBack: true,
|
||||||
|
markup: status.components.scrollView(
|
||||||
|
{
|
||||||
|
keyboardShouldPersistTaps: "always"
|
||||||
|
},
|
||||||
|
[status.components.view(
|
||||||
|
{
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
[
|
||||||
|
status.components.text(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: "rgb(147, 155, 161)",
|
||||||
|
paddingTop: 12,
|
||||||
|
paddingLeft: 16,
|
||||||
|
paddingRight: 16,
|
||||||
|
paddingBottom: 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
I18n.t('send_specify_amount')
|
||||||
|
),
|
||||||
|
status.components.touchable(
|
||||||
|
{
|
||||||
|
onPress: status.components.dispatch([status.events.FOCUS_INPUT, []])
|
||||||
|
},
|
||||||
|
status.components.view(
|
||||||
|
{
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
textAlign: "center",
|
||||||
|
justifyContent: "center"
|
||||||
|
},
|
||||||
|
[
|
||||||
|
status.components.text(
|
||||||
|
{
|
||||||
|
font: "light",
|
||||||
|
numberOfLines: 1,
|
||||||
|
ellipsizeMode: "tail",
|
||||||
|
style: {
|
||||||
|
maxWidth: 250,
|
||||||
|
fontSize: 38,
|
||||||
|
marginLeft: 8,
|
||||||
|
color: "black"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
amount || "0.00"
|
||||||
|
),
|
||||||
|
status.components.text(
|
||||||
|
{
|
||||||
|
font: "light",
|
||||||
|
style: {
|
||||||
|
fontSize: 38,
|
||||||
|
marginLeft: 8,
|
||||||
|
color: "rgb(147, 155, 161)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
I18n.t('eth')
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
status.components.text(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: "rgb(147, 155, 161)",
|
||||||
|
paddingTop: 14,
|
||||||
|
paddingLeft: 16,
|
||||||
|
paddingRight: 16,
|
||||||
|
paddingBottom: 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
I18n.t('send_fee')
|
||||||
|
),
|
||||||
|
status.components.view(
|
||||||
|
{
|
||||||
|
flexDirection: "row"
|
||||||
|
},
|
||||||
|
[
|
||||||
|
status.components.text(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
fontSize: 17,
|
||||||
|
color: "black",
|
||||||
|
paddingLeft: 16
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[status.components.subscribe(["calculatedFee"])]
|
||||||
|
),
|
||||||
|
status.components.text(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
fontSize: 17,
|
||||||
|
color: "rgb(147, 155, 161)",
|
||||||
|
paddingLeft: 4,
|
||||||
|
paddingRight: 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
I18n.t('eth')
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
status.components.slider(
|
||||||
|
{
|
||||||
|
maximumValue: 2,
|
||||||
|
minimumValue: -2,
|
||||||
|
onSlidingComplete: status.components.dispatch(
|
||||||
|
[status.events.UPDATE_DB, "sliderValue"]
|
||||||
|
),
|
||||||
|
step: 1,
|
||||||
|
style: {
|
||||||
|
marginLeft: 16,
|
||||||
|
marginRight: 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
status.components.view(
|
||||||
|
{
|
||||||
|
flexDirection: "row"
|
||||||
|
},
|
||||||
|
[
|
||||||
|
status.components.text(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
flex: 1,
|
||||||
|
fontSize: 14,
|
||||||
|
color: "rgb(147, 155, 161)",
|
||||||
|
paddingLeft: 16,
|
||||||
|
alignSelf: "flex-start"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
I18n.t('send_cheaper')
|
||||||
|
),
|
||||||
|
status.components.text(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
flex: 1,
|
||||||
|
fontSize: 14,
|
||||||
|
color: "rgb(147, 155, 161)",
|
||||||
|
paddingRight: 16,
|
||||||
|
alignSelf: "flex-end",
|
||||||
|
textAlign: "right"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
I18n.t('send_faster')
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
status.components.text(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: "black",
|
||||||
|
paddingTop: 16,
|
||||||
|
paddingLeft: 16,
|
||||||
|
paddingRight: 16,
|
||||||
|
paddingBottom: 16,
|
||||||
|
lineHeight: 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[status.components.subscribe(["feeExplanation"])]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var paramsSend = [
|
||||||
|
{
|
||||||
|
name: "recipient",
|
||||||
|
type: status.types.TEXT,
|
||||||
|
suggestions: function (params) {
|
||||||
|
return {
|
||||||
|
title: I18n.t('send_title'),
|
||||||
|
markup: status.components.chooseContact(I18n.t('send_choose_recipient'), "recipient", 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "amount",
|
||||||
|
type: status.types.NUMBER,
|
||||||
|
suggestions: amountParameterBox
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
function validateSend(params, context) {
|
function validateSend(params, context) {
|
||||||
if (!context.to) {
|
if (!params["bot-db"]) {
|
||||||
|
params["bot-db"] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params["bot-db"]["public"] || !params["bot-db"]["public"]["recipient"] || !params["bot-db"]["public"]["recipient"]["address"]) {
|
||||||
return {
|
return {
|
||||||
markup: status.components.validationMessage(
|
markup: status.components.validationMessage(
|
||||||
"Wrong address",
|
"Wrong address",
|
||||||
|
@ -7,7 +273,8 @@ function validateSend(params, context) {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (!params.amount) {
|
|
||||||
|
if (!params["amount"]) {
|
||||||
return {
|
return {
|
||||||
markup: status.components.validationMessage(
|
markup: status.components.validationMessage(
|
||||||
I18n.t('validation_title'),
|
I18n.t('validation_title'),
|
||||||
|
@ -16,7 +283,7 @@ function validateSend(params, context) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var amount = params.amount.replace(",", ".");
|
var amount = params["amount"].replace(",", ".");
|
||||||
var amountSplitted = amount.split(".");
|
var amountSplitted = amount.split(".");
|
||||||
if (amountSplitted.length === 2 && amountSplitted[1].length > 18) {
|
if (amountSplitted.length === 2 && amountSplitted[1].length > 18) {
|
||||||
return {
|
return {
|
||||||
|
@ -27,6 +294,15 @@ function validateSend(params, context) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isNaN(parseFloat(params.amount.replace(",", ".")))) {
|
||||||
|
return {
|
||||||
|
markup: status.components.validationMessage(
|
||||||
|
I18n.t('validation_title'),
|
||||||
|
I18n.t('validation_invalid_number')
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var val = web3.toWei(amount, "ether");
|
var val = web3.toWei(amount, "ether");
|
||||||
if (val <= 0) {
|
if (val <= 0) {
|
||||||
|
@ -42,13 +318,15 @@ function validateSend(params, context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var balance = web3.eth.getBalance(context.from);
|
var balance = web3.eth.getBalance(context.from);
|
||||||
var estimatedGas = web3.eth.estimateGas({
|
var fee = calculateFee(
|
||||||
from: context.from,
|
params["bot-db"]["sliderValue"],
|
||||||
to: context.to,
|
{
|
||||||
value: val
|
to: params["bot-db"]["public"]["recipient"]["address"],
|
||||||
});
|
value: val
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (bn(val).plus(bn(estimatedGas)).greaterThan(bn(balance))) {
|
if (bn(val).plus(bn(web3.toWei(fee, "ether"))).greaterThan(bn(balance))) {
|
||||||
return {
|
return {
|
||||||
markup: status.components.validationMessage(
|
markup: status.components.validationMessage(
|
||||||
I18n.t('validation_title'),
|
I18n.t('validation_title'),
|
||||||
|
@ -60,11 +338,14 @@ function validateSend(params, context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendTransaction(params, context) {
|
function handleSend(params, context) {
|
||||||
|
var val = web3.toWei(params["amount"].replace(",", "."), "ether");
|
||||||
|
|
||||||
var data = {
|
var data = {
|
||||||
from: context.from,
|
from: context.from,
|
||||||
to: context.to,
|
to: params["bot-db"]["public"]["recipient"]["address"],
|
||||||
value: web3.toWei(params.amount.replace(",", "."), "ether")
|
value: val,
|
||||||
|
gasPrice: calculateGasPrice(params["bot-db"]["sliderValue"])
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -74,107 +355,158 @@ function sendTransaction(params, context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function previewSend(params, context) {
|
||||||
|
var amountStyle = {
|
||||||
|
fontSize: 36,
|
||||||
|
color: "#000000",
|
||||||
|
height: 40
|
||||||
|
};
|
||||||
|
|
||||||
|
var amount = status.components.view(
|
||||||
|
{
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "flex-end",
|
||||||
|
maxWidth: 250
|
||||||
|
},
|
||||||
|
[status.components.text(
|
||||||
|
{
|
||||||
|
style: amountStyle,
|
||||||
|
numberOfLines: 1,
|
||||||
|
ellipsizeMode: "tail",
|
||||||
|
font: "light"
|
||||||
|
},
|
||||||
|
status.localizeNumber(params.amount, context.delimiter, context.separator)
|
||||||
|
)]);
|
||||||
|
|
||||||
|
var currency = status.components.view(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
paddingBottom: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[status.components.text(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
color: "#9199a0",
|
||||||
|
fontSize: 16,
|
||||||
|
lineHeight: 18,
|
||||||
|
marginLeft: 7.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
I18n.t('eth')
|
||||||
|
)]
|
||||||
|
);
|
||||||
|
|
||||||
|
var firstRow = status.components.view(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
marginTop: 8,
|
||||||
|
marginBottom: 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[amount, currency]
|
||||||
|
);
|
||||||
|
|
||||||
|
var markup;
|
||||||
|
if (params["bot-db"]
|
||||||
|
&& params["bot-db"]["public"]
|
||||||
|
&& params["bot-db"]["public"]["recipient"]
|
||||||
|
&& context["chat"]["group-chat"] === true) {
|
||||||
|
var secondRow = status.components.text(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
color: "#9199a0",
|
||||||
|
fontSize: 14,
|
||||||
|
lineHeight: 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"to " + params["bot-db"]["public"]["recipient"]["name"]
|
||||||
|
);
|
||||||
|
markup = [firstRow, secondRow];
|
||||||
|
} else {
|
||||||
|
markup = [firstRow];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
markup: status.components.view(
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
flexDirection: "column"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
markup
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function shortPreviewSend(params, context) {
|
||||||
|
return {
|
||||||
|
markup: status.components.text(
|
||||||
|
{},
|
||||||
|
I18n.t('send_title') + ": "
|
||||||
|
+ status.localizeNumber(params.amount, context.delimiter, context.separator)
|
||||||
|
+ " ETH"
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var send = {
|
var send = {
|
||||||
name: "send",
|
name: "send",
|
||||||
icon: "money_white",
|
icon: "money_white",
|
||||||
color: "#5fc48d",
|
color: "#5fc48d",
|
||||||
title: I18n.t('send_title'),
|
title: I18n.t('send_title'),
|
||||||
description: I18n.t('send_description'),
|
description: I18n.t('send_description'),
|
||||||
sequentialParams: true,
|
params: paramsSend,
|
||||||
params: [{
|
validator: validateSend,
|
||||||
name: "amount",
|
handler: handleSend,
|
||||||
type: status.types.NUMBER
|
preview: previewSend,
|
||||||
}],
|
shortPreview: shortPreviewSend
|
||||||
preview: function (params, context) {
|
|
||||||
var amountStyle = {
|
|
||||||
fontSize: 36,
|
|
||||||
color: "#000000",
|
|
||||||
height: 40
|
|
||||||
};
|
|
||||||
|
|
||||||
var amount = status.components.view(
|
|
||||||
{
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "flex-end",
|
|
||||||
},
|
|
||||||
[status.components.text(
|
|
||||||
{
|
|
||||||
style: amountStyle,
|
|
||||||
font: "light"
|
|
||||||
},
|
|
||||||
status.localizeNumber(params.amount, context.delimiter, context.separator)
|
|
||||||
)]);
|
|
||||||
|
|
||||||
var currency = status.components.view(
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "flex-end",
|
|
||||||
paddingBottom: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[status.components.text(
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
color: "#9199a0",
|
|
||||||
fontSize: 16,
|
|
||||||
lineHeight: 18,
|
|
||||||
marginLeft: 7.5
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ETH"
|
|
||||||
)]
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
markup: status.components.view(
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
marginTop: 8,
|
|
||||||
marginBottom: 8
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[amount, currency]
|
|
||||||
)
|
|
||||||
};
|
|
||||||
},
|
|
||||||
shortPreview: function (params, context) {
|
|
||||||
return {
|
|
||||||
markup: status.components.text(
|
|
||||||
{},
|
|
||||||
I18n.t('send_title') + ": "
|
|
||||||
+ status.localizeNumber(params.amount, context.delimiter, context.separator)
|
|
||||||
+ " ETH"
|
|
||||||
)
|
|
||||||
};
|
|
||||||
},
|
|
||||||
handler: sendTransaction,
|
|
||||||
validator: validateSend
|
|
||||||
};
|
};
|
||||||
|
|
||||||
status.command(send);
|
status.command(send);
|
||||||
status.response(send);
|
status.response(send);
|
||||||
|
|
||||||
|
var paramsRequest = [
|
||||||
|
{
|
||||||
|
name: "recipient",
|
||||||
|
type: status.types.TEXT,
|
||||||
|
suggestions: function (params) {
|
||||||
|
return {
|
||||||
|
title: I18n.t('request_title'),
|
||||||
|
markup: status.components.chooseContact(I18n.t('send_choose_recipient'), "recipient", 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "amount",
|
||||||
|
type: status.types.NUMBER
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
status.command({
|
status.command({
|
||||||
name: "request",
|
name: "request",
|
||||||
color: "#5fc48d",
|
color: "#5fc48d",
|
||||||
title: I18n.t('request_title'),
|
title: I18n.t('request_title'),
|
||||||
description: I18n.t('request_description'),
|
description: I18n.t('request_description'),
|
||||||
sequentialParams: true,
|
params: paramsRequest,
|
||||||
params: [{
|
handler: function (params, context) {
|
||||||
name: "amount",
|
var val = params["amount"].replace(",", ".");
|
||||||
type: status.types.NUMBER
|
|
||||||
}],
|
|
||||||
handler: function (params) {
|
|
||||||
return {
|
return {
|
||||||
event: "request",
|
event: "request",
|
||||||
params: [params.amount],
|
|
||||||
request: {
|
request: {
|
||||||
command: "send",
|
command: "send",
|
||||||
params: {
|
params: {
|
||||||
amount: params.amount
|
recipient: context["current-account"]["name"],
|
||||||
|
amount: val
|
||||||
|
},
|
||||||
|
prefill: [context["current-account"]["name"], val],
|
||||||
|
prefillBotDb: {
|
||||||
|
contact: context["current-account"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -200,8 +532,49 @@ status.command({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
validator: function (params) {
|
validator: function (params) {
|
||||||
|
if (!params["bot-db"]) {
|
||||||
|
params["bot-db"] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params["bot-db"]["public"] || !params["bot-db"]["public"]["recipient"] || !params["bot-db"]["public"]["recipient"]["address"]) {
|
||||||
|
return {
|
||||||
|
markup: status.components.validationMessage(
|
||||||
|
"Wrong address",
|
||||||
|
"Recipient address must be specified"
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!params["amount"]) {
|
||||||
|
return {
|
||||||
|
markup: status.components.validationMessage(
|
||||||
|
I18n.t('validation_title'),
|
||||||
|
I18n.t('validation_amount_specified')
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var amount = params.amount.replace(",", ".");
|
||||||
|
var amountSplitted = amount.split(".");
|
||||||
|
if (amountSplitted.length === 2 && amountSplitted[1].length > 18) {
|
||||||
|
return {
|
||||||
|
markup: status.components.validationMessage(
|
||||||
|
I18n.t('validation_title'),
|
||||||
|
I18n.t('validation_amount_is_too_small')
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(parseFloat(params.amount.replace(",", ".")))) {
|
||||||
|
return {
|
||||||
|
markup: status.components.validationMessage(
|
||||||
|
I18n.t('validation_title'),
|
||||||
|
I18n.t('validation_invalid_number')
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var val = web3.toWei(params.amount.replace(",", "."), "ether");
|
var val = web3.toWei(amount, "ether");
|
||||||
if (val <= 0) {
|
if (val <= 0) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,20 @@
|
||||||
I18n.translations = {
|
I18n.translations = {
|
||||||
en: {
|
en: {
|
||||||
send_title: 'Send ETH',
|
send_title: 'Send transaction',
|
||||||
send_description: 'Send a payment',
|
send_description: 'Send a payment',
|
||||||
|
send_choose_recipient: 'Choose recipient',
|
||||||
|
send_specify_amount: 'Specify amount',
|
||||||
|
send_fee: 'Fee',
|
||||||
|
send_cheaper: 'Cheaper',
|
||||||
|
send_faster: 'Faster',
|
||||||
|
send_explanation: 'This is the most amount of money that might be used to process this transaction. Your transaction will be mined ',
|
||||||
|
send_explanation_0: 'in a few minutes or more.',
|
||||||
|
send_explanation_1: 'likely within a few minutes.',
|
||||||
|
send_explanation_2: 'usually within a minute.',
|
||||||
|
send_explanation_3: 'probably within 30 seconds.',
|
||||||
|
send_explanation_4: 'probably within a few seconds.',
|
||||||
|
|
||||||
|
eth: 'ETH',
|
||||||
|
|
||||||
request_title: 'Request ETH',
|
request_title: 'Request ETH',
|
||||||
request_description: 'Request a payment',
|
request_description: 'Request a payment',
|
||||||
|
@ -14,7 +27,7 @@ I18n.translations = {
|
||||||
validation_insufficient_amount: 'Insufficient funds for gas * price + value (balance '
|
validation_insufficient_amount: 'Insufficient funds for gas * price + value (balance '
|
||||||
},
|
},
|
||||||
ru: {
|
ru: {
|
||||||
send_title: 'Отправить ETH',
|
send_title: 'Отправить транзакцию',
|
||||||
send_description: 'Отправить платеж',
|
send_description: 'Отправить платеж',
|
||||||
|
|
||||||
request_title: 'Запросить ETH',
|
request_title: 'Запросить ETH',
|
||||||
|
|
|
@ -4,11 +4,12 @@ var TopLevel = {
|
||||||
"addEventListener" : function () {},
|
"addEventListener" : function () {},
|
||||||
"addListener" : function () {},
|
"addListener" : function () {},
|
||||||
"addOrientationListener" : function () {},
|
"addOrientationListener" : function () {},
|
||||||
"addSymKey" : function () {},
|
"addSymmetricKeyFromPassword" : function () {},
|
||||||
"Alert" : function () {},
|
"Alert" : function () {},
|
||||||
"alert" : function () {},
|
"alert" : function () {},
|
||||||
"Animated" : function () {},
|
"Animated" : function () {},
|
||||||
"Array" : function () {},
|
"Array" : function () {},
|
||||||
|
"AutoGrowingTextInput" : function () {},
|
||||||
"awesome-phonenumber" : function () {},
|
"awesome-phonenumber" : function () {},
|
||||||
"blur" : function () {},
|
"blur" : function () {},
|
||||||
"call" : function () {},
|
"call" : function () {},
|
||||||
|
@ -16,6 +17,7 @@ var TopLevel = {
|
||||||
"capture" : function () {},
|
"capture" : function () {},
|
||||||
"catch" : function () {},
|
"catch" : function () {},
|
||||||
"Chance" : function () {},
|
"Chance" : function () {},
|
||||||
|
"checkVideoAuthorizationStatus" : function () {},
|
||||||
"clear" : function () {},
|
"clear" : function () {},
|
||||||
"clearCookies" : function () {},
|
"clearCookies" : function () {},
|
||||||
"clearInterval" : function () {},
|
"clearInterval" : function () {},
|
||||||
|
@ -26,7 +28,7 @@ var TopLevel = {
|
||||||
"close" : function () {},
|
"close" : function () {},
|
||||||
"closeDrawer" : function () {},
|
"closeDrawer" : function () {},
|
||||||
"codec" : function () {},
|
"codec" : function () {},
|
||||||
"completeTransaction" : function () {},
|
"completeTransactions" : function () {},
|
||||||
"console" : function () {},
|
"console" : function () {},
|
||||||
"contentOffset" : function () {},
|
"contentOffset" : function () {},
|
||||||
"contentSize" : function () {},
|
"contentSize" : function () {},
|
||||||
|
@ -67,36 +69,34 @@ var TopLevel = {
|
||||||
"fromUtf8" : function () {},
|
"fromUtf8" : function () {},
|
||||||
"fromWei" : function () {},
|
"fromWei" : function () {},
|
||||||
"generate" : function () {},
|
"generate" : function () {},
|
||||||
|
"geoPermissionsGranted" : function () {},
|
||||||
"get" : function () {},
|
"get" : function () {},
|
||||||
"getAll" : function () {},
|
"getAll" : function () {},
|
||||||
"getBlock" : function () {},
|
"getBlock" : function () {},
|
||||||
"getCardId" : function () {},
|
"getCardId" : function () {},
|
||||||
"getExample" : function () {},
|
"getExample" : function () {},
|
||||||
"getInitialOrientation" : function () {},
|
"getInitialOrientation" : function () {},
|
||||||
"getIPAddress" : function () {},
|
|
||||||
"getLayout" : function () {},
|
"getLayout" : function () {},
|
||||||
"getNumber" : function () {},
|
"getNumber" : function () {},
|
||||||
"getSyncing" : function () {},
|
"getSyncing" : function () {},
|
||||||
"getTime" : function () {},
|
"getTime" : function () {},
|
||||||
"getTimezoneOffset" : function () {},
|
"getTimezoneOffset" : function () {},
|
||||||
|
"goBack" : function () {},
|
||||||
|
"goForward" : function () {},
|
||||||
"goog" : function () {},
|
"goog" : function () {},
|
||||||
"guid" : function () {},
|
"guid" : function () {},
|
||||||
"hash" : function () {},
|
"hash" : function () {},
|
||||||
"hasSymKey" : function () {},
|
|
||||||
"headers" : function () {},
|
"headers" : function () {},
|
||||||
"height" : function () {},
|
"height" : function () {},
|
||||||
"hex" : function () {},
|
"hex" : function () {},
|
||||||
"hide" : function () {},
|
"hide" : function () {},
|
||||||
"HttpProvider" : function () {},
|
|
||||||
"IBGLog" : function () {},
|
"IBGLog" : function () {},
|
||||||
"initialPage" : function () {},
|
"initialPage" : function () {},
|
||||||
"initJail" : function () {},
|
"initJail" : function () {},
|
||||||
"isAddress" : function () {},
|
"isAddress" : function () {},
|
||||||
"isConnected" : function () {},
|
"isConnected" : function () {},
|
||||||
"isMatches" : function () {},
|
"isMatches" : function () {},
|
||||||
"isMobile" : function () {},
|
|
||||||
"isNaN" : function () {},
|
"isNaN" : function () {},
|
||||||
"isValid" : function () {},
|
|
||||||
"Item" : function () {},
|
"Item" : function () {},
|
||||||
"JSON" : function () {},
|
"JSON" : function () {},
|
||||||
"jsonEvent" : function () {},
|
"jsonEvent" : function () {},
|
||||||
|
@ -113,13 +113,13 @@ var TopLevel = {
|
||||||
"Math" : function () {},
|
"Math" : function () {},
|
||||||
"message" : function () {},
|
"message" : function () {},
|
||||||
"moveFile" : function () {},
|
"moveFile" : function () {},
|
||||||
|
"moveToInternalStorage" : function () {},
|
||||||
"moveY" : function () {},
|
"moveY" : function () {},
|
||||||
"nativeEvent" : function () {},
|
"nativeEvent" : function () {},
|
||||||
"NativeModules" : function () {},
|
"NativeModules" : function () {},
|
||||||
"Number" : function () {},
|
"Number" : function () {},
|
||||||
"objects" : function () {},
|
"objects" : function () {},
|
||||||
"ok" : function () {},
|
"ok" : function () {},
|
||||||
"open" : function () {},
|
|
||||||
"openDrawer" : function () {},
|
"openDrawer" : function () {},
|
||||||
"openPicker" : function () {},
|
"openPicker" : function () {},
|
||||||
"openURL" : function () {},
|
"openURL" : function () {},
|
||||||
|
@ -132,11 +132,11 @@ var TopLevel = {
|
||||||
"parseInt" : function () {},
|
"parseInt" : function () {},
|
||||||
"parseJail" : function () {},
|
"parseJail" : function () {},
|
||||||
"path" : function () {},
|
"path" : function () {},
|
||||||
|
"PermissionsAndroid" : function () {},
|
||||||
"Platform" : function () {},
|
"Platform" : function () {},
|
||||||
"post" : function () {},
|
"post" : function () {},
|
||||||
"props" : function () {},
|
"props" : function () {},
|
||||||
"prototype" : function () {},
|
"prototype" : function () {},
|
||||||
"providers" : function () {},
|
|
||||||
"push" : function () {},
|
"push" : function () {},
|
||||||
"random" : function () {},
|
"random" : function () {},
|
||||||
"randomBytes" : function () {},
|
"randomBytes" : function () {},
|
||||||
|
@ -149,8 +149,12 @@ var TopLevel = {
|
||||||
"reload" : function () {},
|
"reload" : function () {},
|
||||||
"remove" : function () {},
|
"remove" : function () {},
|
||||||
"removeAllListeners" : function () {},
|
"removeAllListeners" : function () {},
|
||||||
|
"removeEventListener" : function () {},
|
||||||
|
"requestMultiple" : function () {},
|
||||||
"require" : function () {},
|
"require" : function () {},
|
||||||
"reset" : function () {},
|
"reset" : function () {},
|
||||||
|
"resetOkHttpClient" : function () {},
|
||||||
|
"respond" : function () {},
|
||||||
"reverse" : function () {},
|
"reverse" : function () {},
|
||||||
"round" : function () {},
|
"round" : function () {},
|
||||||
"schema" : function () {},
|
"schema" : function () {},
|
||||||
|
@ -160,9 +164,11 @@ var TopLevel = {
|
||||||
"scrollView" : function () {},
|
"scrollView" : function () {},
|
||||||
"selection" : function () {},
|
"selection" : function () {},
|
||||||
"sendToBridge" : function () {},
|
"sendToBridge" : function () {},
|
||||||
|
"sendWeb3Request" : function () {},
|
||||||
"sequence" : function () {},
|
"sequence" : function () {},
|
||||||
"set" : function () {},
|
"set" : function () {},
|
||||||
"setInterval" : function () {},
|
"setInterval" : function () {},
|
||||||
|
"setNativeProps" : function () {},
|
||||||
"setSoftInputMode" : function () {},
|
"setSoftInputMode" : function () {},
|
||||||
"setState" : function () {},
|
"setState" : function () {},
|
||||||
"setString" : function () {},
|
"setString" : function () {},
|
||||||
|
@ -170,7 +176,10 @@ var TopLevel = {
|
||||||
"setValue" : function () {},
|
"setValue" : function () {},
|
||||||
"Sha256" : function () {},
|
"Sha256" : function () {},
|
||||||
"sha3" : function () {},
|
"sha3" : function () {},
|
||||||
|
"Share" : function () {},
|
||||||
|
"share" : function () {},
|
||||||
"shh" : function () {},
|
"shh" : function () {},
|
||||||
|
"shouldMoveToInternalStorage" : function () {},
|
||||||
"show" : function () {},
|
"show" : function () {},
|
||||||
"showActionSheetWithOptions" : function () {},
|
"showActionSheetWithOptions" : function () {},
|
||||||
"sjcl" : function () {},
|
"sjcl" : function () {},
|
||||||
|
@ -197,7 +206,7 @@ var TopLevel = {
|
||||||
"toAscii" : function () {},
|
"toAscii" : function () {},
|
||||||
"toBits" : function () {},
|
"toBits" : function () {},
|
||||||
"toDecimal" : function () {},
|
"toDecimal" : function () {},
|
||||||
"toHex" : function () {},
|
"toJSON" : function () {},
|
||||||
"toLocaleString" : function () {},
|
"toLocaleString" : function () {},
|
||||||
"toLowerCase" : function () {},
|
"toLowerCase" : function () {},
|
||||||
"toNumber" : function () {},
|
"toNumber" : function () {},
|
||||||
|
@ -218,5 +227,6 @@ var TopLevel = {
|
||||||
"writeTag" : function () {},
|
"writeTag" : function () {},
|
||||||
"x" : function () {},
|
"x" : function () {},
|
||||||
"y" : function () {},
|
"y" : function () {},
|
||||||
|
"_bodyText" : function () {},
|
||||||
"_value" : function () {}
|
"_value" : function () {}
|
||||||
}
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "iconBackDark.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "iconBackDark@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "iconBackDark@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 372 B |
After Width: | Height: | Size: 555 B |
After Width: | Height: | Size: 747 B |
|
@ -178,6 +178,14 @@ function validationMessage(titleText, descriptionText) {
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function chooseContact(titleText, botDbKey, argumentIndex) {
|
||||||
|
return ['choose-contact', {
|
||||||
|
title: titleText,
|
||||||
|
"bot-db-key": botDbKey,
|
||||||
|
index: argumentIndex
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
var status = {
|
var status = {
|
||||||
command: function (h) {
|
command: function (h) {
|
||||||
var command = new Command();
|
var command = new Command();
|
||||||
|
@ -208,7 +216,11 @@ var status = {
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
SET_VALUE: 'set-value',
|
SET_VALUE: 'set-value',
|
||||||
SET_COMMAND_ARGUMENT: 'set-command-argument'
|
SET_COMMAND_ARGUMENT: 'set-command-argument',
|
||||||
|
UPDATE_DB: 'set',
|
||||||
|
SET_COMMAND_ARGUMENT_FROM_DB: 'set-command-argument-from-db',
|
||||||
|
SET_VALUE_FROM_DB: 'set-value-from-db',
|
||||||
|
FOCUS_INPUT: 'focus-input'
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
WEB_VIEW_BACK: 'web-view-back',
|
WEB_VIEW_BACK: 'web-view-back',
|
||||||
|
@ -220,6 +232,7 @@ var status = {
|
||||||
view: view,
|
view: view,
|
||||||
text: text,
|
text: text,
|
||||||
textInput: textInput,
|
textInput: textInput,
|
||||||
|
slider: slider,
|
||||||
image: image,
|
image: image,
|
||||||
qrCode: qrCode,
|
qrCode: qrCode,
|
||||||
linking: linking,
|
linking: linking,
|
||||||
|
@ -230,6 +243,7 @@ var status = {
|
||||||
webView: webView,
|
webView: webView,
|
||||||
validationMessage: validationMessage,
|
validationMessage: validationMessage,
|
||||||
bridgedWebView: bridgedWebView,
|
bridgedWebView: bridgedWebView,
|
||||||
|
chooseContact: chooseContact,
|
||||||
subscribe: subscribe,
|
subscribe: subscribe,
|
||||||
dispatch: dispatch
|
dispatch: dispatch
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,8 +3,17 @@
|
||||||
[status-im.components.status :as status]
|
[status-im.components.status :as status]
|
||||||
[status-im.utils.handlers :as u]))
|
[status-im.utils.handlers :as u]))
|
||||||
|
|
||||||
|
(defn chats-with-bot [chats bot]
|
||||||
|
(reduce (fn [acc [_ {:keys [chat-id contacts]}]]
|
||||||
|
(let [contacts (map :identity contacts)]
|
||||||
|
(if (some #{bot} contacts)
|
||||||
|
(conj acc chat-id)
|
||||||
|
acc)))
|
||||||
|
[]
|
||||||
|
chats))
|
||||||
|
|
||||||
(defn check-subscriptions
|
(defn check-subscriptions
|
||||||
[{:keys [bot-db] :as db} [handler {:keys [path key bot]}]]
|
[{:keys [bot-db chats] :as db} [handler {:keys [path key bot]}]]
|
||||||
(let [path' (or path [key])
|
(let [path' (or path [key])
|
||||||
subscriptions (get-in db [:bot-subscriptions path'])
|
subscriptions (get-in db [:bot-subscriptions path'])
|
||||||
current-bot-db (get bot-db bot)]
|
current-bot-db (get bot-db bot)]
|
||||||
|
@ -17,22 +26,23 @@
|
||||||
:function :subscription
|
:function :subscription
|
||||||
:parameters {:name name
|
:parameters {:name name
|
||||||
:subscriptions subs-values}
|
:subscriptions subs-values}
|
||||||
:callback #(re-frame/dispatch
|
:callback #(do
|
||||||
[::calculated-subscription {:bot bot
|
(re-frame/dispatch
|
||||||
:path [name]
|
[::calculated-subscription {:bot bot
|
||||||
:result %}])})))))
|
:path [name]
|
||||||
|
:result %}])
|
||||||
(u/register-handler
|
(doseq [chat-id (chats-with-bot chats bot)]
|
||||||
:set-bot-db
|
(re-frame/dispatch
|
||||||
(re-frame/after check-subscriptions)
|
[::calculated-subscription {:bot chat-id
|
||||||
(fn [db [_ {:keys [bot key value]}]]
|
:path [name]
|
||||||
(assoc-in db [:bot-db bot key] value)))
|
:result %}])))})))))
|
||||||
|
|
||||||
(u/register-handler
|
(u/register-handler
|
||||||
:set-in-bot-db
|
:set-in-bot-db
|
||||||
(re-frame/after check-subscriptions)
|
(re-frame/after check-subscriptions)
|
||||||
(fn [db [_ {:keys [bot path value]}]]
|
(fn [{:keys [current-chat-id] :as db} [_ {:keys [bot path value]}]]
|
||||||
(assoc-in db (concat [:bot-db bot] path) value)))
|
(let [bot (or bot current-chat-id)]
|
||||||
|
(assoc-in db (concat [:bot-db bot] path) value))))
|
||||||
|
|
||||||
(u/register-handler
|
(u/register-handler
|
||||||
:register-bot-subscription
|
:register-bot-subscription
|
||||||
|
@ -61,5 +71,12 @@
|
||||||
|
|
||||||
(u/register-handler
|
(u/register-handler
|
||||||
:update-bot-db
|
:update-bot-db
|
||||||
(fn [app-db [_ {:keys [bot db]}]]
|
(fn [{:keys [current-chat-id] :as app-db} [_ {:keys [bot db]}]]
|
||||||
(update-in app-db [:bot-db bot] merge db)))
|
(let [bot (or bot current-chat-id)]
|
||||||
|
(update-in app-db [:bot-db bot] merge db))))
|
||||||
|
|
||||||
|
(u/register-handler
|
||||||
|
:clear-bot-db
|
||||||
|
(fn [{:keys [current-chat-id] :as app-db} [_ {:keys [bot]}]]
|
||||||
|
(let [bot (or bot current-chat-id)]
|
||||||
|
(assoc-in app-db [:bot-db bot] nil))))
|
|
@ -265,7 +265,7 @@
|
||||||
db' (-> db
|
db' (-> db
|
||||||
(assoc :current-chat-id chat-id)
|
(assoc :current-chat-id chat-id)
|
||||||
(assoc-in [:chats chat-id :was-opened?] true))
|
(assoc-in [:chats chat-id :was-opened?] true))
|
||||||
commands-loaded? (get-in db [:contacts chat-id :commands-loaded])
|
commands-loaded? (get-in db [:contacts chat-id :commands-loaded?])
|
||||||
bot-url (get-in db [:contacts chat-id :bot-url])
|
bot-url (get-in db [:contacts chat-id :bot-url])
|
||||||
was-opened? (get-in db [:chats chat-id :was-opened?])
|
was-opened? (get-in db [:chats chat-id :was-opened?])
|
||||||
call-init-command #(when (and (not was-opened?) bot-url)
|
call-init-command #(when (and (not was-opened?) bot-url)
|
||||||
|
|
|
@ -6,28 +6,37 @@
|
||||||
[status-im.commands.utils :as cu]
|
[status-im.commands.utils :as cu]
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
|
||||||
|
(defn generate-context [{:keys [contacts current-account-id chats] :as db} chat-id to]
|
||||||
|
(merge {:platform platform/platform
|
||||||
|
:from current-account-id
|
||||||
|
:to to
|
||||||
|
:chat {:chat-id chat-id
|
||||||
|
:group-chat (get-in chats [chat-id :group-chat])}}
|
||||||
|
i18n/delimeters))
|
||||||
|
|
||||||
(handlers/register-handler :request-command-data
|
(handlers/register-handler :request-command-data
|
||||||
(handlers/side-effect!
|
(handlers/side-effect!
|
||||||
(fn [{:keys [contacts current-account-id] :as db}
|
(fn [{:keys [contacts current-account-id chats] :as db}
|
||||||
[_ {{:keys [command params content-command type]} :content
|
[_ {{:keys [command params content-command type]} :content
|
||||||
:keys [message-id chat-id on-requested jail-id] :as message} data-type]]
|
:keys [message-id from chat-id on-requested jail-id] :as message} data-type]]
|
||||||
(let [jail-id (or jail-id chat-id)]
|
(let [jail-id (or jail-id chat-id)
|
||||||
(if-not (get-in contacts [jail-id :commands-loaded])
|
jail-id' (if (get-in chats [jail-id :group-chat])
|
||||||
|
(get-in chats [jail-id :command-suggestions (keyword command) :owner-id])
|
||||||
|
jail-id)]
|
||||||
|
(if-not (get-in contacts [jail-id' :commands-loaded?])
|
||||||
(do (dispatch [:add-commands-loading-callback
|
(do (dispatch [:add-commands-loading-callback
|
||||||
jail-id
|
jail-id'
|
||||||
#(dispatch [:request-command-data message data-type])])
|
#(dispatch [:request-command-data message data-type])])
|
||||||
(dispatch [:load-commands! jail-id]))
|
(dispatch [:load-commands! jail-id']))
|
||||||
(let [path [(if (= :response (keyword type)) :responses :commands)
|
(let [path [(if (= :response (keyword type)) :responses :commands)
|
||||||
(if content-command content-command command)
|
(if content-command content-command command)
|
||||||
data-type]
|
data-type]
|
||||||
to (get-in contacts [chat-id :address])
|
to (get-in contacts [chat-id :address])
|
||||||
params {:parameters params
|
params {:parameters params
|
||||||
:context (merge {:platform platform/platform
|
:context (generate-context db chat-id to)}
|
||||||
:from current-account-id
|
|
||||||
:to to}
|
|
||||||
i18n/delimeters)}
|
|
||||||
callback #(let [result (get-in % [:result :returned])
|
callback #(let [result (get-in % [:result :returned])
|
||||||
result (if (:markup result)
|
result (if (:markup result)
|
||||||
(update result :markup cu/generate-hiccup)
|
(update result :markup cu/generate-hiccup)
|
||||||
|
@ -35,7 +44,7 @@
|
||||||
(dispatch [:set-in [:message-data data-type message-id] result])
|
(dispatch [:set-in [:message-data data-type message-id] result])
|
||||||
(when on-requested (on-requested result)))]
|
(when on-requested (on-requested result)))]
|
||||||
;chat-id path params callback lock? type
|
;chat-id path params callback lock? type
|
||||||
(status/call-jail {:jail-id jail-id
|
(status/call-jail {:jail-id jail-id'
|
||||||
:path path
|
:path path
|
||||||
:params params
|
:params params
|
||||||
:callback callback})))))))
|
:callback callback})))))))
|
||||||
|
|
|
@ -14,16 +14,20 @@
|
||||||
[clojure.string :as str]))
|
[clojure.string :as str]))
|
||||||
|
|
||||||
(handlers/register-handler
|
(handlers/register-handler
|
||||||
:set-chat-input-text
|
:set-chat-input-text
|
||||||
(fn [{:keys [current-chat-id chats chat-ui-props] :as db} [_ text chat-id]]
|
(fn [{:keys [current-chat-id chats chat-ui-props] :as db} [_ text chat-id]]
|
||||||
(let [chat-id (or chat-id current-chat-id)
|
(let [chat-id (or chat-id current-chat-id)
|
||||||
ends-with-space? (input-model/text-ends-with-space? text)]
|
ends-with-space? (input-model/text-ends-with-space? text)]
|
||||||
(dispatch [:update-suggestions chat-id text])
|
(dispatch [:update-suggestions chat-id text])
|
||||||
|
|
||||||
(if-let [{command :command} (input-model/selected-chat-command db chat-id text)]
|
(->> text
|
||||||
|
(input-model/text->emoji)
|
||||||
|
(assoc-in db [:chats chat-id :input-text]))
|
||||||
|
|
||||||
|
;; 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)
|
(let [{old-args :args} (input-model/selected-chat-command db chat-id)
|
||||||
text-splitted (input-model/split-command-args text)
|
text-splitted (input-model/split-command-args text)
|
||||||
new-args (rest text-splitted)
|
|
||||||
new-input-text (input-model/make-input-text text-splitted old-args)]
|
new-input-text (input-model/make-input-text text-splitted old-args)]
|
||||||
(assoc-in db [:chats chat-id :input-text] new-input-text))
|
(assoc-in db [:chats chat-id :input-text] new-input-text))
|
||||||
(->> text
|
(->> text
|
||||||
|
@ -41,15 +45,20 @@
|
||||||
:select-chat-input-command
|
:select-chat-input-command
|
||||||
(handlers/side-effect!
|
(handlers/side-effect!
|
||||||
(fn [{:keys [current-chat-id chat-ui-props] :as db}
|
(fn [{:keys [current-chat-id chat-ui-props] :as db}
|
||||||
[_ {:keys [prefill sequential-params] :as command} metadata prevent-auto-focus?]]
|
[_ {:keys [prefill prefill-bot-db sequential-params name] :as command} metadata prevent-auto-focus?]]
|
||||||
(dispatch [:set-chat-input-text (str (chat-utils/command-name command)
|
(dispatch [:set-chat-input-text (str (chat-utils/command-name command)
|
||||||
const/spacing-char
|
const/spacing-char
|
||||||
(when-not sequential-params
|
(when-not sequential-params
|
||||||
(input-model/join-command-args prefill)))])
|
(input-model/join-command-args prefill)))])
|
||||||
|
(dispatch [:clear-bot-db])
|
||||||
|
(when prefill-bot-db
|
||||||
|
(dispatch [:update-bot-db {:bot current-chat-id
|
||||||
|
:db prefill-bot-db}]))
|
||||||
(dispatch [:set-chat-input-metadata metadata])
|
(dispatch [:set-chat-input-metadata metadata])
|
||||||
(dispatch [:set-chat-ui-props {:show-suggestions? false
|
(dispatch [:set-chat-ui-props {:show-suggestions? false
|
||||||
:result-box nil
|
:result-box nil
|
||||||
:validation-messages nil}])
|
:validation-messages nil
|
||||||
|
:prev-command name}])
|
||||||
(dispatch [:load-chat-parameter-box command 0])
|
(dispatch [:load-chat-parameter-box command 0])
|
||||||
(if sequential-params
|
(if sequential-params
|
||||||
(js/setTimeout
|
(js/setTimeout
|
||||||
|
@ -69,14 +78,15 @@
|
||||||
(handlers/register-handler
|
(handlers/register-handler
|
||||||
:set-command-argument
|
:set-command-argument
|
||||||
(handlers/side-effect!
|
(handlers/side-effect!
|
||||||
(fn [{:keys [current-chat-id] :as db} [_ [index arg]]]
|
(fn [{:keys [current-chat-id] :as db} [_ [index arg move-to-next?]]]
|
||||||
(let [command (-> (get-in db [:chats current-chat-id :input-text])
|
(let [command (-> (get-in db [:chats current-chat-id :input-text])
|
||||||
(input-model/split-command-args))
|
(input-model/split-command-args))
|
||||||
seq-params? (-> (input-model/selected-chat-command db current-chat-id)
|
seq-params? (-> (input-model/selected-chat-command db current-chat-id)
|
||||||
(get-in [:command :sequential-params]))]
|
(get-in [:command :sequential-params]))]
|
||||||
(if seq-params?
|
(if seq-params?
|
||||||
(dispatch [:set-chat-seq-arg-input-text arg])
|
(dispatch [:set-chat-seq-arg-input-text arg])
|
||||||
(let [command-name (first command)
|
(let [arg (str/replace arg (re-pattern const/arg-wrapping-char) "")
|
||||||
|
command-name (first command)
|
||||||
command-args (into [] (rest command))
|
command-args (into [] (rest command))
|
||||||
command-args (if (< index (count command-args))
|
command-args (if (< index (count command-args))
|
||||||
(assoc command-args index arg)
|
(assoc command-args index arg)
|
||||||
|
@ -84,7 +94,9 @@
|
||||||
(dispatch [:set-chat-input-text (str command-name
|
(dispatch [:set-chat-input-text (str command-name
|
||||||
const/spacing-char
|
const/spacing-char
|
||||||
(input-model/join-command-args command-args)
|
(input-model/join-command-args command-args)
|
||||||
const/spacing-char)])))))))
|
(when (and move-to-next?
|
||||||
|
(= index (dec (count command-args))))
|
||||||
|
const/spacing-char))])))))))
|
||||||
|
|
||||||
(handlers/register-handler
|
(handlers/register-handler
|
||||||
:chat-input-focus
|
:chat-input-focus
|
||||||
|
@ -104,25 +116,28 @@
|
||||||
requests (->> (suggestions/get-request-suggestions db chat-text)
|
requests (->> (suggestions/get-request-suggestions db chat-text)
|
||||||
(remove (fn [{:keys [type]}]
|
(remove (fn [{:keys [type]}]
|
||||||
(= type :grant-permissions))))
|
(= type :grant-permissions))))
|
||||||
suggestions (suggestions/get-command-suggestions db chat-text)
|
commands (suggestions/get-command-suggestions db chat-text)
|
||||||
global-commands (suggestions/get-global-command-suggestions db chat-text)
|
global-commands (suggestions/get-global-command-suggestions db chat-text)
|
||||||
|
all-commands (->> (into global-commands commands)
|
||||||
|
(remove (fn [[k {:keys [hidden?]}]] hidden?))
|
||||||
|
(into {}))
|
||||||
{:keys [dapp?]} (get-in db [:contacts chat-id])]
|
{:keys [dapp?]} (get-in db [:contacts chat-id])]
|
||||||
(if (and dapp? (str/blank? chat-text))
|
(if (and dapp? (str/blank? chat-text))
|
||||||
(dispatch [:set-in [:chats chat-id :parameter-boxes :message] nil])
|
(dispatch [:set-in [:chats chat-id :parameter-boxes :message] nil])
|
||||||
(dispatch [::check-dapp-suggestions chat-id chat-text]))
|
(dispatch [::check-dapp-suggestions chat-id chat-text]))
|
||||||
(-> db
|
(-> db
|
||||||
(assoc-in [:chats chat-id :request-suggestions] requests)
|
(assoc-in [:chats chat-id :request-suggestions] requests)
|
||||||
(assoc-in [:chats chat-id :command-suggestions] (into suggestions global-commands))))))
|
(assoc-in [:chats chat-id :command-suggestions] all-commands)))))
|
||||||
|
|
||||||
(handlers/register-handler
|
(handlers/register-handler
|
||||||
:load-chat-parameter-box
|
:load-chat-parameter-box
|
||||||
(handlers/side-effect!
|
(handlers/side-effect!
|
||||||
(fn [{:keys [current-chat-id current-account-id] :as db}
|
(fn [{:keys [current-chat-id bot-db current-account-id] :as db}
|
||||||
[_ {:keys [name type bot] :as command}]]
|
[_ {:keys [name type bot owner-id] :as command}]]
|
||||||
(let [parameter-index (input-model/argument-position db current-chat-id)]
|
(let [parameter-index (input-model/argument-position db current-chat-id)]
|
||||||
(when (and command (> parameter-index -1))
|
(when (and command (> parameter-index -1))
|
||||||
(let [jail-id (or bot current-chat-id)
|
(let [data (get-in db [:local-storage current-chat-id])
|
||||||
data (get-in db [:local-storage current-chat-id])
|
bot-db (get bot-db (or bot current-chat-id))
|
||||||
path [(if (= :command type) :commands :responses)
|
path [(if (= :command type) :commands :responses)
|
||||||
name
|
name
|
||||||
:params
|
:params
|
||||||
|
@ -132,13 +147,14 @@
|
||||||
(input-model/split-command-args)
|
(input-model/split-command-args)
|
||||||
(rest))
|
(rest))
|
||||||
to (get-in db [:contacts current-chat-id :address])
|
to (get-in db [:contacts current-chat-id :address])
|
||||||
params {:parameters {:args args}
|
params {:parameters {:args args
|
||||||
|
:bot-db bot-db}
|
||||||
:context (merge {:data data
|
:context (merge {:data data
|
||||||
:from current-account-id
|
:from current-account-id
|
||||||
:to to}
|
:to to}
|
||||||
(input-model/command-dependent-context-params command))}]
|
(input-model/command-dependent-context-params command))}]
|
||||||
(status/call-jail
|
(status/call-jail
|
||||||
{:jail-id jail-id
|
{:jail-id (or bot owner-id current-chat-id)
|
||||||
:path path
|
:path path
|
||||||
:params params
|
:params params
|
||||||
:callback #(dispatch [:received-bot-response
|
:callback #(dispatch [:received-bot-response
|
||||||
|
@ -239,28 +255,33 @@
|
||||||
(handlers/register-handler
|
(handlers/register-handler
|
||||||
::request-command-data
|
::request-command-data
|
||||||
(handlers/side-effect!
|
(handlers/side-effect!
|
||||||
(fn [{:keys [contacts] :as db}
|
(fn [{:keys [contacts bot-db] :as db}
|
||||||
[_ {{:keys [command metadata args] :as c} :command
|
[_ {{:keys [command
|
||||||
:keys [message-id chat-id jail-id data-type after]}]]
|
metadata
|
||||||
|
args]
|
||||||
|
:as c} :command
|
||||||
|
:keys [message-id chat-id jail-id data-type after]}]]
|
||||||
(let [{:keys [dapp? dapp-url name]} (get contacts chat-id)
|
(let [{:keys [dapp? dapp-url name]} (get contacts chat-id)
|
||||||
message-id (random/id)
|
message-id (random/id)
|
||||||
metadata (merge metadata
|
metadata (merge metadata
|
||||||
(when dapp?
|
(when dapp?
|
||||||
{:url (i18n/get-contact-translated chat-id :dapp-url dapp-url)
|
{:url (i18n/get-contact-translated chat-id :dapp-url dapp-url)
|
||||||
:name (i18n/get-contact-translated chat-id :name name)}))
|
:name (i18n/get-contact-translated chat-id :name name)}))
|
||||||
params (input-model/args->params c)
|
owner-id (:owner-id command)
|
||||||
|
bot-db (get bot-db chat-id)
|
||||||
|
params (assoc (input-model/args->params c) :bot-db bot-db)
|
||||||
command-message {:command command
|
command-message {:command command
|
||||||
:params params
|
:params params
|
||||||
:to-message (:to-message-id metadata)
|
:to-message (:to-message-id metadata)
|
||||||
:created-at (time/now-ms)
|
:created-at (time/now-ms)
|
||||||
:id message-id
|
:id message-id
|
||||||
:chat-id chat-id
|
:chat-id chat-id
|
||||||
:jail-id jail-id}
|
:jail-id (or owner-id jail-id)}
|
||||||
request-data {:message-id message-id
|
request-data {:message-id message-id
|
||||||
:chat-id chat-id
|
:chat-id chat-id
|
||||||
:jail-id jail-id
|
:jail-id (or owner-id jail-id)
|
||||||
:content {:command (:name command)
|
:content {:command (:name command)
|
||||||
:params (assoc params :metadata metadata)
|
:params (assoc params :metadata metadata :bot-db bot-db)
|
||||||
:type (:type command)}
|
:type (:type command)}
|
||||||
:on-requested #(after command-message %)}]
|
:on-requested #(after command-message %)}]
|
||||||
(dispatch [:request-command-data request-data data-type])))))
|
(dispatch [:request-command-data request-data data-type])))))
|
||||||
|
@ -342,3 +363,48 @@
|
||||||
(fn [{:keys [current-chat-id] :as db} [_ text chat-id]]
|
(fn [{:keys [current-chat-id] :as db} [_ text chat-id]]
|
||||||
(let [chat-id (or chat-id current-chat-id)]
|
(let [chat-id (or chat-id current-chat-id)]
|
||||||
(assoc-in db [:chats chat-id :seq-argument-input-text] text))))
|
(assoc-in db [:chats chat-id :seq-argument-input-text] text))))
|
||||||
|
|
||||||
|
(handlers/register-handler
|
||||||
|
:update-text-selection
|
||||||
|
(handlers/side-effect!
|
||||||
|
(fn [{:keys [current-chat-id] :as db} [_ selection]]
|
||||||
|
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||||
|
command (input-model/selected-chat-command db current-chat-id input-text)]
|
||||||
|
(when (and (= selection (+ (count const/command-char)
|
||||||
|
(count (get-in command [:command :name]))
|
||||||
|
(count const/spacing-char)))
|
||||||
|
(get-in command [:command :sequential-params]))
|
||||||
|
(dispatch [:chat-input-focus :seq-input-ref]))
|
||||||
|
(dispatch [:set-chat-ui-props {:selection selection}])
|
||||||
|
(dispatch [:load-chat-parameter-box (:command command)])))))
|
||||||
|
|
||||||
|
(handlers/register-handler
|
||||||
|
: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])))))))
|
||||||
|
|
||||||
|
(handlers/register-handler
|
||||||
|
:select-next-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)]
|
||||||
|
(let [input-text (get-in db [:chats current-chat-id :input-text])
|
||||||
|
command-args (cond-> (input-model/split-command-args input-text)
|
||||||
|
(input-model/text-ends-with-space? input-text) (conj ""))
|
||||||
|
new-sel (->> command-args
|
||||||
|
(take (+ 3 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]))))))
|
|
@ -97,7 +97,7 @@
|
||||||
(assoc-in db [:chats chat-id :last-message] message)))
|
(assoc-in db [:chats chat-id :last-message] message)))
|
||||||
|
|
||||||
(defn commands-loaded? [db chat-id]
|
(defn commands-loaded? [db chat-id]
|
||||||
(get-in db [:contacts chat-id :commands-loaded]))
|
(get-in db [:contacts chat-id :commands-loaded?]))
|
||||||
|
|
||||||
(def timeout 400)
|
(def timeout 400)
|
||||||
|
|
||||||
|
|
|
@ -128,19 +128,22 @@
|
||||||
|
|
||||||
(register-handler ::invoke-command-handlers!
|
(register-handler ::invoke-command-handlers!
|
||||||
(u/side-effect!
|
(u/side-effect!
|
||||||
(fn [db [_ {:keys [chat-id address command-message]
|
(fn [{:keys [bot-db accounts current-account-id] :as db}
|
||||||
:as parameters}]]
|
[_ {:keys [chat-id address command-message]
|
||||||
|
:as parameters}]]
|
||||||
(let [{:keys [id command params]} command-message
|
(let [{:keys [id command params]} command-message
|
||||||
{:keys [type name bot]} command
|
{:keys [type name bot owner-id]} command
|
||||||
path [(if (= :command type) :commands :responses)
|
path [(if (= :command type) :commands :responses)
|
||||||
name
|
name
|
||||||
:handler]
|
:handler]
|
||||||
to (get-in db [:contacts chat-id :address])
|
to (get-in db [:contacts chat-id :address])
|
||||||
params {:parameters params
|
identity (or owner-id bot chat-id)
|
||||||
:context {:from address
|
bot-db (get bot-db (or bot chat-id))
|
||||||
:to to
|
params {:parameters (assoc params :bot-db bot-db)
|
||||||
:message-id id}}
|
:context {:from address
|
||||||
identity (or bot chat-id)]
|
:to to
|
||||||
|
:current-account (get accounts current-account-id)
|
||||||
|
:message-id id}}]
|
||||||
(dispatch
|
(dispatch
|
||||||
[:check-and-load-commands!
|
[:check-and-load-commands!
|
||||||
identity
|
identity
|
||||||
|
|
|
@ -26,29 +26,35 @@
|
||||||
(dec (count text)))))
|
(dec (count text)))))
|
||||||
|
|
||||||
(defn possible-chat-actions [{:keys [global-commands] :as db} chat-id]
|
(defn possible-chat-actions [{:keys [global-commands] :as db} chat-id]
|
||||||
(let [{:keys [requests]} (get-in db [:chats chat-id])
|
(let [{:keys [contacts requests]} (get-in db [:chats chat-id])]
|
||||||
{:keys [commands responses]} (get-in db [:contacts chat-id])
|
(->> contacts
|
||||||
|
(map (fn [{:keys [identity]}]
|
||||||
commands' (into {} (map (fn [[k v]] [k [v :any]]) (merge global-commands commands)))
|
(let [{:keys [commands responses]} (get-in db [:contacts identity])]
|
||||||
responses' (into {} (map (fn [{:keys [message-id type]}]
|
(let [commands' (mapv (fn [[k v]] [k [v :any]]) (merge global-commands commands))
|
||||||
[type [(get responses type) message-id]])
|
responses' (mapv (fn [{:keys [message-id type]}]
|
||||||
requests))]
|
[type [(get responses type) message-id]])
|
||||||
(vals (merge commands' responses'))))
|
requests)]
|
||||||
|
(into commands' responses')))))
|
||||||
|
(reduce (fn [m cur] (into (or m {}) cur)))
|
||||||
|
(into {})
|
||||||
|
(vals))))
|
||||||
|
|
||||||
(defn split-command-args [command-text]
|
(defn split-command-args [command-text]
|
||||||
(let [space? (text-ends-with-space? command-text)
|
(let [space? (text-ends-with-space? command-text)
|
||||||
command-text (if space?
|
command-text (if space?
|
||||||
(str command-text ".")
|
(str command-text ".")
|
||||||
command-text)
|
command-text)
|
||||||
command-text-normalized (if command-text (str/replace (str/trim command-text) #" +" " ") command-text)
|
command-text-normalized (if command-text
|
||||||
splitted (cond-> (str/split command-text-normalized const/spacing-char)
|
(str/replace (str/trim command-text) #" +" " ")
|
||||||
space? (drop-last))]
|
command-text)
|
||||||
|
splitted (cond-> (str/split command-text-normalized const/spacing-char)
|
||||||
|
space? (drop-last))]
|
||||||
(->> splitted
|
(->> splitted
|
||||||
(reduce (fn [[list command-started?] arg]
|
(reduce (fn [[list command-started?] arg]
|
||||||
(let [quotes-count (count (filter #(= % const/arg-wrapping-char) arg))
|
(let [quotes-count (count (filter #(= % const/arg-wrapping-char) arg))
|
||||||
has-quote? (and (= quotes-count 1)
|
has-quote? (and (= quotes-count 1)
|
||||||
(str/index-of arg const/arg-wrapping-char))
|
(str/index-of arg const/arg-wrapping-char))
|
||||||
arg (str/replace arg #"\"" "")
|
arg (str/replace arg (re-pattern const/arg-wrapping-char) "")
|
||||||
new-list (if command-started?
|
new-list (if command-started?
|
||||||
(let [index (dec (count list))]
|
(let [index (dec (count list))]
|
||||||
(update list index str const/spacing-char arg))
|
(update list index str const/spacing-char arg))
|
||||||
|
@ -92,27 +98,35 @@
|
||||||
([{:keys [current-chat-id] :as db} chat-id]
|
([{:keys [current-chat-id] :as db} chat-id]
|
||||||
(selected-chat-command db chat-id (get-in db [:chats chat-id :input-text]))))
|
(selected-chat-command db chat-id (get-in db [:chats chat-id :input-text]))))
|
||||||
|
|
||||||
|
(def *no-argument-error* -1)
|
||||||
|
|
||||||
(defn current-chat-argument-position
|
(defn current-chat-argument-position
|
||||||
[{:keys [args] :as command} input-text seq-arguments]
|
[{:keys [args] :as command} input-text selection seq-arguments]
|
||||||
(if command
|
(if command
|
||||||
(let [args-count (count args)]
|
(if (get-in command [:command :sequential-params])
|
||||||
(cond
|
(count seq-arguments)
|
||||||
(:sequential-params command)
|
(let [subs-input-text (subs input-text 0 selection)]
|
||||||
(count seq-arguments)
|
(if subs-input-text
|
||||||
|
(let [args (split-command-args subs-input-text)
|
||||||
(= (last input-text) const/spacing-char)
|
argument-index (dec (count args))
|
||||||
args-count
|
ends-with-space? (text-ends-with-space? subs-input-text)
|
||||||
|
arg-wrapping-count (-> (frequencies subs-input-text)
|
||||||
:default
|
(get const/arg-wrapping-char)
|
||||||
(dec args-count)))
|
(or 0))]
|
||||||
-1))
|
(if (and ends-with-space?
|
||||||
|
(even? arg-wrapping-count))
|
||||||
|
argument-index
|
||||||
|
(dec argument-index)))
|
||||||
|
*no-argument-error*)))
|
||||||
|
*no-argument-error*))
|
||||||
|
|
||||||
(defn argument-position [{:keys [current-chat-id] :as db} chat-id]
|
(defn argument-position [{:keys [current-chat-id] :as db} chat-id]
|
||||||
(let [chat-id (or chat-id current-chat-id)
|
(let [chat-id (or chat-id current-chat-id)
|
||||||
input-text (get-in db [:chats chat-id :input-text])
|
input-text (get-in db [:chats chat-id :input-text])
|
||||||
seq-arguments (get-in db [:chats chat-id :seq-arguments])
|
seq-arguments (get-in db [:chats chat-id :seq-arguments])
|
||||||
|
selection (get-in db [:chat-ui-props chat-id :selection])
|
||||||
chat-command (selected-chat-command db chat-id)]
|
chat-command (selected-chat-command db chat-id)]
|
||||||
(current-chat-argument-position chat-command input-text seq-arguments)))
|
(current-chat-argument-position chat-command input-text selection seq-arguments)))
|
||||||
|
|
||||||
(defn command-completion
|
(defn command-completion
|
||||||
([{:keys [current-chat-id] :as db} chat-id]
|
([{:keys [current-chat-id] :as db} chat-id]
|
||||||
|
@ -189,4 +203,4 @@
|
||||||
(str
|
(str
|
||||||
command
|
command
|
||||||
const/spacing-char
|
const/spacing-char
|
||||||
(str/join const/spacing-char new-args))))
|
(join-command-args new-args))))
|
|
@ -28,10 +28,16 @@
|
||||||
|
|
||||||
(defn get-command-suggestions
|
(defn get-command-suggestions
|
||||||
[{:keys [current-chat-id] :as db} text]
|
[{:keys [current-chat-id] :as db} text]
|
||||||
(let [commands (get-in db [:contacts current-chat-id :commands])]
|
(->> (get-in db [:chats current-chat-id :contacts])
|
||||||
(filter (fn [[_ v]] ((can-be-suggested? text) v)) commands)))
|
(map (fn [{:keys [identity]}]
|
||||||
|
(let [commands (get-in db [:contacts identity :commands])]
|
||||||
|
(->> commands
|
||||||
|
(filter (fn [[_ v]] ((can-be-suggested? text) v)))))))
|
||||||
|
(reduce (fn [m cur] (into (or m {}) cur)))
|
||||||
|
(into {})))
|
||||||
|
|
||||||
(defn get-global-command-suggestions
|
(defn get-global-command-suggestions
|
||||||
[{:keys [global-commands] :as db} text]
|
[{:keys [global-commands] :as db} text]
|
||||||
(filter (fn [[_ v]] ((can-be-suggested? chat-consts/bot-char :bot text) v))
|
(->> global-commands
|
||||||
global-commands))
|
(filter (fn [[_ v]] ((can-be-suggested? chat-consts/bot-char :bot text) v)))
|
||||||
|
(into {})))
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
(ns status-im.chat.styles.input.box-header
|
||||||
|
(:require [status-im.components.styles :as common]))
|
||||||
|
|
||||||
|
(def header-height 33)
|
||||||
|
|
||||||
|
(def header-container
|
||||||
|
{:background-color common/color-white
|
||||||
|
:alignItems :center
|
||||||
|
:justifyContent :center
|
||||||
|
:height header-height})
|
||||||
|
|
||||||
|
(def header-title-container
|
||||||
|
{:flex-direction :row
|
||||||
|
:height header-height
|
||||||
|
:border-bottom-color "rgba(193, 199, 203, 0.28)"
|
||||||
|
:border-bottom-width 1})
|
||||||
|
|
||||||
|
(defn header-title-text [back?]
|
||||||
|
{:color common/color-black
|
||||||
|
:flex 1
|
||||||
|
:font-size 15
|
||||||
|
:text-align :center
|
||||||
|
:padding-top 0
|
||||||
|
:margin-left (if back? 32 72)
|
||||||
|
:margin-right 32})
|
||||||
|
|
||||||
|
(def header-back-container
|
||||||
|
{:width 24
|
||||||
|
:height 24
|
||||||
|
:margin-left 16
|
||||||
|
:top -4})
|
||||||
|
|
||||||
|
(def header-close-container
|
||||||
|
{:width 24
|
||||||
|
:height 24
|
||||||
|
:margin-right 16
|
||||||
|
:top -4})
|
||||||
|
|
||||||
|
(def header-icon
|
||||||
|
{:width 24
|
||||||
|
:height 24})
|
|
@ -15,31 +15,3 @@
|
||||||
:bottom bottom
|
:bottom bottom
|
||||||
:position :absolute})
|
:position :absolute})
|
||||||
|
|
||||||
(def header-container
|
|
||||||
{:background-color common/color-white
|
|
||||||
:alignItems :center
|
|
||||||
:justifyContent :center
|
|
||||||
:height 35})
|
|
||||||
|
|
||||||
(def header-title-container
|
|
||||||
{:margin-bottom 15
|
|
||||||
:flex-direction :row})
|
|
||||||
|
|
||||||
(def header-title-text
|
|
||||||
{:color common/color-black
|
|
||||||
:flex 1
|
|
||||||
:font-size 15
|
|
||||||
:text-align :center
|
|
||||||
:padding-top 1
|
|
||||||
:margin-left 72
|
|
||||||
:margin-right 32})
|
|
||||||
|
|
||||||
(def header-close-container
|
|
||||||
{:width 24
|
|
||||||
:height 24
|
|
||||||
:margin-right 16
|
|
||||||
:top -3})
|
|
||||||
|
|
||||||
(def header-close-icon
|
|
||||||
{:width 24
|
|
||||||
:height 24})
|
|
||||||
|
|
|
@ -70,6 +70,18 @@
|
||||||
(let [current-chat (or chat-id (@db :current-chat-id))]
|
(let [current-chat (or chat-id (@db :current-chat-id))]
|
||||||
(reaction (or (get-in @db [:contacts current-chat :responses]) {})))))
|
(reaction (or (get-in @db [:contacts current-chat :responses]) {})))))
|
||||||
|
|
||||||
|
(register-sub
|
||||||
|
:get-commands-and-responses
|
||||||
|
(fn [db [_ chat-id]]
|
||||||
|
(reaction
|
||||||
|
(let [{:keys [chats contacts]} @db]
|
||||||
|
(->> (get-in chats [chat-id :contacts])
|
||||||
|
(filter :is-in-chat)
|
||||||
|
(mapv (fn [{:keys [identity]}]
|
||||||
|
(let [{:keys [commands responses]} (get contacts identity)]
|
||||||
|
(merge responses commands))))
|
||||||
|
(apply merge))))))
|
||||||
|
|
||||||
(register-sub
|
(register-sub
|
||||||
:possible-chat-actions
|
:possible-chat-actions
|
||||||
(fn [db [_ chat-id]]
|
(fn [db [_ chat-id]]
|
||||||
|
@ -92,9 +104,10 @@
|
||||||
(fn [db]
|
(fn [db]
|
||||||
(let [command (subscribe [:selected-chat-command])
|
(let [command (subscribe [:selected-chat-command])
|
||||||
input-text (subscribe [:chat :input-text])
|
input-text (subscribe [:chat :input-text])
|
||||||
seq-arguments (subscribe [:chat :seq-arguments])]
|
seq-arguments (subscribe [:chat :seq-arguments])
|
||||||
|
selection (subscribe [:chat-ui-props :selection])]
|
||||||
(reaction
|
(reaction
|
||||||
(input-model/current-chat-argument-position @command @input-text @seq-arguments)))))
|
(input-model/current-chat-argument-position @command @input-text @selection @seq-arguments)))))
|
||||||
|
|
||||||
(register-sub
|
(register-sub
|
||||||
:chat-parameter-box
|
:chat-parameter-box
|
||||||
|
@ -104,7 +117,7 @@
|
||||||
index (subscribe [:current-chat-argument-position])]
|
index (subscribe [:current-chat-argument-position])]
|
||||||
(reaction
|
(reaction
|
||||||
(cond
|
(cond
|
||||||
(and @command (> @index -1))
|
(and @command (not= @index input-model/*no-argument-error*))
|
||||||
(let [command-name (get-in @command [:command :name])]
|
(let [command-name (get-in @command [:command :name])]
|
||||||
(get-in @db [:chats @chat-id :parameter-boxes command-name @index]))
|
(get-in @db [:chats @chat-id :parameter-boxes command-name @index]))
|
||||||
|
|
||||||
|
@ -188,8 +201,10 @@
|
||||||
(fn [db [_ chat-id]]
|
(fn [db [_ chat-id]]
|
||||||
(reaction
|
(reaction
|
||||||
(let [{:keys [last-message messages]} (get-in @db [:chats chat-id])]
|
(let [{:keys [last-message messages]} (get-in @db [:chats chat-id])]
|
||||||
(first
|
(->> (conj messages last-message)
|
||||||
(sort-by :clock-value > (conj messages last-message)))))))
|
(sort-by :clock-value >)
|
||||||
|
(filter :show?)
|
||||||
|
(first))))))
|
||||||
|
|
||||||
(register-sub :get-last-message-short-preview
|
(register-sub :get-last-message-short-preview
|
||||||
(fn [db [_ chat-id]]
|
(fn [db [_ chat-id]]
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
(ns status-im.chat.views.choosers.choose-contact
|
||||||
|
(:require-macros [status-im.utils.views :refer [defview]])
|
||||||
|
(:require [reagent.core :as r]
|
||||||
|
[re-frame.core :refer [dispatch subscribe]]
|
||||||
|
[clojure.string :as str]
|
||||||
|
[status-im.chat.constants :as const]
|
||||||
|
[status-im.components.react :refer [view
|
||||||
|
text
|
||||||
|
list-view
|
||||||
|
list-item]]
|
||||||
|
[status-im.components.contact.contact :refer [contact-view]]
|
||||||
|
[status-im.components.renderers.renderers :as renderers]
|
||||||
|
[status-im.utils.listview :as lw]))
|
||||||
|
|
||||||
|
(defn- select-contact [arg-index bot-db-key {:keys [name] :as contact}]
|
||||||
|
(let [contact (select-keys contact [:address :whisper-identity :name :photo-path :dapp?])
|
||||||
|
name (str/replace name (re-pattern const/arg-wrapping-char) "")]
|
||||||
|
(dispatch [:set-command-argument [arg-index name true]])
|
||||||
|
(dispatch [:set-in-bot-db {:path [:public (keyword bot-db-key)]
|
||||||
|
:value contact}])
|
||||||
|
(dispatch [:select-next-argument])))
|
||||||
|
|
||||||
|
(defn render-row [arg-index bot-db-key]
|
||||||
|
(fn [contact _ _]
|
||||||
|
(list-item
|
||||||
|
^{:key contact}
|
||||||
|
[contact-view {:contact contact
|
||||||
|
:on-press #(select-contact arg-index bot-db-key contact)}])))
|
||||||
|
|
||||||
|
(defview choose-contact-view [{title :title
|
||||||
|
arg-index :index
|
||||||
|
bot-db-key :bot-db-key}]
|
||||||
|
[contacts [:contacts-filtered :people-in-current-chat]]
|
||||||
|
[view {:flex 1}
|
||||||
|
[text {:style {:font-size 14
|
||||||
|
:color "rgb(147, 155, 161)"
|
||||||
|
:padding-top 12
|
||||||
|
:padding-left 16
|
||||||
|
:padding-right 16
|
||||||
|
:padding-bottom 12}}
|
||||||
|
title]
|
||||||
|
[list-view {:dataSource (lw/to-datasource contacts)
|
||||||
|
:enableEmptySections true
|
||||||
|
:renderRow (render-row arg-index bot-db-key)
|
||||||
|
:bounces false
|
||||||
|
:keyboardShouldPersistTaps :always
|
||||||
|
:renderSeparator renderers/list-separator-renderer}]])
|
|
@ -0,0 +1,39 @@
|
||||||
|
(ns status-im.chat.views.input.box-header
|
||||||
|
(:require-macros [status-im.utils.views :refer [defview]])
|
||||||
|
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||||
|
[status-im.components.react :refer [view
|
||||||
|
touchable-highlight
|
||||||
|
text
|
||||||
|
icon]]
|
||||||
|
[status-im.chat.styles.input.box-header :as style]
|
||||||
|
[taoensso.timbre :as log]))
|
||||||
|
|
||||||
|
(defn get-header [type]
|
||||||
|
(fn []
|
||||||
|
(let [parameter-box (subscribe [:chat-parameter-box])
|
||||||
|
result-box (subscribe [:chat-ui-props :result-box])
|
||||||
|
chat-id (subscribe [:get-current-chat-id])
|
||||||
|
command (subscribe [:selected-chat-command])
|
||||||
|
index (subscribe [:current-chat-argument-position])]
|
||||||
|
(fn []
|
||||||
|
(let [{:keys [showBack title]} (if (= type :parameter-box)
|
||||||
|
@parameter-box
|
||||||
|
@result-box)]
|
||||||
|
[view {:style style/header-container}
|
||||||
|
[view style/header-title-container
|
||||||
|
(when showBack
|
||||||
|
[touchable-highlight {:on-press #(dispatch [:select-prev-argument])}
|
||||||
|
[view style/header-back-container
|
||||||
|
[icon :back_gray style/header-icon]]])
|
||||||
|
[text {:style (style/header-title-text showBack)
|
||||||
|
:number-of-lines 1
|
||||||
|
:font :medium}
|
||||||
|
title]
|
||||||
|
[touchable-highlight
|
||||||
|
{:on-press (fn []
|
||||||
|
(if (= type :parameter-box)
|
||||||
|
(let [command-name (get-in @command [:command :name])]
|
||||||
|
(dispatch [:set-in [:chats @chat-id :parameter-boxes command-name @index] nil]))
|
||||||
|
(dispatch [:set-chat-ui-props {:result-box nil}])))}
|
||||||
|
[view style/header-close-container
|
||||||
|
[icon :close_light_gray style/header-icon]]]]])))))
|
|
@ -64,6 +64,7 @@
|
||||||
command (subscribe [:selected-chat-command])
|
command (subscribe [:selected-chat-command])
|
||||||
sending-in-progress? (subscribe [:chat-ui-props :sending-in-progress?])
|
sending-in-progress? (subscribe [:chat-ui-props :sending-in-progress?])
|
||||||
input-focused? (subscribe [:chat-ui-props :input-focused?])
|
input-focused? (subscribe [:chat-ui-props :input-focused?])
|
||||||
|
prev-command (subscribe [:chat-ui-props :prev-command])
|
||||||
input-ref (atom nil)]
|
input-ref (atom nil)]
|
||||||
(fn [{:keys [set-layout-height set-container-width height single-line-input?]}]
|
(fn [{:keys [set-layout-height set-container-width height single-line-input?]}]
|
||||||
[text-input
|
[text-input
|
||||||
|
@ -94,23 +95,26 @@
|
||||||
(dispatch [:set-chat-input-text text])
|
(dispatch [:set-chat-input-text text])
|
||||||
(if @command
|
(if @command
|
||||||
(do
|
(do
|
||||||
|
(when (not= @prev-command (-> @command :command :name))
|
||||||
|
(dispatch [:clear-bot-db @command]))
|
||||||
(dispatch [:load-chat-parameter-box (:command @command)])
|
(dispatch [:load-chat-parameter-box (:command @command)])
|
||||||
(dispatch [:set-chat-ui-props {:validation-messages nil}]))
|
(dispatch [:set-chat-ui-props {:validation-messages nil}]))
|
||||||
(do
|
(do
|
||||||
(dispatch [:set-chat-input-metadata nil])
|
(dispatch [:set-chat-input-metadata nil])
|
||||||
(dispatch [:set-chat-ui-props {:result-box nil
|
(dispatch [:set-chat-ui-props
|
||||||
:validation-messages nil}]))))))
|
{:result-box nil
|
||||||
|
:validation-messages nil
|
||||||
|
:prev-command (-> @command :command :name)}]))))))
|
||||||
:on-content-size-change (when (and (not @input-focused?)
|
:on-content-size-change (when (and (not @input-focused?)
|
||||||
(not single-line-input?))
|
(not single-line-input?))
|
||||||
#(let [h (-> (.-nativeEvent %)
|
#(let [h (-> (.-nativeEvent %)
|
||||||
(.-contentSize)
|
(.-contentSize)
|
||||||
(.-height))]
|
(.-height))]
|
||||||
(set-layout-height h)))
|
(set-layout-height h)))
|
||||||
:on-selection-change #(let [s (-> (.-nativeEvent %)
|
:on-selection-change #(let [s (-> (.-nativeEvent %)
|
||||||
(.-selection))]
|
(.-selection))
|
||||||
(when (and (= (.-end s) (+ 2 (count (get-in @command [:command :name]))))
|
end (.-end s)]
|
||||||
(get-in @command [:command :sequential-params]))
|
(dispatch [:update-text-selection end]))
|
||||||
(dispatch [:chat-input-focus :seq-input-ref])))
|
|
||||||
:style (style/input-view height single-line-input?)
|
:style (style/input-view height single-line-input?)
|
||||||
:placeholder-text-color style/color-input-helper-placeholder
|
:placeholder-text-color style/color-input-helper-placeholder
|
||||||
:auto-capitalize :sentences}])))
|
:auto-capitalize :sentences}])))
|
||||||
|
|
|
@ -1,27 +1,23 @@
|
||||||
(ns status-im.chat.views.input.parameter-box
|
(ns status-im.chat.views.input.parameter-box
|
||||||
(:require-macros [status-im.utils.views :refer [defview]])
|
(:require-macros [status-im.utils.views :refer [defview]])
|
||||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||||
[status-im.components.react :refer [view
|
|
||||||
scroll-view
|
|
||||||
touchable-highlight
|
|
||||||
text
|
|
||||||
icon]]
|
|
||||||
[status-im.chat.views.input.animations.expandable :refer [expandable-view]]
|
[status-im.chat.views.input.animations.expandable :refer [expandable-view]]
|
||||||
[status-im.chat.views.input.utils :as input-utils]
|
[status-im.chat.views.input.box-header :as box-header]
|
||||||
[status-im.commands.utils :as command-utils]
|
[status-im.commands.utils :as command-utils]
|
||||||
[status-im.i18n :refer [label]]
|
[taoensso.timbre :as log]))
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[clojure.string :as str]))
|
|
||||||
|
|
||||||
(defview parameter-box-container []
|
(defview parameter-box-container []
|
||||||
[parameter-box [:chat-parameter-box]
|
[{:keys [markup]} [:chat-parameter-box]
|
||||||
bot-db [:current-bot-db]]
|
bot-db [:current-bot-db]]
|
||||||
(when (:hiccup parameter-box)
|
(when markup
|
||||||
(command-utils/generate-hiccup (:hiccup parameter-box) bot-db)))
|
(command-utils/generate-hiccup markup bot-db)))
|
||||||
|
|
||||||
(defview parameter-box-view []
|
(defview parameter-box-view []
|
||||||
[show-parameter-box? [:show-parameter-box?]]
|
[show-parameter-box? [:show-parameter-box?]
|
||||||
|
{:keys [title]} [:chat-parameter-box]]
|
||||||
(when show-parameter-box?
|
(when show-parameter-box?
|
||||||
[expandable-view {:key :parameter-box
|
[expandable-view {:key :parameter-box
|
||||||
:draggable? true}
|
:draggable? true
|
||||||
|
:custom-header (when title
|
||||||
|
(box-header/get-header :parameter-box))}
|
||||||
[parameter-box-container]]))
|
[parameter-box-container]]))
|
||||||
|
|
|
@ -7,23 +7,8 @@
|
||||||
text
|
text
|
||||||
icon]]
|
icon]]
|
||||||
[status-im.chat.views.input.animations.expandable :refer [expandable-view]]
|
[status-im.chat.views.input.animations.expandable :refer [expandable-view]]
|
||||||
[status-im.chat.styles.input.result-box :as style]
|
[status-im.chat.views.input.box-header :as box-header]
|
||||||
[status-im.chat.views.input.utils :as input-utils]
|
[status-im.components.sync-state.offline :refer [offline-view]]))
|
||||||
[status-im.components.sync-state.offline :refer [offline-view]]
|
|
||||||
[status-im.i18n :refer [label]]
|
|
||||||
[taoensso.timbre :as log]))
|
|
||||||
|
|
||||||
(defview header []
|
|
||||||
[{:keys [title]} [:chat-ui-props :result-box]]
|
|
||||||
[view {:style style/header-container}
|
|
||||||
[view style/header-title-container
|
|
||||||
[text {:style style/header-title-text
|
|
||||||
:number-of-lines 1
|
|
||||||
:font :medium}
|
|
||||||
title]
|
|
||||||
[touchable-highlight {:on-press #(dispatch [:set-chat-ui-props {:result-box nil}])}
|
|
||||||
[view style/header-close-container
|
|
||||||
[icon :close_light_gray style/header-close-icon]]]]])
|
|
||||||
|
|
||||||
(defview result-box-container [markup]
|
(defview result-box-container [markup]
|
||||||
[view {:flex 1}
|
[view {:flex 1}
|
||||||
|
@ -34,6 +19,6 @@
|
||||||
(when result-box
|
(when result-box
|
||||||
[expandable-view {:key :result-box
|
[expandable-view {:key :result-box
|
||||||
:draggable? true
|
:draggable? true
|
||||||
:custom-header header}
|
:custom-header (box-header/get-header :result-box)}
|
||||||
[result-box-container markup]
|
[result-box-container markup]
|
||||||
[offline-view]]))
|
[offline-view]]))
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
(let [{:strs [loading url title canGoBack canGoForward]} (js->clj event)]
|
(let [{:strs [loading url title canGoBack canGoForward]} (js->clj event)]
|
||||||
(when-not (= "about:blank" url)
|
(when-not (= "about:blank" url)
|
||||||
(when-not loading
|
(when-not loading
|
||||||
(dispatch [:set-command-argument [0 url]]))
|
(dispatch [:set-command-argument [0 url false]]))
|
||||||
(let [result-box (assoc result-box :can-go-back? canGoBack :can-go-forward? canGoForward)
|
(let [result-box (assoc result-box :can-go-back? canGoBack :can-go-forward? canGoForward)
|
||||||
result-box (if (and dynamicTitle (not (str/blank? title)))
|
result-box (if (and dynamicTitle (not (str/blank? title)))
|
||||||
(assoc result-box :title title)
|
(assoc result-box :title title)
|
||||||
|
@ -48,4 +48,5 @@
|
||||||
:on-navigation-state-change #(on-navigation-change % result-box)
|
:on-navigation-state-change #(on-navigation-change % result-box)
|
||||||
:local-storage-enabled true
|
:local-storage-enabled true
|
||||||
:start-in-loading-state true
|
:start-in-loading-state true
|
||||||
:render-loading #(r/as-element [components/activity-indicator {:animating true}])}]))
|
:render-loading #(r/as-element [view {:padding-top 16}
|
||||||
|
[components/activity-indicator {:animating true}]])}]))
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
(ns status-im.chat.views.message.message
|
(ns status-im.chat.views.message.message
|
||||||
(:require-macros [status-im.utils.views :refer [defview]])
|
(:require-macros [status-im.utils.views :refer [defview]])
|
||||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||||
|
[clojure.walk :as walk]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
[status-im.i18n :refer [message-status-label]]
|
[status-im.i18n :refer [message-status-label]]
|
||||||
[status-im.components.react :refer [view
|
[status-im.components.react :refer [view
|
||||||
|
@ -93,15 +94,13 @@
|
||||||
(defn wallet-command-preview
|
(defn wallet-command-preview
|
||||||
[{{:keys [name]} :contact-chat
|
[{{:keys [name]} :contact-chat
|
||||||
:keys [contact-address params outgoing? current-chat-id]}]
|
:keys [contact-address params outgoing? current-chat-id]}]
|
||||||
(let [amount (if (= 1 (count params))
|
(let [{:keys [recipient amount]} (walk/keywordize-keys params)]
|
||||||
(first (vals params))
|
|
||||||
(str params))]
|
|
||||||
[text {:style st/command-text
|
[text {:style st/command-text
|
||||||
:font :default}
|
:font :default}
|
||||||
(if (= current-chat-id wallet-chat-id)
|
(if (= current-chat-id wallet-chat-id)
|
||||||
(let [label-val (if outgoing? :t/chat-send-eth-to :t/chat-send-eth-from)]
|
(let [label-val (if outgoing? :t/chat-send-eth-to :t/chat-send-eth-from)]
|
||||||
(label label-val {:amount amount
|
(label label-val {:amount amount
|
||||||
:chat-name (or name contact-address)}))
|
:chat-name (or name contact-address recipient)}))
|
||||||
(label :t/chat-send-eth {:amount amount}))]))
|
(label :t/chat-send-eth {:amount amount}))]))
|
||||||
|
|
||||||
(defn wallet-command? [content-type]
|
(defn wallet-command? [content-type]
|
||||||
|
@ -122,18 +121,21 @@
|
||||||
(first (vals params))
|
(first (vals params))
|
||||||
(str params))]))
|
(str params))]))
|
||||||
|
|
||||||
|
(defn commands-subscription [{:keys [type]}]
|
||||||
|
(if (= type "response")
|
||||||
|
:get-responses
|
||||||
|
:get-commands))
|
||||||
|
|
||||||
(defview message-content-command
|
(defview message-content-command
|
||||||
[{:keys [message-id content content-type chat-id to from outgoing] :as message}]
|
[{:keys [message-id content content-type chat-id to from outgoing] :as message}]
|
||||||
[commands [(if (= (:type content) "response")
|
[commands [:get-commands-and-responses chat-id]
|
||||||
:get-responses
|
from-commands [:get-commands-and-responses from]
|
||||||
:get-commands)
|
|
||||||
chat-id]
|
|
||||||
global-commands [:get :global-commands]
|
global-commands [:get :global-commands]
|
||||||
current-chat-id [:get-current-chat-id]
|
current-chat-id [:get-current-chat-id]
|
||||||
contact-chat [:get-in [:chats (if outgoing to from)]]
|
contact-chat [:get-in [:chats (if outgoing to from)]]
|
||||||
preview [:get-in [:message-data :preview message-id :markup]]]
|
preview [:get-in [:message-data :preview message-id :markup]]]
|
||||||
(let [{:keys [command params]}
|
(let [commands (merge commands from-commands)
|
||||||
(parse-command-message-content commands global-commands content)
|
{:keys [command params]} (parse-command-message-content commands global-commands content)
|
||||||
{:keys [name type]
|
{:keys [name type]
|
||||||
icon-path :icon} command]
|
icon-path :icon} command]
|
||||||
[view st/content-command-view
|
[view st/content-command-view
|
||||||
|
|
|
@ -70,19 +70,20 @@
|
||||||
[icon command-icon st/command-request-image])]]))})))
|
[icon command-icon st/command-request-image])]]))})))
|
||||||
|
|
||||||
(defn message-content-command-request
|
(defn message-content-command-request
|
||||||
[{:keys [message-id _ _ _]}]
|
[{:keys [message-id chat-id]}]
|
||||||
(let [commands-atom (subscribe [:get-responses])
|
(let [commands-atom (subscribe [:get-commands-and-responses chat-id])
|
||||||
answered? (subscribe [:is-request-answered? message-id])
|
answered? (subscribe [:is-request-answered? message-id])
|
||||||
status-initialized? (subscribe [:get :status-module-initialized?])
|
status-initialized? (subscribe [:get :status-module-initialized?])
|
||||||
markup (subscribe [:get-in [:message-data :preview message-id :markup]])]
|
markup (subscribe [:get-in [:message-data :preview message-id :markup]])]
|
||||||
(fn [{:keys [message-id content from incoming-group]}]
|
(fn [{:keys [message-id content from incoming-group]}]
|
||||||
(let [commands @commands-atom
|
(let [commands @commands-atom
|
||||||
params (:params content)
|
{:keys [prefill prefillBotDb params]
|
||||||
text-content (:text content)
|
text-content :text} content
|
||||||
{:keys [command content]} (parse-command-request commands content)
|
{:keys [command content]} (parse-command-request commands content)
|
||||||
command (if (and params command)
|
command (if (and params command)
|
||||||
(merge command {:prefill (vals params)})
|
(merge command {:prefill prefill
|
||||||
command)]
|
:prefill-bot-db prefillBotDb})
|
||||||
|
command)]
|
||||||
[view st/comand-request-view
|
[view st/comand-request-view
|
||||||
[touchable-highlight
|
[touchable-highlight
|
||||||
{:on-press (when (and (not @answered?) @status-initialized?)
|
{:on-press (when (and (not @answered?) @status-initialized?)
|
||||||
|
|
|
@ -38,15 +38,14 @@
|
||||||
|
|
||||||
(defn suggestions-handler!
|
(defn suggestions-handler!
|
||||||
[{:keys [contacts chats] :as db} [{:keys [chat-id default-db command parameter-index result]}]]
|
[{:keys [contacts chats] :as db} [{:keys [chat-id default-db command parameter-index result]}]]
|
||||||
(let [returned (get-in result [:result :returned])
|
(let [{:keys [markup] :as returned} (get-in result [:result :returned])
|
||||||
contains-markup? (contains? returned :markup)
|
contains-markup? (contains? returned :markup)
|
||||||
markup (get returned :markup)
|
path (if command
|
||||||
{:keys [dapp? dapp-url]} (get contacts chat-id)
|
[:chats chat-id :parameter-boxes (:name command) parameter-index]
|
||||||
path (if command
|
[:chats chat-id :parameter-boxes :message])]
|
||||||
[:chats chat-id :parameter-boxes (:name command) parameter-index]
|
(dispatch [:choose-predefined-expandable-height :parameter-box :default])
|
||||||
[:chats chat-id :parameter-boxes :message])]
|
|
||||||
(when (and contains-markup? (not= (get-in db path) markup))
|
(when (and contains-markup? (not= (get-in db path) markup))
|
||||||
(dispatch [:set-in path (when markup {:hiccup markup})])
|
(dispatch [:set-in path returned])
|
||||||
(when default-db
|
(when default-db
|
||||||
(dispatch [:update-bot-db {:bot chat-id
|
(dispatch [:update-bot-db {:bot chat-id
|
||||||
:db default-db}])))))
|
:db default-db}])))))
|
||||||
|
@ -56,17 +55,27 @@
|
||||||
(log/debug "Suggestion event: " n (first data) val)
|
(log/debug "Suggestion event: " n (first data) val)
|
||||||
(let [{:keys [dapp?]} (get-in db [:contacts current-chat-id])]
|
(let [{:keys [dapp?]} (get-in db [:contacts current-chat-id])]
|
||||||
(case (keyword n)
|
(case (keyword n)
|
||||||
:set-command-argument (dispatch [:set-command-argument (first data)])
|
:set-command-argument
|
||||||
:set-value (dispatch [:set-chat-input-text (first data)])
|
(let [[index value move-to-next?] (first data)]
|
||||||
:set (let [opts {:bot current-chat-id
|
(dispatch [:set-command-argument [index value move-to-next?]]))
|
||||||
:path (mapv keyword data)
|
:set-value
|
||||||
:value val}]
|
(dispatch [:set-chat-input-text (first data)])
|
||||||
(dispatch [:set-in-bot-db opts]))
|
:set
|
||||||
|
(let [opts {:bot current-chat-id
|
||||||
|
:path (mapv keyword data)
|
||||||
|
:value val}]
|
||||||
|
(dispatch [:set-in-bot-db opts]))
|
||||||
|
:set-command-argument-from-db
|
||||||
|
(let [[index arg move-to-next?] (first data)
|
||||||
|
path (keyword arg)
|
||||||
|
value (str (get-in bot-db [current-chat-id path]))]
|
||||||
|
(dispatch [:set-command-argument [index value move-to-next?]]))
|
||||||
:set-value-from-db
|
:set-value-from-db
|
||||||
(let [path (keyword (first data))
|
(let [path (keyword (first data))
|
||||||
value (str (get-in bot-db [current-chat-id path]))]
|
value (str (get-in bot-db [current-chat-id path]))]
|
||||||
(dispatch [:set-chat-input-text value]))
|
(dispatch [:set-chat-input-text value]))
|
||||||
;; todo show error?
|
:focus-input
|
||||||
|
(dispatch [:chat-input-focus :input-ref])
|
||||||
nil)))
|
nil)))
|
||||||
|
|
||||||
(defn print-error-message! [message]
|
(defn print-error-message! [message]
|
||||||
|
|
|
@ -17,26 +17,23 @@
|
||||||
[status-im.chat.sign-up :as sign-up]
|
[status-im.chat.sign-up :as sign-up]
|
||||||
[status-im.bots.constants :as bots-constants]
|
[status-im.bots.constants :as bots-constants]
|
||||||
[status-im.utils.datetime :as time]
|
[status-im.utils.datetime :as time]
|
||||||
[status-im.data-store.local-storage :as local-storage]))
|
[status-im.data-store.local-storage :as local-storage]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
|
||||||
|
|
||||||
(defn load-commands!
|
(defn load-commands!
|
||||||
[{:keys [current-chat-id contacts]} [contact callback]]
|
[{:keys [current-chat-id contacts chats]} [jail-id callback]]
|
||||||
(let [whole-contact? (map? contact)
|
(let [identity (or jail-id current-chat-id)
|
||||||
{:keys [whisper-identity]} contact
|
contact-ids (if (get contacts identity)
|
||||||
identity' (or whisper-identity contact current-chat-id)
|
[identity]
|
||||||
contact' (if whole-contact?
|
(->> (get-in chats [identity :contacts])
|
||||||
contact
|
(map :identity)
|
||||||
(or (get contacts identity')
|
(into [])))]
|
||||||
sign-up/console-contact))]
|
(when (seq contacts)
|
||||||
(when identity'
|
(doseq [contact-id contact-ids]
|
||||||
(dispatch [::fetch-commands! {:contact contact'
|
(when-let [contact (get contacts contact-id)]
|
||||||
:callback callback}])))
|
(dispatch [::fetch-commands! {:contact contact
|
||||||
;; todo uncomment
|
:callback callback}]))))))
|
||||||
#_(if-let [{:keys [file]} (commands/get-by-chat-id contact)]
|
|
||||||
(dispatch [::parse-commands! contact file])
|
|
||||||
(dispatch [::fetch-commands! contact])))
|
|
||||||
|
|
||||||
|
|
||||||
(defn http-get-commands [params url]
|
(defn http-get-commands [params url]
|
||||||
(http-get url
|
(http-get url
|
||||||
|
@ -48,14 +45,18 @@
|
||||||
|
|
||||||
|
|
||||||
(defn fetch-commands!
|
(defn fetch-commands!
|
||||||
[_ [{{:keys [dapp? dapp-url bot-url whisper-identity]} :contact
|
[_ [{{:keys [whisper-identity
|
||||||
:as params}]]
|
dapp-url
|
||||||
(if
|
bot-url
|
||||||
bot-url
|
dapp?]} :contact
|
||||||
|
:as params}]]
|
||||||
|
(if bot-url
|
||||||
(if-let [resource (js-res/get-resource bot-url)]
|
(if-let [resource (js-res/get-resource bot-url)]
|
||||||
(dispatch [::validate-hash params resource])
|
(dispatch [::validate-hash params resource])
|
||||||
(http-get-commands params bot-url))
|
(http-get-commands params bot-url))
|
||||||
(dispatch [::validate-hash params js-res/commands-js])))
|
(when-not dapp?
|
||||||
|
;; TODO: this part should be removed in the future
|
||||||
|
(dispatch [::validate-hash params js-res/wallet-js]))))
|
||||||
|
|
||||||
(defn dispatch-loaded!
|
(defn dispatch-loaded!
|
||||||
[db [{{:keys [whisper-identity]} :contact
|
[db [{{:keys [whisper-identity]} :contact
|
||||||
|
@ -98,21 +99,25 @@
|
||||||
(get-hash-by-file file))]
|
(get-hash-by-file file))]
|
||||||
(assoc db ::valid-hash valid?)))
|
(assoc db ::valid-hash valid?)))
|
||||||
|
|
||||||
(defn mark-as [as coll]
|
(defn each-merge [coll with]
|
||||||
(->> coll
|
(->> coll
|
||||||
(map (fn [[k v]] [k (assoc v :type as)]))
|
(map (fn [[k v]] [k (merge v with)]))
|
||||||
(into {})))
|
(into {})))
|
||||||
|
|
||||||
(defn filter-forbidden-names [account id commands]
|
(defn filter-commands [account {:keys [contacts chat-id] :as chat} commands]
|
||||||
(->> commands
|
(->> commands
|
||||||
(remove (fn [[_ {:keys [registered-only name]}]]
|
(remove (fn [[_ {:keys [registered-only name]}]]
|
||||||
(and (not (:address account))
|
(and (not (:address account))
|
||||||
(not= name "global")
|
(not= name "global")
|
||||||
registered-only)))
|
registered-only)))
|
||||||
(remove (fn [[n]]
|
;; TODO: this part should be removed because it's much better to provide the ability to do this in the API
|
||||||
(and
|
(map (fn [[k {:keys [name] :as v}]]
|
||||||
(not= console-chat-id id)
|
[k (assoc v :hidden? (and (some #{name} ["send" "request"])
|
||||||
(h/matches (name n) "password"))))
|
(= chat-id wallet-chat-id)))]))
|
||||||
|
(remove (fn [[k _]]
|
||||||
|
(and (= (count contacts) 1)
|
||||||
|
(not= console-chat-id (get (first contacts) :identity))
|
||||||
|
(h/matches (name k) "password"))))
|
||||||
(into {})))
|
(into {})))
|
||||||
|
|
||||||
(defn get-mailmans-commands [db]
|
(defn get-mailmans-commands [db]
|
||||||
|
@ -129,20 +134,24 @@
|
||||||
(into {})))
|
(into {})))
|
||||||
|
|
||||||
(defn add-commands
|
(defn add-commands
|
||||||
[db [id _ {:keys [commands responses subscriptions]}]]
|
[{:keys [chats] :as db} [id _ {:keys [commands responses subscriptions]}]]
|
||||||
(let [account @(subscribe [:get-current-account])
|
(let [account @(subscribe [:get-current-account])
|
||||||
commands' (filter-forbidden-names account id commands)
|
chat (get chats id)
|
||||||
|
commands' (filter-commands account chat commands)
|
||||||
|
responses' (filter-commands account chat responses)
|
||||||
global-command (:global commands')
|
global-command (:global commands')
|
||||||
commands'' (apply dissoc commands' [:init :global])
|
commands'' (apply dissoc commands' [:init :global])
|
||||||
responses' (filter-forbidden-names account id responses)
|
|
||||||
mailman-commands (get-mailmans-commands db)]
|
mailman-commands (get-mailmans-commands db)]
|
||||||
(cond-> db
|
(cond-> db
|
||||||
|
|
||||||
true
|
true
|
||||||
(update-in [:contacts id] assoc
|
(update-in [:contacts id] assoc
|
||||||
:commands-loaded true
|
:commands-loaded? true
|
||||||
:commands (mark-as :command (merge mailman-commands commands''))
|
:commands (-> (merge mailman-commands commands'')
|
||||||
:responses (mark-as :response responses')
|
(each-merge {:type :command
|
||||||
|
:owner-id id}))
|
||||||
|
:responses (each-merge responses' {:type :response
|
||||||
|
:owner-id id})
|
||||||
:subscriptions subscriptions)
|
:subscriptions subscriptions)
|
||||||
|
|
||||||
global-command
|
global-command
|
||||||
|
@ -167,7 +176,7 @@
|
||||||
[{:keys [global-commands contacts]} [id]]
|
[{:keys [global-commands contacts]} [id]]
|
||||||
(let [command (get global-commands (keyword id))
|
(let [command (get global-commands (keyword id))
|
||||||
commands (get-in contacts [id :commands])
|
commands (get-in contacts [id :commands])
|
||||||
responses (get-in contacts [id :commands])]
|
responses (get-in contacts [id :responses])]
|
||||||
(contacts/save {:whisper-identity id
|
(contacts/save {:whisper-identity id
|
||||||
:global-command command
|
:global-command command
|
||||||
:commands (vals commands)
|
:commands (vals commands)
|
||||||
|
@ -187,7 +196,7 @@
|
||||||
(reg-handler :check-and-load-commands!
|
(reg-handler :check-and-load-commands!
|
||||||
(u/side-effect!
|
(u/side-effect!
|
||||||
(fn [{:keys [contacts]} [identity callback]]
|
(fn [{:keys [contacts]} [identity callback]]
|
||||||
(if (get-in contacts [identity :commands-loaded])
|
(if (get-in contacts [identity :commands-loaded?])
|
||||||
(callback)
|
(callback)
|
||||||
(dispatch [:load-commands! identity callback])))))
|
(dispatch [:load-commands! identity callback])))))
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
[status-im.components.react :as components]
|
[status-im.components.react :as components]
|
||||||
[status-im.chat.views.input.web-view :as chat-web-view]
|
[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.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.components.qr-code :as qr]
|
||||||
[status-im.utils.handlers :refer [register-handler]]))
|
[status-im.utils.handlers :refer [register-handler]]
|
||||||
|
[taoensso.timbre :as log]))
|
||||||
|
|
||||||
(defn json->clj [json]
|
(defn json->clj [json]
|
||||||
(when-not (= json "undefined")
|
(when-not (= json "undefined")
|
||||||
|
@ -25,7 +27,8 @@
|
||||||
:touchable components/touchable-highlight
|
:touchable components/touchable-highlight
|
||||||
:activity-indicator components/activity-indicator
|
:activity-indicator components/activity-indicator
|
||||||
:bridged-web-view chat-web-view/bridged-web-view
|
:bridged-web-view chat-web-view/bridged-web-view
|
||||||
:validation-message chat-validation-messages/validation-message})
|
:validation-message chat-validation-messages/validation-message
|
||||||
|
:choose-contact choose-contact/choose-contact-view})
|
||||||
|
|
||||||
(defn get-element [n]
|
(defn get-element [n]
|
||||||
(elements (keyword (.toLowerCase n))))
|
(elements (keyword (.toLowerCase n))))
|
||||||
|
|
|
@ -262,7 +262,7 @@
|
||||||
:dapp-hash dapp-hash}]
|
:dapp-hash dapp-hash}]
|
||||||
(dispatch [:add-contacts [contact]])
|
(dispatch [:add-contacts [contact]])
|
||||||
(when bot-url
|
(when bot-url
|
||||||
(dispatch [:load-commands! contact]))))))))))
|
(dispatch [:load-commands! id']))))))))))
|
||||||
|
|
||||||
|
|
||||||
(register-handler :add-contacts
|
(register-handler :add-contacts
|
||||||
|
|
|
@ -39,6 +39,11 @@
|
||||||
(let [contacts (subscribe [:all-added-contacts])]
|
(let [contacts (subscribe [:all-added-contacts])]
|
||||||
(reaction (remove #(true? (:dapp? %)) @contacts)))))
|
(reaction (remove #(true? (:dapp? %)) @contacts)))))
|
||||||
|
|
||||||
|
(register-sub :people-in-current-chat
|
||||||
|
(fn [{:keys [current-chat-id]} _]
|
||||||
|
(let [contacts (subscribe [:current-chat-contacts])]
|
||||||
|
(reaction (remove #(true? (:dapp? %)) @contacts)))))
|
||||||
|
|
||||||
(defn filter-group-contacts [group-contacts contacts]
|
(defn filter-group-contacts [group-contacts contacts]
|
||||||
(filter #(group-contacts (:whisper-identity %)) contacts))
|
(filter #(group-contacts (:whisper-identity %)) contacts))
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
[[_ {:keys [name] :as command}]]
|
[[_ {:keys [name] :as command}]]
|
||||||
[(keyword name) command])
|
[(keyword name) command])
|
||||||
|
|
||||||
|
(defn- enrich-with-owner-id [owner-id]
|
||||||
|
(fn [[k v]]
|
||||||
|
[k (assoc v :owner-id owner-id)]))
|
||||||
|
|
||||||
(defn- commands-map->commands-list
|
(defn- commands-map->commands-list
|
||||||
[commands-map]
|
[commands-map]
|
||||||
(or (if (and commands-map (map? commands-map))
|
(or (if (and commands-map (map? commands-map))
|
||||||
|
@ -16,9 +20,12 @@
|
||||||
(defn get-all
|
(defn get-all
|
||||||
[]
|
[]
|
||||||
(map
|
(map
|
||||||
(fn [{:keys [commands responses] :as contact}]
|
(fn [{:keys [commands responses whisper-identity] :as contact}]
|
||||||
(assoc contact
|
(assoc contact
|
||||||
:commands (into {} (map command->map-item commands))
|
:commands (->> commands
|
||||||
|
(map command->map-item)
|
||||||
|
(map (enrich-with-owner-id whisper-identity))
|
||||||
|
(into {}))
|
||||||
:responses (into {} (map command->map-item responses))))
|
:responses (into {} (map command->map-item responses))))
|
||||||
(data-store/get-all-as-list)))
|
(data-store/get-all-as-list)))
|
||||||
|
|
||||||
|
|
|
@ -7,19 +7,6 @@
|
||||||
[status-im.constants :as c])
|
[status-im.constants :as c])
|
||||||
(:refer-clojure :exclude [update]))
|
(:refer-clojure :exclude [update]))
|
||||||
|
|
||||||
(defn- map-to-str
|
|
||||||
[m]
|
|
||||||
(join ";" (map #(join "=" %) (stringify-keys m))))
|
|
||||||
|
|
||||||
(defn- str-to-map
|
|
||||||
[s]
|
|
||||||
(->> (keywordize-keys (apply hash-map (split s #"[;=]")))
|
|
||||||
(map (fn [[k v]]
|
|
||||||
[k (if (= k :params)
|
|
||||||
(keywordize-keys (read-string v))
|
|
||||||
v)]))
|
|
||||||
(into {})))
|
|
||||||
|
|
||||||
(defn- user-statuses-to-map
|
(defn- user-statuses-to-map
|
||||||
[user-statuses]
|
[user-statuses]
|
||||||
(->> (vals user-statuses)
|
(->> (vals user-statuses)
|
||||||
|
@ -49,7 +36,7 @@
|
||||||
(defn get-message-content-by-id [message-id]
|
(defn get-message-content-by-id [message-id]
|
||||||
(when-let [{:keys [content-type content] :as message} (get-by-id message-id)]
|
(when-let [{:keys [content-type content] :as message} (get-by-id message-id)]
|
||||||
(when (command-type? content-type)
|
(when (command-type? content-type)
|
||||||
(str-to-map content))))
|
(read-string content))))
|
||||||
|
|
||||||
(defn get-messages
|
(defn get-messages
|
||||||
[messages]
|
[messages]
|
||||||
|
@ -59,7 +46,7 @@
|
||||||
reverse
|
reverse
|
||||||
(keep (fn [{:keys [content-type] :as message}]
|
(keep (fn [{:keys [content-type] :as message}]
|
||||||
(if (command-type? content-type)
|
(if (command-type? content-type)
|
||||||
(clojure.core/update message :content str-to-map)
|
(clojure.core/update message :content read-string)
|
||||||
message)))))
|
message)))))
|
||||||
|
|
||||||
(defn get-count-by-chat-id
|
(defn get-count-by-chat-id
|
||||||
|
@ -76,7 +63,7 @@
|
||||||
reverse
|
reverse
|
||||||
(keep (fn [{:keys [content-type preview] :as message}]
|
(keep (fn [{:keys [content-type preview] :as message}]
|
||||||
(if (command-type? content-type)
|
(if (command-type? content-type)
|
||||||
(clojure.core/update message :content str-to-map)
|
(clojure.core/update message :content read-string)
|
||||||
message))))))
|
message))))))
|
||||||
|
|
||||||
(defn get-log-messages
|
(defn get-log-messages
|
||||||
|
@ -89,7 +76,7 @@
|
||||||
[chat-id]
|
[chat-id]
|
||||||
(if-let [{:keys [content-type] :as message} (data-store/get-last-message chat-id)]
|
(if-let [{:keys [content-type] :as message} (data-store/get-last-message chat-id)]
|
||||||
(if (command-type? content-type)
|
(if (command-type? content-type)
|
||||||
(clojure.core/update message :content str-to-map)
|
(clojure.core/update message :content read-string)
|
||||||
message)))
|
message)))
|
||||||
|
|
||||||
(defn get-last-outgoing
|
(defn get-last-outgoing
|
||||||
|
@ -116,7 +103,7 @@
|
||||||
(when-not (data-store/exists? message-id)
|
(when-not (data-store/exists? message-id)
|
||||||
(let [content' (if (string? content)
|
(let [content' (if (string? content)
|
||||||
content
|
content
|
||||||
(map-to-str content))
|
(pr-str content))
|
||||||
message' (merge default-values
|
message' (merge default-values
|
||||||
message
|
message
|
||||||
{:chat-id chat-id
|
{:chat-id chat-id
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
[status-im.data-store.realm.schemas.account.v6.core :as v6]
|
[status-im.data-store.realm.schemas.account.v6.core :as v6]
|
||||||
[status-im.data-store.realm.schemas.account.v7.core :as v7]
|
[status-im.data-store.realm.schemas.account.v7.core :as v7]
|
||||||
[status-im.data-store.realm.schemas.account.v8.core :as v8]
|
[status-im.data-store.realm.schemas.account.v8.core :as v8]
|
||||||
[status-im.data-store.realm.schemas.account.v9.core :as v9]))
|
[status-im.data-store.realm.schemas.account.v9.core :as v9]
|
||||||
|
[status-im.data-store.realm.schemas.account.v10.core :as v10]))
|
||||||
|
|
||||||
; put schemas ordered by version
|
; put schemas ordered by version
|
||||||
(def schemas [{:schema v1/schema
|
(def schemas [{:schema v1/schema
|
||||||
|
@ -36,4 +37,7 @@
|
||||||
:migration v8/migration}
|
:migration v8/migration}
|
||||||
{:schema v9/schema
|
{:schema v9/schema
|
||||||
:schemaVersion 9
|
:schemaVersion 9
|
||||||
:migration v9/migration}])
|
:migration v9/migration}
|
||||||
|
{:schema v10/schema
|
||||||
|
:schemaVersion 10
|
||||||
|
:migration v10/migration}])
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
(ns status-im.data-store.realm.schemas.account.v10.core
|
||||||
|
(:require [status-im.data-store.realm.schemas.account.v4.chat :as chat]
|
||||||
|
[status-im.data-store.realm.schemas.account.v1.chat-contact :as chat-contact]
|
||||||
|
[status-im.data-store.realm.schemas.account.v6.command :as command]
|
||||||
|
[status-im.data-store.realm.schemas.account.v9.command-parameter :as command-parameter]
|
||||||
|
[status-im.data-store.realm.schemas.account.v7.contact :as contact]
|
||||||
|
[status-im.data-store.realm.schemas.account.v1.discover :as discover]
|
||||||
|
[status-im.data-store.realm.schemas.account.v1.kv-store :as kv-store]
|
||||||
|
[status-im.data-store.realm.schemas.account.v10.message :as message]
|
||||||
|
[status-im.data-store.realm.schemas.account.v7.pending-message :as pending-message]
|
||||||
|
[status-im.data-store.realm.schemas.account.v1.processed-message :as processed-message]
|
||||||
|
[status-im.data-store.realm.schemas.account.v1.request :as request]
|
||||||
|
[status-im.data-store.realm.schemas.account.v1.tag :as tag]
|
||||||
|
[status-im.data-store.realm.schemas.account.v1.user-status :as user-status]
|
||||||
|
[status-im.data-store.realm.schemas.account.v5.contact-group :as contact-group]
|
||||||
|
[status-im.data-store.realm.schemas.account.v5.group-contact :as group-contact]
|
||||||
|
[status-im.data-store.realm.schemas.account.v8.local-storage :as local-storage]
|
||||||
|
[taoensso.timbre :as log]))
|
||||||
|
|
||||||
|
(def schema [chat/schema
|
||||||
|
chat-contact/schema
|
||||||
|
command/schema
|
||||||
|
command-parameter/schema
|
||||||
|
contact/schema
|
||||||
|
discover/schema
|
||||||
|
kv-store/schema
|
||||||
|
message/schema
|
||||||
|
pending-message/schema
|
||||||
|
processed-message/schema
|
||||||
|
request/schema
|
||||||
|
tag/schema
|
||||||
|
user-status/schema
|
||||||
|
contact-group/schema
|
||||||
|
group-contact/schema
|
||||||
|
local-storage/schema])
|
||||||
|
|
||||||
|
(defn migration [old-realm new-realm]
|
||||||
|
(log/debug "migrating v10 account database: " old-realm new-realm)
|
||||||
|
(message/migration old-realm new-realm))
|
|
@ -0,0 +1,51 @@
|
||||||
|
(ns status-im.data-store.realm.schemas.account.v10.message
|
||||||
|
(:require [taoensso.timbre :as log]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
|
||||||
|
(def schema {:name :message
|
||||||
|
:primaryKey :message-id
|
||||||
|
:properties {:message-id :string
|
||||||
|
:from :string
|
||||||
|
:to {:type :string
|
||||||
|
:optional true}
|
||||||
|
:group-id {:type :string
|
||||||
|
:optional true}
|
||||||
|
:content :string ;; TODO make it ArrayBuffer
|
||||||
|
:content-type :string
|
||||||
|
:username {:type :string
|
||||||
|
:optional true}
|
||||||
|
:timestamp :int
|
||||||
|
:chat-id {:type :string
|
||||||
|
:indexed true}
|
||||||
|
:outgoing :bool
|
||||||
|
:retry-count {:type :int
|
||||||
|
:default 0}
|
||||||
|
:same-author :bool
|
||||||
|
:same-direction :bool
|
||||||
|
:preview {:type :string
|
||||||
|
:optional true}
|
||||||
|
:message-type {:type :string
|
||||||
|
:optional true}
|
||||||
|
:message-status {:type :string
|
||||||
|
:optional true}
|
||||||
|
:user-statuses {:type :list
|
||||||
|
:objectType "user-status"}
|
||||||
|
:clock-value {:type :int
|
||||||
|
:default 0}
|
||||||
|
:show? {:type :bool
|
||||||
|
:default true}}})
|
||||||
|
|
||||||
|
(defn migration [old-realm new-realm]
|
||||||
|
(log/debug "migrating message schema v10")
|
||||||
|
(let [messages (.objects new-realm "message")]
|
||||||
|
(dotimes [i (.-length messages)]
|
||||||
|
(let [message (aget messages i)
|
||||||
|
content (aget message "content")
|
||||||
|
type (aget message "content-type")]
|
||||||
|
(when (and (or (= type "wallet-command")
|
||||||
|
(= type "wallet-request")
|
||||||
|
(= type "command")
|
||||||
|
(= type "command-request"))
|
||||||
|
(or (> (str/index-of content "command=send") -1)
|
||||||
|
(> (str/index-of content "command=request") -1)))
|
||||||
|
(aset message "show?" false))))))
|
|
@ -35,5 +35,4 @@
|
||||||
local-storage/schema])
|
local-storage/schema])
|
||||||
|
|
||||||
(defn migration [old-realm new-realm]
|
(defn migration [old-realm new-realm]
|
||||||
(log/debug "migrating v8 account database: " old-realm new-realm)
|
(log/debug "migrating v8 account database: " old-realm new-realm))
|
||||||
(contact/migration old-realm new-realm))
|
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
|
|
||||||
(def demo-bot-js (slurp-bot :demo_bot))
|
(def demo-bot-js (slurp-bot :demo_bot))
|
||||||
|
|
||||||
(def commands-js wallet-js)
|
|
||||||
|
|
||||||
(def resources
|
(def resources
|
||||||
{:wallet-bot wallet-js
|
{:wallet-bot wallet-js
|
||||||
:console-bot console-js
|
:console-bot console-js
|
||||||
|
|