diff --git a/app/assets/styles/blink/_Avatar.scss b/app/assets/styles/blink/_Avatar.scss
index b35a90f..18c5dcf 100644
--- a/app/assets/styles/blink/_Avatar.scss
+++ b/app/assets/styles/blink/_Avatar.scss
@@ -1,3 +1,9 @@
-.avatar {
- margin: 00px;
+.avatarLabelAndroid {
+ margin-top: -3px;
+ margin-left: -1px;
+}
+
+.avatarLabeliOS {
+ margin-top: -2px;
+ margin-left: 0px;
}
diff --git a/app/components/ContactCard.js b/app/components/ContactCard.js
index 941f399..ac25c0f 100644
--- a/app/components/ContactCard.js
+++ b/app/components/ContactCard.js
@@ -1,490 +1,490 @@
import React, { Component, Fragment} from 'react';
-import { View, SafeAreaView, FlatList } from 'react-native';
+import { View, SafeAreaView, FlatList, Platform } 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 {Keyboard} from 'react-native';
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,
selectedContact: this.props.selectedContact,
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,
selectedContact: nextProps.selectedContact,
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
});
}
buttonsEnabledForContact(contact) {
if (contact.tags && contact.tags.indexOf('blocked') > -1) {
return false
}
if (contact.tags && contact.tags.indexOf('@conference') > -1) {
return false
}
if (contact.uri.indexOf('@guest.') > -1) {
return false
}
if (contact.uri.indexOf('anonymous@') > -1) {
return false
}
if (contact.uri.indexOf('@videoconference') > -1) {
return false
}
let username = contact.uri.split('@')[0];
let isPhoneNumber = username ? username.match(/^(\+|0)(\d+)$/) : false;
if (isPhoneNumber) {
return false
}
return true;
}
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;
}
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) {
if (this.state.chat) {
return;
}
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;
}
if (uri === this.props.accountId) {
name = 'My self';
}
let contact_ts = '';
let participantsData = [];
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;
}
if (utils.isAnonymous(uri)) {
//uri = 'anonymous@anonymous.invalid';
if (uri.indexOf('@guest.') > -1) {
subtitle = 'From the Web';
} else {
name = 'Anonymous';
}
}
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 + ')';
}
let greenButtonClass = Platform.OS === 'ios' ? styles.greenButtoniOS : styles.greenButton;
let fileTransfersEnabled = true;
if (this.state.contact.tags.indexOf('test') > -1) {
fileTransfersEnabled = false;
}
if (uri.indexOf('@videoconference') > -1) {
fileTransfersEnabled = false;
}
if (uri.indexOf('@conference') > -1) {
fileTransfersEnabled = false;
}
if (isPhoneNumber) {
fileTransfersEnabled = false;
}
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';
let titlePadding = styles.titlePadding;
if (this.state.fontScale < 1) {
titlePadding = styles.titlePaddingBig;
} else if (this.state.fontScale > 1.2) {
titlePadding = styles.titlePaddingSmall;
}
//console.log('selectedContact', this.state.selectedContact);
if (this.state.selectMode) {
titlePadding = styles.titlePaddingSelect;
return (
{this.setTargetUri(uri, this.state.contact)}}
>
{ this.state.contact.photo || !this.state.contact.email ?
:
}
{title}
);
} else {
return (
{this.setTargetUri(uri, this.state.contact)}}
>
{ this.state.contact.photo || !this.state.contact.email ?
:
}
{title}
{subtitle}
{this.state.fontScale <= 0.85 && !this.state.callButtonsEnabled ?
{this.state.contact.direction ?
: null}
{description}
: null}
{participantsData && participantsData.length && showActions && false?
item.id}
key={item => item.id}
/>
: null}
{contact_ts}
{unread ?
: null
}
);
}
}
}
ContactCard.propTypes = {
id : PropTypes.string,
contact : PropTypes.object,
selectedContact: 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,
sendPublicKey : PropTypes.func,
fontScale : PropTypes.number,
selectMode : PropTypes.bool,
accountId : PropTypes.string
};
export default ContactCard;
diff --git a/app/components/UserIcon.js b/app/components/UserIcon.js
index 6f8db2d..15fa353 100644
--- a/app/components/UserIcon.js
+++ b/app/components/UserIcon.js
@@ -1,56 +1,58 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import utils from '../utils';
-import { Text, View } from 'react-native'
+import { Text, View, Platform } from 'react-native'
import { Avatar} from 'react-native-paper';
import styles from '../assets/styles/blink/_Avatar.scss';
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.size || 50;
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 (
);
}
+ let lableStyle = Platform.OS === 'android' ? styles.avatarLabelAndroid : styles.avatarLabeliOS;
+
return (
-
+
);
};
UserIcon.propTypes = {
identity: PropTypes.object.isRequired,
large: PropTypes.bool,
size: PropTypes.number
};
export default UserIcon;