/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-image-crop-picker')
|
||||
compile project(':react-native-webview-bridge')
|
||||
compile 'testfairy:testfairy-android-sdk:1.+@aar'
|
||||
|
||||
compile fileTree(dir: "node_modules/realm/android/libs", include: ["*.jar"])
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.content.res.Configuration;
|
|||
import android.os.Bundle;
|
||||
import com.facebook.react.ReactActivity;
|
||||
import com.cboy.rn.splashscreen.SplashScreen;
|
||||
import com.testfairy.TestFairy;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -26,6 +27,7 @@ public class MainActivity extends ReactActivity {
|
|||
protected void onCreate(Bundle savedInstanceState) {
|
||||
SplashScreen.show(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
TestFairy.begin(this, "33e4bd97daaaacf3b1b6425096fb65186248fe44");
|
||||
|
||||
if (!RootUtil.isDeviceRooted()) {
|
||||
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) {
|
||||
var suggestions = faucets.map(function (entry) {
|
||||
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(
|
||||
suggestionContainerStyle,
|
||||
[status.components.view(
|
||||
|
@ -561,7 +561,7 @@ status.command({
|
|||
function debugSuggestions(params) {
|
||||
var suggestions = ["On", "Off"].map(function (entry) {
|
||||
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(
|
||||
suggestionContainerStyle,
|
||||
[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) {
|
||||
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 {
|
||||
markup: status.components.validationMessage(
|
||||
"Wrong address",
|
||||
|
@ -7,7 +273,8 @@ function validateSend(params, context) {
|
|||
)
|
||||
};
|
||||
}
|
||||
if (!params.amount) {
|
||||
|
||||
if (!params["amount"]) {
|
||||
return {
|
||||
markup: status.components.validationMessage(
|
||||
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(".");
|
||||
if (amountSplitted.length === 2 && amountSplitted[1].length > 18) {
|
||||
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 {
|
||||
var val = web3.toWei(amount, "ether");
|
||||
if (val <= 0) {
|
||||
|
@ -42,13 +318,15 @@ function validateSend(params, context) {
|
|||
}
|
||||
|
||||
var balance = web3.eth.getBalance(context.from);
|
||||
var estimatedGas = web3.eth.estimateGas({
|
||||
from: context.from,
|
||||
to: context.to,
|
||||
value: val
|
||||
});
|
||||
var fee = calculateFee(
|
||||
params["bot-db"]["sliderValue"],
|
||||
{
|
||||
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 {
|
||||
markup: status.components.validationMessage(
|
||||
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 = {
|
||||
from: context.from,
|
||||
to: context.to,
|
||||
value: web3.toWei(params.amount.replace(",", "."), "ether")
|
||||
to: params["bot-db"]["public"]["recipient"]["address"],
|
||||
value: val,
|
||||
gasPrice: calculateGasPrice(params["bot-db"]["sliderValue"])
|
||||
};
|
||||
|
||||
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 = {
|
||||
name: "send",
|
||||
icon: "money_white",
|
||||
color: "#5fc48d",
|
||||
title: I18n.t('send_title'),
|
||||
description: I18n.t('send_description'),
|
||||
sequentialParams: true,
|
||||
params: [{
|
||||
name: "amount",
|
||||
type: status.types.NUMBER
|
||||
}],
|
||||
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
|
||||
params: paramsSend,
|
||||
validator: validateSend,
|
||||
handler: handleSend,
|
||||
preview: previewSend,
|
||||
shortPreview: shortPreviewSend
|
||||
};
|
||||
|
||||
status.command(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({
|
||||
name: "request",
|
||||
color: "#5fc48d",
|
||||
title: I18n.t('request_title'),
|
||||
description: I18n.t('request_description'),
|
||||
sequentialParams: true,
|
||||
params: [{
|
||||
name: "amount",
|
||||
type: status.types.NUMBER
|
||||
}],
|
||||
handler: function (params) {
|
||||
params: paramsRequest,
|
||||
handler: function (params, context) {
|
||||
var val = params["amount"].replace(",", ".");
|
||||
|
||||
return {
|
||||
event: "request",
|
||||
params: [params.amount],
|
||||
request: {
|
||||
command: "send",
|
||||
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) {
|
||||
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 {
|
||||
var val = web3.toWei(params.amount.replace(",", "."), "ether");
|
||||
var val = web3.toWei(amount, "ether");
|
||||
if (val <= 0) {
|
||||
throw new Error();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,20 @@
|
|||
I18n.translations = {
|
||||
en: {
|
||||
send_title: 'Send ETH',
|
||||
send_title: 'Send transaction',
|
||||
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_description: 'Request a payment',
|
||||
|
@ -14,7 +27,7 @@ I18n.translations = {
|
|||
validation_insufficient_amount: 'Insufficient funds for gas * price + value (balance '
|
||||
},
|
||||
ru: {
|
||||
send_title: 'Отправить ETH',
|
||||
send_title: 'Отправить транзакцию',
|
||||
send_description: 'Отправить платеж',
|
||||
|
||||
request_title: 'Запросить ETH',
|
||||
|
|
|
@ -4,11 +4,12 @@ var TopLevel = {
|
|||
"addEventListener" : function () {},
|
||||
"addListener" : function () {},
|
||||
"addOrientationListener" : function () {},
|
||||
"addSymKey" : function () {},
|
||||
"addSymmetricKeyFromPassword" : function () {},
|
||||
"Alert" : function () {},
|
||||
"alert" : function () {},
|
||||
"Animated" : function () {},
|
||||
"Array" : function () {},
|
||||
"AutoGrowingTextInput" : function () {},
|
||||
"awesome-phonenumber" : function () {},
|
||||
"blur" : function () {},
|
||||
"call" : function () {},
|
||||
|
@ -16,6 +17,7 @@ var TopLevel = {
|
|||
"capture" : function () {},
|
||||
"catch" : function () {},
|
||||
"Chance" : function () {},
|
||||
"checkVideoAuthorizationStatus" : function () {},
|
||||
"clear" : function () {},
|
||||
"clearCookies" : function () {},
|
||||
"clearInterval" : function () {},
|
||||
|
@ -26,7 +28,7 @@ var TopLevel = {
|
|||
"close" : function () {},
|
||||
"closeDrawer" : function () {},
|
||||
"codec" : function () {},
|
||||
"completeTransaction" : function () {},
|
||||
"completeTransactions" : function () {},
|
||||
"console" : function () {},
|
||||
"contentOffset" : function () {},
|
||||
"contentSize" : function () {},
|
||||
|
@ -67,36 +69,34 @@ var TopLevel = {
|
|||
"fromUtf8" : function () {},
|
||||
"fromWei" : function () {},
|
||||
"generate" : function () {},
|
||||
"geoPermissionsGranted" : function () {},
|
||||
"get" : function () {},
|
||||
"getAll" : function () {},
|
||||
"getBlock" : function () {},
|
||||
"getCardId" : function () {},
|
||||
"getExample" : function () {},
|
||||
"getInitialOrientation" : function () {},
|
||||
"getIPAddress" : function () {},
|
||||
"getLayout" : function () {},
|
||||
"getNumber" : function () {},
|
||||
"getSyncing" : function () {},
|
||||
"getTime" : function () {},
|
||||
"getTimezoneOffset" : function () {},
|
||||
"goBack" : function () {},
|
||||
"goForward" : function () {},
|
||||
"goog" : function () {},
|
||||
"guid" : function () {},
|
||||
"hash" : function () {},
|
||||
"hasSymKey" : function () {},
|
||||
"headers" : function () {},
|
||||
"height" : function () {},
|
||||
"hex" : function () {},
|
||||
"hide" : function () {},
|
||||
"HttpProvider" : function () {},
|
||||
"IBGLog" : function () {},
|
||||
"initialPage" : function () {},
|
||||
"initJail" : function () {},
|
||||
"isAddress" : function () {},
|
||||
"isConnected" : function () {},
|
||||
"isMatches" : function () {},
|
||||
"isMobile" : function () {},
|
||||
"isNaN" : function () {},
|
||||
"isValid" : function () {},
|
||||
"Item" : function () {},
|
||||
"JSON" : function () {},
|
||||
"jsonEvent" : function () {},
|
||||
|
@ -113,13 +113,13 @@ var TopLevel = {
|
|||
"Math" : function () {},
|
||||
"message" : function () {},
|
||||
"moveFile" : function () {},
|
||||
"moveToInternalStorage" : function () {},
|
||||
"moveY" : function () {},
|
||||
"nativeEvent" : function () {},
|
||||
"NativeModules" : function () {},
|
||||
"Number" : function () {},
|
||||
"objects" : function () {},
|
||||
"ok" : function () {},
|
||||
"open" : function () {},
|
||||
"openDrawer" : function () {},
|
||||
"openPicker" : function () {},
|
||||
"openURL" : function () {},
|
||||
|
@ -132,11 +132,11 @@ var TopLevel = {
|
|||
"parseInt" : function () {},
|
||||
"parseJail" : function () {},
|
||||
"path" : function () {},
|
||||
"PermissionsAndroid" : function () {},
|
||||
"Platform" : function () {},
|
||||
"post" : function () {},
|
||||
"props" : function () {},
|
||||
"prototype" : function () {},
|
||||
"providers" : function () {},
|
||||
"push" : function () {},
|
||||
"random" : function () {},
|
||||
"randomBytes" : function () {},
|
||||
|
@ -149,8 +149,12 @@ var TopLevel = {
|
|||
"reload" : function () {},
|
||||
"remove" : function () {},
|
||||
"removeAllListeners" : function () {},
|
||||
"removeEventListener" : function () {},
|
||||
"requestMultiple" : function () {},
|
||||
"require" : function () {},
|
||||
"reset" : function () {},
|
||||
"resetOkHttpClient" : function () {},
|
||||
"respond" : function () {},
|
||||
"reverse" : function () {},
|
||||
"round" : function () {},
|
||||
"schema" : function () {},
|
||||
|
@ -160,9 +164,11 @@ var TopLevel = {
|
|||
"scrollView" : function () {},
|
||||
"selection" : function () {},
|
||||
"sendToBridge" : function () {},
|
||||
"sendWeb3Request" : function () {},
|
||||
"sequence" : function () {},
|
||||
"set" : function () {},
|
||||
"setInterval" : function () {},
|
||||
"setNativeProps" : function () {},
|
||||
"setSoftInputMode" : function () {},
|
||||
"setState" : function () {},
|
||||
"setString" : function () {},
|
||||
|
@ -170,7 +176,10 @@ var TopLevel = {
|
|||
"setValue" : function () {},
|
||||
"Sha256" : function () {},
|
||||
"sha3" : function () {},
|
||||
"Share" : function () {},
|
||||
"share" : function () {},
|
||||
"shh" : function () {},
|
||||
"shouldMoveToInternalStorage" : function () {},
|
||||
"show" : function () {},
|
||||
"showActionSheetWithOptions" : function () {},
|
||||
"sjcl" : function () {},
|
||||
|
@ -197,7 +206,7 @@ var TopLevel = {
|
|||
"toAscii" : function () {},
|
||||
"toBits" : function () {},
|
||||
"toDecimal" : function () {},
|
||||
"toHex" : function () {},
|
||||
"toJSON" : function () {},
|
||||
"toLocaleString" : function () {},
|
||||
"toLowerCase" : function () {},
|
||||
"toNumber" : function () {},
|
||||
|
@ -218,5 +227,6 @@ var TopLevel = {
|
|||
"writeTag" : function () {},
|
||||
"x" : function () {},
|
||||
"y" : function () {},
|
||||
"_bodyText" : 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 = {
|
||||
command: function (h) {
|
||||
var command = new Command();
|
||||
|
@ -208,7 +216,11 @@ var status = {
|
|||
},
|
||||
events: {
|
||||
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: {
|
||||
WEB_VIEW_BACK: 'web-view-back',
|
||||
|
@ -220,6 +232,7 @@ var status = {
|
|||
view: view,
|
||||
text: text,
|
||||
textInput: textInput,
|
||||
slider: slider,
|
||||
image: image,
|
||||
qrCode: qrCode,
|
||||
linking: linking,
|
||||
|
@ -230,6 +243,7 @@ var status = {
|
|||
webView: webView,
|
||||
validationMessage: validationMessage,
|
||||
bridgedWebView: bridgedWebView,
|
||||
chooseContact: chooseContact,
|
||||
subscribe: subscribe,
|
||||
dispatch: dispatch
|
||||
},
|
||||
|
|
|
@ -3,8 +3,17 @@
|
|||
[status-im.components.status :as status]
|
||||
[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
|
||||
[{: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])
|
||||
subscriptions (get-in db [:bot-subscriptions path'])
|
||||
current-bot-db (get bot-db bot)]
|
||||
|
@ -17,22 +26,23 @@
|
|||
:function :subscription
|
||||
:parameters {:name name
|
||||
:subscriptions subs-values}
|
||||
:callback #(re-frame/dispatch
|
||||
[::calculated-subscription {:bot bot
|
||||
:path [name]
|
||||
:result %}])})))))
|
||||
|
||||
(u/register-handler
|
||||
:set-bot-db
|
||||
(re-frame/after check-subscriptions)
|
||||
(fn [db [_ {:keys [bot key value]}]]
|
||||
(assoc-in db [:bot-db bot key] value)))
|
||||
:callback #(do
|
||||
(re-frame/dispatch
|
||||
[::calculated-subscription {:bot bot
|
||||
:path [name]
|
||||
:result %}])
|
||||
(doseq [chat-id (chats-with-bot chats bot)]
|
||||
(re-frame/dispatch
|
||||
[::calculated-subscription {:bot chat-id
|
||||
:path [name]
|
||||
:result %}])))})))))
|
||||
|
||||
(u/register-handler
|
||||
:set-in-bot-db
|
||||
(re-frame/after check-subscriptions)
|
||||
(fn [db [_ {:keys [bot path value]}]]
|
||||
(assoc-in db (concat [:bot-db bot] path) value)))
|
||||
(fn [{:keys [current-chat-id] :as db} [_ {:keys [bot path value]}]]
|
||||
(let [bot (or bot current-chat-id)]
|
||||
(assoc-in db (concat [:bot-db bot] path) value))))
|
||||
|
||||
(u/register-handler
|
||||
:register-bot-subscription
|
||||
|
@ -61,5 +71,12 @@
|
|||
|
||||
(u/register-handler
|
||||
:update-bot-db
|
||||
(fn [app-db [_ {:keys [bot db]}]]
|
||||
(update-in app-db [:bot-db bot] merge db)))
|
||||
(fn [{:keys [current-chat-id] :as app-db} [_ {:keys [bot 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
|
||||
(assoc :current-chat-id chat-id)
|
||||
(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])
|
||||
was-opened? (get-in db [:chats chat-id :was-opened?])
|
||||
call-init-command #(when (and (not was-opened?) bot-url)
|
||||
|
|
|
@ -6,28 +6,37 @@
|
|||
[status-im.commands.utils :as cu]
|
||||
[status-im.i18n :as i18n]
|
||||
[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/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 [message-id chat-id on-requested jail-id] :as message} data-type]]
|
||||
(let [jail-id (or jail-id chat-id)]
|
||||
(if-not (get-in contacts [jail-id :commands-loaded])
|
||||
:keys [message-id from chat-id on-requested jail-id] :as message} data-type]]
|
||||
(let [jail-id (or jail-id chat-id)
|
||||
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
|
||||
jail-id
|
||||
jail-id'
|
||||
#(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)
|
||||
(if content-command content-command command)
|
||||
data-type]
|
||||
to (get-in contacts [chat-id :address])
|
||||
params {:parameters params
|
||||
:context (merge {:platform platform/platform
|
||||
:from current-account-id
|
||||
:to to}
|
||||
i18n/delimeters)}
|
||||
:context (generate-context db chat-id to)}
|
||||
callback #(let [result (get-in % [:result :returned])
|
||||
result (if (:markup result)
|
||||
(update result :markup cu/generate-hiccup)
|
||||
|
@ -35,7 +44,7 @@
|
|||
(dispatch [:set-in [:message-data data-type message-id] result])
|
||||
(when on-requested (on-requested result)))]
|
||||
;chat-id path params callback lock? type
|
||||
(status/call-jail {:jail-id jail-id
|
||||
(status/call-jail {:jail-id jail-id'
|
||||
:path path
|
||||
:params params
|
||||
:callback callback})))))))
|
||||
|
|
|
@ -14,16 +14,20 @@
|
|||
[clojure.string :as str]))
|
||||
|
||||
(handlers/register-handler
|
||||
:set-chat-input-text
|
||||
(fn [{:keys [current-chat-id chats chat-ui-props] :as db} [_ text chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)
|
||||
ends-with-space? (input-model/text-ends-with-space? text)]
|
||||
:set-chat-input-text
|
||||
(fn [{:keys [current-chat-id chats chat-ui-props] :as db} [_ text chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)
|
||||
ends-with-space? (input-model/text-ends-with-space? 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)
|
||||
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)]
|
||||
(assoc-in db [:chats chat-id :input-text] new-input-text))
|
||||
(->> text
|
||||
|
@ -41,15 +45,20 @@
|
|||
:select-chat-input-command
|
||||
(handlers/side-effect!
|
||||
(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)
|
||||
const/spacing-char
|
||||
(when-not sequential-params
|
||||
(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-ui-props {:show-suggestions? false
|
||||
:result-box nil
|
||||
:validation-messages nil}])
|
||||
:validation-messages nil
|
||||
:prev-command name}])
|
||||
(dispatch [:load-chat-parameter-box command 0])
|
||||
(if sequential-params
|
||||
(js/setTimeout
|
||||
|
@ -69,14 +78,15 @@
|
|||
(handlers/register-handler
|
||||
:set-command-argument
|
||||
(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])
|
||||
(input-model/split-command-args))
|
||||
seq-params? (-> (input-model/selected-chat-command db current-chat-id)
|
||||
(get-in [:command :sequential-params]))]
|
||||
(if seq-params?
|
||||
(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 (if (< index (count command-args))
|
||||
(assoc command-args index arg)
|
||||
|
@ -84,7 +94,9 @@
|
|||
(dispatch [:set-chat-input-text (str command-name
|
||||
const/spacing-char
|
||||
(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
|
||||
:chat-input-focus
|
||||
|
@ -104,25 +116,28 @@
|
|||
requests (->> (suggestions/get-request-suggestions db chat-text)
|
||||
(remove (fn [{:keys [type]}]
|
||||
(= 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)
|
||||
all-commands (->> (into global-commands commands)
|
||||
(remove (fn [[k {:keys [hidden?]}]] hidden?))
|
||||
(into {}))
|
||||
{:keys [dapp?]} (get-in db [:contacts chat-id])]
|
||||
(if (and dapp? (str/blank? chat-text))
|
||||
(dispatch [:set-in [:chats chat-id :parameter-boxes :message] nil])
|
||||
(dispatch [::check-dapp-suggestions chat-id chat-text]))
|
||||
(-> db
|
||||
(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
|
||||
:load-chat-parameter-box
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [current-chat-id current-account-id] :as db}
|
||||
[_ {:keys [name type bot] :as command}]]
|
||||
(fn [{:keys [current-chat-id bot-db current-account-id] :as db}
|
||||
[_ {:keys [name type bot owner-id] :as command}]]
|
||||
(let [parameter-index (input-model/argument-position db current-chat-id)]
|
||||
(when (and command (> parameter-index -1))
|
||||
(let [jail-id (or bot current-chat-id)
|
||||
data (get-in db [:local-storage current-chat-id])
|
||||
(let [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)
|
||||
name
|
||||
:params
|
||||
|
@ -132,13 +147,14 @@
|
|||
(input-model/split-command-args)
|
||||
(rest))
|
||||
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
|
||||
:from current-account-id
|
||||
:to to}
|
||||
(input-model/command-dependent-context-params command))}]
|
||||
(status/call-jail
|
||||
{:jail-id jail-id
|
||||
{:jail-id (or bot owner-id current-chat-id)
|
||||
:path path
|
||||
:params params
|
||||
:callback #(dispatch [:received-bot-response
|
||||
|
@ -239,28 +255,33 @@
|
|||
(handlers/register-handler
|
||||
::request-command-data
|
||||
(handlers/side-effect!
|
||||
(fn [{:keys [contacts] :as db}
|
||||
[_ {{:keys [command metadata args] :as c} :command
|
||||
:keys [message-id chat-id jail-id data-type after]}]]
|
||||
(fn [{:keys [contacts bot-db] :as db}
|
||||
[_ {{:keys [command
|
||||
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)
|
||||
message-id (random/id)
|
||||
metadata (merge metadata
|
||||
(when dapp?
|
||||
{:url (i18n/get-contact-translated chat-id :dapp-url dapp-url)
|
||||
: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
|
||||
:params params
|
||||
:to-message (:to-message-id metadata)
|
||||
:created-at (time/now-ms)
|
||||
:id message-id
|
||||
:chat-id chat-id
|
||||
:jail-id jail-id}
|
||||
:jail-id (or owner-id jail-id)}
|
||||
request-data {:message-id message-id
|
||||
:chat-id chat-id
|
||||
:jail-id jail-id
|
||||
:jail-id (or owner-id jail-id)
|
||||
:content {:command (:name command)
|
||||
:params (assoc params :metadata metadata)
|
||||
:params (assoc params :metadata metadata :bot-db bot-db)
|
||||
:type (:type command)}
|
||||
:on-requested #(after command-message %)}]
|
||||
(dispatch [:request-command-data request-data data-type])))))
|
||||
|
@ -342,3 +363,48 @@
|
|||
(fn [{:keys [current-chat-id] :as db} [_ text chat-id]]
|
||||
(let [chat-id (or chat-id current-chat-id)]
|
||||
(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)))
|
||||
|
||||
(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)
|
||||
|
||||
|
|
|
@ -128,19 +128,22 @@
|
|||
|
||||
(register-handler ::invoke-command-handlers!
|
||||
(u/side-effect!
|
||||
(fn [db [_ {:keys [chat-id address command-message]
|
||||
:as parameters}]]
|
||||
(fn [{:keys [bot-db accounts current-account-id] :as db}
|
||||
[_ {:keys [chat-id address command-message]
|
||||
:as parameters}]]
|
||||
(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)
|
||||
name
|
||||
:handler]
|
||||
to (get-in db [:contacts chat-id :address])
|
||||
params {:parameters params
|
||||
:context {:from address
|
||||
:to to
|
||||
:message-id id}}
|
||||
identity (or bot chat-id)]
|
||||
identity (or owner-id bot chat-id)
|
||||
bot-db (get bot-db (or bot chat-id))
|
||||
params {:parameters (assoc params :bot-db bot-db)
|
||||
:context {:from address
|
||||
:to to
|
||||
:current-account (get accounts current-account-id)
|
||||
:message-id id}}]
|
||||
(dispatch
|
||||
[:check-and-load-commands!
|
||||
identity
|
||||
|
|
|
@ -26,29 +26,35 @@
|
|||
(dec (count text)))))
|
||||
|
||||
(defn possible-chat-actions [{:keys [global-commands] :as db} chat-id]
|
||||
(let [{:keys [requests]} (get-in db [:chats chat-id])
|
||||
{:keys [commands responses]} (get-in db [:contacts chat-id])
|
||||
|
||||
commands' (into {} (map (fn [[k v]] [k [v :any]]) (merge global-commands commands)))
|
||||
responses' (into {} (map (fn [{:keys [message-id type]}]
|
||||
[type [(get responses type) message-id]])
|
||||
requests))]
|
||||
(vals (merge commands' responses'))))
|
||||
(let [{:keys [contacts requests]} (get-in db [:chats chat-id])]
|
||||
(->> contacts
|
||||
(map (fn [{:keys [identity]}]
|
||||
(let [{:keys [commands responses]} (get-in db [:contacts identity])]
|
||||
(let [commands' (mapv (fn [[k v]] [k [v :any]]) (merge global-commands commands))
|
||||
responses' (mapv (fn [{:keys [message-id type]}]
|
||||
[type [(get responses type) message-id]])
|
||||
requests)]
|
||||
(into commands' responses')))))
|
||||
(reduce (fn [m cur] (into (or m {}) cur)))
|
||||
(into {})
|
||||
(vals))))
|
||||
|
||||
(defn split-command-args [command-text]
|
||||
(let [space? (text-ends-with-space? command-text)
|
||||
command-text (if space?
|
||||
(str command-text ".")
|
||||
command-text)
|
||||
command-text-normalized (if command-text (str/replace (str/trim command-text) #" +" " ") command-text)
|
||||
splitted (cond-> (str/split command-text-normalized const/spacing-char)
|
||||
space? (drop-last))]
|
||||
(let [space? (text-ends-with-space? command-text)
|
||||
command-text (if space?
|
||||
(str command-text ".")
|
||||
command-text)
|
||||
command-text-normalized (if command-text
|
||||
(str/replace (str/trim command-text) #" +" " ")
|
||||
command-text)
|
||||
splitted (cond-> (str/split command-text-normalized const/spacing-char)
|
||||
space? (drop-last))]
|
||||
(->> splitted
|
||||
(reduce (fn [[list command-started?] arg]
|
||||
(let [quotes-count (count (filter #(= % const/arg-wrapping-char) arg))
|
||||
has-quote? (and (= quotes-count 1)
|
||||
(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?
|
||||
(let [index (dec (count list))]
|
||||
(update list index str const/spacing-char arg))
|
||||
|
@ -92,27 +98,35 @@
|
|||
([{:keys [current-chat-id] :as db} chat-id]
|
||||
(selected-chat-command db chat-id (get-in db [:chats chat-id :input-text]))))
|
||||
|
||||
(def *no-argument-error* -1)
|
||||
|
||||
(defn current-chat-argument-position
|
||||
[{:keys [args] :as command} input-text seq-arguments]
|
||||
[{:keys [args] :as command} input-text selection seq-arguments]
|
||||
(if command
|
||||
(let [args-count (count args)]
|
||||
(cond
|
||||
(:sequential-params command)
|
||||
(count seq-arguments)
|
||||
|
||||
(= (last input-text) const/spacing-char)
|
||||
args-count
|
||||
|
||||
:default
|
||||
(dec args-count)))
|
||||
-1))
|
||||
(if (get-in command [:command :sequential-params])
|
||||
(count seq-arguments)
|
||||
(let [subs-input-text (subs input-text 0 selection)]
|
||||
(if subs-input-text
|
||||
(let [args (split-command-args subs-input-text)
|
||||
argument-index (dec (count args))
|
||||
ends-with-space? (text-ends-with-space? subs-input-text)
|
||||
arg-wrapping-count (-> (frequencies subs-input-text)
|
||||
(get const/arg-wrapping-char)
|
||||
(or 0))]
|
||||
(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]
|
||||
(let [chat-id (or chat-id current-chat-id)
|
||||
input-text (get-in db [:chats chat-id :input-text])
|
||||
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)]
|
||||
(current-chat-argument-position chat-command input-text seq-arguments)))
|
||||
(current-chat-argument-position chat-command input-text selection seq-arguments)))
|
||||
|
||||
(defn command-completion
|
||||
([{:keys [current-chat-id] :as db} chat-id]
|
||||
|
@ -189,4 +203,4 @@
|
|||
(str
|
||||
command
|
||||
const/spacing-char
|
||||
(str/join const/spacing-char new-args))))
|
||||
(join-command-args new-args))))
|
|
@ -28,10 +28,16 @@
|
|||
|
||||
(defn get-command-suggestions
|
||||
[{:keys [current-chat-id] :as db} text]
|
||||
(let [commands (get-in db [:contacts current-chat-id :commands])]
|
||||
(filter (fn [[_ v]] ((can-be-suggested? text) v)) commands)))
|
||||
(->> (get-in db [:chats current-chat-id :contacts])
|
||||
(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
|
||||
[{: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
|
||||
: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))]
|
||||
(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
|
||||
:possible-chat-actions
|
||||
(fn [db [_ chat-id]]
|
||||
|
@ -92,9 +104,10 @@
|
|||
(fn [db]
|
||||
(let [command (subscribe [:selected-chat-command])
|
||||
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
|
||||
(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
|
||||
:chat-parameter-box
|
||||
|
@ -104,7 +117,7 @@
|
|||
index (subscribe [:current-chat-argument-position])]
|
||||
(reaction
|
||||
(cond
|
||||
(and @command (> @index -1))
|
||||
(and @command (not= @index input-model/*no-argument-error*))
|
||||
(let [command-name (get-in @command [:command :name])]
|
||||
(get-in @db [:chats @chat-id :parameter-boxes command-name @index]))
|
||||
|
||||
|
@ -188,8 +201,10 @@
|
|||
(fn [db [_ chat-id]]
|
||||
(reaction
|
||||
(let [{:keys [last-message messages]} (get-in @db [:chats chat-id])]
|
||||
(first
|
||||
(sort-by :clock-value > (conj messages last-message)))))))
|
||||
(->> (conj messages last-message)
|
||||
(sort-by :clock-value >)
|
||||
(filter :show?)
|
||||
(first))))))
|
||||
|
||||
(register-sub :get-last-message-short-preview
|
||||
(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])
|
||||
sending-in-progress? (subscribe [:chat-ui-props :sending-in-progress?])
|
||||
input-focused? (subscribe [:chat-ui-props :input-focused?])
|
||||
prev-command (subscribe [:chat-ui-props :prev-command])
|
||||
input-ref (atom nil)]
|
||||
(fn [{:keys [set-layout-height set-container-width height single-line-input?]}]
|
||||
[text-input
|
||||
|
@ -94,23 +95,26 @@
|
|||
(dispatch [:set-chat-input-text text])
|
||||
(if @command
|
||||
(do
|
||||
(when (not= @prev-command (-> @command :command :name))
|
||||
(dispatch [:clear-bot-db @command]))
|
||||
(dispatch [:load-chat-parameter-box (:command @command)])
|
||||
(dispatch [:set-chat-ui-props {:validation-messages nil}]))
|
||||
(do
|
||||
(dispatch [:set-chat-input-metadata nil])
|
||||
(dispatch [:set-chat-ui-props {:result-box nil
|
||||
:validation-messages nil}]))))))
|
||||
(dispatch [:set-chat-ui-props
|
||||
{:result-box nil
|
||||
:validation-messages nil
|
||||
:prev-command (-> @command :command :name)}]))))))
|
||||
:on-content-size-change (when (and (not @input-focused?)
|
||||
(not single-line-input?))
|
||||
#(let [h (-> (.-nativeEvent %)
|
||||
(.-contentSize)
|
||||
(.-height))]
|
||||
(set-layout-height h)))
|
||||
:on-selection-change #(let [s (-> (.-nativeEvent %)
|
||||
(.-selection))]
|
||||
(when (and (= (.-end s) (+ 2 (count (get-in @command [:command :name]))))
|
||||
(get-in @command [:command :sequential-params]))
|
||||
(dispatch [:chat-input-focus :seq-input-ref])))
|
||||
:on-selection-change #(let [s (-> (.-nativeEvent %)
|
||||
(.-selection))
|
||||
end (.-end s)]
|
||||
(dispatch [:update-text-selection end]))
|
||||
:style (style/input-view height single-line-input?)
|
||||
:placeholder-text-color style/color-input-helper-placeholder
|
||||
:auto-capitalize :sentences}])))
|
||||
|
|
|
@ -1,27 +1,23 @@
|
|||
(ns status-im.chat.views.input.parameter-box
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(: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.utils :as input-utils]
|
||||
[status-im.chat.views.input.box-header :as box-header]
|
||||
[status-im.commands.utils :as command-utils]
|
||||
[status-im.i18n :refer [label]]
|
||||
[taoensso.timbre :as log]
|
||||
[clojure.string :as str]))
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defview parameter-box-container []
|
||||
[parameter-box [:chat-parameter-box]
|
||||
[{:keys [markup]} [:chat-parameter-box]
|
||||
bot-db [:current-bot-db]]
|
||||
(when (:hiccup parameter-box)
|
||||
(command-utils/generate-hiccup (:hiccup parameter-box) bot-db)))
|
||||
(when markup
|
||||
(command-utils/generate-hiccup markup bot-db)))
|
||||
|
||||
(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?
|
||||
[expandable-view {:key :parameter-box
|
||||
:draggable? true}
|
||||
[expandable-view {:key :parameter-box
|
||||
:draggable? true
|
||||
:custom-header (when title
|
||||
(box-header/get-header :parameter-box))}
|
||||
[parameter-box-container]]))
|
||||
|
|
|
@ -7,23 +7,8 @@
|
|||
text
|
||||
icon]]
|
||||
[status-im.chat.views.input.animations.expandable :refer [expandable-view]]
|
||||
[status-im.chat.styles.input.result-box :as style]
|
||||
[status-im.chat.views.input.utils :as input-utils]
|
||||
[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]]]]])
|
||||
[status-im.chat.views.input.box-header :as box-header]
|
||||
[status-im.components.sync-state.offline :refer [offline-view]]))
|
||||
|
||||
(defview result-box-container [markup]
|
||||
[view {:flex 1}
|
||||
|
@ -34,6 +19,6 @@
|
|||
(when result-box
|
||||
[expandable-view {:key :result-box
|
||||
:draggable? true
|
||||
:custom-header header}
|
||||
:custom-header (box-header/get-header :result-box)}
|
||||
[result-box-container markup]
|
||||
[offline-view]]))
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
(let [{:strs [loading url title canGoBack canGoForward]} (js->clj event)]
|
||||
(when-not (= "about:blank" url)
|
||||
(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)
|
||||
result-box (if (and dynamicTitle (not (str/blank? title)))
|
||||
(assoc result-box :title title)
|
||||
|
@ -48,4 +48,5 @@
|
|||
:on-navigation-state-change #(on-navigation-change % result-box)
|
||||
:local-storage-enabled 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
|
||||
(:require-macros [status-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[clojure.walk :as walk]
|
||||
[reagent.core :as r]
|
||||
[status-im.i18n :refer [message-status-label]]
|
||||
[status-im.components.react :refer [view
|
||||
|
@ -93,15 +94,13 @@
|
|||
(defn wallet-command-preview
|
||||
[{{:keys [name]} :contact-chat
|
||||
:keys [contact-address params outgoing? current-chat-id]}]
|
||||
(let [amount (if (= 1 (count params))
|
||||
(first (vals params))
|
||||
(str params))]
|
||||
(let [{:keys [recipient amount]} (walk/keywordize-keys params)]
|
||||
[text {:style st/command-text
|
||||
:font :default}
|
||||
(if (= current-chat-id wallet-chat-id)
|
||||
(let [label-val (if outgoing? :t/chat-send-eth-to :t/chat-send-eth-from)]
|
||||
(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}))]))
|
||||
|
||||
(defn wallet-command? [content-type]
|
||||
|
@ -122,18 +121,21 @@
|
|||
(first (vals params))
|
||||
(str params))]))
|
||||
|
||||
(defn commands-subscription [{:keys [type]}]
|
||||
(if (= type "response")
|
||||
:get-responses
|
||||
:get-commands))
|
||||
|
||||
(defview message-content-command
|
||||
[{:keys [message-id content content-type chat-id to from outgoing] :as message}]
|
||||
[commands [(if (= (:type content) "response")
|
||||
:get-responses
|
||||
:get-commands)
|
||||
chat-id]
|
||||
[commands [:get-commands-and-responses chat-id]
|
||||
from-commands [:get-commands-and-responses from]
|
||||
global-commands [:get :global-commands]
|
||||
current-chat-id [:get-current-chat-id]
|
||||
contact-chat [:get-in [:chats (if outgoing to from)]]
|
||||
preview [:get-in [:message-data :preview message-id :markup]]]
|
||||
(let [{:keys [command params]}
|
||||
(parse-command-message-content commands global-commands content)
|
||||
(let [commands (merge commands from-commands)
|
||||
{:keys [command params]} (parse-command-message-content commands global-commands content)
|
||||
{:keys [name type]
|
||||
icon-path :icon} command]
|
||||
[view st/content-command-view
|
||||
|
|
|
@ -70,19 +70,20 @@
|
|||
[icon command-icon st/command-request-image])]]))})))
|
||||
|
||||
(defn message-content-command-request
|
||||
[{:keys [message-id _ _ _]}]
|
||||
(let [commands-atom (subscribe [:get-responses])
|
||||
[{:keys [message-id chat-id]}]
|
||||
(let [commands-atom (subscribe [:get-commands-and-responses chat-id])
|
||||
answered? (subscribe [:is-request-answered? message-id])
|
||||
status-initialized? (subscribe [:get :status-module-initialized?])
|
||||
markup (subscribe [:get-in [:message-data :preview message-id :markup]])]
|
||||
(fn [{:keys [message-id content from incoming-group]}]
|
||||
(let [commands @commands-atom
|
||||
params (:params content)
|
||||
text-content (:text content)
|
||||
(let [commands @commands-atom
|
||||
{:keys [prefill prefillBotDb params]
|
||||
text-content :text} content
|
||||
{:keys [command content]} (parse-command-request commands content)
|
||||
command (if (and params command)
|
||||
(merge command {:prefill (vals params)})
|
||||
command)]
|
||||
command (if (and params command)
|
||||
(merge command {:prefill prefill
|
||||
:prefill-bot-db prefillBotDb})
|
||||
command)]
|
||||
[view st/comand-request-view
|
||||
[touchable-highlight
|
||||
{:on-press (when (and (not @answered?) @status-initialized?)
|
||||
|
|
|
@ -38,15 +38,14 @@
|
|||
|
||||
(defn suggestions-handler!
|
||||
[{: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)
|
||||
markup (get returned :markup)
|
||||
{:keys [dapp? dapp-url]} (get contacts chat-id)
|
||||
path (if command
|
||||
[:chats chat-id :parameter-boxes (:name command) parameter-index]
|
||||
[:chats chat-id :parameter-boxes :message])]
|
||||
path (if command
|
||||
[:chats chat-id :parameter-boxes (:name command) parameter-index]
|
||||
[:chats chat-id :parameter-boxes :message])]
|
||||
(dispatch [:choose-predefined-expandable-height :parameter-box :default])
|
||||
(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
|
||||
(dispatch [:update-bot-db {:bot chat-id
|
||||
:db default-db}])))))
|
||||
|
@ -56,17 +55,27 @@
|
|||
(log/debug "Suggestion event: " n (first data) val)
|
||||
(let [{:keys [dapp?]} (get-in db [:contacts current-chat-id])]
|
||||
(case (keyword n)
|
||||
:set-command-argument (dispatch [:set-command-argument (first data)])
|
||||
:set-value (dispatch [:set-chat-input-text (first data)])
|
||||
:set (let [opts {:bot current-chat-id
|
||||
:path (mapv keyword data)
|
||||
:value val}]
|
||||
(dispatch [:set-in-bot-db opts]))
|
||||
:set-command-argument
|
||||
(let [[index value move-to-next?] (first data)]
|
||||
(dispatch [:set-command-argument [index value move-to-next?]]))
|
||||
:set-value
|
||||
(dispatch [:set-chat-input-text (first data)])
|
||||
: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
|
||||
(let [path (keyword (first data))
|
||||
value (str (get-in bot-db [current-chat-id path]))]
|
||||
(dispatch [:set-chat-input-text value]))
|
||||
;; todo show error?
|
||||
:focus-input
|
||||
(dispatch [:chat-input-focus :input-ref])
|
||||
nil)))
|
||||
|
||||
(defn print-error-message! [message]
|
||||
|
|
|
@ -17,26 +17,23 @@
|
|||
[status-im.chat.sign-up :as sign-up]
|
||||
[status-im.bots.constants :as bots-constants]
|
||||
[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!
|
||||
[{:keys [current-chat-id contacts]} [contact callback]]
|
||||
(let [whole-contact? (map? contact)
|
||||
{:keys [whisper-identity]} contact
|
||||
identity' (or whisper-identity contact current-chat-id)
|
||||
contact' (if whole-contact?
|
||||
contact
|
||||
(or (get contacts identity')
|
||||
sign-up/console-contact))]
|
||||
(when identity'
|
||||
(dispatch [::fetch-commands! {:contact contact'
|
||||
:callback callback}])))
|
||||
;; todo uncomment
|
||||
#_(if-let [{:keys [file]} (commands/get-by-chat-id contact)]
|
||||
(dispatch [::parse-commands! contact file])
|
||||
(dispatch [::fetch-commands! contact])))
|
||||
|
||||
[{:keys [current-chat-id contacts chats]} [jail-id callback]]
|
||||
(let [identity (or jail-id current-chat-id)
|
||||
contact-ids (if (get contacts identity)
|
||||
[identity]
|
||||
(->> (get-in chats [identity :contacts])
|
||||
(map :identity)
|
||||
(into [])))]
|
||||
(when (seq contacts)
|
||||
(doseq [contact-id contact-ids]
|
||||
(when-let [contact (get contacts contact-id)]
|
||||
(dispatch [::fetch-commands! {:contact contact
|
||||
:callback callback}]))))))
|
||||
|
||||
(defn http-get-commands [params url]
|
||||
(http-get url
|
||||
|
@ -48,14 +45,18 @@
|
|||
|
||||
|
||||
(defn fetch-commands!
|
||||
[_ [{{:keys [dapp? dapp-url bot-url whisper-identity]} :contact
|
||||
:as params}]]
|
||||
(if
|
||||
bot-url
|
||||
[_ [{{:keys [whisper-identity
|
||||
dapp-url
|
||||
bot-url
|
||||
dapp?]} :contact
|
||||
:as params}]]
|
||||
(if bot-url
|
||||
(if-let [resource (js-res/get-resource bot-url)]
|
||||
(dispatch [::validate-hash params resource])
|
||||
(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!
|
||||
[db [{{:keys [whisper-identity]} :contact
|
||||
|
@ -98,21 +99,25 @@
|
|||
(get-hash-by-file file))]
|
||||
(assoc db ::valid-hash valid?)))
|
||||
|
||||
(defn mark-as [as coll]
|
||||
(defn each-merge [coll with]
|
||||
(->> coll
|
||||
(map (fn [[k v]] [k (assoc v :type as)]))
|
||||
(map (fn [[k v]] [k (merge v with)]))
|
||||
(into {})))
|
||||
|
||||
(defn filter-forbidden-names [account id commands]
|
||||
(defn filter-commands [account {:keys [contacts chat-id] :as chat} commands]
|
||||
(->> commands
|
||||
(remove (fn [[_ {:keys [registered-only name]}]]
|
||||
(and (not (:address account))
|
||||
(not= name "global")
|
||||
registered-only)))
|
||||
(remove (fn [[n]]
|
||||
(and
|
||||
(not= console-chat-id id)
|
||||
(h/matches (name n) "password"))))
|
||||
;; TODO: this part should be removed because it's much better to provide the ability to do this in the API
|
||||
(map (fn [[k {:keys [name] :as v}]]
|
||||
[k (assoc v :hidden? (and (some #{name} ["send" "request"])
|
||||
(= 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 {})))
|
||||
|
||||
(defn get-mailmans-commands [db]
|
||||
|
@ -129,20 +134,24 @@
|
|||
(into {})))
|
||||
|
||||
(defn add-commands
|
||||
[db [id _ {:keys [commands responses subscriptions]}]]
|
||||
[{:keys [chats] :as db} [id _ {:keys [commands responses subscriptions]}]]
|
||||
(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')
|
||||
commands'' (apply dissoc commands' [:init :global])
|
||||
responses' (filter-forbidden-names account id responses)
|
||||
mailman-commands (get-mailmans-commands db)]
|
||||
(cond-> db
|
||||
|
||||
true
|
||||
(update-in [:contacts id] assoc
|
||||
:commands-loaded true
|
||||
:commands (mark-as :command (merge mailman-commands commands''))
|
||||
:responses (mark-as :response responses')
|
||||
:commands-loaded? true
|
||||
:commands (-> (merge mailman-commands commands'')
|
||||
(each-merge {:type :command
|
||||
:owner-id id}))
|
||||
:responses (each-merge responses' {:type :response
|
||||
:owner-id id})
|
||||
:subscriptions subscriptions)
|
||||
|
||||
global-command
|
||||
|
@ -167,7 +176,7 @@
|
|||
[{:keys [global-commands contacts]} [id]]
|
||||
(let [command (get global-commands (keyword id))
|
||||
commands (get-in contacts [id :commands])
|
||||
responses (get-in contacts [id :commands])]
|
||||
responses (get-in contacts [id :responses])]
|
||||
(contacts/save {:whisper-identity id
|
||||
:global-command command
|
||||
:commands (vals commands)
|
||||
|
@ -187,7 +196,7 @@
|
|||
(reg-handler :check-and-load-commands!
|
||||
(u/side-effect!
|
||||
(fn [{:keys [contacts]} [identity callback]]
|
||||
(if (get-in contacts [identity :commands-loaded])
|
||||
(if (get-in contacts [identity :commands-loaded?])
|
||||
(callback)
|
||||
(dispatch [:load-commands! identity callback])))))
|
||||
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
[status-im.components.react :as components]
|
||||
[status-im.chat.views.input.web-view :as chat-web-view]
|
||||
[status-im.chat.views.input.validation-messages :as chat-validation-messages]
|
||||
[status-im.chat.views.choosers.choose-contact :as choose-contact]
|
||||
[status-im.components.qr-code :as qr]
|
||||
[status-im.utils.handlers :refer [register-handler]]))
|
||||
[status-im.utils.handlers :refer [register-handler]]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn json->clj [json]
|
||||
(when-not (= json "undefined")
|
||||
|
@ -25,7 +27,8 @@
|
|||
:touchable components/touchable-highlight
|
||||
:activity-indicator components/activity-indicator
|
||||
:bridged-web-view chat-web-view/bridged-web-view
|
||||
:validation-message chat-validation-messages/validation-message})
|
||||
:validation-message chat-validation-messages/validation-message
|
||||
:choose-contact choose-contact/choose-contact-view})
|
||||
|
||||
(defn get-element [n]
|
||||
(elements (keyword (.toLowerCase n))))
|
||||
|
|
|
@ -262,7 +262,7 @@
|
|||
:dapp-hash dapp-hash}]
|
||||
(dispatch [:add-contacts [contact]])
|
||||
(when bot-url
|
||||
(dispatch [:load-commands! contact]))))))))))
|
||||
(dispatch [:load-commands! id']))))))))))
|
||||
|
||||
|
||||
(register-handler :add-contacts
|
||||
|
|
|
@ -39,6 +39,11 @@
|
|||
(let [contacts (subscribe [:all-added-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]
|
||||
(filter #(group-contacts (:whisper-identity %)) contacts))
|
||||
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
[[_ {:keys [name] :as 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
|
||||
[commands-map]
|
||||
(or (if (and commands-map (map? commands-map))
|
||||
|
@ -16,9 +20,12 @@
|
|||
(defn get-all
|
||||
[]
|
||||
(map
|
||||
(fn [{:keys [commands responses] :as contact}]
|
||||
(fn [{:keys [commands responses whisper-identity] :as 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))))
|
||||
(data-store/get-all-as-list)))
|
||||
|
||||
|
|
|
@ -7,19 +7,6 @@
|
|||
[status-im.constants :as c])
|
||||
(: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
|
||||
[user-statuses]
|
||||
(->> (vals user-statuses)
|
||||
|
@ -49,7 +36,7 @@
|
|||
(defn get-message-content-by-id [message-id]
|
||||
(when-let [{:keys [content-type content] :as message} (get-by-id message-id)]
|
||||
(when (command-type? content-type)
|
||||
(str-to-map content))))
|
||||
(read-string content))))
|
||||
|
||||
(defn get-messages
|
||||
[messages]
|
||||
|
@ -59,7 +46,7 @@
|
|||
reverse
|
||||
(keep (fn [{:keys [content-type] :as message}]
|
||||
(if (command-type? content-type)
|
||||
(clojure.core/update message :content str-to-map)
|
||||
(clojure.core/update message :content read-string)
|
||||
message)))))
|
||||
|
||||
(defn get-count-by-chat-id
|
||||
|
@ -76,7 +63,7 @@
|
|||
reverse
|
||||
(keep (fn [{:keys [content-type preview] :as message}]
|
||||
(if (command-type? content-type)
|
||||
(clojure.core/update message :content str-to-map)
|
||||
(clojure.core/update message :content read-string)
|
||||
message))))))
|
||||
|
||||
(defn get-log-messages
|
||||
|
@ -89,7 +76,7 @@
|
|||
[chat-id]
|
||||
(if-let [{:keys [content-type] :as message} (data-store/get-last-message chat-id)]
|
||||
(if (command-type? content-type)
|
||||
(clojure.core/update message :content str-to-map)
|
||||
(clojure.core/update message :content read-string)
|
||||
message)))
|
||||
|
||||
(defn get-last-outgoing
|
||||
|
@ -116,7 +103,7 @@
|
|||
(when-not (data-store/exists? message-id)
|
||||
(let [content' (if (string? content)
|
||||
content
|
||||
(map-to-str content))
|
||||
(pr-str content))
|
||||
message' (merge default-values
|
||||
message
|
||||
{: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.v7.core :as v7]
|
||||
[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
|
||||
(def schemas [{:schema v1/schema
|
||||
|
@ -36,4 +37,7 @@
|
|||
:migration v8/migration}
|
||||
{:schema v9/schema
|
||||
: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])
|
||||
|
||||
(defn migration [old-realm new-realm]
|
||||
(log/debug "migrating v8 account database: " old-realm new-realm)
|
||||
(contact/migration old-realm new-realm))
|
||||
(log/debug "migrating v8 account database: " old-realm new-realm))
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
(def demo-bot-js (slurp-bot :demo_bot))
|
||||
|
||||
(def commands-js wallet-js)
|
||||
|
||||
(def resources
|
||||
{:wallet-bot wallet-js
|
||||
:console-bot console-js
|
||||
|
|