Compare commits

..

No commits in common. "master" and "wallet/release/4.10.0" have entirely different histories.

260 changed files with 10268 additions and 49107 deletions

14
.vscode/launch.json vendored
View file

@ -1,14 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/www/index.html"
}
]
}

View file

@ -11,29 +11,8 @@ module.exports = function(grunt) {
appConfig: {
command: 'node ./util/buildAppConfig.js'
},
android_studio: {
command: ' open -a open -a /Applications/Android\\ Studio.app platforms/android',
},
build_android_debug: {
command: 'cordova prepare android && cordova build android --debug',
},
build_android_release: {
command: 'cordova prepare android && cordova build android --release',
},
build_ios_debug: {
command: 'cordova prepare ios && cordova build ios --debug',
options: {
maxBuffer: 3200 * 1024
}
},
build_ios_release: {
command: 'cordova prepare ios && cordova build ios --release',
options: {
maxBuffer: 1600 * 1024
}
},
chrome: {
command: 'make -C chrome-app '
externalServices: {
command: 'node ./util/buildExternalServices.js'
},
clean: {
command: 'rm -Rf bower_components node_modules'
@ -41,41 +20,14 @@ module.exports = function(grunt) {
cordovaclean: {
command: 'make -C cordova clean'
},
macos: {
command: 'sh webkitbuilds/build-macos.sh sign'
},
coveralls: {
command: 'cat coverage/report-lcov/lcov.info |./node_modules/coveralls/bin/coveralls.js'
},
create_dmg_dist: {
command: 'sh webkitbuilds/create-dmg-dist.sh "<%= pkg.name %>" "<%= pkg.fullVersion %>" "<%= pkg.nameCaseNoSpace %>" "<%= pkg.title %>"'
},
create_others_dist: {
command: 'sh webkitbuilds/create-others-dist.sh "<%= pkg.name %>" "<%= pkg.fullVersion %>" "<%= pkg.nameCaseNoSpace %>" "<%= pkg.title %>"'
},
create_pkg_dist: {
command: 'sh webkitbuilds/create-pkg-dist.sh "<%= pkg.name %>" "<%= pkg.fullVersion %>" "<%= pkg.nameCaseNoSpace %>" "<%= pkg.title %>"'
},
externalServices: {
command: 'node ./util/buildExternalServices.js'
},
get_nwjs_for_pkg: {
command: 'if [ ! -d ./cache/0.19.5-pkg/osx64/nwjs.app ]; then cd ./cache; curl https://dl.nwjs.io/v0.19.5-mas-beta/nwjs-mas-v0.19.5-osx-x64.zip --output nwjs.zip; unzip nwjs.zip; mkdir -p ./0.19.5-pkg/osx64; cp -R ./nwjs-mas-v0.19.5-osx-x64/nwjs.app ./0.19.5-pkg/osx64/; fi'
},
log_android: {
command: 'adb logcat | grep chromium',
},
run_android: {
command: 'cordova run android --device',
},
run_android_emulator: {
command: 'cordova run android --emulator',
},
sign_android: {
// When the build log outputs "Built the following apk(s):", it seems to need the filename to start with "android-release".
// It looks like it simply lists all apk files starting with "android-release"
command: 'rm -f platforms/android/build/outputs/apk/android-release-signed-*.apk; jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ../bitcoin-com-release-key.jks -signedjar platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/android-release-unsigned.apk bitcoin-com && zipalign -v 4 platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/bitcoin-com-wallet-<%= pkg.fullVersion %>-android-signed-aligned.apk',
stdin: true,
},
sign_desktop_dist: {
command: 'sh webkitbuilds/sign-desktop-dist.sh "<%= pkg.name %>" "<%= pkg.fullVersion %>"'
chrome: {
command: 'make -C chrome-app '
},
wpinit: {
command: 'make -C cordova wp-init',
@ -83,9 +35,40 @@ module.exports = function(grunt) {
wpcopy: {
command: 'make -C cordova wp-copy',
},
iosdebug: {
command: 'npm run build:ios',
},
ios: {
command: 'npm run build:ios-release',
},
xcode: {
command: 'open platforms/ios/*.xcodeproj',
}
command: 'npm run open:ios',
},
androiddebug: {
command: 'npm run build:android',
},
android: {
command: 'npm run build:android-release',
},
androidrun: {
command: 'npm run run:android && npm run log:android',
},
androidbuild: {
command: 'cd cordova/project && cordova build android --release',
},
androidsign: {
command: 'rm -f cordova/project/platforms/android/build/outputs/apk/android-release-signed-aligned.apk; jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ../bitcoin-com-release-key.jks -signedjar cordova/project/platforms/android/build/outputs/apk/android-release-signed.apk cordova/project/platforms/android/build/outputs/apk/android-release-unsigned.apk bitcoin-com && ../android-sdk-macosx/build-tools/27.0.1/zipalign -v 4 cordova/project/platforms/android/build/outputs/apk/android-release-signed.apk cordova/project/platforms/android/build/outputs/apk/android-release-signed-aligned.apk ',
stdin: true,
},
desktopsign: {
cmd: 'gpg -u E0AE67E7 --output webkitbuilds/<%= pkg.title %>-linux.zip.sig --detach-sig webkitbuilds/<%= pkg.title %>-linux.zip ; gpg -u E0AE67E7 --output webkitbuilds/<%= pkg.title %>.exe.sig --detach-sig webkitbuilds/<%= pkg.title %>.exe'
},
desktopverify: {
cmd: 'gpg --verify webkitbuilds/<%= pkg.title %>-linux.zip.sig webkitbuilds/<%= pkg.title %>-linux.zip; gpg --verify webkitbuilds/<%= pkg.title %>.exe.sig webkitbuilds/<%= pkg.title %>.exe'
},
osxsign: {
cmd: 'gpg -u E0AE67E7 --output webkitbuilds/<%= pkg.title %>.dmg.sig --detach-sig webkitbuilds/<%= pkg.title %>.dmg'
},
},
watch: {
options: {
@ -141,7 +124,6 @@ module.exports = function(grunt) {
},
angular: {
src: [
'src/shim/shim.js',
'bower_components/qrcode-generator/js/qrcode.js',
'bower_components/qrcode-generator/js/qrcode_UTF8.js',
'bower_components/moment/min/moment-with-locales.js',
@ -166,33 +148,15 @@ module.exports = function(grunt) {
],
dest: 'www/lib/bitcoin-cash-js.js'
},
bitanalytics: {
src: [
'bitanalytics/bitanalytics.js'
],
dest: 'www/lib/bitanalytics.js'
},
js: {
src: [
'src/js/app.js',
'src/js/routes.js',
'src/js/decorators/*.js',
'src/js/directives/*.js',
'!src/js/directives/*.spec.js',
'src/js/filters/*.js',
'!src/js/filters/*.spec.js',
'src/js/models/*.js',
'!src/js/models/*.spec.js',
'src/js/services/*.js',
'!src/js/services/*.spec.js',
'src/js/controllers/**/*.js',
'!src/js/controllers/**/*.spec.js',
'src/js/translations.js',
'src/js/appConfig.js',
'src/js/externalServices.js',
@ -213,8 +177,7 @@ module.exports = function(grunt) {
files: {
'www/js/app.js': ['www/js/app.js'],
'www/lib/angular-components.js': ['www/lib/angular-components.js'],
'www/lib/bitcoin-cash-js.js': ['www/lib/bitcoin-cash-js.js'],
'www/lib/bitanalytics.js': ['www/lib/bitanalytics.js']
'www/lib/bitcoin-cash-js.js': ['www/lib/bitcoin-cash-js.js']
}
}
},
@ -237,7 +200,7 @@ module.exports = function(grunt) {
module: 'copayApp'
},
files: {
'src/js/translations.js': ['i18n/po/**/*.po']
'src/js/translations.js': ['i18n/po/*.po']
}
},
},
@ -259,78 +222,38 @@ module.exports = function(grunt) {
expand: true,
cwd: 'webkitbuilds/',
src: ['.desktop', '../www/img/app/favicon.ico', '../resources/<%= pkg.name %>/linux/512x512.png'],
dest: 'webkitbuilds/others/<%= pkg.title %>/linux64/',
dest: 'webkitbuilds/<%= pkg.title %>/linux64/',
flatten: true,
filter: 'isFile'
}],
}
},
nwjs: {
others: {
options: {
appName: '<%= pkg.nameCaseNoSpace %>',
platforms: ['win64', 'linux64'],
buildDir: './webkitbuilds/others',
version: '0.19.5',
exeIco: './www/img/app/logo.ico'
},
src: ['./package.json', './www/**/*']
},
dmg: {
options: {
appName: '<%= pkg.nameCaseNoSpace %>',
platforms: ['osx64'],
buildDir: './webkitbuilds/dmg',
version: '0.19.5',
macIcns: './resources/<%= pkg.name %>/mac/app.icns',
exeIco: './www/img/app/logo.ico',
macPlist: {
'CFBundleDisplayName': '<%= pkg.title %>',
'CFBundleShortVersionString': '<%= pkg.version %>',
'CFBundleVersion': '<%= pkg.androidVersion %>',
'LSApplicationCategoryType': 'public.app-category.finance',
'CFBundleURLTypes': [
{
'CFBundleURLName': 'URI Handler',
'CFBundleURLSchemes': ['bitcoin', '<%= pkg.name %>']
}
]
}
},
src: ['./package.json', './www/**/*']
},
pkg: {
options: {
appName: '<%= pkg.title %>',
platforms: ['osx64'],
buildDir: './webkitbuilds/pkg',
version: '0.19.4',
macIcns: './resources/<%= pkg.name %>/mac/pkg/app.icns',
exeIco: './www/img/app/logo.ico',
macPlist: {
'CFBundleIdentifier': 'com.bitcoin.mwallet.mac',
'CFBundleDisplayName': '<%= pkg.title %>',
'CFBundleShortVersionString': '<%= pkg.version %>',
'CFBundleVersion': '<%= pkg.androidVersion %>',
'LSApplicationCategoryType': 'public.app-category.finance',
'CFBundleURLTypes': [
{
'CFBundleURLName': 'URI Handler',
'CFBundleURLSchemes': ['bitcoin', '<%= pkg.name %>']
}
]
}
},
src: ['./package.json', './www/**/*']
options: {
appName: '<%= pkg.title %>',
platforms: ['win64', 'osx64', 'linux64'],
buildDir: './webkitbuilds',
version: '0.19.5',
macIcns: './resources/<%= pkg.name %>/mac/app.icns',
exeIco: './www/img/app/logo.ico',
macPlist: {
'CFBundleURLTypes': [
{
'CFBundleURLName': 'URI Handler',
'CFBundleURLSchemes': ['bitcoin', '<%= pkg.name %>']
}
]
}
},
src: ['./package.json', './www/**/*']
},
compress: {
linux: {
options: {
archive: './webkitbuilds/others/<%= pkg.title %>-linux.zip'
archive: './webkitbuilds/<%= pkg.title %>-linux.zip'
},
expand: true,
cwd: './webkitbuilds/others/<%= pkg.title %>/linux64/',
cwd: './webkitbuilds/<%= pkg.title %>/linux64/',
src: ['**/*'],
dest: '<%= pkg.title %>-linux/'
}
@ -349,53 +272,20 @@ module.exports = function(grunt) {
grunt.registerTask('default', ['nggettext_compile', 'exec:appConfig', 'exec:externalServices', 'browserify', 'sass', 'concat', 'copy:ionic_fonts', 'copy:ionic_js']);
grunt.registerTask('prod', ['default', 'uglify']);
grunt.registerTask('translate', ['nggettext_extract']);
grunt.registerTask('desktop', ['prod', 'nwjs', 'copy:linux', 'compress:linux']);
grunt.registerTask('osx', ['prod', 'nwjs', 'exec:macos', 'exec:osxsign']);
grunt.registerTask('osx-debug', ['default', 'nwjs']);
grunt.registerTask('chrome', ['default','exec:chrome']);
grunt.registerTask('wp', ['prod', 'exec:wp']);
grunt.registerTask('wp-copy', ['default', 'exec:wpcopy']);
grunt.registerTask('wp-init', ['default', 'exec:wpinit']);
grunt.registerTask('ios', ['exec:ios']);
grunt.registerTask('ios-debug', ['exec:iosdebug']);
grunt.registerTask('ios-run', ['exec:xcode']);
grunt.registerTask('cordovaclean', ['exec:cordovaclean']);
grunt.registerTask('android-debug', ['exec:androiddebug', 'exec:androidrun']);
grunt.registerTask('android', ['exec:android']);
grunt.registerTask('android-release', ['prod', 'exec:android', 'exec:androidsign']);
grunt.registerTask('desktopsign', ['exec:desktopsign', 'exec:desktopverify']);
// Build all
grunt.registerTask('build-app-release', ['build-mobile-release', 'build-desktop-release']);
/**
* Mobile app
*/
// Build mobile app
grunt.registerTask('build-mobile-release', ['build-ios-release', 'build-android-release']);
// Build ios
grunt.registerTask('start-ios', ['default', 'exec:build_ios_debug', 'exec:xcode']);
grunt.registerTask('build-ios-debug', ['default', 'exec:build_ios_debug']);
grunt.registerTask('build-ios-release', ['prod', 'exec:build_ios_release']);
// Build android
grunt.registerTask('start-android', ['build-android-debug', 'exec:run_android']);
grunt.registerTask('build-android-debug', ['default', 'exec:build_android_debug']);
grunt.registerTask('start-android-emulator', ['build-android-debug', 'exec:run_android_emulator']);
grunt.registerTask('build-android-release', ['prod', 'exec:build_android_release', 'sign-android']);
grunt.registerTask('sign-android', ['exec:sign_android']);
/**
* Desktop app
*/
// Build desktop
grunt.registerTask('build-desktop', ['build-desktop-others', 'build-desktop-osx-dmg', 'build-desktop-osx-pkg']);
// Build desktop win64 & linux64
grunt.registerTask('build-desktop-others', ['prod', 'nwjs:others', 'copy:linux', 'exec:create_others_dist']);
// Build desktop osx pkg
grunt.registerTask('build-desktop-osx-pkg', ['prod', 'exec:get_nwjs_for_pkg', 'nwjs:pkg', 'exec:create_pkg_dist']);
// Build desktop osx dmg
grunt.registerTask('build-desktop-osx-dmg', ['prod', 'nwjs:dmg', 'exec:create_dmg_dist']);
// Sign desktop
grunt.registerTask('sign-desktop', ['exec:sign_desktop_dist']);
// Release desktop
grunt.registerTask('build-desktop-release', ['build-desktop', 'sign-desktop']);
};

View file

@ -1,24 +1,3 @@
This is a fork of the Bitcoin.com wallet to add additional features.
Features included:
- Zero fee transactions (only works for Bitcoin Cash). You will be asked for, if you want to send a transaction as zero fee on the confirmation page.
## Zero fee transactions:
Because most network nodes on the Bitcoin Cash network don't relay zero fee txs, you will experience some strange issues, but don't worry: for me personally the Bitcoin.com pool has included all my zero fee transactions, but please beware that the receiver probably won't see your tx before it has been confirmed and please do also keep in mind, that the transactions coming after it won't confirm or be seen before the zero fee one has been confirmed.
If you do already have a Bitcoin.com wallet, you need to create a new one to use this feature or change the wallet URL to: https://bws.freepages.dk/bws/api
## Disclaimer
Please beware this is my personal experimental project. You are more than welcome to play with it, but I don't take any responsibility of loss of funds due to errors in the code, so please make sure you made a backup before running this software.
## Builds
You can build the software yourself using the instructions below or use prebuilt binaries which can be found here (currently Windows and Linux only): https://ipfs.io/ipfs/QmR1DaS3QsDS48SzAWKUWFfmtMfJc4tgMtkSk3JFmuzewe
##
The Bitcoin.com wallet is a fork of the Copay Wallet (https://github.com/bitpay/copay).
The Bitcoin.com wallet is a secure bitcoin wallet platform for both desktop and mobile devices. It uses [Bitcore Wallet Service](https://github.com/Bitcoin-com/bitcore-wallet-service) (our fork of the [Bitpay Bitcore Wallet Service](https://github.com/bitpay/bitcore-wallet-service)) (BWS) for peer synchronization and network interfacing.
@ -126,7 +105,7 @@ The desktop version of the Bitcoin.com wallet currently uses NW.js, an app runti
When NW.js is installed, run the `start:desktop` npm package script.
```sh
npm run apply:bitcoincom
npm run apply:bitcoin.com
npm run start:desktop
```
@ -134,14 +113,14 @@ npm run start:desktop
Before building the release version for a platform, run the `clean-all` command to delete any untracked files in your current working directory. (Be sure to stash any uncommited changes you've made.) This guarantees consistency across builds for the current state of this repository.
The `build:*-release` commands build the production version of the app, and bundle it with the release version of the platform being built.
The `final` commands build the production version of the app, and bundle it with the release version of the platform being built.
### Android
```sh
npm run clean-all
npm run apply:bitcoincom
npm run build:android-release
npm run final:android
```
### iOS
@ -149,7 +128,7 @@ npm run build:android-release
```sh
npm run clean-all
npm run apply:bitcoincom
npm run build:ios-release
npm run final:ios
```
### Desktop (Linux, macOS, and Windows)
@ -157,7 +136,7 @@ npm run build:ios-release
```sh
npm run clean-all
npm run apply:bitcoincom
npm run build:desktop-release
npm run final:desktop
```
## About The Bitcoin.com Wallet

View file

@ -11,10 +11,7 @@ var templates = {
'ionic.config.json': '/',
'.desktop': 'webkitbuilds/',
'setup-win.iss': 'webkitbuilds/',
'create-dmg-dist.sh': 'webkitbuilds/',
'create-others-dist.sh': 'webkitbuilds/',
'create-pkg-dist.sh': 'webkitbuilds/',
'sign-desktop-dist.sh': 'webkitbuilds/',
'build-macos.sh': 'webkitbuilds/',
'manifest.json': 'chrome-app/',
// 'bower.json': '/',
};

View file

@ -2,7 +2,7 @@
"packageName": "bitcoin.com",
"packageDescription": "Bitcoin.com Wallet",
"packageNameId": "com.bitcoin.mwallet",
"userVisibleName": "Bitcoin.com Wallet",
"userVisibleName": "Bitcoin.com",
"purposeLine": "Bitcoin.com Wallet",
"bundleName": "bitcoincom",
"appUri": "bitcoincom",
@ -18,15 +18,14 @@
"appDescription": "Bitcoin.com Wallet",
"winAppName": "BitcoinWallet",
"WindowsStoreIdentityName": "18C7659D.Bitcoin.com-SecureBitcoinWallet",
"WindowsStoreDisplayName": "Bitcoin.com Wallet",
"WindowsStoreDisplayName": "Bitcoin.com - Secure Bitcoin Wallet",
"wpPublisherId": "{31cdd08b-457c-413d-b440-f6665eec847d}",
"wpProductId": "{5381aa50-9069-11e4-84cc-293caf9cbdc8}",
"windowsAppId": "804636ee-b017-4cad-8719-e58ac97ffa5c",
"pushSenderId": "1036948132229",
"description": "A Secure Bitcoin Wallet",
"version": "5.1.3",
"fullVersion": "5.1-rc2",
"androidVersion": "501003",
"version": "4.10.0",
"androidVersion": "410000",
"_extraCSS": "",
"_enabledExtensions": {
"coinbase": false,

View file

@ -268,33 +268,5 @@ div.onboarding-topic {
display: block;
float: left;
max-height: 100%;
max-width: 100%;
}
.bitpay-banner {
background: #1A3A8B;
padding: 10px;
box-shadow: 0px 5px 10px 0px #cccccc;
height: 5em;
}
.bitpay-logo {
display: block;
max-height: 100%;
width: 100%;
height: 4em;
}
.egifter-banner {
background: #1A3A8B;
padding: 10px;
box-shadow: 0px 5px 10px 0px #cccccc;
height: 5em;
text-align: center;
}
.egifter-logo {
max-height: 100%;
max-width: 100%;
height: 4em;
max-width: 100%;
}

View file

@ -1,5 +1,11 @@
#!/bin/bash
SHOULD_SIGN=$1
if [ "$SHOULD_SIGN" ]
then
echo "Will sign the APP"
fi
# by Andy Maloney
# http://asmaloney.com/2013/07/howto/packaging-a-mac-os-x-application-using-a-dmg/
@ -10,25 +16,21 @@ if [ -d "$dir" ]; then
fi
# set up your app name, architecture, and background image file name
APP_PACKAGE=$1
APP_VERSION=$2
APP_NAME=$3
APP_FULLNAME=$4
APP_NAME="*USERVISIBLENAME*"
rm dmg-background.tiff
ln -s ../resources/bitcoin.com/mac/dmg-background.tiff dmg-background.tiff
ln -s ../resources/*PACKAGENAME*/mac/dmg-background.tiff dmg-background.tiff
rm volume-icon.icns
ln -s ../resources/bitcoin.com/mac/volume-icon.icns volume-icon.icns
ln -s ../resources/*PACKAGENAME*/mac/volume-icon.icns volume-icon.icns
DMG_VOLUME_ICON="volume-icon.icns"
DMG_BACKGROUND_IMG="dmg-background.tiff"
PATH_NAME="dmg/${APP_NAME}/osx64/"
PATH_NAME="${APP_NAME}/osx64/"
# you should not need to change these
APP_EXE="${PATH_NAME}${APP_NAME}.app/Contents/MacOS/nwjs"
VOL_NAME="${APP_NAME}"
DMG_TMP="dmg/${VOL_NAME}-temp.dmg"
DMG_FINAL="dmg/${VOL_NAME}.dmg"
DMG_TMP="${VOL_NAME}-temp.dmg"
DMG_FINAL="${VOL_NAME}.dmg"
STAGING_DIR="tmp"
# Check the background image DPI and convert it if it isn't 72x72
@ -64,6 +66,25 @@ SIZE=250
if [ $? -ne 0 ]; then
echo "Error: Cannot compute size of staging dir"
exit
fi
# Sign Code (MATIAS)
if [ $SHOULD_SIGN ]
then
echo "Signing ${APP_NAME} DMG"
export IDENTITY="3rd Party Mac Developer Application: BitPay, Inc. (884JRH5R93)"
# not need for 'out of app store' distribution (?)
# export PARENT_PLIST=parent.plist
# export CHILD_PLIST=child.plist
export APP_PATH=${STAGING_DIR}/${APP_NAME}.app
codesign --deep -s "${IDENTITY}" $APP_PATH"/Contents/Versions/52.0.2743.82/nwjs Helper.app" && echo "Sign 1"
codesign --deep -s "${IDENTITY}" $APP_PATH"/Contents/Versions/52.0.2743.82/nwjs Framework.framework/Resources/app_mode_loader.app" && echo "Sign 2"
codesign --deep -s "${IDENTITY}" $APP_PATH && echo "Sign 3"
echo "Signing Done"
fi
# create the temp DMG file
@ -154,14 +175,6 @@ hdiutil detach "${DEVICE}"
echo "Creating compressed image"
hdiutil convert "${DMG_TMP}" -format UDZO -imagekey zlib-level=9 -o "${DMG_FINAL}"
export DIST_PATH="dist"
if [ ! -d $DIST_PATH ]; then
mkdir $DIST_PATH
fi
cp -vR "${DMG_FINAL}" "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.dmg"
# clean up
rm -rf "${DMG_TMP}"
rm -rf "${STAGING_DIR}"

View file

@ -72,9 +72,6 @@
<plugin name="cordova-plugin-queries-schemes" spec="~0.1.5" />
<plugin name="cordova-plugin-firebase" spec="https://github.com/arnesson/cordova-plugin-firebase.git" />
<plugin name="cordova-plugin-wkwebview-inputfocusfix" spec="https://github.com/onderceylan/cordova-plugin-wkwebview-inputfocusfix.git" />
<plugin name="cordova-plugin-media-fork" spec="~5.0.3">
<variable name="KEEP_AVAUDIOSESSION_ALWAYS_ACTIVE" value="NO" />
</plugin>
<!-- Supported Platforms -->
<engine name="ios" spec="~4.5.3" />
<engine name="android" spec="~6.3.0" />
@ -85,12 +82,6 @@
<config-file platform="ios" target="*-Info.plist" parent="UIStatusBarHidden"><true/></config-file>
<config-file platform="ios" target="*-Info.plist" parent="UIViewControllerBasedStatusBarAppearance"><false/></config-file>
<config-file target="*-Info.plist" parent="ITSAppUsesNonExemptEncryption"><false/></config-file>
<icon src="resources/*PACKAGENAME*/ios/icon/AppIcon24x24@2x.png" width="48" height="48" />
<icon src="resources/*PACKAGENAME*/ios/icon/AppIcon27.5x27.5@2x.png" width="55" height="55" />
<icon src="resources/*PACKAGENAME*/ios/icon/AppIcon44x44@2x.png" width="88" height="88" />
<icon src="resources/*PACKAGENAME*/ios/icon/AppIcon86x86@2x.png" width="172" height="172" />
<icon src="resources/*PACKAGENAME*/ios/icon/AppIcon98x98@2x.png" width="196" height="196" />
<icon src="resources/*PACKAGENAME*/ios/icon/icon-20.png" width="20" height="20" />
<icon src="resources/*PACKAGENAME*/ios/icon/icon-60@3x.png" width="180" height="180" />
<icon src="resources/*PACKAGENAME*/ios/icon/icon-60.png" width="60" height="60" />
<icon src="resources/*PACKAGENAME*/ios/icon/icon-60@2x.png" width="120" height="120" />
@ -108,7 +99,6 @@
<icon src="resources/*PACKAGENAME*/ios/icon/icon-small@3x.png" width="87" height="87" />
<icon src="resources/*PACKAGENAME*/ios/icon/icon-50.png" width="50" height="50" />
<icon src="resources/*PACKAGENAME*/ios/icon/icon-50@2x.png" width="100" height="100" />
<icon src="resources/*PACKAGENAME*/ios/icon/icon-1024.png" width="1024" height="1024" />
<splash src="resources/*PACKAGENAME*/ios/splash/Default~iphone.png" width="320" height="480"/>
<splash src="resources/*PACKAGENAME*/ios/splash/Default@2x~iphone.png" width="640" height="960"/>

View file

@ -1,54 +0,0 @@
#!/bin/bash
# make sure we are in the correct dir when we double-click a .command file
dir=${0%/*}
if [ -d "$dir" ]; then
cd "$dir"
fi
# set up your app name, architecture, and background image file name
APP_PACKAGE=$1
APP_VERSION=$2
APP_NAME=$3
APP_FULLNAME=$4
export APP_LINUX_PATH="others/${APP_NAME}/linux64"
export APP_WIN_PATH="others/${APP_NAME}/win64"
export DIST_PATH="dist"
if [ ! -d $DIST_PATH ]; then
mkdir $DIST_PATH
fi
##
# LINUX
echo "Building Linux..."
# Building package
cp -R $APP_LINUX_PATH bitcoin-com-wallet
tar -cvzf "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-linux-x64.tar.gz" bitcoin-com-wallet
# Clean
rm -R bitcoin-com-wallet
echo "Linux Done."
##
# WINDOWS
echo "Building Windows..."
# Building package
cp -R $APP_WIN_PATH bitcoin-com-wallet
zip -r "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-win-x64.zip" bitcoin-com-wallet
# Clean
rm -R bitcoin-com-wallet
echo "Windows Done."
echo "Done."
exit

View file

@ -1,52 +0,0 @@
#!/bin/bash
# make sure we are in the correct dir when we double-click a .command file
dir=${0%/*}
if [ -d "$dir" ]; then
cd "$dir"
fi
# set up your app name, architecture, and background image file name
APP_PACKAGE=$1
APP_VERSION=$2
APP_NAME=$3
APP_FULLNAME=$4
rm entitlements-child.plist
ln -s ../resources/bitcoin.com/mac/pkg/entitlements-child.plist entitlements-child.plist
rm entitlements-parent.plist
ln -s ../resources/bitcoin.com/mac/pkg/entitlements-parent.plist entitlements-parent.plist
rm build.cfg
ln -s ../resources/bitcoin.com/mac/pkg/build.cfg build.cfg
rm build_mas.py
ln -s ../resources/bitcoin.com/mac/pkg/build_mas.py build_mas.py
echo "Signing ${APP_FULLNAME}"
export CURRENT_PATH=`pwd`
export APP_PATH="pkg/${APP_FULLNAME}/osx64/${APP_FULLNAME}"
export TMP_PATH="tmp"
export DIST_PATH="dist"
rm -rf $TMP_PATH
mkdir $TMP_PATH
if [ ! -d $DIST_PATH ]; then
mkdir $DIST_PATH
fi
cd "${APP_PATH}.app/Contents/Versions"
ln -s "55.0.2883.87" "Current"
cd $CURRENT_PATH
chmod -vR 777 "${APP_PATH}.app/Contents"
python build_mas.py -C build.cfg -O "${TMP_PATH}/${APP_FULLNAME}.app" -I "${APP_PATH}.app" -P "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.pkg"
echo "Signing Done"
echo "Done."
exit

View file

@ -11,7 +11,7 @@
<link rel="stylesheet" type="text/css" href="css/chartist.css">
<link rel="stylesheet" type="text/css" href="css/bitcoin.com.css">
<link rel="stylesheet" type="text/css" href="css/icomoon.css">
<title>*USERVISIBLENAME*</title>
<title>*USERVISIBLENAME* - *PURPOSELINE*</title>
<link rel="shortcut icon" href="img/app/favicon.ico">
</head>
<body>
@ -31,7 +31,6 @@
<script src="lib/ionic.bundle.min.js"></script>
<script src="lib/angular-components.js"></script>
<script src="lib/bitcoin-cash-js.js"></script>
<script src="lib/bitanalytics.js"></script>
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script src="js/moment.min.js"></script>

View file

@ -3,8 +3,6 @@
"description": "*DESCRIPTION*",
"author": "BitPay",
"version": "*VERSION*",
"androidVersion": "*ANDROIDVERSION*",
"fullVersion": "*FULLVERSION*",
"keywords": [
"bitcoin",
"wallet",
@ -15,9 +13,8 @@
],
"main": "www/index.html",
"title": "*USERVISIBLENAME*",
"nameCaseNoSpace": "*NAMECASENOSPACE*",
"window": {
"title": "*USERVISIBLENAME*",
"title": "*USERVISIBLENAME* - *PURPOSELINE*",
"icon": "www/img/app/icon.png",
"toolbar": false,
"show": true,
@ -71,8 +68,6 @@
"grunt-angular-gettext": "^2.2.3",
"grunt-browserify": "^5.0.0",
"grunt-cli": "^1.2.0",
"grunt-curl": "^2.4.1",
"grunt-zip": "^0.17.1",
"grunt-contrib-compress": "^1.3.0",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-copy": "^1.0.0",
@ -84,68 +79,52 @@
"load-grunt-tasks": "^3.5.0",
"shelljs": "^0.3.0",
"android-versions": "^1.2.1",
"bitcoincashjs-fork": "^1.0.3"
"bitcoincashjs": "^0.1.7"
},
"scripts": {
"apply:bitcoincom": "npm i fs-extra && cd app-template && node apply.js bitcoincom && npm i && cordova prepare && cd ../ && ./fix-asn1.sh",
"build:app-release": "grunt build-app-release",
"build:mobile-release": "grunt build-mobile-release",
"build:desktop-release": "grunt build-desktop-release",
"build:android-debug": "grunt build-android-debug",
"build:android-release": "grunt build-android-release",
"build:ios-debug": "grunt build-ios-debug",
"build:ios-release": "grunt build-ios-release",
"build:desktop": "grunt build-desktop",
"build:osx-pkg": "grunt build-desktop-osx-pkg",
"build:osx-dmg": "grunt build-desktop-osx-dmg",
"build:others": "grunt build-desktop-others",
"build:windows": "cordova prepare windows && cordova build windows -- --arch=\"ARM\"",
"build:windows-release": "cordova prepare windows && cordova build windows --release --arch=\"ARM\"",
"postinstall": "bower install",
"start": "npm run build:www && ionic serve --nolivereload --nogulp -s --address 0.0.0.0",
"start:ios": "npm run build:www && npm run build:ios && npm run open:ios",
"start:android": "npm run build:www && npm run build:android && npm run run:android",
"start:windows": "npm run build:www && npm run build:windows",
"start:desktop": "npm start",
"watch": "grunt watch",
"build:www": "grunt",
"build:www-release": "grunt prod",
"clean": "trash platforms && trash plugins && cordova prepare",
"clean-all": "git clean -dfx",
"build:ios": "cordova prepare ios && cordova build ios --debug",
"build:android": "cordova prepare android && cordova build android --debug",
"build:windows": "cordova prepare windows && cordova build windows -- --arch=\"ARM\"",
"build:ios-release": "cordova prepare ios && cordova build ios --release",
"build:android-release": "cordova prepare android && cordova build android --release",
"build:windows-release": "cordova prepare windows && cordova build windows --release --arch=\"ARM\"",
"build:desktop": "grunt desktop",
"build:osx": "grunt osx",
"open:ios": "open platforms/ios/*.xcodeproj",
"open:android": "open -a open -a /Applications/Android\\ Studio.app platforms/android",
"final:www": "npm run build:www-release",
"final:ios": "npm run final:www && npm run build:ios-release && npm run open:ios",
"final:android": "npm run final:www && npm run build:android-release && npm run sign:android && npm run run:android-release",
"final:windows": "npm run final:www && npm run build:windows-release",
"final:desktop": "npm run build:desktop && npm run build:osx",
"run:android": "cordova run android --device",
"run:android-release": "cordova run android --device --release",
"log:android": "adb logcat | grep chromium",
"open:android": "grunt exec:android_studio",
"open:ios": "grunt exec:xcode",
"postinstall": "bower install",
"sign:android": "grunt sign-android",
"sign:desktop": "grunt sign-desktop",
"start": "npm run build:www && ionic serve --nolivereload --nogulp -s --address 0.0.0.0",
"start:chrome": "npm run build:www && ionic serve --nolivereload --nogulp -s --address 0.0.0.0 --browser \"google chrome\"",
"start:android": "grunt start-android",
"start:android-emulator": "grunt start-android",
"start:android-log": "grunt start-android && npm run log:android",
"start:ios": "grunt start-ios",
"start:windows": "npm run build:www && npm run build:windows",
"test": "karma start test/karma.conf.js --single-run",
"sign:android": "rm -f platforms/android/build/outputs/apk/android-release-signed-aligned.apk; jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ../bitcoin-com-release-key.jks -signedjar platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/android-release-unsigned.apk bitcoin-com && $ANDROID_HOME/build-tools/27.0.1/zipalign -v 4 platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/android-release-signed-aligned.apk",
"apply:copay": "npm i fs-extra && cd app-template && node apply.js copay && npm i && cordova prepare",
"apply:bitpay": "npm i fs-extra && cd app-template && node apply.js bitpay && npm i && cordova prepare",
"apply:bitcoincom": "npm i fs-extra && cd app-template && node apply.js bitcoincom && npm i && cordova prepare",
"test": "echo \"no package tests configured\"",
"clean": "trash platforms && trash plugins && cordova prepare",
"unstage-package": "git reset package.json",
"watch": "grunt watch"
"clean-all": "git clean -dfx"
},
"devDependencies": {
"cordova": "^6.3.1",
"grunt": "^1.0.1",
"ionic": "^3.6.0",
"jasmine-core": "^3.1.0",
"karma": "^2.0.2",
"karma-chrome-launcher": "^2.2.0",
"karma-jasmine": "^1.1.2",
"trash-cli": "^1.4.0",
"lodash": "^4.17.4",
"pre-commit": "^1.1.3"
},
"pre-commit": "unstage-package"
}
}

View file

@ -1,40 +0,0 @@
#!/bin/bash
# make sure we are in the correct dir when we double-click a .command file
dir=${0%/*}
if [ -d "$dir" ]; then
cd "$dir"
fi
APP_PACKAGE=$1
APP_VERSION=$2
export DIST_PATH="dist"
##
# INIT GPG (YOU NEED THE PRIVATE KEY CONNECTED TO YOUR DESKTOP)
# gpg --card-edit
##
# LINUX
# Sig tar.gz
gpg --yes --output "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-linux-x64.tar.gz.sig" --detach-sig "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-linux-x64.tar.gz"
gpg --verify "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-linux-x64.tar.gz.sig" "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-linux-x64.tar.gz"
##
# WINDOWS
# Sig zip
gpg --yes --output "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-win-x64.zip.sig" --detach-sig "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-win-x64.zip"
gpg --verify "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-win-x64.zip.sig" "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-win-x64.zip"
##
# OSX
# Sig dmg
gpg --yes --output "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.dmg.sig" --detach-sig "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.dmg"
gpg --verify "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.dmg.sig" "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.dmg"
# Sig pkg
gpg --yes --output "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.pkg.sig" --detach-sig "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.pkg"
gpg --verify "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.pkg.sig" "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.pkg"

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
var bitcoinCashJsModule = angular.module('bitcoinCashJsModule', []);
var bchjs = require('../node_modules/bitcoincashjs-fork');
var bchjs = require('../node_modules/bitcoincashjs');
bitcoinCashJsModule.constant('MODULE_VERSION', '1.0.0');

View file

@ -24,6 +24,6 @@
},
"resolutions": {
"angular": "1.5.3",
"ionic": "eefba1331b"
"ionic": "1b7414faba"
}
}

View file

@ -1,11 +0,0 @@
#!/bin/bash
firstLine=`awk 'NR < 2 {print}' node_modules/asn1.js-rfc5280/index.js`
if [ "$firstLine" = "try {" ]; then
echo "var asn1 = require('asn1.js');" > node_modules/asn1.js-rfc5280/index.new.js
awk 'NR > 6 {print}' node_modules/asn1.js-rfc5280/index.js >> node_modules/asn1.js-rfc5280/index.new.js
rm node_modules/asn1.js-rfc5280/index.js
mv node_modules/asn1.js-rfc5280/index.new.js node_modules/asn1.js-rfc5280/index.js
echo "node_modules/asn1.js-rfc5280/index.js fixed"
fi

View file

@ -2,8 +2,6 @@
'use strict';
const blankOrEmptyTranslationRegex = /^\s*"\s*"$/
if (process.argv[2]) {
var no_build = (process.argv[2].toLowerCase() == '--nobuild')
if (no_build == false) {
@ -24,7 +22,19 @@ var path = require('path');
var https = require('https');
var AdmZip = require('adm-zip');
var crowdin_identifier = 'bitcoincom-wallet'
var crowdin_identifier = 'copay'
var local_file_name2 = path.join(__dirname, 'docs/appstore_en.txt')
var local_file_name3 = path.join(__dirname, 'docs/updateinfo_en.txt')
try {
fs.statSync(local_file_name2);
fs.statSync(local_file_name3);
}
catch (e) {
console.log('\n### ABORTING ### One of the following files does not exist:\n' + local_file_name2 + '\n' + local_file_name3);
process.exit(1);
}
try {
// obtain the crowdin api key
@ -50,22 +60,105 @@ if (no_build == false) { // Reminder: Any changes to the script below must also
'1. No changes since last translation build, or\n' +
'2. API limit of once per 30 minutes has not been waited.\n\n' +
'Since we can not guarantee that translations have been built properly, this script will end here.\n' +
'Log in to Bitcoin.com Wallet\'s Crowdin Settings and click the "Build Project" button to assure it is built recently, and then run this ' +
'Log in to Copay\'s Crowdin Settings and click the "Build Project" button to assure it is built recently, and then run this ' +
'script again with the --nobuild arg to download translations without checking if built.');
process.exit(1);
};
downloadAllTranslationsAfterLastBuild();
// Download most recent translations for all languages.
https.get('https://crowdin.com/download/project/' + crowdin_identifier + '.zip', function(res) {
var data = [], dataLen = 0;
res.on('data', function(chunk) {
data.push(chunk);
dataLen += chunk.length;
}).on('end', function() {
var buf = new Buffer(dataLen);
for (var i=0, len = data.length, pos = 0; i < len; i++) {
data[i].copy(buf, pos);
pos += data[i].length;
};
var zip = new AdmZip(buf);
zip.extractAllTo('./', true);
console.log('Done extracting ZIP file.');
var files = fs.readdirSync('./docs');
for (var i in files) {
debugger;
if (files[i].slice(0,9) == 'appstore_' && files[i].slice(-4) == '.txt' && files[i] != 'appstore_en.txt') {
var english_file = fs.readFileSync(local_file_name2, 'utf8');
var compare_file = fs.readFileSync(path.join(__dirname, 'docs/' + files[i]), 'utf8')
english_file = english_file.replace(/\r\n/g, '\n');
compare_file = compare_file.replace(/\r\n/g, '\n');
if (compare_file == english_file) {
fs.unlinkSync(path.join(__dirname, 'docs/' + files[i]));
};
};
if (files[i].slice(0,11) == 'updateinfo_' && files[i].slice(-4) == '.txt' && files[i] != 'updateinfo_en.txt') {
var english_file = fs.readFileSync(local_file_name3, 'utf8');
var compare_file = fs.readFileSync(path.join(__dirname, 'docs/' + files[i]), 'utf8')
english_file = english_file.replace(/\r\n/g, '\n');
compare_file = compare_file.replace(/\r\n/g, '\n');
if (compare_file == english_file) {
fs.unlinkSync(path.join(__dirname, 'docs/' + files[i]));
};
};
};
console.log('Cleaned out completely untranslated appstore docs.');
var files = fs.readdirSync('./po');
for (var i in files) {
if (files[i] != 'template.pot') {
var po_file = fs.readFileSync(path.join(__dirname, 'po/' + files[i]), 'utf8');
var po_array = po_file.split('\n');
for (var j in po_array) {
if (po_array[j].slice(0,5) == 'msgid') {
var source_text = po_array[j].slice(5);
} else if (po_array[j].slice(0,6) == 'msgstr') {
var translate_text = po_array[j].slice(6);
// if a line is not == English, it means there is translation. Keep this file.
if (source_text != translate_text) {
// erase email addresses of last translator for privacy
po_file = po_file.replace(/ <.+@.+\..+>/, '')
fs.writeFileSync(path.join(__dirname, 'po/' + files[i]), po_file);
// split the file into 3 parts, before locale, locale, and after locale.
var lang_pos = po_file.search('"Language: ') + 11;
var po_start = po_file.slice(0,lang_pos);
var po_locale = po_file.slice(lang_pos,lang_pos + 5);
var po_end = po_file.slice(lang_pos + 5);
// check for underscore, if it's there, only take the first 2 letters and reconstruct the po file.
if (po_locale.search('_') > 0) {
fs.writeFileSync(path.join(__dirname, 'po/' + files[i]), po_start + po_locale.slice(0,2) + po_end);
po_start = '';
po_locale = '';
po_end = '';
};
break;
};
};
if (j == po_array.length - 1) { // All strings are exactly identical to English. Delete po file.
fs.unlinkSync(path.join(__dirname, 'po/' + files[i]));
};
};
};
};
console.log('Cleaned out completely untranslated po files.');
});
});
});
}).on('error', function(e) {
console.log('Export Got error: ' + e.message);
});
} else { // Reminder: Any changes to the script below must also be made to the above and vice versa.
downloadAllTranslationsAfterLastBuild();
};
function downloadAllTranslationsAfterLastBuild () {
// Download most recent translations for all languages.
https.get('https://api.crowdin.com/api/project/' + crowdin_identifier + '/download/all.zip?key=' + crowdin_api_key, function(res) {
var data = [], dataLen = 0;
@ -79,85 +172,77 @@ function downloadAllTranslationsAfterLastBuild () {
data[i].copy(buf, pos);
pos += data[i].length;
};
updateLocalFilesFromDownloadedZipBuffer(buf);
var zip = new AdmZip(buf);
zip.extractAllTo('./', true);
console.log('Done extracting ZIP file.');
var files = fs.readdirSync('./docs');
for (var i in files) {
if (files[i].slice(0,9) == 'appstore_' && files[i].slice(-4) == '.txt' && files[i] != 'appstore_en.txt') {
var english_file = fs.readFileSync(local_file_name2, 'utf8');
var compare_file = fs.readFileSync(path.join(__dirname, 'docs/' + files[i]), 'utf8')
english_file = english_file.replace(/\r\n/g, '\n');
compare_file = compare_file.replace(/\r\n/g, '\n');
if (compare_file == english_file) {
fs.unlinkSync(path.join(__dirname, 'docs/' + files[i]));
};
};
if (files[i].slice(0,11) == 'updateinfo_' && files[i].slice(-4) == '.txt' && files[i] != 'updateinfo_en.txt') {
var english_file = fs.readFileSync(local_file_name3, 'utf8');
var compare_file = fs.readFileSync(path.join(__dirname, 'docs/' + files[i]), 'utf8')
english_file = english_file.replace(/\r\n/g, '\n');
compare_file = compare_file.replace(/\r\n/g, '\n');
if (compare_file == english_file) {
fs.unlinkSync(path.join(__dirname, 'docs/' + files[i]));
};
};
};
console.log('Cleaned out completely untranslated appstore docs.');
var files = fs.readdirSync('./po');
for (var i in files) {
if (files[i] != 'template.pot') {
var po_file = fs.readFileSync(path.join(__dirname, 'po/' + files[i]), 'utf8');
var po_array = po_file.split('\n');
for (var j in po_array) {
if (po_array[j].slice(0,5) == 'msgid') {
var source_text = po_array[j].slice(5);
} else if (po_array[j].slice(0,6) == 'msgstr') {
var translate_text = po_array[j].slice(6);
// if a line is not == English, it means there is translation. Keep this file.
if (source_text != translate_text) {
// erase email addresses of last translator for privacy
po_file = po_file.replace(/ <.+@.+\..+>/, '')
fs.writeFileSync(path.join(__dirname, 'po/' + files[i]), po_file);
// split the file into 3 parts, before locale, locale, and after locale.
var lang_pos = po_file.search('"Language: ') + 11;
var po_start = po_file.slice(0,lang_pos);
var po_locale = po_file.slice(lang_pos,lang_pos + 5);
var po_end = po_file.slice(lang_pos + 5);
// check for underscore, if it's there, only take the first 2 letters and reconstruct the po file.
if (po_locale.search('_') > 0) {
fs.writeFileSync(path.join(__dirname, 'po/' + files[i]), po_start + po_locale.slice(0,2) + po_end);
po_start = '';
po_locale = '';
po_end = '';
};
break;
};
};
if (j == po_array.length - 1) { // All strings are exactly identical to English. Delete po file.
fs.unlinkSync(path.join(__dirname, 'po/' + files[i]));
};
};
};
};
console.log('Cleaned out completely untranslated po files.');
});
});
}
function updateLocalFilesFromDownloadedZipBuffer(buf) {
var zip = new AdmZip(buf);
const extractionPath = path.join(__dirname, 'po')
zip.extractAllTo(extractionPath, true);
console.log('Done extracting ZIP file.');
let untranslatedPoFileDeletedCount = 0;
var files = fs.readdirSync(extractionPath);
for (var i in files) {
const name = files[i];
if (name == 'template.pot') {
continue;
}
const fullPath = path.join(extractionPath, name);
const status = fs.statSync(fullPath);
if (!status.isDirectory()) {
console.log(`Not a directory. Don't know what to do with "%{name}", skipping.`);
continue;
}
const filePath = path.join(fullPath, `template-${name}.po`);
if (name === "zh-HK") {
console.log("Deleting zh-HK, because we also have zh-CN and the app uses 2-character locales. Also zh-HK was untranslated at time of writing.");
fs.unlinkSync(filePath);
continue
}
var po_file = fs.readFileSync(filePath, 'utf8');
var po_array = po_file.split('\n');
const linesCount = po_array.length;
for (let j = 0; j < linesCount; j++) {
if (po_array[j].slice(0,5) === 'msgid') {
var source_text = po_array[j].slice(5);
} else if (po_array[j].slice(0,6) === 'msgstr') {
var translate_text = po_array[j].slice(6);
// If a line is not == English, it means there is at least one translation. Keep this entire file.
if ((!blankOrEmptyTranslationRegex.test(translate_text)) &&
source_text !== translate_text) {
console.log(`Keeping ${name}`);
// erase email addresses of last translator for privacy
po_file = po_file.replace(/ <.+@.+\..+>/, '')
fs.writeFileSync(filePath, po_file);
// split the file into 3 parts, before locale, locale, and after locale.
var lang_pos = po_file.search('"Language: ') + 11;
var po_start = po_file.slice(0,lang_pos);
var po_locale = po_file.slice(lang_pos,lang_pos + 5);
var po_end = po_file.slice(lang_pos + 5);
// check for underscore, if it's there, only take the first 2 letters and reconstruct the po file.
// TODO: Fix how this is done, because it won't work properly for
// Chinese, Traditional and Chinese, Simplified, they will clash.
if (po_locale.search('_') > 0) {
fs.writeFileSync(filePath, po_start + po_locale.slice(0,2) + po_end);
po_start = '';
po_locale = '';
po_end = '';
};
break;
};
};
if (j === (linesCount - 1)) { // All strings are exactly identical to English. Delete po file.
fs.unlinkSync(filePath);
console.log(`Deleted ${name}`)
untranslatedPoFileDeletedCount++;
};
};
};
console.log(`Completely untranslated po files cleaned out: ${untranslatedPoFileDeletedCount} (Not including zh-HK)`);
}
};

View file

@ -7,7 +7,7 @@ var path = require('path');
var https = require('https');
var bhttp = require('bhttp');
var crowdin_identifier = 'bitcoincom-wallet'
var crowdin_identifier = 'copay'
var local_file_name1 = path.join(__dirname, 'po/template.pot')
@ -45,7 +45,9 @@ var crowdin_api_key = fs.readFileSync(path.join(__dirname, 'crowdin_api_key.txt'
if (crowdin_api_key != '') {
var payload = {
'files[template.pot]': local_file1
'files[template.pot]': local_file1,
'files[appstore/appstore_en.txt]': local_file2,
'files[appstore/updateinfo_en.txt]': local_file3
};
bhttp.post('https://api.crowdin.com/api/project/' + crowdin_identifier + '/update-file?key=' + crowdin_api_key, payload, {}, function(err, response) {

View file

@ -1,23 +1,23 @@
Secure bitcoin on your own terms with an open source, multisignature wallet from BitPay.
Copay users can hold funds individually or share finances securely with other users with multisignature wallets, which prevent unauthorized payments by requiring multiple approvals. Here are some ways Copay can be used with others:
To save for vacations or joint purchases with friends
To track family spending and allowances
To manage business, club, or organization funds and expenses
We built the following features into this version of Copay for a bitcoin wallet that doesn't compromise on security or accessibility:
Multiple wallet creation and management in-app
Intuitive multisignature security for personal or shared wallets
Easy spending proposal flow for shared wallets and group payments
Hierarchical deterministic (HD) address generation and wallet backups
Device-based security: all private keys are stored locally, not in the cloud
Support for Bitcoin testnet wallets
Synchronous access across all major mobile and desktop platforms
Payment protocol (BIP70-BIP73) support: easily-identifiable payment requests and verifiably secure bitcoin payments
Support for 150+ currency pricing options and unit denomination in BTC or bits
Email notifications for payments and transfers
Customizable wallet naming and background colors
9 supported languages (EN, CS, FR, DE, IT, ES, JA, PL, RU)
Copay is free and open source software run on non-proprietary servers, so there's no need to rely on any company for continuous support. Anyone can review or contribute to Copay's source code on GitHub (https://github.com/bitpay/copay).
Secure bitcoin on your own terms with an open source, multisignature wallet from BitPay.
Copay users can hold funds individually or share finances securely with other users with multisignature wallets, which prevent unauthorized payments by requiring multiple approvals. Here are some ways Copay can be used with others:
To save for vacations or joint purchases with friends
To track family spending and allowances
To manage business, club, or organization funds and expenses
We built the following features into this version of Copay for a bitcoin wallet that doesn't compromise on security or accessibility:
Multiple wallet creation and management in-app
Intuitive multisignature security for personal or shared wallets
Easy spending proposal flow for shared wallets and group payments
Hierarchical deterministic (HD) address generation and wallet backups
Device-based security: all private keys are stored locally, not in the cloud
Support for Bitcoin testnet wallets
Synchronous access across all major mobile and desktop platforms
Payment protocol (BIP70-BIP73) support: easily-identifiable payment requests and verifiably secure bitcoin payments
Support for 150+ currency pricing options and unit denomination in BTC or bits
Email notifications for payments and transfers
Customizable wallet naming and background colors
9 supported languages (EN, CS, FR, DE, IT, ES, JA, PL, RU)
Copay is free and open source software run on non-proprietary servers, so there's no need to rely on any company for continuous support. Anyone can review or contribute to Copay's source code on GitHub (https://github.com/bitpay/copay).

View file

@ -1 +1 @@

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,16 +2,16 @@ msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Project-Id-Version: bitcoincom-wallet\n"
"Project-Id-Version: copay\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: crowdin.com\n"
"X-Crowdin-Project: bitcoincom-wallet\n"
"X-Crowdin-Project: copay\n"
"X-Crowdin-Language: es-ES\n"
"X-Crowdin-File: template.pot\n"
"Last-Translator: emilold\n"
"Last-Translator: cmgustavo83\n"
"Language-Team: Spanish\n"
"Language: es\n"
"PO-Revision-Date: 2018-09-15 05:56\n"
"PO-Revision-Date: 2017-10-10 08:58-0400\n"
#: www/views/modals/paypro.html:34
msgid "(Trusted)"
@ -64,7 +64,7 @@ msgstr "Acerca de"
#: src/js/controllers/modals/txpDetails.js:62
#: src/js/controllers/tx-details.js:79
msgid "Accepted"
msgstr "Aceptada"
msgstr "Aceptado"
#: www/views/preferencesInformation.html:72
msgid "Account"
@ -77,30 +77,6 @@ msgstr "Cuenta"
msgid "Account Number"
msgstr "Número de cuenta"
#: www/views/tab-home.html:61
msgid "Instant transactions with low fees"
msgstr "Transacciones instantáneas con comisiones bajas"
#: www/views/walletSelector.html:49
msgid "Insufficient funds"
msgstr "Sin fondos suficientes"
#: www/views/amount.html:42
msgid "Change Currency"
msgstr "Cambiar moneda"
#: www/views/amount.html:49
msgid "Available Funds"
msgstr "Fondos disponibles"
#: www/views/amount.html:59
msgid "Use All Available Funds"
msgstr "Usar todos los fondos"
#: www/views/amount.html:99
msgid "Next"
msgstr "Siguiente"
#: www/views/preferencesBitpayServices.html:23
msgid "Accounts"
msgstr "Cuentas"
@ -226,20 +202,6 @@ msgstr "¡Casi listo! Vamos a revisar."
msgid "Alternative Currency"
msgstr "Moneda Alternativa"
#: www/views/tab-settings.html:75
msgid "Price Display"
msgstr "Muestra de precio"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:12
msgid "Fiat"
msgstr "Fiat"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:15
msgid "Cryptocurrency"
msgstr "Criptomoneda"
#: src/js/controllers/buyAmazon.js:98
msgid "Amazon.com is not available at this moment. Please try back later."
msgstr "Amazon.com no está disponible en este momento. Inténtalo de nuevo más tarde."
@ -397,12 +359,12 @@ msgstr "Dirección Bitcoin"
#: www/views/cashScan.html:4
msgid "Bitcoin Cash (BCH) Balances"
msgstr "Saldo Bitcoin Cash (BCH)"
msgstr "Saldos Bitcoin Cash (BCH)"
#: www/views/preferencesCash.html:3
#: www/views/tab-settings.html:47
msgid "Bitcoin Cash Support"
msgstr "Soporte Bitcoin Cash"
msgstr "Soportar Bitcoin Cash"
#: www/views/tab-home.html:98
#: www/views/tab-settings.html:115
@ -418,7 +380,7 @@ msgstr "Política de Comisión de la Red Bitcoin"
#: www/views/tab-home.html:83
#: www/views/tab-settings.html:107
msgid "Bitcoin Core Wallets"
msgstr "Criptobilleteras Bitcoin Core"
msgstr "Billeteras Bitcoin"
#: src/js/services/incomingData.js:151
msgid "Bitcoin cash Payment"
@ -471,7 +433,6 @@ msgid "Buy &amp; Sell Bitcoin"
msgstr "Comprar &amp; Vender Bitcoin"
#: www/views/tab-send.html:35
#: src/js/services/buyAndSellService.js:26
msgid "Buy Bitcoin"
msgstr "Comprar Bitcoin"
@ -520,7 +481,7 @@ msgid "Cannot Create Wallet"
msgstr "No se pudo crear la billetera"
#: src/js/services/profileService.js:442
msgid "Cannot join the same wallet more than once"
msgid "Cannot join the same wallet more that once"
msgstr "No puede unirse a la misma billetera más de una vez"
#: www/views/includes/bitpayCardsCard.html:2
@ -590,7 +551,7 @@ msgstr "Color"
#: www/views/preferencesAbout.html:21
msgid "Commit hash"
msgstr "Hash de commit"
msgstr "Commit hash"
#: www/views/preferences.html:49
msgid "Complete the backup process to use this option"
@ -654,14 +615,10 @@ msgstr "Conectando a Glidera..."
msgid "Connection reset by peer"
msgstr "Conexión re establecida"
#: www/views/tab-send.html:85
#: www/views/tab-send.html:45
msgid "Contacts"
msgstr "Contactos"
#: www/views/tab-send.html:86
msgid "Saved frequently used addresses"
msgstr "Direcciones frecuentes guardadas"
#: www/views/onboarding/notifications.html:9
msgid "Continue"
msgstr "Continuar"
@ -692,11 +649,10 @@ msgstr "Copayer unido"
#: www/views/preferencesInformation.html:94
msgid "Copayer {{$index}}"
msgstr "Co-pagador {{$index}}"
msgstr "Copayer {{$index}}"
#: src/js/controllers/copayers.js:79
#: src/js/controllers/export.js:193
#: src/js/controllers/confirm.js:41
#: www/views/includes/copyToClipboard.html:4
msgid "Copied to clipboard"
msgstr "Copiado al portapapeles"
@ -863,7 +819,7 @@ msgstr "Crear billetera compartida"
#: www/views/onboarding/tour.html:51
#: www/views/tab-home.html:75
#: www/views/tab-send.html:75
#: www/views/tab-send.html:36
msgid "Create bitcoin wallet"
msgstr "Crear billetera"
@ -1017,7 +973,7 @@ msgstr "Se ha alcanzado el límite de direcciones vacías. No se pueden generar
#: www/views/preferencesCash.html:17
msgid "Enable Bitcoin Cash wallet creation and operation within the App."
msgstr "Habilita la creación de billeteras de Bitcoin Cash y operaciones dentro de la app."
msgstr "Habilita la creación y operación de billetera Bitcoin Cash dentro de la aplicación."
#: www/views/tab-scan.html:19
msgid "Enable camera access in your device settings to get started."
@ -1031,10 +987,6 @@ msgstr "Activar notificaciones de correo electrónico"
msgid "Enable push notifications"
msgstr "Activar notificaciones push"
#: www/views/preferencesNotifications.html:33
msgid "Enable sound"
msgstr "Habilitar sonido"
#: www/views/tab-scan.html:18
msgid "Enable the camera to get started."
msgstr "Activar la cámara empezar."
@ -1316,7 +1268,6 @@ msgstr "Para propósitos de auditoría"
#: www/views/modals/txp-details.html:74
#: www/views/topup.html:34
#: www/views/tx-details.html:52
#: www/views/review.html:22
msgid "From"
msgstr "Desde"
@ -1377,6 +1328,10 @@ msgid "Get news and updates from BitPay"
msgstr "Recibir noticias y actualizaciones de BitPay"
#: www/views/onboarding/welcome.html:8
msgctxt "button"
msgid "Get started"
msgstr "Comenzar"
#: www/views/bitpayCard.html:49
msgid "Get started"
msgstr "Empezar"
@ -1623,7 +1578,7 @@ msgstr "Dirección de red incorrecta"
#: src/js/controllers/confirm.js:306
#: src/js/services/bwcError.js:44
msgid "Insufficient confirmed funds"
msgstr "Insuficiencia de fondos confirmado"
msgstr "Fondos insuficientes"
#: src/js/controllers/topup.js:165
#: src/js/controllers/topup.js:177
@ -2041,7 +1996,7 @@ msgstr "Es el momento perfecto para mirar a tu alrededor. ¿ventanas? ¿cámaras
#: src/js/services/popupService.js:72
#: www/views/modals/chooseFeeLevel.html:6
msgid "OK"
msgstr "Ok"
msgstr "OK"
#: www/views/modals/tx-status.html:12
#: www/views/modals/tx-status.html:24
@ -2090,7 +2045,7 @@ msgstr "Abrir Proyecto en GitHub"
#: src/js/controllers/bitpayCard.js:123
#: src/js/controllers/tx-details.js:192
msgid "Open Explorer"
msgstr "Abra Explorador"
msgstr "Abrir Insight"
#: www/views/tab-scan.html:22
msgid "Open Settings"
@ -2200,10 +2155,6 @@ msgstr "Pago Rechazado"
msgid "Payment Sent"
msgstr "Pago Enviado"
#: www/views/includes/slideToAcceptSuccess.html:12
msgid "Share this transaction"
msgstr "Comparte esta transacción"
#: www/views/modals/txp-details.html:32
msgid "Payment accepted, but not yet broadcasted"
msgstr "Pago aceptado, pero aún no fue enviado"
@ -2221,8 +2172,8 @@ msgid "Payment details"
msgstr "Detalles del pago"
#: www/views/modals/paypro.html:6
msgid "Payment Request"
msgstr "Solicitar pago"
msgid "Payment request"
msgstr "Solicitud de pago"
#: www/views/mercadoLibreCards.html:22
#: www/views/modals/mercadolibre-card-details.html:39
@ -2281,7 +2232,7 @@ msgstr "Por favor, selecciona el archivo de copia de seguridad"
#: www/views/bitpayCard.html:81
msgid "Pre-Auth Holds"
msgstr "Retención Pre-Auth"
msgstr "Pre-Auth Holds"
#: www/views/tab-settings.html:40
msgid "Preferences"
@ -2552,7 +2503,7 @@ msgstr "Por favor ingrese su huella digital"
#: www/views/preferencesCash.html:23
msgid "Scan your wallets for Bitcoin Cash"
msgstr "Escanea tus billeteras para Bitcoin Cash"
msgstr "Explora tus billeteras para Bitcoin Cash"
#: src/js/services/onGoingProcess.js:30
msgid "Scanning Wallet funds..."
@ -2574,14 +2525,6 @@ msgstr "Buscar transacciones"
msgid "Search or enter bitcoin address"
msgstr "Buscar o introducir dirección bitcoin"
#: src/js/controllers/tab-send.js:28
msgid "Clipboard"
msgstr "Portapapeles"
#: src/js/controllers/tab-send.js:29
msgid "Your Clipboard is empty"
msgstr "Portapapeles vacío"
#: www/views/modals/search.html:16
msgid "Search transactions"
msgstr "Buscar transacciones"
@ -2640,68 +2583,9 @@ msgid "Send by email"
msgstr "Enviar por correo electrónico"
#: src/js/controllers/confirm.js:177
#: src/js/controllers/tab-send.js:94
msgid "Send from"
msgstr "Enviar desde"
#: src/js/controllers/tab-send.js:77
msgid "Send to"
msgstr "Enviar a"
#: www/views/tab-send.html:20
msgid "Paste Clipboard"
msgstr "Pegar portapapeles"
#: www/views/tab-send.html:21
msgid "Paste Address"
msgstr "Pegar dirección"
#: www/views/tab-send.html:27
msgid "Transfer between wallets"
msgstr "Transferir entre billeteras"
#: www/views/tab-send.html:35
msgid "Scan QR Code"
msgstr "Escanear código QR"
#: www/views/tab-send.html:46
msgid "Send Bitcoin faster!"
msgstr "¡Envía Bitcoin más rápido!"
#: www/views/tab-send.html:50
msgid "Save frequently used addresses and send them Bitcoin in just one tap"
msgstr "Guardar las direcciones que usas frecuentemente y envía Bitcoin en un click"
#: www/views/tab-send.html:55
msgid "Add your first contact"
msgstr "Añade tu primer contacto"
#: www/views/tab-send.html:65
msgid "Your Bitcoin wallet is empty"
msgstr "Tu billetera Bitcoin está vacía"
#: www/views/tab-send.html:69
msgid "To get started, buy Bitcoin Cash (BCH) or Bitcoin Core (BTC), or share your address."
msgstr "Para empezar, compra Bitcoin Cash (BCH) o Bitcoin Core (BTC), o comparte tu dirección."
#: www/views/tab-send.html:70
msgid "You can receive bitcoin from any wallet or service."
msgstr "Puedes recibir bitcoin desde cualquier billetera o servicio."
#: www/views/tab-send.html:72
#: www/views/shapeshift.html:23
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "Para empezar, necesitarás crear una billetera y obtener bitcoins."
#: www/views/tab-send.html:74
msgid "Buy Bitcoin now"
msgstr "Comprar Bitcoin ahora"
#: www/views/tab-send.html:76
msgid "Show my address"
msgstr "Ver mi dirección"
#: www/views/includes/itemSelector.html:8
msgid "Send max amount"
msgstr "Enviar la máxima cantidad"
@ -2918,21 +2802,16 @@ msgstr "Súper Económico"
#: www/views/preferencesCash.html:11
msgid "Support Bitcoin Cash"
msgstr "Apoya a Bitcoin Cash"
msgstr "Soportar Bitcoin Cash"
#: www/views/paperWallet.html:7
msgid "Sweep"
msgstr "Importar"
#: www/views/includes/incomingDataMenu.html:89
msgctxt "List item"
msgid "Sweep paper wallet"
msgstr "Importar billetera de papel"
#: www/views/paperWallet.html:3
msgctxt "Page title"
msgid "Sweep Paper Wallet"
msgstr "Importar billetera de papel"
msgid "Sweep paper wallet"
msgstr "Importar billetera en papel"
#: src/js/services/onGoingProcess.js:33
msgid "Sweeping Wallet..."
@ -3100,14 +2979,6 @@ msgstr "Esta aplicación almacena tus bitcoins con seguridad avanzada."
msgid "This bitcoin payment request has expired."
msgstr "Esta solicitud de pago ha caducado."
#: www/views/review.html:55
msgid "Payment expires:"
msgstr "El pago expira en:"
#: www/views/review.html:56
msgid "Payment request has expired"
msgstr "El pago ha expirado"
#: www/views/join.html:133
#: www/views/tab-create-personal.html:103
#: www/views/tab-create-shared.html:132
@ -3149,6 +3020,10 @@ msgstr "Para"
msgid "To get started, buy bitcoin or share your address. You can receive bitcoin from any wallet or service."
msgstr "Para empezar, compra bitcoin o comparte tu dirección. Puedes recibir bitcoin desde cualquier billetera o servicio."
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "Para empezar, necesitarás crear una billetera y obtener bitcoins."
#: src/js/services/bitpayAccountService.js:73
msgid "To {{reason}} you must first add your BitPay account - {{email}}"
msgstr "Para {{reason}} primero debes agregar tu cuenta de BitPay - {{email}}"
@ -3161,26 +3036,6 @@ msgstr "Recarda en progreso..."
msgid "Top up {{amountStr}} to debit card ({{cardLastNumber}})"
msgstr "Recargar {{amountStr}} a la tarjeta de débito ({{cardLastNumber}})"
#: www/views/shapeshift.html:30
msgid "Start ShapeShift"
msgstr "Empezar ShapeShift"
#: www/views/shapeshift.html:30
msgid "Exchange your BTC to BCH in minutes."
msgstr "Intercambia tus BTC a BCH en minutos."
#: www/views/shapeshift.html:30
msgid "To start the process you need to add funds to your wallet."
msgstr "Para iniciar el cambio necesitas añadir fondos a tu billetera."
#: www/views/shapeshift.html:30
msgid "The process is fast and you will receive the exchanged amount in your wallet."
msgstr "El proceso es rápido y recibirás la cantidad intercambiada en tu cartera."
#: www/views/shapeshift.html:34
msgid "This service is provided by the third-party ShapeShift, who will charge a small fee for the service. The fee will be shown before you start the transaction."
msgstr "Este servicio es proporcionado por el tercero ShapeShift, quien cobrará una pequeña tarifa por el servicio. La tarifa se mostrará antes de empezar la transacción."
#: www/views/buyAmazon.html:61
#: www/views/buyMercadoLibre.html:60
#: www/views/modals/wallet-balance.html:23
@ -3337,7 +3192,7 @@ msgstr "Ver Términos de Uso"
#: src/js/controllers/bitpayCard.js:122
#: src/js/controllers/tx-details.js:191
msgid "View Transaction on Explorer.Bitcoin.com"
msgstr "Ver transacción en Explorer.Bitcoin.com"
msgstr "Ver Transacción en Insight"
#: src/js/controllers/tab-home.js:148
msgid "View Update"
@ -3448,7 +3303,7 @@ msgstr "La frase de recuperación no es válida"
#: www/views/preferencesAdvanced.html:25
#: www/views/tab-import-phrase.html:73
msgid "Wallet Service URL"
msgstr "URL de Servicio de Billetera"
msgstr "Wallet Service URL"
#: www/views/preferences.html:4
msgid "Wallet Settings"
@ -3772,172 +3627,3 @@ msgstr "{{updatingTxHistoryProgress}} transacciones descargadas"
#: www/views/includes/walletInfo.html:18
msgid "{{wallet.m}}-of-{{wallet.n}}"
msgstr "{{wallet.m}}-de-{{wallet.n}}"
#: src/js/services/shapeshiftService.js:8
msgid "Shapeshift"
msgstr "Shapeshift - Cambia BTC a BCH"
#: www/views/includes/community.html:3
msgid "Community"
msgstr "Comunidad"
#: src/js/services/communityService.js:40
msgid "Bitcoin Cash Reddit"
msgstr "Reddit de Bitcoin Cash"
#: src/js/services/communityService.js:47
msgid "Bitcoin.com Twitter"
msgstr "Twitter de Bitcoin.com"
#: www/views/includes/nextSteps.html:3
msgid "Explore Bitcoin.com"
msgstr "Explora Bitcoin.com"
#: src/js/services/bitcoincomService.js:21
msgid "Bitcoin Cash Games"
msgstr "Juegos de Bitcoin Cash"
#: www/views/includes/community.html:29
msgid "Share the Wallet App"
msgstr "Comparte esta app"
#: src/js/services/bitcoincomService.js:28
msgid "News"
msgstr "Noticias"
#: src/js/services/bitcoincomService.js:35
msgid "Mining Pool"
msgstr "Minería en la nube"
#: src/js/services/bitcoincomService.js:42
msgid "Tools"
msgstr "Herramientas"
#: src/js/services/bitcoincomService.js:49
msgid "Bitcoin Price Charts"
msgstr "Gráfica de precios Bitcoin"
#: src/js/services/bitcoincomService.js:56
msgid "Free Bitcoin Cash"
msgstr "Bitcoin Cash gratis"
#: www/views/tab-home.html:30
msgid "Your Bitcoin Wallets are ready!"
msgstr "¡Tus billeteras Bitcoin están listas!"
#: src/js/controllers/amount.js:49
msgid "Address does not contain currency information, please make sure you are sending the correct currency."
msgstr "La dirección no contiene información sobre la criptomoneda. Por favor asegúrese de estar enviando la criptomoneda correcta."
#: www/views/review.html:4
msgid "Review Transaction"
msgstr "Revisar transacción"
#: src/js/controllers/review.controller.js:36
msgid "You are sending"
msgstr "Estás enviando"
#: src/js/controllers/review.controller.js:66
msgid "You are shifting"
msgstr "Estás cambiando"
#: www/views/review.html:36
msgid "To:"
msgstr "Para:"
#: www/views/review.html:53
msgid "Add personal note"
msgstr "Añadir nota personal"
#: www/views/review.html:87
msgid "Suggested by merchant:"
msgstr "Sugerido por el comerciante:"
#: src/js/controllers/review.controller.js:37
msgid "Enter text here"
msgstr "Introduce el texto aquí"
#: www/views/review.html:57
msgid "Personal note:"
msgstr "Nota personal:"
#: www/views/review.html:69
msgid "Less than 1 cent"
msgstr "Menos de 1 centavo"
#: src/js/services/incomingData.js:129
msgid "This invoice is no longer accepting payments"
msgstr "Esta factura ya no está aceptando pagos"
#: www/views/amount.html.js:60
msgid "Send Maximum Amount"
msgstr "Enviar cantidad máxima"
#: src/js/controllers/amount.controller.js:239
msgid "Unknown error."
msgstr "Error desconocido."
#: www/views/paperWallet.html:48
msgid "No Bitcoin Cash wallet to transfer funds to found."
msgstr "No se encontró billetera BCH para transferir estos fondos."
#: www/views/paperWallet.html:54
msgid "No Bitcoin Cash found."
msgstr "No se encontró Bitcoin Cash."
#: www/views/paperWallet.html:60
msgid "Bitcoin Core found:"
msgstr "Bitcoin Core encontrado:"
#: www/views/paperWallet.html:98
msgid "No Bitcoin Core wallet to transfer funds to found."
msgstr "No se encontró billetera BTC para transferir estos fondos."
#: www/views/paperWallet.html:104
msgid "No Bitcoin Core found."
msgstr "No se encontró Bitcoin Core."
#: src/js/controllers/tab-scan.js:120
msgid "Scan Failed"
msgstr "Falló el escaneado"
#: src/js/controllers/tab-scan.js:121
msgid "Data not recognised."
msgstr "Datos no reconocidos."
#: src/js/controllers/tab-scan.js:121
msgid "Unsupported"
msgstr "No compatible"
#: src/js/controllers/tab-scan.js:121
msgid "Testnet is not supported."
msgstr "Testnet no es compatible."
#: www/views/includes/incomingDataMenu.html:81
msgid "URL"
msgstr "URL"
#: www/views/includes/incomingDataMenu.html:90
msgid "Open in web browser"
msgstr "Abrir en navegador web"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid address"
msgstr "Dirección inválida"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is not defined"
msgstr "Cantidad no definida"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is below the minimun"
msgstr "Cantidad por debajo del mínimo"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is above the limit"
msgstr "Cantidad por encima del límite"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid response from Shapeshift"
msgstr "Respuesta inválida de Shapeshift"

File diff suppressed because it is too large Load diff

View file

@ -2,16 +2,16 @@ msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Project-Id-Version: bitcoincom-wallet\n"
"Project-Id-Version: copay\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: crowdin.com\n"
"X-Crowdin-Project: bitcoincom-wallet\n"
"X-Crowdin-Project: copay\n"
"X-Crowdin-Language: fr\n"
"X-Crowdin-File: template.pot\n"
"Last-Translator: emilold\n"
"Last-Translator: cmgustavo83\n"
"Language-Team: French\n"
"Language: fr\n"
"PO-Revision-Date: 2018-09-15 05:56\n"
"PO-Revision-Date: 2017-10-10 08:58-0400\n"
#: www/views/modals/paypro.html:34
msgid "(Trusted)"
@ -77,30 +77,6 @@ msgstr "Compte"
msgid "Account Number"
msgstr "Numéro de compte"
#: www/views/tab-home.html:61
msgid "Instant transactions with low fees"
msgstr "Instant transactions with low fees"
#: www/views/walletSelector.html:49
msgid "Insufficient funds"
msgstr "Fonds insuffisants"
#: www/views/amount.html:42
msgid "Change Currency"
msgstr "Changer de devise"
#: www/views/amount.html:49
msgid "Available Funds"
msgstr "Fonds disponibles"
#: www/views/amount.html:59
msgid "Use All Available Funds"
msgstr "Utiliser tous les fonds disponibles"
#: www/views/amount.html:99
msgid "Next"
msgstr "Suivant"
#: www/views/preferencesBitpayServices.html:23
msgid "Accounts"
msgstr "Comptes"
@ -226,20 +202,6 @@ msgstr "C'est presque terminé ! Vérifions."
msgid "Alternative Currency"
msgstr "Devise alternative"
#: www/views/tab-settings.html:75
msgid "Price Display"
msgstr "Affichage des prix"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:12
msgid "Fiat"
msgstr "Fiat"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:15
msgid "Cryptocurrency"
msgstr "Cryptocurrency"
#: src/js/controllers/buyAmazon.js:98
msgid "Amazon.com is not available at this moment. Please try back later."
msgstr "Amazon.com nest pas disponible pour le moment. Veuillez réessayer plus tard."
@ -388,7 +350,7 @@ msgstr "Noubliez pas de conserver votre phrase de récupération dans un endr
#: www/views/preferencesBitpayServices.html:9
msgid "BitPay Visa&reg; Cards"
msgstr "BitPay Visa® cartes"
msgstr "BitPay Visa&reg; Cards"
#: www/views/addressbook.add.html:38
#: www/views/includes/incomingDataMenu.html:29
@ -471,7 +433,6 @@ msgid "Buy &amp; Sell Bitcoin"
msgstr "Acheter &amp; vendre des bitcoins"
#: www/views/tab-send.html:35
#: src/js/services/buyAndSellService.js:26
msgid "Buy Bitcoin"
msgstr "Acheter des bitcoins"
@ -520,8 +481,8 @@ msgid "Cannot Create Wallet"
msgstr "Impossible de créer le portefeuille"
#: src/js/services/profileService.js:442
msgid "Cannot join the same wallet more than once"
msgstr "Impossible de joindre le même portefeuille plus d'une fois"
msgid "Cannot join the same wallet more that once"
msgstr "Impossible de rejoindre le même portefeuille plus d'une fois"
#: www/views/includes/bitpayCardsCard.html:2
msgid "Cards"
@ -654,14 +615,10 @@ msgstr "Connexion à Glidera..."
msgid "Connection reset by peer"
msgstr "Connexion réinitialisée par un pair"
#: www/views/tab-send.html:85
#: www/views/tab-send.html:45
msgid "Contacts"
msgstr "Contacts"
#: www/views/tab-send.html:86
msgid "Saved frequently used addresses"
msgstr "Adresses fréquemment utilisées enregistrées"
#: www/views/onboarding/notifications.html:9
msgid "Continue"
msgstr "Continuer"
@ -692,11 +649,10 @@ msgstr "Un Copayer à rejoint"
#: www/views/preferencesInformation.html:94
msgid "Copayer {{$index}}"
msgstr "Copayeur {{$index}}"
msgstr "Copayer {{$index}}"
#: src/js/controllers/copayers.js:79
#: src/js/controllers/export.js:193
#: src/js/controllers/confirm.js:41
#: www/views/includes/copyToClipboard.html:4
msgid "Copied to clipboard"
msgstr "Copié(e) dans le presse-papier"
@ -731,7 +687,7 @@ msgstr "Impossible daccéder au portefeuille"
#: src/js/controllers/confirm.js:210
msgid "Could not add message to imported wallet without shared encrypting key"
msgstr "Ne peut pas ajouter de message au portefeuille importé sans clé de chiffrement partagée"
msgstr "Could not add message to imported wallet without shared encrypting key"
#: src/js/controllers/modals/txpDetails.js:199
msgid "Could not broadcast payment"
@ -863,7 +819,7 @@ msgstr "Créer un portefeuille partagé"
#: www/views/onboarding/tour.html:51
#: www/views/tab-home.html:75
#: www/views/tab-send.html:75
#: www/views/tab-send.html:36
msgid "Create bitcoin wallet"
msgstr "Créer un portefeuille bitcoin"
@ -1031,10 +987,6 @@ msgstr "Activer les notifications e-mail"
msgid "Enable push notifications"
msgstr "Autoriser les notifications"
#: www/views/preferencesNotifications.html:33
msgid "Enable sound"
msgstr "Malayu"
#: www/views/tab-scan.html:18
msgid "Enable the camera to get started."
msgstr "Autorisez la caméra pour commencer."
@ -1316,7 +1268,6 @@ msgstr "À des fins de vérification"
#: www/views/modals/txp-details.html:74
#: www/views/topup.html:34
#: www/views/tx-details.html:52
#: www/views/review.html:22
msgid "From"
msgstr "De"
@ -1377,6 +1328,10 @@ msgid "Get news and updates from BitPay"
msgstr "Obtenir les actualités et mises à jour de BitPay"
#: www/views/onboarding/welcome.html:8
msgctxt "button"
msgid "Get started"
msgstr "Commencer"
#: www/views/bitpayCard.html:49
msgid "Get started"
msgstr "Commencez"
@ -1593,7 +1548,7 @@ msgstr "Afin de vérifier la sauvegarde de votre portefeuille, veuillez saisir v
#: www/views/mercadoLibreCards.html:24
#: www/views/modals/mercadolibre-card-details.html:29
msgid "Inactive"
msgstr "Inactif"
msgstr "Inactive"
#: www/views/includes/walletItem.html:9
#: www/views/includes/walletList.html:6
@ -1623,7 +1578,7 @@ msgstr "Adresse réseau invalide"
#: src/js/controllers/confirm.js:306
#: src/js/services/bwcError.js:44
msgid "Insufficient confirmed funds"
msgstr "Fonds confirmé insuffisant"
msgstr "Fonds insuffisants"
#: src/js/controllers/topup.js:165
#: src/js/controllers/topup.js:177
@ -1997,7 +1952,7 @@ msgstr "Pas maintenant"
#: www/views/includes/output.html:15
msgid "Note"
msgstr "Commentaire"
msgstr "Note"
#: www/views/backup.html:19
msgid "Note: if this BCH wallet was duplicated from a BTC wallet, they share the same recovery phrase."
@ -2090,7 +2045,7 @@ msgstr "Ouvrir le projet GitHub"
#: src/js/controllers/bitpayCard.js:123
#: src/js/controllers/tx-details.js:192
msgid "Open Explorer"
msgstr "Ouvrir l'explorer"
msgstr "Ouvrir Insight"
#: www/views/tab-scan.html:22
msgid "Open Settings"
@ -2200,10 +2155,6 @@ msgstr "Paiement rejeté"
msgid "Payment Sent"
msgstr "Paiement envoyé"
#: www/views/includes/slideToAcceptSuccess.html:12
msgid "Share this transaction"
msgstr "Partager cette transaction"
#: www/views/modals/txp-details.html:32
msgid "Payment accepted, but not yet broadcasted"
msgstr "Paiement accepté, mais pas encore diffusé"
@ -2221,7 +2172,7 @@ msgid "Payment details"
msgstr "Détails du paiement"
#: www/views/modals/paypro.html:6
msgid "Payment Request"
msgid "Payment request"
msgstr "Demande de paiement"
#: www/views/mercadoLibreCards.html:22
@ -2574,14 +2525,6 @@ msgstr "Rechercher des transactions"
msgid "Search or enter bitcoin address"
msgstr "Recherchez ou saisissez une adresse bitcoin"
#: src/js/controllers/tab-send.js:28
msgid "Clipboard"
msgstr "Presse-papiers"
#: src/js/controllers/tab-send.js:29
msgid "Your Clipboard is empty"
msgstr "Votre presse-papiers est vide"
#: www/views/modals/search.html:16
msgid "Search transactions"
msgstr "Rechercher des transactions"
@ -2640,68 +2583,9 @@ msgid "Send by email"
msgstr "Envoyer par e-mail"
#: src/js/controllers/confirm.js:177
#: src/js/controllers/tab-send.js:94
msgid "Send from"
msgstr "Envoyer à partir de"
#: src/js/controllers/tab-send.js:77
msgid "Send to"
msgstr "Envoyer à"
#: www/views/tab-send.html:20
msgid "Paste Clipboard"
msgstr "Coller le contenu du presse-papiers"
#: www/views/tab-send.html:21
msgid "Paste Address"
msgstr "Coller l'adresse"
#: www/views/tab-send.html:27
msgid "Transfer between wallets"
msgstr "Transfert entre les portefeuilles"
#: www/views/tab-send.html:35
msgid "Scan QR Code"
msgstr "Numérisez le code QR"
#: www/views/tab-send.html:46
msgid "Send Bitcoin faster!"
msgstr "Envoyez des Bitcoin plus vite !"
#: www/views/tab-send.html:50
msgid "Save frequently used addresses and send them Bitcoin in just one tap"
msgstr "Enregistrez les adresses fréquemment utilisées et envoyez-leurs des Bitcoins en un seul geste"
#: www/views/tab-send.html:55
msgid "Add your first contact"
msgstr "Ajoutez votre premier contact"
#: www/views/tab-send.html:65
msgid "Your Bitcoin wallet is empty"
msgstr "Votre portefeuille Bitcoin est vide"
#: www/views/tab-send.html:69
msgid "To get started, buy Bitcoin Cash (BCH) or Bitcoin Core (BTC), or share your address."
msgstr "Pour commencer, achetez des Bitcoins Cash (BCH) ou des Bitcoins Core (BTC), ou partagez votre adresse."
#: www/views/tab-send.html:70
msgid "You can receive bitcoin from any wallet or service."
msgstr "Vous pouvez recevoir des Bitcoins de n'importe quel portefeuille ou service."
#: www/views/tab-send.html:72
#: www/views/shapeshift.html:23
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "Pour commencer, vous aurez besoin de créer un portefeuille bitcoin et d'obtenir quelques bitcoins."
#: www/views/tab-send.html:74
msgid "Buy Bitcoin now"
msgstr "Acheter des Bitcoins maintenant"
#: www/views/tab-send.html:76
msgid "Show my address"
msgstr "Afficher mon adresse"
#: www/views/includes/itemSelector.html:8
msgid "Send max amount"
msgstr "Envoyer le montant maximal"
@ -2925,14 +2809,9 @@ msgid "Sweep"
msgstr "Balayer"
#: www/views/includes/incomingDataMenu.html:89
msgctxt "List item"
msgid "Sweep paper wallet"
msgstr "Balayer un portefeuille papier"
#: www/views/paperWallet.html:3
msgctxt "Page title"
msgid "Sweep Paper Wallet"
msgstr "Balayer un portefeuille papier"
msgid "Sweep paper wallet"
msgstr "Balayer un portefeuille de papier"
#: src/js/services/onGoingProcess.js:33
msgid "Sweeping Wallet..."
@ -3100,14 +2979,6 @@ msgstr "Cette appli conserve vos bitcoins avec une sécurité de pointe."
msgid "This bitcoin payment request has expired."
msgstr "Cette demande de paiement bitcoin a expiré."
#: www/views/review.html:55
msgid "Payment expires:"
msgstr "Expiration du paiement:"
#: www/views/review.html:56
msgid "Payment request has expired"
msgstr "La demande de paiement a expiré"
#: www/views/join.html:133
#: www/views/tab-create-personal.html:103
#: www/views/tab-create-shared.html:132
@ -3149,6 +3020,10 @@ msgstr "À"
msgid "To get started, buy bitcoin or share your address. You can receive bitcoin from any wallet or service."
msgstr "Pour commencer, achetez des bitcoins ou partagez votre adresse. Vous pouvez recevoir des bitcoins de n'importe quel portefeuille ou service."
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "Pour commencer, vous aurez besoin de créer un portefeuille bitcoin et d'obtenir quelques bitcoins."
#: src/js/services/bitpayAccountService.js:73
msgid "To {{reason}} you must first add your BitPay account - {{email}}"
msgstr "Pour {{reason}} vous devez d'abord ajouter votre compte BitPay - {{email}}"
@ -3161,26 +3036,6 @@ msgstr "Rechargement en cours..."
msgid "Top up {{amountStr}} to debit card ({{cardLastNumber}})"
msgstr "Rechargement de {{amountStr}} vers la carte de débit ({{cardLastNumber}})"
#: www/views/shapeshift.html:30
msgid "Start ShapeShift"
msgstr "Démarrer ShapeShift"
#: www/views/shapeshift.html:30
msgid "Exchange your BTC to BCH in minutes."
msgstr "Changez vos BTC en BCH en quelques minutes."
#: www/views/shapeshift.html:30
msgid "To start the process you need to add funds to your wallet."
msgstr "Pour démarrer, vous devez ajouter des fonds à votre portefeuille."
#: www/views/shapeshift.html:30
msgid "The process is fast and you will receive the exchanged amount in your wallet."
msgstr "Le processus est rapide et vous recevrez le montant changé dans votre portefeuille."
#: www/views/shapeshift.html:34
msgid "This service is provided by the third-party ShapeShift, who will charge a small fee for the service. The fee will be shown before you start the transaction."
msgstr "Ce service est fourni par le tiers ShapeShift, qui facturera une somme modique pour le service. Le montant sera affiché avant de démarrer la transaction."
#: www/views/buyAmazon.html:61
#: www/views/buyMercadoLibre.html:60
#: www/views/modals/wallet-balance.html:23
@ -3337,7 +3192,7 @@ msgstr "Voir les conditions d'utilisation"
#: src/js/controllers/bitpayCard.js:122
#: src/js/controllers/tx-details.js:191
msgid "View Transaction on Explorer.Bitcoin.com"
msgstr "Voir la transaction sur Explorer.Bitcoin.com"
msgstr "Voir la transaction sur Insight"
#: src/js/controllers/tab-home.js:148
msgid "View Update"
@ -3448,7 +3303,7 @@ msgstr "La phrase de récupération du portefeuille est invalide"
#: www/views/preferencesAdvanced.html:25
#: www/views/tab-import-phrase.html:73
msgid "Wallet Service URL"
msgstr "URL de service"
msgstr "Wallet Service URL"
#: www/views/preferences.html:4
msgid "Wallet Settings"
@ -3772,172 +3627,3 @@ msgstr "{{updatingTxHistoryProgress}} transactions téléchargées"
#: www/views/includes/walletInfo.html:18
msgid "{{wallet.m}}-of-{{wallet.n}}"
msgstr "{{wallet.m}}-sur-{{wallet.n}}"
#: src/js/services/shapeshiftService.js:8
msgid "Shapeshift"
msgstr "Shapeshift"
#: www/views/includes/community.html:3
msgid "Community"
msgstr "Communauté"
#: src/js/services/communityService.js:40
msgid "Bitcoin Cash Reddit"
msgstr "Reddit Bitcoin Cash"
#: src/js/services/communityService.js:47
msgid "Bitcoin.com Twitter"
msgstr "Twitter Bitcoin.com"
#: www/views/includes/nextSteps.html:3
msgid "Explore Bitcoin.com"
msgstr "Explorez Bitcoin.com"
#: src/js/services/bitcoincomService.js:21
msgid "Bitcoin Cash Games"
msgstr "Jeux Bitcoin Cash"
#: www/views/includes/community.html:29
msgid "Share the Wallet App"
msgstr "Partager lapplication Wallet"
#: src/js/services/bitcoincomService.js:28
msgid "News"
msgstr "Nouvelles"
#: src/js/services/bitcoincomService.js:35
msgid "Mining Pool"
msgstr "Coopératives de mineurs"
#: src/js/services/bitcoincomService.js:42
msgid "Tools"
msgstr "Outils"
#: src/js/services/bitcoincomService.js:49
msgid "Bitcoin Price Charts"
msgstr "Graphiques du prix du Bitcoin"
#: src/js/services/bitcoincomService.js:56
msgid "Free Bitcoin Cash"
msgstr "Bitcoin Cash Gratuit"
#: www/views/tab-home.html:30
msgid "Your Bitcoin Wallets are ready!"
msgstr "Vos portefeuilles bitcoin sont prêts !"
#: src/js/controllers/amount.js:49
msgid "Address does not contain currency information, please make sure you are sending the correct currency."
msgstr "L'adresse ne contient pas dinformations de devise, assurez-vous que vous envoyez la bonne devise."
#: www/views/review.html:4
msgid "Review Transaction"
msgstr "Vérifier la transaction"
#: src/js/controllers/review.controller.js:36
msgid "You are sending"
msgstr "Vous envoyez"
#: src/js/controllers/review.controller.js:66
msgid "You are shifting"
msgstr "Vous changez"
#: www/views/review.html:36
msgid "To:"
msgstr "À :"
#: www/views/review.html:53
msgid "Add personal note"
msgstr "Ajouter une note personnelle"
#: www/views/review.html:87
msgid "Suggested by merchant:"
msgstr "Suggéré par le marchand :"
#: src/js/controllers/review.controller.js:37
msgid "Enter text here"
msgstr "Entrez le texte ici"
#: www/views/review.html:57
msgid "Personal note:"
msgstr "Note personnelle :"
#: www/views/review.html:69
msgid "Less than 1 cent"
msgstr "Moins de 1 centime"
#: src/js/services/incomingData.js:129
msgid "This invoice is no longer accepting payments"
msgstr "Cette facture naccepte plus les paiements"
#: www/views/amount.html.js:60
msgid "Send Maximum Amount"
msgstr "Envoi du montant maximal"
#: src/js/controllers/amount.controller.js:239
msgid "Unknown error."
msgstr "Erreur inconnue."
#: www/views/paperWallet.html:48
msgid "No Bitcoin Cash wallet to transfer funds to found."
msgstr "Aucun portefeuille Bitcoin Cash auquel transférer des fonds trouvé."
#: www/views/paperWallet.html:54
msgid "No Bitcoin Cash found."
msgstr "Pas de Bitcoin Cash trouvé."
#: www/views/paperWallet.html:60
msgid "Bitcoin Core found:"
msgstr "Bitcoin Core trouvé :"
#: www/views/paperWallet.html:98
msgid "No Bitcoin Core wallet to transfer funds to found."
msgstr "Aucun portefeuille Bitcoin Core auquel transférer des fonds trouvé."
#: www/views/paperWallet.html:104
msgid "No Bitcoin Core found."
msgstr "Pas de Bitcoin Core trouvé."
#: src/js/controllers/tab-scan.js:120
msgid "Scan Failed"
msgstr "Échec de l'analyse"
#: src/js/controllers/tab-scan.js:121
msgid "Data not recognised."
msgstr "Données non reconnues."
#: src/js/controllers/tab-scan.js:121
msgid "Unsupported"
msgstr "Non pris en charge"
#: src/js/controllers/tab-scan.js:121
msgid "Testnet is not supported."
msgstr "Testnet nest pas pris en charge."
#: www/views/includes/incomingDataMenu.html:81
msgid "URL"
msgstr "URL"
#: www/views/includes/incomingDataMenu.html:90
msgid "Open in web browser"
msgstr "Ouvrir dans le navigateur web"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid address"
msgstr "Adresse invalide"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is not defined"
msgstr "Le montant nest pas défini"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is below the minimun"
msgstr "Le montant est inférieur au minimum"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is above the limit"
msgstr "Le montant est supérieur à la limite"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid response from Shapeshift"
msgstr "Réponse de Shapeshift invalide"

View file

@ -2,16 +2,16 @@ msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Project-Id-Version: bitcoincom-wallet\n"
"Project-Id-Version: copay\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: crowdin.com\n"
"X-Crowdin-Project: bitcoincom-wallet\n"
"X-Crowdin-Project: copay\n"
"X-Crowdin-Language: it\n"
"X-Crowdin-File: template.pot\n"
"Last-Translator: emilold\n"
"Last-Translator: cmgustavo83\n"
"Language-Team: Italian\n"
"Language: it\n"
"PO-Revision-Date: 2018-09-15 05:56\n"
"PO-Revision-Date: 2017-10-09 10:33-0400\n"
#: www/views/modals/paypro.html:34
msgid "(Trusted)"
@ -77,30 +77,6 @@ msgstr "Conto"
msgid "Account Number"
msgstr "Numero del Conto"
#: www/views/tab-home.html:61
msgid "Instant transactions with low fees"
msgstr "Transazioni istantanee con commissioni basse"
#: www/views/walletSelector.html:49
msgid "Insufficient funds"
msgstr "Fondi insufficienti"
#: www/views/amount.html:42
msgid "Change Currency"
msgstr "Cambia valuta"
#: www/views/amount.html:49
msgid "Available Funds"
msgstr "Fondi disponibili"
#: www/views/amount.html:59
msgid "Use All Available Funds"
msgstr "Usa tutti i fondi disponibili"
#: www/views/amount.html:99
msgid "Next"
msgstr "Avanti"
#: www/views/preferencesBitpayServices.html:23
msgid "Accounts"
msgstr "Account"
@ -226,20 +202,6 @@ msgstr "Quasi finito! Ripassiamo."
msgid "Alternative Currency"
msgstr "Valuta alternativa"
#: www/views/tab-settings.html:75
msgid "Price Display"
msgstr "Visualizzazione prezzi"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:12
msgid "Fiat"
msgstr "Fiat"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:15
msgid "Cryptocurrency"
msgstr "Criptovaluta"
#: src/js/controllers/buyAmazon.js:98
msgid "Amazon.com is not available at this moment. Please try back later."
msgstr "Ia tabella dei guadagni di Amazon.com non è disponibile al momento. Per favore riprova piu tardi."
@ -397,17 +359,17 @@ msgstr "Indirizzo Bitcoin"
#: www/views/cashScan.html:4
msgid "Bitcoin Cash (BCH) Balances"
msgstr "Saldi Bitcoin Cash (BCH)"
msgstr "Saldi di Bitcoin Cash (BCH)"
#: www/views/preferencesCash.html:3
#: www/views/tab-settings.html:47
msgid "Bitcoin Cash Support"
msgstr "Supporto di Bitcoin Cash"
msgstr "Supporto Bitcoin Cash"
#: www/views/tab-home.html:98
#: www/views/tab-settings.html:115
msgid "Bitcoin Cash Wallets"
msgstr "Portafogli Bitcoin Cash"
msgstr ""
#: www/views/modals/chooseFeeLevel.html:4
#: www/views/preferencesFee.html:4
@ -418,7 +380,7 @@ msgstr "Criterio delle Commissioni del Bitcoin Network"
#: www/views/tab-home.html:83
#: www/views/tab-settings.html:107
msgid "Bitcoin Core Wallets"
msgstr "Portafogli Bitcoin Core"
msgstr ""
#: src/js/services/incomingData.js:151
msgid "Bitcoin cash Payment"
@ -471,7 +433,6 @@ msgid "Buy &amp; Sell Bitcoin"
msgstr "Comprare &amp; Vendere Bitcoin"
#: www/views/tab-send.html:35
#: src/js/services/buyAndSellService.js:26
msgid "Buy Bitcoin"
msgstr "Acquista Bitcoin"
@ -520,7 +481,7 @@ msgid "Cannot Create Wallet"
msgstr "Impossibile creare portafoglio"
#: src/js/services/profileService.js:442
msgid "Cannot join the same wallet more than once"
msgid "Cannot join the same wallet more that once"
msgstr "Non è possibile aggiungere un portafoglio più di una volta"
#: www/views/includes/bitpayCardsCard.html:2
@ -654,14 +615,10 @@ msgstr "Connessione a Glidera..."
msgid "Connection reset by peer"
msgstr "Connessione ripristinata dall'utente"
#: www/views/tab-send.html:85
#: www/views/tab-send.html:45
msgid "Contacts"
msgstr "Contatti"
#: www/views/tab-send.html:86
msgid "Saved frequently used addresses"
msgstr "Indirizzi più utilizzati salvati"
#: www/views/onboarding/notifications.html:9
msgid "Continue"
msgstr "Continua"
@ -692,11 +649,10 @@ msgstr "Copayer iscritto"
#: www/views/preferencesInformation.html:94
msgid "Copayer {{$index}}"
msgstr "Pagatore {{$index}}"
msgstr "Copayer {{$index}}"
#: src/js/controllers/copayers.js:79
#: src/js/controllers/export.js:193
#: src/js/controllers/confirm.js:41
#: www/views/includes/copyToClipboard.html:4
msgid "Copied to clipboard"
msgstr "Copiato negli appunti"
@ -863,7 +819,7 @@ msgstr "Creare portafoglio condiviso"
#: www/views/onboarding/tour.html:51
#: www/views/tab-home.html:75
#: www/views/tab-send.html:75
#: www/views/tab-send.html:36
msgid "Create bitcoin wallet"
msgstr "Creare portafoglio bitcoin"
@ -980,7 +936,7 @@ msgstr "Non vedi la tua lingua su Crowdin? Contatta il proprietario su Crowdin!
#: www/views/tab-export-file.html:59
#: www/views/tab-home.html:22
msgid "Download"
msgstr "Scarica"
msgstr "Download"
#: www/views/cashScan.html:37
msgid "Duplicate for BCH"
@ -1017,7 +973,7 @@ msgstr "Raggiunto il limite degli indirizzi vuoti. Non possono essere generati n
#: www/views/preferencesCash.html:17
msgid "Enable Bitcoin Cash wallet creation and operation within the App."
msgstr "Attivare la creazione di portafoglio Bitcoin Cash."
msgstr "Attivare la creazione del portafoglio funzionalità Bitcoin Cash e all'interno dell'App."
#: www/views/tab-scan.html:19
msgid "Enable camera access in your device settings to get started."
@ -1031,10 +987,6 @@ msgstr "Attiva Notifiche Email"
msgid "Enable push notifications"
msgstr "Abilitare le notifiche push"
#: www/views/preferencesNotifications.html:33
msgid "Enable sound"
msgstr "Attivare l'audio"
#: www/views/tab-scan.html:18
msgid "Enable the camera to get started."
msgstr "Abilita la fotocamera per iniziare."
@ -1316,7 +1268,6 @@ msgstr "Per finalità di controllo"
#: www/views/modals/txp-details.html:74
#: www/views/topup.html:34
#: www/views/tx-details.html:52
#: www/views/review.html:22
msgid "From"
msgstr "Da"
@ -1377,6 +1328,10 @@ msgid "Get news and updates from BitPay"
msgstr "Ricevi notizie e aggiornamenti da BitPay"
#: www/views/onboarding/welcome.html:8
msgctxt "button"
msgid "Get started"
msgstr "Per iniziare"
#: www/views/bitpayCard.html:49
msgid "Get started"
msgstr "Inizia"
@ -1392,7 +1347,7 @@ msgstr "Ottenendo i livelli di commissione..."
#: www/views/buyAmazon.html:43
#: www/views/buyMercadoLibre.html:42
msgid "Gift Card"
msgstr "Carta Regalo"
msgstr ""
#: www/views/modals/mercadolibre-card-details.html:30
#: www/views/modals/mercadolibre-card-details.html:35
@ -1623,7 +1578,7 @@ msgstr "Indirizzo di rete non corretto"
#: src/js/controllers/confirm.js:306
#: src/js/services/bwcError.js:44
msgid "Insufficient confirmed funds"
msgstr "Insufficienti fondi confermati"
msgstr "Fondi insufficienti"
#: src/js/controllers/topup.js:165
#: src/js/controllers/topup.js:177
@ -1633,7 +1588,7 @@ msgstr "Fondi insufficienti per la commissione"
#: www/views/tab-settings.html:123
msgid "Integrations"
msgstr "Integrazioni"
msgstr ""
#: www/views/includes/walletHistory.html:49
msgid "Invalid"
@ -2090,7 +2045,7 @@ msgstr "Aprire il progetto GitHub"
#: src/js/controllers/bitpayCard.js:123
#: src/js/controllers/tx-details.js:192
msgid "Open Explorer"
msgstr "Aprire Explorer"
msgstr "Aprire Insight"
#: www/views/tab-scan.html:22
msgid "Open Settings"
@ -2200,10 +2155,6 @@ msgstr "Pagamento Rifiutato"
msgid "Payment Sent"
msgstr "Pagamento Inviato"
#: www/views/includes/slideToAcceptSuccess.html:12
msgid "Share this transaction"
msgstr "Condividi questa transazione"
#: www/views/modals/txp-details.html:32
msgid "Payment accepted, but not yet broadcasted"
msgstr "Pagamento accettato, ma non ancora inviata alla rete"
@ -2221,7 +2172,7 @@ msgid "Payment details"
msgstr "Dettagli pagamento"
#: www/views/modals/paypro.html:6
msgid "Payment Request"
msgid "Payment request"
msgstr "Richiesta di pagamento"
#: www/views/mercadoLibreCards.html:22
@ -2552,7 +2503,7 @@ msgstr "Per cortesia procedere alla scansione dell'impronta digitale"
#: www/views/preferencesCash.html:23
msgid "Scan your wallets for Bitcoin Cash"
msgstr "Scansiona il tuo portafogli Bitcoin Cash"
msgstr "Cercare nei tuoi portafogli per Bitcoin Cash"
#: src/js/services/onGoingProcess.js:30
msgid "Scanning Wallet funds..."
@ -2574,14 +2525,6 @@ msgstr "Cerca Transazioni"
msgid "Search or enter bitcoin address"
msgstr "Cerca o inserisci indirizzo bitcoin"
#: src/js/controllers/tab-send.js:28
msgid "Clipboard"
msgstr "Appunti"
#: src/js/controllers/tab-send.js:29
msgid "Your Clipboard is empty"
msgstr "Gli appunti sono vuoti"
#: www/views/modals/search.html:16
msgid "Search transactions"
msgstr "Ricerca transazioni"
@ -2640,68 +2583,9 @@ msgid "Send by email"
msgstr "Invia via email"
#: src/js/controllers/confirm.js:177
#: src/js/controllers/tab-send.js:94
msgid "Send from"
msgstr "Inviata Da"
#: src/js/controllers/tab-send.js:77
msgid "Send to"
msgstr "Invia a"
#: www/views/tab-send.html:20
msgid "Paste Clipboard"
msgstr "Incolla appunti"
#: www/views/tab-send.html:21
msgid "Paste Address"
msgstr "Incolla indirizzo"
#: www/views/tab-send.html:27
msgid "Transfer between wallets"
msgstr "Trasferisci tra portafogli"
#: www/views/tab-send.html:35
msgid "Scan QR Code"
msgstr "Scansiona codice QR"
#: www/views/tab-send.html:46
msgid "Send Bitcoin faster!"
msgstr "Invia Bitcoin più velocemente!"
#: www/views/tab-send.html:50
msgid "Save frequently used addresses and send them Bitcoin in just one tap"
msgstr "Salva gli indirizzi più utilizzati e invia Bitcoin con un solo tocco"
#: www/views/tab-send.html:55
msgid "Add your first contact"
msgstr "Aggiungi il tuo primo contatto"
#: www/views/tab-send.html:65
msgid "Your Bitcoin wallet is empty"
msgstr "Il tuo portafoglio Bitcoin è vuoto"
#: www/views/tab-send.html:69
msgid "To get started, buy Bitcoin Cash (BCH) or Bitcoin Core (BTC), or share your address."
msgstr "Per iniziare, acquista Bitcoin Cash (BCH) o Bitcoin Core (BTC), oppure condividi il tuo indirizzo."
#: www/views/tab-send.html:70
msgid "You can receive bitcoin from any wallet or service."
msgstr "Puoi ricevere Bitcoin da qualsiasi portafoglio o servizio."
#: www/views/tab-send.html:72
#: www/views/shapeshift.html:23
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "Per iniziare, è necessario che tu crei un portafoglio bitcoin e ottenerne qualcuno."
#: www/views/tab-send.html:74
msgid "Buy Bitcoin now"
msgstr "Acquista subito Bitcoin"
#: www/views/tab-send.html:76
msgid "Show my address"
msgstr "Visualizza il mio indirizzo"
#: www/views/includes/itemSelector.html:8
msgid "Send max amount"
msgstr "Inviare l'importo massimo"
@ -2918,20 +2802,15 @@ msgstr "Super Economica"
#: www/views/preferencesCash.html:11
msgid "Support Bitcoin Cash"
msgstr "Supporta Bitcoin Cash"
msgstr "Supporto Bitcoin Cash"
#: www/views/paperWallet.html:7
msgid "Sweep"
msgstr "Spazzola"
#: www/views/includes/incomingDataMenu.html:89
msgctxt "List item"
msgid "Sweep paper wallet"
msgstr "Spazzare il portafoglio di carta"
#: www/views/paperWallet.html:3
msgctxt "Page title"
msgid "Sweep Paper Wallet"
msgid "Sweep paper wallet"
msgstr "Spazzare il portafoglio di carta"
#: src/js/services/onGoingProcess.js:33
@ -3100,14 +2979,6 @@ msgstr "Questa app memorizza i tuoi bitcoin con sicurezza all'avanguardia."
msgid "This bitcoin payment request has expired."
msgstr "Questa richiesta di pagamento in bitcoin è scaduta."
#: www/views/review.html:55
msgid "Payment expires:"
msgstr "Scadenza del pagamento:"
#: www/views/review.html:56
msgid "Payment request has expired"
msgstr "La richiesta di pagamento è scaduta"
#: www/views/join.html:133
#: www/views/tab-create-personal.html:103
#: www/views/tab-create-shared.html:132
@ -3149,6 +3020,10 @@ msgstr "A"
msgid "To get started, buy bitcoin or share your address. You can receive bitcoin from any wallet or service."
msgstr "Per iniziare, acquista bitcoin o condividi il tuo indirizzo. È possibile ricevere bitcoin da qualsiasi servizio o portafoglio."
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "Per iniziare, è necessario che tu crei un portafoglio bitcoin e ottenerne qualcuno."
#: src/js/services/bitpayAccountService.js:73
msgid "To {{reason}} you must first add your BitPay account - {{email}}"
msgstr "Per {{reason}} è necessario innanzitutto aggiungere il tuo account BitPay - {{email}}"
@ -3161,26 +3036,6 @@ msgstr "Ricarica in corso..."
msgid "Top up {{amountStr}} to debit card ({{cardLastNumber}})"
msgstr "Ricaricare di {{amountStr}} sulla carta di debito ({{cardLastNumber}})"
#: www/views/shapeshift.html:30
msgid "Start ShapeShift"
msgstr "Avvia ShapeShift"
#: www/views/shapeshift.html:30
msgid "Exchange your BTC to BCH in minutes."
msgstr "Cambia i tuoi BTC in BCH in pochi minuti."
#: www/views/shapeshift.html:30
msgid "To start the process you need to add funds to your wallet."
msgstr "Per avviare il processo devi aggiungere fondi al tuo portafoglio."
#: www/views/shapeshift.html:30
msgid "The process is fast and you will receive the exchanged amount in your wallet."
msgstr "Il processo è veloce e riceverai l'importo cambiato nel tuo portafoglio."
#: www/views/shapeshift.html:34
msgid "This service is provided by the third-party ShapeShift, who will charge a small fee for the service. The fee will be shown before you start the transaction."
msgstr "Questo servizio è fornito dalla terza parte ShapeShift, che addebiterà una piccola commissione per lo stesso. La commissione sarà mostrata prima di iniziare la transazione."
#: www/views/buyAmazon.html:61
#: www/views/buyMercadoLibre.html:60
#: www/views/modals/wallet-balance.html:23
@ -3337,7 +3192,7 @@ msgstr "Visualizza i termini di servizio"
#: src/js/controllers/bitpayCard.js:122
#: src/js/controllers/tx-details.js:191
msgid "View Transaction on Explorer.Bitcoin.com"
msgstr "Visualizza transazione a Explorer.Bitcoin.com"
msgstr "Visualizzazione della transazione su Insight"
#: src/js/controllers/tab-home.js:148
msgid "View Update"
@ -3772,172 +3627,3 @@ msgstr "{{updatingTxHistoryProgress}} transazioni scaricate"
#: www/views/includes/walletInfo.html:18
msgid "{{wallet.m}}-of-{{wallet.n}}"
msgstr "{{wallet.m}}-di-{{wallet.n}}"
#: src/js/services/shapeshiftService.js:8
msgid "Shapeshift"
msgstr "Shapeshift"
#: www/views/includes/community.html:3
msgid "Community"
msgstr "Community"
#: src/js/services/communityService.js:40
msgid "Bitcoin Cash Reddit"
msgstr "Bitcoin Cash su Reddit"
#: src/js/services/communityService.js:47
msgid "Bitcoin.com Twitter"
msgstr "Bitcoin.com su Twitter"
#: www/views/includes/nextSteps.html:3
msgid "Explore Bitcoin.com"
msgstr "Esplora Bitcoin.com"
#: src/js/services/bitcoincomService.js:21
msgid "Bitcoin Cash Games"
msgstr "Giochi Bitcoin Cash"
#: www/views/includes/community.html:29
msgid "Share the Wallet App"
msgstr "Condividere l'app Portafoglio"
#: src/js/services/bitcoincomService.js:28
msgid "News"
msgstr "News"
#: src/js/services/bitcoincomService.js:35
msgid "Mining Pool"
msgstr "Mining Pool"
#: src/js/services/bitcoincomService.js:42
msgid "Tools"
msgstr "Strumenti"
#: src/js/services/bitcoincomService.js:49
msgid "Bitcoin Price Charts"
msgstr "Tabella prezzi Bitcoin"
#: src/js/services/bitcoincomService.js:56
msgid "Free Bitcoin Cash"
msgstr "Bitcoin Cash gratis"
#: www/views/tab-home.html:30
msgid "Your Bitcoin Wallets are ready!"
msgstr "I tuoi portafogli Bitcoin sono pronti!"
#: src/js/controllers/amount.js:49
msgid "Address does not contain currency information, please make sure you are sending the correct currency."
msgstr "L'indirizzo non contiene informazioni sulla valuta. Verifica di inviare la valuta corretta."
#: www/views/review.html:4
msgid "Review Transaction"
msgstr "Rivedi transazione"
#: src/js/controllers/review.controller.js:36
msgid "You are sending"
msgstr "Stai inviando"
#: src/js/controllers/review.controller.js:66
msgid "You are shifting"
msgstr "Stai spostando"
#: www/views/review.html:36
msgid "To:"
msgstr "A:"
#: www/views/review.html:53
msgid "Add personal note"
msgstr "Aggiungi nota personale"
#: www/views/review.html:87
msgid "Suggested by merchant:"
msgstr "Suggerito dal commerciante:"
#: src/js/controllers/review.controller.js:37
msgid "Enter text here"
msgstr "Inserisci il testo qui"
#: www/views/review.html:57
msgid "Personal note:"
msgstr "Nota personale:"
#: www/views/review.html:69
msgid "Less than 1 cent"
msgstr "Meno di 1 centesimo"
#: src/js/services/incomingData.js:129
msgid "This invoice is no longer accepting payments"
msgstr "Questa fattura non accetta più pagamenti"
#: www/views/amount.html.js:60
msgid "Send Maximum Amount"
msgstr "Inviare importo massimo"
#: src/js/controllers/amount.controller.js:239
msgid "Unknown error."
msgstr "Errore sconosciuto."
#: www/views/paperWallet.html:48
msgid "No Bitcoin Cash wallet to transfer funds to found."
msgstr "Nessun portafoglio Bitcoin Cash trovato per il trasferimento di fondi."
#: www/views/paperWallet.html:54
msgid "No Bitcoin Cash found."
msgstr "Nessun Bitcoin Cash trovato."
#: www/views/paperWallet.html:60
msgid "Bitcoin Core found:"
msgstr "Bitcoin Core trovato:"
#: www/views/paperWallet.html:98
msgid "No Bitcoin Core wallet to transfer funds to found."
msgstr "Nessun portafoglio Bitcoin Core trovato per il trasferimento di fondi."
#: www/views/paperWallet.html:104
msgid "No Bitcoin Core found."
msgstr "Nessun Bitcoin Core trovato."
#: src/js/controllers/tab-scan.js:120
msgid "Scan Failed"
msgstr "Scansione non riuscita"
#: src/js/controllers/tab-scan.js:121
msgid "Data not recognised."
msgstr "Dati non riconosciuti."
#: src/js/controllers/tab-scan.js:121
msgid "Unsupported"
msgstr "Non supportato"
#: src/js/controllers/tab-scan.js:121
msgid "Testnet is not supported."
msgstr "Testnet non supportato."
#: www/views/includes/incomingDataMenu.html:81
msgid "URL"
msgstr "URL"
#: www/views/includes/incomingDataMenu.html:90
msgid "Open in web browser"
msgstr "Aprire nel browser web"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid address"
msgstr "Indirizzo non valido"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is not defined"
msgstr "Importo non definito"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is below the minimun"
msgstr "Importo inferiore al minimo"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is above the limit"
msgstr "Importo sopra il limite"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid response from Shapeshift"
msgstr "Risposta non valida da Shapeshift"

View file

@ -2,16 +2,16 @@ msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Project-Id-Version: bitcoincom-wallet\n"
"Project-Id-Version: copay\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: crowdin.com\n"
"X-Crowdin-Project: bitcoincom-wallet\n"
"X-Crowdin-Project: copay\n"
"X-Crowdin-Language: ja\n"
"X-Crowdin-File: template.pot\n"
"Last-Translator: emilold\n"
"Last-Translator: cmgustavo83\n"
"Language-Team: Japanese\n"
"Language: ja\n"
"PO-Revision-Date: 2018-09-15 05:56\n"
"PO-Revision-Date: 2017-10-09 10:33-0400\n"
#: www/views/modals/paypro.html:34
msgid "(Trusted)"
@ -77,30 +77,6 @@ msgstr "ポケット"
msgid "Account Number"
msgstr "ポケット番号"
#: www/views/tab-home.html:61
msgid "Instant transactions with low fees"
msgstr "僅かな手数料で即時決済"
#: www/views/walletSelector.html:49
msgid "Insufficient funds"
msgstr "残高不足"
#: www/views/amount.html:42
msgid "Change Currency"
msgstr "通貨を変更"
#: www/views/amount.html:49
msgid "Available Funds"
msgstr "利用可能な残高"
#: www/views/amount.html:59
msgid "Use All Available Funds"
msgstr "利用可能な資金をすべて使用"
#: www/views/amount.html:99
msgid "Next"
msgstr "次"
#: www/views/preferencesBitpayServices.html:23
msgid "Accounts"
msgstr "アカウント一覧"
@ -226,20 +202,6 @@ msgstr "ほぼ完了!確認してみましょう。"
msgid "Alternative Currency"
msgstr "表示通貨"
#: www/views/tab-settings.html:75
msgid "Price Display"
msgstr "価格表示"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:12
msgid "Fiat"
msgstr "法定通貨"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:15
msgid "Cryptocurrency"
msgstr "仮想通貨"
#: src/js/controllers/buyAmazon.js:98
msgid "Amazon.com is not available at this moment. Please try back later."
msgstr "Amazon.com は現在ご利用できません、また後でお試しください"
@ -440,7 +402,7 @@ msgstr "ビットコインは世界で<br>最も安全な仮想通貨。"
#: www/views/preferencesFee.html:11
msgid "Bitcoin transactions include a fee collected by miners on the network."
msgstr "ビットコインの取引はネットワークの安全を守る「採掘者」と呼ばれる達に送る手数料が含まれます。"
msgstr "ビットコインの取引はネットワークの安全を守る「採掘者」と呼ばれる達に送る手数料が含まれます。"
#: www/views/buyAmazon.html:108
msgid "Bought {{amountUnitStr}}"
@ -473,7 +435,6 @@ msgid "Buy &amp; Sell Bitcoin"
msgstr "ビットコインの購入&amp;売却"
#: www/views/tab-send.html:35
#: src/js/services/buyAndSellService.js:26
msgid "Buy Bitcoin"
msgstr "ビットコインを購入"
@ -522,8 +483,8 @@ msgid "Cannot Create Wallet"
msgstr "ウォレットを作成できません。"
#: src/js/services/profileService.js:442
msgid "Cannot join the same wallet more than once"
msgstr "同じ端末で同じウォレットに複数回参加することできません。"
msgid "Cannot join the same wallet more that once"
msgstr "同じ端末で同じウォレットに複数回参加することできません。"
#: www/views/includes/bitpayCardsCard.html:2
msgid "Cards"
@ -656,14 +617,10 @@ msgstr "Glidera に接続中…"
msgid "Connection reset by peer"
msgstr "接続がピアによってリセットされました"
#: www/views/tab-send.html:85
#: www/views/tab-send.html:45
msgid "Contacts"
msgstr "連絡先"
#: www/views/tab-send.html:86
msgid "Saved frequently used addresses"
msgstr "よく使う保存済みのアドレス"
#: www/views/onboarding/notifications.html:9
msgid "Continue"
msgstr "続ける"
@ -674,7 +631,7 @@ msgstr "翻訳に協力"
#: src/js/controllers/confirm.js:130
msgid "Copay only supports Bitcoin Cash using new version numbers addresses"
msgstr "のビットコインキャッシュはビットコインと完全に異なる別通貨なので、アドレスの頭文字が異なります。"
msgstr "Copay のビットコインキャッシュはビットコインと完全に異なる別通貨なので、アドレスの頭文字が異なります。"
#: src/js/services/bwcError.js:62
msgid "Copayer already in this wallet"
@ -698,7 +655,6 @@ msgstr "ウォレット参加者 {{$index}}"
#: src/js/controllers/copayers.js:79
#: src/js/controllers/export.js:193
#: src/js/controllers/confirm.js:41
#: www/views/includes/copyToClipboard.html:4
msgid "Copied to clipboard"
msgstr "クリップボードにコピーしました"
@ -865,7 +821,7 @@ msgstr "共有ウォレットを作成"
#: www/views/onboarding/tour.html:51
#: www/views/tab-home.html:75
#: www/views/tab-send.html:75
#: www/views/tab-send.html:36
msgid "Create bitcoin wallet"
msgstr "ビットコインウォレット作成"
@ -1033,10 +989,6 @@ msgstr "メール通知を有効化"
msgid "Enable push notifications"
msgstr "プッシュ通知を有効化"
#: www/views/preferencesNotifications.html:33
msgid "Enable sound"
msgstr "サウンドを有効にする"
#: www/views/tab-scan.html:18
msgid "Enable the camera to get started."
msgstr "始めるためにカメラを有効にして下さい。"
@ -1318,7 +1270,6 @@ msgstr "監査用機能"
#: www/views/modals/txp-details.html:74
#: www/views/topup.html:34
#: www/views/tx-details.html:52
#: www/views/review.html:22
msgid "From"
msgstr "送信者"
@ -1379,13 +1330,17 @@ msgid "Get news and updates from BitPay"
msgstr "BitPay からのニュースや更新情報を受け取ります。"
#: www/views/onboarding/welcome.html:8
msgctxt "button"
msgid "Get started"
msgstr "始めよう"
#: www/views/bitpayCard.html:49
msgid "Get started"
msgstr "始めよう"
#: www/views/addressbook.html:20
msgid "Get started by adding your first one."
msgstr "連絡先を追加しましょう。"
msgstr "初めての連絡先を追加しましょう。"
#: src/js/services/onGoingProcess.js:23
msgid "Getting fee levels..."
@ -1394,7 +1349,7 @@ msgstr "手数料レベルを取得しています…"
#: www/views/buyAmazon.html:43
#: www/views/buyMercadoLibre.html:42
msgid "Gift Card"
msgstr "ギフト カード"
msgstr ""
#: www/views/modals/mercadolibre-card-details.html:30
#: www/views/modals/mercadolibre-card-details.html:35
@ -1625,7 +1580,7 @@ msgstr "サーバーのアドレスが不正です"
#: src/js/controllers/confirm.js:306
#: src/js/services/bwcError.js:44
msgid "Insufficient confirmed funds"
msgstr "承認済み残高不足"
msgstr "残高不足"
#: src/js/controllers/topup.js:165
#: src/js/controllers/topup.js:177
@ -1910,7 +1865,7 @@ msgstr "バックアップは非常に重要です!"
#: www/views/addressbook.html:19
msgid "No contacts yet"
msgstr "連絡先はありません"
msgstr "連絡先が無い"
#: www/views/preferencesLogs.html:16
msgid "No entries for this log level"
@ -2092,7 +2047,7 @@ msgstr "GitHub のプロジェクトを開く"
#: src/js/controllers/bitpayCard.js:123
#: src/js/controllers/tx-details.js:192
msgid "Open Explorer"
msgstr "ブロック・エクスプローラを開く"
msgstr "Insightを開く"
#: www/views/tab-scan.html:22
msgid "Open Settings"
@ -2202,10 +2157,6 @@ msgstr "送金が却下されました"
msgid "Payment Sent"
msgstr "送金が完了しました"
#: www/views/includes/slideToAcceptSuccess.html:12
msgid "Share this transaction"
msgstr "このトランザクションを共有"
#: www/views/modals/txp-details.html:32
msgid "Payment accepted, but not yet broadcasted"
msgstr "取引が承認されましたが、まだ送信していません。"
@ -2223,8 +2174,8 @@ msgid "Payment details"
msgstr "支払いの詳細"
#: www/views/modals/paypro.html:6
msgid "Payment Request"
msgstr "支払いを要求する"
msgid "Payment request"
msgstr "支払い請求"
#: www/views/mercadoLibreCards.html:22
#: www/views/modals/mercadolibre-card-details.html:39
@ -2270,7 +2221,7 @@ msgstr "正しい順序で各単語をタップしてください。"
#: src/js/services/bwcError.js:101
msgid "Please upgrade Copay to perform this action"
msgstr "この操作を実行するにはを最新バージョンに更新してください"
msgstr "この操作を実行するにはCopayを最新バージョンに更新してください"
#: www/views/walletDetails.html:142
#: www/views/walletDetails.html:62
@ -2576,14 +2527,6 @@ msgstr "取引を検索"
msgid "Search or enter bitcoin address"
msgstr "連絡先検索かビットコインアドレスを指定"
#: src/js/controllers/tab-send.js:28
msgid "Clipboard"
msgstr "クリップボード"
#: src/js/controllers/tab-send.js:29
msgid "Your Clipboard is empty"
msgstr "クリップボードは空です"
#: www/views/modals/search.html:16
msgid "Search transactions"
msgstr "取引を検索"
@ -2642,68 +2585,9 @@ msgid "Send by email"
msgstr "メールで送信"
#: src/js/controllers/confirm.js:177
#: src/js/controllers/tab-send.js:94
msgid "Send from"
msgstr "ここから送金"
#: src/js/controllers/tab-send.js:77
msgid "Send to"
msgstr "送金先:"
#: www/views/tab-send.html:20
msgid "Paste Clipboard"
msgstr "クリップボードからペースト"
#: www/views/tab-send.html:21
msgid "Paste Address"
msgstr "アドレスをペースト"
#: www/views/tab-send.html:27
msgid "Transfer between wallets"
msgstr "ウォレット間送金"
#: www/views/tab-send.html:35
msgid "Scan QR Code"
msgstr "QRコードを読み取る"
#: www/views/tab-send.html:46
msgid "Send Bitcoin faster!"
msgstr "ビットコイン送金をより高速に!"
#: www/views/tab-send.html:50
msgid "Save frequently used addresses and send them Bitcoin in just one tap"
msgstr "よく使うアドレスを保存すればワンタップでビットコインを送金できます"
#: www/views/tab-send.html:55
msgid "Add your first contact"
msgstr "最初の連絡先を追加"
#: www/views/tab-send.html:65
msgid "Your Bitcoin wallet is empty"
msgstr "ビットコインウォレットが空です"
#: www/views/tab-send.html:69
msgid "To get started, buy Bitcoin Cash (BCH) or Bitcoin Core (BTC), or share your address."
msgstr "始めるには、Bitcoin Cash (BCH) または Bitcoin Core (BTC) を購入するか、あなたのアドレスを共有してください。"
#: www/views/tab-send.html:70
msgid "You can receive bitcoin from any wallet or service."
msgstr "どのウォレットやサービスからでもビットコインを受け取ることができます。"
#: www/views/tab-send.html:72
#: www/views/shapeshift.html:23
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "はじめに、ビットコインウォレットを作成し、ビットコインを入手する必要があります。"
#: www/views/tab-send.html:74
msgid "Buy Bitcoin now"
msgstr "今すぐビットコインを購入"
#: www/views/tab-send.html:76
msgid "Show my address"
msgstr "自分のアドレスを表示"
#: www/views/includes/itemSelector.html:8
msgid "Send max amount"
msgstr "全残高を送金"
@ -2929,13 +2813,8 @@ msgid "Sweep"
msgstr "全残高インポート"
#: www/views/includes/incomingDataMenu.html:89
msgctxt "List item"
msgid "Sweep paper wallet"
msgstr "ペーパーウォレットの全残高インポート"
#: www/views/paperWallet.html:3
msgctxt "Page title"
msgid "Sweep Paper Wallet"
msgid "Sweep paper wallet"
msgstr "ペーパーウォレットの全残高インポート"
#: src/js/services/onGoingProcess.js:33
@ -3106,14 +2985,6 @@ msgstr "このアプリは、最先端のセキュリティであなたのビッ
msgid "This bitcoin payment request has expired."
msgstr "ビットコインペイメントの請求期限が切れています。"
#: www/views/review.html:55
msgid "Payment expires:"
msgstr "支払い請求の有効期限:"
#: www/views/review.html:56
msgid "Payment request has expired"
msgstr "支払い要求の期限が切れています"
#: www/views/join.html:133
#: www/views/tab-create-personal.html:103
#: www/views/tab-create-shared.html:132
@ -3155,6 +3026,10 @@ msgstr "宛先"
msgid "To get started, buy bitcoin or share your address. You can receive bitcoin from any wallet or service."
msgstr "はじめるには、ビットコインを購入したり、アドレスを他の人に共有したりしましょう。どのビットコインウォレットやサービスから受け取れます。"
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "はじめに、ビットコインウォレットを作成し、ビットコインを入手する必要があります。"
#: src/js/services/bitpayAccountService.js:73
msgid "To {{reason}} you must first add your BitPay account - {{email}}"
msgstr "{{reason}}その前にBitPayアカウントを追加する必要があります - {{email}}"
@ -3167,26 +3042,6 @@ msgstr "残高補充処理中..."
msgid "Top up {{amountStr}} to debit card ({{cardLastNumber}})"
msgstr "デビットカード ({{cardLastNumber}}) に {{amountStr}} の入金を行う"
#: www/views/shapeshift.html:30
msgid "Start ShapeShift"
msgstr "ShapeShiftを開始"
#: www/views/shapeshift.html:30
msgid "Exchange your BTC to BCH in minutes."
msgstr "数分でBTCをBCHに変換できます。"
#: www/views/shapeshift.html:30
msgid "To start the process you need to add funds to your wallet."
msgstr "処理を開始するには、資金をウォレットに追加する必要があります。"
#: www/views/shapeshift.html:30
msgid "The process is fast and you will receive the exchanged amount in your wallet."
msgstr "処理は高速で、交換した金額がウォレットに届きます。"
#: www/views/shapeshift.html:34
msgid "This service is provided by the third-party ShapeShift, who will charge a small fee for the service. The fee will be shown before you start the transaction."
msgstr "このサービスは、少額のサービス手数料を請求する第三者組織である ShapeShift によって提供されています。手数料は取引を開始する前に表示されます。"
#: www/views/buyAmazon.html:61
#: www/views/buyMercadoLibre.html:60
#: www/views/modals/wallet-balance.html:23
@ -3343,7 +3198,7 @@ msgstr "サービス利用規約を表示"
#: src/js/controllers/bitpayCard.js:122
#: src/js/controllers/tx-details.js:191
msgid "View Transaction on Explorer.Bitcoin.com"
msgstr "explorer.bitcoin.comで取引詳細を表示する"
msgstr "Insightにて取引を表示"
#: src/js/controllers/tab-home.js:148
msgid "View Update"
@ -3587,7 +3442,7 @@ msgstr "送金発生時のメール通知はどのメールアドレスで受け
#: www/views/addresses.html:19
msgid "Why?"
msgstr "なぜですか"
msgstr "なぜ?"
#: www/views/feedback/rateApp.html:10
msgid "Would you be willing to rate {{appName}} in the app store?"
@ -3777,173 +3632,4 @@ msgstr "{{updatingTxHistoryProgress}} 個の取引ダウンロード済み"
#: www/views/copayers.html:46
#: www/views/includes/walletInfo.html:18
msgid "{{wallet.m}}-of-{{wallet.n}}"
msgstr "{{wallet.m}} の{{wallet.n}}"
#: src/js/services/shapeshiftService.js:8
msgid "Shapeshift"
msgstr "Shapeshift"
#: www/views/includes/community.html:3
msgid "Community"
msgstr "コミュニティ"
#: src/js/services/communityService.js:40
msgid "Bitcoin Cash Reddit"
msgstr "Bitcoin Cash Reddit"
#: src/js/services/communityService.js:47
msgid "Bitcoin.com Twitter"
msgstr "Bitcoin.com Twitter"
#: www/views/includes/nextSteps.html:3
msgid "Explore Bitcoin.com"
msgstr "Bitcoin.com を参照"
#: src/js/services/bitcoincomService.js:21
msgid "Bitcoin Cash Games"
msgstr "Bitcoin Cash ゲーム"
#: www/views/includes/community.html:29
msgid "Share the Wallet App"
msgstr "ウォレットアプリを共有"
#: src/js/services/bitcoincomService.js:28
msgid "News"
msgstr "ニュース"
#: src/js/services/bitcoincomService.js:35
msgid "Mining Pool"
msgstr "マイニングプール"
#: src/js/services/bitcoincomService.js:42
msgid "Tools"
msgstr "ツール"
#: src/js/services/bitcoincomService.js:49
msgid "Bitcoin Price Charts"
msgstr "ビットコインの価格チャート"
#: src/js/services/bitcoincomService.js:56
msgid "Free Bitcoin Cash"
msgstr "無料 Bitcoin Cash"
#: www/views/tab-home.html:30
msgid "Your Bitcoin Wallets are ready!"
msgstr "ビットコインウォレットが完成しました!"
#: src/js/controllers/amount.js:49
msgid "Address does not contain currency information, please make sure you are sending the correct currency."
msgstr "アドレスに通貨情報が含まれていません。正しい通貨を送金していることを確認してください。"
#: www/views/review.html:4
msgid "Review Transaction"
msgstr "トランザクションの確認"
#: src/js/controllers/review.controller.js:36
msgid "You are sending"
msgstr "送金中: "
#: src/js/controllers/review.controller.js:66
msgid "You are shifting"
msgstr "取引中: "
#: www/views/review.html:36
msgid "To:"
msgstr "宛先:"
#: www/views/review.html:53
msgid "Add personal note"
msgstr "個人用メモを追加"
#: www/views/review.html:87
msgid "Suggested by merchant:"
msgstr "お店からのおすすめ:"
#: src/js/controllers/review.controller.js:37
msgid "Enter text here"
msgstr "ここにテキストを入力してください"
#: www/views/review.html:57
msgid "Personal note:"
msgstr "個人用メモ:"
#: www/views/review.html:69
msgid "Less than 1 cent"
msgstr "1セント以下"
#: src/js/services/incomingData.js:129
msgid "This invoice is no longer accepting payments"
msgstr "この請求書はもう支払を受け付けていません"
#: www/views/amount.html.js:60
msgid "Send Maximum Amount"
msgstr "全残高を送金"
#: src/js/controllers/amount.controller.js:239
msgid "Unknown error."
msgstr "不明なエラーです。"
#: www/views/paperWallet.html:48
msgid "No Bitcoin Cash wallet to transfer funds to found."
msgstr "資金を送金できるビットコインキャッシュウォレットが見つかりません。"
#: www/views/paperWallet.html:54
msgid "No Bitcoin Cash found."
msgstr "ビットコインキャッシュが見つかりません。"
#: www/views/paperWallet.html:60
msgid "Bitcoin Core found:"
msgstr "ビットコインが見つかりました:"
#: www/views/paperWallet.html:98
msgid "No Bitcoin Core wallet to transfer funds to found."
msgstr "資金を送金できるビットコインウォレットが見つかりません。"
#: www/views/paperWallet.html:104
msgid "No Bitcoin Core found."
msgstr "ビットコインが見つかりません。"
#: src/js/controllers/tab-scan.js:120
msgid "Scan Failed"
msgstr "スキャンできませんでした"
#: src/js/controllers/tab-scan.js:121
msgid "Data not recognised."
msgstr "データが認識されていません。"
#: src/js/controllers/tab-scan.js:121
msgid "Unsupported"
msgstr "未対応"
#: src/js/controllers/tab-scan.js:121
msgid "Testnet is not supported."
msgstr "Testnet には対応していません。"
#: www/views/includes/incomingDataMenu.html:81
msgid "URL"
msgstr "URL"
#: www/views/includes/incomingDataMenu.html:90
msgid "Open in web browser"
msgstr "ウェブブラウザで開く"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid address"
msgstr "無効なアドレス"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is not defined"
msgstr "金額が定義されていません"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is below the minimun"
msgstr "金額が最少額を下回っています"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is above the limit"
msgstr "金額が上限を超えています"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid response from Shapeshift"
msgstr "Shapeshift から無効な応答がありました"
msgstr "{{wallet.m}}-of-{{wallet.n}}"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,16 +2,16 @@ msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Project-Id-Version: bitcoincom-wallet\n"
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
"Project-Id-Version: copay\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Generator: crowdin.com\n"
"X-Crowdin-Project: bitcoincom-wallet\n"
"X-Crowdin-Project: copay\n"
"X-Crowdin-Language: pl\n"
"X-Crowdin-File: template.pot\n"
"Last-Translator: emilold\n"
"Last-Translator: cmgustavo83\n"
"Language-Team: Polish\n"
"Language: pl\n"
"PO-Revision-Date: 2018-09-15 05:56\n"
"PO-Revision-Date: 2017-10-09 10:33-0400\n"
#: www/views/modals/paypro.html:34
msgid "(Trusted)"
@ -41,7 +41,7 @@ msgstr "5-gwiazdkowa ocena pozwoli na wzrost popularności {{appName}}, a więks
#: www/views/mercadoLibre.html:18
#: www/views/mercadoLibre.html:40
msgid "<b>Only</b> redeemable on Mercado Livre (Brazil)"
msgstr "98804213800207"
msgstr ""
#: src/js/controllers/feedback/send.js:27
#: www/views/feedback/complete.html:21
@ -77,30 +77,6 @@ msgstr "Konto"
msgid "Account Number"
msgstr "Numer konta"
#: www/views/tab-home.html:61
msgid "Instant transactions with low fees"
msgstr "Natychmiastowe transakcje z niskimi prowizjami"
#: www/views/walletSelector.html:49
msgid "Insufficient funds"
msgstr "Niewystarczające środki"
#: www/views/amount.html:42
msgid "Change Currency"
msgstr "Zmień walutę"
#: www/views/amount.html:49
msgid "Available Funds"
msgstr "Dostępne środki"
#: www/views/amount.html:59
msgid "Use All Available Funds"
msgstr "Użyj wszystkich dostępnych środków"
#: www/views/amount.html:99
msgid "Next"
msgstr "Dalej"
#: www/views/preferencesBitpayServices.html:23
msgid "Accounts"
msgstr "Konta"
@ -226,20 +202,6 @@ msgstr "Prawie gotowe! Dokonajmy przeglądu."
msgid "Alternative Currency"
msgstr "Alternatywna waluta"
#: www/views/tab-settings.html:75
msgid "Price Display"
msgstr "Wyświetlanie ceny"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:12
msgid "Fiat"
msgstr "Fiat"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:15
msgid "Cryptocurrency"
msgstr "Kryptowaluta"
#: src/js/controllers/buyAmazon.js:98
msgid "Amazon.com is not available at this moment. Please try back later."
msgstr "Amazon.com jest aktualnie niedostępny. Spróbuj później."
@ -272,7 +234,7 @@ msgstr "Każdy, kto ma Twoją kluczową frazę może uzyskać dostęp lub wydać
#: www/views/addresses.html:94
msgid "Approximate Bitcoin network fee to transfer wallet's balance (with normal priority)"
msgstr "Szacunkowe opłaty sieci Bitcoin do przeniesienia salda portfela (normalny priorytet)"
msgstr ""
#: www/views/backupWarning.html:10
msgid "Are you being watched?"
@ -341,7 +303,7 @@ msgstr "BIP32 ścieżka dla adresu derywacji"
#: www/views/cashScan.html:25
msgid "BTC wallets"
msgstr "Portfele BTC"
msgstr ""
#: www/views/preferences.html:34
msgid "Backup"
@ -397,17 +359,17 @@ msgstr "Adres bitcoin"
#: www/views/cashScan.html:4
msgid "Bitcoin Cash (BCH) Balances"
msgstr "Salda Bitcoin Cash (BCH)"
msgstr ""
#: www/views/preferencesCash.html:3
#: www/views/tab-settings.html:47
msgid "Bitcoin Cash Support"
msgstr "Wsparcie Bitcoin Cash"
msgstr ""
#: www/views/tab-home.html:98
#: www/views/tab-settings.html:115
msgid "Bitcoin Cash Wallets"
msgstr "Płatność Bitcoin Cash"
msgstr ""
#: www/views/modals/chooseFeeLevel.html:4
#: www/views/preferencesFee.html:4
@ -418,11 +380,11 @@ msgstr "Polityka prowizji sieci bitcoin"
#: www/views/tab-home.html:83
#: www/views/tab-settings.html:107
msgid "Bitcoin Core Wallets"
msgstr "Portfele Bitcoin Core"
msgstr ""
#: src/js/services/incomingData.js:151
msgid "Bitcoin cash Payment"
msgstr "Płatność Bitcoin Cash"
msgstr ""
#: www/views/onboarding/tour.html:31
msgid "Bitcoin is a currency."
@ -471,7 +433,6 @@ msgid "Buy &amp; Sell Bitcoin"
msgstr "Kup &amp; sprzedaj bitcoiny"
#: www/views/tab-send.html:35
#: src/js/services/buyAndSellService.js:26
msgid "Buy Bitcoin"
msgstr "Kup bitcoiny"
@ -520,7 +481,7 @@ msgid "Cannot Create Wallet"
msgstr "Nie można utworzyć portfela"
#: src/js/services/profileService.js:442
msgid "Cannot join the same wallet more than once"
msgid "Cannot join the same wallet more that once"
msgstr "Nie można dołączyć tego samego portfela więcej niż raz"
#: www/views/includes/bitpayCardsCard.html:2
@ -654,14 +615,10 @@ msgstr "Łączenie z Gildera..."
msgid "Connection reset by peer"
msgstr "Połączenie zostało zresetowane"
#: www/views/tab-send.html:85
#: www/views/tab-send.html:45
msgid "Contacts"
msgstr "Kontakty"
#: www/views/tab-send.html:86
msgid "Saved frequently used addresses"
msgstr "Zapisane często używane adresy"
#: www/views/onboarding/notifications.html:9
msgid "Continue"
msgstr "Dalej"
@ -672,7 +629,7 @@ msgstr "Wkład do tłumaczenia"
#: src/js/controllers/confirm.js:130
msgid "Copay only supports Bitcoin Cash using new version numbers addresses"
msgstr "Copay obsługuje tylko Bitcoin gotówki za pomocą nowej wersji numery adresy"
msgstr ""
#: src/js/services/bwcError.js:62
msgid "Copayer already in this wallet"
@ -696,7 +653,6 @@ msgstr "Współwłaściciele {{$index}}"
#: src/js/controllers/copayers.js:79
#: src/js/controllers/export.js:193
#: src/js/controllers/confirm.js:41
#: www/views/includes/copyToClipboard.html:4
msgid "Copied to clipboard"
msgstr "Skopiowano do schowka"
@ -863,7 +819,7 @@ msgstr "Utwórz współdzielony portfel"
#: www/views/onboarding/tour.html:51
#: www/views/tab-home.html:75
#: www/views/tab-send.html:75
#: www/views/tab-send.html:36
msgid "Create bitcoin wallet"
msgstr "Utwórz portfel bitcoin"
@ -984,7 +940,7 @@ msgstr "Pobierz"
#: www/views/cashScan.html:37
msgid "Duplicate for BCH"
msgstr "Duplikat dla BCH"
msgstr ""
#: src/js/services/onGoingProcess.js:49
msgid "Duplicating wallet..."
@ -1017,7 +973,7 @@ msgstr "Puste adresy osiągnęły limit. Nowe adresy nie mogą być generowane."
#: www/views/preferencesCash.html:17
msgid "Enable Bitcoin Cash wallet creation and operation within the App."
msgstr "Włącz tworzenie i obsługę portfela Bitcoin Cash w aplikacji."
msgstr ""
#: www/views/tab-scan.html:19
msgid "Enable camera access in your device settings to get started."
@ -1031,17 +987,13 @@ msgstr "Włącz powiadomienia e-mail"
msgid "Enable push notifications"
msgstr "Włącz powiadomienia"
#: www/views/preferencesNotifications.html:33
msgid "Enable sound"
msgstr "Włącz dźwięk"
#: www/views/tab-scan.html:18
msgid "Enable the camera to get started."
msgstr "Włącz kamerę aby rozpocząć."
#: www/views/tab-settings.html:49
msgid "Enabled"
msgstr "Włączono"
msgstr "Włączone"
#: src/js/services/walletService.js:1047
#: src/js/services/walletService.js:1062
@ -1316,7 +1268,6 @@ msgstr "Do celów audytu"
#: www/views/modals/txp-details.html:74
#: www/views/topup.html:34
#: www/views/tx-details.html:52
#: www/views/review.html:22
msgid "From"
msgstr "Z"
@ -1377,6 +1328,10 @@ msgid "Get news and updates from BitPay"
msgstr "Otrzymywanie wiadomości i aktualizacji z BitPay"
#: www/views/onboarding/welcome.html:8
msgctxt "button"
msgid "Get started"
msgstr "Pierwsze kroki"
#: www/views/bitpayCard.html:49
msgid "Get started"
msgstr "Zacznij"
@ -1392,7 +1347,7 @@ msgstr "Uzyskiwanie informacji o prowizji..."
#: www/views/buyAmazon.html:43
#: www/views/buyMercadoLibre.html:42
msgid "Gift Card"
msgstr "Karta podarunkowa"
msgstr ""
#: www/views/modals/mercadolibre-card-details.html:30
#: www/views/modals/mercadolibre-card-details.html:35
@ -1451,7 +1406,7 @@ msgstr "Portfel sprzętowy"
#: src/js/controllers/create.js:180
#: src/js/controllers/join.js:145
msgid "Hardware wallets are not yet supported with Bitcoin Cash"
msgstr "Portfele sprzętowe nie są jeszcze obsługiwane z Bitcoin gotówki"
msgstr ""
#: www/views/tab-settings.html:20
msgid "Help & Support"
@ -1623,7 +1578,7 @@ msgstr "Nieprawidłowy adres"
#: src/js/controllers/confirm.js:306
#: src/js/services/bwcError.js:44
msgid "Insufficient confirmed funds"
msgstr "Niewystarczające potwierdzone środki"
msgstr "Nie ma wystarczającej ilości środków"
#: src/js/controllers/topup.js:165
#: src/js/controllers/topup.js:177
@ -1633,7 +1588,7 @@ msgstr "Niewystarczające środki na prowizję"
#: www/views/tab-settings.html:123
msgid "Integrations"
msgstr "Integracje"
msgstr ""
#: www/views/includes/walletHistory.html:49
msgid "Invalid"
@ -1782,7 +1737,7 @@ msgstr "Wyloguj się"
#: www/views/addresses.html:87
msgid "Low amount inputs"
msgstr "Niska kwota"
msgstr ""
#: www/views/includes/walletHistory.html:27
msgid "Low fees"
@ -1814,11 +1769,11 @@ msgstr "Notatka"
#: www/views/mercadoLibre.html:6
msgid "Mercado Livre Brazil Gift Cards"
msgstr "Karty podarunkowe Mercado Livre Brazil"
msgstr ""
#: src/js/controllers/buyMercadoLibre.js:98
msgid "Mercadolibre Gift Card Service is not available at this moment. Please try back later."
msgstr "Karta podarunkowa MercadoLibre nie jest obecnie dostępna. Spróbuj później."
msgstr ""
#: www/views/modals/txp-details.html:131
msgid "Merchant Message"
@ -1828,7 +1783,7 @@ msgstr "Wiadomość handlowa"
#: www/views/buyMercadoLibre.html:54
#: www/views/topup.html:63
msgid "Miner Fee"
msgstr "Opłata dla górnika"
msgstr ""
#: src/js/services/bwcError.js:134
msgid "Missing parameter"
@ -1871,7 +1826,7 @@ msgstr "Nazwa"
#: www/views/buyMercadoLibre.html:48
#: www/views/topup.html:56
msgid "Network Cost"
msgstr "Koszty sieci"
msgstr ""
#: src/js/services/bwcError.js:47
msgid "Network error"
@ -1933,7 +1888,7 @@ msgstr "Brak wcześniejszych transakcji"
#: src/js/controllers/buyAmazon.js:44
#: src/js/controllers/topup.js:47
msgid "No signing proposal: No private key"
msgstr "Nie podpisywania wniosku: nie ma klucza prywatnego"
msgstr ""
#: www/views/walletDetails.html:204
msgid "No transactions yet"
@ -1960,15 +1915,15 @@ msgstr "Brak portfeli do otrzymania środków"
#: www/views/cashScan.html:15
msgid "No wallets eligible for Bitcoin Cash support"
msgstr "Brak portfeli wspierających Bitcoin Cash"
msgstr ""
#: src/js/controllers/cashScan.js:58
msgid "Non BIP44 wallet"
msgstr "Nie BIP44 portfel"
msgstr ""
#: www/views/cashScan.html:46
msgid "Non eligible BTC wallets"
msgstr "Niewspierane portfele BTC"
msgstr ""
#: src/js/services/feeService.js:12
msgid "Normal"
@ -2001,7 +1956,7 @@ msgstr "Notatka"
#: www/views/backup.html:19
msgid "Note: if this BCH wallet was duplicated from a BTC wallet, they share the same recovery phrase."
msgstr "Uwaga: Jeśli ten portfel BCH został zduplikowany z portfela BTC, będą one współdzielić ten sam zwrot odzyskiwania."
msgstr ""
#: www/views/modals/wallets.html:25
msgid "Notice: only 1-1 (single signature) wallets can be used for sell bitcoin"
@ -2090,7 +2045,7 @@ msgstr "Otwórz projekt GitHub"
#: src/js/controllers/bitpayCard.js:123
#: src/js/controllers/tx-details.js:192
msgid "Open Explorer"
msgstr "Otwórz Explorer"
msgstr "Otwórz Insight"
#: www/views/tab-scan.html:22
msgid "Open Settings"
@ -2110,7 +2065,7 @@ msgstr "Otworzyć bitcoincash.org?"
#: src/js/controllers/cashScan.js:18
msgid "Open the recovery tool."
msgstr "Otwórz narzędzie do odzyskiwania."
msgstr ""
#: www/views/tab-receive.html:27
msgid "Open wallet"
@ -2200,10 +2155,6 @@ msgstr "Wypłata odrzucona"
msgid "Payment Sent"
msgstr "Płatność wysłana"
#: www/views/includes/slideToAcceptSuccess.html:12
msgid "Share this transaction"
msgstr "Udostępnij tę transakcję"
#: www/views/modals/txp-details.html:32
msgid "Payment accepted, but not yet broadcasted"
msgstr "Wypłata zaakceptowana, ale jeszcze nie nadana"
@ -2214,14 +2165,14 @@ msgstr "Wypłata zaakceptowana. Będzie nadana przez Glidera. W przypadku wystą
#: src/js/services/incomingData.js:152
msgid "Payment address was translated to new Bitcoin Cash address format:"
msgstr "Adres płatności został przetłumaczony na nowy format adresów Bitcoin Cash:"
msgstr ""
#: www/views/modals/txp-details.html:107
msgid "Payment details"
msgstr "Szczegóły wypłaty"
#: www/views/modals/paypro.html:6
msgid "Payment Request"
msgid "Payment request"
msgstr "Wniosek o płatność"
#: www/views/mercadoLibreCards.html:22
@ -2281,7 +2232,7 @@ msgstr "Proszę wybrać plik kopii zapasowej"
#: www/views/bitpayCard.html:81
msgid "Pre-Auth Holds"
msgstr "Wstrzymanie przedautoryzacyjne"
msgstr ""
#: www/views/tab-settings.html:40
msgid "Preferences"
@ -2385,7 +2336,7 @@ msgstr "Więcej informacji w naszej Wiki"
#: src/js/controllers/cashScan.js:61
msgid "Read only wallet"
msgstr "Portfel tylko do odczytu"
msgstr ""
#: www/views/tab-receive.html:3
#: www/views/tabs.html:7
@ -2394,7 +2345,7 @@ msgstr "Otrzymaj"
#: www/views/customAmount.html:44
msgid "Receive in"
msgstr "Otrzymaj w"
msgstr ""
#: www/views/includes/walletHistory.html:24
#: www/views/tx-details.html:18
@ -2552,7 +2503,7 @@ msgstr "Proszę zeskanować linie papilarne"
#: www/views/preferencesCash.html:23
msgid "Scan your wallets for Bitcoin Cash"
msgstr "Skanuj portfele w poszukiwaniu Bitcoin Cash"
msgstr ""
#: src/js/services/onGoingProcess.js:30
msgid "Scanning Wallet funds..."
@ -2574,14 +2525,6 @@ msgstr "Szukaj transakcji"
msgid "Search or enter bitcoin address"
msgstr "Wyszukaj lub wpisz adres bitcoin"
#: src/js/controllers/tab-send.js:28
msgid "Clipboard"
msgstr "Schowek"
#: src/js/controllers/tab-send.js:29
msgid "Your Clipboard is empty"
msgstr "Schowek jest pusty"
#: www/views/modals/search.html:16
msgid "Search transactions"
msgstr "Szukaj transakcji"
@ -2596,7 +2539,7 @@ msgstr "Bezpieczeństwo"
#: www/views/modals/mercadolibre-card-details.html:64
msgid "See invoice"
msgstr "Zobacz fakturę"
msgstr ""
#: www/views/tab-import-file.html:7
msgid "Select a backup file"
@ -2640,68 +2583,9 @@ msgid "Send by email"
msgstr "Wyślij przez e-mail"
#: src/js/controllers/confirm.js:177
#: src/js/controllers/tab-send.js:94
msgid "Send from"
msgstr "Wyślij z"
#: src/js/controllers/tab-send.js:77
msgid "Send to"
msgstr "Wyślij do"
#: www/views/tab-send.html:20
msgid "Paste Clipboard"
msgstr "Wklej ze schowka"
#: www/views/tab-send.html:21
msgid "Paste Address"
msgstr "Wklej adres"
#: www/views/tab-send.html:27
msgid "Transfer between wallets"
msgstr "Transfer między portfelami"
#: www/views/tab-send.html:35
msgid "Scan QR Code"
msgstr "Zeskanuj kod QR"
#: www/views/tab-send.html:46
msgid "Send Bitcoin faster!"
msgstr "Przesyłaj Bitcoiny szybciej!"
#: www/views/tab-send.html:50
msgid "Save frequently used addresses and send them Bitcoin in just one tap"
msgstr "Zapisz często używane adresy i wyślij im Bitcoin za pomocą jednego dotknięcia"
#: www/views/tab-send.html:55
msgid "Add your first contact"
msgstr "Dodaj swój pierwszy kontakt"
#: www/views/tab-send.html:65
msgid "Your Bitcoin wallet is empty"
msgstr "Twój portfel jest pusty"
#: www/views/tab-send.html:69
msgid "To get started, buy Bitcoin Cash (BCH) or Bitcoin Core (BTC), or share your address."
msgstr "Aby zacząć, kup Bitcoin Cash (BCH) lub Bitcoin Core (BTC), albo udostępnij swój adres."
#: www/views/tab-send.html:70
msgid "You can receive bitcoin from any wallet or service."
msgstr "Bitcoiny można odbierać z dowolnego portfela lub usługi."
#: www/views/tab-send.html:72
#: www/views/shapeshift.html:23
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "Aby rozpocząć należy utworzyć portfel i dostać trochę bitcoinów."
#: www/views/tab-send.html:74
msgid "Buy Bitcoin now"
msgstr "Kup Bitcoin teraz"
#: www/views/tab-send.html:76
msgid "Show my address"
msgstr "Pokaż mój adres"
#: www/views/includes/itemSelector.html:8
msgid "Send max amount"
msgstr "Wyślij całą kwotę"
@ -2855,7 +2739,7 @@ msgstr "Pomiń"
#: src/js/controllers/confirm.js:371
#: src/js/controllers/modals/txpDetails.js:47
msgid "Slide to accept"
msgstr "Przesuń, aby zaakceptować"
msgstr ""
#: www/views/buyAmazon.html:96
msgid "Slide to buy"
@ -2863,16 +2747,16 @@ msgstr "Przesuń, aby kupić"
#: src/js/controllers/confirm.js:365
msgid "Slide to pay"
msgstr "Przesuń, aby zapłacić"
msgstr ""
#: src/js/controllers/confirm.js:377
#: src/js/controllers/modals/txpDetails.js:40
msgid "Slide to send"
msgstr "Przesuń, aby wysłać"
msgstr ""
#: www/views/cashScan.html:56
msgid "Some of your wallets are not eligible for Bitcoin Cash support. You can try to access BCH funds from these wallets using the"
msgstr "Niektóre z twoich portfeli nie kwalifikują się do wsparcia Bitcoin Cash. Dostęp do środków BCH z tych portfeli można spróbować uzyskać, korzystając z"
msgstr ""
#: src/js/controllers/create.js:88
#: src/js/controllers/join.js:71
@ -2893,7 +2777,7 @@ msgstr "Wymagane hasło wypłat"
#: www/views/walletDetails.html:173
msgid "Spending this balance will need significant Bitcoin network fees"
msgstr "Wydanie tego salda będzie wymagało znacznych opłat sieciowych Bitcoin"
msgstr ""
#: www/views/tab-send.html:28
msgid "Start sending bitcoin"
@ -2906,7 +2790,7 @@ msgstr "Blokada uruchamiania"
#: www/views/mercadoLibreCards.html:21
#: www/views/modals/mercadolibre-card-details.html:42
msgid "Still pending"
msgstr "Jeszcze w toku"
msgstr ""
#: www/views/topup.html:101
msgid "Success"
@ -2918,20 +2802,15 @@ msgstr "Super Ekonomiczna"
#: www/views/preferencesCash.html:11
msgid "Support Bitcoin Cash"
msgstr "Wsparcie Bitcoin Cash"
msgstr ""
#: www/views/paperWallet.html:7
msgid "Sweep"
msgstr "Opróżnij"
#: www/views/includes/incomingDataMenu.html:89
msgctxt "List item"
msgid "Sweep paper wallet"
msgstr "Wyczyść papierowy portfel"
#: www/views/paperWallet.html:3
msgctxt "Page title"
msgid "Sweep Paper Wallet"
msgid "Sweep paper wallet"
msgstr "Wyczyść papierowy portfel"
#: src/js/services/onGoingProcess.js:33
@ -2953,7 +2832,7 @@ msgstr "Dotknij i przytrzymaj, aby pokazać"
#: www/views/includes/walletInfo.html:3
msgid "Tap to recreate"
msgstr "Dotknij, aby odświeżyć"
msgstr ""
#: www/views/includes/walletInfo.html:4
msgid "Tap to retry"
@ -3100,14 +2979,6 @@ msgstr "Ta aplikacja przechowuje Twoje bitcoiny z zaawansowanymi zabezpieczeniam
msgid "This bitcoin payment request has expired."
msgstr "Ten wniosek płatności wygasł."
#: www/views/review.html:55
msgid "Payment expires:"
msgstr "Płatność wygasa:"
#: www/views/review.html:56
msgid "Payment request has expired"
msgstr "Wniosek o płatność wygasł"
#: www/views/join.html:133
#: www/views/tab-create-personal.html:103
#: www/views/tab-create-shared.html:132
@ -3120,7 +2991,7 @@ msgstr "Ta kluczowa fraza został utworzona przy użyciu hasła. Aby odzyskać p
#: www/views/tx-details.html:91
msgid "This transaction amount is too small compared to current Bitcoin network fees. Spending these funds will need a Bitcoin network fee cost comparable to the funds itself."
msgstr "Ta kwota transakcji jest zbyt mała w porównaniu z obecnymi opłatami sieci Bitcoin. Wydanie tych środków będzie wymagało opłaty sieciowej Bitcoin, która jest porównywalna do kosztów samych funduszy."
msgstr ""
#: www/views/tx-details.html:87
msgid "This transaction could take a long time to confirm or could be dropped due to the low fees set by the sender"
@ -3149,37 +3020,21 @@ msgstr "Do"
msgid "To get started, buy bitcoin or share your address. You can receive bitcoin from any wallet or service."
msgstr "Aby zacząć, kup bitcoiny lub udostępnij swój adres. Możesz otrzymać bitcoiny z dowolnego portfela lub usługi."
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "Aby rozpocząć należy utworzyć portfel i dostać trochę bitcoinów."
#: src/js/services/bitpayAccountService.js:73
msgid "To {{reason}} you must first add your BitPay account - {{email}}"
msgstr "Aby móc wykonać czynność {{reason}}, musisz przedtem dodać swoje konto BitPay {{email}}"
msgstr ""
#: src/js/services/onGoingProcess.js:48
msgid "Top up in progress..."
msgstr "Doładowanie w trakcie..."
msgstr ""
#: src/js/controllers/topup.js:206
msgid "Top up {{amountStr}} to debit card ({{cardLastNumber}})"
msgstr "Doładuj o {{amountStr}} kartę debetową ({{cardLastNumber}})"
#: www/views/shapeshift.html:30
msgid "Start ShapeShift"
msgstr "Rozpocznij ShapeShift"
#: www/views/shapeshift.html:30
msgid "Exchange your BTC to BCH in minutes."
msgstr "Wymień BTC na BCH w ciągu paru chwil."
#: www/views/shapeshift.html:30
msgid "To start the process you need to add funds to your wallet."
msgstr "Aby zacząć, dodaj środki do portfela."
#: www/views/shapeshift.html:30
msgid "The process is fast and you will receive the exchanged amount in your wallet."
msgstr "Proces jest szybki, a użytkownik otrzyma wymienione środki do portfela."
#: www/views/shapeshift.html:34
msgid "This service is provided by the third-party ShapeShift, who will charge a small fee for the service. The fee will be shown before you start the transaction."
msgstr "Ta usługa jest świadczona przez podmiot zewnętrzny ShapeShift, który naliczy za nią niewielką opłatę. Będzie ona widoczna przed rozpoczęciem transakcji."
msgstr ""
#: www/views/buyAmazon.html:61
#: www/views/buyMercadoLibre.html:60
@ -3198,7 +3053,7 @@ msgstr "Liczba współwłaścicieli portfela"
#: www/views/addresses.html:81
msgid "Total wallet inputs"
msgstr "Dane wejściowe portfela łącznie"
msgstr ""
#: src/js/services/fingerprintService.js:63
#: src/js/services/fingerprintService.js:68
@ -3226,7 +3081,7 @@ msgstr "Transakcja została już wysłana"
#: src/js/controllers/buyMercadoLibre.js:301
#: src/js/controllers/topup.js:281
msgid "Transaction has not been created"
msgstr "Transakcja nie została utworzona"
msgstr ""
#: www/views/topup.html:104
msgid "Transaction initiated"
@ -3337,7 +3192,7 @@ msgstr "Zobacz zasady użytkowania"
#: src/js/controllers/bitpayCard.js:122
#: src/js/controllers/tx-details.js:191
msgid "View Transaction on Explorer.Bitcoin.com"
msgstr "Zobacz transakcję na Explorer.Bitcoin.com"
msgstr "Zobacz transakcje na Insight"
#: src/js/controllers/tab-home.js:148
msgid "View Update"
@ -3349,7 +3204,7 @@ msgstr "Zobacz na blockchainie"
#: www/views/mercadoLibre.html:26
msgid "Visit mercadolivre.com.br &rarr;"
msgstr "Odwiedź mercadolivre.com.br &rarr;"
msgstr ""
#: www/views/walletDetails.html:182
msgid "WARNING: Key derivation is not working on this device/wallet. Actions cannot be performed on this wallet."
@ -3411,7 +3266,7 @@ msgstr "Informacje o portfelu"
#: www/views/addresses.html:76
msgid "Wallet Inputs"
msgstr "Dane wejściowe portfela"
msgstr ""
#: www/views/join.html:26
msgid "Wallet Invitation"
@ -3465,7 +3320,7 @@ msgstr "Portfel już istnieje"
#: src/js/services/profileService.js:516
msgid "Wallet already in {{appName}}"
msgstr "Portfel już w aplikacji {{appName}}"
msgstr ""
#: www/views/includes/walletActivity.html:6
msgid "Wallet created"
@ -3516,7 +3371,7 @@ msgstr "Portfel nie jest zarejestrowany w Wallet Service. Odtwórz go używając
#: www/views/backup.html:12
msgid "Wallet recovery phrase not available"
msgstr "Fraza odzyskiwania portfela nie jest dostępna"
msgstr ""
#: src/js/services/bwcError.js:50
msgid "Wallet service not found"
@ -3645,7 +3500,7 @@ msgstr "Nie należy ustawiać opłatę wyższą niż {{maxFeeRecommended}} satos
#: www/views/modals/bitpay-card-confirmation.html:5
msgid "You will need to log back for fill in your BitPay Card."
msgstr "Musisz zalogować się ponownie, aby wypełnić swoją kartę BitPay."
msgstr ""
#: www/views/preferencesNotifications.html:34
msgid "You'll receive email notifications about payments sent and received from your wallets."
@ -3658,7 +3513,7 @@ msgstr "Twoja karta BitPay jest gotowa. Zasil kartę, aby zacząć ją używać
#: www/views/mercadoLibre.html:57
#: www/views/mercadoLibreCards.html:6
msgid "Your Gift Cards"
msgstr "Twoje karty podarunkowe"
msgstr ""
#: www/views/includes/confirmBackupPopup.html:6
msgid "Your bitcoin wallet is backed up!"
@ -3717,7 +3572,7 @@ msgstr "[Balans ukryty]"
#: www/views/walletDetails.html:141
#: www/views/walletDetails.html:61
msgid "[Scanning Funds]"
msgstr "[Skanowanie środków]"
msgstr ""
#: src/js/controllers/bitpayCardIntro.js:11
msgid "add your BitPay Visa card(s)"
@ -3741,7 +3596,7 @@ msgstr "Przygotowywanie..."
#: www/views/cashScan.html:57
msgid "recovery tool."
msgstr "narzędzie do odzyskiwania."
msgstr ""
#: src/js/controllers/buyAmazon.js:239
msgid "{{amountStr}} for Amazon.com Gift Card"
@ -3749,7 +3604,7 @@ msgstr "{{amountStr}} dla karty upominkowej Amazon.com"
#: src/js/controllers/buyMercadoLibre.js:237
msgid "{{amountStr}} for Mercado Livre Brazil Gift Card"
msgstr "{{amountStr}} na karcie podarunkowej Mercado Livre Brazil"
msgstr ""
#: www/views/preferencesBwsUrl.html:21
msgid "{{appName}} depends on Bitcore Wallet Service (BWS) for blockchain information, networking and Copayer synchronization. The default configuration points to https://bws.bitpay.com (BitPay's public BWS instance)."
@ -3761,7 +3616,7 @@ msgstr "{{fee}} zostanie potrącone jako prowizja sieci bitcoin."
#: www/views/confirm.html:85
msgid "{{tx.txp[wallet.id].feeRatePerStr}} of the sending amount"
msgstr "{{tx.txp[wallet.id].feeRatePerStr}} wysyłanej kwoty"
msgstr ""
#: www/views/walletDetails.html:218
msgid "{{updatingTxHistoryProgress}} transactions downloaded"
@ -3772,172 +3627,3 @@ msgstr "{{updatingTxHistoryProgress}} transakcje pobrane"
#: www/views/includes/walletInfo.html:18
msgid "{{wallet.m}}-of-{{wallet.n}}"
msgstr "{{wallet.m}}-z-{{wallet.n}}"
#: src/js/services/shapeshiftService.js:8
msgid "Shapeshift"
msgstr "Shapeshift"
#: www/views/includes/community.html:3
msgid "Community"
msgstr "Społeczność"
#: src/js/services/communityService.js:40
msgid "Bitcoin Cash Reddit"
msgstr "Reddit Bitcoin Cash"
#: src/js/services/communityService.js:47
msgid "Bitcoin.com Twitter"
msgstr "Twitter Bitcoin.com"
#: www/views/includes/nextSteps.html:3
msgid "Explore Bitcoin.com"
msgstr "Poznaj Bitcoin.com"
#: src/js/services/bitcoincomService.js:21
msgid "Bitcoin Cash Games"
msgstr "Gry Bitcoin Cash"
#: www/views/includes/community.html:29
msgid "Share the Wallet App"
msgstr "Udostępnij aplikację Portfel"
#: src/js/services/bitcoincomService.js:28
msgid "News"
msgstr "Aktualności"
#: src/js/services/bitcoincomService.js:35
msgid "Mining Pool"
msgstr "Pula kopalni"
#: src/js/services/bitcoincomService.js:42
msgid "Tools"
msgstr "Narzędzia"
#: src/js/services/bitcoincomService.js:49
msgid "Bitcoin Price Charts"
msgstr "Wykresy kursu Bitcoin"
#: src/js/services/bitcoincomService.js:56
msgid "Free Bitcoin Cash"
msgstr "Darmowa Bitcoin Cash"
#: www/views/tab-home.html:30
msgid "Your Bitcoin Wallets are ready!"
msgstr "Twoje portfele Bitcoin są gotowe!"
#: src/js/controllers/amount.js:49
msgid "Address does not contain currency information, please make sure you are sending the correct currency."
msgstr "Adres nie zawiera informacji o walucie; upewnij się, że przesyłasz odpowiednią walutę."
#: www/views/review.html:4
msgid "Review Transaction"
msgstr "Potwierdzenie transakcji"
#: src/js/controllers/review.controller.js:36
msgid "You are sending"
msgstr "Przesyłasz"
#: src/js/controllers/review.controller.js:66
msgid "You are shifting"
msgstr "Przelewasz"
#: www/views/review.html:36
msgid "To:"
msgstr "Do:"
#: www/views/review.html:53
msgid "Add personal note"
msgstr "Dodaj notatkę osobistą"
#: www/views/review.html:87
msgid "Suggested by merchant:"
msgstr "Sugestia handlowca:"
#: src/js/controllers/review.controller.js:37
msgid "Enter text here"
msgstr "Wprowadź tekst tutaj"
#: www/views/review.html:57
msgid "Personal note:"
msgstr "Notatka osobista:"
#: www/views/review.html:69
msgid "Less than 1 cent"
msgstr "Mniej niż 1 cent"
#: src/js/services/incomingData.js:129
msgid "This invoice is no longer accepting payments"
msgstr "Nie można już opłacić tej faktury"
#: www/views/amount.html.js:60
msgid "Send Maximum Amount"
msgstr "Wyślij maksymalną kwotę"
#: src/js/controllers/amount.controller.js:239
msgid "Unknown error."
msgstr "Nieznany błąd."
#: www/views/paperWallet.html:48
msgid "No Bitcoin Cash wallet to transfer funds to found."
msgstr "Nie znaleziono portfela Bitcoin Cash do przekazania środków."
#: www/views/paperWallet.html:54
msgid "No Bitcoin Cash found."
msgstr "Nie znaleziono Bitcoin Cash."
#: www/views/paperWallet.html:60
msgid "Bitcoin Core found:"
msgstr "Znaleziono Bitcoin Core:"
#: www/views/paperWallet.html:98
msgid "No Bitcoin Core wallet to transfer funds to found."
msgstr "Nie znaleziono portfela Bitcoin Core do przekazania środków."
#: www/views/paperWallet.html:104
msgid "No Bitcoin Core found."
msgstr "Nie znaleziono Bitcoin Core."
#: src/js/controllers/tab-scan.js:120
msgid "Scan Failed"
msgstr "Skanowanie nie powiodło się"
#: src/js/controllers/tab-scan.js:121
msgid "Data not recognised."
msgstr "Nie rozpoznano danych."
#: src/js/controllers/tab-scan.js:121
msgid "Unsupported"
msgstr "Nieobsługiwane"
#: src/js/controllers/tab-scan.js:121
msgid "Testnet is not supported."
msgstr "Sieć testowa nie jest obsługiwana."
#: www/views/includes/incomingDataMenu.html:81
msgid "URL"
msgstr "Adres URL"
#: www/views/includes/incomingDataMenu.html:90
msgid "Open in web browser"
msgstr "Otwórz w przeglądarce internetowej"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid address"
msgstr "Nieprawidłowy adres"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is not defined"
msgstr "Kwota nie jest określona"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is below the minimun"
msgstr "Kwota niższa od minimalnej"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is above the limit"
msgstr "Kwota przekracza limit"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid response from Shapeshift"
msgstr "Nieprawidłowa odpowiedź z Shapeshift"

View file

@ -2,16 +2,16 @@ msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Project-Id-Version: bitcoincom-wallet\n"
"Project-Id-Version: copay\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: crowdin.com\n"
"X-Crowdin-Project: bitcoincom-wallet\n"
"X-Crowdin-Project: copay\n"
"X-Crowdin-Language: pt-BR\n"
"X-Crowdin-File: template.pot\n"
"Last-Translator: emilold\n"
"Last-Translator: cmgustavo83\n"
"Language-Team: Portuguese, Brazilian\n"
"Language: pt\n"
"PO-Revision-Date: 2018-09-15 05:56\n"
"PO-Revision-Date: 2017-10-10 08:58-0400\n"
#: www/views/modals/paypro.html:34
msgid "(Trusted)"
@ -77,30 +77,6 @@ msgstr "Conta"
msgid "Account Number"
msgstr "Número de conta"
#: www/views/tab-home.html:61
msgid "Instant transactions with low fees"
msgstr "Transações instantâneas com taxas baixas"
#: www/views/walletSelector.html:49
msgid "Insufficient funds"
msgstr "Fundos insuficientes"
#: www/views/amount.html:42
msgid "Change Currency"
msgstr "Alterar moeda"
#: www/views/amount.html:49
msgid "Available Funds"
msgstr "Fundos disponíveis"
#: www/views/amount.html:59
msgid "Use All Available Funds"
msgstr "Usar todos os fundos disponíveis"
#: www/views/amount.html:99
msgid "Next"
msgstr "Próximo"
#: www/views/preferencesBitpayServices.html:23
msgid "Accounts"
msgstr "Contas"
@ -226,20 +202,6 @@ msgstr "Quase pronto! Vamos rever."
msgid "Alternative Currency"
msgstr "Moeda Alternativa"
#: www/views/tab-settings.html:75
msgid "Price Display"
msgstr "Exibição de preço"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:12
msgid "Fiat"
msgstr "Fiat"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:15
msgid "Cryptocurrency"
msgstr "Criptomoeda"
#: src/js/controllers/buyAmazon.js:98
msgid "Amazon.com is not available at this moment. Please try back later."
msgstr "Amazon.com não está disponível neste momento. Por favor, tente mais tarde."
@ -345,7 +307,7 @@ msgstr "Carteiras BTC"
#: www/views/preferences.html:34
msgid "Backup"
msgstr "Backup de"
msgstr "Backup"
#: www/views/includes/backupNeededPopup.html:7
msgid "Backup Needed"
@ -471,7 +433,6 @@ msgid "Buy &amp; Sell Bitcoin"
msgstr "Comprar &amp; Vender Bitcoin"
#: www/views/tab-send.html:35
#: src/js/services/buyAndSellService.js:26
msgid "Buy Bitcoin"
msgstr "Comprar Bitcoin"
@ -520,8 +481,8 @@ msgid "Cannot Create Wallet"
msgstr "Não é possível criar a carteira"
#: src/js/services/profileService.js:442
msgid "Cannot join the same wallet more than once"
msgstr "Não pode juntar-se à mesma carteira mais que uma vez"
msgid "Cannot join the same wallet more that once"
msgstr "Não pode juntar-se a mesma carteira mais que uma vez"
#: www/views/includes/bitpayCardsCard.html:2
msgid "Cards"
@ -654,14 +615,10 @@ msgstr "A conectar ao Glidera..."
msgid "Connection reset by peer"
msgstr "Ligação redefinida pelo mesmo nível"
#: www/views/tab-send.html:85
#: www/views/tab-send.html:45
msgid "Contacts"
msgstr "Contactos"
#: www/views/tab-send.html:86
msgid "Saved frequently used addresses"
msgstr "Salvou os endereços usados com frequência"
#: www/views/onboarding/notifications.html:9
msgid "Continue"
msgstr "Continuar"
@ -696,7 +653,6 @@ msgstr "Copayer {{$index}}"
#: src/js/controllers/copayers.js:79
#: src/js/controllers/export.js:193
#: src/js/controllers/confirm.js:41
#: www/views/includes/copyToClipboard.html:4
msgid "Copied to clipboard"
msgstr "Copiado para a área de transferência"
@ -863,7 +819,7 @@ msgstr "Criar carteira partilhada"
#: www/views/onboarding/tour.html:51
#: www/views/tab-home.html:75
#: www/views/tab-send.html:75
#: www/views/tab-send.html:36
msgid "Create bitcoin wallet"
msgstr "Criar carteira bitcoin"
@ -980,7 +936,7 @@ msgstr "Não vê o seu idioma no Crowdin? Contacte o Dono no Crowdin! Nós adora
#: www/views/tab-export-file.html:59
#: www/views/tab-home.html:22
msgid "Download"
msgstr "Baixar"
msgstr "Download"
#: www/views/cashScan.html:37
msgid "Duplicate for BCH"
@ -1031,10 +987,6 @@ msgstr "Ativar notificações por email"
msgid "Enable push notifications"
msgstr "Ativar notificações push"
#: www/views/preferencesNotifications.html:33
msgid "Enable sound"
msgstr "Ativar som"
#: www/views/tab-scan.html:18
msgid "Enable the camera to get started."
msgstr "Ative a câmera para começar."
@ -1316,7 +1268,6 @@ msgstr "Para fins de auditoria"
#: www/views/modals/txp-details.html:74
#: www/views/topup.html:34
#: www/views/tx-details.html:52
#: www/views/review.html:22
msgid "From"
msgstr "De"
@ -1377,6 +1328,10 @@ msgid "Get news and updates from BitPay"
msgstr "Receba notícias e atualizações da BitPay"
#: www/views/onboarding/welcome.html:8
msgctxt "button"
msgid "Get started"
msgstr "Começar"
#: www/views/bitpayCard.html:49
msgid "Get started"
msgstr "Começar"
@ -1623,7 +1578,7 @@ msgstr "Endereço de rede incorreto"
#: src/js/controllers/confirm.js:306
#: src/js/services/bwcError.js:44
msgid "Insufficient confirmed funds"
msgstr "Insuficiência de fundos confirmada"
msgstr "Fundos insuficientes"
#: src/js/controllers/topup.js:165
#: src/js/controllers/topup.js:177
@ -2041,7 +1996,7 @@ msgstr "Agora é a hora perfeita para olhar em volta. Próximo de janelas? Câme
#: src/js/services/popupService.js:72
#: www/views/modals/chooseFeeLevel.html:6
msgid "OK"
msgstr "Okey"
msgstr "OK"
#: www/views/modals/tx-status.html:12
#: www/views/modals/tx-status.html:24
@ -2060,7 +2015,7 @@ msgstr "Oh não!"
#: src/js/controllers/buyMercadoLibre.js:306
msgid "Ok"
msgstr "Okey"
msgstr "Ok"
#: www/views/tab-home.html:39
msgid "On this screen you can see all your wallets, accounts, and assets."
@ -2090,7 +2045,7 @@ msgstr "Abrir Projeto no GitHub"
#: src/js/controllers/bitpayCard.js:123
#: src/js/controllers/tx-details.js:192
msgid "Open Explorer"
msgstr "Abrir o Explorer"
msgstr "Abrir Insight"
#: www/views/tab-scan.html:22
msgid "Open Settings"
@ -2200,10 +2155,6 @@ msgstr "Pagamento Rejeitado"
msgid "Payment Sent"
msgstr "Pagamento Enviado"
#: www/views/includes/slideToAcceptSuccess.html:12
msgid "Share this transaction"
msgstr "Compartilhar esta transação"
#: www/views/modals/txp-details.html:32
msgid "Payment accepted, but not yet broadcasted"
msgstr "Pagamento aceito, mas ainda não publicado"
@ -2221,8 +2172,8 @@ msgid "Payment details"
msgstr "Detalhes do pagamento"
#: www/views/modals/paypro.html:6
msgid "Payment Request"
msgstr "Solicitação de pagamento"
msgid "Payment request"
msgstr "Pedido de pagamento"
#: www/views/mercadoLibreCards.html:22
#: www/views/modals/mercadolibre-card-details.html:39
@ -2574,14 +2525,6 @@ msgstr "Procurar transações"
msgid "Search or enter bitcoin address"
msgstr "Procure ou digite o endereço bitcoin"
#: src/js/controllers/tab-send.js:28
msgid "Clipboard"
msgstr "Área de transferência"
#: src/js/controllers/tab-send.js:29
msgid "Your Clipboard is empty"
msgstr "A sua área de transferência está vazia"
#: www/views/modals/search.html:16
msgid "Search transactions"
msgstr "Procurar transações"
@ -2640,68 +2583,9 @@ msgid "Send by email"
msgstr "Enviar por E-mail"
#: src/js/controllers/confirm.js:177
#: src/js/controllers/tab-send.js:94
msgid "Send from"
msgstr "Enviar De"
#: src/js/controllers/tab-send.js:77
msgid "Send to"
msgstr "Enviar para"
#: www/views/tab-send.html:20
msgid "Paste Clipboard"
msgstr "Colar na área de trabalho"
#: www/views/tab-send.html:21
msgid "Paste Address"
msgstr "Colar endereço"
#: www/views/tab-send.html:27
msgid "Transfer between wallets"
msgstr "Transferência entre carteiras"
#: www/views/tab-send.html:35
msgid "Scan QR Code"
msgstr "Digitalizar o código QR"
#: www/views/tab-send.html:46
msgid "Send Bitcoin faster!"
msgstr "Envie Bitcoin mais rápido!"
#: www/views/tab-send.html:50
msgid "Save frequently used addresses and send them Bitcoin in just one tap"
msgstr "Salvar endereços usados com frequência e enviar Bitcoin com apenas um toque"
#: www/views/tab-send.html:55
msgid "Add your first contact"
msgstr "Adicionar o seu primeiro contato"
#: www/views/tab-send.html:65
msgid "Your Bitcoin wallet is empty"
msgstr "Sua carteira de Bitcoin está vazia"
#: www/views/tab-send.html:69
msgid "To get started, buy Bitcoin Cash (BCH) or Bitcoin Core (BTC), or share your address."
msgstr "Para começar, compre Bitcoin Cash (BCH) ou Bitcoin Core (BTC) ou compartilhe o seu endereço."
#: www/views/tab-send.html:70
msgid "You can receive bitcoin from any wallet or service."
msgstr "Você pode receber bitcoin de qualquer carteira ou serviço."
#: www/views/tab-send.html:72
#: www/views/shapeshift.html:23
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "Para começar, você precisa criar uma carteira de bitcoins e obter alguns bitcoins."
#: www/views/tab-send.html:74
msgid "Buy Bitcoin now"
msgstr "Comprar Bitcoin agora"
#: www/views/tab-send.html:76
msgid "Show my address"
msgstr "Mostrar meu endereço"
#: www/views/includes/itemSelector.html:8
msgid "Send max amount"
msgstr "Quantidade Máxima de envio"
@ -2925,13 +2809,8 @@ msgid "Sweep"
msgstr "Limpar"
#: www/views/includes/incomingDataMenu.html:89
msgctxt "List item"
msgid "Sweep paper wallet"
msgstr "Varrer a carteira de papel"
#: www/views/paperWallet.html:3
msgctxt "Page title"
msgid "Sweep Paper Wallet"
msgid "Sweep paper wallet"
msgstr "Varrer a carteira de papel"
#: src/js/services/onGoingProcess.js:33
@ -3100,14 +2979,6 @@ msgstr "Este aplicativo armazena seu bitcoin com segurança de ponta."
msgid "This bitcoin payment request has expired."
msgstr "Este bitcoin pagamento pedido expirou."
#: www/views/review.html:55
msgid "Payment expires:"
msgstr "Pagamento expira em:"
#: www/views/review.html:56
msgid "Payment request has expired"
msgstr "Pedido de pagamento expirou"
#: www/views/join.html:133
#: www/views/tab-create-personal.html:103
#: www/views/tab-create-shared.html:132
@ -3149,6 +3020,10 @@ msgstr "Para"
msgid "To get started, buy bitcoin or share your address. You can receive bitcoin from any wallet or service."
msgstr "Para começar, compre bitcoins ou compartilhe seu endereço. Você pode receber bitcoins de qualquer carteira ou serviço."
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "Para começar, você precisa criar uma carteira de bitcoins e obter alguns bitcoins."
#: src/js/services/bitpayAccountService.js:73
msgid "To {{reason}} you must first add your BitPay account - {{email}}"
msgstr "Para {{reason}} você deve primeiro adicionar sua conta BitPay - {{email}}"
@ -3161,26 +3036,6 @@ msgstr "Recarga em andamento..."
msgid "Top up {{amountStr}} to debit card ({{cardLastNumber}})"
msgstr "Recarga de {{amountStr}} para cartão de débito ({{cardLastNumber}})"
#: www/views/shapeshift.html:30
msgid "Start ShapeShift"
msgstr "Iniciar ShapeShift"
#: www/views/shapeshift.html:30
msgid "Exchange your BTC to BCH in minutes."
msgstr "Troque seu BTC para BCH em minutos."
#: www/views/shapeshift.html:30
msgid "To start the process you need to add funds to your wallet."
msgstr "Para iniciar o processo, você precisa adicionar fundos à sua carteira."
#: www/views/shapeshift.html:30
msgid "The process is fast and you will receive the exchanged amount in your wallet."
msgstr "O processo é rápido e você receberá a quantia convertida na sua carteira."
#: www/views/shapeshift.html:34
msgid "This service is provided by the third-party ShapeShift, who will charge a small fee for the service. The fee will be shown before you start the transaction."
msgstr "Este serviço é fornecido pela terceira ShapeShift, que cobrará uma pequena taxa pelo serviço. A taxa será exibida antes de você iniciar a transação."
#: www/views/buyAmazon.html:61
#: www/views/buyMercadoLibre.html:60
#: www/views/modals/wallet-balance.html:23
@ -3267,7 +3122,7 @@ msgstr "Digite a frase de recuperação (normalmente 12 palavras)"
#: src/js/controllers/backup.js:75
msgid "Uh oh..."
msgstr "Ah Ah..."
msgstr "Uh oh..."
#: www/views/tx-details.html:100
msgid "Unconfirmed"
@ -3337,7 +3192,7 @@ msgstr "Ver os Termos de Serviço"
#: src/js/controllers/bitpayCard.js:122
#: src/js/controllers/tx-details.js:191
msgid "View Transaction on Explorer.Bitcoin.com"
msgstr "Ver transação no Explorer.Bitcoin.com"
msgstr "Exibir Transação no Insight"
#: src/js/controllers/tab-home.js:148
msgid "View Update"
@ -3772,172 +3627,3 @@ msgstr "Transações de {{updatingTxHistoryProgress}} transferidas"
#: www/views/includes/walletInfo.html:18
msgid "{{wallet.m}}-of-{{wallet.n}}"
msgstr "{{wallet.m}}-de-{{wallet.n}}"
#: src/js/services/shapeshiftService.js:8
msgid "Shapeshift"
msgstr "Shapeshift"
#: www/views/includes/community.html:3
msgid "Community"
msgstr "Comunidade"
#: src/js/services/communityService.js:40
msgid "Bitcoin Cash Reddit"
msgstr "Bitcoin Cash Reddit"
#: src/js/services/communityService.js:47
msgid "Bitcoin.com Twitter"
msgstr "Twitter Bitcoin.com"
#: www/views/includes/nextSteps.html:3
msgid "Explore Bitcoin.com"
msgstr "Explore Bitcoin.com"
#: src/js/services/bitcoincomService.js:21
msgid "Bitcoin Cash Games"
msgstr "Jogos Bitcoin Cash"
#: www/views/includes/community.html:29
msgid "Share the Wallet App"
msgstr "Compartilhar o app de carteira"
#: src/js/services/bitcoincomService.js:28
msgid "News"
msgstr "Notícias"
#: src/js/services/bitcoincomService.js:35
msgid "Mining Pool"
msgstr "Pool de mineração"
#: src/js/services/bitcoincomService.js:42
msgid "Tools"
msgstr "Ferramentas"
#: src/js/services/bitcoincomService.js:49
msgid "Bitcoin Price Charts"
msgstr "Gráficos de preço do Bitcoin"
#: src/js/services/bitcoincomService.js:56
msgid "Free Bitcoin Cash"
msgstr "Bitcoin Cash grátis"
#: www/views/tab-home.html:30
msgid "Your Bitcoin Wallets are ready!"
msgstr "As suas carteiras de Bitcoin estão prontas!"
#: src/js/controllers/amount.js:49
msgid "Address does not contain currency information, please make sure you are sending the correct currency."
msgstr "O endereço não contém informações de moeda. Certifique-se de que está enviando a moeda correta."
#: www/views/review.html:4
msgid "Review Transaction"
msgstr "Revisar transação"
#: src/js/controllers/review.controller.js:36
msgid "You are sending"
msgstr "Você está enviando"
#: src/js/controllers/review.controller.js:66
msgid "You are shifting"
msgstr "Você está trocando"
#: www/views/review.html:36
msgid "To:"
msgstr "Para:"
#: www/views/review.html:53
msgid "Add personal note"
msgstr "Adicionar nota pessoal"
#: www/views/review.html:87
msgid "Suggested by merchant:"
msgstr "Sugerido pelo comerciante:"
#: src/js/controllers/review.controller.js:37
msgid "Enter text here"
msgstr "Insira o texto aqui"
#: www/views/review.html:57
msgid "Personal note:"
msgstr "Nota pessoal:"
#: www/views/review.html:69
msgid "Less than 1 cent"
msgstr "Menos de 1 centavo"
#: src/js/services/incomingData.js:129
msgid "This invoice is no longer accepting payments"
msgstr "Essa fatura não aceita mais pagamentos"
#: www/views/amount.html.js:60
msgid "Send Maximum Amount"
msgstr "Enviar montante máximo"
#: src/js/controllers/amount.controller.js:239
msgid "Unknown error."
msgstr "Erro desconhecido."
#: www/views/paperWallet.html:48
msgid "No Bitcoin Cash wallet to transfer funds to found."
msgstr "Nenhuma carteira de Bitcoin Cash para transferir fundos encontrada."
#: www/views/paperWallet.html:54
msgid "No Bitcoin Cash found."
msgstr "Bitcoin Cash não encontrado."
#: www/views/paperWallet.html:60
msgid "Bitcoin Core found:"
msgstr "Bitcoin Core encontrado:"
#: www/views/paperWallet.html:98
msgid "No Bitcoin Core wallet to transfer funds to found."
msgstr "Nenhuma carteira de Bitcoin Core para transferir fundos encontrada."
#: www/views/paperWallet.html:104
msgid "No Bitcoin Core found."
msgstr "Nenhum Bitcoin Core encontrado."
#: src/js/controllers/tab-scan.js:120
msgid "Scan Failed"
msgstr "Falha de verificação"
#: src/js/controllers/tab-scan.js:121
msgid "Data not recognised."
msgstr "Dados não reconhecidos."
#: src/js/controllers/tab-scan.js:121
msgid "Unsupported"
msgstr "Não suportado"
#: src/js/controllers/tab-scan.js:121
msgid "Testnet is not supported."
msgstr "Testnet não suportado."
#: www/views/includes/incomingDataMenu.html:81
msgid "URL"
msgstr "URL"
#: www/views/includes/incomingDataMenu.html:90
msgid "Open in web browser"
msgstr "Abrir no navegador da Web"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid address"
msgstr "Endereço inválido"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is not defined"
msgstr "Montante não definido"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is below the minimun"
msgstr "Montante abaixo do mínimo"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is above the limit"
msgstr "Montante acima do limite"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid response from Shapeshift"
msgstr "Resposta inválida do Shapeshift"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,16 +2,16 @@ msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Project-Id-Version: bitcoincom-wallet\n"
"Project-Id-Version: copay\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: crowdin.com\n"
"X-Crowdin-Project: bitcoincom-wallet\n"
"X-Crowdin-Project: copay\n"
"X-Crowdin-Language: zh-CN\n"
"X-Crowdin-File: template.pot\n"
"Last-Translator: emilold\n"
"Last-Translator: cmgustavo83\n"
"Language-Team: Chinese Simplified\n"
"Language: zh\n"
"PO-Revision-Date: 2018-09-15 05:56\n"
"PO-Revision-Date: 2017-10-09 10:33-0400\n"
#: www/views/modals/paypro.html:34
msgid "(Trusted)"
@ -41,7 +41,7 @@ msgstr "5 星评级帮助我们进入更多的人手, {{appName}} 和更多的
#: www/views/mercadoLibre.html:18
#: www/views/mercadoLibre.html:40
msgid "<b>Only</b> redeemable on Mercado Livre (Brazil)"
msgstr "<b>只</b>可以在 Mercado Livre巴西兑换"
msgstr "<b>Only</b>可在悔尔卡多里弗(巴西) 兌換"
#: src/js/controllers/feedback/send.js:27
#: www/views/feedback/complete.html:21
@ -77,30 +77,6 @@ msgstr "帐户"
msgid "Account Number"
msgstr "帐号"
#: www/views/tab-home.html:61
msgid "Instant transactions with low fees"
msgstr "以较低费用进行即时交易"
#: www/views/walletSelector.html:49
msgid "Insufficient funds"
msgstr "资金不足"
#: www/views/amount.html:42
msgid "Change Currency"
msgstr "更改货币"
#: www/views/amount.html:49
msgid "Available Funds"
msgstr "可用资金"
#: www/views/amount.html:59
msgid "Use All Available Funds"
msgstr "使用所有可用资金"
#: www/views/amount.html:99
msgid "Next"
msgstr "下一步"
#: www/views/preferencesBitpayServices.html:23
msgid "Accounts"
msgstr "帐户"
@ -226,20 +202,6 @@ msgstr "差不多完成了 !让我们回顾一下。"
msgid "Alternative Currency"
msgstr "替代货币"
#: www/views/tab-settings.html:75
msgid "Price Display"
msgstr "价格显示"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:12
msgid "Fiat"
msgstr "法币"
#: src/js/controllers/tab-settings.js:19
#: www/views/preferencesPriceDisplay.html:15
msgid "Cryptocurrency"
msgstr "加密货币"
#: src/js/controllers/buyAmazon.js:98
msgid "Amazon.com is not available at this moment. Please try back later."
msgstr "亚马逊服务器暂时无法访问,请稍候再试。"
@ -260,7 +222,7 @@ msgstr "量太大"
#: www/views/includes/walletHistory.html:31
msgid "Amount too low to spend"
msgstr "数量太少,无法支付"
msgstr "數額低於可消費額"
#: src/js/controllers/tab-home.js:147
msgid "An update to this app is available. For your security, please update to the latest version."
@ -272,7 +234,7 @@ msgstr "任何人只要持有你的备份短语,就可以访问或者花掉你
#: www/views/addresses.html:94
msgid "Approximate Bitcoin network fee to transfer wallet's balance (with normal priority)"
msgstr "转移钱包余额大约需要的比特币网络费用(正常优先级)"
msgstr "近似的比特币网络费用将钱包的余额转移 (与正常优先级)"
#: www/views/backupWarning.html:10
msgid "Are you being watched?"
@ -280,7 +242,7 @@ msgstr "你正在被监视吗?"
#: src/js/controllers/preferencesExternal.js:15
msgid "Are you being watched? Anyone with your recovery phrase can access or spend your bitcoin."
msgstr "请确认目前没有人在监视你的屏幕!因为只要有人知道了你的恢复短语,他就拥有你的比特币完全访问权限,甚至可以直接用于消费!"
msgstr "有旁观者么?只要有人知道了你的恢复短语,他就能访问你的比特币,或者花费它。"
#: src/js/controllers/copayers.js:56
msgid "Are you sure you want to cancel and delete this wallet?"
@ -341,7 +303,7 @@ msgstr "BIP32 路径的地址衍生"
#: www/views/cashScan.html:25
msgid "BTC wallets"
msgstr "比特币钱包"
msgstr "比特幣錢包"
#: www/views/preferences.html:34
msgid "Backup"
@ -353,7 +315,7 @@ msgstr "需要备份"
#: src/js/controllers/lockSetup.js:87
msgid "Backup all livenet wallets before using this function"
msgstr "请在使用此功能之前备份你所有的 livenet 钱包"
msgstr "请在使用此功能之前备份你的钱包。"
#: src/js/controllers/cashScan.js:64
#: www/views/includes/walletListSettings.html:12
@ -397,17 +359,17 @@ msgstr "比特币地址"
#: www/views/cashScan.html:4
msgid "Bitcoin Cash (BCH) Balances"
msgstr "Bitcoin Cash (BCH) 余额"
msgstr "小比特幣(BCH) 結餘"
#: www/views/preferencesCash.html:3
#: www/views/tab-settings.html:47
msgid "Bitcoin Cash Support"
msgstr "Bitcoin Cash 支持"
msgstr "小比特幣支援"
#: www/views/tab-home.html:98
#: www/views/tab-settings.html:115
msgid "Bitcoin Cash Wallets"
msgstr "比特币现金钱包"
msgstr ""
#: www/views/modals/chooseFeeLevel.html:4
#: www/views/preferencesFee.html:4
@ -418,11 +380,11 @@ msgstr "比特币网络手续费策略"
#: www/views/tab-home.html:83
#: www/views/tab-settings.html:107
msgid "Bitcoin Core Wallets"
msgstr "Bitcoin Core 钱包"
msgstr ""
#: src/js/services/incomingData.js:151
msgid "Bitcoin cash Payment"
msgstr "比特币现金支付"
msgstr "小比特幣支付"
#: www/views/onboarding/tour.html:31
msgid "Bitcoin is a currency."
@ -471,7 +433,6 @@ msgid "Buy &amp; Sell Bitcoin"
msgstr "购买或出售比特币"
#: www/views/tab-send.html:35
#: src/js/services/buyAndSellService.js:26
msgid "Buy Bitcoin"
msgstr "购买比特币"
@ -520,7 +481,7 @@ msgid "Cannot Create Wallet"
msgstr "不能创建钱包"
#: src/js/services/profileService.js:442
msgid "Cannot join the same wallet more than once"
msgid "Cannot join the same wallet more that once"
msgstr "无法重复加入同一个钱包"
#: www/views/includes/bitpayCardsCard.html:2
@ -558,16 +519,16 @@ msgstr "清空缓存"
#: src/js/controllers/confirm.js:373
#: src/js/controllers/modals/txpDetails.js:49
msgid "Click to accept"
msgstr "点击这里接受"
msgstr "在此點擊以接受"
#: src/js/controllers/confirm.js:367
msgid "Click to pay"
msgstr "点击这里支付"
msgstr "在此點擊以支付"
#: src/js/controllers/confirm.js:379
#: src/js/controllers/modals/txpDetails.js:42
msgid "Click to send"
msgstr "点击这里发送"
msgstr "點擊以寄出"
#: www/views/customAmount.html:4
#: www/views/modals/mercadolibre-card-details.html:3
@ -582,7 +543,7 @@ msgstr "关闭"
#: www/views/includes/cash.html:2
#: www/views/preferencesInformation.html:17
msgid "Coin"
msgstr "种"
msgstr "電子幣种"
#: www/views/preferences.html:22
msgid "Color"
@ -654,14 +615,10 @@ msgstr "正在连接 Glidera..."
msgid "Connection reset by peer"
msgstr "连接被对方重置"
#: www/views/tab-send.html:85
#: www/views/tab-send.html:45
msgid "Contacts"
msgstr "联系人"
#: www/views/tab-send.html:86
msgid "Saved frequently used addresses"
msgstr "保存的常用地址"
#: www/views/onboarding/notifications.html:9
msgid "Continue"
msgstr "继续"
@ -672,7 +629,7 @@ msgstr "参与翻译"
#: src/js/controllers/confirm.js:130
msgid "Copay only supports Bitcoin Cash using new version numbers addresses"
msgstr "Copay只支持新版本的比特币现金地址"
msgstr "本公司Copay只支持用新版本數字地址的小比特幣"
#: src/js/services/bwcError.js:62
msgid "Copayer already in this wallet"
@ -696,7 +653,6 @@ msgstr "Copayer {{$index}}"
#: src/js/controllers/copayers.js:79
#: src/js/controllers/export.js:193
#: src/js/controllers/confirm.js:41
#: www/views/includes/copyToClipboard.html:4
msgid "Copied to clipboard"
msgstr "已复制到剪贴板"
@ -753,7 +709,7 @@ msgstr "不能创建发票"
#: src/js/controllers/buyMercadoLibre.js:164
#: src/js/controllers/topup.js:142
msgid "Could not create transaction"
msgstr "无法创建交易"
msgstr "无法创建交易记录"
#: src/js/services/profileService.js:350
msgid "Could not create using the specified extended private key"
@ -777,7 +733,7 @@ msgstr "无法删除支付提议"
#: src/js/controllers/cashScan.js:117
msgid "Could not duplicate"
msgstr "法复制"
msgstr "法复制"
#: src/js/services/feeService.js:73
msgid "Could not get dynamic fee"
@ -863,7 +819,7 @@ msgstr "创建自己的免费钱包"
#: www/views/onboarding/tour.html:51
#: www/views/tab-home.html:75
#: www/views/tab-send.html:75
#: www/views/tab-send.html:36
msgid "Create bitcoin wallet"
msgstr "创建比特币的钱包"
@ -962,7 +918,7 @@ msgstr "详情"
#: src/js/controllers/tab-settings.js:65
#: www/views/tab-settings.html:50
msgid "Disabled"
msgstr "禁用"
msgstr "已经禁用"
#: www/views/includes/backupNeededPopup.html:10
#: www/views/onboarding/backupRequest.html:12
@ -984,11 +940,11 @@ msgstr "下载"
#: www/views/cashScan.html:37
msgid "Duplicate for BCH"
msgstr "复制 BCH"
msgstr "為小比特幣复制"
#: src/js/services/onGoingProcess.js:49
msgid "Duplicating wallet..."
msgstr "正在复制钱包……"
msgstr "复制錢包進行中"
#: www/views/addresses.html:19
msgid "Each bitcoin wallet can generate billions of addresses from your 12-word backup. A new address is automatically generated and shown each time you receive a payment."
@ -1017,7 +973,7 @@ msgstr "已达到空地址限制。无法生成新的地址。"
#: www/views/preferencesCash.html:17
msgid "Enable Bitcoin Cash wallet creation and operation within the App."
msgstr "在应用内启用 Bitcoin Cash 创建和操作。"
msgstr "能在本應用程序中創建和啟用小比特幣錢包"
#: www/views/tab-scan.html:19
msgid "Enable camera access in your device settings to get started."
@ -1031,17 +987,13 @@ msgstr "启用电子邮件通知"
msgid "Enable push notifications"
msgstr "启用推式通知"
#: www/views/preferencesNotifications.html:33
msgid "Enable sound"
msgstr "启用声音"
#: www/views/tab-scan.html:18
msgid "Enable the camera to get started."
msgstr "使该摄像机开始。"
#: www/views/tab-settings.html:49
msgid "Enabled"
msgstr "已启用"
msgstr "巳啟用"
#: src/js/services/walletService.js:1047
#: src/js/services/walletService.js:1062
@ -1316,7 +1268,6 @@ msgstr "供审计目的"
#: www/views/modals/txp-details.html:74
#: www/views/topup.html:34
#: www/views/tx-details.html:52
#: www/views/review.html:22
msgid "From"
msgstr "来自"
@ -1342,7 +1293,7 @@ msgstr "找到资金"
#: www/views/topup.html:49
msgid "Funds to be added"
msgstr "充值金额"
msgstr "要添加的资金"
#: www/views/paperWallet.html:51
msgid "Funds transferred"
@ -1350,7 +1301,7 @@ msgstr "资金转移"
#: www/views/topup.html:103
msgid "Funds were added to debit card"
msgstr "提现到借记卡成功"
msgstr "資金已添加到借寄卡"
#: www/views/paperWallet.html:22
msgid "Funds will be transferred to"
@ -1377,6 +1328,10 @@ msgid "Get news and updates from BitPay"
msgstr "从 BitPay 获取新闻和更新"
#: www/views/onboarding/welcome.html:8
msgctxt "button"
msgid "Get started"
msgstr "入门"
#: www/views/bitpayCard.html:49
msgid "Get started"
msgstr "马上体验"
@ -1392,7 +1347,7 @@ msgstr "正在获取收费水平..."
#: www/views/buyAmazon.html:43
#: www/views/buyMercadoLibre.html:42
msgid "Gift Card"
msgstr "礼品卡"
msgstr ""
#: www/views/modals/mercadolibre-card-details.html:30
#: www/views/modals/mercadolibre-card-details.html:35
@ -1405,7 +1360,7 @@ msgstr "礼品卡过期"
#: www/views/buyAmazon.html:111
msgid "Gift card generated and ready to use."
msgstr "礼品卡已生成,可以使用了。"
msgstr "礼品卡生成并准备使用。"
#: src/js/controllers/bitpayCard.js:114
#: src/js/controllers/bitpayCard.js:124
@ -1420,7 +1375,7 @@ msgstr "礼品卡已生成,可以使用了。"
#: src/js/controllers/tx-details.js:193
#: src/js/controllers/tx-details.js:56
msgid "Go Back"
msgstr "返回\t#"
msgstr "返回 #"
#: src/js/controllers/confirm.js:131
#: src/js/controllers/onboarding/backupRequest.js:20
@ -1451,7 +1406,7 @@ msgstr "硬件钱包"
#: src/js/controllers/create.js:180
#: src/js/controllers/join.js:145
msgid "Hardware wallets are not yet supported with Bitcoin Cash"
msgstr "比特币现金钱包暂时不支持硬件钱包"
msgstr "硬體錢包不支持小比特幣"
#: www/views/tab-settings.html:20
msgid "Help & Support"
@ -1460,7 +1415,7 @@ msgstr "帮助与支持"
#: src/js/controllers/bitpayCard.js:112
#: src/js/controllers/tab-settings.js:51
msgid "Help and support information is available at the website."
msgstr "已在网站上提供帮助和支持"
msgstr "此網站提供幫助及支援資訊"
#: www/views/addresses.html:25
msgid "Hide"
@ -1543,7 +1498,7 @@ msgstr "我已经把它写下来"
#: www/views/preferences.html:45
msgid "If enabled, all sensitive information (private key and recovery phrase) and actions (spending and exporting) associated with this wallet will be protected."
msgstr "如果启用,与此钱包相关的所有敏感信息(私钥、回复短语)和操作(消费、导出)都将受到保护。"
msgstr "如果启用,将保护所有的敏感信息(私人密钥和恢复短语) 和与这个钱包关联的操作 (支出和出口)."
#: www/views/advancedSettings.html:23
msgid "If enabled, the Recent Transactions card - a list of transactions occuring across all wallets - will appear in the Home tab."
@ -1563,7 +1518,7 @@ msgstr "如果你有额外的反馈,请让我们知道通过点击设置选项
#: www/views/includes/screenshotWarningModal.html:8
msgid "If you take a screenshot, your backup may be viewed by other apps. You can make a safe backup with physical paper and a pen."
msgstr "如果您截一张屏幕截图,您的备份可能会被其他应用程序浏览。您可以用实体纸和笔来安全备份。"
msgstr "如果你拿一张截图,您的备份可能会被其他应用程序。您可以安全备份与物理纸和一支钢笔。"
#: www/views/tab-import-hardware.html:42
#: www/views/tab-import-phrase.html:80
@ -1593,7 +1548,7 @@ msgstr "为了验证您的钱包的备份,请键入您的密码。"
#: www/views/mercadoLibreCards.html:24
#: www/views/modals/mercadolibre-card-details.html:29
msgid "Inactive"
msgstr "禁用"
msgstr "处于非活动状态"
#: www/views/includes/walletItem.html:9
#: www/views/includes/walletList.html:6
@ -1623,7 +1578,7 @@ msgstr "网络地址不正确"
#: src/js/controllers/confirm.js:306
#: src/js/services/bwcError.js:44
msgid "Insufficient confirmed funds"
msgstr "确认的资金不足"
msgstr "资金不足"
#: src/js/controllers/topup.js:165
#: src/js/controllers/topup.js:177
@ -1633,7 +1588,7 @@ msgstr "费用的资金不足"
#: www/views/tab-settings.html:123
msgid "Integrations"
msgstr "积分"
msgstr ""
#: www/views/includes/walletHistory.html:49
msgid "Invalid"
@ -1733,7 +1688,7 @@ msgstr "上个月"
#: www/views/preferencesCash.html:18
#: www/views/tx-details.html:94
msgid "Learn more"
msgstr "了解更多"
msgstr "更多資訊"
#: www/views/backup.html:43
msgid "Let's verify your backup phrase."
@ -1754,7 +1709,7 @@ msgstr "锁定应用"
#: src/js/controllers/lockSetup.js:23
msgid "Lock by Fingerprint"
msgstr "通过指纹锁定"
msgstr "通过指纹挂起应用。"
#: src/js/controllers/lockSetup.js:14
msgid "Lock by PIN"
@ -1818,7 +1773,7 @@ msgstr "梅尔卡多里弗巴西礼品卡"
#: src/js/controllers/buyMercadoLibre.js:98
msgid "Mercadolibre Gift Card Service is not available at this moment. Please try back later."
msgstr "Mercadolibre 礼品卡服务暂时不可用,请稍后再试。"
msgstr "馬卡杜勒比禮品卡服務現時未能使用,請稍後再試"
#: www/views/modals/txp-details.html:131
msgid "Merchant Message"
@ -1828,7 +1783,7 @@ msgstr "商人的消息"
#: www/views/buyMercadoLibre.html:54
#: www/views/topup.html:63
msgid "Miner Fee"
msgstr "矿工费用"
msgstr "礦工費用"
#: src/js/services/bwcError.js:134
msgid "Missing parameter"
@ -1871,7 +1826,7 @@ msgstr "名称"
#: www/views/buyMercadoLibre.html:48
#: www/views/topup.html:56
msgid "Network Cost"
msgstr "网络手续费"
msgstr "網路支援成本"
#: src/js/services/bwcError.js:47
msgid "Network error"
@ -1900,7 +1855,7 @@ msgstr "没钱包"
#: src/js/controllers/buyAmazon.js:115
#: src/js/controllers/buyMercadoLibre.js:115
msgid "No access key defined"
msgstr "授权密钥未定义"
msgstr "没有定义的访问键"
#: www/views/onboarding/backupRequest.html:5
msgid "No backup, no bitcoin."
@ -2048,7 +2003,7 @@ msgstr "好的"
#: www/views/modals/tx-status.html:36
#: www/views/modals/tx-status.html:46
msgid "OKAY"
msgstr "确定"
msgstr "OKAY"
#: www/views/modals/terms.html:15
msgid "Official English Disclaimer"
@ -2090,7 +2045,7 @@ msgstr "打开 GitHub 项目"
#: src/js/controllers/bitpayCard.js:123
#: src/js/controllers/tx-details.js:192
msgid "Open Explorer"
msgstr "打开浏览器"
msgstr "开放的洞察力"
#: www/views/tab-scan.html:22
msgid "Open Settings"
@ -2106,7 +2061,7 @@ msgstr "打开网站"
#: src/js/controllers/preferencesCash.js:32
msgid "Open bitcoincash.org?"
msgstr "打开 bitcoincash.org"
msgstr "打開小比特幣網址bitcoincash.org?"
#: src/js/controllers/cashScan.js:18
msgid "Open the recovery tool."
@ -2200,10 +2155,6 @@ msgstr "支付被拒绝"
msgid "Payment Sent"
msgstr "支付已发送"
#: www/views/includes/slideToAcceptSuccess.html:12
msgid "Share this transaction"
msgstr "分享此交易"
#: www/views/modals/txp-details.html:32
msgid "Payment accepted, but not yet broadcasted"
msgstr "支付已被接受,但尚未广播"
@ -2221,8 +2172,8 @@ msgid "Payment details"
msgstr "支付明细"
#: www/views/modals/paypro.html:6
msgid "Payment Request"
msgstr "付请求"
msgid "Payment request"
msgstr "付请求"
#: www/views/mercadoLibreCards.html:22
#: www/views/modals/mercadolibre-card-details.html:39
@ -2552,7 +2503,7 @@ msgstr "请扫描你的指纹"
#: www/views/preferencesCash.html:23
msgid "Scan your wallets for Bitcoin Cash"
msgstr "扫描您的 Bitcoin Cash 钱包"
msgstr "掃描你的錢包以存取小比特幣"
#: src/js/services/onGoingProcess.js:30
msgid "Scanning Wallet funds..."
@ -2574,14 +2525,6 @@ msgstr "搜索交易"
msgid "Search or enter bitcoin address"
msgstr "搜索或输入比特币地址"
#: src/js/controllers/tab-send.js:28
msgid "Clipboard"
msgstr "剪贴板"
#: src/js/controllers/tab-send.js:29
msgid "Your Clipboard is empty"
msgstr "您的剪贴板为空"
#: www/views/modals/search.html:16
msgid "Search transactions"
msgstr "搜索交易"
@ -2640,68 +2583,9 @@ msgid "Send by email"
msgstr "通过电邮发送"
#: src/js/controllers/confirm.js:177
#: src/js/controllers/tab-send.js:94
msgid "Send from"
msgstr "从发送"
#: src/js/controllers/tab-send.js:77
msgid "Send to"
msgstr "发送到"
#: www/views/tab-send.html:20
msgid "Paste Clipboard"
msgstr "粘贴剪贴板"
#: www/views/tab-send.html:21
msgid "Paste Address"
msgstr "粘贴地址"
#: www/views/tab-send.html:27
msgid "Transfer between wallets"
msgstr "在钱包之间转账"
#: www/views/tab-send.html:35
msgid "Scan QR Code"
msgstr "扫描二维码"
#: www/views/tab-send.html:46
msgid "Send Bitcoin faster!"
msgstr "更快地发送比特币!"
#: www/views/tab-send.html:50
msgid "Save frequently used addresses and send them Bitcoin in just one tap"
msgstr "保存常用地址,只需点击一下即可将比特币发送到这些地址"
#: www/views/tab-send.html:55
msgid "Add your first contact"
msgstr "添加您的第一个联系人"
#: www/views/tab-send.html:65
msgid "Your Bitcoin wallet is empty"
msgstr "您的比特币钱包为空"
#: www/views/tab-send.html:69
msgid "To get started, buy Bitcoin Cash (BCH) or Bitcoin Core (BTC), or share your address."
msgstr "首先,购买 Bitcoin Cash (BCH) 或 Bitcoin Core (BTC),或者共享您的地址。"
#: www/views/tab-send.html:70
msgid "You can receive bitcoin from any wallet or service."
msgstr "您可以从任何钱包或服务接收比特币。"
#: www/views/tab-send.html:72
#: www/views/shapeshift.html:23
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "若要开始,您将需要创建一个比特币的钱包,并获得一些比特币。"
#: www/views/tab-send.html:74
msgid "Buy Bitcoin now"
msgstr "立即购买比特币"
#: www/views/tab-send.html:76
msgid "Show my address"
msgstr "显示我的地址"
#: www/views/includes/itemSelector.html:8
msgid "Send max amount"
msgstr "发送最大数量"
@ -2918,21 +2802,16 @@ msgstr "超级经济"
#: www/views/preferencesCash.html:11
msgid "Support Bitcoin Cash"
msgstr "支持 Bitcoin Cash"
msgstr "支持小比特幣"
#: www/views/paperWallet.html:7
msgid "Sweep"
msgstr "扫描"
#: www/views/includes/incomingDataMenu.html:89
msgctxt "List item"
msgid "Sweep paper wallet"
msgstr "清空纸钱包"
#: www/views/paperWallet.html:3
msgctxt "Page title"
msgid "Sweep Paper Wallet"
msgstr "清空纸钱包"
msgid "Sweep paper wallet"
msgstr "Sweep 纸钱包"
#: src/js/services/onGoingProcess.js:33
msgid "Sweeping Wallet..."
@ -2973,7 +2852,7 @@ msgstr "使用条款"
#: www/views/tab-create-personal.html:118
#: www/views/tab-import-phrase.html:68
msgid "Testnet"
msgstr "测试网"
msgstr "Testnet"
#: www/views/includes/incomingDataMenu.html:61
msgid "Text"
@ -3100,14 +2979,6 @@ msgstr "此应用程序商店你比特币与尖端的安全。"
msgid "This bitcoin payment request has expired."
msgstr "这比特币付款请求已过期。"
#: www/views/review.html:55
msgid "Payment expires:"
msgstr "付款到期:"
#: www/views/review.html:56
msgid "Payment request has expired"
msgstr "付款请求已过期"
#: www/views/join.html:133
#: www/views/tab-create-personal.html:103
#: www/views/tab-create-shared.html:132
@ -3149,6 +3020,10 @@ msgstr "发送到"
msgid "To get started, buy bitcoin or share your address. You can receive bitcoin from any wallet or service."
msgstr "若要开始,请买比特币或共享您的地址。你可以从任何钱包或服务接收比特币。"
#: www/views/tab-send.html:33
msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin."
msgstr "若要开始,您将需要创建一个比特币的钱包,并获得一些比特币。"
#: src/js/services/bitpayAccountService.js:73
msgid "To {{reason}} you must first add your BitPay account - {{email}}"
msgstr "到 {{reason}},您必须首先添加您的 BitPay 帐户-{{email}}"
@ -3161,26 +3036,6 @@ msgstr "在进展充值..."
msgid "Top up {{amountStr}} to debit card ({{cardLastNumber}})"
msgstr "充值 {{amountStr}},记入借方卡 ({{cardLastNumber}})"
#: www/views/shapeshift.html:30
msgid "Start ShapeShift"
msgstr "开始 ShapeShift"
#: www/views/shapeshift.html:30
msgid "Exchange your BTC to BCH in minutes."
msgstr "在数分钟内将您的 BTC 兑换为 BCH。"
#: www/views/shapeshift.html:30
msgid "To start the process you need to add funds to your wallet."
msgstr "要开始兑换,您需要先向钱包中充入资金。"
#: www/views/shapeshift.html:30
msgid "The process is fast and you will receive the exchanged amount in your wallet."
msgstr "兑换操作非常快,您将在自己的钱包中收到兑换后的金额。"
#: www/views/shapeshift.html:34
msgid "This service is provided by the third-party ShapeShift, who will charge a small fee for the service. The fee will be shown before you start the transaction."
msgstr "此服务由第三方 ShapeShift 提供,他们将收取少量服务费。所需费用将在您开始交易之前显示。"
#: www/views/buyAmazon.html:61
#: www/views/buyMercadoLibre.html:60
#: www/views/modals/wallet-balance.html:23
@ -3337,7 +3192,7 @@ msgstr "查看服务条款"
#: src/js/controllers/bitpayCard.js:122
#: src/js/controllers/tx-details.js:191
msgid "View Transaction on Explorer.Bitcoin.com"
msgstr "在 Explorer.Bitcoin.com 上查看交易"
msgstr "查看交易记录的洞察"
#: src/js/controllers/tab-home.js:148
msgid "View Update"
@ -3772,172 +3627,3 @@ msgstr "下载的 {{updatingTxHistoryProgress}} 交易"
#: www/views/includes/walletInfo.html:18
msgid "{{wallet.m}}-of-{{wallet.n}}"
msgstr "{{wallet.m}}{{wallet.n}}"
#: src/js/services/shapeshiftService.js:8
msgid "Shapeshift"
msgstr "Shapeshift"
#: www/views/includes/community.html:3
msgid "Community"
msgstr "社区"
#: src/js/services/communityService.js:40
msgid "Bitcoin Cash Reddit"
msgstr "Bitcoin Cash Reddit"
#: src/js/services/communityService.js:47
msgid "Bitcoin.com Twitter"
msgstr "Bitcoin.com Twitter"
#: www/views/includes/nextSteps.html:3
msgid "Explore Bitcoin.com"
msgstr "探索 Bitcoin.com"
#: src/js/services/bitcoincomService.js:21
msgid "Bitcoin Cash Games"
msgstr "Bitcoin Cash 游戏"
#: www/views/includes/community.html:29
msgid "Share the Wallet App"
msgstr "分享钱包应用"
#: src/js/services/bitcoincomService.js:28
msgid "News"
msgstr "新闻"
#: src/js/services/bitcoincomService.js:35
msgid "Mining Pool"
msgstr "矿池"
#: src/js/services/bitcoincomService.js:42
msgid "Tools"
msgstr "工具"
#: src/js/services/bitcoincomService.js:49
msgid "Bitcoin Price Charts"
msgstr "比特币价格图表"
#: src/js/services/bitcoincomService.js:56
msgid "Free Bitcoin Cash"
msgstr "免费的 Bitcoin Cash"
#: www/views/tab-home.html:30
msgid "Your Bitcoin Wallets are ready!"
msgstr "您的比特币钱包已就绪!"
#: src/js/controllers/amount.js:49
msgid "Address does not contain currency information, please make sure you are sending the correct currency."
msgstr "地址未包含货币信息,请确保您发送的货币正确。"
#: www/views/review.html:4
msgid "Review Transaction"
msgstr "检查交易"
#: src/js/controllers/review.controller.js:36
msgid "You are sending"
msgstr "您将发送"
#: src/js/controllers/review.controller.js:66
msgid "You are shifting"
msgstr "您将兑换"
#: www/views/review.html:36
msgid "To:"
msgstr "到:"
#: www/views/review.html:53
msgid "Add personal note"
msgstr "添加个人注释"
#: www/views/review.html:87
msgid "Suggested by merchant:"
msgstr "商户建议:"
#: src/js/controllers/review.controller.js:37
msgid "Enter text here"
msgstr "在此处输入文本"
#: www/views/review.html:57
msgid "Personal note:"
msgstr "个人注释:"
#: www/views/review.html:69
msgid "Less than 1 cent"
msgstr "少于 1 美分"
#: src/js/services/incomingData.js:129
msgid "This invoice is no longer accepting payments"
msgstr "此发票不再接受付款"
#: www/views/amount.html.js:60
msgid "Send Maximum Amount"
msgstr "发送最大金额"
#: src/js/controllers/amount.controller.js:239
msgid "Unknown error."
msgstr "未知错误。"
#: www/views/paperWallet.html:48
msgid "No Bitcoin Cash wallet to transfer funds to found."
msgstr "未找到可以转入资金的 Bitcoin Cash 钱包。"
#: www/views/paperWallet.html:54
msgid "No Bitcoin Cash found."
msgstr "未找到 Bitcoin Cash。"
#: www/views/paperWallet.html:60
msgid "Bitcoin Core found:"
msgstr "已找到 Bitcoin Core"
#: www/views/paperWallet.html:98
msgid "No Bitcoin Core wallet to transfer funds to found."
msgstr "未找到可以转入资金的 Bitcoin Core 钱包。"
#: www/views/paperWallet.html:104
msgid "No Bitcoin Core found."
msgstr "未找到 Bitcoin Core。"
#: src/js/controllers/tab-scan.js:120
msgid "Scan Failed"
msgstr "扫描失败"
#: src/js/controllers/tab-scan.js:121
msgid "Data not recognised."
msgstr "数据未被识别。"
#: src/js/controllers/tab-scan.js:121
msgid "Unsupported"
msgstr "不受支持"
#: src/js/controllers/tab-scan.js:121
msgid "Testnet is not supported."
msgstr "不支持测试网。"
#: www/views/includes/incomingDataMenu.html:81
msgid "URL"
msgstr "网址"
#: www/views/includes/incomingDataMenu.html:90
msgid "Open in web browser"
msgstr "在网络浏览器中打开"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid address"
msgstr "地址无效"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is not defined"
msgstr "未定义金额"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is below the minimun"
msgstr "金额低于最低金额"
#: src/js/services/shapeshift.service.js.html:90
msgid "Amount is above the limit"
msgstr "金额高于限额"
#: src/js/services/shapeshift.service.js.html:90
msgid "Invalid response from Shapeshift"
msgstr "Shapeshift 的响应无效"

View file

@ -8,7 +8,7 @@
"postinstall": "npm run apply:copay && echo && echo \"Repo configured for standard Copay distribution. To switch to the BitPay distribution, run 'npm run apply:bitpay'.\" && echo",
"start": "echo && echo \"Choose a distribution by running 'npm run apply:copay' or 'npm run apply:bitpay'.\" && echo",
"apply:copay": "npm i fs-extra@0.30 && cd app-template && node apply.js copay && cd .. && npm i",
"apply:bitcoincom": "npm i fs-extra && cd app-template && node apply.js bitcoincom && npm i && cordova prepare && cd ../ && ./fix-asn1.sh",
"apply:bitcoincom": "npm i fs-extra && cd app-template && node apply.js bitcoincom && npm i && cordova prepare",
"apply:bitpay": "npm i fs-extra@0.30 && cd app-template && node apply.js bitpay && cd .. && npm i",
"unstage-package": "git reset package.json",
"clean-all": "git clean -dfx"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 B

View file

@ -1,32 +0,0 @@
[Sign]
## [REQUIRED] Your Application Certificate Identity
ApplicationIdentity = 3rd Party Mac Developer Application: Saint Bitts LLC (299HJ3G3BP)
## [OPTIONAL] Parent entitlements file
ParentEntitlements = entitlements-parent.plist
## [OPTIONAL] Child entitlements file
ChildEntitlements = entitlements-child.plist
## [OPTIONAL] Sandbox. Default: Yes
Sandbox = Yes
[Package]
## [REQUIRED for --pkg] Your Installer Certificate Identity
InstallerIdentity = 3rd Party Mac Developer Installer: Saint Bitts LLC (299HJ3G3BP)
## [OPTIONAL for --pkg] Installation path
InstallPath = /Applications
[Info.plist]
## [OPTIONAL] Your app bundle identifier
CFBundleIdentifier = com.bitcoin.mwallet.mac
## [REQUIRED] Team ID obtained from Apple Developer -> Membership -> Team ID
NWTeamID = 299HJ3G3BP
## Properties of Info.plist will be overwritten in this section.
[Resources]
## [OPTIONAL] Your custom icon file
Icon = ../resources/bitcoin.com/mac/pkg/app.icns
## [OPTIONAL] Locales
## If Locales is not set, all current locales are preserved.
## If comma separated locale list (e.g. en,fr,zh_CN) is given, you should have
## additional [Locale locale_name] section for each locale containing localized strings.
## Locales not in the list will be removed.
Locales = en

View file

@ -1,259 +0,0 @@
#!/usr/bin/env python
import argparse
import ConfigParser
import shutil
import os
import fnmatch
import plistlib
import tempfile
from datetime import datetime
import sys
import io
bundleid = None
verbose = False
def info(msg):
global verbose
if verbose:
print '[INFO] %s' % msg
def error(msg):
print '[ERROR] %s' % msg
print '\nFailed.'
sys.exit(1)
def system(cmd):
info(cmd)
os.system(cmd)
def check_options(config, section, required_options, msg):
missed_options = []
for option in required_options:
if not config.has_option(section, option):
missed_options.append(option)
if len(missed_options) != 0:
error(msg % (section, ', '.join(missed_options)))
def glob(pathname, pattern, returnOnFound=False):
matches = []
for root, dirnames, filenames in os.walk(pathname):
for dirname in fnmatch.filter(dirnames, pattern):
if returnOnFound:
return os.path.join(root, dirname)
matches.append(os.path.join(root, dirname))
for filename in fnmatch.filter(filenames, pattern):
if returnOnFound:
return os.path.join(root, filename)
matches.append(os.path.join(root, filename))
return matches
def get_bundle_id(args):
global bundleid
if bundleid is None:
plist = plistlib.readPlist(os.path.join(args.output, 'Contents/Info.plist'))
bundleid = plist['CFBundleIdentifier']
return bundleid
def get_from_info_plist(args, key, default=None):
plist = plistlib.readPlist(os.path.join(args.output, 'Contents/Info.plist'))
if key in plist:
return plist[key]
else:
return default
def patch_info_plist_file(file, replaces):
plist = plistlib.readPlist(file)
for (key, val) in replaces:
plist[key] = val
plistlib.writePlist(plist, file)
def generate_infoplist_strings_file(file, items):
with io.open(file, 'w', encoding='utf-16') as fd:
for item in items:
fd.write(unicode('%s = "%s";\n' % item, 'utf-8'))
def read_config(args):
print '\nParsing config file %s' % args.config_file
if not os.path.isfile(args.config_file):
error('%s does not exist' % args.config_file)
config = ConfigParser.SafeConfigParser()
config.optionxform = str # set to str to prevent transforming into lower cases
config.read(args.config_file)
check_options(config, 'Sign', ['ApplicationIdentity'], 'Missed options in [%s]: %s')
if args.pkg:
check_options(config, 'Package', ['InstallerIdentity'], 'Missed options for --pkg in [%s]: %s')
return config
def copy_to_output(args):
print '\nCopying %s to %s' % (args.input, args.output)
shutil.rmtree(args.output, ignore_errors=True)
shutil.copytree(args.input, args.output, symlinks=True) # symblic links are required
def patch_info_plist(config, args):
print '\nPatching Info.plist files'
replaces = []
for (key, val) in config.items('Info.plist'):
replaces.append((key, val))
file = os.path.join(args.output, 'Contents/Info.plist')
info(file)
patch_info_plist_file(file, replaces)
info_plist_files = glob(os.path.join(args.output, 'Contents/Versions'), 'Info.plist')
for file in info_plist_files:
if 'nwjs Framework' in file:
tmp_replaces = [('CFBundleIdentifier', '%s.framework' % get_bundle_id(args))]
elif 'nwjs Helper' in file:
tmp_replaces = [('CFBundleIdentifier', '%s.helper' % get_bundle_id(args))]
else:
error('Cannot patch unknown Info.plist %s' % file)
info(file)
patch_info_plist_file(file, tmp_replaces)
def patch_locales(config, args):
print '\nPatching locales'
locales = config.get('Resources', 'Locales').split(',')
removed_locales = []
generated_locales = []
for infoplist_strings_file in glob(os.path.join(args.output, 'Contents/Resources'), 'InfoPlist.strings'):
locale_dir = os.path.dirname(infoplist_strings_file)
(locale, _) = os.path.splitext(os.path.basename(locale_dir))
if locale not in locales:
removed_locales.append(locale)
shutil.rmtree(locale_dir)
elif config.has_section('Locale %s' % locale):
generated_locales.append(locale)
generate_infoplist_strings_file(infoplist_strings_file, config.items('Locale %s' % locale))
else:
error('Missing [Locale %s] section' % locale)
if len(generated_locales) > 0:
info('Generated locales for %s' % ', '.join(generated_locales))
if len(removed_locales) > 0:
info('Removed locales for %s' % ', '.join(removed_locales))
removed_paks = []
for local_pak in glob(os.path.join(args.output, 'Contents/Versions'), 'locale.pak'):
locale_dir = os.path.dirname(local_pak)
(locale, _) = os.path.splitext(os.path.basename(locale_dir))
if locale != 'en' and locale not in locales:
removed_paks.append(locale)
shutil.rmtree(locale_dir)
if len(removed_paks) > 0:
info('Removed .pak files for %s' % ', '.join(removed_locales))
def patch_icon(config, args):
plist = plistlib.readPlist(os.path.join(args.output, 'Contents/Info.plist'))
icon = os.path.join(os.path.dirname(args.config_file), config.get('Resources', 'Icon'))
dest_icon = os.path.join(args.output, 'Contents/Resources/%s' % plist['CFBundleIconFile'])
info('Copying icon from %s to %s' % (icon, dest_icon))
shutil.copy2(icon, dest_icon)
def codesign_app(config, args):
print '\nCodesigning'
bundleid = get_bundle_id(args)
identity = config.get('Sign', 'ApplicationIdentity')
sandbox = True
if config.has_option('Sign', 'Sandbox'):
sandbox = config.getboolean('Sign', 'Sandbox')
## sign child frameworks and helpers
(_, tmp_child_entitlements) = tempfile.mkstemp()
if config.has_option('Sign', 'ChildEntitlements'):
child = config.get('Sign', 'ChildEntitlements')
child_entitlements = plistlib.readPlist(child)
else:
child_entitlements = {
'com.apple.security.app-sandbox' : sandbox,
'com.apple.security.inherit' : True
}
plistlib.writePlist(child_entitlements, tmp_child_entitlements)
info('Child entitlements: %s' % tmp_child_entitlements)
libffmpeg = glob(os.path.join(args.output, 'Contents/Versions/55.0.2883.87/nwjs Framework.framework/Versions/A'), 'libffmpeg.dylib', returnOnFound=True)
system('codesign --deep --force --verbose --verify --sign "%s" --entitlements %s --deep "%s"' % (identity, tmp_child_entitlements, libffmpeg))
libnode = glob(os.path.join(args.output, 'Contents/Versions/55.0.2883.87/nwjs Framework.framework/Versions/A'), 'libnode.dylib', returnOnFound=True)
system('codesign --deep --force --verbose --verify --sign "%s" --entitlements %s --deep "%s"' % (identity, tmp_child_entitlements, libnode))
helperApp = glob(args.output, 'nwjs Helper.app', returnOnFound=True)
system('codesign --deep --force --verbose --verify --sign "%s" --entitlements %s --deep "%s"' % (identity, tmp_child_entitlements, helperApp))
framework = glob(args.output, 'nwjs Framework.framework', returnOnFound=True)
system('codesign --deep --force --verbose --verify --sign "%s" --entitlements %s --deep "%s"' % (identity, tmp_child_entitlements, framework))
## sign parent app
(_, tmp_parent_entitlements) = tempfile.mkstemp()
if config.has_option('Sign', 'ParentEntitlements'):
parent = config.get('Sign', 'ParentEntitlements')
parent_entitlements = plistlib.readPlist(parent)
else:
parent_entitlements = {}
teamid = get_from_info_plist(args, 'NWTeamID', default=None)
if teamid is None:
groupid = bundleid
else:
groupid = '%s.%s' % (teamid, bundleid)
parent_entitlements['com.apple.security.app-sandbox'] = sandbox
parent_entitlements['com.apple.security.application-groups'] = [groupid]
plistlib.writePlist(parent_entitlements, tmp_parent_entitlements)
info('Parent entitlements: %s' % tmp_parent_entitlements)
system('codesign -f --verbose -s "%s" --entitlements %s --deep "%s"' % (identity, tmp_parent_entitlements, args.output))
def productbuild(config, args):
print '\nRunning productbuild'
installer_identity = config.get('Package', 'InstallerIdentity')
if config.has_option('Package', 'InstallPath'):
install_path = config.get('Package', 'InstallPath')
else:
install_path = '/Applications'
system('productbuild --component "%s" "%s" --sign "%s" "%s"' % (args.output, install_path, installer_identity, args.pkg))
def main():
parser = argparse.ArgumentParser(description='Signing tool for NW.js app')
parser.add_argument('-C', '--config-file', default='build.cfg', help='config file. (default: build.cfg)')
parser.add_argument('-I', '--input', default='nwjs.app', help='path to input app. (default: nwjs.app)')
parser.add_argument('-O', '--output', default='nwjs_output.app', help='path to output app. (default: nwjs_output.app)')
parser.add_argument('-S', '--skip-patching', default=False, help='run codesign without patching the app. (default: False)', action='store_true')
parser.add_argument('-P', '--pkg', default=None, help='run productbuild to generate .pkg after codesign. (default: None)')
parser.add_argument('-V', '--verbose', default=False, help='display detailed information. (default: False)', action='store_true')
args = parser.parse_args()
global verbose
verbose = args.verbose
# read config file
config = read_config(args)
# make a copy
copy_to_output(args)
if not args.skip_patching:
# patch Info.plist
patch_info_plist(config, args)
# process resources & locales
if config.has_section('Resources'):
if config.has_option('Resources', 'Locales'):
patch_locales(config, args)
if config.has_option('Resources', 'Icon'):
patch_icon(config, args)
# codesign
codesign_app(config, args)
if args.pkg:
productbuild(config, args)
print '\nDone.'
if __name__ == "__main__":
main()

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>299HJ3G3BP.com.bitcoin.mwallet.mac</string>
</array>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>
</dict>
</plist>

View file

@ -1,25 +1,20 @@
ext {
ANDROID_SUPPORT_V4_VERSION = '26.1.0'
}
configurations.all {
resolutionStrategy {
force "com.android.support:support-v4:26.1.0"
force "com.google.android.gms:play-services-auth:11.8.0"
force "com.google.android.gms:play-services-identity:11.8.0"
force "com.google.android.gms:play-services-ads:11.8.0"
force "com.google.android.gms:play-services-base:11.8.0"
force "com.google.android.gms:play-services-gcm:11.8.0"
force "com.google.android.gms:play-services-analytics:11.8.0"
force "com.google.android.gms:play-services-location:11.8.0"
force "com.google.android.gms:play-services-basement:11.8.0"
force "com.google.android.gms:play-services-tagmanager:11.8.0"
force 'com.google.firebase:firebase-core:11.8.0'
force 'com.google.firebase:firebase-crash:11.8.0'
force 'com.google.firebase:firebase-auth:11.8.0'
force 'com.google.firebase:firebase-common:11.8.0'
force 'com.google.firebase:firebase-config:11.8.0'
force 'com.google.firebase:firebase-perf:11.8.0'
force 'com.google.firebase:firebase-messaging:11.8.0'
}
resolutionStrategy {
force "com.google.android.gms:play-services-auth:11.8.0"
force "com.google.android.gms:play-services-identity:11.8.0"
force "com.google.android.gms:play-services-ads:11.8.0"
force "com.google.android.gms:play-services-base:11.8.0"
force "com.google.android.gms:play-services-gcm:11.8.0"
force "com.google.android.gms:play-services-analytics:11.8.0"
force "com.google.android.gms:play-services-location:11.8.0"
force "com.google.android.gms:play-services-basement:11.8.0"
force "com.google.android.gms:play-services-tagmanager:11.8.0"
force 'com.google.firebase:firebase-core:11.8.0'
force 'com.google.firebase:firebase-crash:11.8.0'
force 'com.google.firebase:firebase-auth:11.8.0'
force 'com.google.firebase:firebase-common:11.8.0'
force 'com.google.firebase:firebase-config:11.8.0'
force 'com.google.firebase:firebase-perf:11.8.0'
force 'com.google.firebase:firebase-messaging:11.8.0'
}
}

View file

@ -19,9 +19,7 @@ var modules = [
'copayApp.controllers',
'copayApp.directives',
'copayApp.addons',
'bitcoincom.controllers',
'bitcoincom.directives',
'bitcoincom.services'
'bitcoincom.directives'
];
var copayApp = window.copayApp = angular.module('copayApp', modules);
@ -31,6 +29,4 @@ angular.module('copayApp.services', []);
angular.module('copayApp.controllers', []);
angular.module('copayApp.directives', []);
angular.module('copayApp.addons', []);
angular.module('bitcoincom.controllers', []);
angular.module('bitcoincom.directives', []);
angular.module('bitcoincom.services', []);

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('addressbookAddController', function($scope, $state, $stateParams, $timeout, $ionicHistory, gettextCatalog, addressbookService, popupService, configService, bitcoinCashJsService, platformInfo) {
angular.module('copayApp.controllers').controller('addressbookAddController', function($scope, $state, $stateParams, $timeout, $ionicHistory, gettextCatalog, addressbookService, popupService, configService, bitcoinCashJsService) {
var config = configService.getSync();
var defaults = configService.getDefaults();
@ -21,9 +21,6 @@ angular.module('copayApp.controllers').controller('addressbookAddController', fu
$timeout(function() {
var form = addressbookForm;
if (data && form) {
if (data.result) {
data = data.result;
}
data = data.replace(/^bitcoin(cash)?:/, '');
form.address.$setViewValue(data);
form.address.$isValid = true;
@ -38,16 +35,6 @@ angular.module('copayApp.controllers').controller('addressbookAddController', fu
var translated = bitcoinCashJsService.readAddress(addressbook.address);
addressbook.address = translated.legacy;
}
var channel = "ga";
if (platformInfo.isCordova) {
channel = "firebase";
}
var log = new window.BitAnalytics.LogEvent("contact_created", [{
"coin": $scope.addressbookEntry.coin
}], [channel]);
window.BitAnalytics.LogEventHandlers.postEvent(log);
$timeout(function() {
addressbookService.add(addressbook, function(err, ab) {
if (err) {

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('addressbookViewController', function($scope, sendFlowService, $state, $timeout, lodash, addressbookService, popupService, $ionicHistory, platformInfo, gettextCatalog, configService, bitcoinCashJsService) {
angular.module('copayApp.controllers').controller('addressbookViewController', function($scope, $state, $timeout, lodash, addressbookService, popupService, $ionicHistory, platformInfo, gettextCatalog, configService, bitcoinCashJsService) {
var config = configService.getSync();
var defaults = configService.getDefaults();
@ -21,14 +21,23 @@ angular.module('copayApp.controllers').controller('addressbookViewController', f
});
$scope.sendTo = function() {
var stateParams = {
data: $scope.addressbookEntry.address,
toName: $scope.addressbookEntry.name,
toEmail: $scope.addressbookEntry.email,
coin: $scope.addressbookEntry.coin
};
sendFlowService.start(stateParams);
$ionicHistory.removeBackView();
$state.go('tabs.send');
$timeout(function() {
var to = '';
if ($scope.addressbookEntry.coin == 'bch') {
var a = 'bitcoincash:' + $scope.addressbookEntry.address;
to = bitcoinCashJsService.readAddress(a).legacy;
} else {
to = $scope.addressbookEntry.address;
}
$state.transitionTo('tabs.send.amount', {
toAddress: to,
toName: $scope.addressbookEntry.name,
toEmail: $scope.addressbookEntry.email,
coin: $scope.addressbookEntry.coin
});
}, 100);
};
$scope.remove = function(addressbookEntry) {

View file

@ -13,6 +13,10 @@ angular.module('copayApp.controllers').controller('advancedSettingsController',
$scope.hideNextSteps = {
value: config.hideNextSteps.enabled
};
$scope.displayBitcoinCoreEnabled = {
value: config.displayBitcoinCore.enabled
};
};
$scope.spendUnconfirmedChange = function() {
@ -48,6 +52,17 @@ angular.module('copayApp.controllers').controller('advancedSettingsController',
});
};
$scope.displayBitcoinCoreChange = function() {
var opts = {
displayBitcoinCore: {
enabled: $scope.displayBitcoinCoreEnabled.value
}
};
configService.set(opts, function(err) {
if (err) $log.debug(err);
});
};
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP;
updateConfig();

View file

@ -1,774 +0,0 @@
'use strict';
(function(){
angular
.module('bitcoincom.controllers')
.controller('amountController', amountController);
function amountController(configService, $filter, gettextCatalog, $ionicHistory, $ionicModal, $ionicScrollDelegate, lodash, $log, nodeWebkitService, rateService, $scope, $state, $timeout, sendFlowService, shapeshiftService, txFormatService, platformInfo, ongoingProcess, popupService, profileService, walletService, $window) {
var vm = this;
// Variables
vm.allowSend = false;
vm.altCurrencyList = [];
vm.alternativeAmount = '';
vm.alternativeUnit = '';
vm.amount = '0';
vm.availableFunds = '';
vm.canSendAllAvailableFunds = true;
vm.errorMessage = '';
// Use insufficient for logic, as when the amount is invalid, funds being
// either sufficent or insufficient doesn't make sense.
vm.fundsAreInsufficient = false;
vm.globalResult = '';
vm.isRequestingSpecificAmount = false;
vm.listComplete = false;
vm.lastUsedPopularList = [];
vm.maxAmount = 0;
vm.minAmount = 0;
vm.sendableFunds = '';
vm.showSendMaxButton = false;
vm.showSendLimitMaxButton = false;
vm.thirdParty = false;
vm.unit = '';
// Functions
vm.changeUnit = changeUnit;
vm.close = close;
vm.findCurrency = findCurrency;
vm.finish = finish;
vm.goBack = goBack;
vm.loadMore = loadMore;
vm.next = next;
vm.openPopup = openPopup;
vm.pushDigit = pushDigit;
vm.removeDigit = removeDigit;
vm.save = save;
vm.sendMax = sendMax;
$scope.$on('$ionicView.beforeEnter', onBeforeEnter);
$scope.$on('$ionicView.leave', onLeave);
var LENGTH_EXPRESSION_LIMIT = 19;
var LENGTH_BEFORE_COMMA_EXPRESSION_LIMIT = 8;
var LENGTH_AFTER_COMMA_EXPRESSION_LIMIT = 8;
var altCurrencyModal = null;
var altUnitIndex = 0;
var availableUnits = [];
var canSendMax = true;
var fiatCode;
var isNW = platformInfo.isNW;
var isAndroid = platformInfo.isAndroid;
var isIos = platformInfo.isIOS;
var lastUsedAltCurrencyList = [];
var passthroughParams = {};
var satToUnit;
var transactionSendableAmount = {
crypto: '',
satoshis: null
};
var unitDecimals;
var unitIndex = 0;
var unitToSatoshi;
var useSendMax = false;
var walletSpendableAmount = {
crypto: '',
satoshis: null
};
function onLeave() {
angular.element($window).off('keydown');
}
function onBeforeEnter(event, data) {
if (data.direction == "back") {
sendFlowService.state.pop();
}
initCurrencies();
passthroughParams = sendFlowService.state.getClone();
console.log('amount onBeforeEnter after back sendflow ', passthroughParams);
vm.fromWalletId = passthroughParams.fromWalletId;
vm.toWalletId = passthroughParams.toWalletId;
vm.minAmount = parseFloat(passthroughParams.minAmount);
vm.maxAmount = parseFloat(passthroughParams.maxAmount);
vm.isRequestingSpecificAmount = !passthroughParams.fromWalletId;
vm.showSendMaxButton = !vm.isRequestingSpecificAmount;
var config = configService.getSync().wallet.settings;
unitToSatoshi = config.unitToSatoshi;
satToUnit = 1 / unitToSatoshi;
unitDecimals = config.unitDecimals;
setAvailableUnits();
updateUnitUI();
var reNr = /^[1234567890\.]$/;
var reOp = /^[\*\+\-\/]$/;
if (!isAndroid && !isIos) {
angular.element($window).on('keydown', function(e) {
if (!e.key) return;
if (e.which === 8) { // you can add others here inside brackets.
if (!altCurrencyModal) {
e.preventDefault();
vm.removeDigit();
}
}
if (e.key.match(reNr)) {
vm.pushDigit(e.key);
} else if (e.key.match(reOp)) {
pushOperator(e.key);
} else if (e.keyCode === 86) {
if (e.ctrlKey || e.metaKey) processClipboard();
} else if (e.keyCode === 13) vm.finish();
$timeout(function() {
$scope.$apply();
});
});
}
resetAmount();
processAmount();
$timeout(function() {
$ionicScrollDelegate.resize();
}, 10);
function setAvailableUnits() {
var defaults = configService.getDefaults();
var configCache = configService.getSync();
availableUnits = [];
var coinFromWallet = '';
if (passthroughParams.fromWalletId) {
var fromWallet = profileService.getWallet(passthroughParams.fromWalletId);
coinFromWallet = fromWallet.coin;
} else {
var toWallet = profileService.getWallet(passthroughParams.toWalletId);
coinFromWallet = toWallet.coin;
}
if (coinFromWallet === 'bch') {
availableUnits.push({
name: 'Bitcoin Cash',
id: 'bch',
shortName: (configCache.bitcoinCashAlias || defaults.bitcoinCashAlias).toUpperCase(),
});
};
if (coinFromWallet === 'btc') {
availableUnits.push({
name: 'Bitcoin',
id: 'btc',
shortName: (configCache.bitcoinAlias || defaults.bitcoinAlias).toUpperCase(),
});
}
unitIndex = 0;
// currency have preference
var fiatName;
if (passthroughParams.currency) {
fiatCode = passthroughParams.currency;
altUnitIndex = unitIndex
unitIndex = availableUnits.length;
} else {
fiatCode = config.alternativeIsoCode || 'USD';
fiatName = config.alternanativeName || fiatCode;
altUnitIndex = availableUnits.length;
}
availableUnits.push({
name: fiatName || fiatCode,
// TODO
id: fiatCode,
shortName: fiatCode,
isFiat: true,
});
unitIndex = lodash.findIndex(availableUnits, {
isFiat: true
});
altUnitIndex = 0;
if (passthroughParams.fromWalletId) {
var fromWallet = profileService.getWallet(passthroughParams.fromWalletId);
updateAvailableFundsFromWallet(fromWallet);
}
if (passthroughParams.thirdParty) {
vm.thirdParty = passthroughParams.thirdParty; // Parse stringified JSON-object
if (vm.thirdParty) {
initShapeshift();
}
}
}
}
function goBack() {
sendFlowService.router.goBack();
}
function initShapeshift() {
if (vm.thirdParty.id === 'shapeshift') {
vm.thirdParty.data = vm.thirdParty.data || {};
vm.fromWallet = profileService.getWallet(vm.fromWalletId);
vm.toWallet = profileService.getWallet(vm.toWalletId);
vm.showSendMaxButton = false;
vm.showSendLimitMaxButton = false;
vm.canSendAllAvailableFunds = false;
ongoingProcess.set('connectingShapeshift', true);
shapeshiftService.getMarketData(vm.fromWallet.coin, vm.toWallet.coin, function onMarketData(err, data) {
ongoingProcess.set('connectingShapeshift', false);
if (err) {
// Error stop here
popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.message, function () {
goBack();
});
} else {
vm.thirdParty.data.minAmount = vm.minAmount = parseFloat(data.minimum);
vm.thirdParty.data.maxAmount = vm.maxAmount = parseFloat(data.maxLimit);
setMaximumButtonFromWallet(vm.fromWallet);
}
});
}
}
function paste(value) {
vm.amount = value;
processAmount();
$timeout(function() {
$scope.$apply();
});
}
function processClipboard() {
if (!isNW) return;
var value = nodeWebkitService.readFromClipboard();
if (value && evaluate(value) > 0) paste(evaluate(value));
}
function sendMax() {
if (canSendMax) {
useSendMax = true;
finish();
} else {
var transactionSendableAmountInUnits = transactionSendableAmount.satoshis * satToUnit;
if (vm.minAmount && transactionSendableAmountInUnits < vm.minAmount) {
popupService.showAlert(
gettextCatalog.getString('Insufficient funds'),
gettextCatalog.getString('Amount below minimum allowed')
);
} else {
// Need to be precise, so use crypto directly rather than fiat with exchange rate
if (availableUnits[unitIndex].isFiat) {
var tempIndex = altUnitIndex;
altUnitIndex = unitIndex;
unitIndex = tempIndex;
}
vm.amount = transactionSendableAmountInUnits.toFixed(LENGTH_AFTER_COMMA_EXPRESSION_LIMIT);
useSendMax = true;
finish();
}
}
}
function updateUnitUI() {
vm.unit = availableUnits[unitIndex].shortName;
vm.alternativeUnit = availableUnits[altUnitIndex].shortName;
processAmount();
$log.debug('Update unit coin @amount unit:' + vm.unit + " alternativeUnit:" + vm.alternativeUnit);
}
function changeUnit() {
vm.amount = '0';
if (!(availableUnits[unitIndex].isFiat && availableUnits.length > 2 && altUnitIndex == 0)) {
unitIndex++;
if (unitIndex >= availableUnits.length) unitIndex = 0;
}
if (availableUnits[unitIndex].isFiat) {
altUnitIndex = altUnitIndex == 0 && availableUnits.length > 2 ? 1 : 0;
} else {
altUnitIndex = lodash.findIndex(availableUnits, {
isFiat: true
});
}
updateAvailableFundsStringIfNeeded();
updateUnitUI();
}
function pushDigit(digit) {
if (vm.amount && digit != '.') {
var amountSplitByComma = vm.amount.split('.');
if (amountSplitByComma.length > 1 && amountSplitByComma[1].length >= LENGTH_AFTER_COMMA_EXPRESSION_LIMIT) return;
if (amountSplitByComma.length == 1 && amountSplitByComma[0].length >= LENGTH_BEFORE_COMMA_EXPRESSION_LIMIT) return;
}
if (vm.amount && vm.amount.length >= LENGTH_EXPRESSION_LIMIT) return;
if (vm.amount.indexOf('.') > -1 && digit == '.') return;
if (vm.amount == '0' && digit == '0') return;
if (availableUnits[unitIndex].isFiat && vm.amount.indexOf('.') > -1 && vm.amount[vm.amount.indexOf('.') + 2]) return;
if (vm.amount == '0' && digit != '.') {
vm.amount = '';
}
if (vm.amount == '' && digit == '.') {
vm.amount = '0';
}
vm.amount = (vm.amount + digit).replace('..', '.');
processAmount();
}
function pushOperator(operator) {
if (!vm.amount || vm.amount.length == 0) return;
vm.amount = pushOperator(vm.amount);
function pushOperator(val) {
if (!isOperator(lodash.last(val))) {
return val + operator;
} else {
return val.slice(0, -1) + operator;
}
}
}
function isOperator(val) {
var regex = /[\/\-\+\x\*]/;
return regex.test(val);
}
function isExpression(val) {
var regex = /^\.?\d+(\.?\d+)?([\/\-\+\*x]\d?\.?\d+)+$/;
return regex.test(val);
}
function removeDigit() {
vm.amount = (vm.amount).toString().slice(0, -1);
processAmount();
}
function resetAmount() {
vm.amount = vm.alternativeAmount = vm.globalResult = '0';
vm.allowSend = false;
}
function openPopup() {
$ionicModal.fromTemplateUrl('views/modals/altCurrency.html', {
scope: $scope
}).then(function(modal) {
altCurrencyModal = modal;
altCurrencyModal.show();
});
}
function close() {
altCurrencyModal.remove();
altCurrencyModal = null;
}
function processAmount() {
var formatedValue = format(vm.amount);
var result = evaluate(formatedValue);
var amountInCrypto = 0;
if (lodash.isNumber(result)) {
vm.globalResult = isExpression(vm.amount) ? '= ' + processResult(result) : '';
if (availableUnits[unitIndex].isFiat) {
var a = fromFiat(result);
if (a) {
amountInCrypto = a;
var amountInSatoshis = a * unitToSatoshi;
vm.fundsAreInsufficient = !!passthroughParams.fromWalletId
&& walletSpendableAmount.satoshis !== null
&& walletSpendableAmount.satoshis < amountInSatoshis;
vm.alternativeAmount = txFormatService.formatAmount(amountInSatoshis, true);
vm.allowSend = lodash.isNumber(a)
&& a > 0
&& (!vm.minAmount || a >= vm.minAmount)
&& (!vm.maxAmount || a <= vm.maxAmount)
&& !vm.fundsAreInsufficient;
} else {
if (result) {
vm.alternativeAmount = 'N/A';
} else {
vm.alternativeAmount = null;
}
vm.fundsAreInsufficient = false;
vm.allowSend = false;
}
} else {
amountInCrypto = result;
vm.fundsAreInsufficient = passthroughParams.fromWalletId
&& walletSpendableAmount.satoshis !== null
&& walletSpendableAmount.satoshis < result * unitToSatoshi;
vm.alternativeAmount = $filter('formatFiatAmount')(toFiat(result));
vm.allowSend = lodash.isNumber(result)
&& result > 0
&& (!vm.minAmount || result >= vm.minAmount)
&& (!vm.maxAmount || result <= vm.maxAmount)
&& !vm.fundsAreInsufficient;
}
} else {
vm.fundsAreInsufficient = false;
}
if (vm.fundsAreInsufficient) {
vm.errorMessage = gettextCatalog.getString('Not enough available funds');
} else if (amountInCrypto && vm.thirdParty && vm.thirdParty.id === 'shapeshift') {
if (amountInCrypto < vm.minAmount) {
vm.errorMessage = gettextCatalog.getString('Amount is below minimum');
} else if (amountInCrypto > vm.maxAmount) {
vm.errorMessage = gettextCatalog.getString('Amount is above maximum');
} else {
vm.errorMessage = '';
}
} else {
vm.errorMessage = '';
}
}
function processResult(val) {
if (availableUnits[unitIndex].isFiat) return $filter('formatFiatAmount')(val);
else return txFormatService.formatAmount(val.toFixed(unitDecimals) * unitToSatoshi, true);
}
function fromFiat(val) {
return parseFloat((rateService.fromFiat(val, fiatCode, availableUnits[altUnitIndex].id) * satToUnit).toFixed(unitDecimals));
}
function toFiat(val) {
if (!rateService.getRate(fiatCode)) return;
return parseFloat((rateService.toFiat(val * unitToSatoshi, fiatCode, availableUnits[unitIndex].id)).toFixed(2));
}
function evaluate(val) {
var result;
try {
result = $scope.$eval(val);
} catch (e) {
return 0;
}
if (!lodash.isFinite(result)) return 0;
return result;
}
function format(val) {
if (!val) return;
var result = val.toString();
if (isOperator(lodash.last(val))) result = result.slice(0, -1);
return result.replace('x', '*');
}
function finish() {
var unit = availableUnits[unitIndex];
var uiAmount = evaluate(format(vm.amount));
var satoshis = 0;
if (unit.isFiat) {
satoshis = Math.floor(fromFiat(uiAmount) * unitToSatoshi);
} else {
satoshis = Math.floor(uiAmount * unitToSatoshi);
}
var confirmData = {
amount: (useSendMax && canSendMax) ? undefined : satoshis,
displayAddress: passthroughParams.displayAddress,
fromWalletId: passthroughParams.fromWalletId,
sendMax: useSendMax,
toAddress: passthroughParams.toAddress,
toWalletId: passthroughParams.toWalletId
};
if (vm.thirdParty) {
confirmData.thirdParty = vm.thirdParty;
}
if (!confirmData.fromWalletId) {
$state.transitionTo('tabs.paymentRequest.confirm', confirmData);
} else {
sendFlowService.goNext(confirmData);
useSendMax = false;
}
}
// Currency
var nextCurrencies = 10;
var completeAlternativeList = [];
var popularCurrencyList = [
{isoCode: 'USD', order: 0},
{isoCode: 'EUR', order: 1},
{isoCode: 'JPY', order: 2},
{isoCode: 'GBP', order: 3},
{isoCode: 'AUD', order: 4},
{isoCode: 'CAD', order: 5},
{isoCode: 'CHF', order: 6},
{isoCode: 'CNY', order: 7},
{isoCode: 'KRW', order: 8},
{isoCode: 'HKD', order: 9},
];
function initCurrencies() {
var unusedCurrencyList = [{
isoCode: 'LTL'
}, {
isoCode: 'BTC'
}, {
isoCode: 'BCC'
}, {
isoCode: 'BCH_BTC'
}, {
isoCode: 'BCH'
}];
rateService.whenAvailable(function() {
vm.listComplete = false;
var idx = lodash.indexBy(unusedCurrencyList, 'isoCode');
var idx2 = lodash.indexBy(lastUsedAltCurrencyList, 'isoCode');
var idx3 = lodash.indexBy(popularCurrencyList, 'isoCode');
var alternatives = rateService.listAlternatives(true);
lodash.each(alternatives, function(c) {
if (idx3[c.isoCode]) {
idx3[c.isoCode].name = c.name;
}
if (!idx[c.isoCode] && !idx2[c.isoCode] && !idx3[c.isoCode]) {
completeAlternativeList.push(c);
}
});
vm.altCurrencyList = completeAlternativeList.slice(0, 10);
vm.lastUsedPopularList = lodash.unique(lodash.union(lastUsedAltCurrencyList, popularCurrencyList), 'isoCode');
rateService.updateRates();
$timeout(function() {
$scope.$apply();
});
});
}
function loadMore() {
$timeout(function() {
vm.altCurrencyList = completeAlternativeList.slice(0, nextCurrencies);
nextCurrencies += 10;
vm.listComplete = vm.altCurrencyList.length >= completeAlternativeList.length;
$scope.$broadcast('scroll.infiniteScrollComplete');
}, 100);
}
function next() {
useSendMax = false;
vm.finish();
}
function findCurrency(search) {
if (!search) initCurrencies();
var list = lodash.unique(lodash.union(completeAlternativeList, lodash.union(lastUsedAltCurrencyList, popularCurrencyList)), 'isoCode');
vm.altCurrencyList = lodash.filter(list, function(item) {
var val = item.name
var val2 = item.isoCode;
return lodash.includes(val.toLowerCase(), search.toLowerCase()) || lodash.includes(val2.toLowerCase(), search.toLowerCase());
});
$timeout(function() {
$scope.$apply();
});
}
function save(newAltCurrency) {
var opts = {
wallet: {
settings: {
alternativeName: newAltCurrency.name,
alternativeIsoCode: newAltCurrency.isoCode,
}
}
};
configService.set(opts, function(err) {
if (err) $log.warn(err);
walletService.updateRemotePreferences(profileService.getWallets());
var altUnitIndex = lodash.findIndex(availableUnits, {
isFiat: true
});
availableUnits[altUnitIndex].id = newAltCurrency.isoCode;
availableUnits[altUnitIndex].name = newAltCurrency.isoCode;
availableUnits[altUnitIndex].shortName = newAltCurrency.isoCode;
fiatCode = newAltCurrency.isoCode;
updateAvailableFundsStringIfNeeded();
updateUnitUI();
close();
});
}
function updateAvailableFundsStringIfNeeded() {
if (passthroughParams.fromWalletId && walletSpendableAmount.satoshis !== null) {
vm.availableFunds = walletSpendableAmount.crypto;
if (availableUnits[unitIndex].isFiat) {
var coin = availableUnits[altUnitIndex].id;
txFormatService.formatAlternativeStr(coin, walletSpendableAmount.satoshis, function formatCallback(formatted){
if (formatted) {
$scope.$apply(function() {
vm.availableFunds = formatted;
});
}
});
}
updateMaximumButtonIfNeeded();
}
}
function updateAvailableFundsFromWallet(wallet) {
console.log('amount updateAvailableFundsFromWallet()');
var availableFundsInFiat = '';
if (wallet.status && wallet.status.isValid) {
walletSpendableAmount.crypto = wallet.status.spendableBalanceStr;
walletSpendableAmount.satoshis = wallet.status.spendableAmount;
if (wallet.status.alternativeBalanceAvailable) {
availableFundsInFiat = wallet.status.spendableBalanceAlternative + ' ' + wallet.status.alternativeIsoCode;
} else {
availableFundsInFiat = '';
}
} else if (wallet.cachedStatus && wallet.cachedStatus.isValid) {
if (wallet.cachedStatus.alternativeBalanceAvailable) {
availableFundsInFiat = wallet.cachedStatus.spendableBalanceAlternative + ' ' + wallet.cachedStatus.alternativeIsoCode;
} else {
availableFundsInFiat = '';
}
walletSpendableAmount.crypto = wallet.cachedStatus.spendableBalanceStr;
walletSpendableAmount.satoshis = wallet.cachedStatus.spendableAmount;
} else {
walletSpendableAmount.crypto = '';
walletSpendableAmount.satoshis = null;
}
if (availableUnits[unitIndex].isFiat) {
vm.availableFunds = availableFundsInFiat || walletSpendableAmount.crypto;
} else {
vm.availableFunds = walletSpendableAmount.crypto;
}
setMaximumButtonFromWallet(wallet);
}
function updateMaximumButtonIfNeeded() {
console.log('sendmax updateMaximumButtonIfNeeded()');
if (vm.showSendMaxButton || vm.showSendLimitMaxButton) {
transactionSendableAmount.fiat = '';
vm.sendableFunds = transactionSendableAmount.crypto;
if (availableUnits[unitIndex].isFiat) {
var coin = availableUnits[altUnitIndex].id;
txFormatService.formatAlternativeStr(coin, transactionSendableAmount.satoshis, function formatCallback(formatted){
if (formatted) {
$scope.$apply(function onApply() {
vm.sendableFunds = formatted;
});
}
});
}
}
}
function setMaximumButtonFromWallet(wallet) {
console.log('sendmax setMaximumButtonFromWallet()');
var minSatoshis = vm.minAmount * unitToSatoshi;
var maxSatoshis = vm.maxAmount * unitToSatoshi;
if (minSatoshis > walletSpendableAmount.satoshis) {
console.log('sendmax Hiding max buttons as minimum is too high.');
canSendMax = false;
vm.showSendMaxButton = true;
vm.showSendLimitMaxButton = false;
transactionSendableAmount.satoshis = walletSpendableAmount.satoshis;
} else if (maxSatoshis) {
if (walletSpendableAmount.satoshis > maxSatoshis) {
console.log('sendmax Showing max limit button as available is greater than max limit.');
canSendMax = false;
vm.showSendMaxButton = false;
vm.showSendLimitMaxButton = true;
transactionSendableAmount.satoshis = maxSatoshis;
} else {
console.log('sendmax Showing sendmax as all available as less than max limit.');
// Enabling send max here is a little dangerous, if they receive funds between pressing
// this and the calculation in the Review screen.
canSendMax = false;
vm.showSendMaxButton = true;
vm.showSendLimitMaxButton = false;
transactionSendableAmount.satoshis = walletSpendableAmount.satoshis;
}
} else {
console.log('sendmax Showing sendmax as all available because no limits.');
canSendMax = true;
vm.showSendMaxButton = true;
vm.showSendLimitMaxButton = false;
transactionSendableAmount.satoshis = walletSpendableAmount.satoshis;
}
if (vm.showSendMaxButton || vm.showSendLimitMaxButton) {
console.log('sendmax Setting max button text');
transactionSendableAmount.crypto = txFormatService.formatAmountStr(wallet.coin, transactionSendableAmount.satoshis);
vm.sendableFunds = transactionSendableAmount.crypto;
if (availableUnits[unitIndex].isFiat) {
txFormatService.formatAlternativeStr(wallet.coin, transactionSendableAmount.satoshis, function onFormat(formatted){
if (formatted) {
$scope.$apply(function onApply() {
vm.sendableFunds = formatted;
});
}
});
}
}
}
}
})();

View file

@ -0,0 +1,628 @@
'use strict';
angular.module('copayApp.controllers').controller('amountController', function($scope, $filter, $timeout, $ionicModal, $ionicScrollDelegate, $ionicHistory, storageService, walletService, gettextCatalog, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, txFormatService, ongoingProcess, popupService, bwcError, payproService, profileService, bitcore, amazonService, nodeWebkitService) {
var _id;
var unitToSatoshi;
var satToUnit;
var unitDecimals;
var satToBtc;
var SMALL_FONT_SIZE_LIMIT = 10;
var LENGTH_EXPRESSION_LIMIT = 19;
var LENGTH_BEFORE_COMMA_EXPRESSION_LIMIT = 8;
var LENGTH_AFTER_COMMA_EXPRESSION_LIMIT = 8;
var isNW = platformInfo.isNW;
var unitIndex = 0;
var altUnitIndex = 0;
var availableUnits = [];
var fiatCode;
var fixedUnit;
$scope.amountModel = { amount: 0 };
$scope.isChromeApp = platformInfo.isChromeApp;
$scope.isAndroid = platformInfo.isAndroid;
$scope.isIos = platformInfo.isIOS;
$scope.$on('$ionicView.leave', function() {
angular.element($window).off('keydown');
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
initCurrencies();
if (data.stateParams.shapeshiftOrderId && data.stateParams.shapeshiftOrderId.length > 0) {
$scope.minShapeshiftAmount = parseFloat(data.stateParams.minShapeshiftAmount);
$scope.maxShapeshiftAmount = parseFloat(data.stateParams.maxShapeshiftAmount);
$scope.shapeshiftOrderId = data.stateParams.shapeshiftOrderId;
$scope.fromWalletId = data.stateParams.fromWalletId;
}
if (data.stateParams.noPrefix) {
$scope.showWarningMessage = data.stateParams.noPrefix != 0;
if ($scope.showWarningMessage) {
var message = 'Address doesn\'t contain currency information, please make sure you are sending the correct currency.';
popupService.showAlert('', message, function() {}, 'Ok');
}
}
var config = configService.getSync().wallet.settings;
function setAvailableUnits() {
var defaults = configService.getDefaults();
var configCache = configService.getSync();
availableUnits = [];
var hasBCHWallets = profileService.getWallets({
coin: 'bch'
}).length;
if (hasBCHWallets) {
availableUnits.push({
name: 'Bitcoin Cash',
id: 'bch',
shortName: (configCache.bitcoinCashAlias || defaults.bitcoinCashAlias).toUpperCase(),
});
};
var hasBTCWallets = profileService.getWallets({
coin: 'btc'
}).length;
if (hasBTCWallets) {
availableUnits.push({
name: 'Bitcoin',
id: 'btc',
shortName: (configCache.bitcoinAlias || defaults.bitcoinAlias).toUpperCase(),
});
}
unitIndex = 0;
if (data.stateParams.coin) {
var coins = data.stateParams.coin.split(',');
var newAvailableUnits = [];
lodash.each(coins, function(c) {
var coin = lodash.find(availableUnits, {
id: c
});
if (!coin) {
$log.warn('Could not find desired coin:' + data.stateParams.coin)
} else {
newAvailableUnits.push(coin);
}
});
if (newAvailableUnits.length > 0) {
availableUnits = newAvailableUnits;
}
}
// currency have preference
var fiatName;
if (data.stateParams.currency) {
fiatCode = data.stateParams.currency;
altUnitIndex = unitIndex
unitIndex = availableUnits.length;
} else {
fiatCode = config.alternativeIsoCode || 'USD';
fiatName = config.alternanativeName || fiatCode;
altUnitIndex = availableUnits.length;
}
availableUnits.push({
name: fiatName || fiatCode,
// TODO
id: fiatCode,
shortName: fiatCode,
isFiat: true,
});
if (data.stateParams.fixedUnit) {
fixedUnit = true;
}
unitIndex = lodash.findIndex(availableUnits, {
isFiat: true
});
altUnitIndex = 0;
};
// Go to...
_id = data.stateParams.id; // Optional (BitPay Card ID or Wallet ID)
$scope.nextStep = data.stateParams.nextStep;
setAvailableUnits();
updateUnitUI();
$scope.hasMaxAmount = true;
if ($ionicHistory.backView().stateName == 'tabs.receive') {
$scope.hasMaxAmount = false;
}
$scope.showMenu = $ionicHistory.backView() && ($ionicHistory.backView().stateName == 'tabs.send' || $ionicHistory.backView().stateName == 'tabs.bitpayCard');
$scope.recipientType = data.stateParams.recipientType || null;
$scope.toAddress = data.stateParams.toAddress;
$scope.displayAddress = data.stateParams.displayAddress;
$scope.toName = data.stateParams.toName;
$scope.toEmail = data.stateParams.toEmail;
$scope.toColor = data.stateParams.toColor;
if (!$scope.nextStep && !data.stateParams.toAddress) {
$log.error('Bad params at amount')
throw ('bad params');
}
var reNr = /^[1234567890\.]$/;
var reOp = /^[\*\+\-\/]$/;
if (!$scope.isAndroid && !$scope.isIos) {
var disableKeys = angular.element($window).on('keydown', function(e) {
if (!e.key) return;
if (e.which === 8) { // you can add others here inside brackets.
if (!$scope.altCurrencyModal) {
e.preventDefault();
$scope.removeDigit();
}
}
if (e.key.match(reNr)) {
$scope.pushDigit(e.key);
} else if (e.key.match(reOp)) {
$scope.pushOperator(e.key);
} else if (e.keyCode === 86) {
if (e.ctrlKey || e.metaKey) processClipboard();
} else if (e.keyCode === 13) $scope.finish();
$timeout(function() {
$scope.$apply();
});
});
}
$scope.specificAmount = $scope.specificAlternativeAmount = '';
$scope.isCordova = platformInfo.isCordova;
unitToSatoshi = config.unitToSatoshi;
satToUnit = 1 / unitToSatoshi;
satToBtc = 1 / 100000000;
unitDecimals = config.unitDecimals;
$scope.resetAmount();
// in SAT ALWAYS
if ($stateParams.toAmount) {
$scope.amountModel.amount = (($stateParams.toAmount) * satToUnit).toFixed(unitDecimals);
}
$scope.processAmount();
$timeout(function() {
$ionicScrollDelegate.resize();
}, 10);
});
$scope.goBack = function() {
if ($scope.shapeshiftOrderId) {
$state.go('tabs.send').then(function() {
$ionicHistory.clearHistory();
$state.go('tabs.home').then(function() {
$state.transitionTo('tabs.shapeshift');
});
});
} else {
$ionicHistory.goBack();
}
}
function paste(value) {
$scope.amountModel.amount = value;
$scope.processAmount();
$timeout(function() {
$scope.$apply();
});
};
function processClipboard() {
if (!isNW) return;
var value = nodeWebkitService.readFromClipboard();
if (value && evaluate(value) > 0) paste(evaluate(value));
};
$scope.sendMax = function() {
$scope.useSendMax = true;
$scope.finish();
};
$scope.toggleAlternative = function() {
if ($scope.amountModel.amount && isExpression($scope.amountModel.amount)) {
var amount = evaluate(format($scope.amountModel.amount));
$scope.globalResult = '= ' + processResult(amount);
}
};
function updateUnitUI() {
$scope.unit = availableUnits[unitIndex].shortName;
$scope.alternativeUnit = availableUnits[altUnitIndex].shortName;
$scope.processAmount();
$log.debug('Update unit coin @amount unit:' + $scope.unit + " alternativeUnit:" + $scope.alternativeUnit);
};
$scope.changeUnit = function() {
$scope.amountModel.amount = '0';
if (fixedUnit) return;
if (!(availableUnits[unitIndex].isFiat && availableUnits.length > 2 && altUnitIndex == 0)) {
unitIndex++;
if (unitIndex >= availableUnits.length) unitIndex = 0;
}
if (availableUnits[unitIndex].isFiat) {
altUnitIndex = altUnitIndex == 0 && availableUnits.length > 2 ? 1 : 0;
} else {
altUnitIndex = lodash.findIndex(availableUnits, {
isFiat: true
});
}
updateUnitUI();
};
$scope.changeAlternativeUnit = function() {
// Do nothing is fiat is not main unit
if (!availableUnits[unitIndex].isFiat) return;
var nextCoin = lodash.findIndex(availableUnits, function(x) {
if (x.isFiat) return false;
if (x.id == availableUnits[altUnitIndex].id) return false;
return true;
});
if (nextCoin >= 0) {
altUnitIndex = nextCoin;
updateUnitUI();
}
};
function checkFontSize() {
if ($scope.amountModel.amount && $scope.amountModel.amount.length >= SMALL_FONT_SIZE_LIMIT) $scope.smallFont = true;
else $scope.smallFont = false;
};
$scope.pushDigit = function(digit) {
if ($scope.amountModel.amount && digit != '.') {
var amountSplitByComma = $scope.amountModel.amount.split('.');
if (amountSplitByComma.length > 1 && amountSplitByComma[1].length >= LENGTH_AFTER_COMMA_EXPRESSION_LIMIT) return;
if (amountSplitByComma.length == 1 && amountSplitByComma[0].length >= LENGTH_BEFORE_COMMA_EXPRESSION_LIMIT) return;
}
if ($scope.amountModel.amount && $scope.amountModel.amount.length >= LENGTH_EXPRESSION_LIMIT) return;
if (($scope.amountModel.amount.indexOf('.') > -1 || $scope.amountModel.amount == '') && digit == '.') return;
if ($scope.amountModel.amount == '0' && digit == '0') return;
if (availableUnits[unitIndex].isFiat && $scope.amountModel.amount.indexOf('.') > -1 && $scope.amountModel.amount[$scope.amountModel.amount.indexOf('.') + 2]) return;
if ($scope.amountModel.amount == '0' && digit != '.') { $scope.amountModel.amount = ''}
$scope.amountModel.amount = ($scope.amountModel.amount + digit).replace('..', '.');
checkFontSize();
$scope.processAmount();
navigator.vibrate(50);
};
$scope.pushOperator = function(operator) {
if (!$scope.amountModel.amount || $scope.amountModel.amount.length == 0) return;
$scope.amountModel.amount = _pushOperator($scope.amountModel.amount);
function _pushOperator(val) {
if (!isOperator(lodash.last(val))) {
return val + operator;
} else {
return val.slice(0, -1) + operator;
}
};
};
function isOperator(val) {
var regex = /[\/\-\+\x\*]/;
return regex.test(val);
};
function isExpression(val) {
var regex = /^\.?\d+(\.?\d+)?([\/\-\+\*x]\d?\.?\d+)+$/;
return regex.test(val);
};
$scope.removeDigit = function() {
$scope.amountModel.amount = ($scope.amountModel.amount).toString().slice(0, -1);
$scope.processAmount();
checkFontSize();
};
$scope.resetAmount = function() {
$scope.amountModel.amount = $scope.alternativeAmount = $scope.globalResult = '';
$scope.allowSend = false;
checkFontSize();
navigator.vibrate(50);
};
$scope.openPopup = function() {
$ionicModal.fromTemplateUrl('views/modals/altCurrency.html', {
scope: $scope
}).then(function(modal) {
$scope.altCurrencyModal = modal;
$scope.altCurrencyModal.show();
});
};
$scope.close = function() {
$scope.altCurrencyModal.remove();
$scope.altCurrencyModal = false;
};
$scope.processAmount = function() {
var formatedValue = format($scope.amountModel.amount);
var result = evaluate(formatedValue);
if (lodash.isNumber(result)) {
$scope.globalResult = isExpression($scope.amountModel.amount) ? '= ' + processResult(result) : '';
if (availableUnits[unitIndex].isFiat) {
var a = fromFiat(result);
if (a) {
$scope.alternativeAmount = txFormatService.formatAmount(a * unitToSatoshi, true);
$scope.allowSend = lodash.isNumber(a) && a > 0
&& (!$scope.shapeshiftOrderId
|| (a >= $scope.minShapeshiftAmount && a <= $scope.maxShapeshiftAmount));
} else {
if (result) {
$scope.alternativeAmount = 'N/A';
} else {
$scope.alternativeAmount = null;
}
$scope.allowSend = false;
}
} else {
$scope.alternativeAmount = $filter('formatFiatAmount')(toFiat(result));
$scope.allowSend = lodash.isNumber(result) && result > 0
&& (!$scope.shapeshiftOrderId
|| (result >= $scope.minShapeshiftAmount && result <= $scope.maxShapeshiftAmount));
}
}
};
function processResult(val) {
if (availableUnits[unitIndex].isFiat) return $filter('formatFiatAmount')(val);
else return txFormatService.formatAmount(val.toFixed(unitDecimals) * unitToSatoshi, true);
};
function fromFiat(val) {
return parseFloat((rateService.fromFiat(val, fiatCode, availableUnits[altUnitIndex].id) * satToUnit).toFixed(unitDecimals));
};
function toFiat(val) {
if (!rateService.getRate(fiatCode)) return;
return parseFloat((rateService.toFiat(val * unitToSatoshi, fiatCode, availableUnits[unitIndex].id)).toFixed(2));
};
function evaluate(val) {
var result;
try {
result = $scope.$eval(val);
} catch (e) {
return 0;
}
if (!lodash.isFinite(result)) return 0;
return result;
};
function format(val) {
if (!val) return;
var result = val.toString();
if (isOperator(lodash.last(val))) result = result.slice(0, -1);
return result.replace('x', '*');
};
$scope.finish = function() {
function finish() {
var unit = availableUnits[unitIndex];
var _amount = evaluate(format($scope.amountModel.amount));
var coin = unit.id;
if (unit.isFiat) {
coin = availableUnits[altUnitIndex].id;
}
if ($scope.nextStep) {
$state.transitionTo($scope.nextStep, {
id: _id,
amount: $scope.useSendMax ? null : _amount,
currency: unit.id.toUpperCase(),
coin: coin,
useSendMax: $scope.useSendMax
});
} else {
var amount = _amount;
if (unit.isFiat) {
amount = (fromFiat(amount) * unitToSatoshi).toFixed(0);
} else {
amount = (amount * unitToSatoshi).toFixed(0);
}
var confirmData = {
recipientType: $scope.recipientType,
toAmount: amount,
toAddress: $scope.toAddress,
displayAddress: $scope.displayAddress || $scope.toAddress,
toName: $scope.toName,
toEmail: $scope.toEmail,
toColor: $scope.toColor,
coin: coin,
useSendMax: $scope.useSendMax,
};
if ($scope.shapeshiftOrderId) {
var shapeshiftOrderUrl = 'https://www.shapeshift.io/#/status/';
shapeshiftOrderUrl += $scope.shapeshiftOrderId;
confirmData.description = shapeshiftOrderUrl;
confirmData.fromWalletId = $scope.fromWalletId;
if (confirmData.useSendMax) {
var wallet = lodash.find(profileService.getWallets({ coin: coin }),
function(w) {
return w.id == $scope.fromWalletId;
});
var balance = parseFloat(wallet.cachedBalance.substring(0, wallet.cachedBalance.length-4));
if (balance < $scope.minShapeshiftAmount * 1.04) {
confirmData.useSendMax = false;
confirmData.toAmount = $scope.minShapeshiftAmount * unitToSatoshi;
} else if (balance > $scope.maxShapeshiftAmount) {
confirmData.useSendMax = false;
confirmData.toAmount = $scope.maxShapeshiftAmount * unitToSatoshi * 0.99;
}
}
}
$state.transitionTo('tabs.send.confirm', confirmData);
}
$scope.useSendMax = null;
}
if ($scope.showWarningMessage) {
var u = $scope.unit == 'BCH' || $scope.unit == 'BTC' ? $scope.unit : $scope.alternativeUnit;
var message = 'Are you sure you want to send ' + u.toUpperCase() + '?';
popupService.showConfirm(message, '', 'Yes', 'No', function(res) {
if (!res) {
$scope.useSendMax = null;
return;
};
finish();
});
} else {
finish();
}
};
// Currency
var next = 10;
var completeAlternativeList = [];
var popularCurrencyList = [
{isoCode: 'USD', order: 0},
{isoCode: 'EUR', order: 1},
{isoCode: 'JPY', order: 2},
{isoCode: 'GBP', order: 3},
{isoCode: 'AUD', order: 4},
{isoCode: 'CAD', order: 5},
{isoCode: 'CHF', order: 6},
{isoCode: 'CNY', order: 7},
{isoCode: 'KRW', order: 8},
{isoCode: 'HKD', order: 9},
]
function initCurrencies() {
var unusedCurrencyList = [{
isoCode: 'LTL'
}, {
isoCode: 'BTC'
}, {
isoCode: 'BCC'
}, {
isoCode: 'BCH_BTC'
}, {
isoCode: 'BCH'
}];
rateService.whenAvailable(function() {
$scope.listComplete = false;
var idx = lodash.indexBy(unusedCurrencyList, 'isoCode');
var idx2 = lodash.indexBy($scope.lastUsedAltCurrencyList, 'isoCode');
var idx3 = lodash.indexBy(popularCurrencyList, 'isoCode');
var alternatives = rateService.listAlternatives(true);
lodash.each(alternatives, function(c) {
if (idx3[c.isoCode]) {
idx3[c.isoCode].name = c.name;
}
if (!idx[c.isoCode] && !idx2[c.isoCode] && !idx3[c.isoCode]) {
completeAlternativeList.push(c);
}
});
$scope.altCurrencyList = completeAlternativeList.slice(0, 10);
$scope.lastUsedPopularList = lodash.unique(lodash.union($scope.lastUsedAltCurrencyList, popularCurrencyList), 'isoCode');
$timeout(function() {
$scope.$apply();
});
});
}
$scope.loadMore = function() {
$timeout(function() {
$scope.altCurrencyList = completeAlternativeList.slice(0, next);
next += 10;
$scope.listComplete = $scope.altCurrencyList.length >= completeAlternativeList.length;
$scope.$broadcast('scroll.infiniteScrollComplete');
}, 100);
};
$scope.findCurrency = function(search) {
if (!search) initCurrencies();
var list = lodash.unique(lodash.union(completeAlternativeList, lodash.union($scope.lastUsedAltCurrencyList, popularCurrencyList)), 'isoCode');
$scope.altCurrencyList = lodash.filter(list, function(item) {
var val = item.name
var val2 = item.isoCode;
return lodash.includes(val.toLowerCase(), search.toLowerCase()) || lodash.includes(val2.toLowerCase(), search.toLowerCase());
});
$timeout(function() {
$scope.$apply();
});
};
$scope.save = function(newAltCurrency) {
var opts = {
wallet: {
settings: {
alternativeName: newAltCurrency.name,
alternativeIsoCode: newAltCurrency.isoCode,
}
}
};
configService.set(opts, function(err) {
if (err) $log.warn(err);
walletService.updateRemotePreferences(profileService.getWallets());
var altUnitIndex = lodash.findIndex(availableUnits, {
isFiat: true
});
availableUnits[altUnitIndex].id = newAltCurrency.isoCode;
availableUnits[altUnitIndex].name = newAltCurrency.isoCode;
availableUnits[altUnitIndex].shortName = newAltCurrency.isoCode;
fiatCode = newAltCurrency.isoCode;
updateUnitUI();
$scope.close();
});
};
});

View file

@ -1,604 +0,0 @@
describe('amountController', function(){
var configCache,
configService,
gettextCatalog,
$controller,
$ionicHistory,
$rootScope,
ongoingProcess,
platformInfo,
popupService,
profileService,
rateService,
sendFlowService,
shapeshiftService,
txFormatService,
$scope,
$state,
$stateParams;
beforeEach(function(){
module('ngLodash');
module('copayApp.controllers');
configCache = {
wallet: {
settings: {
unitToSatoshi: 100000000
}
}
};
configService = jasmine.createSpyObj(['getDefaults','getSync']);
configService.getDefaults.and.returnValue({
bitcoinCashAlias: 'bch',
bitcoinAlias: 'btc'
});
configService.getSync.and.returnValue(configCache);
gettextCatalog = jasmine.createSpyObj(['getString']);
gettextCatalog.getString.and.callFake(function(str){ return str; });
$ionicHistory = jasmine.createSpyObj(['backView']);
ongoingProcess = jasmine.createSpyObj(['set']);
platformInfo = {
isChromeApp: false,
isAndroid: false,
isIos: true
};
popupService = jasmine.createSpyObj(['showAlert']);
profileService = jasmine.createSpyObj(['getWallet', 'getWallets']);
rateService = jasmine.createSpyObj(['fromFiat', 'listAlternatives', 'updateRates', 'whenAvailable']);
sendFlowService = jasmine.createSpyObj(['getStateClone', 'pushState']);
shapeshiftService = jasmine.createSpyObj(['getMarketData']);
txFormatService = jasmine.createSpyObj(['formatAlternativeStr', 'formatAmountStr']);
txFormatService.formatAlternativeStr.and.callFake(function(coin, satoshis, cb) {
if (typeof satoshis !== "number") {
throw "satoshis in formatAlternativeStr() is not a number."
}
var units = satoshis / 100000000;
var formatted = (units * 10000).toFixed(2) + ' USD';
cb(formatted);
});
txFormatService.formatAmountStr.and.callFake(function(coin, satoshis) {
if (typeof satoshis !== "number") {
throw "satoshis in formatAmountStr() is not a number."
}
return (satoshis * 100000000).toFixed(8) + ' ' + (coin || 'bch').toUpperCase();
});
$state = jasmine.createSpyObj(['transitionTo']);
$stateParams = {};
inject(function(_$controller_, _$rootScope_){
// The injector unwraps the underscores (_) from around the parameter names when matching
$controller = _$controller_;
$rootScope = _$rootScope_;
});
});
it('receives fromWalletId and toAddress.', function() {
var backView = {
stateName: 'ignoreme'
};
$ionicHistory.backView.and.returnValue(backView);
var wallet = {
status: {
isValid: true,
spendableAmount: 123456
}
};
profileService.getWallet.and.returnValue(wallet);
profileService.getWallets.and.returnValue([{}]);
rateService.fromFiat.and.returnValue(12); // satoshis or coins?
var $scope = $rootScope.$new();
var amountController = $controller('amountController', {
configService: configService,
gettextCatalog: gettextCatalog,
$ionicHistory: $ionicHistory,
$ionicModal: {},
$ionicScrollDelegate: {},
nodeWebkitService: {},
ongoingProcess: ongoingProcess,
platformInfo: platformInfo,
profileService: profileService,
popupService: popupService,
rateService: rateService,
$scope: $scope,
sendFlowService: sendFlowService,
shapeshiftService: shapeshiftService,
$state: {},
$stateParams: $stateParams,
txFormatService: txFormatService,
walletService: {}
});
var sendFlowState = {
fromWalletId: 'fd56c1e7-e3ac-4fd9-8afc-27b9c1b3718b',
toAddress: 'qrup46avn8t466xxwlzs4qelht7cnwvesv2e29wf7s'
};
sendFlowService.getStateClone.and.returnValue(sendFlowState);
$scope.$emit('$ionicView.beforeEnter', {});
//expect($scope.fromWalletId).toBe('fd56c1e7-e3ac-4fd9-8afc-27b9c1b3718b');
//expect($scope.toAddress).toBe('qrup46avn8t466xxwlzs4qelht7cnwvesv2e29wf7s');
});
describe('Shapeshift', function() {
var walletFrom;
var walletTo;
beforeEach(function(){
walletFrom = {};
walletTo = {};
profileService.getWallet.and.callFake(function(walletId){
if (walletId === '4cd7673e-7320-4dfa-86e5-d4edb51d460a') {
return walletFrom;
} else if (walletId === 'bf00af8f-0788-4b57-b30a-0390747407e9') {
return walletTo;
} else {
return null;
}
});
rateService.listAlternatives.and.returnValue([
{name: "Australian Dollar", isoCode: "AUD"},
{name: "United States Dollar", isoCode: "USD"}
]);
});
it ('with available balance below limit, shows sendMax for triggering alert', function() {
walletFrom.coin = 'btc';
walletFrom.status = {
isValid: true,
spendableAmount: 789
};
walletTo.coin = 'bch';
profileService.getWallets.and.returnValue([{}]);
rateService.fromFiat.and.returnValue(12);
var $scope = $rootScope.$new();
var amountController = $controller('amountController', {
configService: configService,
gettextCatalog: gettextCatalog,
$ionicHistory: $ionicHistory,
$ionicModal: {},
$ionicScrollDelegate: {},
nodeWebkitService: {},
ongoingProcess: ongoingProcess,
platformInfo: platformInfo,
profileService: profileService,
popupService: popupService,
rateService: rateService,
$scope: $scope,
sendFlowService: sendFlowService,
shapeshiftService: shapeshiftService,
$state: $state,
$stateParams: $stateParams,
txFormatService: txFormatService,
walletService: {}
});
rateService.whenAvailable.and.callFake(function(cb){
cb();
});
var sendFlowState = {
amount: '',
displayAddress: null,
fromWalletId: '4cd7673e-7320-4dfa-86e5-d4edb51d460a',
sendMax: false,
thirdParty: {
id: 'shapeshift',
data: {},
},
toAddress: '',
toWalletId: 'bf00af8f-0788-4b57-b30a-0390747407e9'
};
sendFlowService.getStateClone.and.returnValue(sendFlowState);
var reqCoinIn = '';
var reqCoinOut = '';
shapeshiftService.getMarketData.and.callFake(function(coinIn, coinOut, cb){
reqCoinIn = coinIn;
reqCoinOut = coinOut;
cb({
maxLimit: '0.6846239',
minimum: '0.00013692'
});
});
$scope.$emit('$ionicView.beforeEnter', {});
expect(rateService.updateRates.calls.any()).toEqual(true);
expect(reqCoinIn).toBe('btc');
expect(reqCoinOut).toBe('bch');
expect(amountController.maxAmount).toBe(0.68462390);
expect(amountController.minAmount).toBe(0.00013692);
expect(amountController.showSendMaxButton).toEqual(true);
expect(amountController.showSendLimitMaxButton).toEqual(false);
expect(amountController.sendableFunds).toEqual('0.08 USD');
// Now hit the Send Max button
amountController.sendMax();
expect(popupService.showAlert.calls.argsFor(0)[0]).toEqual('Insufficient funds');
expect(popupService.showAlert.calls.argsFor(0)[1]).toEqual('Amount below minimum allowed');
expect(sendFlowService.pushState.calls.any()).toEqual(false);
expect($state.transitionTo.calls.any()).toEqual(false);
});
it ('with available balance between limits, uses sendMax', function() {
walletFrom.coin = 'btc';
walletFrom.status = {
isValid: true,
spendableAmount: 456789
};
walletTo.coin = 'bch';
profileService.getWallets.and.returnValue([{}]);
rateService.fromFiat.and.returnValue(12);
var $scope = $rootScope.$new();
var amountController = $controller('amountController', {
configService: configService,
gettextCatalog: {},
$ionicHistory: $ionicHistory,
$ionicModal: {},
$ionicScrollDelegate: {},
nodeWebkitService: {},
ongoingProcess: ongoingProcess,
platformInfo: platformInfo,
profileService: profileService,
popupService: {},
rateService: rateService,
$scope: $scope,
sendFlowService: sendFlowService,
shapeshiftService: shapeshiftService,
$state: $state,
$stateParams: $stateParams,
txFormatService: txFormatService,
walletService: {}
});
rateService.whenAvailable.and.callFake(function(cb){
cb();
});
var sendFlowState = {
amount: '',
displayAddress: null,
fromWalletId: '4cd7673e-7320-4dfa-86e5-d4edb51d460a',
sendMax: false,
thirdParty: {
id: 'shapeshift',
data: {},
},
toAddress: '',
toWalletId: 'bf00af8f-0788-4b57-b30a-0390747407e9'
};
sendFlowService.getStateClone.and.returnValue(sendFlowState);
var reqCoinIn = '';
var reqCoinOut = '';
shapeshiftService.getMarketData.and.callFake(function(coinIn, coinOut, cb){
reqCoinIn = coinIn;
reqCoinOut = coinOut;
cb({
maxLimit: '0.6846239',
minimum: '0.00013692'
});
});
$scope.$emit('$ionicView.beforeEnter', {});
expect(rateService.updateRates.calls.any()).toEqual(true);
expect(reqCoinIn).toBe('btc');
expect(reqCoinOut).toBe('bch');
expect(amountController.maxAmount).toBe(0.68462390);
expect(amountController.minAmount).toBe(0.00013692);
expect(amountController.showSendMaxButton).toEqual(true);
expect(amountController.showSendLimitMaxButton).toEqual(false);
// Now hit the Send Max button
var pushedState = null;
sendFlowService.pushState.and.callFake(function (sendFlowState){
pushedState = sendFlowState;
});
amountController.sendMax();
expect(pushedState.amount).toBeUndefined();
expect(pushedState.fromWalletId).toEqual('4cd7673e-7320-4dfa-86e5-d4edb51d460a');
expect(pushedState.sendMax).toEqual(true);
expect(pushedState.toWalletId).toEqual('bf00af8f-0788-4b57-b30a-0390747407e9');
expect(pushedState.thirdParty.id).toEqual('shapeshift');
expect(pushedState.thirdParty.data.maxAmount).toEqual(0.6846239);
expect(pushedState.thirdParty.data.minAmount).toEqual(0.00013692);
expect($state.transitionTo.calls.count()).toEqual(1);
expect($state.transitionTo.calls.argsFor(0)[0]).toEqual('tabs.send.review');
});
it ('with available balance higher than max, uses send limit max instead of sendMax', function() {
walletFrom.coin = 'btc';
walletFrom.status = {
isValid: true,
spendableAmount: 123456789
};
walletTo.coin = 'bch';
profileService.getWallets.and.returnValue([{}]);
rateService.fromFiat.and.returnValue(12); // satoshis or coins?
var $scope = $rootScope.$new();
var amountController = $controller('amountController', {
configService: configService,
gettextCatalog: {},
$ionicHistory: $ionicHistory,
$ionicModal: {},
$ionicScrollDelegate: {},
nodeWebkitService: {},
ongoingProcess: ongoingProcess,
platformInfo: platformInfo,
profileService: profileService,
popupService: {},
rateService: rateService,
$scope: $scope,
sendFlowService: sendFlowService,
shapeshiftService: shapeshiftService,
$state: $state,
$stateParams: $stateParams,
txFormatService: txFormatService,
walletService: {}
});
rateService.whenAvailable.and.callFake(function(cb){
cb();
});
var sendFlowState = {
amount: '',
displayAddress: null,
fromWalletId: '4cd7673e-7320-4dfa-86e5-d4edb51d460a',
sendMax: false,
thirdParty: {
id: 'shapeshift',
data: {},
},
toAddress: '',
toWalletId: 'bf00af8f-0788-4b57-b30a-0390747407e9'
};
sendFlowService.getStateClone.and.returnValue(sendFlowState);
var reqCoinIn = '';
var reqCoinOut = '';
shapeshiftService.getMarketData.and.callFake(function(coinIn, coinOut, cb){
reqCoinIn = coinIn;
reqCoinOut = coinOut;
cb({
maxLimit: '0.6846239',
minimum: '0.00013692'
});
});
$scope.$emit('$ionicView.beforeEnter', {});
expect(rateService.updateRates.calls.any()).toEqual(true);
expect(reqCoinIn).toBe('btc');
expect(reqCoinOut).toBe('bch');
expect(amountController.maxAmount).toBe(0.6846239);
expect(amountController.minAmount).toBe(0.00013692);
expect(amountController.showSendMaxButton).toEqual(false);
expect(amountController.showSendLimitMaxButton).toEqual(true);
// Now hit the Send Max button
var pushedState = null;
sendFlowService.pushState.and.callFake(function (sendFlowState){
pushedState = sendFlowState;
});
amountController.sendMax();
expect(pushedState.amount).toEqual(68462390);
expect(pushedState.fromWalletId).toEqual('4cd7673e-7320-4dfa-86e5-d4edb51d460a');
expect(pushedState.sendMax).toEqual(false);
expect(pushedState.toWalletId).toEqual('bf00af8f-0788-4b57-b30a-0390747407e9');
expect(pushedState.thirdParty.id).toEqual('shapeshift');
expect(pushedState.thirdParty.data.maxAmount).toEqual(0.6846239);
expect(pushedState.thirdParty.data.minAmount).toEqual(0.00013692);
expect($state.transitionTo.calls.count()).toEqual(1);
expect($state.transitionTo.calls.argsFor(0)[0]).toEqual('tabs.send.review');
});
});
describe('Wallet transfer', function() {
var walletFrom;
var walletTo;
beforeEach(function(){
walletFrom = {};
walletTo = {};
profileService.getWallet.and.callFake(function(walletId){
if (walletId === '4cd7673e-7320-4dfa-86e5-d4edb51d460a') {
return walletFrom;
} else if (walletId === 'bf00af8f-0788-4b57-b30a-0390747407e9') {
return walletTo;
} else {
return null;
}
});
rateService.listAlternatives.and.returnValue([
{name: "Australian Dollar", isoCode: "AUD"},
{name: "United States Dollar", isoCode: "USD"}
]);
});
it('wallet transfer send max.', function() {
walletFrom.coin = 'btc';
walletFrom.status = {
isValid: true,
spendableAmount: 123456789
};
profileService.getWallets.and.returnValue([{}]);
var $scope = $rootScope.$new();
var amountController = $controller('amountController', {
configService: configService,
gettextCatalog: gettextCatalog,
$ionicHistory: $ionicHistory,
$ionicModal: {},
$ionicScrollDelegate: {},
nodeWebkitService: {},
ongoingProcess: ongoingProcess,
platformInfo: platformInfo,
profileService: profileService,
popupService: popupService,
rateService: rateService,
$scope: $scope,
sendFlowService: sendFlowService,
shapeshiftService: shapeshiftService,
$state: $state,
$stateParams: $stateParams,
txFormatService: txFormatService,
walletService: {}
});
var sendFlowState = {
fromWalletId: '4cd7673e-7320-4dfa-86e5-d4edb51d460a',
toWalletId: 'bf00af8f-0788-4b57-b30a-0390747407e9'
};
sendFlowService.getStateClone.and.returnValue(sendFlowState);
$scope.$emit('$ionicView.beforeEnter', {});
expect(amountController.showSendMaxButton).toEqual(true);
expect(amountController.showSendLimitMaxButton).toEqual(false);
expect(amountController.sendableFunds).toEqual('12345.68 USD');
// Now hit the Send Max button
var pushedState = null;
sendFlowService.pushState.and.callFake(function (sendFlowState){
pushedState = sendFlowState;
});
amountController.sendMax();
expect(pushedState.amount).toBeUndefined();
expect(pushedState.fromWalletId).toEqual('4cd7673e-7320-4dfa-86e5-d4edb51d460a');
expect(pushedState.sendMax).toEqual(true);
expect(pushedState.toWalletId).toEqual('bf00af8f-0788-4b57-b30a-0390747407e9');
expect($state.transitionTo.calls.count()).toEqual(1);
expect($state.transitionTo.calls.argsFor(0)[0]).toEqual('tabs.send.review');
});
// This situation was seen in real life
it('wallet transfer with valid cached status only.', function() {
walletFrom.coin = 'btc';
walletFrom.status = {
isValid: false,
};
walletFrom.cachedStatus = {
isValid: true,
spendableAmount: 5678
};
profileService.getWallets.and.returnValue([{}]);
var $scope = $rootScope.$new();
var amountController = $controller('amountController', {
configService: configService,
gettextCatalog: gettextCatalog,
$ionicHistory: $ionicHistory,
$ionicModal: {},
$ionicScrollDelegate: {},
nodeWebkitService: {},
ongoingProcess: ongoingProcess,
platformInfo: platformInfo,
profileService: profileService,
popupService: popupService,
rateService: rateService,
$scope: $scope,
sendFlowService: sendFlowService,
shapeshiftService: shapeshiftService,
$state: $state,
$stateParams: $stateParams,
txFormatService: txFormatService,
walletService: {}
});
var sendFlowState = {
fromWalletId: '4cd7673e-7320-4dfa-86e5-d4edb51d460a',
toWalletId: 'bf00af8f-0788-4b57-b30a-0390747407e9'
};
sendFlowService.getStateClone.and.returnValue(sendFlowState);
$scope.$emit('$ionicView.beforeEnter', {});
expect(amountController.showSendMaxButton).toEqual(true);
expect(amountController.showSendLimitMaxButton).toEqual(false);
expect(amountController.sendableFunds).toEqual('0.57 USD');
});
});
});

View file

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('backupController',
function($scope, $timeout, $log, $state, $stateParams, $ionicHistory, lodash, profileService, bwcService, walletService, ongoingProcess, popupService, gettextCatalog, $ionicModal) {
function($scope, $timeout, $log, $state, $stateParams, $ionicHistory, lodash, profileService, bwcService, walletService, ongoingProcess, popupService, gettextCatalog, $ionicModal, firebaseEventsService) {
if ($state.current.name == 'onboarding.backup') {
$scope.onboarding = true;
@ -89,8 +89,7 @@ angular.module('copayApp.controllers').controller('backupController',
$scope.setFlow(2);
})
} else {
//firebaseEventsService.logEvent('backed_up_wallet');
firebaseEventsService.logEvent('backed_up_wallet');
openConfirmBackupModal();
}
};

View file

@ -1,9 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('buyBitcoindotcomController',
function($scope, platformInfo, externalLinkService) {
$scope.os = platformInfo.isAndroid ? 'android' : platformInfo.isIOS ? 'ios' : 'desktop';
function($scope, $timeout, $ionicModal, $log, $state, $ionicHistory, lodash, bitcoincomService, externalLinkService, popupService) {
$scope.openExternalLink = function(url) {
externalLinkService.open(url);

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('communityController', function($scope, communityService, $ionicScrollDelegate, $timeout, platformInfo, configService, externalLinkService) {
angular.module('copayApp.controllers').controller('communityController', function($scope, communityService, $ionicScrollDelegate, $timeout, platformInfo, configService) {
$scope.hide = false;
@ -29,7 +29,7 @@ angular.module('copayApp.controllers').controller('communityController', functio
}
$scope.open = function(url) {
externalLinkService.open(url, false);
window.open(url, '_system');
}
});

View file

@ -1,20 +1,25 @@
'use strict';
angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $timeout, $ionicScrollDelegate, $ionicLoading, ionicToast, addressbookService, gettextCatalog, walletService, platformInfo, lodash, configService, $state, $log, profileService, bitcore, bitcoreCash, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, feeService, bitcoinCashJsService, bwcError, txConfirmNotification, soundService, clipboardService) {
angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, $stateParams, $window, $state, $log, profileService, bitcore, bitcoreCash, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, payproService, feeService, bwcError, txConfirmNotification, externalLinkService, firebaseEventsService) {
var countDown = null;
var FEE_TOO_HIGH_LIMIT_PER = 15;
var tx = {};
var lastTxId = "";
// Config Related values
var config = configService.getSync();
var walletConfig = config.wallet;
var unitToSatoshi = walletConfig.settings.unitToSatoshi;
var unitDecimals = walletConfig.settings.unitDecimals;
var satToUnit = 1 / unitToSatoshi;
var configFeeLevel = walletConfig.settings.feeLevel ? walletConfig.settings.feeLevel : 'normal';
// Platform info
var isChromeApp = platformInfo.isChromeApp;
var isCordova = platformInfo.isCordova;
var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP;
//custom fee flag
var usingCustomFee = false;
@ -26,16 +31,6 @@ angular.module('copayApp.controllers').controller('confirmController', function(
}, 10);
}
$scope.shareTransaction = function() {
var explorerTxUrl = 'https://explorer.bitcoin.com/'+tx.coin+'/tx/'+lastTxId;
if (platformInfo.isCordova) {
var text = 'Take a look at this Bitcoin transaction here: '+explorerTxUrl;
window.plugins.socialsharing.share(text, null, null, null);
} else {
ionicToast.show(gettextCatalog.getString('Copied to clipboard'), 'bottom', false, 3000);
clipboardService.copyToClipboard(explorerTxUrl);
}
};
$scope.showWalletSelector = function() {
$scope.walletSelector = true;
@ -50,6 +45,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
$ionicConfig.views.swipeBackEnabled(false);
});
function exitWithError(err) {
$log.info('Error setting wallet selector:' + err);
popupService.showAlert(gettextCatalog.getString(), bwcError.msg(err), function() {
@ -72,108 +68,112 @@ angular.module('copayApp.controllers').controller('confirmController', function(
});
};
var setWalletSelector = function(coin, network, minAmount, cb) {
$scope.$on("$ionicView.beforeEnter", function(event, data) {
// no min amount? (sendMax) => look for no empty wallets
minAmount = minAmount || 1;
function setWalletSelector(coin, network, minAmount, cb) {
$scope.wallets = profileService.getWallets({
onlyComplete: true,
network: network,
coin: coin
});
// no min amount? (sendMax) => look for no empty wallets
minAmount = minAmount || 1;
if (tx.fromWalletId) {
$scope.wallets = lodash.filter($scope.wallets, function (w) {
return w.id == tx.fromWalletId;
$scope.wallets = profileService.getWallets({
onlyComplete: true,
network: network,
coin: coin
});
}
if (tx.fromWalletId) {
$scope.wallets = lodash.filter($scope.wallets, function(w) {
return w.id == tx.fromWalletId;
});
}
if (!$scope.wallets || !$scope.wallets.length) {
setNoWallet(gettextCatalog.getString('No wallets available'), true);
return cb();
}
var filteredWallets = [];
var index = 0;
var walletsUpdated = 0;
if (!$scope.wallets || !$scope.wallets.length) {
setNoWallet(gettextCatalog.getString('No wallets available'), true);
return cb();
}
lodash.each($scope.wallets, function (w) {
walletService.getStatus(w, {}, function (err, status) {
if (err || !status) {
$log.error(err);
} else {
walletsUpdated++;
w.status = status;
var filteredWallets = [];
var index = 0;
var walletsUpdated = 0;
if (!status.availableBalanceSat)
$log.debug('No balance available in: ' + w.name);
lodash.each($scope.wallets, function(w) {
walletService.getStatus(w, {}, function(err, status) {
if (err || !status) {
$log.error(err);
} else {
walletsUpdated++;
w.status = status;
if (status.availableBalanceSat > minAmount) {
filteredWallets.push(w);
if (!status.availableBalanceSat)
$log.debug('No balance available in: ' + w.name);
if (status.availableBalanceSat > minAmount) {
filteredWallets.push(w);
}
}
}
if (++index == $scope.wallets.length) {
if (!walletsUpdated)
return cb('Could not update any wallet');
if (++index == $scope.wallets.length) {
if (!walletsUpdated)
return cb('Could not update any wallet');
if (lodash.isEmpty(filteredWallets)) {
setNoWallet(gettextCatalog.getString('Insufficient confirmed funds'), true);
if (lodash.isEmpty(filteredWallets)) {
setNoWallet(gettextCatalog.getString('Insufficient confirmed funds'), true);
}
$scope.wallets = lodash.clone(filteredWallets);
return cb();
}
$scope.wallets = lodash.clone(filteredWallets);
return cb();
}
});
});
};
$scope.getContacts = function(addr) {
addressbookService.list(function(err, ab) {
if (err) $log.error(err);
$scope.hasContacts = lodash.isEmpty(ab) ? false : true;
if (!$scope.hasContacts) return cb();
var completeContacts = [];
lodash.each(ab, function(v, k) {
completeContacts.push({
name: lodash.isObject(v) ? v.name : v,
address: k,
email: lodash.isObject(v) ? v.email : null,
recipientType: 'contact',
coin: v.coin,
displayCoin: (v.coin == 'bch'
? (config.bitcoinCashAlias || defaults.bitcoinCashAlias)
: (config.bitcoinAlias || defaults.bitcoinAlias)).toUpperCase()
});
});
};
return cb();
});
};
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.fromWallet = profileService.getWallet(data.stateParams.fromWalletId); // Wallet to send from
// Setup $scope
var B = data.stateParams.coin == 'bch' ? bitcoreCash : bitcore;
var networkName;
try {
networkName = (new B.Address(data.stateParams.toAddress)).network.name;
} catch(e) {
var message = gettextCatalog.getString('Invalid address');
var backText = gettextCatalog.getString('Go back');
var learnText = gettextCatalog.getString('Learn more');
popupService.showConfirm(null, message, backText, learnText, function(back) {
$ionicHistory.nextViewOptions({
disableAnimate: true,
historyRoot: true
});
$state.go('tabs.send').then(function() {
$ionicHistory.clearHistory();
if (!back) {
var url = 'https://support.bitpay.com/hc/en-us/articles/115004671663';
externalLinkService.open(url);
}
});
});
return;
}
// Grab stateParams
tx = {
amount: parseInt(data.stateParams.amount),
toAmount: parseInt(data.stateParams.toAmount),
sendMax: data.stateParams.useSendMax == 'true' ? true : false,
fromWalletId: data.stateParams.fromWalletId,
toAddress: data.stateParams.toAddress,
displayAddress: data.stateParams.displayAddress,
description: data.stateParams.description,
paypro: data.stateParams.paypro,
feeLevel: configFeeLevel,
spendUnconfirmed: walletConfig.spendUnconfirmed,
// Vanity tx info (not in the real tx)
recipientType: $scope.recipientType || null,
toName: null,
toEmail: null,
toColor: null,
network: false,
coin: $scope.fromWallet.coin,
recipientType: data.stateParams.recipientType || null,
toName: data.stateParams.toName,
toEmail: data.stateParams.toEmail,
toColor: data.stateParams.toColor,
network: networkName,
coin: data.stateParams.coin,
txp: {},
};
@ -182,71 +182,18 @@ angular.module('copayApp.controllers').controller('confirmController', function(
tx.feeRate = parseInt(data.stateParams.requiredFeeRate);
}
if (tx.coin && tx.coin === 'bch') {
if (tx.coin && tx.coin == 'bch') {
tx.feeLevel = 'normal';
}
var B = data.stateParams.coin === 'bch' ? bitcoreCash : bitcore;
var networkName;
$scope.recipientType = null;
try {
if (data.stateParams.toWalletId) { // There is a toWalletId, so we presume this is a wallet-to-wallet transfer
$scope.recipientType = 'wallet'; // set transaction type to wallet-to-wallet
$ionicLoading.show();
var toWallet = profileService.getWallet(data.stateParams.toWalletId);
tx.toColor = toWallet.color;
tx.toName = toWallet.name;
// We need an address to send to, so we ask the walletService to create a new address for the toWallet.
walletService.getAddress(toWallet, true, function (err, addr) {
$ionicLoading.hide();
tx.toAddress = addr;
networkName = (new B.Address(tx.toAddress)).network.name;
tx.network = networkName;
setupTx(tx);
});
} else { // This is a Wallet-to-address transfer
networkName = (new B.Address(tx.toAddress)).network.name;
tx.network = networkName;
setupTx(tx);
}
} catch (e) {
var message = gettextCatalog.getString('Invalid address');
popupService.showAlert(null, message, function () {
$ionicHistory.nextViewOptions({
disableAnimate: true,
historyRoot: true
});
$state.go('tabs.send').then(function () {
$ionicHistory.clearHistory();
});
});
return;
}
});
var setupTx = function(tx) {
if (tx.coin === 'bch') {
tx.displayAddress = bitcoinCashJsService.readAddress(tx.toAddress).cashaddr;
} else {
tx.displayAddress = entry.address;
}
addressbookService.get(tx.coin+tx.toAddress, function(err, addr) { // Check if the recipient is a contact
if (!err && addr) {
tx.toName = addr.name;
tx.toEmail = addr.email;
tx.recipientType = 'contact';
}
});
// Other Scope vars
$scope.isCordova = isCordova;
$scope.isWindowsPhoneApp = isWindowsPhoneApp;
$scope.showAddress = false;
$scope.walletSelectorTitle = gettextCatalog.getString('Send from');
setWalletSelector(tx.coin, tx.network, tx.amount, function(err) {
setWalletSelector(tx.coin, tx.network, tx.toAmount, function(err) {
if (err) {
return exitWithError('Could not update wallets');
}
@ -258,9 +205,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
}
});
$scope.displayBalanceAsFiat = walletConfig.settings.priceDisplay === 'fiat';
};
});
function getSendMaxInfo(tx, wallet, cb) {
@ -284,7 +229,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
return setSendError(msg);
}
if (tx.amount > Number.MAX_SAFE_INTEGER) {
if (tx.toAmount > Number.MAX_SAFE_INTEGER) {
var msg = gettextCatalog.getString('Amount too big');
$log.warn(msg);
return setSendError(msg);
@ -294,7 +239,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
txp.outputs = [{
'toAddress': tx.toAddress,
'amount': tx.amount,
'amount': tx.toAmount,
'message': tx.description
}];
@ -333,17 +278,14 @@ angular.module('copayApp.controllers').controller('confirmController', function(
$scope.tx = tx;
function updateAmount() {
if (!tx.amount) return;
if (!tx.toAmount) return;
// Amount
tx.amountStr = txFormatService.formatAmountStr(wallet.coin, tx.amount);
tx.amountStr = txFormatService.formatAmountStr(wallet.coin, tx.toAmount);
tx.amountValueStr = tx.amountStr.split(' ')[0];
tx.amountUnitStr = tx.amountStr.split(' ')[1];
txFormatService.formatAlternativeStr(wallet.coin, tx.amount, function(v) {
var parts = v.split(' ');
txFormatService.formatAlternativeStr(wallet.coin, tx.toAmount, function(v) {
tx.alternativeAmountStr = v;
tx.alternativeAmountValueStr = parts[0];
tx.alternativeAmountUnitStr = (parts.length > 0) ? parts[1] : '';
});
}
@ -395,7 +337,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
}
tx.sendMaxInfo = sendMaxInfo;
tx.amount = tx.sendMaxInfo.amount;
tx.toAmount = tx.sendMaxInfo.amount;
updateAmount();
ongoingProcess.set('calculatingFee', false);
$timeout(function() {
@ -446,7 +388,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
function useSelectedWallet() {
if (!$scope.useSendMax) {
showAmount(tx.amount);
showAmount(tx.toAmount);
}
$scope.onWalletSelect($scope.wallet);
@ -455,19 +397,19 @@ angular.module('copayApp.controllers').controller('confirmController', function(
function setButtonText(isMultisig, isPayPro) {
if (isPayPro) {
if (isCordova) {
if (isCordova && !isWindowsPhoneApp) {
$scope.buttonText = gettextCatalog.getString('Slide to pay');
} else {
$scope.buttonText = gettextCatalog.getString('Click to pay');
}
} else if (isMultisig) {
if (isCordova) {
if (isCordova && !isWindowsPhoneApp) {
$scope.buttonText = gettextCatalog.getString('Slide to accept');
} else {
$scope.buttonText = gettextCatalog.getString('Click to accept');
}
} else {
if (isCordova) {
if (isCordova && !isWindowsPhoneApp) {
$scope.buttonText = gettextCatalog.getString('Slide to send');
} else {
$scope.buttonText = gettextCatalog.getString('Click to send');
@ -475,14 +417,13 @@ angular.module('copayApp.controllers').controller('confirmController', function(
}
};
$scope.toggleAddress = function() {
$scope.showAddress = !$scope.showAddress;
};
function showSendMaxWarning(wallet, sendMaxInfo) {
var feeAlternative = '',
msg = '';
function verifyExcludedUtxos() {
var warningMsg = [];
@ -500,25 +441,15 @@ angular.module('copayApp.controllers').controller('confirmController', function(
return warningMsg.join('\n');
};
feeAlternative = txFormatService.formatAlternativeStr(wallet.coin, sendMaxInfo.fee);
if (feeAlternative) {
msg = gettextCatalog.getString("{{feeAlternative}} will be deducted for bitcoin networking fees ({{fee}}).", {
fee: txFormatService.formatAmountStr(wallet.coin, sendMaxInfo.fee),
feeAlternative: feeAlternative
});
} else {
msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees).", {
fee: txFormatService.formatAmountStr(wallet.coin, sendMaxInfo.fee)
});
}
var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees.", {
fee: txFormatService.formatAmountStr(wallet.coin, sendMaxInfo.fee)
});
var warningMsg = verifyExcludedUtxos();
if (!lodash.isEmpty(warningMsg))
msg += '\n' + warningMsg;
popupService.showAlert(null, msg, function() {});
popupService.showAlert(null, msg, function() {});
};
$scope.onWalletSelect = function(wallet) {
@ -665,7 +596,6 @@ angular.module('copayApp.controllers').controller('confirmController', function(
txConfirmNotification.subscribe(wallet, {
txid: txp.txid
});
lastTxId = txp.txid;
}
}, onSendStatusChange);
};
@ -692,23 +622,11 @@ angular.module('copayApp.controllers').controller('confirmController', function(
(processName == 'sendingTx' && !$scope.wallet.canSign() && !$scope.wallet.isPrivKeyExternal())
) && !isOn) {
$scope.sendStatus = 'success';
if ($state.current.name === "tabs.send.confirm") { // XX SP: Otherwise all open wallets on other devices play this sound if you have been in a send flow before on that device.
soundService.play('misc/payment_sent.mp3');
if (config.soundsEnabled && $scope.wallet.coin == 'bch') {
var audio = new Audio('misc/bch_sent.mp3');
audio.play();
}
var channel = "ga";
if (platformInfo.isCordova) {
channel = "firebase";
}
var log = new window.BitAnalytics.LogEvent("transfer_success", [{
"coin": $scope.wallet.coin,
"type": "outgoing",
"amount": $scope.amount,
"fees": $scope.fee
}], [channel, "adjust"]);
window.BitAnalytics.LogEventHandlers.postEvent(log);
firebaseEventsService.logEvent('sent_bitcoin', { coin: $scope.wallet.coin });
$timeout(function() {
$scope.$digest();
}, 100);

View file

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('createController',
function($scope, $timeout, $log, lodash, $state, $ionicScrollDelegate, $ionicHistory, profileService, configService, gettextCatalog, ledger, trezor, intelTEE, derivationPathHelper, ongoingProcess, walletService, popupService, appConfigService, pushNotificationsService, $ionicNavBarDelegate) {
function($scope, $rootScope, $timeout, $log, lodash, $state, $ionicScrollDelegate, $ionicHistory, profileService, configService, gettextCatalog, ledger, trezor, intelTEE, derivationPathHelper, ongoingProcess, walletService, storageService, popupService, appConfigService, pushNotificationsService, firebaseEventsService, $ionicNavBarDelegate) {
/* For compressed keys, m*73 + n*34 <= 496 */
var COPAYER_PAIR_LIMITS = {
@ -268,7 +268,7 @@ angular.module('copayApp.controllers').controller('createController',
}, 100);
}
else {
//firebaseEventsService.logEvent('wallet_created', { coin: opts.coin });
firebaseEventsService.logEvent('wallet_created', { coin: opts.coin });
$state.go('tabs.home');
}
}

View file

@ -17,7 +17,7 @@ angular.module('copayApp.controllers').controller('customAmountController', func
}
$scope.$on("$ionicView.beforeEnter", function(event, data) {
var walletId = data.stateParams.toWalletId;
var walletId = data.stateParams.id;
if (!walletId) {
showErrorAndBack('Error', 'No wallet selected');
@ -53,26 +53,17 @@ angular.module('copayApp.controllers').controller('customAmountController', func
$scope.address = bchAddresses[$scope.bchAddressType];
}
$scope.coin = $scope.wallet.coin;
var satoshis = parseInt(data.stateParams.amount, 10);
$scope.coin = data.stateParams.coin;
var parsedAmount = txFormatService.parseAmount(
$scope.wallet.coin,
satoshis,
'sat');
data.stateParams.amount,
data.stateParams.currency);
// Amount in USD or BTC
var amount = parsedAmount.amount;
var currency = parsedAmount.currency;
$scope.amountUnitStr = parsedAmount.amountUnitStr;
configService.whenAvailable(function (config) {
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay;
$timeout(function () {
$scope.$apply();
});
});
if (currency != 'BTC' && currency != 'BCH') {
// Convert to BTC or BCH
var config = configService.getSync().wallet.settings;

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('shareAppController', function($scope, $stateParams, $timeout, $log, $ionicHistory, $state, $ionicNavBarDelegate, $ionicConfig, platformInfo, configService, storageService, lodash, appConfigService, gettextCatalog) {
angular.module('copayApp.controllers').controller('completeController', function($scope, $stateParams, $timeout, $log, $ionicHistory, $state, $ionicNavBarDelegate, $ionicConfig, platformInfo, configService, storageService, lodash, appConfigService, gettextCatalog) {
$scope.isCordova = platformInfo.isCordova;
$scope.title = gettextCatalog.getString("Share {{appName}}", {
appName: appConfigService.nameCase
@ -57,8 +57,28 @@ angular.module('copayApp.controllers').controller('shareAppController', function
$ionicConfig.views.swipeBackEnabled(true);
});
$scope.$on("$ionicView.enter", function() {
if (!$scope.fromSettings)
$ionicConfig.views.swipeBackEnabled(false);
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$ionicNavBarDelegate.showBackButton(true);
$scope.score = (data.stateParams && data.stateParams.score) ? parseInt(data.stateParams.score) : null;
$scope.skipped = (data.stateParams && data.stateParams.skipped) ? true : false;
$scope.rated = (data.stateParams && data.stateParams.rated) ? true : false;
$scope.fromSettings = (data.stateParams && data.stateParams.fromSettings) ? true : false;
if (!$scope.fromSettings) {
$ionicNavBarDelegate.showBackButton(false);
} else {
$ionicNavBarDelegate.showBackButton(true);
}
storageService.getFeedbackInfo(function(error, info) {
var feedbackInfo = lodash.isString(info) ? JSON.parse(info) : null;
feedbackInfo.sent = true;
storageService.setFeedbackInfo(JSON.stringify(feedbackInfo), function() {});
});
if (!$scope.isCordova) return;
$scope.animate = true;
@ -113,4 +133,13 @@ angular.module('copayApp.controllers').controller('shareAppController', function
}
}, 100);
});
$scope.close = function() {
$ionicHistory.nextViewOptions({
disableAnimate: false,
historyRoot: true
});
if ($scope.score == 5) $ionicHistory.goBack(-3);
else $ionicHistory.goBack(-2);
};
});

View file

@ -0,0 +1,53 @@
'use strict';
angular.module('copayApp.controllers').controller('rateAppController', function($scope, $state, $stateParams, $window, lodash, externalLinkService, configService, platformInfo, feedbackService, ongoingProcess, popupService, appConfigService) {
$scope.score = parseInt($stateParams.score);
$scope.appName = appConfigService.nameCase;
var isAndroid = platformInfo.isAndroid;
var isIOS = platformInfo.isIOS;
var config = configService.getSync();
$scope.skip = function() {
var dataSrc = {
"Email": lodash.values(config.emailFor)[0] || ' ',
"Feedback": ' ',
"Score": $stateParams.score,
"AppVersion": $window.version,
"Platform": ionic.Platform.platform(),
"DeviceVersion": ionic.Platform.version()
};
feedbackService.send(dataSrc, function(err) {
if (err) {
// try to send, but not essential, since the user didn't add a message
$log.warn('Could not send feedback.');
}
});
$state.go('tabs.rate.complete', {
score: $stateParams.score,
skipped: true
});
};
$scope.sendFeedback = function() {
$state.go('tabs.rate.send', {
score: $scope.score
});
};
$scope.goAppStore = function() {
var defaults = configService.getDefaults();
var url;
if (isAndroid)
url = defaults.rateApp.bitcoincom.android;
if (isIOS)
url = defaults.rateApp.bitcoincom.ios;
externalLinkService.open(url);
$state.go('tabs.rate.complete', {
score: $stateParams.score,
skipped: true,
rated: true
});
};
});

View file

@ -0,0 +1,60 @@
'use strict';
angular.module('copayApp.controllers').controller('rateCardController', function($scope, $state, $timeout, $log, gettextCatalog, platformInfo, storageService, appConfigService) {
$scope.isCordova = platformInfo.isCordova;
$scope.score = 0;
$scope.appName = appConfigService.nameCase;
$scope.goFeedbackFlow = function() {
$scope.hideCard();
if ($scope.isCordova && $scope.score == 5) {
$state.go('tabs.rate.rateApp', {
score: $scope.score
});
} else {
$state.go('tabs.rate.send', {
score: $scope.score
});
}
};
$scope.setScore = function(score) {
$scope.score = score;
switch ($scope.score) {
case 1:
$scope.button_title = gettextCatalog.getString("I think this app is terrible.");
break;
case 2:
$scope.button_title = gettextCatalog.getString("I don't like it");
break;
case 3:
$scope.button_title = gettextCatalog.getString("Meh - it's alright");
break;
case 4:
$scope.button_title = gettextCatalog.getString("I like the app");
break;
case 5:
$scope.button_title = gettextCatalog.getString("This app is fantastic!");
break;
}
$timeout(function() {
$scope.$apply();
});
};
$scope.hideCard = function() {
$log.debug('Feedback card dismissed.')
storageService.getFeedbackInfo(function(error, info) {
var feedbackInfo = JSON.parse(info);
feedbackInfo.sent = true;
storageService.setFeedbackInfo(JSON.stringify(feedbackInfo), function() {
$scope.showRateCard.value = false;
$timeout(function() {
$scope.$apply();
}, 100);
});
});
}
});

View file

@ -0,0 +1,102 @@
'use strict';
angular.module('copayApp.controllers').controller('sendController', function($scope, $state, $log, $timeout, $stateParams, $ionicNavBarDelegate, $ionicHistory, $ionicConfig, $window, gettextCatalog, popupService, configService, lodash, feedbackService, ongoingProcess, platformInfo, appConfigService) {
$scope.sendFeedback = function(feedback, goHome) {
var config = configService.getSync();
var dataSrc = {
"Email": lodash.values(config.emailFor)[0] || ' ',
"Feedback": goHome ? ' ' : feedback,
"Score": $stateParams.score || ' ',
"AppVersion": $window.version,
"Platform": ionic.Platform.platform(),
"DeviceVersion": ionic.Platform.version()
};
if (!goHome) ongoingProcess.set('sendingFeedback', true);
feedbackService.send(dataSrc, function(err) {
if (goHome) return;
ongoingProcess.set('sendingFeedback', false);
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Feedback could not be submitted. Please try again later.'));
return;
}
if (!$stateParams.score) {
popupService.showAlert(gettextCatalog.getString('Thank you!'), gettextCatalog.getString('A member of the team will review your feedback as soon as possible.'), function() {
$scope.feedback.value = '';
$ionicHistory.nextViewOptions({
disableAnimate: false,
historyRoot: true
});
$ionicHistory.goBack();
}, gettextCatalog.getString('Finish'));
return;
}
$state.go('tabs.rate.complete', {
score: $stateParams.score
});
});
if (goHome) $state.go('tabs.home');
};
$scope.$on("$ionicView.beforeLeave", function(event, data) {
$ionicConfig.views.swipeBackEnabled(true);
});
$scope.$on("$ionicView.enter", function(event, data) {
if ($scope.score)
$ionicConfig.views.swipeBackEnabled(false);
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.isCordova = platformInfo.isCordova;
$scope.score = (data.stateParams && data.stateParams.score) ? parseInt(data.stateParams.score) : null;
$scope.feedback = {};
switch ($scope.score) {
case 1:
$scope.reaction = "Ouch!";
$scope.comment = gettextCatalog.getString("There's obviously something we're doing wrong.") + ' ' + gettextCatalog.getString("How could we improve your experience?");
break;
case 2:
$scope.reaction = gettextCatalog.getString("Oh no!");
$scope.comment = gettextCatalog.getString("There's obviously something we're doing wrong.") + ' ' + gettextCatalog.getString("How could we improve your experience?");
break;
case 3:
$scope.reaction = "Hmm...";
$scope.comment = gettextCatalog.getString("We'd love to do better.") + ' ' + gettextCatalog.getString("How could we improve your experience?");
break;
case 4:
$scope.reaction = gettextCatalog.getString("Thanks!");
$scope.comment = gettextCatalog.getString("That's exciting to hear. We'd love to earn that fifth star from you how could we improve your experience?");
break;
case 5:
$scope.reaction = gettextCatalog.getString("Thank you!");
$scope.comment = gettextCatalog.getString("We're always looking for ways to improve {{appName}}.", {
appName: appConfigService.nameCase
}) + ' ' + gettextCatalog.getString("Is there anything we could do better?");
break;
default:
$scope.justFeedback = true;
$scope.comment = gettextCatalog.getString("We're always looking for ways to improve {{appName}}. How could we improve your experience?", {
appName: appConfigService.nameCase
});
break;
}
});
$scope.$on("$ionicView.afterEnter", function() {
$scope.showForm = true;
});
$scope.goBack = function() {
$ionicHistory.nextViewOptions({
disableAnimate: false,
historyRoot: true
});
$ionicHistory.goBack();
};
});

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('searchController', function($scope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicScrollDelegate, bwcError, profileService, lodash, configService, gettext, gettextCatalog, platformInfo, walletService, externalLinkService, bitcoinCashJsService) {
angular.module('copayApp.controllers').controller('searchController', function($scope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicScrollDelegate, bwcError, profileService, lodash, configService, gettext, gettextCatalog, platformInfo, walletService) {
var HISTORY_SHOW_LIMIT = 10;
var currentTxHistoryPage = 0;
@ -21,8 +21,6 @@ angular.module('copayApp.controllers').controller('searchController', function($
function filter(search) {
$scope.filteredTxHistory = [];
$scope.searchTermIsAddress = false;
$scope.searchTermIsTxId = false;
function computeSearchableString(tx) {
var addrbook = '';
@ -31,19 +29,6 @@ angular.module('copayApp.controllers').controller('searchController', function($
var message = tx.message ? tx.message : '';
var comment = tx.note ? tx.note.body : '';
var addressTo = tx.addressTo ? tx.addressTo : '';
if ($scope.wallet.coin === 'bch') {
/**
* For each address
* I translate the legacy address and add in the searchable string the 3 kind of addresses
*/
lodash.each(tx.outputs, function(output) {
var addr = bitcoinCashJsService.translateAddresses(output.address);
addressTo += addr.legacy + addr.bitpay + 'bitcoincash:' + addr.cashaddr
});
}
var txid = tx.txid ? tx.txid : '';
return ((tx.amountStr + message + addressTo + addrbook + searchableDate + comment + txid).toString()).toLowerCase();
}
@ -65,19 +50,8 @@ angular.module('copayApp.controllers').controller('searchController', function($
return lodash.includes(tx.searcheableString, search.toLowerCase());
});
if (search) {
if ((search.indexOf('bitcoincash:') === 0 || search[0] === 'C' || search[0] === 'H' || search[0] === 'p' || search[0] === 'q') && search.replace('bitcoincash:', '').length === 42) { // CashAddr
$scope.searchTermIsAddress = true;
} else if ((search[0] === "1" || search[0] === "3" || search.substring(0, 3) === "bc1") && search.length >= 26 && search.length <= 35) { // Legacy Addresses
$scope.searchTermIsAddress = true;
} else if (search.length === 64) {
$scope.searchTermIsTxId = true;
}
}
if ($scope.filteredTxHistory.length > HISTORY_SHOW_LIMIT) $scope.txHistoryShowMore = true;
else $scope.txHistoryShowMore = false;
return $scope.filteredTxHistory;
};
@ -103,14 +77,4 @@ angular.module('copayApp.controllers').controller('searchController', function($
$scope.txHistoryShowMore = $scope.filteredTxHistory.length > $scope.txHistorySearchResults.length;
};
$scope.searchOnBlockchain = function(searchTerm) {
var url = 'https://explorer.bitcoin.com/'+$scope.wallet.coin+'/search/' + searchTerm;
var optIn = true;
var title = null;
var message = gettextCatalog.getString('Search on Explorer.Bitcoin.com');
var okText = gettextCatalog.getString('Open Explorer');
var cancelText = gettextCatalog.getString('Go Back');
externalLinkService.open(url, optIn, title, message, okText, cancelText);
};
});

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('nextStepsController', function($scope, nextStepsService, $ionicScrollDelegate, $timeout, platformInfo, configService, externalLinkService) {
angular.module('copayApp.controllers').controller('nextStepsController', function($scope, nextStepsService, $ionicScrollDelegate, $timeout, configService) {
$scope.hide = false;
@ -22,6 +22,6 @@ angular.module('copayApp.controllers').controller('nextStepsController', functio
};
$scope.open = function(url) {
externalLinkService.open(url, false)
window.open(url, '_system');
}
});

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('tourController',
function ($scope, $state, $log, $timeout, $filter, ongoingProcess, configService, profileService, rateService, popupService, gettextCatalog, lodash, startupService, storageService, uxLanguage, walletService, $q) {
function($scope, $state, $log, $timeout, $filter, ongoingProcess, profileService, rateService, popupService, gettextCatalog, startupService, storageService, walletService, $q) {
$scope.data = {
index: 0
@ -46,90 +46,62 @@ angular.module('copayApp.controllers').controller('tourController',
creatingWallet = true;
ongoingProcess.set('creatingWallet', true);
$timeout(function() {
uxLanguage.init(function(lang) {
var rateCode = uxLanguage.getRateCode(lang);
console.log("When Available: rateService");
rateService.whenAvailable(function() {
var alternatives = rateService.listAlternatives(true);
profileService.createDefaultWallet(function(err, walletClients) {
if (err) {
$log.warn(err);
var newAltCurrency = lodash.find(alternatives, {
'isoCode': rateCode
return $timeout(function() {
$log.warn('Retrying to create default wallet.....:' + ++retryCount);
if (retryCount > 3) {
ongoingProcess.set('creatingWallet', false);
popupService.showAlert(
gettextCatalog.getString('Cannot Create Wallet'), err,
function() {
retryCount = 0;
return $scope.createDefaultWallet();
}, gettextCatalog.getString('Retry'));
} else {
return $scope.createDefaultWallet();
}
}, 2000);
};
ongoingProcess.set('creatingWallet', false);
var bchWallet = walletClients[0];
var btcWallet = walletClients[1];
var bchWalletId = bchWallet.credentials.walletId;
var btcWalletId = btcWallet.credentials.walletId;
function createAddressPromise(wallet) {
return $q(function(resolve, reject) {
walletService.getAddress(wallet, true, function(e, addr) {
if (e) reject(e);
resolve(addr);
});
configService.whenAvailable(function(config) {
var opts = {
wallet: {
settings: {
alternativeName: newAltCurrency.name,
alternativeIsoCode: newAltCurrency.isoCode,
}
}
};
configService.set(opts, function(err) {
if (err) $log.warn(err);
profileService.createDefaultWallet(function(err, walletClients) {
if (err) {
$log.warn(err);
return $timeout(function() {
$log.warn('Retrying to create default wallet.....:' + ++retryCount);
if (retryCount > 3) {
ongoingProcess.set('creatingWallet', false);
popupService.showAlert(
gettextCatalog.getString('Cannot Create Wallet'), err,
function() {
retryCount = 0;
return $scope.createDefaultWallet();
}, gettextCatalog.getString('Retry'));
} else {
return $scope.createDefaultWallet();
}
}, 2000);
}
;
ongoingProcess.set('creatingWallet', false);
var bchWallet = walletClients[0];
var btcWallet = walletClients[1];
var bchWalletId = bchWallet.credentials.walletId;
var btcWalletId = btcWallet.credentials.walletId;
function createAddressPromise(wallet) {
return $q(function (resolve, reject) {
walletService.getAddress(wallet, true, function (e, addr) {
if (e) reject(e);
resolve(addr);
});
});
}
function goToCollectEmail() {
$state.go('onboarding.collectEmail', {
bchWalletId: bchWalletId,
btcWalletId: btcWalletId
});
}
var bchAddressPromise = createAddressPromise(bchWallet);
var btcAddressPromise = createAddressPromise(btcWallet);
ongoingProcess.set('generatingNewAddress', true);
$q.all([bchAddressPromise, btcAddressPromise]).then(function (addresses) {
ongoingProcess.set('generatingNewAddress', false);
$state.go('tabs.home');
}, function (e) {
ongoingProcess.set('generatingNewAddress', false);
$log.warn(e);
popupService.showAlert(gettextCatalog.getString('Error'), e);
$state.go('tabs.home');
});
});
});
});
$log.debug('Setting default currency : ' + newAltCurrency);
});
})
}, 300);
};
});
}
function goToCollectEmail() {
$state.go('onboarding.collectEmail', {
bchWalletId: bchWalletId,
btcWalletId: btcWalletId
});
}
var bchAddressPromise = createAddressPromise(bchWallet);
var btcAddressPromise = createAddressPromise(btcWallet);
ongoingProcess.set('generatingNewAddress', true);
$q.all([bchAddressPromise, btcAddressPromise]).then(function(addresses) {
ongoingProcess.set('generatingNewAddress', false);
$state.go('tabs.home');
}, function(e) {
ongoingProcess.set('generatingNewAddress', false);
$log.warn(e);
popupService.showAlert(gettextCatalog.getString('Error'), e);
$state.go('tabs.home');
});
});
}, 300);
};
});

View file

@ -59,7 +59,7 @@ angular.module('copayApp.controllers').controller('preferencesController',
};
$scope.openWikiSpendingPassword = function() {
var url = 'https://walletsupport.bitcoin.com/article/129/what-does-the-spending-password-do-';
var url = 'https://github.com/bitpay/copay/wiki/COPAY---FAQ#what-the-spending-password-does';
var optIn = true;
var title = null;
var message = gettextCatalog.getString('Read more in our Wiki');

View file

@ -4,7 +4,7 @@ angular.module('copayApp.controllers').controller('preferencesAbout',
function($scope, $window, appConfigService, gettextCatalog, externalLinkService, $ionicNavBarDelegate) {
$scope.title = gettextCatalog.getString('About') + ' ' + appConfigService.nameCase;
$scope.version = $window.fullVersion;
$scope.version = $window.version;
$scope.commitHash = $window.commitHash;
$scope.openExternalLink = function() {

View file

@ -16,7 +16,7 @@ angular.module('copayApp.controllers').controller('preferencesBwsUrlController',
};
$scope.resetDefaultUrl = function() {
$scope.bwsurl.value = ($scope.wallet.coin === 'btc') ? defaults.bws.url : defaults.bwscash.url;
$scope.bwsurl.value = defaults.bws.url;
};
$scope.save = function() {
@ -25,15 +25,15 @@ angular.module('copayApp.controllers').controller('preferencesBwsUrlController',
switch ($scope.bwsurl.value) {
case 'prod':
case 'production':
bws = ($scope.wallet.coin === 'btc') ? defaults.bws.url : defaults.bwscash.url;
bws = 'https://bws.bitcoin.com/bws/api'
break;
case 'sta':
case 'staging':
bws = 'https://bws-staging.b-pay.net/bws/api';
bws = 'https://bws-staging.b-pay.net/bws/api'
break;
case 'loc':
case 'local':
bws = 'http://localhost:3232/bws/api';
bws = 'http://localhost:3232/bws/api'
break;
};
if (bws) {

View file

@ -6,7 +6,7 @@ angular.module('copayApp.controllers').controller('preferencesLanguageController
$scope.availableLanguages = uxLanguage.getLanguages();
$scope.openExternalLink = function() {
var url = 'https://crowdin.com/project/bitcoincom-wallet';
var url = 'https://crowdin.com/project/copay';
var optIn = true;
var title = gettextCatalog.getString('Open Translation Community');
var message = gettextCatalog.getString('You can make contributions by signing up on our Crowdin community translation website. Were looking forward to hearing from you!');

View file

@ -75,15 +75,6 @@ angular.module('copayApp.controllers').controller('preferencesNotificationsContr
};
emailService.updateEmail(opts);
var channel = "ga";
if (platformInfo.isCordova) {
channel = "firebase";
}
var log = new window.BitAnalytics.LogEvent("settings_email_notification_toggle", [{
"toggle": $scope.emailNotifications.value
}], [channel]);
window.BitAnalytics.LogEventHandlers.postEvent(log);
};
$scope.soundNotificationsChange = function() {

View file

@ -1,974 +0,0 @@
'use strict';
(function () {
angular
.module('copayApp.controllers')
.controller('reviewController', reviewController);
function reviewController(addressbookService, bitcoinCashJsService, bitcore, bitcoreCash, bwcError, clipboardService, configService, feeService, gettextCatalog, $interval, $ionicHistory, $ionicModal, ionicToast, lodash, $log, ongoingProcess, platformInfo, popupService, profileService, $scope, sendFlowService, shapeshiftService, soundService, $state, $timeout, txConfirmNotification, txFormatService, walletService) {
var vm = this;
vm.buttonText = '';
vm.destination = {
address: '',
balanceAmount: '',
balanceCurrency: '',
coin: '',
color: '',
currency: '',
currencyColor: '',
kind: '', // 'address', 'contact', 'wallet'
name: ''
};
vm.displayAddress = '';
vm.feeCrypto = '';
vm.feeFiat = '';
vm.fiatCurrency = '';
vm.feeIsHigh = false;
vm.feeLessThanACent = false;
vm.isCordova = platformInfo.isCordova;
vm.memo = '';
vm.notReadyMessage = '';
vm.origin = {
balanceAmount: '',
balanceCurrency: '',
currency: '',
currencyColor: '',
};
vm.originWallet = null;
vm.paymentExpired = false;
vm.personalNotePlaceholder = gettextCatalog.getString('Enter text here');
vm.primaryAmount = '';
vm.primaryCurrency = '';
vm.usingMerchantFee = false;
vm.readyToSend = false;
vm.remainingTimeStr = '';
vm.secondaryAmount = '';
vm.secondaryCurrency = '';
vm.sendingTitle = gettextCatalog.getString('You are sending');
vm.sendStatus = '';
vm.showAddress = true;
vm.thirdParty = false;
vm.wallet = null;
vm.memoExpanded = false;
// Functions
vm.goBack = goBack;
vm.onSuccessConfirm = onSuccessConfirm;
vm.onShareTransaction = onShareTransaction;
var sendFlowData;
var config = null;
var coin = '';
var countDown = null;
var defaults = {};
var usingCustomFee = false;
var usingMerchantFee = false;
var destinationWalletId = '';
var lastTxId = '';
var originWalletId = '';
var priceDisplayIsFiat = true;
var satoshis = null;
var toAddress = '';
var tx = {};
var txPayproData = null;
var unitFromSat = 0;
var FEE_TOO_HIGH_LIMIT_PERCENTAGE = 15;
$scope.$on("$ionicView.beforeEnter", onBeforeEnter);
function onBeforeEnter(event, data) {
console.log('review onBeforeEnter sendflow ', sendFlowService.state);
// Reset from last time
vm.memo = '';
defaults = configService.getDefaults();
sendFlowData = sendFlowService.state.getClone();
originWalletId = sendFlowData.fromWalletId;
if (typeof sendFlowData.amount === 'string') {
satoshis = parseInt(sendFlowData.amount, 10);
} else {
satoshis = sendFlowData.amount;
}
toAddress = sendFlowData.toAddress;
destinationWalletId = sendFlowData.toWalletId;
vm.displayAddress = sendFlowData.displayAddress;
vm.originWallet = profileService.getWallet(originWalletId);
vm.origin.currency = vm.originWallet.coin.toUpperCase();
coin = vm.originWallet.coin;
if (sendFlowData.thirdParty) {
vm.thirdParty = sendFlowData.thirdParty;
switch (vm.thirdParty.id) {
case 'shapeshift':
initShapeshift(function (err) {
if (err) {
// Error stop here
ongoingProcess.set('connectingShapeshift', false);
popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString(), function () {
$ionicHistory.goBack();
});
} else {
_next(data);
}
});
break;
case 'bip70':
initBip70();
default:
_next(data);
break;
}
} else {
_next(data);
}
function _next() {
configService.get(function onConfig(err, configCache) {
if (err) {
$log.err('Error getting config.', err);
} else {
config = configCache;
priceDisplayIsFiat = config.wallet.settings.priceDisplay === 'fiat';
vm.origin.currencyColor = (vm.originWallet.coin === 'btc' ? defaults.bitcoinWalletColor : defaults.bitcoinCashWalletColor);
console.log("coin", vm.originWallet.coin, vm.origin.currencyColor, config.bitcoinWalletColor, vm.originWallet.coin === 'btc');
unitFromSat = 1 / config.wallet.settings.unitToSatoshi;
}
updateSendAmounts();
getOriginWalletBalance(vm.originWallet);
handleDestinationAsAddress(toAddress, coin);
handleDestinationAsWallet(sendFlowData.toWalletId);
createVanityTransaction(data);
});
}
}
vm.approve = function() {
if (!tx || !vm.originWallet) return;
if (vm.paymentExpired) {
popupService.showAlert(null, gettextCatalog.getString('This bitcoin payment request has expired.', function () {
$ionicHistory.goBack();
}));
vm.sendStatus = '';
$timeout(function() {
$scope.$apply();
});
return;
}
ongoingProcess.set('creatingTx', true, statusChangeHandler);
getTxp(lodash.clone(tx), vm.originWallet, false, function(err, txp) {
ongoingProcess.set('creatingTx', false, statusChangeHandler);
if (err) return;
// confirm txs for more that 20usd, if not spending/touchid is enabled
function confirmTx(cb) {
if (walletService.isEncrypted(vm.originWallet))
return cb();
var amountUsd = parseFloat(txFormatService.formatToUSD(vm.originWallet.coin, txp.amount));
return cb();
};
function publishAndSign() {
if (!vm.originWallet.canSign() && !vm.originWallet.isPrivKeyExternal()) {
$log.info('No signing proposal: No private key');
return walletService.onlyPublish(vm.originWallet, txp, function(err) {
if (err) setSendError(err);
}, statusChangeHandler);
}
walletService.publishAndSign(vm.originWallet, txp, function(err, txp) {
if (err) return setSendError(err);
if (config.confirmedTxsNotifications && config.confirmedTxsNotifications.enabled) {
txConfirmNotification.subscribe(vm.originWallet, {
txid: txp.txid
});
lastTxId = txp.txid;
}
}, statusChangeHandler);
};
confirmTx(function(nok) {
if (nok) {
vm.sendStatus = '';
$timeout(function() {
$scope.$apply();
});
return;
}
publishAndSign();
});
});
};
vm.chooseFeeLevel = function(tx, wallet) {
if (wallet.coin == 'bch') return;
if (usingMerchantFee) return;
var scope = $rootScope.$new(true);
scope.network = tx.network;
scope.feeLevel = tx.feeLevel;
scope.noSave = true;
scope.coin = vm.originWallet.coin;
if (usingCustomFee) {
scope.customFeePerKB = tx.feeRate;
scope.feePerSatByte = tx.feeRate / 1000;
}
$ionicModal.fromTemplateUrl('views/modals/chooseFeeLevel.html', {
scope: scope,
backdropClickToClose: false,
hardwareBackButtonClose: false
}).then(function(modal) {
scope.chooseFeeLevelModal = modal;
scope.openModal();
});
scope.openModal = function() {
scope.chooseFeeLevelModal.show();
};
scope.hideModal = function(newFeeLevel, customFeePerKB) {
scope.chooseFeeLevelModal.hide();
$log.debug('New fee level choosen:' + newFeeLevel + ' was:' + tx.feeLevel);
usingCustomFee = newFeeLevel == 'custom' ? true : false;
if (tx.feeLevel == newFeeLevel && !usingCustomFee) return;
tx.feeLevel = newFeeLevel;
if (usingCustomFee) tx.feeRate = parseInt(customFeePerKB);
updateTx(tx, vm.originWallet, {
clearCache: true,
dryRun: true
}, function() {});
};
};
function createVanityTransaction(data) {
console.log('createVanityTransaction()');
var configFeeLevel = config.wallet.settings.feeLevel ? config.wallet.settings.feeLevel : 'normal';
// Grab stateParams
tx = {
amount: parseInt(sendFlowData.amount),
sendMax: sendFlowData.sendMax,
fromWalletId: sendFlowData.fromWalletId,
toAddress: sendFlowData.toAddress,
paypro: txPayproData,
feeLevel: configFeeLevel,
spendUnconfirmed: config.wallet.spendUnconfirmed,
// Vanity tx info (not in the real tx)
recipientType: vm.destination.kind || null,
toName: vm.destination.name || null,
toEmail: vm.destination.email || null,
toColor: vm.destination.color || null,
network: false,
coin: vm.originWallet.coin,
txp: {},
};
if (data.stateParams.requiredFeeRate) {
vm.usingMerchantFee = true;
tx.feeRate = parseInt(data.stateParams.requiredFeeRate);
}
if (tx.coin && tx.coin === 'bch') {
tx.feeLevel = 'normal';
}
var B = tx.coin === 'bch' ? bitcoreCash : bitcore;
var networkName;
try {
if (vm.destination.kind === 'wallet') { // This is a wallet-to-wallet transfer
ongoingProcess.set('generatingNewAddress', true);
var toWallet = profileService.getWallet(destinationWalletId);
// We need an address to send to, so we ask the walletService to create a new address for the toWallet.
console.log('Getting address for wallet...');
walletService.getAddress(toWallet, true, function onWalletAddress(err, addr) {
console.log('getAddress cb called', err);
ongoingProcess.set('generatingNewAddress', false);
tx.toAddress = addr;
networkName = (new B.Address(tx.toAddress)).network.name;
tx.network = networkName;
console.log('calling setupTx() for wallet.');
setupTx(tx);
});
} else { // This is a Wallet-to-address transfer
networkName = (new B.Address(tx.toAddress)).network.name;
tx.network = networkName;
console.log('calling setupTx() for address.');
setupTx(tx);
}
} catch (e) {
console.error('Error setting up tx', e);
var message = gettextCatalog.getString('Invalid address');
popupService.showAlert(null, message, function () {
$ionicHistory.nextViewOptions({
disableAnimate: true,
historyRoot: true
});
$state.go('tabs.send').then(function () {
$ionicHistory.clearHistory();
});
});
return;
}
}
function getOriginWalletBalance(originWallet) {
var balanceText = getWalletBalanceDisplayText(vm.originWallet);
vm.origin.balanceAmount = balanceText.amount;
vm.origin.balanceCurrency = balanceText.currency;
}
function getSendMaxInfo(tx, wallet, cb) {
if (!tx.sendMax) return cb();
//ongoingProcess.set('retrievingInputs', true);
walletService.getSendMaxInfo(wallet, {
feePerKb: tx.feeRate,
excludeUnconfirmedUtxos: !tx.spendUnconfirmed,
returnInputs: true,
}, cb);
};
function getTxp(tx, wallet, dryRun, cb) {
// ToDo: use a credential's (or fc's) function for this
if (tx.description && !wallet.credentials.sharedEncryptingKey) {
var msg = gettextCatalog.getString('Could not add message to imported wallet without shared encrypting key');
$log.warn(msg);
return setSendError(msg);
}
if (tx.amount > Number.MAX_SAFE_INTEGER) {
var msg = gettextCatalog.getString('Amount too big');
$log.warn(msg);
return setSendError(msg);
}
var txp = {};
txp.outputs = [{
'toAddress': tx.toAddress,
'amount': tx.amount,
'message': vm.memo
}];
if (tx.sendMaxInfo) {
txp.inputs = tx.sendMaxInfo.inputs;
txp.fee = tx.sendMaxInfo.fee;
} else {
if (usingCustomFee || usingMerchantFee) {
txp.feePerKb = tx.feeRate;
} else txp.feeLevel = tx.feeLevel;
}
txp.message = vm.memo;
if (tx.paypro) {
txp.payProUrl = tx.paypro.url;
}
txp.excludeUnconfirmedUtxos = !tx.spendUnconfirmed;
txp.dryRun = dryRun;
walletService.createTx(wallet, txp, function(err, ctxp) {
if (err) {
setSendError(err);
return cb(err);
}
return cb(null, ctxp);
});
};
function getWalletBalanceDisplayText(wallet) {
var balanceCryptoAmount = '';
var balanceCryptoCurrencyCode = '';
var balanceFiatAmount = '';
var balanceFiatCurrency = '';
var displayAmount = '';
var displayCurrency = '';
var walletStatus = null;
if (wallet.status && wallet.status.isValid) {
walletStatus = wallet.status;
} else if (wallet.cachedStatus.isValid) {
walletStatus = wallet.cachedStatus;
}
if (walletStatus) {
var cryptoBalanceParts = walletStatus.spendableBalanceStr.split(' ');
balanceCryptoAmount = cryptoBalanceParts[0];
balanceCryptoCurrencyCode = cryptoBalanceParts.length > 1 ? cryptoBalanceParts[1] : '';
if (walletStatus.alternativeBalanceAvailable) {
balanceFiatAmount = walletStatus.spendableBalanceAlternative;
balanceFiatCurrency = walletStatus.alternativeIsoCode;
}
}
if (priceDisplayIsFiat) {
displayAmount = balanceFiatAmount ? balanceFiatAmount : balanceCryptoAmount;
displayCurrency = balanceFiatAmount ? balanceFiatCurrency : balanceCryptoCurrencyCode;
} else {
displayAmount = balanceCryptoAmount;
displayCurrency = balanceCryptoCurrencyCode;
}
return {
amount: displayAmount,
currency: displayCurrency
};
}
function goBack() {
sendFlowService.router.goBack();
}
function handleDestinationAsAddress(address, originCoin) {
if (!address) {
return;
}
// Check if the recipient is a contact
addressbookService.get(originCoin + address, function(err, contact) {
if (!err && contact) {
handleDestinationAsAddressOfContact(contact);
} else {
if (originCoin === 'bch') {
vm.destination.address = bitcoinCashJsService.readAddress(address).cashaddr;
} else {
vm.destination.address = address;
}
vm.destination.kind = 'address';
}
});
}
function handleDestinationAsAddressOfContact(contact) {
vm.destination.kind = 'contact';
vm.destination.name = contact.name;
vm.destination.email = contact.email;
vm.destination.color = contact.coin === 'btc' ? defaults.bitcoinWalletColor : defaults.bitcoinCashWalletColor;
vm.destination.currency = contact.coin.toUpperCase();
vm.destination.currencyColor = vm.destination.color;
}
function handleDestinationAsWallet(walletId) {
destinationWalletId = walletId;
if (!destinationWalletId) {
return;
}
var destinationWallet = profileService.getWallet(destinationWalletId);
vm.destination.coin = destinationWallet.coin;
vm.destination.color = destinationWallet.color;
vm.destination.currency = destinationWallet.coin.toUpperCase();
vm.destination.kind = 'wallet';
vm.destination.name = destinationWallet.name;
if (defaults) {
vm.destination.currencyColor = vm.destination.coin === 'btc' ? defaults.bitcoinWalletColor : defaults.bitcoinCashWalletColor;
}
var balanceText = getWalletBalanceDisplayText(destinationWallet);
vm.destination.balanceAmount = balanceText.amount;
vm.destination.balanceCurrency = balanceText.currency;
}
function initBip70() {
vm.sendingTitle = gettextCatalog.getString('You are paying');
vm.memo = vm.thirdParty.memo;
vm.memoExpanded = !!vm.memo;
vm.destination.name = vm.thirdParty.name;
txPayproData = {
caTrusted: vm.thirdParty.caTrusted,
domain: vm.thirdParty.domain,
expires: vm.thirdParty.expires,
toAddress: toAddress,
url: vm.thirdParty.url,
verified: vm.thirdParty.verified,
};
}
function initShapeshift(cb) {
vm.sendingTitle = gettextCatalog.getString('You are shifting');
if (!vm.thirdParty.data) {
vm.thirdParty.data = {};
}
var toWallet = profileService.getWallet(destinationWalletId);
vm.destination.name = toWallet.name;
vm.destination.color = toWallet.color;
vm.destination.currency = toWallet.coin.toUpperCase();
ongoingProcess.set('connectingShapeshift', true);
walletService.getAddress(vm.originWallet, false, function onReturnWalletAddress(err, returnAddr) {
if (err) {
return cb(err);
}
walletService.getAddress(toWallet, false, function onWithdrawalWalletAddress(err, withdrawalAddr) {
if (err) {
return cb(err);
}
// Need to use the correct service to do it.
var amount = parseFloat(satoshis / 100000000);
shapeshiftService.shiftIt(vm.originWallet.coin, toWallet.coin, withdrawalAddr, returnAddr, amount, function onShiftIt(err, shapeshiftData) {
if (err) {
return cb(err);
} else {
vm.destination.kind = 'shapeshift';
vm.destination.address = toAddress;
tx.toAddress = shapeshiftData.toAddress;
vm.memo = 'ShapeShift Order:\nhttps://www.shapeshift.io/#/status/' + shapeshiftData.orderId;
vm.memoExpanded = !!vm.memo;
ongoingProcess.set('connectingShapeshift', false);
cb();
}
});
});
});
}
function onShareTransaction() {
var explorerTxUrl = 'https://explorer.bitcoin.com/' + tx.coin + '/tx/' + lastTxId;
if (platformInfo.isCordova) {
var text = gettextCatalog.getString('Take a look at this Bitcoin Cash transaction here: ') + explorerTxUrl;
if (coin === 'btc') {
text = gettextCatalog.getString('Take a look at this Bitcoin transaction here: ') + explorerTxUrl;
}
window.plugins.socialsharing.share(text, null, null, null);
} else {
ionicToast.show(gettextCatalog.getString('Copied to clipboard'), 'bottom', false, 3000);
clipboardService.copyToClipboard(explorerTxUrl);
}
}
function startExpirationTimer(expirationTime) {
vm.paymentExpired = false;
setExpirationTime();
countDown = $interval(function() {
setExpirationTime();
}, 1000);
function setExpirationTime() {
console.log('setExpirationTime()');
var now = Math.floor(Date.now() / 1000);
if (now > expirationTime) {
setExpiredValues();
return;
}
var totalSecs = expirationTime - now;
var m = Math.floor(totalSecs / 60);
var s = totalSecs % 60;
vm.remainingTimeStr = m + ":" + ('0' + s).slice(-2);
};
function setExpiredValues() {
vm.paymentExpired = true;
vm.remainingTimeStr = gettextCatalog.getString('Expired');
vm.readyToSend = false;
if (countDown) $interval.cancel(countDown);
$timeout(function() {
$scope.$apply();
});
};
};
function updateSendAmounts() {
if (typeof satoshis !== 'number') {
return;
}
var cryptoAmount = '';
var cryptoCurrencyCode = '';
var amountStr = txFormatService.formatAmountStr(coin, satoshis);
if (amountStr) {
var amountParts = amountStr.split(' ');
cryptoAmount = amountParts[0];
cryptoCurrencyCode = amountParts.length > 1 ? amountParts[1] : '';
}
// Want to avoid flashing of amount strings so do all formatting after this has returned.
txFormatService.formatAlternativeStr(coin, satoshis, function(v) {
if (!v) {
vm.primaryAmount = cryptoAmount;
vm.primaryCurrency = cryptoCurrencyCode;
vm.secondaryAmount = '';
vm.secondaryCurrency = '';
return;
}
vm.secondaryAmount = vm.primaryAmount;
vm.secondaryCurrency = vm.primaryCurrency;
var fiatParts = v.split(' ');
var fiatAmount = fiatParts[0];
var fiatCurrency = fiatParts.length > 1 ? fiatParts[1] : '';
if (priceDisplayIsFiat) {
vm.primaryAmount = fiatAmount;
vm.primaryCurrency = fiatCurrency;
vm.secondaryAmount = cryptoAmount;
vm.secondaryCurrency = cryptoCurrencyCode;
} else {
vm.primaryAmount = cryptoAmount;
vm.primaryCurrency = cryptoCurrencyCode;
vm.secondaryAmount = fiatAmount;
vm.secondaryCurrency = fiatCurrency;
}
});
}
function onSuccessConfirm() {
vm.sendStatus = '';
$ionicHistory.nextViewOptions({
disableAnimate: true,
historyRoot: true
});
$state.go('tabs.send').then(function() {
$ionicHistory.clearHistory();
$state.transitionTo('tabs.home');
});
};
function setButtonText(isMultisig, isPayPro) {
if (isPayPro) {
if (vm.isCordova) {
vm.buttonText = gettextCatalog.getString('Slide to pay');
} else {
vm.buttonText = gettextCatalog.getString('Click to pay');
}
} else if (isMultisig) {
if (vm.isCordova) {
vm.buttonText = gettextCatalog.getString('Slide to accept');
} else {
vm.buttonText = gettextCatalog.getString('Click to accept');
}
} else {
if (vm.isCordova) {
vm.buttonText = gettextCatalog.getString('Slide to send');
} else {
vm.buttonText = gettextCatalog.getString('Click to send');
}
}
}
function setNotReady(msg, criticalError) {
vn.readyToSend = false;
vm.notReadyMessage = msg;
$scope.criticalError = criticalError;
$log.warn('Not ready to make the payment:' + msg);
$timeout(function() {
$scope.$apply();
});
};
function setSendError(msg) {
$scope.sendStatus = '';
vm.readyToSend = false;
$timeout(function() {
$scope.$apply();
});
popupService.showAlert(gettextCatalog.getString('Error at confirm'), bwcError.msg(msg), function () {
$ionicHistory.goBack();
});
};
function setupTx(tx) {
if (tx.coin === 'bch') {
tx.displayAddress = bitcoinCashJsService.readAddress(tx.toAddress).cashaddr;
} else {
tx.displayAddress = tx.toAddress;
}
addressbookService.get(tx.coin+tx.toAddress, function(err, addr) { // Check if the recipient is a contact
if (!err && addr) {
tx.toName = addr.name;
tx.toEmail = addr.email;
tx.recipientType = 'contact';
}
});
vm.showAddress = false;
setButtonText(vm.originWallet.credentials.m > 1, !!tx.paypro);
if (tx.paypro)
startExpirationTimer(tx.paypro.expires);
popupService.showConfirm(null, 'Do you want this transaction to be sent without a fee?', 'Yes', 'No', function(ok) {
if(ok){
tx.feeRate = 0;
// tx.feeLevel = 'free';
usingCustomFee = true;
}
updateTx(tx, vm.originWallet, {
dryRun: true
}, function(err) {
$timeout(function() {
$scope.$apply();
}, 10);
});
});
// setWalletSelector(tx.coin, tx.network, tx.amount, function(err) {
// if (err) {
// return exitWithError('Could not update wallets');
// }
//
// if (vm.wallets.length > 1) {
// vm.showWalletSelector();
// } else if (vm.wallets.length) {
// setWallet(vm.wallets[0], tx);
// }
// });
}
function showSendMaxWarning(wallet, sendMaxInfo) {
var feeAlternative = '',
msg = '';
function verifyExcludedUtxos() {
var warningMsg = [];
if (sendMaxInfo.utxosBelowFee > 0) {
warningMsg.push(gettextCatalog.getString("A total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.", {
amountBelowFeeStr: txFormatService.formatAmountStr(wallet.coin, sendMaxInfo.amountBelowFee)
}));
}
if (sendMaxInfo.utxosAboveMaxSize > 0) {
warningMsg.push(gettextCatalog.getString("A total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded.", {
amountAboveMaxSizeStr: txFormatService.formatAmountStr(vm.originWallet.coin, sendMaxInfo.amountAboveMaxSize)
}));
}
return warningMsg.join('\n');
};
feeAlternative = txFormatService.formatAlternativeStr(vm.originWallet.coin, sendMaxInfo.fee);
if (feeAlternative) {
msg = gettextCatalog.getString("{{feeAlternative}} will be deducted for bitcoin networking fees ({{fee}}).", {
fee: txFormatService.formatAmountStr(vm.originWallet.coin, sendMaxInfo.fee),
feeAlternative: feeAlternative
});
} else {
msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees).", {
fee: txFormatService.formatAmountStr(vm.originWallet.coin, sendMaxInfo.fee)
});
}
var warningMsg = verifyExcludedUtxos();
if (!lodash.isEmpty(warningMsg))
msg += '\n' + warningMsg;
popupService.showAlert(null, msg, function() {});
//popupService.showConfirm(null, msg, null, null, function() {});
};
function statusChangeHandler(processName, showName, isOn) {
$log.debug('statusChangeHandler: ', processName, showName, isOn);
if (
(
processName === 'broadcastingTx' ||
((processName === 'signingTx') && vm.originWallet.m > 1) ||
(processName == 'sendingTx' && !vm.originWallet.canSign() && !vm.originWallet.isPrivKeyExternal())
) && !isOn) {
// Show the popup
vm.sendStatus = 'success';
// Clear the send flow service state
sendFlowService.state.clear();
if ($state.current.name === "tabs.send.review") { // XX SP: Otherwise all open wallets on other devices play this sound if you have been in a send flow before on that device.
soundService.play('misc/payment_sent.mp3');
}
var channel = "firebase";
if (platformInfo.isNW) {
channel = "ga";
}
// When displaying Fiat, if the formatting fails, the crypto will be the primary amount.
var amount = unitFromSat * satoshis;
var log = new window.BitAnalytics.LogEvent("transfer_success", [{
"coin": vm.originWallet.coin,
"type": "outgoing",
"amount": amount,
"fees": vm.feeCrypto
}], [channel, "adjust"]);
window.BitAnalytics.LogEventHandlers.postEvent(log);
$timeout(function() {
$scope.$digest();
}, 100);
} else if (showName) {
vm.sendStatus = showName;
}
};
function updateTx(tx, wallet, opts, cb) {
ongoingProcess.set('calculatingFee', true);
if (opts.clearCache) {
tx.txp = {};
}
// $scope.tx = tx;
// function updateAmount() {
// if (!tx.amount) return;
//
// // Amount
// tx.amountStr = txFormatService.formatAmountStr(originWallet.coin, tx.amount);
// tx.amountValueStr = tx.amountStr.split(' ')[0];
// tx.amountUnitStr = tx.amountStr.split(' ')[1];
// txFormatService.formatAlternativeStr(wallet.coin, tx.amount, function(v) {
// var parts = v.split(' ');
// tx.alternativeAmountStr = v;
// tx.alternativeAmountValueStr = parts[0];
// tx.alternativeAmountUnitStr = (parts.length > 0) ? parts[1] : '';
// });
// }
//
// updateAmount();
// refresh();
var feeServiceLevel = usingMerchantFee && vm.originWallet.coin == 'btc' ? 'urgent' : tx.feeLevel;
feeService.getFeeRate(vm.originWallet.coin, tx.network, feeServiceLevel, function(err, feeRate) {
if (err) {
ongoingProcess.set('calculatingFee', false);
return cb(err);
}
var msg;
// if (tx.feeLevel == 'free'){
// tx.feeRate = 0;
// }
// else
if (usingCustomFee) {
msg = gettextCatalog.getString('Custom');
tx.feeLevelName = msg;
} else if (usingMerchantFee) {
$log.info('Using Merchant Fee:' + tx.feeRate + ' vs. Urgent level:' + feeRate);
msg = gettextCatalog.getString('Suggested by Merchant');
tx.feeLevelName = msg;
} else {
tx.feeLevelName = feeService.feeOpts[tx.feeLevel];
tx.feeRate = feeRate;
}
getSendMaxInfo(lodash.clone(tx), wallet, function(err, sendMaxInfo) {
if (err) {
ongoingProcess.set('calculatingFee', false);
var msg = gettextCatalog.getString('Error getting SendMax information');
return setSendError(msg);
}
if (sendMaxInfo) {
$log.debug('Send max info', sendMaxInfo);
if (tx.sendMax && sendMaxInfo.amount == 0) {
ongoingProcess.set('calculatingFee', false);
setNotReady(gettextCatalog.getString('Insufficient confirmed funds'));
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee'), function () {
$ionicHistory.goBack();
});
return cb('no_funds');
}
tx.sendMaxInfo = sendMaxInfo;
tx.amount = tx.sendMaxInfo.amount;
satoshis = tx.amount;
updateSendAmounts();
ongoingProcess.set('calculatingFee', false);
$timeout(function() {
showSendMaxWarning(wallet, sendMaxInfo);
}, 200);
}
// txp already generated for this wallet?
if (tx.txp[wallet.id]) {
ongoingProcess.set('calculatingFee', false);
vm.readyToSend = true;
updateSendAmounts();
$scope.$apply();
return cb();
}
console.log('calling getTxp() from getSendMaxInfo cb.');
getTxp(lodash.clone(tx), wallet, opts.dryRun, function(err, txp) {
ongoingProcess.set('calculatingFee', false);
if (err) {
if (err.message == 'Insufficient funds') {
setNotReady(gettextCatalog.getString('Insufficient funds'));
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee'));
return cb('no_funds');
} else
return cb(err);
}
txp.feeStr = txFormatService.formatAmountStr(wallet.coin, txp.fee);
txFormatService.formatAlternativeStr(wallet.coin, txp.fee, function(v) {
// txp.alternativeFeeStr = v;
// if (txp.alternativeFeeStr.substring(0, 4) == '0.00')
// txp.alternativeFeeStr = '< ' + txp.alternativeFeeStr;
vm.feeFiat = v;
vm.fiatCurrency = config.wallet.settings.alternativeIsoCode;
if (v.substring(0, 1) === "<") {
vm.feeLessThanACent = true;
}
console.log("fiat", vm.feeFiat);
});
var per = (txp.fee / (txp.amount + txp.fee) * 100);
var perString = per.toFixed(2);
txp.feeRatePerStr = (perString == '0.00' ? '< ' : '') + perString + '%';
txp.feeToHigh = per > FEE_TOO_HIGH_LIMIT_PERCENTAGE;
vm.feeCrypto = (unitFromSat * txp.fee).toFixed(8);
vm.feeIsHigh = txp.feeToHigh;
console.log("crypto", vm.feeCrypto);
tx.txp[wallet.id] = txp;
$log.debug('Confirm. TX Fully Updated for wallet:' + wallet.id, tx);
vm.readyToSend = true;
updateSendAmounts();
console.log('readyToSend:', vm.readyToSend);
$scope.$apply();
return cb();
});
});
});
}
}
})();

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('servicesController', function(externalLinkService, $scope, $ionicScrollDelegate, $timeout, servicesService, configService) {
angular.module('copayApp.controllers').controller('servicesController', function($scope, $ionicScrollDelegate, $timeout, servicesService, configService) {
$scope.hide = false;
configService.whenAvailable(function(config) {
@ -20,8 +20,4 @@ angular.module('copayApp.controllers').controller('servicesController', function
}, 10);
};
$scope.open = function(url) {
externalLinkService.open(url, false);
}
});

View file

@ -1,58 +1,67 @@
'use strict';
angular.module('copayApp.controllers').controller('shapeshiftController', function($scope, sendFlowService, $state, $timeout, $ionicHistory, profileService, walletService, popupService, lodash, $ionicNavBarDelegate) {
angular.module('copayApp.controllers').controller('shapeshiftController', function($scope, $interval, profileService, walletService, popupService, lodash, $ionicNavBarDelegate) {
var walletsBtc = [];
var walletsBch = [];
$scope.showMyAddress = showMyAddress;
function generateAddress(wallet, cb) {
if (!wallet) return;
walletService.getAddress(wallet, false, function(err, addr) {
if (err) {
popupService.showAlert(err);
}
return cb(addr);
});
}
function showToWallets() {
$scope.toWallets = $scope.fromWallet.coin == 'btc' ? walletsBch : walletsBtc;
$scope.onToWalletSelect($scope.toWallets[0]);
$scope.singleToWallet = $scope.toWallets.length == 1;
}
$scope.onFromWalletSelect = function(wallet) {
$scope.fromWallet = wallet;
showToWallets();
generateAddress(wallet, function(addr) {
$scope.fromWalletAddress = addr;
});
};
$scope.onToWalletSelect = function(wallet) {
$scope.toWallet = wallet;
generateAddress(wallet, function(addr) {
$scope.toWalletAddress = addr;
});
}
$scope.$on("$ionicView.beforeEnter", function(event, data) {
walletsBtc = profileService.getWallets({coin: 'btc'});
walletsBch = profileService.getWallets({coin: 'bch'});
$scope.fromWallets = lodash.filter(walletsBtc.concat(walletsBch), function(w) {
return (w.status && w.status.balance && w.status.balance.availableAmount > 0);
return w.status.balance.availableAmount > 0;
});
$scope.singleFromWallet = $scope.fromWallets.length === 1;
if ($scope.fromWallets.length == 0) return;
$scope.onFromWalletSelect($scope.fromWallets[0]);
$scope.onToWalletSelect($scope.toWallets[0]);
$scope.singleFromWallet = $scope.fromWallets.length == 1;
$scope.singleToWallet = $scope.toWallets.length == 1;
$scope.fromWalletSelectorTitle = 'From';
$scope.toWalletSelectorTitle = 'To';
$scope.showFromWallets = false;
$scope.showToWallets = false;
$scope.walletsWithFunds = profileService.getWallets({onlyComplete: true, hasFunds: true});
$scope.wallets = profileService.getWallets({onlyComplete: true});
$scope.hasWallets = !lodash.isEmpty($scope.wallets);
});
$scope.$on("$ionicView.enter", function(event, data) {
$ionicNavBarDelegate.showBar(true);
});
// This could probably be enhanced refactoring the routes abstract states
$scope.createWallet = function() {
$state.go('tabs.home').then(function() {
$state.go('tabs.add.create-personal');
});
};
$scope.buyBitcoin = function() {
$state.go('tabs.home').then(function() {
$state.go('tabs.buyandsell');
});
};
$scope.shapeshift = function() {
var stateParams = {
thirdParty: {
id: 'shapeshift'
}
};
sendFlowService.start(stateParams);
$scope.showFromWalletSelector = function() {
$scope.showFromWallets = true;
}
function showMyAddress() {
$state.go('tabs.home').then(function() {
$state.go('tabs.receive');
});
$scope.showToWalletSelector = function() {
$scope.showToWallets = true;
}
});

View file

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('tabHomeController',
function($rootScope, $timeout, $scope, $state, $stateParams, $ionicModal, $ionicScrollDelegate, $window, gettextCatalog, lodash, popupService, ongoingProcess, bannerService, communityService, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, sendFlowService, storageService, txpModalService, appConfigService, startupService, addressbookService, bwcError, nextStepsService, buyAndSellService, homeIntegrationsService, bitpayCardService, pushNotificationsService, timeService, bitcoincomService, pricechartService, firebaseEventsService, servicesService, shapeshiftService, $ionicNavBarDelegate, signVerifyMessageService) {
function($rootScope, $timeout, $scope, $state, $stateParams, $ionicModal, $ionicScrollDelegate, $window, gettextCatalog, lodash, popupService, ongoingProcess, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, storageService, txpModalService, appConfigService, startupService, addressbookService, feedbackService, bwcError, nextStepsService, buyAndSellService, homeIntegrationsService, bitpayCardService, pushNotificationsService, timeService, bitcoincomService, pricechartService, firebaseEventsService, servicesService, shapeshiftService, $ionicNavBarDelegate, signVerifyMessageService) {
var wallet;
var listeners = [];
var notifications = [];
@ -14,53 +14,78 @@ angular.module('copayApp.controllers').controller('tabHomeController',
$scope.isAndroid = platformInfo.isAndroid;
$scope.isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP;
$scope.isNW = platformInfo.isNW;
$scope.showRateCard = {};
$scope.showServices = false;
$scope.bannerIsLoading = true;
$scope.bannerImageUrl = '';
$scope.bannerUrl = '';
$scope.$on("$ionicView.beforeEnter", onBeforeEnter);
$scope.$on("$ionicView.enter", onEnter);
$scope.$on("$ionicView.afterEnter", onAfterEnter);
$scope.$on("$ionicView.leave", onLeave);
function onAfterEnter () {
$scope.$on("$ionicView.afterEnter", function() {
startupService.ready();
});
bannerService.getBanner(function (banner) {
$scope.bannerImageUrl = banner.imageURL;
$scope.bannerUrl = banner.url;
$scope.bannerIsLoading = false;
});
};
function onBeforeEnter (event, data) {
$scope.$on("$ionicView.beforeEnter", function(event, data) {
if (!$scope.homeTip) {
storageService.getHomeTipAccepted(function(error, value) {
$scope.homeTip = (value == 'accepted') ? false : true;
});
}
latestReleaseService.checkLatestRelease(function(err, newReleaseData) {
if (err) {
$log.warn(err);
if ($scope.isNW) {
latestReleaseService.checkLatestRelease(function(err, newRelease) {
if (err) {
$log.warn(err);
return;
}
if (newRelease) {
$scope.newRelease = true;
$scope.updateText = gettextCatalog.getString('There is a new version of {{appName}} available', {
appName: $scope.name
});
}
});
}
storageService.getFeedbackInfo(function(error, info) {
if ($scope.isWindowsPhoneApp) {
$scope.showRateCard.value = false;
return;
}
if (newReleaseData) {
$scope.newRelease = true;
$scope.newReleaseText = gettextCatalog.getString('There is a new version of {{appName}} available', {
appName: $scope.name
if (!info) {
initFeedBackInfo();
} else {
var feedbackInfo = JSON.parse(info);
//Check if current version is greater than saved version
var currentVersion = $scope.version;
var savedVersion = feedbackInfo.version;
var isVersionUpdated = feedbackService.isVersionUpdated(currentVersion, savedVersion);
if (!isVersionUpdated) {
initFeedBackInfo();
return;
}
var now = moment().unix();
var timeExceeded = (now - feedbackInfo.time) >= 24 * 7 * 60 * 60;
$scope.showRateCard.value = timeExceeded && !feedbackInfo.sent;
$timeout(function() {
$scope.$apply();
});
$scope.newReleaseNotes = newReleaseData.releaseNotes;
}
});
}
function onEnter(event, data) {
function initFeedBackInfo() {
var feedbackInfo = {};
feedbackInfo.time = moment().unix();
feedbackInfo.version = $scope.version;
feedbackInfo.sent = false;
storageService.setFeedbackInfo(JSON.stringify(feedbackInfo), function() {
$scope.showRateCard.value = false;
});
};
});
$scope.$on("$ionicView.enter", function(event, data) {
$ionicNavBarDelegate.showBar(true);
updateAllWallets();
updateAllWallets(function() {
profileService.initBitcoinCoreDisplay();
});
addressbookService.list(function(err, ab) {
if (err) $log.error(err);
@ -101,35 +126,37 @@ angular.module('copayApp.controllers').controller('tabHomeController',
$scope.nextStepsItems = nextStepsService.get();
}
$scope.displayBitcoinCore = config.displayBitcoinCore.enabled;
$scope.showServices = true;
pushNotificationsService.init();
firebaseEventsService.init();
$timeout(function() {
$ionicScrollDelegate.resize();
$scope.$apply();
}, 10);
});
}
});
function onLeave (event, data) {
$scope.$on("$ionicView.leave", function(event, data) {
lodash.each(listeners, function(x) {
x();
});
}
});
$scope.createdWithinPastDay = function(time) {
return timeService.withinPastDay(time);
};
$scope.startFreshSend = function() {
sendFlowService.start();
}
$scope.showUpdatePopup = function() {
latestReleaseService.showUpdatePopup();
};
$scope.openBannerUrl = function() {
externalLinkService.open($scope.bannerUrl, false);
$scope.openExternalLink = function() {
var url = 'https://github.com/Bitcoin-com/Wallet/releases/latest';
var optIn = true;
var title = gettextCatalog.getString('Update Available');
var message = gettextCatalog.getString('An update to this app is available. For your security, please update to the latest version.');
var okText = gettextCatalog.getString('View Update');
var cancelText = gettextCatalog.getString('Go Back');
externalLinkService.open(url, optIn, title, message, okText, cancelText);
};
$scope.openNotificationModal = function(n) {
@ -206,7 +233,6 @@ angular.module('copayApp.controllers').controller('tabHomeController',
var j = 0;
lodash.each(wallets, function(wallet) {
walletService.invalidateCache(wallet); // Temporary solution, to have the good balance, when we ask to reload the wallets.
walletService.getStatus(wallet, {}, function(err, status) {
if (err) {
@ -226,7 +252,6 @@ angular.module('copayApp.controllers').controller('tabHomeController',
cb();
}
}
$scope.walletsWithFunds = profileService.getWallets({hasFunds: true});
});
});
};
@ -256,6 +281,8 @@ angular.module('copayApp.controllers').controller('tabHomeController',
var txIdList = [];
var notificationsBeforeCheck = notifications.length;
for (var i=0; i<notifications.length; i++) {
var txId = notifications[i].txid;
if (txIdList.includes(txId)) {
@ -266,7 +293,15 @@ angular.module('copayApp.controllers').controller('tabHomeController',
}
}
var notificationsAfterCheck = notifications.length;
var removedNotifications = notificationsBeforeCheck - notificationsAfterCheck;
if (notificationsBeforeCheck != notificationsAfterCheck) {
total = total - removedNotifications;
}
$scope.notifications = notifications;
$scope.notificationsN = total;
$timeout(function() {
$ionicScrollDelegate.resize();
$scope.$apply();
@ -291,4 +326,9 @@ angular.module('copayApp.controllers').controller('tabHomeController',
updateAllWallets();
};
$rootScope.$on('Local/SettingsUpdated', function(e, walletId) {
configService.whenAvailable(function(config) {
$scope.displayBitcoinCore = config.displayBitcoinCore.enabled;
});
});
});

View file

@ -1,8 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('tabReceiveController', function($rootScope, $scope, $timeout, $log, $ionicModal, $state, $ionicHistory, $ionicPopover, storageService, platformInfo, walletService, profileService, configService, lodash, gettextCatalog, popupService, bwcError, bitcoinCashJsService, $ionicNavBarDelegate, sendFlowService, txFormatService, soundService, clipboardService) {
angular.module('copayApp.controllers').controller('tabReceiveController', function($rootScope, $scope, $timeout, $log, $ionicModal, $state, $ionicHistory, $ionicPopover, storageService, platformInfo, walletService, profileService, configService, lodash, gettextCatalog, popupService, bwcError, bitcoinCashJsService, $ionicNavBarDelegate, txFormatService) {
var CLOSE_NORMAL = 1000;
var listeners = [];
$scope.bchAddressType = { type: 'cashaddr' };
var bchAddresses = {};
@ -11,64 +10,17 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
$scope.isCordova = platformInfo.isCordova;
$scope.isNW = platformInfo.isNW;
var currentAddressSocket = null;
var paymentSubscriptionObj = { op:'addr_sub' };
$scope.displayBalanceAsFiat = true;
$scope.$on('$ionicView.beforeLeave', onBeforeLeave);
var currentAddressSocket = {};
var paymentSubscriptionObj = { op:"addr_sub" }
$scope.requestSpecificAmount = function() {
sendFlowService.start({
toWalletId: $scope.wallet.credentials.walletId,
isRequestAmount: true
$state.go('tabs.paymentRequest.amount', {
id: $scope.wallet.credentials.walletId,
coin: $scope.wallet.coin
});
};
function connectSocket() {
// Close existing socket if not connected with current address
if (currentAddressSocket) {
currentAddressSocket.close([CLOSE_NORMAL]);
}
if ($scope.wallet.coin === 'bch') {
// listen to bch address
currentAddressSocket = new WebSocket('wss://ws.blockchain.info/bch/inv');
paymentSubscriptionObj.addr = $scope.addrBchLegacy;
} else {
// listen to btc address
currentAddressSocket = new WebSocket('wss://ws.blockchain.info/inv');
paymentSubscriptionObj.addr = $scope.addr;
}
// create subscription to address
var msg = JSON.stringify(paymentSubscriptionObj);
currentAddressSocket.onopen = function (event) {
currentAddressSocket.send(msg);
};
// listen for response
currentAddressSocket.onmessage = function (event) {
//console.log("message received:" + event.data);
receivedPayment(event.data);
};
currentAddressSocket.onclose = function(event) {
if (event.code !== CLOSE_NORMAL) {
$log.debug('Socket was closed abnormally. Reconnect will be attempted in 1 second.');
$timeout(function() {
connectSocket();
}, 1000);
}
};
currentAddressSocket.onerror = function(err) {
console.error('Socket encountered error: ', err, 'Closing socket');
currentAddressSocket.close();
};
}
$scope.setAddress = function(newAddr, copyAddress) {
$scope.setAddress = function(newAddr) {
$scope.addr = null;
if (!$scope.wallet || $scope.generatingAddress || !$scope.wallet.isComplete()) return;
$scope.generatingAddress = true;
@ -80,23 +32,40 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
popupService.showAlert(err);
}
if ($scope.wallet.coin === 'bch') {
bchAddresses = bitcoinCashJsService.translateAddresses(addr);
$scope.addr = bchAddresses[$scope.bchAddressType.type];
$scope.addrBchLegacy = bchAddresses['legacy'];
} else {
$scope.addr = addr;
//close existing socket
if (currentAddressSocket.close === 'function') {
currentAddressSocket.close();
}
connectSocket();
if ($scope.wallet.coin == 'bch') {
bchAddresses = bitcoinCashJsService.translateAddresses(addr);
$scope.addr = bchAddresses[$scope.bchAddressType.type];
$scope.addrBchLegacy = bchAddresses['legacy'];
if (copyAddress === true) {
try {
clipboardService.copyToClipboard($scope.wallet.coin == 'bch' && $scope.bchAddressType.type == 'cashaddr' ? 'bitcoincash:' + $scope.addr : $scope.addr);
} catch (error) {
$log.debug('Error copying to clipboard:');
$log.debug(error);
}
// listen to bch address
currentAddressSocket = new WebSocket("wss://ws.blockchain.info/bch/inv");
paymentSubscriptionObj.addr = bchAddresses['legacy'];
} else {
$scope.addr = addr;
// listen to btc address
currentAddressSocket = new WebSocket("wss://ws.blockchain.info/inv");
paymentSubscriptionObj.addr = $scope.addr
}
// create subscription
var msg = JSON.stringify(paymentSubscriptionObj);
currentAddressSocket.onopen = function (event) {
//console.log("message sent: " + msg);
currentAddressSocket.send(msg);
}
// listen for response
currentAddressSocket.onmessage = function (event) {
//console.log("message received:" + event.data);
receivedPayment(event.data);
}
$timeout(function() {
@ -154,38 +123,11 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
for (var i = 0; i < data.x.out.length; i++) {
if (data.x.out[i].addr == watchAddress) {
$scope.paymentReceivedAmount = txFormatService.formatAmount(data.x.out[i].value, 'full');
$scope.paymentReceivedAlternativeAmount = ''; // For when a subsequent payment is received.
txFormatService.formatAlternativeStr($scope.wallet.coin, data.x.out[i].value, function(alternativeStr){
if (alternativeStr) {
$scope.$apply(function () {
$scope.paymentReceivedAlternativeAmount = alternativeStr;
});
}
});
}
}
$scope.paymentReceivedCoin = $scope.wallet.coin;
var channel = "ga";
if (platformInfo.isCordova) {
channel = "firebase";
}
var log = new window.BitAnalytics.LogEvent("transfer_success", [{
"coin": $scope.wallet.coin,
"type": "incoming"
}], [channel, "adjust"]);
window.BitAnalytics.LogEventHandlers.postEvent(log);
if ($state.current.name === "tabs.receive") {
soundService.play('misc/payment_received.mp3');
}
// Notify new tx
$scope.$emit('bwsEvent', $scope.wallet.id);
$scope.$apply(function () {
$scope.showingPaymentReceived = true;
});
$scope.showingPaymentReceived = true
$scope.$apply();
}
}
@ -251,24 +193,16 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
}
};
function onBeforeLeave() {
currentAddressSocket.close([CLOSE_NORMAL]);
}
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.wallets = profileService.getWallets();
$scope.singleWallet = $scope.wallets.length == 1;
if (!$scope.wallets[0]) return;
var selectedWallet = null;
if (data.stateParams.walletId) { // from walletDetails
selectedWallet = checkSelectedWallet(profileService.getWallet(data.stateParams.walletId), $scope.wallets);
} else {
// select first wallet if no wallet selected previously
selectedWallet = checkSelectedWallet($scope.wallet, $scope.wallets);
}
// select first wallet if no wallet selected previously
var selectedWallet = checkSelectedWallet($scope.wallet, $scope.wallets);
$scope.onWalletSelect(selectedWallet);
$scope.showShareButton = platformInfo.isCordova ? (platformInfo.isIOS ? 'iOS' : 'Android') : null;
listeners = [
@ -277,14 +211,9 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
if ($scope.wallet && walletId == $scope.wallet.id && type == 'NewIncomingTx') $scope.setAddress(true);
})
];
configService.whenAvailable(function(_config) {
$scope.displayBalanceAsFiat = _config.wallet.settings.priceDisplay === 'fiat';
});
});
$scope.$on("$ionicView.enter", function(event, data) {
$scope.showingPaymentReceived = false;
$ionicNavBarDelegate.showBar(true);
});
@ -319,10 +248,6 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
$scope.setAddress();
};
$scope.hidePaymentScreen = function() {
$scope.showingPaymentReceived = false;
};
$scope.showWalletSelector = function() {
if ($scope.singleWallet) return;
$scope.walletSelectorTitle = gettextCatalog.getString('Select a wallet');

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('tabScanController', function(gettextCatalog, popupService, $scope, $log, $timeout, scannerService, incomingDataService, $state, $ionicHistory, $rootScope, $ionicNavBarDelegate) {
angular.module('copayApp.controllers').controller('tabScanController', function($scope, $log, $timeout, scannerService, incomingData, $state, $ionicHistory, $rootScope, $ionicNavBarDelegate) {
var scannerStates = {
unauthorized: 'unauthorized',
@ -60,14 +60,8 @@ angular.module('copayApp.controllers').controller('tabScanController', function(
});
$scope.$on("$ionicView.afterEnter", function() {
var capabilities = scannerService.getCapabilities();
if (capabilities.hasPermission) {
// try initializing and refreshing status any time the view is entered
if(!scannerService.isInitialized()) {
scannerService.gentleInitialize();
}
activate();
}
// try initializing and refreshing status any time the view is entered
scannerService.gentleInitialize();
});
function activate(){
@ -108,21 +102,7 @@ angular.module('copayApp.controllers').controller('tabScanController', function(
function handleSuccessfulScan(contents){
$log.debug('Scan returned: "' + contents + '"');
scannerService.pausePreview();
// Sometimes (testing in Chrome, when reading QR Code) data is an object
// that has a string data.result.
contents = contents.result || contents;
incomingDataService.redir(contents, function onError(err) {
if (err) {
var title = gettextCatalog.getString('Scan Failed');
popupService.showAlert(title, err.message, function onAlertShown() {
// Enable another scan since we won't receive incomingDataMenu.menuHidden
activate();
});
} else {
scannerService.resumePreview();
}
});
incomingData.redir(contents);
}
$rootScope.$on('incomingDataMenu.menuHidden', function() {
@ -133,11 +113,8 @@ angular.module('copayApp.controllers').controller('tabScanController', function(
scannerService.openSettings();
};
$scope.reactivationCount = 0;
$scope.attemptToReactivate = function(){
scannerService.reinitialize(function(){
$scope.reactivationCount++;
});
scannerService.reinitialize();
};
$scope.toggleLight = function(){

View file

@ -1,237 +0,0 @@
'use strict';
angular.module('copayApp.controllers').controller('tabSendController', function(bitcoinUriService, $scope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, platformInfo, sendFlowService, gettextCatalog, configService, $ionicPopup, $ionicNavBarDelegate, clipboardService, incomingDataService) {
var clipboardHasAddress = false;
var clipboardHasContent = false;
var originalList;
$scope.displayBalanceAsFiat = true;
$scope.walletSelectorTitleForce = true;
$scope.addContact = function() {
$state.go('tabs.send.addressbook');
};
$scope.pasteClipboard = function() {
if ($scope.clipboardHasAddress || $scope.clipboardHasContent) {
clipboardService.readFromClipboard(function(text) {
$scope.$apply(function() {
$scope.formData.search = text;
$scope.findContact($scope.formData.search);
});
});
} else {
$ionicPopup.alert({
title: gettextCatalog.getString('Clipboard'),
template: gettextCatalog.getString('Your Clipboard is empty')
});
}
};
$scope.$on("$ionicView.enter", function(event, data) {
var stateParams = sendFlowService.state.getClone();
$scope.fromWallet = profileService.getWallet(stateParams.fromWalletId);
clipboardService.readFromClipboard(function(text) {
if (text.length > 200) {
text = text.substring(0, 200);
}
$scope.clipboardHasAddress = false;
$scope.clipboardHasContent = false;
var parsed = bitcoinUriService.parse(text);
console.log('parsed', parsed);
if (parsed.isValid && parsed.publicAddress && parsed.coin === 'bch' && !parsed.testnet) { // CashAddr
$scope.clipboardHasAddress = true;
} else if ((text[0] === "1" || text[0] === "3" || text.substring(0, 3) === "bc1") && text.length >= 26 && text.length <= 35) { // Legacy Addresses
$scope.clipboardHasAddress = true;
} else if (text.length > 1) {
$scope.clipboardHasContent = true;
}
});
$ionicNavBarDelegate.showBar(true);
if (!$scope.hasWallets) {
$scope.checkingBalance = false;
return;
}
updateHasFunds();
updateContactsList(function() {
updateList();
});
});
$scope.findContact = function(search) {
if (!search || search.length < 1) {
$scope.list = originalList;
$timeout(function() {
$scope.$apply();
});
return;
}
var params = sendFlowService.state.getClone();
params.data = search;
sendFlowService.start(params, function onError() {
var result = lodash.filter(originalList, function(item) {
var val = item.name;
return lodash.startsWith(val.toLowerCase(), search.toLowerCase());
});
$scope.list = result;
});
};
var hasWallets = function() {
$scope.walletsWithFunds = profileService.getWallets({
onlyComplete: true,
hasFunds: true
});
$scope.wallets = profileService.getWallets({
onlyComplete: true,
});
$scope.walletsBch = profileService.getWallets({
onlyComplete: true,
coin: 'bch'
});
$scope.walletsBtc = profileService.getWallets({
onlyComplete: true,
coin: 'btc'
});
$scope.hasWallets = lodash.isEmpty($scope.wallets) ? false : true;
};
var updateHasFunds = function() {
$scope.hasFunds = false;
var index = 0;
lodash.each($scope.wallets, function(w) {
walletService.getStatus(w, {}, function(err, status) {
++index;
if (err && !status) {
$log.error(err);
// error updating the wallet. Probably a network error, do not show
// the 'buy bitcoins' message.
$scope.hasFunds = true;
} else if (status.availableBalanceSat > 0) {
$scope.hasFunds = true;
}
if (index === $scope.wallets.length) {
$scope.checkingBalance = false;
$timeout(function() {
$scope.$apply();
});
}
});
});
};
var updateContactsList = function(cb) {
var config = configService.getSync();
var defaults = configService.getDefaults();
addressbookService.list(function(err, ab) {
if (err) $log.error(err);
$scope.hasContacts = lodash.isEmpty(ab) ? false : true;
if (!$scope.hasContacts) return cb();
var completeContacts = [];
lodash.each(ab, function(v, k) {
completeContacts.push({
name: lodash.isObject(v) ? v.name : v,
address: k,
email: lodash.isObject(v) ? v.email : null,
recipientType: 'contact',
coin: v.coin,
displayCoin: (v.coin == 'bch'
? (config.bitcoinCashAlias || defaults.bitcoinCashAlias)
: (config.bitcoinAlias || defaults.bitcoinAlias)).toUpperCase()
});
});
originalList = completeContacts;
return cb();
});
};
var updateList = function() {
$scope.list = lodash.clone(originalList);
$timeout(function() {
$ionicScrollDelegate.resize();
$scope.$apply();
}, 10);
};
$scope.searchInFocus = function() {
$scope.searchFocus = true;
};
$scope.searchBlurred = function() {
if ($scope.formData.search == null || $scope.formData.search.length === 0) {
$scope.searchFocus = false;
}
};
$scope.sendToContact = function (item) {
$timeout(function () {
var toAddress = item.address;
if (item.recipientType && item.recipientType === 'contact') {
if (toAddress.indexOf('bch') === 0 || toAddress.indexOf('btc') === 0) {
toAddress = toAddress.substring(3);
}
}
$log.debug('Got toAddress:' + toAddress + ' | ' + item.name);
var stateParams = sendFlowService.state.getClone();
stateParams.toAddress = toAddress;
stateParams.coin = item.coin;
sendFlowService.start(stateParams);
});
};
$scope.startWalletToWalletTransfer = function() {
console.log('startWalletToWalletTransfer()');
var params = sendFlowService.state.getClone();
params.isWalletTransfer = true;
sendFlowService.start(params);
}
// This could probably be enhanced refactoring the routes abstract states
$scope.createWallet = function() {
$state.go('tabs.home').then(function() {
$state.go('tabs.add.create-personal');
});
};
$scope.buyBitcoin = function() {
$state.go('tabs.home').then(function() {
$state.go('tabs.buyandsell');
});
};
$scope.$on("$ionicView.beforeEnter", function(event, data) {
console.log(data);
console.log('tab-send onBeforeEnter sendflow ', sendFlowService.state);
$scope.isIOS = platformInfo.isIOS && platformInfo.isCordova;
$scope.showWalletsBch = $scope.showWalletsBtc = $scope.showWallets = false;
$scope.checkingBalance = true;
$scope.formData = {
search: null
};
originalList = [];
hasWallets();
configService.whenAvailable(function(_config) {
$scope.displayBalanceAsFiat = _config.wallet.settings.priceDisplay === 'fiat';
});
if (data.direction == "back") {
sendFlowService.state.clear();
}
});
});

View file

@ -0,0 +1,260 @@
'use strict';
angular.module('copayApp.controllers').controller('tabSendController', function($scope, $rootScope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, bwcError, gettextCatalog, scannerService, configService, bitcoinCashJsService, $ionicNavBarDelegate) {
var originalList;
var CONTACTS_SHOW_LIMIT;
var currentContactsPage;
$scope.isChromeApp = platformInfo.isChromeApp;
$scope.sectionDisplay = {
transferToWallet: false
};
var hasWallets = function() {
$scope.wallets = profileService.getWallets({
onlyComplete: true
});
$scope.hasWallets = lodash.isEmpty($scope.wallets) ? false : true;
};
// THIS is ONLY to show the 'buy bitcoins' message
// does not has any other function.
var updateHasFunds = function() {
if ($rootScope.everHasFunds) {
$scope.hasFunds = true;
return;
}
$scope.hasFunds = false;
var index = 0;
lodash.each($scope.wallets, function(w) {
walletService.getStatus(w, {}, function(err, status) {
++index;
if (err && !status) {
$log.error(err);
// error updating the wallet. Probably a network error, do not show
// the 'buy bitcoins' message.
$scope.hasFunds = true;
} else if (status.availableBalanceSat > 0) {
$scope.hasFunds = true;
$rootScope.everHasFunds = true;
}
if (index == $scope.wallets.length) {
$scope.checkingBalance = false;
$timeout(function() {
$scope.$apply();
});
}
});
});
};
var updateWalletsList = function() {
var config = configService.getSync();
var networkResult = lodash.countBy($scope.wallets, 'network');
$scope.showTransferCard = $scope.hasWallets && (networkResult.livenet > 1 || networkResult.testnet > 1);
if ($scope.showTransferCard) {
var walletsToTransfer = $scope.wallets;
if (!(networkResult.livenet > 1)) {
walletsToTransfer = lodash.filter(walletsToTransfer, function(item) {
return item.network == 'testnet';
});
}
if (!(networkResult.testnet > 1)) {
walletsToTransfer = lodash.filter(walletsToTransfer, function(item) {
return item.network == 'livenet';
});
}
var walletList = [];
lodash.each(walletsToTransfer, function(v) {
walletList.push({
color: v.color,
name: v.name,
recipientType: 'wallet',
coin: v.coin,
network: v.network,
balanceString: v.cachedBalance,
displayWallet: v.coin == 'btc' ? config.displayBitcoinCore.enabled : true,
getAddress: function(cb) {
walletService.getAddress(v, false, cb);
},
});
});
originalList = originalList.concat(walletList);
}
}
var updateContactsList = function(cb) {
var config = configService.getSync();
var defaults = configService.getDefaults();
addressbookService.list(function(err, ab) {
if (err) $log.error(err);
$scope.hasContacts = lodash.isEmpty(ab) ? false : true;
if (!$scope.hasContacts) return cb();
var completeContacts = [];
lodash.each(ab, function(v, k) {
completeContacts.push({
name: lodash.isObject(v) ? v.name : v,
address: k,
email: lodash.isObject(v) ? v.email : null,
recipientType: 'contact',
coin: v.coin,
displayCoin: (v.coin == 'bch'
? (config.bitcoinCashAlias || defaults.bitcoinCashAlias)
: (config.bitcoinAlias || defaults.bitcoinAlias)).toUpperCase(),
getAddress: function(cb) {
return cb(null, k);
},
});
});
var contacts = completeContacts.slice(0, (currentContactsPage + 1) * CONTACTS_SHOW_LIMIT);
$scope.contactsShowMore = completeContacts.length > contacts.length;
originalList = originalList.concat(contacts);
return cb();
});
};
var updateList = function() {
$scope.list = lodash.clone(originalList);
$timeout(function() {
$ionicScrollDelegate.resize();
$scope.$apply();
}, 10);
};
$scope.openScanner = function() {
var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP;
if (!isWindowsPhoneApp) {
$state.go('tabs.scan');
return;
}
scannerService.useOldScanner(function(err, contents) {
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err);
return;
}
incomingData.redir(contents);
});
};
$scope.showMore = function() {
currentContactsPage++;
updateWalletsList();
};
$scope.searchInFocus = function() {
$scope.searchFocus = true;
};
$scope.searchBlurred = function() {
if ($scope.formData.search == null || $scope.formData.search.length == 0) {
$scope.searchFocus = false;
}
};
$scope.findContact = function(search) {
if (incomingData.redir(search)) {
return;
}
if (!search || search.length < 2) {
$scope.list = originalList;
$timeout(function() {
$scope.$apply();
});
return;
}
var result = lodash.filter(originalList, function(item) {
var val = item.name;
return lodash.includes(val.toLowerCase(), search.toLowerCase());
});
$scope.list = result;
};
$scope.goToAmount = function(item) {
$timeout(function() {
item.getAddress(function(err, addr) {
if (err || !addr) {
//Error is already formated
return popupService.showAlert(err);
}
if (item.recipientType && item.recipientType == 'contact') {
if (addr.indexOf('bch') == 0 || addr.indexOf('btc') == 0) {
addr = addr.substring(3);
}
}
$log.debug('Got toAddress:' + addr + ' | ' + item.name);
return $state.transitionTo('tabs.send.amount', {
recipientType: item.recipientType,
displayAddress: item.coin == 'bch' ? bitcoinCashJsService.translateAddresses(addr).cashaddr : addr,
toAddress: addr,
toName: item.name,
toEmail: item.email,
toColor: item.color,
coin: item.coin
});
});
});
};
// This could probably be enhanced refactoring the routes abstract states
$scope.createWallet = function() {
$state.go('tabs.home').then(function() {
$state.go('tabs.add.create-personal');
});
};
$scope.buyBitcoin = function() {
$state.go('tabs.home').then(function() {
$state.go('tabs.buyandsell');
});
};
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.checkingBalance = true;
$scope.formData = {
search: null
};
originalList = [];
CONTACTS_SHOW_LIMIT = 10;
currentContactsPage = 0;
hasWallets();
});
$scope.$on("$ionicView.enter", function(event, data) {
$ionicNavBarDelegate.showBar(true);
if (!$scope.hasWallets) {
$scope.checkingBalance = false;
return;
}
updateHasFunds();
updateWalletsList();
updateContactsList(function() {
updateList();
});
});
$scope.toggle = function(section) {
$scope.sectionDisplay[section] = !$scope.sectionDisplay[section];
$timeout(function() {
$ionicScrollDelegate.resize();
$scope.$apply();
}, 10);
};
});

View file

@ -16,7 +16,7 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
isoCode: config.wallet.settings.alternativeIsoCode
};
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay === 'crypto' ? gettextCatalog.getString('Cryptocurrency') : gettextCatalog.getString('Fiat');
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay;
// TODO move this to a generic service
bitpayAccountService.getAccounts(function(err, data) {
@ -45,18 +45,6 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
});
};
$scope.sendFeedback = function() {
var mailToLink = 'mailto:wallet@bitcoin.com?subject=Feedback%20for%20Bitcoin.com%20Wallet';
if (platformInfo.isNW) {
nw.Shell.openExternal(mailToLink);
} else if (platformInfo.isCordova) {
var mailWindow = window.open(mailToLink, '_system');
mailWindow.close(); // XX SP: bugfix for some browsers in cordova to change the view entirely
} else {
window.location.href = mailToLink;
}
};
$scope.openExternalLink = function() {
var appName = appConfigService.name;
var url = appName == 'copay' ? 'https://github.com/bitcoin-com/wallet/issues' : 'https://www.bitcoin.com/wallet-support';

View file

@ -1,13 +1,11 @@
'use strict';
angular.module('copayApp.controllers').controller('tabsController', function($rootScope, $log, $scope, $state, $stateParams, $timeout, platformInfo, incomingDataService, lodash, popupService, gettextCatalog, scannerService, sendFlowService) {
angular.module('copayApp.controllers').controller('tabsController', function($rootScope, $log, $scope, $state, $stateParams, $timeout, platformInfo, incomingData, lodash, popupService, gettextCatalog, scannerService) {
$scope.onScan = function(data) {
incomingDataService.redir(data, function onError(err) {
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err.message);
}
});
if (!incomingData.redir(data)) {
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid data'));
}
};
$scope.setScanFn = function(scanFn) {
@ -17,10 +15,6 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro
};
};
$scope.startFreshSend = function() {
sendFlowService.start();
};
$scope.importInit = function() {
$scope.fromOnboarding = $stateParams.fromOnboarding;
$timeout(function() {
@ -29,6 +23,7 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro
};
$scope.chooseScanner = function() {
var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP;
if (!isWindowsPhoneApp) {
@ -38,14 +33,10 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro
scannerService.useOldScanner(function(err, contents) {
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err.message);
} else {
incomingDataService.redir(contents, function onError(err) {
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err.message);
}
});
popupService.showAlert(gettextCatalog.getString('Error'), err);
return;
}
incomingData.redir(contents);
});
};

View file

@ -45,7 +45,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
});
$scope.readMore = function() {
var url = 'https://walletsupport.bitcoin.com/article/101/transaction-fees';
var url = 'https://github.com/bitpay/copay/wiki/COPAY---FAQ#amount-too-low-to-spend';
var optIn = true;
var title = null;
var message = gettextCatalog.getString('Read more in our Wiki');
@ -201,7 +201,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
$scope.viewOnBlockchain = function() {
var btx = $scope.btx;
var url = 'https://' + ($scope.getShortNetworkName() == 'test' ? 'test-' : '') + blockexplorerUrl + '/tx/' + btx.txid;
externalLinkService.open(url, false);
window.open(url, '_system');
};
$scope.getShortNetworkName = function() {

View file

@ -1,204 +0,0 @@
'use strict';
(function () {
angular
.module('copayApp.controllers')
.controller('walletSelectorController', walletSelectorController);
function walletSelectorController ($scope, $state, sendFlowService, configService, gettextCatalog, ongoingProcess, profileService, walletService, txFormatService) {
var fromWalletId = '';
var priceDisplayAsFiat = false;
var unitDecimals = 0;
var unitsFromSatoshis = 0;
$scope.$on("$ionicView.beforeEnter", onBeforeEnter);
$scope.$on("$ionicView.enter", onEnter);
function onBeforeEnter(event, data) {
if (data.direction == "back") {
sendFlowService.state.pop();
}
$scope.params = sendFlowService.state.getClone();
console.log('walletSelector onBeforeEnter after back sendflow', $scope.params);
var config = configService.getSync().wallet.settings;
priceDisplayAsFiat = config.priceDisplay === 'fiat';
unitDecimals = config.unitDecimals;
unitsFromSatoshis = 1 / config.unitToSatoshi;
if ($scope.params.isWalletTransfer) {
$scope.sendFlowTitle = gettextCatalog.getString('Transfer between wallets');
} else if (!$scope.params.thirdParty) {
$scope.sendFlowTitle = gettextCatalog.getString('Send');
}
$scope.coin = false; // Wallets to show (for destination screen or contacts)
$scope.type = $scope.params['fromWalletId'] ? 'destination' : 'origin'; // origin || destination
fromWalletId = $scope.params['fromWalletId'];
if ($scope.type === 'destination' && $scope.params.toAddress) {
$state.transitionTo(getNextStep($scope.params));
}
if ($scope.params.coin) {
$scope.coin = $scope.params.coin; // Contacts have a coin embedded
}
if ($scope.params.amount) { // There is an amount, so presume that it is a payment request
$scope.sendFlowTitle = gettextCatalog.getString('Payment Request');
$scope.specificAmount = $scope.specificAlternativeAmount = '';
$scope.isPaymentRequest = true;
}
if ($scope.params.thirdParty) {
$scope.thirdParty = $scope.params.thirdParty;
}
};
function onEnter (event, data) {
configService.whenAvailable(function(config) {
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay;
});
if ($scope.thirdParty) {
// Third party services specific logic
handleThirdPartyIfShapeshift();
}
prepareWalletLists();
formatRequestedAmount();
};
function formatRequestedAmount() {
if ($scope.params.amount) {
var cryptoAmount = (unitsFromSatoshis * $scope.params.amount).toFixed(unitDecimals);
var cryptoCoin = $scope.coin.toUpperCase();
txFormatService.formatAlternativeStr($scope.coin, $scope.params.amount, function onFormatAlternativeStr(formatted){
if (formatted) {
var fiatParts = formatted.split(' ');
var fiatAmount = fiatParts[0];
var fiatCurrrency = fiatParts.length > 1 ? fiatParts[1] : '';
if (priceDisplayAsFiat) {
$scope.requestAmount = fiatAmount;
$scope.requestCurrency = fiatCurrrency;
$scope.requestAmountSecondary = cryptoAmount;
$scope.requestCurrencySecondary = cryptoCoin;
} else {
$scope.requestAmount = cryptoAmount;
$scope.requestCurrency = cryptoCoin;
$scope.requestAmountSecondary = fiatAmount;
$scope.requestCurrencySecondary = fiatCurrrency;
}
$scope.$apply();
}
});
}
}
function handleThirdPartyIfShapeshift() {
console.log($scope.thirdParty, $scope.coin);
if ($scope.thirdParty.id === 'shapeshift' && $scope.type === 'destination') { // Shapeshift wants to know the
$scope.coin = profileService.getWallet(fromWalletId).coin;
if ($scope.coin === 'bch') {
$scope.coin = 'btc';
} else {
$scope.coin = 'bch';
}
}
}
function prepareWalletLists() {
var walletsAll = [];
var walletsSufficientFunds = [];
$scope.walletsInsufficientFunds = []; // For origin screen
if ($scope.type === 'origin') {
$scope.headerTitle = gettextCatalog.getString('Choose a wallet to send from');
if ($scope.params.amount || $scope.coin) {
walletsAll = profileService.getWallets({coin: $scope.coin});
ongoingProcess.set('scanning', true);
walletsAll.forEach(function forWallet(wallet) {
if (!wallet.status && !wallet.cachedStatus) {
walletService.getStatus(wallet, {}, function(err, status) {
wallet.status = status;
if (status.availableBalanceSat > ($scope.params.amount ? $scope.params.amount : 0)) {
walletsSufficientFunds.push(wallet);
} else {
$scope.walletsInsufficientFunds.push(wallet);
}
if ($scope.coin === 'btc') { // As this is a promise
$scope.walletsBtc = walletsSufficientFunds;
} else {
$scope.walletsBch = walletsSufficientFunds;
}
ongoingProcess.set('scanning', false);
});
} else {
var walletStatus = null;
if (wallet.status && wallet.status.isValid) {
walletStatus = wallet.status;
} else if (wallet.cachedStatus && wallet.status.isValid) {
walletStatus = wallet.cachedStatus;
}
if (walletStatus && walletStatus.availableBalanceSat > ($scope.params.amount ? $scope.params.amount : 0)) {
walletsSufficientFunds.push(wallet);
} else {
$scope.walletsInsufficientFunds.push(wallet);
}
ongoingProcess.set('scanning', false);
}
});
if ($scope.coin === 'btc') {
$scope.walletsBtc = walletsSufficientFunds;
} else {
$scope.walletsBch = walletsSufficientFunds;
}
} else {
$scope.walletsBch = profileService.getWallets({coin: 'bch', hasFunds: true});
$scope.walletsBtc = profileService.getWallets({coin: 'btc', hasFunds: true});
$scope.walletsInsufficientFunds = profileService.getWallets({coin: $scope.coin, hasNoFunds: true});
}
} else if ($scope.type === 'destination') {
if (!$scope.coin) { // Allow for the coin to be set by a third party
$scope.fromWallet = profileService.getWallet(fromWalletId);
$scope.coin = $scope.fromWallet.coin; // Only show wallets with the select origin wallet coin
}
$scope.headerTitle = gettextCatalog.getString('Choose a wallet to send to');
if ($scope.coin === 'btc') { // if no specific coin is set or coin is set btc
$scope.walletsBtc = profileService.getWallets({coin: $scope.coin});
} else {
$scope.walletsBch = profileService.getWallets({coin: $scope.coin});
}
}
}
$scope.useWallet = function(wallet) {
var params = sendFlowService.state.getClone();
if ($scope.type === 'origin') { // we're on the origin screen, set wallet to send from
params.fromWalletId = wallet.id;
} else { // we're on the destination screen, set wallet to send to
params.toWalletId = wallet.id;
}
sendFlowService.goNext(params);
};
$scope.goBack = function() {
sendFlowService.router.goBack();
}
}
})();

View file

@ -1,65 +1,45 @@
'use strict';
angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicHistory, profileService, lodash, configService, platformInfo, walletService, txpModalService, externalLinkService, popupService, addressbookService, sendFlowService, storageService, $ionicScrollDelegate, $window, bwcError, gettextCatalog, timeService, feeService, appConfigService, rateService, walletHistoryService) {
// Desktop can display 13 rows of transactions, bump it up to a nice round 15.
var DISPLAY_PAGE_SIZE = 15;
var currentTxHistoryDisplayPage = 0;
var completeTxHistory = []
angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicHistory, profileService, lodash, configService, platformInfo, walletService, txpModalService, externalLinkService, popupService, addressbookService, storageService, $ionicScrollDelegate, $window, bwcError, gettextCatalog, timeService, feeService, appConfigService, rateService) {
var HISTORY_SHOW_LIMIT = 10;
var currentTxHistoryPage = 0;
var listeners = [];
// For gradual migration for doing it properly
$scope.vm = {
allowInfiniteScroll: false,
gettingCachedHistory: true,
gettingInitialHistory: true,
updatingTxHistory: false,
fetchedAllTxHistory: false,
//updateTxHistoryError: false
updateTxHistoryFailed: false
};
// Need flag for when to allow infinite scroll at bottom
// - ie not when loading initial data and there is no more cached data
$scope.amountIsCollapsible = false;
$scope.color = '#888888';
$scope.filteredTxHistory = [];
$scope.txps = [];
$scope.completeTxHistory = [];
$scope.openTxpModal = txpModalService.open;
$scope.isCordova = platformInfo.isCordova;
$scope.isAndroid = platformInfo.isAndroid;
$scope.isIOS = platformInfo.isIOS;
$scope.isSearching = false;
$scope.openTxpModal = txpModalService.open;
$scope.requiresMultipleSignatures = false;
$scope.showBalanceButton = false;
$scope.status = null;
// Displaying 50 transactions when entering the screen takes a while, so only display a subset
// of everything we have, not the complete history.
$scope.txHistory = []; // This is what is displayed
$scope.txHistorySearchResults = [];
$scope.txps = [];
$scope.updatingStatus = false;
$scope.updateStatusError = null;
$scope.updatingTxHistoryProgress = 0;
$scope.wallet = null;
$scope.walletId = '';
$scope.walletNotRegistered = false;
var channel = "ga";
if (platformInfo.isCordova) {
channel = "firebase";
}
var log = new window.BitAnalytics.LogEvent("wallet_details_open", [], [channel]);
window.BitAnalytics.LogEventHandlers.postEvent(log);
$scope.amountIsCollapsible = !$scope.isAndroid;
$scope.openExternalLink = function(url, target) {
externalLinkService.open(url, target);
};
var setPendingTxps = function(txps) {
/* Uncomment to test multiple outputs */
// var txp = {
// message: 'test multi-output',
// fee: 1000,
// createdOn: new Date() / 1000,
// outputs: [],
// wallet: $scope.wallet
// };
//
// function addOutput(n) {
// txp.outputs.push({
// amount: 600,
// toAddress: '2N8bhEwbKtMvR2jqMRcTCQqzHP6zXGToXcK',
// message: 'output #' + (Number(n) + 1)
// });
// };
// lodash.times(15, addOutput);
// txps.push(txp);
if (!txps) {
$scope.txps = [];
return;
@ -86,7 +66,6 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
$scope.updatingStatus = true;
$scope.updateStatusError = null;
$scope.walletNotRegistered = false;
$scope.vm.fetchedAllTxHistory = false;
walletService.getStatus($scope.wallet, {
force: !!force,
@ -170,97 +149,68 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
if (err) return;
$timeout(function() {
walletService.startScan($scope.wallet, function() {
$scope.updateAll(true, true);
$scope.updateAll();
$scope.$apply();
});
});
});
};
var updateTxHistory = function(cb) {
if (!cb) cb = function() {};
$scope.updateTxHistoryError = false;
$scope.updatingTxHistoryProgress = 0;
feeService.getFeeLevels($scope.wallet.coin, function(err, levels) {
walletService.getTxHistory($scope.wallet, {
feeLevels: levels
}, function(err, txHistory) {
$scope.updatingTxHistory = false;
if (err) {
$scope.txHistory = null;
$scope.updateTxHistoryError = true;
return;
}
applyCurrencyAliases(txHistory);
var config = configService.getSync();
var fiatCode = config.wallet.settings.alternativeIsoCode;
lodash.each(txHistory, function(t) {
var r = rateService.toFiat(t.amount, fiatCode, $scope.wallet.coin);
t.alternativeAmountStr = r.toFixed(2) + ' ' + fiatCode;
});
$scope.completeTxHistory = txHistory;
$scope.showHistory();
$timeout(function() {
$scope.$apply();
});
return cb();
});
});
};
function applyCurrencyAliases(txHistory) {
var defaults = configService.getDefaults();
var configCache = configService.getSync();
lodash.each(txHistory, function onTx(tx) {
tx.amountUnitStr = $scope.wallet.coin == 'btc'
lodash.each(txHistory, function(t) {
t.amountUnitStr = $scope.wallet.coin == 'btc'
? (configCache.bitcoinAlias || defaults.bitcoinAlias)
: (configCache.bitcoinCashAlias || defaults.bitcoinCashAlias);
tx.amountUnitStr = tx.amountUnitStr.toUpperCase();
t.amountUnitStr = t.amountUnitStr.toUpperCase();
});
}
function formatTxHistoryForDisplay(txHistory) {
applyCurrencyAliases(txHistory);
var config = configService.getSync();
var fiatCode = config.wallet.settings.alternativeIsoCode;
lodash.each(txHistory, function(t) {
var r = rateService.toFiat(t.amount, fiatCode, $scope.wallet.coin);
t.alternativeAmountStr = r.toFixed(2) + ' ' + fiatCode;
});
}
function updateTxHistoryFromCachedData() {
$scope.vm.gettingCachedHistory = true;
walletHistoryService.getCachedTxHistory($scope.wallet.id, function onGetCachedTxHistory(err, txHistory){
$scope.vm.gettingCachedHistory = false;
if (err) {
// Don't display an error because we are also requesting the history.
$log.error('Error getting cached tx history.', err);
return;
}
if (!txHistory) {
$log.debug('No cached tx history.');
return;
}
formatTxHistoryForDisplay(txHistory);
completeTxHistory = txHistory;
showHistory(false);
$scope.$apply();
});
}
function fetchAndShowTxHistory(getLatest, flushCacheOnNew) {
$scope.vm.updatingTxHistory = true;
walletHistoryService.updateLocalTxHistoryByPage($scope.wallet, getLatest, flushCacheOnNew, function onUpdateLocalTxHistoryByPage(err, txHistory, fetchedAllTransactions) {
$scope.vm.gettingInitialHistory = false;
$scope.vm.updatingTxHistory = false;
$scope.$broadcast('scroll.infiniteScrollComplete');
if (err) {
console.error('pagination Failed to get history.', err);
$scope.vm.updateTxHistoryFailed = true;
return;
}
if (fetchedAllTransactions) {
$scope.vm.fetchedAllTxHistory = true;
}
formatTxHistoryForDisplay(txHistory);
completeTxHistory = txHistory;
showHistory(true);
$scope.$apply();
});
}
function showHistory(showAll) {
if (completeTxHistory) {
$scope.txHistory = showAll ? completeTxHistory : completeTxHistory.slice(0, (currentTxHistoryDisplayPage + 1) * DISPLAY_PAGE_SIZE);
$scope.vm.allowInfiniteScroll = !$scope.vm.fetchedAllTxHistory && !(completeTxHistory.length === $scope.txHistory.length && $scope.vm.gettingInitialHistory);
} else {
$scope.vm.allowInfiniteScroll = false;
$scope.showHistory = function() {
if ($scope.completeTxHistory) {
$scope.txHistory = $scope.completeTxHistory.slice(0, (currentTxHistoryPage + 1) * HISTORY_SHOW_LIMIT);
$scope.txHistoryShowMore = $scope.completeTxHistory.length > $scope.txHistory.length;
}
}
};
$scope.getDate = function(txCreated) {
var date = new Date(txCreated * 1000);
@ -299,35 +249,24 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
return !tx.confirmations || tx.confirmations === 0;
};
// on-infinite="showMore()"
$scope.showMore = function() {
// Check if we have more than we are displaying
if (completeTxHistory.length > $scope.txHistory.length) {
currentTxHistoryDisplayPage++;
showHistory(false);
$timeout(function() {
currentTxHistoryPage++;
$scope.showHistory();
$scope.$broadcast('scroll.infiniteScrollComplete');
return;
}
if ($scope.vm.updatingTxHistory) {
return;
}
fetchAndShowTxHistory(false, false);
}, 100);
};
// on-refresh="onRefresh()"
$scope.onRefresh = function() {
$timeout(function() {
$scope.$broadcast('scroll.refreshComplete');
}, 300);
$scope.updateAll(true, false);
$scope.updateAll(true);
};
$scope.updateAll = function(forceStatusUpdate, flushTxCacheOnNew)  {
updateStatus(forceStatusUpdate);
//updateTxHistory(cb);
fetchAndShowTxHistory(true, flushTxCacheOnNew);
$scope.updateAll = function(force, cb)  {
updateStatus(force);
updateTxHistory(cb);
};
$scope.hideToggle = function() {
@ -337,36 +276,97 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
};
var prevPos;
$scope.txHistoryPaddingBottom = 0;
function getScrollPosition() {
var scrollPosition = $ionicScrollDelegate.getScrollPosition();
$timeout(function() {
getScrollPosition();
}, 200);
if (!scrollPosition) {
$window.requestAnimationFrame(function() {
getScrollPosition();
});
return;
}
var pos = scrollPosition.top;
if (pos > 0) {
$scope.txHistoryPaddingBottom = "200px";
}
if (pos === prevPos) {
$window.requestAnimationFrame(function() {
getScrollPosition();
});
return;
}
prevPos = pos;
$scope.scrollPosition = pos;
refreshAmountSection(pos);
};
function refreshAmountSection(scrollPos) {
$scope.showBalanceButton = false;
if ($scope.status) {
$scope.showBalanceButton = ($scope.status.totalBalanceSat != $scope.status.spendableAmount);
}
if (!$scope.amountIsCollapsible) {
var t = ($scope.showBalanceButton ? 15 : 45);
$scope.amountScale = 'translateY(' + t + 'px)';
return;
}
scrollPos = scrollPos || 0;
var amountHeight = 210 - scrollPos;
if (amountHeight < 80) {
amountHeight = 80;
}
var contentMargin = amountHeight;
if (contentMargin > 210) {
contentMargin = 210;
}
var amountScale = (amountHeight / 210);
if (amountScale < 0.5) {
amountScale = 0.5;
}
if (amountScale > 1.1) {
amountScale = 1.1;
}
var s = amountScale;
// Make space for the balance button when it needs to display.
var TOP_NO_BALANCE_BUTTON = 115;
var TOP_BALANCE_BUTTON = 30;
var top = TOP_NO_BALANCE_BUTTON;
if ($scope.showBalanceButton) {
top = TOP_BALANCE_BUTTON;
}
var amountTop = ((amountScale - 0.7) / 0.7) * top;
if (amountTop < -10) {
amountTop = -10;
}
if (amountTop > top) {
amountTop = top;
}
var t = amountTop;
$scope.altAmountOpacity = (amountHeight - 100) / 80;
$window.requestAnimationFrame(function() {
$scope.amountHeight = amountHeight + 'px';
$scope.contentMargin = contentMargin + 'px';
$scope.amountScale = 'scale3d(' + s + ',' + s + ',' + s + ') translateY(' + t + 'px)';
$scope.$digest();
getScrollPosition();
});
}
var scrollWatcherInitialized;
$scope.$on("$ionicView.enter", function(event, data) {
if ($scope.isCordova && $scope.isAndroid) setAndroidStatusBarColor();
if (scrollWatcherInitialized || !$scope.amountIsCollapsible) {
return;
}
scrollWatcherInitialized = true;
});
$scope.$on("$ionicView.beforeEnter", function(event, data) {
configService.whenAvailable(function (config) {
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay;
@ -380,7 +380,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
if (!$scope.wallet) return;
$scope.requiresMultipleSignatures = $scope.wallet.credentials.m > 1;
$scope.vm.gettingInitialHistory = true;
$scope.updatingTxHistory = true;
addressbookService.list(function(err, ab) {
if (err) $log.error(err);
@ -390,31 +390,28 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
listeners = [
$rootScope.$on('bwsEvent', function(e, walletId) {
if (walletId == $scope.wallet.id && e.type != 'NewAddress')
$scope.updateAll(false, false);
$scope.updateAll();
}),
$rootScope.$on('Local/TxAction', function(e, walletId) {
if (walletId == $scope.wallet.id)
$scope.updateAll(false, false);
$scope.updateAll();
}),
];
});
var refreshInterval;
$scope.$on("$ionicView.afterEnter", function onAfterEnter(event, data) {
updateTxHistoryFromCachedData();
$scope.updateAll(true, true);
// refreshAmountSection();
$scope.$on("$ionicView.afterEnter", function(event, data) {
$scope.updateAll();
refreshAmountSection();
refreshInterval = $interval($scope.onRefresh, 10 * 1000);
$timeout(function() {
getScrollPosition();
}, 1000);
});
$scope.$on("$ionicView.afterLeave", function(event, data) {
$interval.cancel(refreshInterval);
if ($window.StatusBar) {
$window.StatusBar.backgroundColorByHexString('#000000');
var statusBarColor = appConfigService.name == 'copay' ? '#192c3a' : '#1e3186';
$window.StatusBar.backgroundColorByHexString(statusBarColor);
}
});
@ -466,30 +463,4 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
function rgbToHex(r, g, b) {
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
$scope.goToSend = function() {
sendFlowService.start({
fromWalletId: $scope.wallet.id
});
};
$scope.goToReceive = function() {
$state.go('tabs.home', {
walletId: $scope.wallet.id
}).then(function () {
$ionicHistory.clearHistory();
$state.go('tabs.receive', {
walletId: $scope.wallet.id
});
});
};
$scope.goToBuy = function() {
$state.go('tabs.home', {
walletId: $scope.wallet.id
}).then(function () {
$ionicHistory.clearHistory();
$state.go('tabs.buyandsell');
});
};
});

View file

@ -1,15 +0,0 @@
angular.module('copayApp')
.config(['$provide', '$logProvider', function($provide, $logProvider) {
// expose a provider to reach debugEnabled in $log
$provide.value('$logProvider', $logProvider);
}])
.decorator('$log', ['$logProvider', '$delegate', function($logProvider, $delegate) {
// override $log.debug to display in Chrome
$delegate.debug = function () {
if ($logProvider.debugEnabled()) {
$delegate.info.apply($delegate, arguments);
}
};
return $delegate;
}]);

View file

@ -1,26 +1,38 @@
'use strict';
angular.module('copayApp.directives')
.directive('copyToClipboard', function(clipboardService, ionicToast, gettextCatalog) {
.directive('copyToClipboard', function(platformInfo, nodeWebkitService, gettextCatalog, ionicToast, clipboard) {
return {
restrict: 'A',
scope: {
copyToClipboard: '=copyToClipboard'
},
link: function(scope, elem, attrs, ctrl) {
var isCordova = platformInfo.isCordova;
var isChromeApp = platformInfo.isChromeApp;
var isNW = platformInfo.isNW;
elem.bind('mouseover', function() {
elem.css('cursor', 'pointer');
});
var msg = gettextCatalog.getString('Copied to clipboard');
elem.bind('click', function() {
var data = scope.copyToClipboard;
clipboardService.copyToClipboard(data);
if (!data) return;
var msg = gettextCatalog.getString('Copied to clipboard');
scope.$apply(function () {
if (isCordova) {
cordova.plugins.clipboard.copy(data);
} else if (isNW) {
nodeWebkitService.writeToClipboard(data);
} else if (clipboard.supported) {
clipboard.copyText(data);
} else {
// No supported
return;
}
scope.$apply(function() {
ionicToast.show(msg, 'bottom', false, 1000);
});
});
}
}

View file

@ -1,198 +0,0 @@
'use strict';
(function(){
/**
* @desc amount directive that can be used to display formatted financial values
* size-equal attribute is optional, defaults to false.
* @example fee = {
* value: 12.49382901,
* currency: 'BCH'
* }
* @example <formatted-amount value="fee.value" currency="fee.currency"></formatted-amount>
* @example <formatted-amount value="fee.value" currency="fee.currency" size-equal="true"></formatted-amount>
*/
angular
.module('bitcoincom.directives')
.directive('formattedAmount', function() {
return {
restrict: 'E',
scope: {
value: '@',
currency: '@',
sizeEqual: '@'
},
templateUrl: 'views/includes/formatted-amount.html',
controller: formattedAmountController
}
});
function formattedAmountController($scope, uxLanguage) {
$scope.vm = {};
var vm = $scope.vm;
vm.currency = '';
vm.value = '';
$scope.canShow = false
$scope.displaySizeEqual = !!$scope.sizeEqual;
var decimalPlaces = {
'0': ['BIF', 'CLP', 'DJF', 'GNF', 'ILS', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF'],
'3': ['BHD', 'IQD', 'JOD', 'KWD', 'OMR', 'TND'],
'8': ['BCH', 'BTC']
};
$scope.$watch('value', function onFormattedAmountWatch() {
formatNumbers();
});
function buildAmount(start, middle, end) {
$scope.start = start;
$scope.middle = middle;
$scope.end = end;
};
/**
* On Android 4.4, toLocaleString() only returns 3 fractional digits when 8 is specified.
*/
function ensureEnoughFractionDigits(localizedString, number, desiredFractionDigits) {
if (desiredFractionDigits === 0) {
// Assume it is OK
return localizedString;
}
var fractionalRe = /^-*(\d*\D)(\d+)$/;
var match = fractionalRe.exec(localizedString);
if (!match || match.length !== 3) {
// Don't know what's happening, just return what we have
return localizedString;
}
var decimals = match[2];
var decimalCount = decimals.length;
if (decimalCount >= desiredFractionDigits) {
// Everything is OK.
return localizedString;
}
if (typeof number !== 'number') {
number = parseFloat(number);
}
var fixed = number.toFixed(desiredFractionDigits);
var fixedMatch = fractionalRe.exec(fixed);
if (!fixedMatch || fixedMatch.length !== 3) {
// Don't know what's happening, just return what we have
return localizedString;
}
// Keeps locale decimal separator.
var enough = match[1] + fixedMatch[2];
return enough;
}
function formatNumbers() {
// Might get "< 0.01 USD" being passed in.
// During watch, may be changed from having a separate currency value,
// to both being in value. Don't want to use previous currency value.
// Try to extract currency from value..
if (!$scope.currency || $scope.currency.length === 0) {
var currencySplit = $scope.value.split(" ");
if (currencySplit.length >= 2) {
vm.currency = currencySplit[currencySplit.length - 1];
}
} else {
vm.currency = $scope.currency;
}
// Redo this when we have proper formatting for low fees
if ($scope.value.indexOf("<") === 0) {
buildAmount($scope.value, '', '');
vm.currency = '';
$scope.canShow = true;
return;
}
// Remove thousands separators for parseFloat()
$scope.value = $scope.value.replace(',', '');
var parsed = parseFloat($scope.value);
var valueFormatted = '';
var valueProcessing = '';
switch (getDecimalPlaces(vm.currency)) {
case '0':
if (isNaN(parsed)) {
buildAmount('-', '', '');
} else {
valueFormatted = localizeNumbers(Math.round(parsed), 0);
buildAmount(valueFormatted, '', '');
}
break;
case '3':
if (isNaN(parsed)) {
buildAmount('-' + getDecimalSeparator() + '---', '', '');
} else {
valueProcessing = parsed.toFixed(3);
valueFormatted = localizeNumbers(valueProcessing, 3);
buildAmount(valueFormatted, '', '');
}
break;
case '8':
if (isNaN(parsed)) {
buildAmount('-' + getDecimalSeparator() + '---', '', '');
} else if (parsed === 0) {
buildAmount('0', '', '');
} else {
valueFormatted = parsed.toFixed(8);
valueFormatted = localizeNumbers(valueFormatted, 8);
var start = valueFormatted.slice(0, -5);
var middle = valueFormatted.slice(-5, -2);
var end = valueFormatted.substr(valueFormatted.length - 2);
buildAmount(start, middle, end);
}
break;
default: // 2
if (isNaN(parsed)) {
buildAmount('-' + getDecimalSeparator() + '--', '', '');
} else {
valueProcessing = parseFloat(parsed.toFixed(2));
valueFormatted = localizeNumbers(valueProcessing, 2);
buildAmount(valueFormatted, '', '');
}
break;
}
$scope.canShow = true;
};
function getDecimalPlaces(currency) {
if (decimalPlaces['0'].indexOf(currency.toUpperCase()) > -1) return '0';
if (decimalPlaces['3'].indexOf(currency.toUpperCase()) > -1) return '3';
if (decimalPlaces['8'].indexOf(currency.toUpperCase()) > -1) return '8';
return '2';
};
function getDecimalSeparator() {
var testNum = 1.5;
var testString = testNum.toLocaleString(uxLanguage.getCurrentLanguage());
// Some environments let you set decimal separators that are more than one character
var separator = /^1(.+)5$/.exec(testString)[1]
return separator;
};
function localizeNumbers(x, minimumFractionDigits) {
var parsed = parseFloat(x);
var opts = {
minimumFractionDigits: minimumFractionDigits,
useGrouping: true
};
var lang = uxLanguage.getCurrentLanguage();
var localized = parsed.toLocaleString(lang, opts);
var corrected = ensureEnoughFractionDigits(localized, x, minimumFractionDigits);
return corrected;
};
}
})();

View file

@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.directives')
.directive('gravatar', function(md5, $http) {
.directive('gravatar', function(md5) {
return {
restrict: 'AE',
replace: true,
@ -9,24 +9,13 @@ angular.module('copayApp.directives')
name: '@',
height: '@',
width: '@',
email: '@',
url: '@'
email: '@'
},
link: function(scope, el, attr) {
if (typeof scope.email === "string") {
scope.emailHash = md5.createHash(scope.email.toLowerCase() || '');
var req = {
method: 'GET',
url: 'https://secure.gravatar.com/'+scope.emailHash+'.json',
};
scope.url = 'img/contact-placeholder.svg';
$http(req).then(function (response) {
scope.url = 'https://secure.gravatar.com/avatar/'+scope.emailHash+'.jpg?s='+scope.width+'&d=mm';
}, function (error) {
scope.url = 'img/contact-placeholder.svg';
});
}
},
template: '<img class="gravatar" alt="{{ name }}" height="{{ height }}" width="{{ width }}" src="{{ url }}">'
template: '<img class="gravatar" alt="{{ name }}" height="{{ height }}" width="{{ width }}" src="https://secure.gravatar.com/avatar/{{ emailHash }}.jpg?s={{ width }}&d=mm">'
};
});

View file

@ -1,28 +1,23 @@
'use strict';
angular.module('copayApp.directives')
.directive('incomingDataMenu', function($timeout, $rootScope, $state, externalLinkService, sendFlowService, bitcoinCashJsService) {
.directive('incomingDataMenu', function($timeout, $rootScope, $state, externalLinkService) {
return {
restrict: 'E',
templateUrl: 'views/includes/incomingDataMenu.html',
link: function(scope, element, attrs) {
$rootScope.$on('incomingDataMenu.showMenu', function(event, data) {
$timeout(function() {
scope.data = data;
if (scope.data.parsed.privateKey) {
scope.type = "privateKey";
} else if (scope.data.parsed.url) {
scope.type = "url";
} else if (scope.data.parsed.publicAddress) {
scope.type = "bitcoinAddress";
var prefix = scope.data.parsed.isTestnet ? 'bchtest:' : 'bitcoincash:';
scope.data.toAddress = (prefix + scope.data.parsed.publicAddress.cashAddr) || scope.data.parsed.publicAddress.legacy || scope.data.parsed.publicAddress.bitpay;
} else {
scope.type = "text";
}
scope.data = data.data;
scope.type = data.type;
scope.showMenu = true;
scope.https = false;
if (scope.type === 'url') {
if (scope.data.indexOf('https://') === 0) {
scope.https = true;
}
}
});
});
scope.hide = function() {
@ -33,9 +28,18 @@ angular.module('copayApp.directives')
externalLinkService.open(url);
};
scope.sendPaymentToAddress = function(bitcoinAddress) {
var noPrefixInAddress = 0;
if (bitcoinAddress.toLowerCase().indexOf('bitcoin') < 0) {
noPrefixInAddress = 1;
}
scope.showMenu = false;
sendFlowService.start({
data: bitcoinAddress
$state.go('tabs.send').then(function() {
$timeout(function() {
$state.transitionTo('tabs.send.amount', {
toAddress: bitcoinAddress,
noPrefix: noPrefixInAddress
});
}, 50);
});
};
scope.addToAddressBook = function(bitcoinAddress) {

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.directives').directive('shapeshiftCoinTrader', function($interval, shapeshiftApiService, profileService, incomingDataService, ongoingProcess) {
angular.module('copayApp.directives').directive('shapeshiftCoinTrader', function($interval, shapeshiftApiService, profileService, incomingData, ongoingProcess) {
return {
restrict: 'E',
transclude: true,
@ -111,8 +111,7 @@ angular.module('copayApp.directives').directive('shapeshiftCoinTrader', function
orderId: $scope.depositInfo.orderId
};
// How to handle this
if (incomingDataService.redir(sendAddress, 'shapeshift', shapeshiftData)) {
if (incomingData.redir(sendAddress, shapeshiftData)) {
ongoingProcess.set('connectingShapeshift', false);
return;
}

View file

@ -116,8 +116,7 @@ angular.module('copayApp.directives')
function getTransformStyle(translatePct) {
return {
'transform': 'translateX(' + translatePct + '%)',
'-webkit-transform': 'translateX(' + translatePct + '%)'
'transform': 'translateX(' + translatePct + '%)'
};
}

View file

@ -9,12 +9,12 @@ angular.module('copayApp.directives')
scope: {
isShown: '=slideSuccessShow',
onConfirm: '&slideSuccessOnConfirm',
hideOnConfirm: '=slideSuccessHideOnConfirm',
onShare: '=slideSuccessOnShare',
hideOnConfirm: '=slideSuccessHideOnConfirm'
},
link: function(scope, element, attrs) {
scope.isCordova = platformInfo.isCordova;
scope.hasShareFunction = typeof scope.onShare === 'function';
scope.isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP;
var elm = element[0];
elm.style.display = 'none';
scope.$watch('isShown', function() {
@ -32,9 +32,6 @@ angular.module('copayApp.directives')
elm.style.display = 'none';
}
};
scope.onShareButtonClick = function() {
scope.onShare();
}
}
};
});

View file

@ -1,131 +0,0 @@
'use strict';
(function(){
angular
.module('bitcoincom.directives')
.directive('walletBalance', function() {
return {
restrict: 'E',
scope: {
displayAsFiat: '@',
totalBalanceSat: '@',
// The Wallet object is sometimes not stringify()-able, so not interpolatable,
// so can't be passed to a directive.
walletCoin: '@',
walletStatus: '@',
walletCachedBalance: '@',
walletCachedBalanceUpdatedOn: '@',
walletCachedStatus: '@'
},
templateUrl: 'views/includes/wallet-balance.html',
controller: walletBalanceController
}
});
function walletBalanceController($log, $scope, txFormatService) {
var cryptoBalanceHasBeenDisplayed = false;
formatBalance();
$scope.$watchGroup(['displayAsFiat', 'totalBalanceSat'], function onWalletBalanceWatch() {
formatBalance();
});
function displayCryptoBalance(walletStatus, walletCachedBalance, walletCachedBalanceUpdatedOn, walletCachedStatus) {
if (walletStatus && walletStatus.isValid && walletStatus.totalBalanceStr) {
setDisplay(walletStatus.totalBalanceStr, '');
cryptoBalanceHasBeenDisplayed = true;
return;
}
if (walletCachedBalance) {
setDisplay(walletCachedBalance, walletCachedBalanceUpdatedOn);
return;
}
if (walletCachedStatus && walletCachedStatus.isValid && walletCachedStatus.totalBalanceStr) {
setDisplay(walletCachedStatus.totalBalanceStr, '');
return;
}
setDisplay('', '');
}
function displayFiatBalance(walletStatus, walletCachedStatus, walletCoin) {
var displayAmount = '';
if (walletStatus && walletStatus.isValid && walletStatus.alternativeBalanceAvailable) {
displayAmount = walletStatus.totalBalanceAlternative + ' ' + walletStatus.alternativeIsoCode;
setDisplay(displayAmount, '');
return;
}
if (walletCachedStatus && walletCachedStatus.isValid && walletCachedStatus.alternativeBalanceAvailable) {
displayAmount = walletCachedStatus.totalBalanceAlternative + ' ' + walletCachedStatus.alternativeIsoCode;
setDisplay(displayAmount, '');
return;
}
getFiatBalance(walletStatus, walletCachedStatus, walletCoin);
}
function formatBalance() {
var displayAsFiat = $scope.displayAsFiat === 'true';
var walletStatusObj = null;
var walletCachedBalance = null;
var walletCachedBalanceUpdatedOn = null;
var walletCachedStatusObj = null;
try {
walletStatusObj = JSON.parse($scope.walletStatus);
} catch (e) {
$log.warn('Failed to parse walletStatus.', e);
}
try {
walletCachedStatusObj = JSON.parse($scope.walletCachedStatus);
} catch (e) {
$log.warn('Failed to parse walletCachedStatus.', e);
}
if (!displayAsFiat || displayAsFiat && !cryptoBalanceHasBeenDisplayed) {
displayCryptoBalance(walletStatusObj, walletCachedBalance, walletCachedBalanceUpdatedOn, walletCachedStatusObj);
}
if (displayAsFiat) {
displayFiatBalance(walletStatusObj, walletCachedStatusObj, $scope.walletCoin);
}
}
function getFiatBalance(walletStatus, walletCachedStatus, walletCoin) {
var totalBalanceSat = null;
if (walletStatus && walletStatus.isValid) {
totalBalanceSat = walletStatus.totalBalanceSat
} else if (walletCachedStatus && walletCachedStatus.isValid) {
totalBalanceSat = walletCachedStatus.totalBalanceSat
}
// 0 is valid
if (totalBalanceSat === null) {
$log.warn('Abandoning call to get fiat balance, because no valid wallet status (cached or otherwise).');
return;
}
txFormatService.formatAlternativeStr(walletCoin, totalBalanceSat, function onFormatAlernativeStr(formatted) {
if (formatted) {
setDisplay(formatted, '');
} else {
$log.error('Failed to format fiat balance of wallet.');
}
});
}
function setDisplay(amount, cachedBalanceUpdatedOn) {
$scope.displayAmount = amount;
$scope.cachedBalanceUpdatedOn = cachedBalanceUpdatedOn;
}
}
})();

View file

@ -8,21 +8,16 @@ angular.module('copayApp.directives')
transclude: true,
scope: {
title: '=walletSelectorTitle',
forceTitle: '=walletSelectorForceTitle',
show: '=walletSelectorShow',
wallets: '=walletSelectorWallets',
selectedWallet: '=walletSelectorSelectedWallet',
onSelect: '=walletSelectorOnSelect',
onHide: '=walletSelectorOnHide',
displayBalanceAsFiat : '=walletSelectorDisplayBalanceAsFiat'
alwaysDisplayBitcoinCore: '=walletSelectorAlwaysDisplayBitcoinCore'
},
link: function(scope, element, attrs) {
console.log(scope, element, attrs);
scope.displayWallet = true;
scope.hide = function() {
scope.show = false;
if (typeof scope.onHide === "function") {
scope.onHide()
}
};
scope.selectWallet = function(wallet) {
$timeout(function() {
@ -33,6 +28,19 @@ angular.module('copayApp.directives')
scope.$watch('wallets', function(newValue, oldValue) {
scope.wallets = newValue;
});
scope.initDisplayBitcoinCoreConfig = function() {
configService.whenAvailable(function(config) {
scope.displayBitcoinCore = config.displayBitcoinCore.enabled;
scope.initWalletDisplay();
});
};
scope.initWalletDisplay = function() {
scope.displayWallet = scope.alwaysDisplayBitcoinCore ? true : scope.displayBitcoinCore;
};
scope.initDisplayBitcoinCoreConfig();
$rootScope.$on('Local/SettingsUpdated', function(e, walletId) {
scope.initDisplayBitcoinCoreConfig();
});
}
};
});

Some files were not shown because too many files have changed in this diff Show more