diff --git a/app/assets/styles/blink/_ContactCard.scss b/app/assets/styles/blink/_ContactCard.scss
index 79f4e6f..4d6e03b 100644
--- a/app/assets/styles/blink/_ContactCard.scss
+++ b/app/assets/styles/blink/_ContactCard.scss
@@ -1,116 +1,116 @@
.containerPortrait {
}
.containerLandscape {
}
.cardPortraitContainer {
margin-top: 0.5px;
}
.cardLandscapeContainer {
flex: 1;
margin-left: 1px;
margin-top: 1px;
border-radius: 2px;
}
.cardLandscapeTabletContainer {
flex: 1;
border: 1px;
border-radius: 2px;
}
.cardPortraitTabletContainer {
flex: 1;
border: 1px;
border-radius: 2px;
}
.rowContent {
flex: 1;
flex-direction: row;
justify-content: space-between;
}
.cardContent {
flex: 1;
flex-direction: row;
}
.title {
font-size: 18px;
padding-bottom: 7px;
flex: 1;
}
.subtitle {
font-size:14px;
margin-top: -5px;
margin-bottom: 0px;
flex: 1;
}
.description {
font-size:12px;
margin-bottom: 0px;
flex: 1;
}
.avatarContent {
margin-top: 5px;
}
.gravatar {
- width: 60px;
- height: 60px;
+ width: 50px;
+ height: 50px;
border-width: 2px;
border-color: white;
border-radius: 50px;
}
.mainContent {
margin-left: 10px;
}
.rightContent {
margin-top: 10px;
margin-left: 60px;
margin-right: 10px;
align-items: flex-end;
border: 0px;
}
.badgeTextStyle {
font-size: 12px;
}
.badgeContainer {
position: absolute;
bottom: 10;
right: 0;
size: 30;
}
.selectedContact {
margin-top: 15px;
}
.participants {
margin-top: 10px;
}
.participant {
font-size: 14px;
}
.buttonContainer {
margin: 0 auto;
margin-top:auto;
}
.button {
border-radius: 2px;
padding-left: 30px;
padding-right: 30px;
}
diff --git a/app/components/ContactCard.js b/app/components/ContactCard.js
index a607e5e..59bb62f 100644
--- a/app/components/ContactCard.js
+++ b/app/components/ContactCard.js
@@ -1,432 +1,432 @@
import React, { Component, Fragment} from 'react';
import { View, SafeAreaView, FlatList } from 'react-native';
import { Badge } from 'react-native-elements'
import autoBind from 'auto-bind';
import PropTypes from 'prop-types';
import moment from 'moment';
import momentFormat from 'moment-duration-format';
import { Card, IconButton, Button, Caption, Title, Subheading, List, Text, Menu} from 'react-native-paper';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import uuid from 'react-native-uuid';
import styles from '../assets/styles/blink/_ContactCard.scss';
import UserIcon from './UserIcon';
import { GiftedChat } from 'react-native-gifted-chat'
import {Gravatar, GravatarApi} from 'react-native-gravatar';
import utils from '../utils';
function toTitleCase(str) {
return str.replace(
/\w\S*/g,
function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
}
);
}
const Item = ({ nr, uri, name }) => (
{name !== uri?
{name} ({uri})
:
{uri}
}
);
const renderItem = ({ item }) => (
-
);
function isIp(ipaddress) {
if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipaddress)) {
return (true)
}
return (false)
}
class ContactCard extends Component {
constructor(props) {
super(props);
autoBind(this);
this.state = {
id: this.props.contact.id,
contact: this.props.contact,
invitedParties: this.props.invitedParties,
orientation: this.props.orientation,
isTablet: this.props.isTablet,
isLandscape: this.props.isLandscape,
favorite: (this.props.contact.tags.indexOf('favorite') > -1)? true : false,
blocked: (this.props.contact.tags.indexOf('blocked') > -1)? true : false,
confirmRemoveFavorite: false,
confirmPurgeChat: false,
messages: this.props.messages,
unread: this.props.unread,
chat: this.props.chat,
pinned: this.props.pinned,
fontScale: this.props.fontScale,
selectMode: this.props.selectMode
}
this.menuRef = React.createRef();
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
id: nextProps.contact.id,
contact: nextProps.contact,
invitedParties: nextProps.invitedParties,
isLandscape: nextProps.isLandscape,
orientation: nextProps.orientation,
favorite: (nextProps.contact.tags.indexOf('favorite') > -1)? true : false,
blocked: (nextProps.contact.tags.indexOf('blocked') > -1)? true : false,
chat: nextProps.chat,
pinned: nextProps.pinned,
messages: nextProps.messages,
unread: nextProps.unread,
fontScale: nextProps.fontScale,
selectMode: nextProps.selectMode
});
}
shouldComponentUpdate(nextProps) {
//https://medium.com/sanjagh/how-to-optimize-your-react-native-flatlist-946490c8c49b
return true;
}
findObjectByKey(array, key, value) {
for (var i = 0; i < array.length; i++) {
if (array[i][key] === value) {
return array[i];
}
}
return null;
}
toggleBlocked() {
this.props.toggleBlocked(this.state.contact.uri);
}
setBlockedDomain() {
let newBlockedState = this.props.toggleBlocked('@' + this.state.contact.uri.split('@')[1]);
this.setState({blocked: newBlockedState});
}
undo() {
this.setState({confirmRemoveFavorite: false,
confirmDeleteChat: false,
action: null});
}
onSendMessage(messages) {
messages.forEach((message) => {
// TODO send messages using account API
});
this.setState({messages: GiftedChat.append(this.state.messages, messages)});
}
setTargetUri(uri, contact) {
this.props.setTargetUri(uri, this.state.contact);
}
renderChatComposer () {
return null;
}
render () {
let showActions = this.state.contact.showActions &&
this.state.contact.tags.indexOf('test') === -1 &&
this.state.contact.tags !== ["synthetic"];
let tags = this.state.contact ? this.state.contact.tags : [];
let uri = this.state.contact.uri;
let username = uri.split('@')[0];
let domain = uri.split('@')[1];
let isPhoneNumber = username.match(/^(\+|0)(\d+)$/);
let name = this.state.contact.name;
if (this.state.contact.organization) {
name = name + ' - ' + this.state.contact.organization;
}
let showBlockButton = !this.state.contact.conference && !this.state.chat;
let showBlockDomainButton = false;
let blockTextbutton = 'Block';
let blockDomainTextbutton = 'Block domain';
let contact_ts = '';
let participantsData = [];
if (this.state.favorite) {
if (!this.state.blocked) {
showBlockButton = false;
}
}
if (tags.indexOf('test') > -1) {
showBlockButton = false;
}
if (name === 'Myself') {
showBlockButton = false;
}
if (this.state.blocked) {
blockTextbutton = 'Unblock';
}
let color = {};
let title = name || username;
let subtitle = uri;
let description = 'No calls or messages';
var todayStart = new Date();
todayStart.setHours(0,0,0,0);
if (this.state.contact.timestamp) {
description = moment(this.state.contact.timestamp).format('MMM D HH:mm');
if (this.state.contact.timestamp > todayStart) {
contact_ts = moment(this.state.contact.timestamp).format('HH:mm');
} else {
contact_ts = moment(this.state.contact.timestamp).format('DD-MM');
}
}
if (name === uri) {
title = toTitleCase(username);
}
if (isPhoneNumber && isIp(domain)) {
title = 'Tel ' + username;
subtitle = 'From @' + domain;
showBlockDomainButton = true;
}
if (utils.isAnonymous(uri)) {
//uri = 'anonymous@anonymous.invalid';
if (uri.indexOf('@guest.') > -1) {
subtitle = 'From the Web';
} else {
name = 'Anonymous';
}
showBlockDomainButton = true;
if (!this.state.blocked) {
showBlockButton = false;
}
blockDomainTextbutton = 'Block Web callers';
}
if (!username || username.length === 0) {
if (isIp(domain)) {
title = 'IP domain';
} else if (domain.indexOf('guest.') > -1) {
title = 'Calls from the Web';
} else {
title = 'Domain';
}
}
let cardContainerClass = styles.portraitContainer;
if (this.state.isTablet) {
cardContainerClass = (this.state.orientation === 'landscape') ? styles.cardLandscapeTabletContainer : styles.cardPortraitTabletContainer;
} else {
cardContainerClass = (this.state.orientation === 'landscape') ? styles.cardLandscapeContainer : styles.cardPortraitContainer;
}
let cardHeight = this.state.fontScale <= 1 ? 75 : 70;
let duration;
if (this.state.contact.tags.indexOf('history') > -1) {
duration = moment.duration(this.state.contact.lastCallDuration, 'seconds').format('HH:mm:ss', {trim: false});
if (this.state.contact.direction === 'incoming' && this.state.contact.lastCallDuration === 0) {
duration = 'missed';
} else if (this.state.contact.direction === 'outgoing' && this.state.contact.lastCallDuration === 0) {
duration = 'cancelled';
}
}
if (this.state.contact.conference) {
let participants = this.state.contact.participants;
if (this.state.invitedParties && this.state.invitedParties.length > 0 ) {
participants = this.state.invitedParties;
}
if (participants && participants.length > 0) {
const p_text = participants.length > 1 ? 'participants' : 'participant';
subtitle = 'With ' + participants.length + ' ' + p_text;
let i = 1;
let contact_obj;
let dn;
let _item;
participants.forEach((participant) => {
contact_obj = this.findObjectByKey(this.props.contacts, 'uri', participant);
dn = contact_obj ? contact_obj.name : participant;
_item = {nr: i, id: uuid.v4(), uri: participant, name: dn};
participantsData.push(_item);
i = i + 1;
});
} else {
subtitle = 'With no participants';
}
}
if (!name) {
title = uri;
}
if (duration === 'missed') {
subtitle = 'Last call missed from ', + uri;
} else if (duration === 'cancelled') {
subtitle = 'Last call cancelled to ' + uri;
} else {
subtitle = uri;
}
if (subtitle !== uri) {
subtitle = subtitle + ' ' + uri;
}
if (title.indexOf('@videoconference') > -1) {
title = name || username;
}
if (uri === 'anonymous@anonymous.invalid') {
title = 'Anonymous caller';
} else {
let isAnonymous = uri.indexOf('@guest.') > -1;
if (isAnonymous) {
title = title + ' (Web call)';
}
}
if (duration && duration !== "00:00:00") {
let media = 'Audio call';
if (this.state.contact.lastCallMedia.indexOf('video') > -1) {
media = 'Video call';
}
description = description + ' (' + media + ' ' + duration + ')';
}
const container = this.state.isLandscape ? styles.containerLandscape : styles.containerPortrait;
const chatContainer = this.state.isLandscape ? styles.chatLandscapeContainer : styles.chatPortraitContainer;
let showSubtitle = (showActions || this.state.isTablet || !description);
let label = this.state.contact.label ? (" (" + this.state.contact.label + ")" ) : '';
if (this.state.contact.lastMessage) {
subtitle = this.state.contact.lastMessage.split("\n")[0];
//description = description + ': ' + this.state.contact.lastMessage;
} else {
subtitle = subtitle + label;
}
let unread = (this.state.contact && this.state.contact.unread && !this.state.selectMode) ? this.state.contact.unread.length : 0;
let selectCircle = this.state.contact.selected ? 'check-circle' : 'circle-outline';
return (
{this.setTargetUri(uri, this.state.contact)}}
>
{ this.state.contact.photo || ! this.state.contact.email ?
:
-
+
}
{title}
{subtitle}
{this.state.fontScale <= 1 ?
{this.state.contact.direction ?
: null}
{description}
: null}
{participantsData && participantsData.length && showActions && false?
item.id}
key={item => item.id}
/>
: null}
{ this.state.selectMode ?
:
{contact_ts}
}
{unread ?
: null
}
{showActions && false ?
{showBlockButton? : null}
{showBlockDomainButton? : null}
: null}
);
}
}
ContactCard.propTypes = {
id : PropTypes.string,
contact : PropTypes.object,
setTargetUri : PropTypes.func,
chat : PropTypes.bool,
orientation : PropTypes.string,
isTablet : PropTypes.bool,
isLandscape : PropTypes.bool,
contacts : PropTypes.array,
defaultDomain : PropTypes.string,
accountId : PropTypes.string,
favoriteUris : PropTypes.array,
messages : PropTypes.array,
pinned : PropTypes.bool,
unread : PropTypes.array,
toggleBlocked : PropTypes.func,
sendPublicKey : PropTypes.func,
fontScale : PropTypes.number,
selectMode : PropTypes.bool
};
export default ContactCard;
diff --git a/app/components/UserIcon.js b/app/components/UserIcon.js
index f2b553d..d750a48 100644
--- a/app/components/UserIcon.js
+++ b/app/components/UserIcon.js
@@ -1,61 +1,61 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import utils from '../utils';
import { Text, View } from 'react-native'
import { Avatar} from 'react-native-paper';
const UserIcon = (props) => {
if (!props.identity) {
return (null)
}
const name = props.identity.name || props.identity.uri;
const photo = props.identity.photo;
let initials = '';
if (name) {
initials = name.split(' ', 2).map(x => x[0]).join('');
}
const color = utils.generateMaterialColor(props.identity.uri)['300'];
let avatarSize = props.large ? 130: 50;
if (props.carousel === true) {
- avatarSize = 60;
+ avatarSize = 50;
}
if (props.small) {
avatarSize = 40;
}
if (photo) {
return (
);
}
if (props.identity.uri && props.identity.uri.search('anonymous') !== -1) {
return (
);
}
if (props.identity.uri && props.identity.uri.search('videoconference') !== -1) {
return (
);
}
return (
);
};
UserIcon.propTypes = {
identity: PropTypes.object.isRequired,
large: PropTypes.bool,
carousel: PropTypes.bool
};
export default UserIcon;