Gravatar implemented and addressbook refactor

This commit is contained in:
Gabriel Masclef 2018-01-03 12:48:55 -03:00
parent b4770f75ae
commit d12f9d92f5
No known key found for this signature in database
GPG Key ID: DD6D7EAADE12280D
16 changed files with 210 additions and 85 deletions

View File

@ -119,6 +119,7 @@
"rxjs": "^5.5.2",
"simple-plist": "^0.2.1",
"sw-toolbox": "^3.6.0",
"ts-md5": "^1.2.2",
"zone.js": "^0.8.18"
},
"devDependencies": {

View File

@ -83,6 +83,7 @@ import { ShapeshiftShiftPage } from '../pages/integrations/shapeshift/shapeshift
/*Includes */
import { FeedbackCardPage } from '../pages/includes/feedback-card/feedback-card';
import { GravatarPage } from '../pages/includes/gravatar/gravatar';
import { TxpPage } from '../pages/includes/txp/txp';
import { WalletInfoPage } from '../pages/includes/wallet-info/wallet-info';
import { WalletItemPage } from '../pages/includes/wallet-item/wallet-item';
@ -246,6 +247,7 @@ let pages: any = [
CollectEmailPage,
FeeWarningPage,
GlideraPage,
GravatarPage,
FingerprintModalPage,
HomePage,
LanguagePage,

View File

@ -0,0 +1 @@
<img class="gravatar" alt="{{ name }}" height="{{ height }}" width="{{ width }}" src="https://secure.gravatar.com/avatar/{{ emailHash }}.jpg?s={{ width }}&d=mm">

View File

@ -0,0 +1,3 @@
page-gravatar {
}

View File

@ -0,0 +1,31 @@
import { Component, Input, OnInit } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { Md5 } from 'ts-md5/dist/md5';
import { Logger } from '@nsalaun/ng-logger';
@Component({
selector: 'gravatar',
templateUrl: 'gravatar.html',
})
export class GravatarPage {
private emailHash: any;
@Input() email: string;
@Input() name: string;
@Input() height: number;
@Input() width: number;
constructor(
private logger: Logger
) {
}
ngOnInit() {
this.logger.info('ionViewDidLoad GravatarPage');
if (typeof this.email === "string") {
this.emailHash = Md5.hashStr(this.email.toLowerCase() || '');
}
}
}

View File

@ -27,8 +27,7 @@
</ion-icon>
</ion-icon>
<ion-icon *ngIf="recipientType == 'contact'" item-left>
<img src="assets/img/contact-placeholder.svg" class="icon-contact">
<!-- TODO add gravatar -->
<gravatar [name]="name" [height]="30" [width]="30" [email]="email"></gravatar>
</ion-icon>
<ion-icon *ngIf="!recipientType" item-left>
<img src="assets/img/contact-placeholder.svg" class="icon-contact">

View File

@ -75,10 +75,7 @@
</div>
<div class="wallet" *ngIf="tx.recipientType == 'contact'" (click)="toggleAddress()">
<!--TODO: <gravatar class="send-gravatar" name="{{tx.name}}" height="30" width="30" email="{{toEmail}}"></gravatar> -->
<ion-icon item-start>
<img src="assets/img/contact-placeholder.svg" class="icon-contact">
</ion-icon>
<gravatar [name]="tx.name" [height]="30" [width]="30" [email]="tx.email"></gravatar>
<span *ngIf="tx.name && !showAddress">{{tx.name}}</span>
<span *ngIf="tx.name && showAddress">{{tx.toAddress}}</span>
</div>

View File

@ -15,14 +15,14 @@
<ion-icon class="scanner-icon" name="qr-scanner" item-right (click)="openScanner()"></ion-icon>
</ion-item>
</ion-card>
<ion-card *ngIf="filteredContactsList">
<ion-card *ngIf="filteredContactsList[0]">
<ion-item class="title">
<span translate>Transfer to Contact</span>
</ion-item>
<ion-list>
<button ion-item *ngFor="let item of filteredContactsList" (click)="goToAmount(item)">
<ion-icon item-start>
<img src="assets/img/contact-placeholder.svg" class="icon-contact">
<gravatar [name]="item.name" [width]="30" [email]="item.email"></gravatar>
</ion-icon>
<h2>{{item.name}}</h2>
</button>
@ -44,10 +44,14 @@
<ion-list>
<button ion-item *ngFor="let wallet of walletBtcList" (click)="goToAmount(wallet)">
<ion-icon item-start>
<img *ngIf="wallet.network == 'testnet'" [ngStyle]="{'background-color': wallet.color}" src="assets/img/icon-wallet-testnet.svg" class="icon-wallet" />
<img *ngIf="wallet.network != 'testnet'" [ngStyle]="{'background-color': wallet.color}" src="assets/img/icon-wallet.svg" class="icon-wallet" />
<img *ngIf="wallet.network == 'testnet'" [ngStyle]="{'background-color': wallet.color}" src="assets/img/icon-wallet-testnet.svg"
class="icon-wallet" />
<img *ngIf="wallet.network != 'testnet'" [ngStyle]="{'background-color': wallet.color}" src="assets/img/icon-wallet.svg"
class="icon-wallet" />
</ion-icon>
<h2>{{wallet.name}} <span *ngIf="wallet.m > 1">{{wallet.m}}-{{wallet.n}}</span></h2>
<h2>{{wallet.name}}
<span *ngIf="wallet.m > 1">{{wallet.m}}-{{wallet.n}}</span>
</h2>
</button>
</ion-list>
</ion-card>
@ -65,10 +69,14 @@
<ion-list>
<button ion-item *ngFor="let wallet of walletBchList" (click)="goToAmount(wallet)">
<ion-icon item-start>
<img *ngIf="wallet.network == 'testnet'" [ngStyle]="{'background-color': wallet.color}" src="assets/img/icon-wallet-testnet.svg" class="icon-wallet" />
<img *ngIf="wallet.network != 'testnet'" [ngStyle]="{'background-color': wallet.color}" src="assets/img/icon-wallet.svg" class="icon-wallet" />
<img *ngIf="wallet.network == 'testnet'" [ngStyle]="{'background-color': wallet.color}" src="assets/img/icon-wallet-testnet.svg"
class="icon-wallet" />
<img *ngIf="wallet.network != 'testnet'" [ngStyle]="{'background-color': wallet.color}" src="assets/img/icon-wallet.svg"
class="icon-wallet" />
</ion-icon>
<h2>{{wallet.name}} <span *ngIf="wallet.m > 1">{{wallet.m}}-{{wallet.n}}</span></h2>
<h2>{{wallet.name}}
<span *ngIf="wallet.m > 1">{{wallet.m}}-{{wallet.n}}</span>
</h2>
</button>
</ion-list>
</ion-card>

View File

@ -15,7 +15,7 @@
<div class="zero-state" *ngIf="isEmptyList">
<i class="icon zero-state-icon">
<img class="svg" src="assets/img/address-book-add.svg"/>
<img class="svg" src="assets/img/address-book-add.svg" />
</i>
<div class="zero-state-heading" translate>No contacts yet</div>
<div class="zero-state-description" translate>Get started by adding your first one.</div>
@ -29,8 +29,12 @@
<div *ngIf="!isEmptyList">
<ion-searchbar (ionInput)="getItems($event)"></ion-searchbar>
<ion-list>
<button ion-item *ngFor="let entry of filteredAddressbook" (click)="viewEntry(entry)">
{{ entry.name }}
<button class="contact" ion-item *ngFor="let entry of filteredAddressbook" (click)="viewEntry(entry)">
<gravatar [name]="entry.name" [height]="30" [width]="30" [email]="entry.email"></gravatar>
<div>
<div>{{ entry.name }}</div>
<div class="text-gray">{{ entry.address }}</div>
</div>
</button>
</ion-list>
</div>

View File

@ -33,5 +33,14 @@ page-addressbook {
max-width: 300px;
}
}
.contact {
ion-label {
display: flex;
align-items: center;
gravatar {
margin-right: 1.5rem;
}
}
}
}

View File

@ -34,20 +34,20 @@ export class AddressbookPage {
}
private initAddressbook(): void {
this.addressbookProvider.list().then((ab) => {
this.isEmptyList = _.isEmpty(ab);
this.addressbookProvider.list().then((addressBook: any) => {
this.isEmptyList = _.isEmpty(addressBook);
let contacts: Array<object> = [];
_.each(ab, (v, k) => {
_.each(addressBook, (contact: any, k: string) => {
contacts.push({
name: _.isObject(v) ? v.name : v,
name: _.isObject(contact) ? contact.name : contact,
address: k,
email: _.isObject(v) ? v.email : null
email: _.isObject(contact) ? contact.email : null
});
});
this.addressbook = _.clone(contacts);
this.filteredAddressbook = _.clone(this.addressbook);
}).catch((err) => {
}).catch((err: any) => {
this.logger.error(err);
let alertError = this.alertCtrl.create({
title: err,
@ -68,14 +68,14 @@ export class AddressbookPage {
this.navCtrl.push(AddressbookAddPage);
};
public viewEntry(ab: any): void {
this.navCtrl.push(AddressbookViewPage, { address: ab.address });
public viewEntry(contact: any): void {
this.navCtrl.push(AddressbookViewPage, { contact: contact });
}
public getItems(ev: any): void {
public getItems(event: any): void {
// set val to the value of the searchbar
let val = ev.target.value;
let val = event.target.value;
// if the value is an empty string don't filter the items
if (val && val.trim() != '') {

View File

@ -1,23 +1,36 @@
<ion-header>
<ion-navbar>
<ion-title>{{ contact.name }}</ion-title>
<ion-navbar transparent>
<ion-title>{{ name }}</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-card>
<ion-card-header>
{{ contact.name }}
</ion-card-header>
<ion-card-content text-wrap>
{{ contact.address }}
</ion-card-content>
</ion-card>
<button ion-button clear color="danger" (click)="remove()">Remove</button>
</ion-content>
<ion-content>
<div class="contact-view-header">
<gravatar [name]="name" [height]="80" [width]="80" [email]="email"></gravatar>
</div>
<ion-list>
<ion-item>
{{'Name' | translate}}
<ion-note item-end>
{{ name }}
</ion-note>
</ion-item>
<ion-item>
{{'Email' | translate}}
<ion-note item-end>
{{ email }}
</ion-note>
</ion-item>
<ion-item copy-to-clipboard="{{ address }}">
{{'Address' | translate}}
<ion-note item-end>
{{ address }}
</ion-note>
</ion-item>
<ion-item-divider color="light"></ion-item-divider>
<button ion-item class="btn-send" (click)="sendTo()" translate>Send Money</button>
<ion-item-divider color="light"></ion-item-divider>
<button ion-item class="btn-remove" (click)="remove()" translate>Remove</button>
<ion-item-divider color="light"></ion-item-divider>
</ion-list>
</ion-content>

View File

@ -1,3 +1,36 @@
page-addressbook-view {
.toolbar {
background-color: #192c3a;
&-content {
margin-right: 70px;
}
&-title {
text-align: center;
}
.back-button, &-title {
color: white;
}
.back-button:hover {
color: white;
}
}
.contact-view-header {
position: relative;
height: 70px;
border-color: #192c3a;
background-color: #192c3a;
padding-top: 20px;
margin-bottom: 50px;
text-align: center;
.gravatar {
border-radius: 3px;
display: inline-block;
}
}
.btn-send {
color: color($colors, primary);
}
.btn-remove {
color: color($global-colors, assertive);
}
}

View File

@ -1,6 +1,15 @@
import { Component } from '@angular/core';
import { NavController, NavParams, AlertController } from 'ionic-angular';
import { importType } from '@angular/compiler/src/output/output_ast';
// Pages
import { AmountPage } from '../../../../pages/send/amount/amount';
// Providers
import { AddressBookProvider } from '../../../../providers/address-book/address-book';
import { AddressProvider } from '../../../../providers/address/address';
import { BwcProvider } from '../../../../providers/bwc/bwc';
import { PopupProvider } from '../../../../providers/popup/popup';
@Component({
selector: 'page-addressbook-view',
@ -8,55 +17,62 @@ import { AddressBookProvider } from '../../../../providers/address-book/address-
})
export class AddressbookViewPage {
private address: string;
public contact: any;
public address: string;
public name: string;
public email: string;
private bitcoreCash: any;
private coin: string;
public contact: Object = {
name: '',
address: '',
email: ''
};
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public alertCtrl: AlertController,
public ab: AddressBookProvider
private addressBookProvider: AddressBookProvider,
private addressProvider: AddressProvider,
private alertCtrl: AlertController,
private bwcProvider: BwcProvider,
private navCtrl: NavController,
private navParams: NavParams,
private popupProvider: PopupProvider
) {
this.address = this.navParams.get('address');
this.bitcoreCash = this.bwcProvider.getBitcoreCash();
this.address = this.navParams.data.contact.address;
this.name = this.navParams.data.contact.name;
this.email = this.navParams.data.contact.email;
var cashAddress = this.bitcoreCash.Address.isValid(this.address, 'livenet');
if (cashAddress) {
this.coin = 'bch';
} else {
this.coin = 'btc';
}
}
ionViewDidLoad() {
this.ab.get(this.address).then((entry) => {
this.contact = entry;
}).catch((err) => {
let alertError = this.alertCtrl.create({
title: err,
buttons: [
{
text: 'Go back',
handler: () => {
this.navCtrl.pop();
}
}
]
});
alertError.present();
}
public sendTo(): void {
this.navCtrl.push(AmountPage, {
toAddress: this.address,
name: this.name,
email: this.email,
coin: this.coin,
recipientType: 'contact',
network: this.addressProvider.validateAddress(this.address).network,
});
}
public remove(): void {
this.ab.remove(this.address).then(() => {
this.navCtrl.pop();
}).catch((err) => {
let alertError = this.alertCtrl.create({
title: err,
buttons: [
{
text: 'OK'
}
]
public remove(addr: string): void {
var title = 'Warning!'; // Todo: gettextCatalog
var message = 'Are you sure you want to delete this contact?'; // Todo: gettextCatalog
this.popupProvider.ionicConfirm(title, message, null, null).then((res: any) => {
if (!res) return;
this.addressBookProvider.remove(addr).then((ab) => {
this.navCtrl.pop();
}).catch((err: any) => {
this.popupProvider.ionicAlert('Error', err); // Todo: gettextCatalog
return;
});
alertError.present();
});
}

View File

@ -1,4 +1,6 @@
import { Injectable } from '@angular/core';
// Providers
import { BwcProvider } from '../../providers/bwc/bwc';
@Injectable()

View File

@ -122,6 +122,12 @@ $global-colors: (
.text-bold {
font-weight: 700;
}
.gravatar {
min-width: 3rem;
min-height: 3rem;
}
/*
* Wallet selector
*/