Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-161-partial-redemption-fix

This commit is contained in:
Godwin Asuquo 2022-11-29 17:06:35 +02:00
commit 2eb9db4ca6
37 changed files with 438 additions and 363 deletions

116
.github/workflows/pr_test_build.yml vendored Normal file
View file

@ -0,0 +1,116 @@
name: PR Test Build
on:
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: '8.x'
- name: Flutter action
uses: subosito/flutter-action@v1
with:
flutter-version: '3.3.x'
channel: stable
- name: Install package dependencies
run: sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang
- name: Execute Build and Setup Commands
run: |
sudo mkdir -p /opt/android
sudo chown $USER /opt/android
cd /opt/android
git clone https://github.com/cake-tech/cake_wallet.git --branch $GITHUB_HEAD_REF
cd cake_wallet/scripts/android/
./install_ndk.sh
source ./app_env.sh cakewallet
./app_config.sh
./build_all.sh
./copy_monero_deps.sh
- name: Install Flutter dependencies
run: |
cd /opt/android/cake_wallet
flutter pub get
- name: Generate KeyStore
run: |
cd /opt/android/cake_wallet/android/app
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass ${{ secrets.STORE_PASS }} -keypass ${{ secrets.KEY_PASS }}
- name: Generate key properties
run: |
cd /opt/android/cake_wallet
flutter packages pub run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=${{ secrets.STORE_PASS }} keyPassword=${{ secrets.KEY_PASS }}
- name: Generate localization
run: |
cd /opt/android/cake_wallet
flutter packages pub run tool/generate_localization.dart
- name: Build generated code
run: |
cd /opt/android/cake_wallet
cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
flutter packages pub run build_runner build --delete-conflicting-outputs
- name: Add secrets
run: |
cd /opt/android/cake_wallet
touch lib/.secrets.g.dart
echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart
echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart
echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart
echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart
echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart
echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
echo "const sideShiftApiKey = '${{ secrets.SIDE_SHIFT_API_KEY }}';" >> lib/.secrets.g.dart
echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
- name: Build
run: |
cd /opt/android/cake_wallet
flutter build apk --release
# - name: Push to App Center
# run: |
# echo 'Installing App Center CLI tools'
# npm install -g appcenter-cli
# echo "Publishing test to App Center"
# appcenter distribute release \
# --group "Testers" \
# --file "/opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk" \
# --release-notes ${GITHUB_HEAD_REF} \
# --app Cake-Labs/Cake-Wallet \
# --token ${{ secrets.APP_CENTER_TOKEN }} \
# --quiet
- name: Send Test APK
run: |
cd /opt/android/cake_wallet
var=$(curl --upload-file build/app/outputs/apk/release/app-release.apk https://transfer.sh/app-release.apk)
curl ${{ secrets.SLACK_WEB_HOOK }} -H "Content-Type: application/json" -d '{"apk_link": "'"$var"'","ticket": "'"$GITHUB_HEAD_REF"'"}'

View file

@ -46,7 +46,7 @@ android {
defaultConfig { defaultConfig {
applicationId appProperties['id'] applicationId appProperties['id']
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 30 targetSdkVersion 31
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View file

@ -21,7 +21,8 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:screenOrientation="portrait"> android:screenOrientation="portrait"
android:exported="true">
<meta-data <meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable" android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" android:resource="@drawable/launch_background"

View file

@ -55,7 +55,7 @@ You may download and install the latest version of Android Studio [here](https:/
### 3. Installing Flutter ### 3. Installing Flutter
Need to install flutter with version `2.0.4`. For this please check section [Install Flutter manually](https://docs.flutter.dev/get-started/install/linux#install-flutter-manually). When flutter repository is downloaded please open it with `cd <flutter-path>` and checkout version 2.0.4 by `git checkout 2.0.4`. Need to install flutter with version `3.x.x`. For this please check section [Install Flutter manually](https://docs.flutter.dev/get-started/install/linux#install-flutter-manually).
### 4. Verify Installations ### 4. Verify Installations
@ -66,7 +66,7 @@ Verify that the Android toolchain, Flutter, and Android Studio have been correct
The output of this command will appear like this, indicating successful installations. If there are problems with your installation, they **must** be corrected before proceeding. The output of this command will appear like this, indicating successful installations. If there are problems with your installation, they **must** be corrected before proceeding.
``` ```
Doctor summary (to see all details, run flutter doctor -v): Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.0.4, on Linux, locale en_US.UTF-8) [✓] Flutter (Channel stable, 3.x.x, on Linux, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 28) [✓] Android toolchain - develop for Android devices (Android SDK version 28)
[✓] Android Studio (version 4.0) [✓] Android Studio (version 4.0)
``` ```
@ -156,6 +156,10 @@ Generate mobx models for `cw_bitcoin`:
`cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..` `cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..`
Generate mobx models for `cw_haven`:
`cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..`
Finally build mobx models for the app: Finally build mobx models for the app:
`$ flutter packages pub run build_runner build --delete-conflicting-outputs` `$ flutter packages pub run build_runner build --delete-conflicting-outputs`

View file

@ -701,6 +701,7 @@ Future setup(
ioniaAnyPayService: getIt.get<IoniaAnyPay>(), ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
amount: amount, amount: amount,
ioniaMerchant: merchant, ioniaMerchant: merchant,
sendViewModel: getIt.get<SendViewModel>()
); );
}); });

View file

@ -11,6 +11,7 @@ class PreferencesKey {
static const shouldSaveRecipientAddressKey = 'save_recipient_address'; static const shouldSaveRecipientAddressKey = 'save_recipient_address';
static const allowBiometricalAuthenticationKey = static const allowBiometricalAuthenticationKey =
'allow_biometrical_authentication'; 'allow_biometrical_authentication';
static const disableExchangeKey = 'disable_exchange';
static const currentTheme = 'current_theme'; static const currentTheme = 'current_theme';
static const isDarkThemeLegacy = 'dark_theme'; static const isDarkThemeLegacy = 'dark_theme';
static const displayActionListModeKey = 'display_list_mode'; static const displayActionListModeKey = 'display_list_mode';

View file

@ -232,7 +232,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final fromAmount = double.parse(responseJSON['fromAmount'].toString()); final fromAmount = double.parse(responseJSON['fromAmount'].toString());
final toAmount = double.parse(responseJSON['toAmount'].toString()); final toAmount = double.parse(responseJSON['toAmount'].toString());
final rateId = responseJSON['rateId'] as String ?? ''; final rateId = responseJSON['rateId'] as String? ?? '';
if (rateId.isNotEmpty) { if (rateId.isNotEmpty) {
_lastUsedRateId = rateId; _lastUsedRateId = rateId;

View file

@ -315,6 +315,8 @@ class DashboardPage extends BasePage {
} }
Future<void> _onClickExchangeButton(BuildContext context) async { Future<void> _onClickExchangeButton(BuildContext context) async {
await Navigator.of(context).pushNamed(Routes.exchange); if (walletViewModel.isEnabledExchangeAction) {
await Navigator.of(context).pushNamed(Routes.exchange);
}
} }
} }

View file

@ -3,7 +3,6 @@ import 'package:cake_wallet/ionia/ionia_merchant.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/ionia/ionia_tip.dart';
import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/ionia/widgets/confirm_modal.dart';
import 'package:cake_wallet/src/screens/ionia/widgets/ionia_alert_model.dart'; import 'package:cake_wallet/src/screens/ionia/widgets/ionia_alert_model.dart';
import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart'; import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
@ -18,6 +17,7 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
class IoniaBuyGiftCardDetailPage extends BasePage { class IoniaBuyGiftCardDetailPage extends BasePage {
IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel); IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel);
@ -295,73 +295,35 @@ class IoniaBuyGiftCardDetailPage extends BasePage {
final amount = ioniaPurchaseViewModel.invoice!.totalAmount; final amount = ioniaPurchaseViewModel.invoice!.totalAmount;
final addresses = ioniaPurchaseViewModel.invoice!.outAddresses; final addresses = ioniaPurchaseViewModel.invoice!.outAddresses;
ioniaPurchaseViewModel.sendViewModel.outputs.first.setCryptoAmount(amount);
ioniaPurchaseViewModel.sendViewModel.outputs.first.address = addresses.first;
await showPopUp<void>( await showPopUp<void>(
context: context, context: context,
builder: (_) { builder: (_) {
return IoniaConfirmModal( return ConfirmSendingAlert(
alertTitle: S.of(context).confirm_sending, alertTitle: S.of(context).confirm_sending,
alertContent: Container( paymentId: S.of(context).payment_id,
height: 200, paymentIdValue: ioniaPurchaseViewModel.invoice!.paymentId,
padding: EdgeInsets.all(15), amount: S.of(context).send_amount,
child: Column(children: [ amountValue: '$amount ${ioniaPurchaseViewModel.invoice!.chain}',
Row(children: [ fiatAmountValue:
Text(S.of(context).payment_id, '~ ${ioniaPurchaseViewModel.sendViewModel.outputs.first.fiatAmount} '
textAlign: TextAlign.center, '${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
style: TextStyle( fee: S.of(context).send_fee,
fontSize: 16, feeValue:
fontWeight: FontWeight.w400, '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFee} '
color: PaletteDark.pigeonBlue, '${ioniaPurchaseViewModel.invoice!.chain}',
decoration: TextDecoration.none)), feeFiatAmount:
Text(ioniaPurchaseViewModel.invoice!.paymentId, '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFeeFiatAmount} '
style: TextStyle( '${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
fontSize: 16, outputs: ioniaPurchaseViewModel.sendViewModel.outputs,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none))
], mainAxisAlignment: MainAxisAlignment.spaceBetween),
SizedBox(height: 10),
Row(children: [
Text(S.of(context).amount,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none)),
Text('$amount ${ioniaPurchaseViewModel.invoice!.chain}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none))
], mainAxisAlignment: MainAxisAlignment.spaceBetween),
SizedBox(height: 25),
Row(children: [
Text(S.of(context).recipient_address,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none))
], mainAxisAlignment: MainAxisAlignment.center),
Expanded(
child: ListView.builder(
itemBuilder: (_, int index) {
return Text(addresses[index],
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none));
},
itemCount: addresses.length,
physics: NeverScrollableScrollPhysics()))
])),
rightButtonText: S.of(context).ok, rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel, leftButtonText: S.of(context).cancel,
leftActionColor: Color(0xffFF6600), alertLeftActionButtonTextColor: Colors.white,
rightActionColor: Theme.of(context).accentTextTheme!.bodyText1!.color!, alertRightActionButtonTextColor: Colors.white,
alertLeftActionButtonColor: Palette.brightOrange,
alertRightActionButtonColor: Theme.of(context).textTheme!.subtitle2!.color,
actionRightButton: () async { actionRightButton: () async {
Navigator.of(context).pop(); Navigator.of(context).pop();
await ioniaPurchaseViewModel.commitPaymentInvoice(); await ioniaPurchaseViewModel.commitPaymentInvoice();

View file

@ -1,149 +0,0 @@
import 'dart:ui';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
class IoniaConfirmModal extends StatelessWidget {
IoniaConfirmModal({
required this.alertTitle,
required this.alertContent,
required this.leftButtonText,
required this.rightButtonText,
required this.actionLeftButton,
required this.actionRightButton,
required this.leftActionColor,
required this.rightActionColor,
this.hideActions = false,
});
final String alertTitle;
final Widget alertContent;
final String leftButtonText;
final String rightButtonText;
final VoidCallback actionLeftButton;
final VoidCallback actionRightButton;
final Color leftActionColor;
final Color rightActionColor;
final bool hideActions;
Widget actionButtons(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IoniaActionButton(
buttonText: leftButtonText,
action: actionLeftButton,
backgoundColor: leftActionColor,
),
Container(
width: 1,
height: 52,
color: Theme.of(context).dividerColor,
),
IoniaActionButton(
buttonText: rightButtonText,
action: actionRightButton,
backgoundColor: rightActionColor,
),
],
);
}
Widget title(BuildContext context) {
return Text(
alertTitle,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
decoration: TextDecoration.none,
),
);
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.transparent,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
child: Container(
decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)),
child: Center(
child: GestureDetector(
onTap: () => null,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
width: 327,
color: Theme.of(context).accentTextTheme!.headline6!.decorationColor!,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: EdgeInsets.fromLTRB(24, 20, 24, 0),
child: title(context),
),
Padding(
padding: EdgeInsets.only(top: 16, bottom: 8),
child: Container(
height: 1,
color: Theme.of(context).dividerColor,
),
),
alertContent,
actionButtons(context),
],
),
),
),
),
),
),
),
);
}
}
class IoniaActionButton extends StatelessWidget {
const IoniaActionButton({
required this.buttonText,
required this.action,
required this.backgoundColor,
});
final String buttonText;
final VoidCallback action;
final Color backgoundColor;
@override
Widget build(BuildContext context) {
return Flexible(
child: Container(
height: 52,
padding: EdgeInsets.only(left: 6, right: 6),
color: backgoundColor,
child: ButtonTheme(
minWidth: double.infinity,
child: TextButton(
onPressed: action,
// FIX-ME: ignored highlightColor and splashColor
//highlightColor: Colors.transparent,
//splashColor: Colors.transparent,
child: Text(
buttonText,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: backgoundColor != null ? Colors.white : Theme.of(context).primaryTextTheme!.bodyText2!.backgroundColor!,
decoration: TextDecoration.none,
),
)),
),
));
}
}

View file

@ -9,7 +9,6 @@ class QrPainter extends CustomPainter {
this.errorCorrectionLevel, this.errorCorrectionLevel,
) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) { ) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) {
_p.color = this.color; _p.color = this.color;
_qr.addData(data);
_qrImage = QrImage(_qr); _qrImage = QrImage(_qr);
} }

View file

@ -4,10 +4,13 @@ import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/cake_scrollbar.dart'; import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
import 'package:flutter/scheduler.dart';
class ConfirmSendingAlert extends BaseAlertDialog { class ConfirmSendingAlert extends BaseAlertDialog {
ConfirmSendingAlert({ ConfirmSendingAlert({
required this.alertTitle, required this.alertTitle,
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -19,9 +22,15 @@ class ConfirmSendingAlert extends BaseAlertDialog {
required this.rightButtonText, required this.rightButtonText,
required this.actionLeftButton, required this.actionLeftButton,
required this.actionRightButton, required this.actionRightButton,
this.alertBarrierDismissible = true}); this.alertBarrierDismissible = true,
this.alertLeftActionButtonTextColor,
this.alertRightActionButtonTextColor,
this.alertLeftActionButtonColor,
this.alertRightActionButtonColor});
final String alertTitle; final String alertTitle;
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -34,6 +43,10 @@ class ConfirmSendingAlert extends BaseAlertDialog {
final VoidCallback actionLeftButton; final VoidCallback actionLeftButton;
final VoidCallback actionRightButton; final VoidCallback actionRightButton;
final bool alertBarrierDismissible; final bool alertBarrierDismissible;
final Color? alertLeftActionButtonTextColor;
final Color? alertRightActionButtonTextColor;
final Color? alertLeftActionButtonColor;
final Color? alertRightActionButtonColor;
@override @override
String get titleText => alertTitle; String get titleText => alertTitle;
@ -56,8 +69,22 @@ class ConfirmSendingAlert extends BaseAlertDialog {
@override @override
bool get barrierDismissible => alertBarrierDismissible; bool get barrierDismissible => alertBarrierDismissible;
@override
Color? get leftActionButtonTextColor => alertLeftActionButtonTextColor;
@override
Color? get rightActionButtonTextColor => alertRightActionButtonTextColor;
@override
Color? get leftActionButtonColor => alertLeftActionButtonColor;
@override
Color? get rightActionButtonColor => alertRightActionButtonColor;
@override @override
Widget content(BuildContext context) => ConfirmSendingAlertContent( Widget content(BuildContext context) => ConfirmSendingAlertContent(
paymentId: paymentId,
paymentIdValue: paymentIdValue,
amount: amount, amount: amount,
amountValue: amountValue, amountValue: amountValue,
fiatAmountValue: fiatAmountValue, fiatAmountValue: fiatAmountValue,
@ -70,6 +97,8 @@ class ConfirmSendingAlert extends BaseAlertDialog {
class ConfirmSendingAlertContent extends StatefulWidget { class ConfirmSendingAlertContent extends StatefulWidget {
ConfirmSendingAlertContent({ ConfirmSendingAlertContent({
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -78,6 +107,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
required this.feeFiatAmount, required this.feeFiatAmount,
required this.outputs}); required this.outputs});
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -88,6 +119,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
@override @override
ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState( ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState(
paymentId: paymentId,
paymentIdValue: paymentIdValue,
amount: amount, amount: amount,
amountValue: amountValue, amountValue: amountValue,
fiatAmountValue: fiatAmountValue, fiatAmountValue: fiatAmountValue,
@ -100,6 +133,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent> { class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent> {
ConfirmSendingAlertContentState({ ConfirmSendingAlertContentState({
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -115,6 +150,8 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
: S.current.recipient_address; : S.current.recipient_address;
} }
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -129,6 +166,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
double fromTop = 0; double fromTop = 0;
String recipientTitle; String recipientTitle;
int itemCount; int itemCount;
bool showScrollbar = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -140,6 +178,12 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
setState(() {}); setState(() {});
}); });
SchedulerBinding.instance.addPostFrameCallback((_) {
setState(() {
showScrollbar = controller.position.maxScrollExtent > 0;
});
});
return Stack( return Stack(
alignment: Alignment.center, alignment: Alignment.center,
clipBehavior: Clip.none, clipBehavior: Clip.none,
@ -150,6 +194,44 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
controller: controller, controller: controller,
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
if (paymentIdValue != null && paymentId != null)
Padding(
padding: EdgeInsets.only(bottom: 32),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
paymentId!,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme!
.headline6!.color!,
decoration: TextDecoration.none,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
paymentIdValue!,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme!
.headline6!.color!,
decoration: TextDecoration.none,
),
),
],
)
],
),
),
Row( Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -365,7 +447,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
) )
) )
), ),
if (itemCount > 1) CakeScrollbar( if (showScrollbar) CakeScrollbar(
backgroundHeight: backgroundHeight, backgroundHeight: backgroundHeight,
thumbHeight: thumbHeight, thumbHeight: thumbHeight,
fromTop: fromTop, fromTop: fromTop,

View file

@ -11,6 +11,10 @@ class BaseAlertDialog extends StatelessWidget {
VoidCallback get actionLeft => () {}; VoidCallback get actionLeft => () {};
VoidCallback get actionRight => () {}; VoidCallback get actionRight => () {};
bool get barrierDismissible => true; bool get barrierDismissible => true;
Color? get leftActionButtonTextColor => null;
Color? get rightActionButtonTextColor => null;
Color? get leftActionButtonColor => null;
Color? get rightActionButtonColor => null;
Widget title(BuildContext context) { Widget title(BuildContext context) {
return Text( return Text(
@ -45,52 +49,64 @@ class BaseAlertDialog extends StatelessWidget {
height: 52, height: 52,
child: Row( child: Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
Flexible( Expanded(
child: Container( child: TextButton(
width: double.infinity, onPressed: actionLeft,
color: Theme.of(context).accentTextTheme!.bodyText1!.decorationColor!, style: TextButton.styleFrom(
child: TextButton( backgroundColor: leftActionButtonColor ??
onPressed: actionLeft, Theme.of(context)
child: Text( .accentTextTheme!
leftActionButtonText, .bodyText1!
textAlign: TextAlign.center, .decorationColor!,
style: TextStyle( shape: const RoundedRectangleBorder(
fontSize: 15, borderRadius: BorderRadius.all(Radius.zero))),
fontFamily: 'Lato', child: Text(
fontWeight: FontWeight.w600, leftActionButtonText,
color: Theme.of(context).primaryTextTheme!.bodyText1!.backgroundColor!, textAlign: TextAlign.center,
decoration: TextDecoration.none, style: TextStyle(
), fontSize: 15,
)), fontFamily: 'Lato',
), fontWeight: FontWeight.w600,
), color: leftActionButtonTextColor ??
Theme.of(context).primaryTextTheme!
.bodyText1!.backgroundColor!,
decoration: TextDecoration.none,
),
)),
),
Container( Container(
width: 1, width: 1,
color: Theme.of(context).dividerColor, color: Theme.of(context).dividerColor,
), ),
Flexible( Expanded(
child: Container( child: TextButton(
width: double.infinity, onPressed: actionRight,
color: Theme.of(context).accentTextTheme!.bodyText2!.backgroundColor!, style: TextButton.styleFrom(
child: TextButton( backgroundColor: rightActionButtonColor ??
onPressed: actionRight, Theme.of(context).accentTextTheme!
child: Text( .bodyText2!.backgroundColor!,
rightActionButtonText, shape: const RoundedRectangleBorder(
textAlign: TextAlign.center, borderRadius: BorderRadius.all(Radius.zero))),
style: TextStyle( child: Text(
fontSize: 15, rightActionButtonText,
fontFamily: 'Lato', textAlign: TextAlign.center,
fontWeight: FontWeight.w600, style: TextStyle(
color: Theme.of(context).primaryTextTheme!.bodyText2!.backgroundColor!, fontSize: 15,
decoration: TextDecoration.none, fontFamily: 'Lato',
), fontWeight: FontWeight.w600,
)), color: rightActionButtonTextColor ??
), Theme.of(context)
), .primaryTextTheme!
], .bodyText2!
)); .backgroundColor!,
decoration: TextDecoration.none,
),
)),
),
],
));
} }
@override @override

View file

@ -30,6 +30,7 @@ abstract class SettingsStoreBase with Store {
required BalanceDisplayMode initialBalanceDisplayMode, required BalanceDisplayMode initialBalanceDisplayMode,
required bool initialSaveRecipientAddress, required bool initialSaveRecipientAddress,
required bool initialAllowBiometricalAuthentication, required bool initialAllowBiometricalAuthentication,
required bool initialExchangeEnabled,
required ThemeBase initialTheme, required ThemeBase initialTheme,
required int initialPinLength, required int initialPinLength,
required String initialLanguageCode, required String initialLanguageCode,
@ -47,6 +48,7 @@ abstract class SettingsStoreBase with Store {
balanceDisplayMode = initialBalanceDisplayMode, balanceDisplayMode = initialBalanceDisplayMode,
shouldSaveRecipientAddress = initialSaveRecipientAddress, shouldSaveRecipientAddress = initialSaveRecipientAddress,
allowBiometricalAuthentication = initialAllowBiometricalAuthentication, allowBiometricalAuthentication = initialAllowBiometricalAuthentication,
disableExchange = initialExchangeEnabled,
currentTheme = initialTheme, currentTheme = initialTheme,
pinCodeLength = initialPinLength, pinCodeLength = initialPinLength,
languageCode = initialLanguageCode, languageCode = initialLanguageCode,
@ -143,6 +145,9 @@ abstract class SettingsStoreBase with Store {
@observable @observable
bool allowBiometricalAuthentication; bool allowBiometricalAuthentication;
@observable
bool disableExchange;
@observable @observable
ThemeBase currentTheme; ThemeBase currentTheme;
@ -221,6 +226,8 @@ abstract class SettingsStoreBase with Store {
final allowBiometricalAuthentication = sharedPreferences final allowBiometricalAuthentication = sharedPreferences
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? .getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
false; false;
final disableExchange = sharedPreferences
.getBool(PreferencesKey.disableExchangeKey) ?? false;
final legacyTheme = final legacyTheme =
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false) (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
? ThemeType.dark.index ? ThemeType.dark.index
@ -284,6 +291,7 @@ abstract class SettingsStoreBase with Store {
initialBalanceDisplayMode: currentBalanceDisplayMode, initialBalanceDisplayMode: currentBalanceDisplayMode,
initialSaveRecipientAddress: shouldSaveRecipientAddress, initialSaveRecipientAddress: shouldSaveRecipientAddress,
initialAllowBiometricalAuthentication: allowBiometricalAuthentication, initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
initialExchangeEnabled: disableExchange,
initialTheme: savedTheme, initialTheme: savedTheme,
actionlistDisplayMode: actionListDisplayMode, actionlistDisplayMode: actionListDisplayMode,
initialPinLength: pinLength, initialPinLength: pinLength,

View file

@ -53,7 +53,6 @@ abstract class DashboardViewModelBase with Store {
hasBuyAction = false, hasBuyAction = false,
isEnabledBuyAction = false, isEnabledBuyAction = false,
hasExchangeAction = false, hasExchangeAction = false,
isEnabledExchangeAction = false,
isShowFirstYatIntroduction = false, isShowFirstYatIntroduction = false,
isShowSecondYatIntroduction = false, isShowSecondYatIntroduction = false,
isShowThirdYatIntroduction = false, isShowThirdYatIntroduction = false,
@ -249,8 +248,8 @@ abstract class DashboardViewModelBase with Store {
void furtherShowYatPopup(bool shouldShow) => void furtherShowYatPopup(bool shouldShow) =>
settingsStore.shouldShowYatPopup = shouldShow; settingsStore.shouldShowYatPopup = shouldShow;
@observable @computed
bool isEnabledExchangeAction; bool get isEnabledExchangeAction => !settingsStore.disableExchange;
@observable @observable
bool hasExchangeAction; bool hasExchangeAction;
@ -365,7 +364,6 @@ abstract class DashboardViewModelBase with Store {
} }
void updateActions() { void updateActions() {
isEnabledExchangeAction = true;
hasExchangeAction = !isHaven; hasExchangeAction = !isHaven;
isEnabledBuyAction = wallet.type != WalletType.haven isEnabledBuyAction = wallet.type != WalletType.haven
&& wallet.type != WalletType.monero; && wallet.type != WalletType.monero;

View file

@ -7,7 +7,6 @@ import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart'
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart'; import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart'; import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart';
import 'package:cake_wallet/view_model/settings/settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart'; import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
@ -375,96 +374,105 @@ abstract class ExchangeViewModelBase with Store {
TradeRequest? request; TradeRequest? request;
String amount = ''; String amount = '';
for (var provider in _sortedAvailableProviders.values) { try {
if (!(await provider.checkIsAvailable())) { for (var provider in _sortedAvailableProviders.values) {
continue; if (!(await provider.checkIsAvailable())) {
} continue;
}
if (provider is SideShiftExchangeProvider) { if (provider is SideShiftExchangeProvider) {
request = SideShiftRequest( request = SideShiftRequest(
depositMethod: depositCurrency, depositMethod: depositCurrency,
settleMethod: receiveCurrency, settleMethod: receiveCurrency,
depositAmount: depositAmount.replaceAll(',', '.'), depositAmount: depositAmount.replaceAll(',', '.'),
settleAddress: receiveAddress, settleAddress: receiveAddress,
refundAddress: depositAddress, refundAddress: depositAddress,
); );
amount = depositAmount; amount = depositAmount;
} }
if (provider is SimpleSwapExchangeProvider) { if (provider is SimpleSwapExchangeProvider) {
request = SimpleSwapRequest( request = SimpleSwapRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'),
address: receiveAddress,
refundAddress: depositAddress,
);
amount = depositAmount;
}
if (provider is XMRTOExchangeProvider) {
request = XMRTOTradeRequest(
from: depositCurrency, from: depositCurrency,
to: receiveCurrency, to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'), amount: depositAmount.replaceAll(',', '.'),
receiveAmount: receiveAmount.replaceAll(',', '.'),
address: receiveAddress, address: receiveAddress,
refundAddress: depositAddress, refundAddress: depositAddress,
isBTCRequest: isReceiveAmountEntered); );
amount = depositAmount; amount = depositAmount;
} }
if (provider is ChangeNowExchangeProvider) { if (provider is XMRTOExchangeProvider) {
request = ChangeNowRequest( request = XMRTOTradeRequest(
from: depositCurrency, from: depositCurrency,
to: receiveCurrency, to: receiveCurrency,
fromAmount: depositAmount.replaceAll(',', '.'), amount: depositAmount.replaceAll(',', '.'),
toAmount: receiveAmount.replaceAll(',', '.'), receiveAmount: receiveAmount.replaceAll(',', '.'),
refundAddress: depositAddress, address: receiveAddress,
address: receiveAddress, refundAddress: depositAddress,
isReverse: isReverse); isBTCRequest: isReceiveAmountEntered);
amount = isReverse ? receiveAmount : depositAmount; amount = depositAmount;
} }
if (provider is MorphTokenExchangeProvider) { if (provider is ChangeNowExchangeProvider) {
request = MorphTokenRequest( request = ChangeNowRequest(
from: depositCurrency, from: depositCurrency,
to: receiveCurrency, to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'), fromAmount: depositAmount.replaceAll(',', '.'),
refundAddress: depositAddress, toAmount: receiveAmount.replaceAll(',', '.'),
address: receiveAddress); refundAddress: depositAddress,
amount = depositAmount; address: receiveAddress,
} isReverse: isReverse);
amount = isReverse ? receiveAmount : depositAmount;
}
amount = amount.replaceAll(',', '.'); if (provider is MorphTokenExchangeProvider) {
request = MorphTokenRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'),
refundAddress: depositAddress,
address: receiveAddress);
amount = depositAmount;
}
if (limitsState is LimitsLoadedSuccessfully) { amount = amount.replaceAll(',', '.');
if (double.parse(amount) < limits.min!) {
continue; if (limitsState is LimitsLoadedSuccessfully) {
} else if (limits.max != null && double.parse(amount) > limits.max!) { if (double.parse(amount) < limits.min!) {
continue;
} else {
try {
tradeState = TradeIsCreating();
final trade = await provider.createTrade(
request: request!, isFixedRateMode: isFixedRateMode);
trade.walletId = wallet.id;
tradesStore.setTrade(trade);
await trades.add(trade);
tradeState = TradeIsCreatedSuccessfully(trade: trade);
/// return after the first successful trade
return;
} catch (e) {
continue; continue;
} else if (limits.max != null && double.parse(amount) > limits.max!) {
continue;
} else {
try {
tradeState = TradeIsCreating();
final trade = await provider.createTrade(
request: request!, isFixedRateMode: isFixedRateMode);
trade.walletId = wallet.id;
tradesStore.setTrade(trade);
await trades.add(trade);
tradeState = TradeIsCreatedSuccessfully(trade: trade);
/// return after the first successful trade
return;
} catch (e) {
continue;
}
} }
} }
} }
}
/// if the code reached here then none of the providers succeeded /// if the code reached here then none of the providers succeeded
tradeState = TradeIsCreatedFailure( tradeState = TradeIsCreatedFailure(
title: S.current.trade_not_created, title: S.current.trade_not_created,
error: S.current.none_of_selected_providers_can_exchange); error: S.current.none_of_selected_providers_can_exchange);
} on ConcurrentModificationError {
/// if create trade happened at the exact same time of the scheduled rate update
/// then delay the create trade a bit and try again
///
/// this is because the limitation of the SplayTreeMap that
/// you can't modify it while iterating through it
Future.delayed(Duration(milliseconds: 500), createTrade);
}
} }
@action @action

View file

@ -7,6 +7,7 @@ import 'package:cake_wallet/ionia/ionia_anypay.dart';
import 'package:cake_wallet/ionia/ionia_merchant.dart'; import 'package:cake_wallet/ionia/ionia_merchant.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/ionia/ionia_tip.dart';
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
import 'package:cake_wallet/view_model/send/send_view_model.dart';
part 'ionia_purchase_merch_view_model.g.dart'; part 'ionia_purchase_merch_view_model.g.dart';
@ -17,6 +18,7 @@ abstract class IoniaMerchPurchaseViewModelBase with Store {
required this.ioniaAnyPayService, required this.ioniaAnyPayService,
required this.amount, required this.amount,
required this.ioniaMerchant, required this.ioniaMerchant,
required this.sendViewModel,
}) : tipAmount = 0.0, }) : tipAmount = 0.0,
percentage = 0.0, percentage = 0.0,
invoiceCreationState = InitialExecutionState(), invoiceCreationState = InitialExecutionState(),
@ -40,6 +42,8 @@ abstract class IoniaMerchPurchaseViewModelBase with Store {
final IoniaMerchant ioniaMerchant; final IoniaMerchant ioniaMerchant;
final SendViewModel sendViewModel;
final IoniaAnyPay ioniaAnyPayService; final IoniaAnyPay ioniaAnyPayService;
IoniaAnyPayPaymentInfo? paymentInfo; IoniaAnyPayPaymentInfo? paymentInfo;

View file

@ -208,6 +208,12 @@ abstract class SettingsViewModelBase with Store {
setAllowBiometricalAuthentication(value); setAllowBiometricalAuthentication(value);
} }
}), }),
SwitcherListItem(
title: S.current.disable_exchange,
value: () => _settingsStore.disableExchange,
onValueChange: (BuildContext context, bool value) {
_settingsStore.disableExchange = value;
}),
ChoicesListItem( ChoicesListItem(
title: S.current.color_theme, title: S.current.color_theme,
items: ThemeList.all, items: ThemeList.all,

View file

@ -34,7 +34,7 @@ dependencies:
local_auth: ^2.1.0 local_auth: ^2.1.0
package_info: ^2.0.0 package_info: ^2.0.0
#package_info_plus: ^1.4.2 #package_info_plus: ^1.4.2
devicelocale: ^0.5.4 devicelocale: ^0.4.3
auto_size_text: ^3.0.0 auto_size_text: ^3.0.0
dotted_border: ^2.0.0+2 dotted_border: ^2.0.0+2
smooth_page_indicator: ^1.0.0+2 smooth_page_indicator: ^1.0.0+2

View file

@ -651,5 +651,6 @@
"ignor": "Ignorieren", "ignor": "Ignorieren",
"use_suggested": "Vorgeschlagen verwenden", "use_suggested": "Vorgeschlagen verwenden",
"do_not_share_warning_text" : "Teilen Sie diese nicht mit anderen, einschließlich des Supports.\n\nSie werden Ihr Geld stehlen!", "do_not_share_warning_text" : "Teilen Sie diese nicht mit anderen, einschließlich des Supports.\n\nSie werden Ihr Geld stehlen!",
"help": "hilfe" "help": "hilfe",
"disable_exchange": "Exchange deaktivieren"
} }

View file

@ -651,5 +651,6 @@
"ignor": "Ignore", "ignor": "Ignore",
"use_suggested": "Use Suggested", "use_suggested": "Use Suggested",
"do_not_share_warning_text" : "Do not share these with anyone else, including support.\n\nThey will steal your money!", "do_not_share_warning_text" : "Do not share these with anyone else, including support.\n\nThey will steal your money!",
"help": "help" "help": "help",
"disable_exchange": "Disable exchange"
} }

View file

@ -651,5 +651,6 @@
"ignor": "Pasar por alto", "ignor": "Pasar por alto",
"use_suggested": "Usar sugerido", "use_suggested": "Usar sugerido",
"do_not_share_warning_text" : "No comparta estos con nadie más, incluido el soporte.\n\n¡Te robarán tu dinero!", "do_not_share_warning_text" : "No comparta estos con nadie más, incluido el soporte.\n\n¡Te robarán tu dinero!",
"help": "ayuda" "help": "ayuda",
"disable_exchange": "Deshabilitar intercambio"
} }

View file

@ -649,5 +649,6 @@
"ignor": "Ignorer", "ignor": "Ignorer",
"use_suggested": "Utilisation suggérée", "use_suggested": "Utilisation suggérée",
"do_not_share_warning_text" : "Ne les partagez avec personne d'autre, y compris avec l'assistance.\n\nIls vont voler votre argent!", "do_not_share_warning_text" : "Ne les partagez avec personne d'autre, y compris avec l'assistance.\n\nIls vont voler votre argent!",
"help": "aider" "help": "aider",
"disable_exchange": "Désactiver l'échange"
} }

View file

@ -651,5 +651,6 @@
"ignor": "नज़रअंदाज़ करना", "ignor": "नज़रअंदाज़ करना",
"use_suggested": "सुझाए गए का प्रयोग करें", "use_suggested": "सुझाए गए का प्रयोग करें",
"do_not_share_warning_text" : "इन्हें समर्थन सहित किसी और के साथ साझा न करें।\n\nवे आपका पैसा चुरा लेंगे!", "do_not_share_warning_text" : "इन्हें समर्थन सहित किसी और के साथ साझा न करें।\n\nवे आपका पैसा चुरा लेंगे!",
"help": "मदद करना" "help": "मदद करना",
"disable_exchange": "एक्सचेंज अक्षम करें"
} }

View file

@ -651,5 +651,6 @@
"ignor": "Zanemariti", "ignor": "Zanemariti",
"use_suggested": "Koristite predloženo", "use_suggested": "Koristite predloženo",
"do_not_share_warning_text" : "Nemojte ih dijeliti ni s kim, uključujući podršku.\n\nUkrast će vam novac!", "do_not_share_warning_text" : "Nemojte ih dijeliti ni s kim, uključujući podršku.\n\nUkrast će vam novac!",
"help": "pomozite" "help": "pomozite",
"disable_exchange": "Onemogući exchange"
} }

View file

@ -651,5 +651,6 @@
"ignor": "Ignorare", "ignor": "Ignorare",
"use_suggested": "Usa suggerito", "use_suggested": "Usa suggerito",
"do_not_share_warning_text" : "Non condividerli con nessun altro, incluso il supporto.\n\nTi ruberanno i soldi!", "do_not_share_warning_text" : "Non condividerli con nessun altro, incluso il supporto.\n\nTi ruberanno i soldi!",
"help": "aiuto" "help": "aiuto",
"disable_exchange": "Disabilita scambio"
} }

View file

@ -651,5 +651,6 @@
"ignor": "無視", "ignor": "無視",
"use_suggested": "推奨を使用", "use_suggested": "推奨を使用",
"do_not_share_warning_text" : "サポートを含め、これらを他の誰とも共有しないでください。\n\n彼らはあなたのお金を盗みます", "do_not_share_warning_text" : "サポートを含め、これらを他の誰とも共有しないでください。\n\n彼らはあなたのお金を盗みます",
"help": "ヘルプ" "help": "ヘルプ",
"disable_exchange": "交換を無効にする"
} }

View file

@ -651,5 +651,6 @@
"ignor": "무시하다", "ignor": "무시하다",
"use_suggested": "추천 사용", "use_suggested": "추천 사용",
"do_not_share_warning_text" : "지원을 포함하여 다른 사람과 이러한 정보를 공유하지 마십시오.\n\n그들은 당신의 돈을 훔칠 것입니다!", "do_not_share_warning_text" : "지원을 포함하여 다른 사람과 이러한 정보를 공유하지 마십시오.\n\n그들은 당신의 돈을 훔칠 것입니다!",
"help": "돕다" "help": "돕다",
"disable_exchange": "교환 비활성화"
} }

View file

@ -651,5 +651,6 @@
"ignor": "Negeren", "ignor": "Negeren",
"use_suggested": "Gebruik aanbevolen", "use_suggested": "Gebruik aanbevolen",
"do_not_share_warning_text" : "Deel deze met niemand anders, ook niet met support.\n\nZe zullen je geld stelen!", "do_not_share_warning_text" : "Deel deze met niemand anders, ook niet met support.\n\nZe zullen je geld stelen!",
"help": "helpen" "help": "helpen",
"disable_exchange": "Uitwisseling uitschakelen"
} }

View file

@ -651,5 +651,6 @@
"ignor": "Ignorować", "ignor": "Ignorować",
"use_suggested": "Użyj sugerowane", "use_suggested": "Użyj sugerowane",
"do_not_share_warning_text" : "Nie udostępniaj ich nikomu innemu, w tym wsparcia.\n\nUkradną twoje pieniądze!", "do_not_share_warning_text" : "Nie udostępniaj ich nikomu innemu, w tym wsparcia.\n\nUkradną twoje pieniądze!",
"help": "pomoc" "help": "pomoc",
"disable_exchange": "Wyłącz wymianę"
} }

View file

@ -651,5 +651,6 @@
"ignor": "Ignorar", "ignor": "Ignorar",
"use_suggested": "Uso sugerido", "use_suggested": "Uso sugerido",
"do_not_share_warning_text" : "Não os compartilhe com mais ninguém, incluindo suporte.\n\nEles vão roubar seu dinheiro!", "do_not_share_warning_text" : "Não os compartilhe com mais ninguém, incluindo suporte.\n\nEles vão roubar seu dinheiro!",
"help": "ajuda" "help": "ajuda",
"disable_exchange": "Desativar troca"
} }

View file

@ -651,5 +651,6 @@
"ignor": "Игнорировать", "ignor": "Игнорировать",
"use_suggested": "Использовать предложенный", "use_suggested": "Использовать предложенный",
"do_not_share_warning_text" : "Не делитесь ими с кем-либо еще, в том числе со службой поддержки.\n\nОни украдут ваши деньги!", "do_not_share_warning_text" : "Не делитесь ими с кем-либо еще, в том числе со службой поддержки.\n\nОни украдут ваши деньги!",
"help": "помощь" "help": "помощь",
"disable_exchange": "Отключить обмен"
} }

View file

@ -650,5 +650,6 @@
"ignor": "Ігнорувати", "ignor": "Ігнорувати",
"use_suggested": "Використати запропоноване", "use_suggested": "Використати запропоноване",
"do_not_share_warning_text" : "Не повідомляйте їх нікому, включно зі службою підтримки.\n\nВони вкрадуть ваші гроші!", "do_not_share_warning_text" : "Не повідомляйте їх нікому, включно зі службою підтримки.\n\nВони вкрадуть ваші гроші!",
"help": "допомога" "help": "допомога",
"disable_exchange": "Вимкнути exchange"
} }

View file

@ -649,5 +649,6 @@
"ignor": "忽视", "ignor": "忽视",
"use_suggested": "使用建议", "use_suggested": "使用建议",
"do_not_share_warning_text" : "不要與其他任何人分享這些內容,包括支持。\n\n他們會偷你的錢", "do_not_share_warning_text" : "不要與其他任何人分享這些內容,包括支持。\n\n他們會偷你的錢",
"help": "帮助" "help": "帮助",
"disable_exchange": "禁用交换"
} }

View file

@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_ANDROID_TYPE=$1 APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.2.0" MONERO_COM_VERSION="1.2.1"
MONERO_COM_BUILD_NUMBER=26 MONERO_COM_BUILD_NUMBER=32
MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_PACKAGE="com.monero.app"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.5.0" CAKEWALLET_VERSION="4.5.1"
CAKEWALLET_BUILD_NUMBER=130 CAKEWALLET_BUILD_NUMBER=136
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"

View file

@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_IOS_TYPE=$1 APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.2.0" MONERO_COM_VERSION="1.2.1"
MONERO_COM_BUILD_NUMBER=26 MONERO_COM_BUILD_NUMBER=29
MONERO_COM_BUNDLE_ID="com.cakewallet.monero" MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.5.0" CAKEWALLET_VERSION="4.5.1"
CAKEWALLET_BUILD_NUMBER=130 CAKEWALLET_BUILD_NUMBER=133
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven" HAVEN_NAME="Haven"

View file

@ -28,6 +28,7 @@ class SecretKey {
SecretKey('simpleSwapApiKey', () => ''), SecretKey('simpleSwapApiKey', () => ''),
SecretKey('anypayToken', () => ''), SecretKey('anypayToken', () => ''),
SecretKey('onramperApiKey', () => ''), SecretKey('onramperApiKey', () => ''),
SecretKey('ioniaClientId', () => ''),
]; ];
final String name; final String name;