diff --git a/.gitignore b/.gitignore index 0a7848506..fb26abc57 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,8 @@ webapp browser-extensions/chrome/copay-chrome-extension browser-extensions/chrome/copay-chrome-extension.zip browser-extensions/firefox/firefox-addon +browser-extensions/firefox/data +browser-extensions/firefox/copay.xpi version.js android/package diff --git a/app.js b/app.js index 2c514a2fa..ebc3b7826 100644 --- a/app.js +++ b/app.js @@ -2,6 +2,11 @@ var express = require('express'); var http = require('http'); var app = express(); +app.use('/', express.static(__dirname + '/')); +app.get('*', function(req, res) { + return res.sendfile('index.html'); +}); + app.start = function(port, callback) { app.set('port', port); diff --git a/config.js b/config.js index 9b24dbf01..da543f5d9 100644 --- a/config.js +++ b/config.js @@ -120,8 +120,6 @@ var defaultConfig = { storageSalt: 'mjuBtGybi/4=', }, - // theme list - themes: ['default'], disableVideo: true, verbose: 1, }; diff --git a/css/main.css b/css/main.css index f968bcfcf..571353bd2 100644 --- a/css/main.css +++ b/css/main.css @@ -9,18 +9,72 @@ padding:0; } -html, body {height: 100%;} - -#wrap {min-height: 100%;} - -#main { - overflow:auto; - padding-bottom: 80px;} /* must be same height as the footer */ - -.main-home { - padding-bottom: 28px !important; +body, html{ + height:100%; + width:100%; + background: #F8F8FB; } +.page, .main, .sidebar { + height:100%; +} + +.sidebar { + position: fixed; + width: 250px; + padding: 15px; + background-color: #2C3E50; + color: #fff; +} + +.sidebar a { + color: #fff; +} + +.main { + margin-left: 250px; +} + +[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { + display: none !important; +} + +.dn {display: none;} +.pr {position: relative;} +.m0 {margin: 0;} +.db {display: block;} +.size-12 { font-size: 12px; } +.size-14 { font-size: 14px; } +.size-16 { font-size: 16px; } +.size-18 { font-size: 18px; } +.size-21 { font-size: 21px; } +.size-24 { font-size: 24px; } +.size-36 { font-size: 36px; } +.size-48 { font-size: 48px; } +.size-60 { font-size: 60px; } +.size-72 { font-size: 72px; } +.m5t {margin-top: 5px;} +.m10t {margin-top: 10px;} +.m5b {margin-bottom: 5px;} +.m10b {margin-bottom: 10px;} +.m15b {margin-bottom: 20px;} +.m10r {margin-right: 10px;} +.m10 {margin: 10px;} +.m15 {margin: 15px;} +.p10t {padding-top: 10px;} +.p0r {padding-right: 0;} +.p70r {padding-right: 70px;} +.p70l {padding-left: 70px;} +.p5h {padding: 0 5px;} +.p20h {padding: 0 20px;} +.m30v {margin: 30px 0;} +.m10h {margin:0 10px;} +.m30a {margin: 30px auto;} +.br100 {border-radius: 100%;} +.lh {line-height: 0;} +.oh {overflow:hidden;} +.lh {line-height: 0;} + .panel.input { padding: 0.7rem 1rem; margin-bottom: 0; @@ -31,98 +85,15 @@ html, body {height: 100%;} } .text-gray.active { - color: #111 !important; + color: #111; font-weight: 700; } -#footer { - position: fixed; - margin-top: -80px; /* negative value of footer height */ - height: 70px; - clear:both; - padding: 5px 2rem; - bottom: 0; - width: 100%; - z-index: 100; -} - -.footer-home { - position: relative !important; - margin-top: -28px !important; - height: 28px !important; -} - -.bottom-copay { - width: 50px; - text-align: center; - position: relative; - float: right; - margin-left: 20px; - /* height: 551px; */ -} - .logo { display: block; height: 51px; } -.top-bar-section li:not(.has-form) a:not(.button) { - line-height: 60px; -} - -.top-bar-section li.active:not(.has-form) a:not(.button) { - line-height: 60px; - font-weight: 700; -} - -.top-bar-section ul li>a { - text-transform: uppercase; - font-weight: 100; - font-size: 0.9rem; -} - -.top-bar-section ul li { - width: 25%; -} - -.top-bar-section .label.alert { - vertical-align: super; - margin-left: 5px; -} - -.header { - margin-bottom: 30px; -} - -.header-content { - padding: 2rem; - overflow: hidden; -} - -.header a.button.small-icon { - padding: 0.1rem 0.3rem; - font-size: 0.9rem; - margin-left: 5px; -} - -.header h1, h5, p { - font-weight: 100; - margin-bottom: 0; -} - -.header button, .button { - margin-bottom: 0; -} - -.header h6 { - font-weight: 100; -} - -.top-bar { - height: auto; - width: 100%; -} - .panel { border:0; } @@ -148,31 +119,11 @@ html, body {height: 100%;} border: none; } -.box-backup { - margin: 0.6rem 0; - padding: 2rem 1rem; -} - -a.box-backup { - display: block; -} - -.box-backup i { - margin-bottom: 2rem; -/* display: block; -*/} - -h3 { - font-weight: 100; - font-size: 25px; -} - .line-dashed-v { border-right: 2px dashed #E3E3E3; } .line-dashed-h { - margin: 1rem 0; border-bottom: 1px dashed #E3E3E3; } @@ -203,7 +154,6 @@ span.panel-res { overflow: hidden; } - small.is-valid { font-weight: bold; } @@ -225,7 +175,6 @@ input[type=number]::-webkit-outer-spin-button { margin: 0; } - .small { font-size: 60%; line-height: inherit; @@ -241,45 +190,6 @@ input[type=number]::-webkit-outer-spin-button { hr { margin: 2.25rem 0;} -[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { - display: none !important; -} -.dn {display: none;} -.pr {position: relative;} -.m0 {margin: 0 !important;} -.db {display: block;} -.size-12 { font-size: 12px; } -.size-14 { font-size: 14px; } -.size-16 { font-size: 16px; } -.size-18 { font-size: 18px; } -.size-21 { font-size: 21px; } -.size-24 { font-size: 24px; } -.size-36 { font-size: 36px; } -.size-48 { font-size: 48px; } -.size-60 { font-size: 60px; } -.size-72 { font-size: 72px; } -.m5t {margin-top: 5px;} -.m10t {margin-top: 10px;} -.m5b {margin-bottom: 5px;} -.m10b {margin-bottom: 10px;} -.m15b {margin-bottom: 20px !important;} -.m10r {margin-right: 10px;} -.m10 {margin: 10px !important;} -.m15 {margin: 15px !important;} -.p10t {padding-top: 10px;} -.p0r {padding-right: 0;} -.p70r {padding-right: 70px;} -.p70l {padding-left: 70px;} -.p5h {padding: 0 5px;} -.p20h {padding: 0 20px;} -.m30v {/* margin: 30px 0; */} -.m10h {margin:0 10px;} -.m30a {margin: 30px auto;} -.br100 {border-radius: 100%;} -.lh {line-height: 0;} -.oh {overflow:hidden;} -.lh {line-height: 0;} - .video-small { width: 50px; height: 50px; @@ -487,31 +397,29 @@ a.loading { } @-webkit-keyframes yellow-flash { - 0% { - background-color: #FFFFE0; - opacity:1; - } - 22% { - background-color: #FFFFE0; - } - 100% { - background-color: none; - } + 0% { + background-color: #FFFFE0; + opacity:1; + } + 22% { + background-color: #FFFFE0; + } + 100% { + background-color: none; + } } .highlight{ -webkit-animation-name: yellow-flash; - -webkit-animation-duration: 400ms; - -webkit-animation-iteration-count: 1; - -webkit-animation-timing-function: linear; + -webkit-animation-duration: 400ms; + -webkit-animation-iteration-count: 1; + -webkit-animation-timing-function: linear; -moz-animation-name: yellow-flash; - -moz-animation-duration: 400ms; - -moz-animation-iteration-count: 1; - -moz-animation-timing-function: linear; + -moz-animation-duration: 400ms; + -moz-animation-iteration-count: 1; + -moz-animation-timing-function: linear; } - - /* notifications */ .dr-notification-container { @@ -660,3 +568,299 @@ ul.pagination li.current a:hover, ul.pagination li.current a:focus { float: left; } +/* + * + * Copay Default Template + * + */ + +@font-face { + font-family: 'Ubuntu'; + font-style: normal; + font-weight: 300; + src: local('Ubuntu Light'), local('Ubuntu-Light'), url(../font/ubuntu-light.woff) format('woff'); +} +@font-face { + font-family: 'Ubuntu'; + font-style: normal; + font-weight: 400; + src: local('Ubuntu'), url(../font/ubuntu.woff) format('woff'); +} +@font-face { + font-family: 'Ubuntu'; + font-style: normal; + font-weight: 700; + src: local('Ubuntu Bold'), local('Ubuntu-Bold'), url(../font/ubuntu-bold.woff) format('woff'); +} +@font-face { + font-family: 'Ubuntu'; + font-style: italic; + font-weight: 700; + src: local('Ubuntu Bold Italic'), local('Ubuntu-BoldItalic'), url(../font/ubuntu-bold-italic.woff) format('woff'); +} + +* { + font-family: 'Ubuntu', Helvetica, sans-serif !important; +} + +.logo { + background: transparent url('../img/logo-negative-beta.svg') no-repeat; + background-size: 130px 51px; +} + +.panel { + color: #333; + background: #FFFFFF; + border: 1px solid #EFEFEF; +} + +.transactions .panel { + background: #f5f5f5; +} + +.transactions .panel.pending { + background-color: #fff; +} + +.btransactions .panel { + background: #fff; +} + +.addresses .panel:hover, .addresses .panel.selected { + background: #efefef; +} + +a.box-backup { + color: #111; +} + +a.box-backup:hover { + background-color: #16A085; +} + +a.box-backup:hover i, a.box-backup:hover p { + color: #fff; +} + +.panel-sign { + color: #111; + background: #FAE448; +} + +.panel-ignore { + color: #fff; + background: #111; +} + +.share-wallet.panel { + background-color: #111; + color: #FBE500; +} + +.alert-box.success { + background-color: #CDEFE6; + color: #16A085; + border:none; +} +.alert-box.info { + background-color: #DEE6EF; + border:none; + color: #2C3E50; +} + +.alert-box.error { + background-color: #E8D7D7; + border:none; + color: #C0392B; +} + +.text-warning { + color:#C0392A; +} + +small.is-valid { + color: #04B404; +} + +small.has-error { + color: #f04124; +} + +.radius { + -webkit-border-radius: 10px; + border-radius: 10px; +} + +button.radius, .button.radius { + -webkit-border-radius: 5px; + border-radius: 5px; +} + +/* SECONDARY */ +button.secondary, +.button.secondary { + background-color: #1ABC9C; + color: #fff; +} +button.secondary:hover, +button.secondary:focus, +.button.secondary:hover, +.button.secondary:focus { + background-color: #16A085; + color: #e6e6e6; +} +button.disabled.secondary, +button[disabled].secondary, +.button.disabled.secondary, +.button[disabled].secondary, +button.disabled.secondary:hover, +button.disabled.secondary:focus, +button[disabled].secondary:hover, +button[disabled].secondary:focus, +.button.disabled.secondary:hover, +.button.disabled.secondary:focus, +.button[disabled].secondary:hover, +.button[disabled].secondary:focus { + background-color: #1ABC9C; + color: #E6E6E6; +} + +/* PRIMARY */ +button.primary, +.button.primary { + background-color: #E67E22; + color: #fff; +} +button.primary:hover, +button.primary:focus, +.button.primary:hover, +.button.primary:focus { + background-color: #D86601; + color: #e6e6e6; +} +button.disabled.primary, +button[disabled].primary, +.button.disabled.primary, +.button[disabled].primary, +button.disabled.primary:hover, +button.disabled.primary:focus, +button[disabled].primary:hover, +button[disabled].primary:focus, +.button.disabled.primary:hover, +.button.disabled.primary:focus, +.button[disabled].primary:hover, +.button[disabled].primary:focus { + background-color: #E67E22; + color: #E6E6E6; +} + +/* WARNING */ +button.warning, +.button.warning { + background-color: #C0392A; + color: #fff; +} +button.warning:hover, +button.warning:focus, +.button.warning:hover, +.button.warning:focus { + background-color: #82251A; + color: #e6e6e6; +} +button.disabled.warning, +button[disabled].warning, +.button.disabled.warning, +.button[disabled].warning, +button.disabled.warning:hover, +button.disabled.warning:focus, +button[disabled].warning:hover, +button[disabled].warning:focus, +.button.disabled.warning:hover, +.button.disabled.warning:focus, +.button[disabled].warning:hover, +.button[disabled].warning:focus { + background-color: #C0392A; + color: #E6E6E6; +} + +.text-gray { color: #999 !important;} + +#footer { + background: #2C3E50; + color: #fff; +} + +fieldset legend { + background: #F8F8FB; +} + +input.ng-invalid-wallet-secret { + background: #FFB6C1; +} + +.dr-notification { + background-color: #2C3E50; + color: #bfe2de; + border: 1px solid rgba(4, 94, 123, 0.85); + opacity: 0.9; +} +.dr-notification-close-btn { + background-color: #2C3E50; + color: #fff; + border: 1px solid rgba(4, 94, 123, 0.85); +} + +.dr-notification-image.dr-notification-type-info { + color: #FFF; +} + +.dr-notification-image.dr-notification-type-warning { + color: #FFA226; +} + +.dr-notification-image.dr-notification-type-error { + color: #FF4B4F; +} + +.dr-notification-image.dr-notification-type-success { + color: #B4D455; +} + +.dr-notification-image.success { + color: #B4D455; +} + +.success { + color: #3FBC9C; +} + +.box-setup fieldset { + background: #fff; +} + +.tooltip { + background: #16A085; + color: #fff; + font-weight: normal; + font-size: 14px; + padding: 3px 5px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + border: 1px solid #16A085; +} + +.tooltip>.nub { + border-color:transparent transparent #16A085 transparent; +} +.tooltip.tip-top>.nub { + border-color:#16A085 transparent transparent transparent; +} +.tooltip.tip-right>.nub { + border-color:transparent #16A085 transparent transparent; +} +.tooltip.tip-left>.nub { + border-color:transparent transparent transparent #16A085; +} + + diff --git a/css/mobile.css b/css/mobile.css index 1662fa149..54d34b3dc 100644 --- a/css/mobile.css +++ b/css/mobile.css @@ -1,50 +1,7 @@ -@media (max-width: 1024px) { - .logo { - background-size: 90px 44px !important; - height: 41px; - } - - .header-content { - font-size: 70%; - line-height: 120%; - font-weight: normal; - } - - .line-dashed-v { - border: none !important; - } +/* + * + * Copay mobile CSS + * + */ - .top-bar-section ul li>a { - font-size: 70%; - } -} -@media (max-width: 640px) { - .hide_menu { - display: none; - } - .show_menu { - display: block; - } - .top-bar-section ul li { - width: 100%; - } - .top-bar-section ul li>a { - padding: 0 0 0 15px; - } - - .top-bar { - background: #1ABC9C; - } - - .header-content .small-7 { - text-align: right !important; - padding-top: 0; - } - - .box-copayers figure { - height: 71px; - width: 71px; - } - -} diff --git a/css/tpl-clean.css b/css/tpl-clean.css deleted file mode 100644 index a6b2c3581..000000000 --- a/css/tpl-clean.css +++ /dev/null @@ -1,14 +0,0 @@ -.logo { - background: transparent url('../img/logo.png') no-repeat; -} - -#footer { - background: #333; - color: #fff; -} - -.dr-notification { - background-color: #000; - color: #fff; - border: 1px solid #eee; -} diff --git a/css/tpl-default.css b/css/tpl-default.css deleted file mode 100644 index e6cb2e01e..000000000 --- a/css/tpl-default.css +++ /dev/null @@ -1,349 +0,0 @@ -/* - * - * Copay Default Template - * - */ - -@font-face { - font-family: 'Ubuntu'; - font-style: normal; - font-weight: 300; - src: local('Ubuntu Light'), local('Ubuntu-Light'), url(../font/ubuntu-light.woff) format('woff'); -} -@font-face { - font-family: 'Ubuntu'; - font-style: normal; - font-weight: 400; - src: local('Ubuntu'), url(../font/ubuntu.woff) format('woff'); -} -@font-face { - font-family: 'Ubuntu'; - font-style: normal; - font-weight: 700; - src: local('Ubuntu Bold'), local('Ubuntu-Bold'), url(../font/ubuntu-bold.woff) format('woff'); -} -@font-face { - font-family: 'Ubuntu'; - font-style: italic; - font-weight: 700; - src: local('Ubuntu Bold Italic'), local('Ubuntu-BoldItalic'), url(../font/ubuntu-bold-italic.woff) format('woff'); -} - -* { - font-family: 'Ubuntu', Helvetica, sans-serif !important; -} - -body { - background: #F8F8FB; -} - -.logo { - background: transparent url('../img/logo-negative-beta.svg') no-repeat; - background-size: 130px 51px; -} - -.top-bar-section li:not(.has-form) a:not(.button) { - background: #1ABC9C; - color: #fff; -} - -.top-bar-section li.active:not(.has-form) a:not(.button) { - background: #F8F8FB; - color: #111; -} - -.top-bar-section li.active:not(.has-form) a:not(.button):hover, .top-bar-section li:not(.has-form) a:not(.button):hover { - background: #16A085; - color: white; -} - -.top-bar-section ul li>a { - color: #111; -} - -.header { - background: #2C3E50; - color: white; -} - -.header h1, h5, p { - color: #93A9BD; -} - -.header h6 { - color: #fff; -} - -.header .line-dashed-v { - border-right: 1px dashed #5A6B7D; -} - -.header a.button.small-icon { - background: white; - color: #2C3E50; -} - -.header a.button.small-icon:hover { - background: #16A085; - color: #fff; -} - -.header-content a { - color: #fff; -} - -.panel { - color: #333; - background: #FFFFFF; - border: 1px solid #EFEFEF; -} - -.transactions .panel { - background: #f5f5f5; -} - -.transactions .panel.pending { - background-color: #fff; -} - -.btransactions .panel { - background: #fff; -} - -.addresses .panel:hover, .addresses .panel.selected { - background: #efefef; -} - -a.box-backup { - color: #111; -} - -a.box-backup:hover { - background-color: #16A085; -} - -a.box-backup:hover i, a.box-backup:hover p { - color: #fff; -} - -.panel-sign { - color: #111; - background: #FAE448; -} - -.panel-ignore { - color: #fff; - background: #111; -} - -.share-wallet.panel { - background-color: #111; - color: #FBE500; -} - -.alert-box.success { - background-color: #CDEFE6; - color: #16A085; - border:none; -} -.alert-box.info { - background-color: #DEE6EF; - border:none; - color: #2C3E50; -} - -.alert-box.error { - background-color: #E8D7D7; - border:none; - color: #C0392B; -} - -.text-warning { - color:#C0392A; -} - -small.is-valid { - color: #04B404; -} - -small.has-error { - color: #f04124; -} - -.radius { - -webkit-border-radius: 10px; - border-radius: 10px; -} - -button.radius, .button.radius { - -webkit-border-radius: 5px; - border-radius: 5px; -} - -/* SECONDARY */ -button.secondary, -.button.secondary { - background-color: #1ABC9C; - color: #fff; -} -button.secondary:hover, -button.secondary:focus, -.button.secondary:hover, -.button.secondary:focus { - background-color: #16A085; - color: #e6e6e6; -} -button.disabled.secondary, -button[disabled].secondary, -.button.disabled.secondary, -.button[disabled].secondary, -button.disabled.secondary:hover, -button.disabled.secondary:focus, -button[disabled].secondary:hover, -button[disabled].secondary:focus, -.button.disabled.secondary:hover, -.button.disabled.secondary:focus, -.button[disabled].secondary:hover, -.button[disabled].secondary:focus { - background-color: #1ABC9C; - color: #E6E6E6; -} - -/* PRIMARY */ -button.primary, -.button.primary { - background-color: #E67E22; - color: #fff; -} -button.primary:hover, -button.primary:focus, -.button.primary:hover, -.button.primary:focus { - background-color: #D86601; - color: #e6e6e6; -} -button.disabled.primary, -button[disabled].primary, -.button.disabled.primary, -.button[disabled].primary, -button.disabled.primary:hover, -button.disabled.primary:focus, -button[disabled].primary:hover, -button[disabled].primary:focus, -.button.disabled.primary:hover, -.button.disabled.primary:focus, -.button[disabled].primary:hover, -.button[disabled].primary:focus { - background-color: #E67E22; - color: #E6E6E6; -} - -/* WARNING */ -button.warning, -.button.warning { - background-color: #C0392A; - color: #fff; -} -button.warning:hover, -button.warning:focus, -.button.warning:hover, -.button.warning:focus { - background-color: #82251A; - color: #e6e6e6; -} -button.disabled.warning, -button[disabled].warning, -.button.disabled.warning, -.button[disabled].warning, -button.disabled.warning:hover, -button.disabled.warning:focus, -button[disabled].warning:hover, -button[disabled].warning:focus, -.button.disabled.warning:hover, -.button.disabled.warning:focus, -.button[disabled].warning:hover, -.button[disabled].warning:focus { - background-color: #C0392A; - color: #E6E6E6; -} - -.text-gray { color: #999 !important;} - -#footer { - background: #2C3E50; - color: #fff; -} - -fieldset legend { - background: #F8F8FB; -} - -input.ng-invalid-wallet-secret { - background: #FFB6C1; -} - -.dr-notification { - background-color: #2C3E50; - color: #bfe2de; - border: 1px solid rgba(4, 94, 123, 0.85); - opacity: 0.9; -} -.dr-notification-close-btn { - background-color: #2C3E50; - color: #fff; - border: 1px solid rgba(4, 94, 123, 0.85); -} - -.dr-notification-image.dr-notification-type-info { - color: #FFF; -} - -.dr-notification-image.dr-notification-type-warning { - color: #FFA226; -} - -.dr-notification-image.dr-notification-type-error { - color: #FF4B4F; -} - -.dr-notification-image.dr-notification-type-success { - color: #B4D455; -} - -.dr-notification-image.success { - color: #B4D455; -} - -.success { - color: #3FBC9C; -} - -.box-setup fieldset { - background: #fff; -} - -.tooltip { - background: #16A085; - color: #fff; - font-weight: normal; - font-size: 14px; - padding: 3px 5px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - border: 1px solid #16A085; -} - -.tooltip>.nub { - border-color:transparent transparent #16A085 transparent; -} -.tooltip.tip-top>.nub { - border-color:#16A085 transparent transparent transparent; -} -.tooltip.tip-right>.nub { - border-color:transparent #16A085 transparent transparent; -} -.tooltip.tip-left>.nub { - border-color:transparent transparent transparent #16A085; -} - diff --git a/index.html b/index.html index 7e1d39cba..dc7f47cb5 100644 --- a/index.html +++ b/index.html @@ -1,1031 +1,83 @@ - - - - - Copay - Multisignature Wallet - - - - - - - - -
-
-
-
-
- -
-
- -
- Balance
- - - - {{totalBalance || 0 - |noFractionNumber}} {{$root.unitName}} - -
-
- Available to Spend
- - - - {{availableBalance || 0|noFractionNumber}} {{$root.unitName}} - -
- -
-
- - - -
- -
-
-
-
-

Share this secret with your other copayers -

-
-
-
-

{{$root.wallet.getSecret()}}

-
-
-
-
{{$root.wallet.getName()}}
-

{{$root.wallet.requiredCopayers}}-of-{{$root.wallet.totalCopayers}} wallet

-
-
-
-
-
-
-
-
-
-
People on this wallet
- -
- - - - - -

you{{c.nick}} - Backup ready

- [ID: {{c.peerId}}] -
-
- -
-

Waiting for other copayers to join

-
- -
-
-
-
-
- Download seed backup - - -
-
-
-
- -
- + + + + + Copay - Multisignature Wallet + + + + + + + + +
-
-
-
+
+ +
+ +
- + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + -

- Copay is a free, open-source, multisignature bitcoin wallet. A single-owner bitcoin wallet's security depends on carefully securing the private keys. With copay you can have multiple people controlling the funds, using bitcoin's multisignature functionality, requiring no trust in any third party. -

- Create -
- - -
-
-

Join a Wallet in Creation

-
- - - - -
-
-
- + + + + + + + + + + + -
-
- Settings · - - Create a new wallet · - - Import a backup -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/js/controllers/backup.js b/js/controllers/backup.js index f6fa34ad1..6a986f21a 100644 --- a/js/controllers/backup.js +++ b/js/controllers/backup.js @@ -2,10 +2,18 @@ angular.module('copayApp.controllers').controller('BackupController', function($scope, $rootScope, $location, $window, $timeout, $modal, backupService, walletFactory, controllerUtils) { - $scope.download = function() { - backupService.download($rootScope.wallet); + + $scope.backup = function() { + var w = $rootScope.wallet; + w.setBackupReady(); + backupService.download(w); }; + $scope.downloadBackup = function() { + var w = $rootScope.wallet; + backupService.download(w); + } + $scope.deleteWallet = function() { var w = $rootScope.wallet; w.disconnect(); diff --git a/js/controllers/footer.js b/js/controllers/footer.js deleted file mode 100644 index 491958f64..000000000 --- a/js/controllers/footer.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -angular.module('copayApp.controllers').controller('FooterController', function($rootScope, $sce, $scope, $http) { - - $scope.networkName = config.networkName; - - if (config.themes && Array.isArray(config.themes) && config.themes[0]) { - $scope.themes = config.themes; - } else { - $scope.themes = ['default']; - } - - $scope.theme = 'css/tpl-' + $scope.themes[0] + '.css'; - - $scope.change_theme = function(name) { - $scope.theme = 'css/tpl-' + name + '.css'; - }; - $scope.version = copay.version; - - $scope.getVideoURL = function(copayer) { - if (config.disableVideo) return; - - var vi = $rootScope.videoInfo[copayer] - if (!vi) return; - - if ($rootScope.wallet.getOnlinePeerIDs().indexOf(copayer) === -1) { - // peer disconnected, remove his video - delete $rootScope.videoInfo[copayer] - return; - } - - var encoded = vi.url; - var url = decodeURI(encoded); - var trusted = $sce.trustAsResourceUrl(url); - return trusted; - }; -}); diff --git a/js/controllers/send.js b/js/controllers/send.js index e9f3d92ec..7b7c87ce9 100644 --- a/js/controllers/send.js +++ b/js/controllers/send.js @@ -206,7 +206,7 @@ angular.module('copayApp.controllers').controller('SendController', $scope.openAddressBookModal = function() { var modalInstance = $modal.open({ - templateUrl: 'addressBookModal.html', + templateUrl: 'views/modals/addressbook.html', windowClass: 'tiny', controller: function($scope, $modalInstance) { diff --git a/js/controllers/setup.js b/js/controllers/setup.js index 3ac730299..cd3811853 100644 --- a/js/controllers/setup.js +++ b/js/controllers/setup.js @@ -85,4 +85,10 @@ angular.module('copayApp.controllers').controller('SetupController', }); }; + $scope.isSetupWalletPage = 0; + + $scope.setupWallet = function() { + $scope.isSetupWalletPage = !$scope.isSetupWalletPage; + }; + }); diff --git a/js/controllers/header.js b/js/controllers/sidebar.js similarity index 58% rename from js/controllers/header.js rename to js/controllers/sidebar.js index 3da4cc23e..82b8cf191 100644 --- a/js/controllers/header.js +++ b/js/controllers/sidebar.js @@ -1,25 +1,59 @@ 'use strict'; -angular.module('copayApp.controllers').controller('HeaderController', - function($scope, $rootScope, $location, notification, $http, $sce, controllerUtils, backupService) { +angular.module('copayApp.controllers').controller('SidebarController', + function($scope, $rootScope, $sce, $location, $http, notification, controllerUtils) { + + $scope.version = copay.version; + $scope.networkName = config.networkName; $scope.menu = [{ 'title': 'Addresses', 'icon': 'fi-address-book', - 'link': '#/addresses' + 'link': 'addresses' }, { 'title': 'Transactions', 'icon': 'fi-clipboard-pencil', - 'link': '#/transactions' + 'link': 'transactions' }, { 'title': 'Send', 'icon': 'fi-arrow-right', - 'link': '#/send' + 'link': 'send' }, { 'title': 'More...', 'icon': 'fi-download', - 'link': '#/backup' + 'link': 'backup' }]; + $scope.signout = function() { + logout(); + }; + + // Ensures a graceful disconnect + window.onbeforeunload = logout; + + $scope.$on('$destroy', function() { + window.onbeforeunload = undefined; + }); + + + $scope.refresh = function() { + var w = $rootScope.wallet; + w.connectToAll(); + if ($rootScope.addrInfos.length > 0) { + controllerUtils.updateBalance(function() { + $rootScope.$digest(); + }); + } + }; + + function logout() { + var w = $rootScope.wallet; + if (w) { + w.disconnect(); + controllerUtils.logout(); + } + } + + // ng-repeat defined number of times instead of repeating over array? $scope.getNumber = function(num) { return new Array(num); } @@ -41,79 +75,7 @@ angular.module('copayApp.controllers').controller('HeaderController', } }); - // Init socket handlers (with no wallet yet) controllerUtils.setSocketHandlers(); - $scope.isActive = function(item) { - if (item.link && item.link.replace('#', '') == $location.path()) { - return true; - } - return false; - }; - - $scope.signout = function() { - logout(); - }; - - $scope.refresh = function() { - var w = $rootScope.wallet; - w.connectToAll(); - if ($rootScope.addrInfos.length > 0) { - controllerUtils.updateBalance(function() { - $rootScope.$digest(); - }); - } - }; - - $rootScope.isCollapsed = true; - - $scope.toggleCollapse = function() { - $rootScope.isCollapsed = !$rootScope.isCollapsed; - }; - - function logout() { - var w = $rootScope.wallet; - if (w) { - w.disconnect(); - controllerUtils.logout(); - } - } - - // Ensures a graceful disconnect - window.onbeforeunload = logout; - - $scope.$on('$destroy', function() { - window.onbeforeunload = undefined; - }); - - $scope.backup = function() { - var w = $rootScope.wallet; - w.setBackupReady(); - backupService.download(w); - }; - - $scope.dowloadBackup = function() { - var w = $rootScope.wallet; - backupService.download(w); - } - - $scope.getVideoURL = function(copayer) { - if (config.disableVideo) return; - - var vi = $rootScope.videoInfo[copayer] - if (!vi) return; - - if ($rootScope.wallet.getOnlinePeerIDs().indexOf(copayer) === -1) { - // peer disconnected, remove his video - delete $rootScope.videoInfo[copayer] - return; - } - - var encoded = vi.url; - var url = decodeURI(encoded); - var trusted = $sce.trustAsResourceUrl(url); - return trusted; - }; - }); diff --git a/js/controllers/signin.js b/js/controllers/signin.js index 6503d46ab..3c7a097d8 100644 --- a/js/controllers/signin.js +++ b/js/controllers/signin.js @@ -75,4 +75,26 @@ angular.module('copayApp.controllers').controller('SigninController', }); }); } + + $scope.isHome = 1; + $scope.isJoin = 0; + $scope.isOpen = 0; + + $scope.backWallet = function() { + $scope.isHome = 1; + $scope.isJoin = 0; + $scope.isOpen = 0; + }; + + $scope.openWallet = function() { + $scope.isHome = 0; + $scope.isJoin = 0; + $scope.isOpen = 1; + }; + + $scope.joinWallet = function() { + $scope.isHome = 0; + $scope.isOpen = 0; + $scope.isJoin = 1; + }; }); diff --git a/js/controllers/video.js b/js/controllers/video.js new file mode 100644 index 000000000..159fcc277 --- /dev/null +++ b/js/controllers/video.js @@ -0,0 +1,25 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('VideoController', + function($scope, $rootScope, $sce) { + + $scope.getVideoURL = function(copayer) { + if (config.disableVideo) return; + + var vi = $rootScope.videoInfo[copayer] + if (!vi) return; + + if ($rootScope.wallet.getOnlinePeerIDs().indexOf(copayer) === -1) { + // peer disconnected, remove his video + delete $rootScope.videoInfo[copayer] + return; + } + + var encoded = vi.url; + var url = decodeURI(encoded); + var trusted = $sce.trustAsResourceUrl(url); + return trusted; + }; + +}); + diff --git a/js/routes.js b/js/routes.js index e4fe14cff..910fac48d 100644 --- a/js/routes.js +++ b/js/routes.js @@ -7,49 +7,50 @@ angular $routeProvider .when('/', { - templateUrl: 'signin.html', + templateUrl: 'views/signin.html', validate: false }) .when('/signin', { - templateUrl: 'signin.html', + templateUrl: 'views/signin.html', validate: false }) .when('/import', { - templateUrl: 'import.html', + templateUrl: 'views/import.html', validate: false }) .when('/setup', { - templateUrl: 'setup.html', + templateUrl: 'views/setup.html', validate: false }) .when('/addresses', { - templateUrl: 'addresses.html', + templateUrl: 'views/addresses.html', validate: true }) .when('/transactions', { - templateUrl: 'transactions.html', + templateUrl: 'views/transactions.html', validate: true }) .when('/send', { - templateUrl: 'send.html', + templateUrl: 'views/send.html', validate: true }) .when('/backup', { - templateUrl: 'backup.html', + templateUrl: 'views/backup.html', validate: true }) .when('/settings', { - templateUrl: 'settings.html', + templateUrl: 'views/settings.html', validate: false }) .when('/unsupported', { - templateUrl: 'unsupported.html' + templateUrl: 'views/unsupported.html' }) .when('/uri_payment/:data', { - templateUrl: 'uri_payment.html' + templateUrl: 'views/uri_payment.html' }) .otherwise({ - templateUrl: '404.html' + templateUrl: 'views/errors/404.html', + title: 'Error' }); }); @@ -58,8 +59,8 @@ angular .module('copayApp') .config(function($locationProvider) { $locationProvider - .html5Mode(false); - //.hashPrefix('!'); + .html5Mode(true) + .hashPrefix('!'); }) .run(function($rootScope, $location) { $rootScope.$on('$routeChangeStart', function(event, next, current) { diff --git a/test/unit/controllers/controllersSpec.js b/test/unit/controllers/controllersSpec.js index 58ef7cc73..91ac09904 100644 --- a/test/unit/controllers/controllersSpec.js +++ b/test/unit/controllers/controllersSpec.js @@ -44,7 +44,7 @@ describe("Unit: Controllers", function() { it('Backup controller #download', function() { scope.wallet.setEnc('1234567'); expect(saveAsLastCall).equal(null); - scope.download(); + scope.downloadBackup(); expect(saveAsLastCall.size).equal(7); expect(saveAsLastCall.type).equal('text/plain;charset=utf-8'); }); @@ -220,7 +220,7 @@ describe("Unit: Controllers", function() { }); - describe("Unit: Header Controller", function() { + describe("Unit: Sidebar Controller", function() { var scope, $httpBackendOut; var GH = 'https://api.github.com/repos/bitpay/copay/tags'; beforeEach(inject(function($controller, $injector) { @@ -241,7 +241,7 @@ describe("Unit: Controllers", function() { beforeEach(inject(function($controller, $rootScope) { rootScope = $rootScope; scope = $rootScope.$new(); - headerCtrl = $controller('HeaderController', { + headerCtrl = $controller('SidebarController', { $scope: scope, }); })); diff --git a/views/addresses.html b/views/addresses.html new file mode 100644 index 000000000..b9407f29b --- /dev/null +++ b/views/addresses.html @@ -0,0 +1,60 @@ +
+
+
+
+ +
+ +

+ + + + + + {{balanceByAddr[selectedAddr.address] || 0 | noFractionNumber}} + + + + {{selectedAddr.address}}
+ {{selectedAddr.balance || 0|noFractionNumber}} {{$root.unitName}} +
+
+

+
+
+
+

Create a New Address

+ +
+
+
+
+ diff --git a/views/backup.html b/views/backup.html new file mode 100644 index 000000000..4a9a48bba --- /dev/null +++ b/views/backup.html @@ -0,0 +1,18 @@ +
+
+

Backup

+

Its important to back up your wallet so that you can recover your wallet in case of disaster

+ +
+
+
+

Delete Wallet

+

If all funds have been removed from your wallet and you do not wish to have the wallet data stored on your computer anymore, you can delete your wallet.

+
+ Delete +
+
+
+ diff --git a/views/errors/404.html b/views/errors/404.html new file mode 100644 index 000000000..a171f16e8 --- /dev/null +++ b/views/errors/404.html @@ -0,0 +1,4 @@ +

404

+

Page not found

+

go back...

+ diff --git a/views/import.html b/views/import.html new file mode 100644 index 000000000..14edf580c --- /dev/null +++ b/views/import.html @@ -0,0 +1,35 @@ +
+
+ + {{ importStatus }} +
+
+
+
+
+

{{title}}

+
+ Choose backup file from your computer + +
+
+ +
+ + +
+
+
+
+
+ « Back + +
+
+
+
+
+
+ diff --git a/views/includes/copayers.html b/views/includes/copayers.html new file mode 100644 index 000000000..d331b2b29 --- /dev/null +++ b/views/includes/copayers.html @@ -0,0 +1,62 @@ +
+
+

Share this secret with your other copayers

+
+

{{$root.wallet.getSecret()}}

+
+
+

+ New Wallet Created +

+

Waiting Copayers for {{$root.wallet.getName()}}

+

+ {{$root.wallet.getName()}} - + {{$root.wallet.requiredCopayers}}-of-{{$root.wallet.totalCopayers}} +

+ + {{$root.wallet.requiredCopayers}}-of-{{$root.wallet.totalCopayers}} wallet + +
+ +
+ Waiting for other copayers to join +
+ +
+ Waiting for other + copayers to make a Backup +
+ + Download seed backup + + +
+ diff --git a/views/includes/sidebar.html b/views/includes/sidebar.html new file mode 100644 index 000000000..dda9d5d1f --- /dev/null +++ b/views/includes/sidebar.html @@ -0,0 +1,63 @@ +
+ + Copay v{{version}} + + Project Homapage + +
+ {{$root.wallet.getName()}} +
+
+ {{$root.wallet.requiredCopayers}}-of-{{$root.wallet.totalCopayers}} wallet + [LIVENET] + [TESTNET] +
+ +
+ + {{$root.wallet.getName()}} + + + +
+
+ Balance
+ + + + {{totalBalance || 0 + |noFractionNumber}} {{$root.unitName}} + +
+
+ Available to Spend
+ + + + {{availableBalance || 0|noFractionNumber}} {{$root.unitName}} + +
+ + + +
+ +
+ diff --git a/views/includes/video.html b/views/includes/video.html new file mode 100644 index 000000000..651181d9c --- /dev/null +++ b/views/includes/video.html @@ -0,0 +1,28 @@ +
+ + {{c}} +
+ you + {{c.nick}} + + Backup ready + + [ID: {{c.peerId}}] +
+
+ diff --git a/views/modals/addressbook.html b/views/modals/addressbook.html new file mode 100644 index 000000000..8dc679230 --- /dev/null +++ b/views/modals/addressbook.html @@ -0,0 +1,20 @@ +

Add Address Book Entry

+
+ + + Cancel + +
+× + diff --git a/views/send.html b/views/send.html new file mode 100644 index 000000000..abf12a60b --- /dev/null +++ b/views/send.html @@ -0,0 +1,146 @@ +
+
+
+

{{title}}

+
+
+
+
+ +
+ +
+
+ +
+
+ Cancel +
+
+
+
+ +
+
+ + + Get QR code + + +
+
+
+ +
+
+
+
+
+ +
+
+
+ + +
+ {{$root.unitName}} +
+
+
+
+ + Total amount for this transaction: + +
+ {{amount + defaultFee |noFractionNumber}} {{$root.unitName}} + + {{ ((amount + defaultFee) * unitToBtc)|noFractionNumber:8}} BTC + +
+ + Including fee of {{defaultFee|noFractionNumber}} {{$root.unitName}} + +
+
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+
+

Address Book

+

Empty. Create an alias for your addresses

+ + + + + + + + + + + + + + + + + + + +
LabelAddressCreatorDate 
{{info.label}}{{addr}}{{$root.wallet.publicKeyRing.nicknameForCopayer(info.copayerId)}}{{info.hidden ? + 'Enable' : 'Disable'}}
+ +
+
+
+ diff --git a/views/settings.html b/views/settings.html new file mode 100644 index 000000000..7496b40a1 --- /dev/null +++ b/views/settings.html @@ -0,0 +1,71 @@ +
+
+
+
+

{{title}}

+
+ Bitcoin Network + + +
+ Network has been fixed to + {{networkName}} in this setup. See copay.io + for options to use Copay on both livenet and testnet. +
+
+
+ Wallet Unit + +
+
+ Videoconferencing + + +
+
+ Insight API server + + + + + + + +

+ Insight API server is open-source software. You can run your own instance, check Insight API Homepage + +

+
+ PeerJS server + + + + + + + + + + +

+ PeerJS Server is open-source software. You can run your own instance, or use PeerJS Server cloud. Check PeerJS Server +

+
+
+
+
+
+ « Back + +
+
+
+
+
+ diff --git a/views/setup.html b/views/setup.html new file mode 100644 index 000000000..67aadbb05 --- /dev/null +++ b/views/setup.html @@ -0,0 +1,78 @@ +
+
+ + Creating wallet... +
+
+
+
+
+

Create new wallet

+ +
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+ « Back + « Back + + Next +
+
+
+
+
+
+ diff --git a/views/signin.html b/views/signin.html new file mode 100644 index 000000000..bff920108 --- /dev/null +++ b/views/signin.html @@ -0,0 +1,67 @@ +
+
+ + Authenticating and looking for peers... +
+
+
+
+

Open Wallet

+
+ + + « Back + +
+
+
+

Open a wallet

+ Open +
+
+

Create a new wallet

+ Create +
+
+

Join a Wallet in Creation

+
+ + + + « Back + +
+
+
+

Join a Wallet in Creation

+ Join +
+
+
Create a wallet
+ Create +
+
+ +
+

+ Copay is a free, open-source, multisignature bitcoin wallet. A single-owner bitcoin wallet's security depends on carefully securing the private keys. With copay you can have multiple people controlling the funds, using bitcoin's multisignature functionality, requiring no trust in any third party. +

+ +
+
+
+ + diff --git a/views/transactions.html b/views/transactions.html new file mode 100644 index 000000000..a1e809356 --- /dev/null +++ b/views/transactions.html @@ -0,0 +1,181 @@ +
+
+
+

Transaction proposals ({{txs.length}})

+ + +
+
+
+
+
+ {{out.value | noFractionNumber}} {{$root.unitName}}
+
+
+ +
+
+
+
+
{{tx.createdTs | amCalendar}}
+
+
+ +
+
+ "{{tx.comment}}" - {{$root.wallet.publicKeyRing.nicknameForCopayer(tx.creator)}} +
+ +
+
+ + {{cId}} + +
+ + +
+ {{$root.wallet.publicKeyRing.nicknameForCopayer(cId)}} +
+
+
+ +
+
+
+ + +
+
+ +
+
+ +
+
+ Transaction finally rejected +
+
+
+ Sent +
+
+ Transaction ID: + + {{tx.sentTxid}} + +
+
+

+ One signature missing +

+

+ {{tx.missingSignatures}} signatures missing

+
+ Fee: {{tx.fee|noFractionNumber}} {{$root.unitName}} + Proposal ID: {{tx.ntxid}} +
+
+
+
+

No pending transactions proposals.

+

No transactions proposals yet.

+ +
+
+
+

+ Last transactions + + + +

+ + +
+
+ No transactions yet. +
+
+
+
+ +
+
+ first seen at + +
+
+ mined at + +
+
+
+
+
+
+
+
+ {{vin.value| noFractionNumber}} {{$root.unitName}} +

+ +

+
+
+
+ +
+
+
+ {{vout.value| noFractionNumber}} {{$root.unitName}} +

+ +

+
+
+
+
+
+
+
Fees: {{btx.fees | noFractionNumber}} {{$root.unitName}}
+
Confirmations: {{btx.confirmations || 0}}
+
Total: {{btx.valueOut| noFractionNumber}} {{$root.unitName}}
+
+
+
+
+
+
+
+ diff --git a/views/unsupported.html b/views/unsupported.html new file mode 100644 index 000000000..75f043ef0 --- /dev/null +++ b/views/unsupported.html @@ -0,0 +1,13 @@ +

Browser unsupported

+

+ Copay uses webRTC for peer-to-peer communications, + but your browser does not support it. + Please use + a current version of Google Chrome, Mozilla Firefox, or Opera. +

+ + For more information + on supported browsers please check http://www.webrtc.org/ +

+ + diff --git a/views/uri_payment.html b/views/uri_payment.html new file mode 100644 index 000000000..6c488ee8d --- /dev/null +++ b/views/uri_payment.html @@ -0,0 +1,11 @@ +

+Preparing payment... +

+
+

Protocol: {{protocol}}

+

To: {{address}}

+

Amount: {{amount}}

+

Message:

+
{{message}}
+
+