diff --git a/.gitignore b/.gitignore index 0445455f1..7f0f7a730 100644 --- a/.gitignore +++ b/.gitignore @@ -47,7 +47,6 @@ 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..8e2fc4089 100644 --- a/css/main.css +++ b/css/main.css @@ -4,250 +4,364 @@ * */ +@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'); +} + +@keyframes rotateThis { + from { transform: scale( 1 ) rotate( 0deg ); } + to { transform: scale( 1 ) rotate( 360deg ); } +} + +@-webkit-keyframes rotateThis { + from { -webkit-transform: scale( 1 ) rotate( 0deg ); } + to { -webkit-transform: scale( 1 ) rotate( 360deg ); } +} + +@-webkit-keyframes yellow-flash { + 0% { + background-color: #FFFFE0; + opacity:1; + } + 22% { + background-color: #FFFFE0; + } + 100% { + background-color: none; + } +} + +::-webkit-input-placeholder { + color: #7A8C9E; +} + +:-moz-placeholder { /* Firefox 18- */ + color: #7A8C9E; +} + +::-moz-placeholder { /* Firefox 19+ */ + color: #7A8C9E; +} + +:-ms-input-placeholder { + color: #7A8C9E; +} + +#qr-canvas { display: none; } +#qrcode-scanner-video { + display: block; + margin: 0 auto; +} + * { - margin:0; - padding:0; + font-family: 'Ubuntu', Helvetica, sans-serif !important; } -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; -} - -.panel.input { - padding: 0.7rem 1rem; - margin-bottom: 0; - border-radius: 5px; - background: #F8F8F8; - -moz-box-shadow: inset 0px 0px 3px 0px rgba(0,0,0,0.10); - box-shadow: inset 0px 0px 3px 0px rgba(0,0,0,0.10); -} - -.text-gray.active { - color: #111 !important; - 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; +h1 { font-weight: 100; - font-size: 0.9rem; + font-size: 24px; + color: #2C3E50; + margin-bottom: 1rem; } -.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 { +h2 { + font-size: 20px; font-weight: 100; } -.top-bar { - height: auto; - width: 100%; -} - -.panel { - border:0; -} - -.panel.status { - margin: 0; -} - -.addresses .panel { - font-size: 0.9rem; -} - -.transactions .panel { - border: 1px solid #eee; -} - -.transactions .panel { - padding: 0; -} - -.pending table { - width: 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: 300; + font-size: 16px; + color: #fff; +} + +h4 { + font-size: 0.875rem; +} + +body, html{ + height:100%; + width:100%; +} + +.off-canvas-wrap, .inner-wrap{ + height:100%; +} + +.tab-bar { + display: none; +} + +a { + color: #3498DB; +} + +input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill, input:-webkit-autofill:focus, textarea:-webkit-autofill:focus, select:-webkit-autofill:focus { + -webkit-box-shadow: 0 0 0px 1000px white inset; +} + +.join label, +.open label, +.setup label { + font-size: 0.875rem; + color: #fff; font-weight: 100; - font-size: 25px; } -.line-dashed-v { - border-right: 2px dashed #E3E3E3; +a:hover { + color: #2980b9; } -.line-dashed-h { - margin: 1rem 0; - border-bottom: 1px dashed #E3E3E3; +.open input, +.join input, +.setup input, +.import input, +.settings input { + background: #2C3E50 !important; + -moz-box-shadow: inset 0px 0px 3px 0px rgba(0,0,0,0.10) !important; + box-shadow: inset 0px 0px 3px 0px rgba(0,0,0,0.10) !important; + border: 0 !important; + color: #7A8C9E !important; } -.panel p { - margin-bottom: 0; +.open select, +.join select, +.setup select, +.import select, +.settings select { + background: #2C3E50 !important; + border: 0 !important; + color: #7A8C9E !important; } -span.panel-res { - float: right; - padding: 0.4rem 0.55rem; - margin: 0 1rem; - border-radius: 1rem; +.page, .main { + height:100%; + overflow-y: auto; + overflow-x: none; + background-color: #2C3E50; } -.pending button { - margin: 0 10px 0 0; +.sidebar { + height:100%; + overflow-y: auto; + overflow-x: none; } -.line { - border-top: 1px solid #f2f2f2; - margin: 0.5rem 0 1rem; +.sidebar { + position: fixed; + width: 250px; + background-color: #2C3E50; + color: #fff; + line-height: 24px; } -.line-dashed { - border-top: 1px dashed #ccc; - margin: 1rem 0; - padding: 1rem 0; +.sidebar a { + color: #fff; +} + +.sidebar ul.copayer-list { + list-style-type: none; + padding:0; margin:0; +} + +.sidebar ul.copayer-list li { + margin-top: 15px; + font-weight: 100; + font-size: 12px; + color: #C9C9C9; +} + +.sidebar ul.copayer-list img { + width: 30px; + height: 30px; +} + +.button.small.side-bar { + padding: 0rem 0.4rem; +} + +.waiting { + border: 2px solid #fff; +} + + +.online { + border: 2px solid #1ABC9C; +} + +.offline { + border: 2px solid gray; + opacity: 0.4; +} + +.main { + margin-left: 250px; + padding: 1.5rem; + background-color: #F8F8FB; +} + +.home, .open, .join, .waiting-copayers, .setup, .import, .settings { + margin-top: 15%; + color: #fff; +} + +.import fieldset, .settings fieldset { + border: 1px solid #3C5269; +} + +.import fieldset legend, .settings fieldset legend { + background: transparent; + color: #fff; + font-weight: normal; +} + +.import input[type="file"], +.import label, +.import label small, +.settings label, +.settings label small { + color: #fff; +} + +.logo-setup { + text-align: center; + margin-top: 9%; +} + +.box-setup { + padding: 20px 30px; + background: #34495E; + margin-bottom: 20px; +} + +.last-transactions { + border: 1px solid #eee; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -ms-border-radius: 3px; + border-radius: 3px; + margin-bottom: 1.25rem; + background-color: #fff; +} + +.last-transactions-header { + padding: 10px 0; overflow: hidden; } - -small.is-valid { - font-weight: bold; +.last-transactions-footer { + padding: 10px 0; + overflow: hidden; } -small.has-error { - font-weight: bold; +.last-transactions-content { + background-color: #FDFCFC; + overflow: hidden; + padding: 10px 0; } -.totalAmount { - line-height: 120%; - margin-top:2px; +.last-transactions-content .box-status { + text-align: center; + font-size: 14; } - -/* Turn Off Number Input Spinners */ -input[type=number]::-webkit-inner-spin-button, -input[type=number]::-webkit-outer-spin-button { - -webkit-appearance: none; - margin: 0; +.last-transactions-content .box-copayer { + width: 60px; + margin-right: 20px; + float: left; + text-align: center; } - -.small { - font-size: 60%; - line-height: inherit; +.last-transactions-content .copayer-ico { + width: 30px; + height: 30px; } -.new-address { - width: 220px; +.last-transactions-content .box-copayer .icon-inactive { + color: #4C5B69; } - -.transactions button, .transactions .button { - padding: 0.5rem 2rem; + +.last-transactions-content .box-copayer .icon-active { + color: #ccc; +} + +.last-transactions-content .box-copayer .icon-active-check { + color: #3FBC9C; +} + +.last-transactions-content .box-copayer .icon-active-x { + color: #C0392B; +} + +.input-note { + margin-top: -10px; + display: block; + margin-bottom: 1rem; +} + +.send-note { + font-style: italic; + color: gray; + background-color: #EDEDF5; + padding: 1.5rem; + width: 400px; +} + +.box-note { + text-align: center; + clear: both; + font-style: italic; + color: gray; + margin-bottom: 10px; +} + +.button-setup a { + display: block; + padding: 20px 30px; + background: #34495E; + margin-bottom: 20px; + font-weight: 100; + font-size: 24px; +} + +.button-setup a:hover { + background: #3C4E60; +} + +.footer-setup { + overflow: hidden; } - -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;} +.pa {position: absolute;} +.m0 {margin: 0;} +.db {display: block;} .size-12 { font-size: 12px; } .size-14 { font-size: 14px; } .size-16 { font-size: 16px; } @@ -261,218 +375,114 @@ hr { margin: 2.25rem 0;} .m5t {margin-top: 5px;} .m10t {margin-top: 10px;} .m5b {margin-bottom: 5px;} +.m5r {margin-right: 5px;} .m10b {margin-bottom: 10px;} -.m15b {margin-bottom: 20px !important;} +.m15b {margin-bottom: 20px;} .m10r {margin-right: 10px;} -.m10 {margin: 10px !important;} -.m15 {margin: 15px !important;} +.m15l {margin-left: 15px;} +.m15t {margin-top: 15px;} +.m20r {margin-right: 20px;} +.m15r {margin-right: 15px;} +.m20t {margin-top: 20px;} +.m10 {margin: 10px;} +.m15 {margin: 15px;} +.m15h {margin: 0 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; */} +.p15 {padding:15px;} +.p20 {padding:20px;} +.p10 {padding:10px;} +.m30v {margin: 30px 0;} .m10h {margin:0 10px;} +.m10v {margin:10px 0;} .m30a {margin: 30px auto;} +.m-negative-l {margin-left: -0.9375rem;} .br100 {border-radius: 100%;} .lh {line-height: 0;} .oh {overflow:hidden;} .lh {line-height: 0;} -.video-small { - width: 50px; - height: 50px; - border-radius: 0.3rem; - display: inline; - float: right; +.small { + font-size: 60%; + line-height: inherit; } -.setup .video-small { - float: none !important; +.line-dashed-setup-v { + border-left: 1px dashed #415970; } -.online { - background-color: black; - border: 3px solid #1ABC9C; -} -.online:hover { - border-color: #16A085; -} -.offline { - border: 3px solid gray; - opacity: 0.4; +.line-dashed-v { + border-right: 1px dashed #E3E3E3; } -.tx-copayers { - overflow: hidden; - padding: 10px; +.line-dashed-h { + border-bottom: 1px dashed #E3E3E3; } -.box-copayers { - padding: 0.5rem 2rem 0.5rem 1rem; - float: left; +.line { + border-top: 1px solid #f2f2f2; + margin: 0.5rem 0 1rem; } -.box-copayers figure { - width: 51px; - height: 63px; - border-top-left-radius: 4px 4px; - border-bottom-left-radius: 4px 4px; - overflow: hidden; - margin-right: 0.8px; +.line-sidebar { + border-top: 1px solid #34495E; + margin: 1rem 0; } -.box-status { - width: 16px; - height: 55px; - border-top-right-radius: 4px 4px; - border-bottom-right-radius: 4px 4px; - float: left; +.line-sidebar-t { + border-top: 1px solid #3C5269; + padding-top: 0.5rem; +} + +.line-sidebar-b { + border-bottom: 1px solid #3C5269; + padding-bottom: 0.5rem; +} + +.line-dashed { + border-top: 1px dashed #ccc; + margin: 1rem 0; + padding: 1rem 0; overflow: hidden; } -.icon-status { - background: #2C3E50; - width: 16px; - float: left; - text-align: center; - display: block; - margin: 0.8px; - padding: 2.7px; +.name-wallet { + font-size: 16px; + line-height: 16px; } -.box-setup { - margin-bottom: 25px; +.box-livenet { + background: #213140; + padding: 0rem 0.5rem 0.2rem; + color: #7A8C9E; } -.box-setup-copayers { - position: relative; - background: #ffffff; - border: 2px solid #eee; +.founds { + font-weight: 100; + color: #7A8C9E; } -.box-setup-copayers:after, .box-setup-copayers:before { - bottom: 100%; - left: 50%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; +.hidden { + visibility: hidden; } -.box-setup-copayers:after { - border-color: rgba(255, 255, 255, 0); - border-bottom-color: #ffffff; - border-width: 20px; - margin-left: -20px; -} - -.box-setup-copayers:before { - border-color: rgba(238, 238, 238, 0); - border-bottom-color: #eee; - border-width: 23px; - margin-left: -23px; -} - -.box-setup-copayers-fix { - overflow: hidden; - padding: 10px 10px 0 10px; -} - -.box-setup-copay { - width: 60px; - height: 60px; - float: left; - margin-right: 10px; - margin-bottom: 10px; - border: 3px solid #eee; - opacity: 0.3; - border-radius: 0.3rem; -} - -.box-setup-copay-required { - border: 3px solid #1ABC9C; - opacity: 1; -} - -.tx-copayers { - background: #F8F8F8; - -moz-box-shadow: inset 0px 0px 4px 0px rgba(0,0,0,0.05), inset 0px 1px 1px 0px rgba(0,0,0,0.05); - box-shadow: inset 0px 0px 4px 0px rgba(0,0,0,0.05), inset 0px 1px 1px 0px rgba(0,0,0,0.05); -} - -.box-copayers .icon-inactive { - color: #4C5B69; -} - -.box-copayers .icon-active { - color: #fff; -} - -.box-copayers .icon-active-check { - color: #fff; - background: #3FBC9C; -} - -.box-copayers .icon-active-x { - color: #fff; - background: #C0392B; -} - -.box-note { - text-align: center; - clear: both; - font-style: italic; - color: gray; - margin-bottom: 10px; -} - -.box-signin { - padding: 20px 40px; - border: 1px solid #eee; - background-color: #fff; - text-align: center; - margin-bottom: 20px; -} - -.box-signin h3 { - margin-bottom: 20px; -} - -.box-signin .button { - margin: 20px 0; - width: 200px; -} - -a.loading { - background: #fff; -} - -#qr-canvas { display: none; } -#qrcode-scanner-video { - display: block; - margin: 0 auto; -} - -@keyframes rotateThis { - from { transform: scale( 1 ) rotate( 0deg ); } - to { transform: scale( 1 ) rotate( 360deg ); } -} - -@-webkit-keyframes rotateThis { - from { -webkit-transform: scale( 1 ) rotate( 0deg ); } - to { -webkit-transform: scale( 1 ) rotate( 360deg ); } +/* Turn Off Number Input Spinners */ +input[type=number]::-webkit-inner-spin-button, +input[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; } .icon-rotate { - animation-name: rotateThis; - animation-duration: 2s; - animation-iteration-count: infinite; - animation-timing-function: linear; - -webkit-animation-name: rotateThis; + animation-name: rotateThis; + animation-duration: 2s; + animation-iteration-count: infinite; + animation-timing-function: linear; + -webkit-animation-name: rotateThis; -webkit-animation-duration: 2s; -webkit-animation-iteration-count: infinite; -webkit-animation-timing-function: linear; @@ -486,32 +496,17 @@ a.loading { vertical-align:middle; } -@-webkit-keyframes yellow-flash { - 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 { @@ -524,7 +519,7 @@ a.loading { } .dr-notification-container.right { - right: 20px; + right: 0; } .dr-notification-container.left { @@ -541,20 +536,15 @@ a.loading { } .dr-notification-wrapper { - width: 380px; + width: 360px; position: relative; margin: 10px 0; } .dr-notification { - width: 380px; + width: 360px; clear: both; - min-height: 80px; - max-height: 90px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - -ms-border-radius: 5px; - border-radius: 5px; + height: 90px; overflow: hidden; } @@ -564,20 +554,15 @@ a.loading { -ms-border-radius: 20px; border-radius: 20px; display: inline-block; - padding: 3px; + padding: 5px; font-size: 12px; position: absolute; - right: -8px; + right: 350px; top: -8px; - -webkit-transition: all 0.35s cubic-bezier(0.31, 0.39, 0.21, 1.65); - -moz-transition: all 0.35s cubic-bezier(0.31, 0.39, 0.21, 1.65); - transition: all 0.35s cubic-bezier(0.31, 0.39, 0.21, 1.65); cursor: pointer; z-index: 10; } -.dr-notification-close-btn i { - padding-left: 3px; -} + .dr-notification-close-btn:hover { -webkit-transform: scale3d(1.25, 1.25, 1); -moz-transform: scale3d(1.25, 1.25, 1); @@ -587,13 +572,13 @@ a.loading { .dr-notification-image { width: 80px; - height: 80px; - border-right: 1px solid rgba(4, 94, 123, 0.85); + height: 90px; float: left; display: block; font-size: 40px; color: white; text-align: center; + border-right: 1px dashed #415970; } .dr-notification-image i { display: block; @@ -615,12 +600,50 @@ a.loading { .dr-notification-title { color: white; padding: 0px; - font-size: 16px; + font-size: 18px; + margin-top: 0; } -p.dr-notification-text { - margin-top: -5px; +.dr-notification { + background-color: #34495E; + color: #eee; + border: 1px solid #2C3E50; + opacity: 0.9; + +} +.dr-notification-close-btn { + background-color: #34495E; + color: #fff; + border: 1px solid #3C5269; +} + +.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: #1ABC9C; +} + +.dr-notification-text { font-size: 12px; + line-height: 120%; } .ellipsis { @@ -638,25 +661,342 @@ ul.pagination li.current a:hover, ul.pagination li.current a:focus { background: #16A085; } -.alert-box a { - color:white; +.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; + text-overflow: ellipsis; + overflow-y: hidden; } -.input-note { - margin-top: -10px; - display: block; - margin-bottom: 1rem; +.tooltip>.nub { + border-color:transparent transparent #16A085 transparent; } -.addressbook-disabled td { - color: #ccc; +.tooltip.tip-top>.nub { + border-color:#16A085 transparent transparent transparent; } -.addressbook-disabled td a { - color: #7A9FB6; +.tooltip.tip-right>.nub { + border-color:transparent #16A085 transparent transparent; +} +.tooltip.tip-left>.nub { + border-color:transparent transparent transparent #16A085; } -.back-button { - padding-top: 15px; - display: block; +.logo { + background: transparent url('../img/logo-negative-beta.svg') no-repeat; + background-size: 130px 51px; +} + +button.radius, .button.radius { + -webkit-border-radius: 5px; + border-radius: 5px; +} + +/* SECONDARY */ +button.secondary, +.button.secondary { + background-color: #4A90E2; + color: #fff; +} +button.secondary:hover, +button.secondary:focus, +.button.secondary:hover, +.button.secondary:focus { + background-color: #2980B9; + color: #fff; +} +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: #95a5a6; + color: #E6E6E6; +} + +/* PRIMARY */ +button.primary, +.button.primary { + background-color: #1ABC9C; + color: #fff; +} +button.primary:hover, +button.primary:focus, +.button.primary:hover, +.button.primary:focus { + background-color: #16A085; + color: #fff; +} +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: #95a5a6; + 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: #95a5a6; + color: #E6E6E6; +} + +/* WHITE */ +button.white, +.button.white { + background-color: #fff; + color: #2C3E50; +} +button.white:hover, +button.white:focus, +.button.white:hover, +.button.white:focus { + background-color: #E0E0E0; + color: #2C3E50; +} + +button.disabled.white, +button[disabled].white, +.button.disabled.white, +.button[disabled].white, +button.disabled.white:hover, +button.disabled.white:focus, +button[disabled].white:hover, +button[disabled].white:focus, +.button.disabled.white:hover, +.button.disabled.white:focus, +.button[disabled].white:hover, +.button[disabled].white:focus { + background-color: #95a5a6; + color: #E6E6E6; +} + +/* BLACK */ +button.black, +.button.black { + background-color: #2C3E50; + color: #fff; +} +button.black:hover, +button.black:focus, +.button.black:hover, +.button.black:focus { + background-color: #213140; + color: #fff; +} + +button.disabled.black, +button[disabled].black, +.button.disabled.black, +.button[disabled].black, +button.disabled.black:hover, +button.disabled.black:focus, +button[disabled].black:hover, +button[disabled].black:focus, +.button.disabled.black:hover, +.button.disabled.black:focus, +.button[disabled].black:hover, +.button[disabled].black:focus { + background-color: #95a5a6; + color: #E6E6E6; +} + +/* GRAY */ +button.gray, +.button.gray { + background-color: #A9B2B8; + color: #2C3E50; +} +button.gray:hover, +button.gray:focus, +.button.gray:hover, +.button.gray:focus { + background-color: #E0E5E5; + color: #2C3E50; +} + +.side-nav {padding: 0;} + +.side-nav li { + font-size: 16px; + line-height: 40px; + font-weight: 100; +} + +.side-nav li.active>a:first-child:not(.button) { + color: #2C3E50; + background-color: #F8F8FB; +} + +.side-nav li>a:first-child:not(.button), .side-nav li a:not(.button) { + color: #fff; +} + +.side-nav li>a:first-child:not(.button) i { + opacity: 0.6; +} + +.side-nav li.active>a:first-child:not(.button) i { + opacity: 1; +} + +.side-nav li.active:hover a { + background-color: #F8F8FB; +} + +.side-nav li:hover a { + background-color: #3C4E60; +} + +.addresses ul { + margin-left: 0; +} + +.video-box { + width: 70px; + text-align: center; + margin-right: 20px; + padding-bottom: 5px; float: left; } +.video-small { + width: 50px; + height: 50px; +} + +.icon-input { + position: absolute; + top: 11px; + right: 20px; + font-size: 16px; + color: #fff; +} + +.icon-input .fi-check { + background-color: #1ABC9C; + padding: 0.2rem 0.4rem; +} + +.icon-input .fi-x { + background-color: #C0392A; + padding: 0.2rem 0.4rem; +} + +.has-error { + color: #C0392A; +} + +.is-valid { + color: #1ABC9C; +} + +input.ng-invalid-match, input.ng-invalid-match:focus { + border-color: red; +} + +.copayers h3, .copayers h4, .waiting-copayers h4 { + color: #fff; + font-weight: 100; +} + +.copayers { + width: 100%; + background-color: #213140; + position: absolute; + bottom: 0; + left: 0; + padding: 20px; + border-top: 1px solid #475065; + overflow-y: hidden; +} + +.copayers i { + opacity: 0.6; +} + +.text-light {font-weight: 100;} +.text-gray {color: #8597A7;} +.text-primary {color: #1ABC9C;} +.text-secondary {color: #3498DB;} +.text-white {color: #fff;} + + +.footer-setup a.text-gray:hover {color: #fff;} +a.text-gray:hover {color: #2C3E50;} +a.text-primary:hover {color: #50E3C2;} +a.text-secondary:hover {color: #4A90E2;} +a.text-white:hover {color: #ccc;} + +.box-setup-copayers { + background: #2C3E50; + -moz-box-shadow: 0px 0px 0px 0px rgba(255,255,255,0.09), inset 0px 0px 2px 0px rgba(0,0,0,0.20); + box-shadow: 0px 0px 0px 0px rgba(255,255,255,0.09), inset 0px 0px 2px 0px rgba(0,0,0,0.20); + margin-bottom: 20px; +} + +.box-setup-copay-required { + border: 3px solid #1ABC9C; + opacity: 1; +} + +.loading-screen { + text-align: center; + background-color: #1ABC9C; + width: 100%; + position: absolute; + top: 40%; +} + +.box-setup .panel { + background-color: #2C3E50; + padding: 0.5rem; + border: 0; +} + +/*-----------------------------------------------------------------*/ diff --git a/css/mobile.css b/css/mobile.css index 1662fa149..37ee18786 100644 --- a/css/mobile.css +++ b/css/mobile.css @@ -1,50 +1,106 @@ +/* + * + * Copay mobile CSS + * + */ + @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; + + .line-dashed-setup-v, + .line-dashed-v, + .line-dashed-h { + border: none; } - .top-bar-section ul li>a { - font-size: 70%; - } -} + .logo-setup { + margin: 20px 0; + } -@media (max-width: 640px) { - .hide_menu { + .home, .open, .join, .waiting-copayers, .setup, .import, .settings { + margin-top: 0; + } + + .sidebar { 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; + .page, .main { + height: auto; + } + + .main { + height: 100%; + margin-top: 40px; + margin-left: 0; + margin-bottom: -40px; + padding-bottom: 60px; + } + + .tab-bar { + display: block; + position: fixed; + width: 100%; + z-index: 5; + background: #3C4E60; + } + + .left-off-canvas-menu { + background: #2C3E50; + } + + .off-canvas-wrap,.inner-wrap{ + height:100%; + } + + .page{ + height:100%; } - .box-copayers figure { - height: 71px; - width: 71px; + .copayers { + position: relative; + padding: 0; + overflow-y: none; + } + + ul.copayer-list img { + width: 30px; + height: 30px; + } + + .tab-bar-section { + text-align: left; + } + + .setup-page { + height: 100%; + } + + .hide-tab-bar { + display: none; + } + + + .tab-bar h1 { + font-weight: 100; + } + + ul.off-canvas-list li a { + border-bottom: 1px solid #425568; + padding: 0.66667rem 1rem; + color: #fff; + } + + ul.off-canvas-list li a i { + opacity: 0.6; + } + + .box-founds { + background-color: #213140; + } + + .left-small { + border-right: 1px solid #425568; } } + 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 3abe358a7..a531e0d0c 100644 --- a/index.html +++ b/index.html @@ -1,1045 +1,111 @@ - - - - - - Copay - Multisignature Wallet - - - - - - - - -
-
-
-
-
- -
-
- -
- Balance
- - - - {{totalBalance || 0 - |noFractionNumber}} {{$root.unitName}} - -
-
- Available to Spend
- - - - {{availableBalance || 0|noFractionNumber}} {{$root.unitName}} - -
+ + + + + Copay - Multisignature Wallet + + + + + + + + +
+
+
-
-
+
+ -
-
-
-
-

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

-
+
-
-
-
-
-
- - Save seed backup - | - - Delete 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 -
-
- - - + + + + + + + + + + + + + + + - + + + + + + + + + + + + + -
- - -
- -
-
-
- « Back - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/js/controllers/addresses.js b/js/controllers/addresses.js index a0281e1b1..72d985653 100644 --- a/js/controllers/addresses.js +++ b/js/controllers/addresses.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.controllers').controller('AddressesController', - function($scope, $rootScope, $timeout, controllerUtils) { + function($scope, $rootScope, $timeout, $modal, controllerUtils) { $scope.loading = false; var w = $rootScope.wallet; @@ -16,8 +16,22 @@ angular.module('copayApp.controllers').controller('AddressesController', }); }; - $scope.selectAddress = function(addr) { - $scope.selectedAddr = addr; + $scope.openAddressModal = function(address) { + var ModalInstanceCtrl = function ($scope, $modalInstance, address) { + $scope.address = address; + $scope.cancel = function () { + $modalInstance.dismiss('cancel'); + }; + }; + + $modal.open({ + templateUrl: 'views/modals/qr-address.html', + windowClass: 'tiny', + controller: ModalInstanceCtrl, + resolve: { + address: function() { return address; } + } + }); }; $rootScope.$watch('addrInfos', function() { @@ -37,9 +51,7 @@ angular.module('copayApp.controllers').controller('AddressesController', 'owned': addrinfo.owned }); } - $scope.selectedAddr = $scope.addresses[0]; - $scope.addrWithFund = $rootScope.receivedFund ? $rootScope.receivedFund[1] : null; - $rootScope.receivedFund = null; } } - }); + } +); diff --git a/js/controllers/backup.js b/js/controllers/backup.js index 509163b9d..df14062c7 100644 --- a/js/controllers/backup.js +++ b/js/controllers/backup.js @@ -2,9 +2,11 @@ angular.module('copayApp.controllers').controller('BackupController', function($scope, $rootScope, backupService, walletFactory, controllerUtils) { - $scope.download = function() { - backupService.download($rootScope.wallet); - }; + + $scope.downloadBackup = function() { + var w = $rootScope.wallet; + backupService.download(w); + } $scope.deleteWallet = function() { var w = $rootScope.wallet; diff --git a/js/controllers/copayers.js b/js/controllers/copayers.js new file mode 100644 index 000000000..c6a9c2c54 --- /dev/null +++ b/js/controllers/copayers.js @@ -0,0 +1,21 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('CopayersController', + function($scope, $rootScope, $location, backupService) { + + $scope.backup = function() { + var w = $rootScope.wallet; + w.setBackupReady(); + backupService.download(w); + }; + + $scope.downloadBackup = function() { + var w = $rootScope.wallet; + backupService.download(w); + } + + $scope.goToWallet = function() { + $location.path('/addresses'); + }; + + }); 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/home.js b/js/controllers/home.js new file mode 100644 index 000000000..14c5505ad --- /dev/null +++ b/js/controllers/home.js @@ -0,0 +1,10 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('HomeController', + function($scope, $rootScope, walletFactory, notification) { + $scope.loading = false; + if ($rootScope.pendingPayment) { + notification.info('Login Required', 'Please open wallet to complete payment'); + } + $scope.hasWallets = walletFactory.getWallets().length > 0 ? true : false; + }); diff --git a/js/controllers/join.js b/js/controllers/join.js new file mode 100644 index 000000000..13019b032 --- /dev/null +++ b/js/controllers/join.js @@ -0,0 +1,37 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('JoinController', + function($scope, $rootScope, walletFactory, controllerUtils, Passphrase, notification) { + $scope.loading = false; + + $scope.join = function(form) { + if (form && form.$invalid) { + notification.error('Error', 'Please enter the required fields'); + return; + } + + $scope.loading = true; + walletFactory.network.on('badSecret', function() {}); + + Passphrase.getBase64Async($scope.joinPassword, function(passphrase) { + walletFactory.joinCreateSession($scope.connectionId, $scope.nickname, passphrase, function(err, w) { + $scope.loading = false; + if (err || !w) { + if (err === 'joinError') + notification.error('Can\'t find peer.'); + else if (err === 'walletFull') + notification.error('The wallet is full'); + else if (err === 'badNetwork') + notification.error('Network Error', 'The wallet your are trying to join uses a different Bitcoin Network. Check your settings.'); + else if (err === 'badSecret') + notification.error('Bad secret', 'The secret string you entered is invalid'); + else + notification.error('Unknown error'); + controllerUtils.onErrorDigest(); + } else { + controllerUtils.startNetwork(w, $scope); + } + }); + }); + } + }); diff --git a/js/controllers/open.js b/js/controllers/open.js new file mode 100644 index 000000000..02d47dd1f --- /dev/null +++ b/js/controllers/open.js @@ -0,0 +1,43 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('OpenController', + function($scope, $rootScope, walletFactory, controllerUtils, Passphrase, notification) { + var cmp = function(o1, o2) { + var v1 = o1.show.toLowerCase(), + v2 = o2.show.toLowerCase(); + return v1 > v2 ? 1 : (v1 < v2) ? -1 : 0; + }; + $scope.loading = false; + $scope.wallets = walletFactory.getWallets().sort(cmp); + $scope.selectedWalletId = $scope.wallets.length ? $scope.wallets[0].id : null; + $scope.openPassword = ''; + + $scope.open = function(form) { + if (form && form.$invalid) { + notification.error('Error', 'Please enter the required fields'); + return; + } + + $scope.loading = true; + var password = form.openPassword.$modelValue; + + Passphrase.getBase64Async(password, function(passphrase) { + var w, errMsg; + try { + var w = walletFactory.open($scope.selectedWalletId, { + passphrase: passphrase + }); + } catch (e) { + errMsg = e.message; + }; + if (!w) { + $scope.loading = false; + notification.error('Error', errMsg || 'Wrong password'); + $rootScope.$digest(); + return; + } + controllerUtils.startNetwork(w, $scope); + }); + }; + + }); diff --git a/js/controllers/send.js b/js/controllers/send.js index e74966138..af3b819f4 100644 --- a/js/controllers/send.js +++ b/js/controllers/send.js @@ -2,7 +2,7 @@ var bitcore = require('bitcore'); angular.module('copayApp.controllers').controller('SendController', - function($scope, $rootScope, $window, $location, $timeout, $anchorScroll, $modal, isMobile, notification) { + function($scope, $rootScope, $window, $timeout, $anchorScroll, $modal, isMobile, notification) { $scope.title = 'Send'; $scope.loading = false; var satToUnit = 1 / config.unitToSatoshi; @@ -226,7 +226,7 @@ angular.module('copayApp.controllers').controller('SendController', $scope.openAddressBookModal = function() { var modalInstance = $modal.open({ - templateUrl: 'addressBookModal.html', + templateUrl: 'views/modals/address-book.html', windowClass: 'tiny', controller: function($scope, $modalInstance) { diff --git a/js/controllers/settings.js b/js/controllers/settings.js index cb1c7852c..c8f1532f8 100644 --- a/js/controllers/settings.js +++ b/js/controllers/settings.js @@ -74,7 +74,7 @@ angular.module('copayApp.controllers').controller('SettingsController', unitToSatoshi: $scope.selectedUnit.value, })); - var target = ($window.location.origin !== 'null' ? $window.location.origin : '') + $window.location.pathname; + var target = ($window.location.origin !== 'null' ? $window.location.origin : ''); $window.location.href = target; }; 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 56% rename from js/controllers/header.js rename to js/controllers/sidebar.js index 8ecf69e90..79b8ad859 100644 --- a/js/controllers/header.js +++ b/js/controllers/sidebar.js @@ -1,25 +1,63 @@ 'use strict'; -angular.module('copayApp.controllers').controller('HeaderController', - function($scope, $rootScope, $location, notification, $http, $sce, controllerUtils, backupService, walletFactory) { +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(); + }); + } + }; + + $scope.isActive = function(item) { + return item.link && item.link == $location.path().split('/')[1]; + }; + + 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,87 +79,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.deleteWallet = function() { - var w = $rootScope.wallet; - w.disconnect(); - walletFactory.delete(w.id, function() { - controllerUtils.logout(); - }); - }; - - $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 deleted file mode 100644 index 6503d46ab..000000000 --- a/js/controllers/signin.js +++ /dev/null @@ -1,78 +0,0 @@ -'use strict'; - -angular.module('copayApp.controllers').controller('SigninController', - function($scope, $rootScope, $location, walletFactory, controllerUtils, Passphrase, backupService, notification) { - var cmp = function(o1, o2) { - var v1 = o1.show.toLowerCase(), - v2 = o2.show.toLowerCase(); - return v1 > v2 ? 1 : (v1 < v2) ? -1 : 0; - }; - $rootScope.videoInfo = {}; - $scope.loading = false; - $scope.wallets = walletFactory.getWallets().sort(cmp); - $scope.selectedWalletId = $scope.wallets.length ? $scope.wallets[0].id : null; - $scope.openPassword = ''; - - if ($rootScope.pendingPayment) { - notification.info('Login Required', 'Please open wallet to complete payment'); - } - - $scope.open = function(form) { - if (form && form.$invalid) { - notification.error('Error', 'Please enter the required fields'); - return; - } - - $scope.loading = true; - var password = form.openPassword.$modelValue; - - Passphrase.getBase64Async(password, function(passphrase) { - var w, errMsg; - try { - var w = walletFactory.open($scope.selectedWalletId, { - passphrase: passphrase - }); - } catch (e) { - errMsg = e.message; - }; - if (!w) { - $scope.loading = false; - notification.error('Error', errMsg || 'Wrong password'); - $rootScope.$digest(); - return; - } - controllerUtils.startNetwork(w, $scope); - }); - }; - - $scope.join = function(form) { - if (form && form.$invalid) { - notification.error('Error', 'Please enter the required fields'); - return; - } - - $scope.loading = true; - walletFactory.network.on('badSecret', function() {}); - - Passphrase.getBase64Async($scope.joinPassword, function(passphrase) { - walletFactory.joinCreateSession($scope.connectionId, $scope.nickname, passphrase, function(err, w) { - $scope.loading = false; - if (err || !w) { - if (err === 'joinError') - notification.error('Can\'t find peer.'); - else if (err === 'walletFull') - notification.error('The wallet is full'); - else if (err === 'badNetwork') - notification.error('Network Error', 'The wallet your are trying to join uses a different Bitcoin Network. Check your settings.'); - else if (err === 'badSecret') - notification.error('Bad secret', 'The secret string you entered is invalid'); - else - notification.error('Unknown error'); - controllerUtils.onErrorDigest(); - } else { - controllerUtils.startNetwork(w, $scope); - } - }); - }); - } - }); diff --git a/js/controllers/uriPayment.js b/js/controllers/uriPayment.js index 9cbc383c6..18c02d000 100644 --- a/js/controllers/uriPayment.js +++ b/js/controllers/uriPayment.js @@ -10,7 +10,7 @@ angular.module('copayApp.controllers').controller('UriPaymentController', functi $scope.message = $rootScope.pendingPayment.message; $timeout(function() { - $location.path('signin'); + $location.path('/'); }, 1000); diff --git a/js/controllers/video.js b/js/controllers/video.js new file mode 100644 index 000000000..520f84e30 --- /dev/null +++ b/js/controllers/video.js @@ -0,0 +1,46 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('VideoController', + function($scope, $rootScope, $sce) { + + $rootScope.videoInfo = {}; + + // Cached list of copayers + $scope.copayers = $rootScope.wallet.getRegisteredPeerIds(); + + $scope.copayersList = function() { + return $rootScope.wallet.getRegisteredPeerIds(); + } + + $scope.hasVideo = function(copayer) { + return $rootScope.videoInfo[copayer.peerId]; + } + + $scope.isConnected = function(copayer) { + return $rootScope.wallet.getOnlinePeerIDs().indexOf(copayer.peerId) != -1; + } + + $scope.isBackupReady = function(copayer) { + return $rootScope.wallet.publicKeyRing.isBackupReady(copayer.copayerId); + } + + $scope.getVideoURL = function(copayer) { + if (config.disableVideo) return; + + var vi = $scope.videoInfo[copayer.peerId]; + if (!vi) return; + + if ($scope.isConnected(copayer)) { + // peer disconnected, remove his video + delete $rootScope.videoInfo[copayer.peerId]; + return; + } + + var encoded = vi.url; + var url = decodeURI(encoded); + var trusted = $sce.trustAsResourceUrl(url); + return trusted; + }; + +}); + diff --git a/js/directives.js b/js/directives.js index e0e2a2d00..b1d6c3b35 100644 --- a/js/directives.js +++ b/js/directives.js @@ -23,18 +23,6 @@ angular.module('copayApp.directives') }; } ]) - .directive('notification', ['$rootScope', - function($rootScope) { - return { - restrict: 'A', - link: function(scope, element, attrs, ctrl) { - setTimeout(function() { - scope.$apply(function() {}); - }, 5000); - } - }; - } - ]) .directive('enoughAmount', ['$rootScope', function($rootScope) { var bitcore = require('bitcore'); @@ -228,4 +216,20 @@ angular.module('copayApp.directives') } ]) + .directive('match', function () { + return { + require: 'ngModel', + restrict: 'A', + scope: { + match: '=' + }, + link: function(scope, elem, attrs, ctrl) { + scope.$watch(function() { + return (ctrl.$pristine && angular.isUndefined(ctrl.$modelValue)) || scope.match === ctrl.$modelValue; + }, function(currentValue) { + ctrl.$setValidity('match', currentValue); + }); + } + }; + }) ; diff --git a/js/routes.js b/js/routes.js index e4fe14cff..3f7308341 100644 --- a/js/routes.js +++ b/js/routes.js @@ -7,49 +7,58 @@ angular $routeProvider .when('/', { - templateUrl: 'signin.html', + templateUrl: 'views/home.html', validate: false }) - .when('/signin', { - templateUrl: 'signin.html', + .when('/open', { + templateUrl: 'views/open.html', + validate: false + }) + .when('/join', { + templateUrl: 'views/join.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('/copayers', { + templateUrl: 'views/copayers.html', + validate: true + }) .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' + .when('/uri-payment/:data', { + templateUrl: 'views/uri-payment.html' }) .otherwise({ - templateUrl: '404.html' + templateUrl: 'views/errors/404.html', + title: 'Error' }); }); @@ -58,8 +67,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) { @@ -67,7 +76,10 @@ angular $location.path('unsupported'); } else { if ((!$rootScope.wallet || !$rootScope.wallet.id) && next.validate) { - $location.path('signin'); + $location.path('/'); + } + if ($rootScope.wallet && !$rootScope.wallet.isReady()) { + $location.path('/copayers'); } } }); diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index 48024a837..7bae6bdce 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -27,7 +27,7 @@ angular.module('copayApp.services') } } - $location.path('signin'); + $location.path('/'); }; root.onError = function(scope) { diff --git a/js/services/notifications.js b/js/services/notifications.js index 43668edec..908ae74b7 100644 --- a/js/services/notifications.js +++ b/js/services/notifications.js @@ -242,24 +242,6 @@ directive('notifications', function(notification, $compile) { * Finally, the directive should have its own controller for * handling all of the notifications from the notification service */ - var html = - '
' + - '
' + - '' + - '
' + - '
' + - '
' + - '' + - '' + - '
' + - '
' + - '

{{noti.title}}

' + - '

{{noti.content}}

' + - '
' + - '
' + - '
'; - - function link(scope, element, attrs) { var position = attrs.notifications; position = position.split(' '); @@ -269,11 +251,10 @@ directive('notifications', function(notification, $compile) { } } - return { restrict: 'A', scope: {}, - template: html, + templateUrl: 'views/includes/notifications.html', link: link, controller: ['$scope', function NotificationsCtrl($scope) { diff --git a/js/services/uriHandler.js b/js/services/uriHandler.js index 969ff1c0e..59a8304c0 100644 --- a/js/services/uriHandler.js +++ b/js/services/uriHandler.js @@ -4,8 +4,8 @@ var UriHandler = function() {}; UriHandler.prototype.register = function() { var base = window.location.origin + '/'; - var url = base + '#/uri_payment/%s'; - // navigator.registerProtocolHandler('bitcoin', url, 'Copay'); + var url = base + '#/uri-payment/%s'; + navigator.registerProtocolHandler('bitcoin', url, 'Copay'); }; angular.module('copayApp.services').value('uriHandler', new UriHandler()); diff --git a/test/unit/controllers/controllersSpec.js b/test/unit/controllers/controllersSpec.js index 58ef7cc73..ba9d9e70e 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'); }); @@ -82,6 +82,7 @@ describe("Unit: Controllers", function() { describe('Address Controller', function() { var addressCtrl; + beforeEach(angular.mock.module('copayApp')); beforeEach(inject(function($controller, $rootScope) { scope = $rootScope.$new(); addressCtrl = $controller('AddressesController', { @@ -92,13 +93,6 @@ describe("Unit: Controllers", function() { it('should have a AddressesController controller', function() { expect(scope.loading).equal(false); }); - - it('selectedAddr should modify scope', function() { - expect(scope.selectedAddress).equal(undefined); - scope.selectAddress('hola'); - expect(scope.selectedAddr).equal('hola'); - }); - }); describe('Transactions Controller', function() { @@ -220,7 +214,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 +235,7 @@ describe("Unit: Controllers", function() { beforeEach(inject(function($controller, $rootScope) { rootScope = $rootScope; scope = $rootScope.$new(); - headerCtrl = $controller('HeaderController', { + headerCtrl = $controller('SidebarController', { $scope: scope, }); })); @@ -342,11 +336,11 @@ describe("Unit: Controllers", function() { }); }); - describe('Signin Controller', function() { + describe('Open Controller', function() { var what; beforeEach(inject(function($controller, $rootScope) { scope = $rootScope.$new(); - what = $controller('SigninController', { + what = $controller('OpenController', { $scope: scope, }); })); @@ -359,6 +353,20 @@ describe("Unit: Controllers", function() { scope.open(invalidForm); }); }); + }); + + describe('Join Controller', function() { + var what; + beforeEach(inject(function($controller, $rootScope) { + scope = $rootScope.$new(); + what = $controller('JoinController', { + $scope: scope, + }); + })); + + it('should exist', function() { + should.exist(what); + }); describe('#join', function() { it('should work with invalid form', function() { scope.join(invalidForm); diff --git a/test/unit/directives/directivesSpec.js b/test/unit/directives/directivesSpec.js index 07d71e84d..e0a2b389e 100644 --- a/test/unit/directives/directivesSpec.js +++ b/test/unit/directives/directivesSpec.js @@ -202,4 +202,37 @@ describe("Unit: Testing Directives", function() { }); }); + + describe('Match Password Inputs', function() { + beforeEach(inject(function($compile, $rootScope) { + $scope = $rootScope; + $rootScope.availableBalance = 1000; + var element = angular.element( + '
' + + '' + + '' + + '
' + ); + $scope.model = { + walletPassword: null, + walletPasswordConfirm: null + }; + $compile(element)($scope); + $scope.$digest(); + form = $scope.form; + })); + it('should not validate', function() { + form.walletPassword.$setViewValue('mysecretpassword'); + form.walletPasswordConfirm.$setViewValue('mySecretPassword'); + $scope.$digest(); + expect(form.walletPasswordConfirm.$invalid).to.equal(true); + }); + it('should validate', function() { + form.walletPassword.$setViewValue('mysecretpassword123'); + form.walletPasswordConfirm.$setViewValue('mysecretpassword123'); + $scope.$digest(); + expect(form.walletPasswordConfirm.$invalid).to.equal(false); + }); + }); + }); diff --git a/views/addresses.html b/views/addresses.html new file mode 100644 index 000000000..fe9a72184 --- /dev/null +++ b/views/addresses.html @@ -0,0 +1,41 @@ +
+
+

+ Addresses + +

+ +
+
+
    +
  • + +
    +
    +   + + change +
    +
    + +
    + + + + + {{addr.balance || 0|noFractionNumber}} {{$root.unitName}} + +
    +
  • +
+ + + Show all + Show less + +
+
+
+
+ diff --git a/views/backup.html b/views/backup.html new file mode 100644 index 000000000..174100023 --- /dev/null +++ b/views/backup.html @@ -0,0 +1,21 @@ +
+

Backup & Delete

+
+

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/copayers.html b/views/copayers.html new file mode 100644 index 000000000..593299d66 --- /dev/null +++ b/views/copayers.html @@ -0,0 +1,107 @@ +
+
+
+
+ Copay +
+
+
+
+

Waiting copayers

+

Share this secret with your other copayers

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

New Wallet Created

+
+
+

Download Backup

+
+
+

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

+
+
+
+
+

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

+
+
+

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

+
+
+ +
+
+
+
+ Waiting Copayer +

+ + Waiting... +

+
+
+
+
+
+ Waiting for other + copayers to make a Backup +
+
+
+ +
+ Download seed backup + + +
+
+
+
+
+ diff --git a/views/errors/404.html b/views/errors/404.html new file mode 100644 index 000000000..412bd093e --- /dev/null +++ b/views/errors/404.html @@ -0,0 +1,7 @@ +
+ Copay +
+

404

+

Page not found

+

go back...

+ diff --git a/views/home.html b/views/home.html new file mode 100644 index 000000000..3d9725e5a --- /dev/null +++ b/views/home.html @@ -0,0 +1,28 @@ +
+
+
+ Copay +
+ +
+
+ + diff --git a/views/import.html b/views/import.html new file mode 100644 index 000000000..02c3b0d62 --- /dev/null +++ b/views/import.html @@ -0,0 +1,33 @@ +
+
+ + {{ importStatus }} +
+
+
+ Copay +
+
+
+

{{title}}

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

{{noti.title}}

+
{{noti.content}}
+
+
+
+ diff --git a/views/includes/peer-list.html b/views/includes/peer-list.html new file mode 100644 index 000000000..4adcce3bf --- /dev/null +++ b/views/includes/peer-list.html @@ -0,0 +1,34 @@ +
+
+

+ + Copayers + + {{$root.wallet.requiredCopayers}} of {{$root.wallet.totalCopayers}} + +

+
+ + + +
diff --git a/views/includes/sidebar-mobile.html b/views/includes/sidebar-mobile.html new file mode 100644 index 000000000..3ed69cedb --- /dev/null +++ b/views/includes/sidebar-mobile.html @@ -0,0 +1,55 @@ +
+
+
+ + + + v{{version}} + LIVENET + TESTNET +
+
+
+
+ Balance + + + + {{totalBalance || 0 + |noFractionNumber}} {{$root.unitName}} + +
+
+ Available + + + + {{availableBalance || 0|noFractionNumber}} {{$root.unitName}} + +
+
+
+
+ + +
+ diff --git a/views/includes/sidebar.html b/views/includes/sidebar.html new file mode 100644 index 000000000..29f00ed44 --- /dev/null +++ b/views/includes/sidebar.html @@ -0,0 +1,64 @@ +
+
+
+ + + +
+ v{{version}} + LIVENET + TESTNET +
+
+
+
+ + {{$root.wallet.getName()}} + + +
+
+ Balance + + + + {{totalBalance || 0 + |noFractionNumber}} {{$root.unitName}} + +
+ Available + + + + {{availableBalance || 0|noFractionNumber}} {{$root.unitName}} + +
+
+
+ + +
+ +
+ diff --git a/views/includes/video.html b/views/includes/video.html new file mode 100644 index 000000000..78e757262 --- /dev/null +++ b/views/includes/video.html @@ -0,0 +1,29 @@ +
+
+ + + {{copayer}} + +
+ you + {{copayer.nick}} +
+ +
+ Backup ready +
+
+
diff --git a/views/join.html b/views/join.html new file mode 100644 index 000000000..04012b032 --- /dev/null +++ b/views/join.html @@ -0,0 +1,41 @@ +
+
+ + Authenticating and looking for peers... +
+
+
+ Copay +
+
+
+

Join a Wallet in Creation

+
+ + + + + + + +
+ « Back + +
+
+
+
+
+
+ + diff --git a/views/modals/address-book.html b/views/modals/address-book.html new file mode 100644 index 000000000..05bc3579f --- /dev/null +++ b/views/modals/address-book.html @@ -0,0 +1,20 @@ +

Add Address Book Entry

+
+ + + Cancel + +
+× + diff --git a/views/modals/qr-address.html b/views/modals/qr-address.html new file mode 100644 index 000000000..418a88cc9 --- /dev/null +++ b/views/modals/qr-address.html @@ -0,0 +1,13 @@ +
+ +

{{address.address}}

+
+ + + + + {{address.balance || 0|noFractionNumber}} {{$root.unitName}} + +
+
+× diff --git a/views/open.html b/views/open.html new file mode 100644 index 000000000..e665b8eff --- /dev/null +++ b/views/open.html @@ -0,0 +1,27 @@ +
+
+ + Authenticating and looking for peers... +
+
+
+ Copay +
+
+
+

Open Wallet

+
+ + +
+ « Back + +
+
+
+
+
+
+ + diff --git a/views/send.html b/views/send.html new file mode 100644 index 000000000..2d37e9655 --- /dev/null +++ b/views/send.html @@ -0,0 +1,156 @@ +
+
+

{{title}}

+
+
+
+
+
+ +
+ + + +
+
+ +
+
+ Cancel +
+
+
+
+ +
+
+ + + Get QR code + + +
+
+
+ +
+
+
+
+
+ +
+
+
+ + +
+ {{$root.unitName}} +
+
+
+
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+
Send to
+

+ {{address}}  +

+
Total amount for this transaction:
+

+ {{amount + defaultFee |noFractionNumber}} {{$root.unitName}} + + {{ ((amount + defaultFee) * unitToBtc)|noFractionNumber:8}} BTC
+ Including fee of {{defaultFee|noFractionNumber}} {{$root.unitName}} +
+

+
+
Note
+

{{commentText}}

+
+
+
+ +
+

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..c294f95f1 --- /dev/null +++ b/views/settings.html @@ -0,0 +1,76 @@ +
+
+
+ Copay +
+
+
+

{{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..0c182c23f --- /dev/null +++ b/views/setup.html @@ -0,0 +1,84 @@ +
+
+ + Creating wallet... +
+
+
+
+
+ Copay +
+
+
+

Create new wallet

+ +
+
+ + +
+
+ + + + +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+
+ « Back + « Back + + Next +
+
+
+
+
+
+
+ diff --git a/views/transactions.html b/views/transactions.html new file mode 100644 index 000000000..b3db5c600 --- /dev/null +++ b/views/transactions.html @@ -0,0 +1,173 @@ +
+
+

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)}} +
+
+
+ + +
+

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}} +

+ +

+
+
+
+ +
+
+
+
+
+ diff --git a/views/unsupported.html b/views/unsupported.html new file mode 100644 index 000000000..ac92f56b0 --- /dev/null +++ b/views/unsupported.html @@ -0,0 +1,14 @@ +
+ Copay +
+

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}}
+
+