diff --git a/app/mobile/src/constants/Colors.js b/app/mobile/src/constants/Colors.js index ca846ce3..6ab4b5cf 100644 --- a/app/mobile/src/constants/Colors.js +++ b/app/mobile/src/constants/Colors.js @@ -56,7 +56,7 @@ const LightColors = { const DarkColors = { overlay: 'dark', statusBar: 'light-content', - tabBar: '#111111', + tabBar: '#118811', activeTabIcon: '#dddddd', idleTabIcon: '#aaaaaa', activeBorder: '#aaaaaa', @@ -103,7 +103,7 @@ const DarkColors = { disabledIndicator: '#eeeeee', disconnectedIndicator: '#aa0000', sliderGrip: '#eeeeee', - areaBorder: '#aaaaaa', + areaBorder: '#777777', }; function getColor(label) { diff --git a/app/mobile/src/constants/Strings.js b/app/mobile/src/constants/Strings.js index d57205f3..cd41c0bb 100644 --- a/app/mobile/src/constants/Strings.js +++ b/app/mobile/src/constants/Strings.js @@ -84,6 +84,7 @@ const Strings = [ // contacts page add: 'Add', + back: 'Back', }, { visibleRegistry: 'Visible dans le Registre', @@ -165,6 +166,7 @@ const Strings = [ //constacts page add: 'Ajouter', + back: 'Arrière', }, { visibleRegistry: 'Visible en el Registro', @@ -246,6 +248,7 @@ const Strings = [ // contacts page add: 'Agregar', + back: 'Atrás', }, { visibleRegistry: 'Sichtbar in der Registrierung', @@ -327,6 +330,7 @@ const Strings = [ //contacts page add: 'Hinzufügen', + back: 'Rückwärts', } ]; diff --git a/app/mobile/src/session/Session.jsx b/app/mobile/src/session/Session.jsx index 034fd836..394d1691 100644 --- a/app/mobile/src/session/Session.jsx +++ b/app/mobile/src/session/Session.jsx @@ -14,7 +14,7 @@ import { Profile } from './profile/Profile'; import { ProfileSettings } from './profileSettings/ProfileSettings'; import { CardsHeader, CardsBody, Cards } from './cards/Cards'; import { RegistryHeader, RegistryBody, Registry } from './registry/Registry'; -import { ContactHeader, ContactBody, Contact } from './contact/Contact'; +import { Contact } from './contact/Contact'; import { Details } from './details/Details'; import { Conversation, ConversationHeader, ConversationBody } from './conversation/Conversation'; import { Welcome } from './welcome/Welcome'; @@ -163,10 +163,8 @@ function ContactStackScreen({ addChannel }) { {(props) => openContact(props.navigation, contact)} addChannel={addChannel} />} - ( - - )}}> - {(props) => } + + {(props) => } ( diff --git a/app/mobile/src/session/Session.styled.js b/app/mobile/src/session/Session.styled.js index ff1ad439..5177a50f 100644 --- a/app/mobile/src/session/Session.styled.js +++ b/app/mobile/src/session/Session.styled.js @@ -67,8 +67,8 @@ export const styles = StyleSheet.create({ color: Colors.white, }, tabBar: { - borderTopWidth: 0, - backgroundColor: Colors.primary, + borderColor: Colors.tabBar, + backgroundColor: Colors.screenBase, maxHeight: 72, }, home: { diff --git a/app/mobile/src/session/contact/Contact.jsx b/app/mobile/src/session/contact/Contact.jsx index 8532b89d..4ab62761 100644 --- a/app/mobile/src/session/contact/Contact.jsx +++ b/app/mobile/src/session/contact/Contact.jsx @@ -1,9 +1,11 @@ -import { Alert, View, Text, TouchableOpacity } from 'react-native'; +import { Alert, View, Text, TouchableOpacity, ScrollView, Image } from 'react-native'; import { styles } from './Contact.styled'; import { useContact } from './useContact.hook'; import Ionicons from 'react-native-vector-icons/AntDesign'; import { Logo } from 'utils/Logo'; import { Colors } from 'constants/Colors'; +import AntIcons from 'react-native-vector-icons/AntDesign'; +import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons'; export function ContactHeader({ contact }) { const handle = contact?.node ? `${contact?.handle}@${contact?.node}` : contact?.handle; @@ -298,13 +300,62 @@ export function ContactBody({ contact }) { ); } -export function Contact({ contact }) { +export function Contact({ contact, drawer, back }) { + + const { state, actions } = useContact(contact); + const OVERLAP = 32; return ( - - - - + <> + { drawer && ( + CONTACT DRAWER + )} + { !drawer && ( + + + + + + { state.strings.back } + + + + { state.name && ( + { state.name } + )} + { !state.name && ( + { state.strings.name } + )} + { state.username } + + + + { state.location && ( + { state.location } + )} + { !state.location && ( + Location + )} + + + + + + { state.description && ( + { state.description } + )} + { !state.description && ( + Description + )} + + + + + + + )} + ); } diff --git a/app/mobile/src/session/contact/Contact.styled.js b/app/mobile/src/session/contact/Contact.styled.js index 01765511..2be2fb86 100644 --- a/app/mobile/src/session/contact/Contact.styled.js +++ b/app/mobile/src/session/contact/Contact.styled.js @@ -2,133 +2,162 @@ import { StyleSheet } from 'react-native'; import { Colors } from 'constants/Colors'; export const styles = StyleSheet.create({ - container: { + container: { width: '100%', height: '100%', + }, + content: { + width: '100%', + height: '100%', + position: 'absolute', + top: 0, display: 'flex', - flexDirection: 'column', - paddingBottom: 32, alignItems: 'center', - justifyContent: 'center', - backgroundColor: Colors.formBackground, }, - wrapper: { - backgroundColor: Colors.formBackground, + logo: { + alignSelf: 'center', }, - title: { + details: { + minHeight: 32, + borderTopRightRadius: 32, + borderTopLeftRadius: 32, + backgroundColor: Colors.screenBase, + borderTopWidth: 1, + borderColor: Colors.areaBorder, + borderLeftWidth: 0.2, + borderRightWidth: 0.2, + paddingLeft: 1, + paddingRight: 1, + display: 'flex', + flexShrink: 1, + flexGrow: 1, + paddingBottom: 16, + }, + space: { + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'flex-start', + }, + back: { + backgroundColor: Colors.screenBase, + borderTopLeftRadius: 8, + borderTopRightRadius: 8, + marginLeft: 32, + borderColor: Colors.areaBorder, + borderTopWidth: 1, + borderLeftWidth: 1, + borderRightWidth: 1, + }, + backLabel: { + color: Colors.linkText, + fontSize: 14, + fontFamily: 'Roboto', + paddingLeft: 16, + paddingRight: 16, + paddingTop: 4, + paddingBottom: 2, + }, + nameSet: { + display: 'flex', + color: Colors.text, + fontFamily: 'roboto', + fontSize: 48, + flexShrink: 1, + paddingTop: 8, + paddingLeft: 16, + paddingRight: 16, + }, + nameUnset: { + color: Colors.inputPlaceholder, + fontFamily: 'roboto', + fontSize: 48, + fontStyle: 'italic', + paddingTop: 8, + paddingLeft: 16, + paddingRight: 16, + }, + username: { + color: Colors.text, + fontFamily: 'roboto', fontSize: 18, + paddingLeft: 16, + paddingRight: 16, }, - resync: { + group: { + marginLeft: 16, + marginRight: 16, + backgroundColor: Colors.areaBase, + borderRadius: 8, + marginTop: 16, display: 'flex', - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', }, - glyph: { - paddingTop: 2, + attributes: { + marginLeft: 16, + marginRight: 16, + backgroundColor: Colors.areaBase, + borderRadius: 8, + marginTop: 16, + display: 'flex', + flexShrink: 1, }, - icon: { - width: 32, - paddingLeft: 8 + divider: { + width: '100%', + height: 2, + backgroundColor: Colors.screenBase, }, - drawer: { - paddingTop: 16, - }, - close: { + entry: { width: '100%', display: 'flex', - alignItems: 'flex-end', - paddingRight: 32, - }, - header: { - display: 'flex', - flexDirection: 'row', - alignItems: 'flex-end', - justifyContent: 'center', - }, - status: { - color: Colors.grey, - paddingBottom: 20, - paddingTop: 4, - }, - headerText: { - fontSize: 18, - overflow: 'hidden', - textAlign: 'center', - color: Colors.text, - }, - camera: { - position: 'absolute', - bottom: 0, - left: 0, - padding: 8, - backgroundColor: Colors.lightgrey, - borderBottomLeftRadius: 8, - borderTopRightRadius: 8, - }, - gallery: { - position: 'absolute', - bottom: 0, - right: 0, - padding: 8, - backgroundColor: Colors.lightgrey, - borderBottomRightRadius: 8, - borderTopLeftRadius: 8, - }, - detail: { - paddingTop: 32, - paddingLeft: 32, - paddingRight: 32, - display: 'flex', - flexDirection: 'column', alignItems: 'center', - color: Colors.text, - }, - attribute: { - display: 'flex', flexDirection: 'row', - paddingBottom: 8, + padding: 8, }, - nametext: { - fontSize: 18, + description: { + display: 'flex', + flexShrink: 1, + }, + descriptionIcon: { + alignSelf: 'flex-start', + paddingLeft: 8, + paddingRight: 16, + }, + drawerDescriptionIcon: { + alignSelf: 'flex-start', + paddingLeft: 8, paddingRight: 8, - fontWeight: 'bold', - color: Colors.text, }, - locationtext: { - fontSize: 16, + icon: { paddingLeft: 8, - color: Colors.text, + paddingRight: 16, }, - descriptiontext: { - fontSize: 16, + drawerIcon: { paddingLeft: 8, + paddingRight: 8, + }, + locationSet: { + fontSize: 16, color: Colors.text, + fontFamily: 'roboto', + flex: 1, }, - button: { - width: 192, - padding: 6, - backgroundColor: Colors.primary, - borderRadius: 4, - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - marginTop: 16, + locationUnset: { + fontSize: 16, + color: Colors.inputPlaceholder, + fontFamily: 'roboto', + fontStyle: 'italic', + flex: 1, }, - buttonText: { - color: Colors.white, + descriptionSet: { + fontSize: 16, + color: Colors.text, + fontFamily: 'roboto', + flex: 1, }, - alert: { - width: 192, - padding: 6, - backgroundColor: Colors.alert, - borderRadius: 4, - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - marginTop: 16, - }, - alertText: { - color: Colors.white, + descriptionUnset: { + fontSize: 16, + color: Colors.inputPlaceholder, + fontFamily: 'roboto', + fontStyle: 'italic', + flex: 1, }, }) diff --git a/app/mobile/src/session/contact/useContact.hook.js b/app/mobile/src/session/contact/useContact.hook.js index d217a6af..eed85166 100644 --- a/app/mobile/src/session/contact/useContact.hook.js +++ b/app/mobile/src/session/contact/useContact.hook.js @@ -1,10 +1,13 @@ import { useState, useEffect, useRef, useContext } from 'react'; +import { useWindowDimensions } from 'react-native'; import { CardContext } from 'context/CardContext'; import { ProfileContext } from 'context/ProfileContext'; import { getListingMessage } from 'api/getListingMessage'; import { getListingImageUrl } from 'api/getListingImageUrl'; import { addFlag } from 'api/addFlag'; import { getCardByGuid } from 'context/cardUtil'; +import { getLanguageStrings } from 'constants/Strings'; +import avatar from 'images/avatar.png'; export function useContact(contact) { @@ -14,14 +17,22 @@ export function useContact(contact) { node: null, location: null, description: null, - logo: null, status: null, cardId: null, guid: null, busy: false, offsync: false, + + + strings: getLanguageStrings(), + imageSource: null, + imageWidth: null, + imageHeight: null, + detailWidth: null, + username: null, }); + const dimensions = useWindowDimensions(); const card = useContext(CardContext); const profile = useContext(ProfileContext); @@ -29,6 +40,16 @@ export function useContact(contact) { setState((s) => ({ ...s, ...value })); } + useEffect(() => { + const { width, height } = dimensions; + if (height > width) { + updateState({ imageWidth: width, imageHeight: width, detailWidth: width + 2 }); + } + else { + updateState({ imageWidth: height, imageHeight: height, detailWidth: width + 2 }); + } + }, [dimensions]); + useEffect(() => { const contactCard = getCardByGuid(card.state.cards, contact?.guid); const { server } = profile.state; @@ -36,14 +57,18 @@ export function useContact(contact) { const { offsync, profile, detail, cardId } = contactCard.card; const { name, handle, node, location, description, guid, imageSet, revision } = profile; const host = node ? node : server; - const logo = imageSet ? card.actions.getCardImageUrl(cardId) : 'avatar'; - updateState({ offsync, name, handle, node: server, location, description, logo, cardId, guid, status: detail.status }); + + const username = `${handle}/${node}` + const imageSource = imageSet ? { uri: card.actions.getCardImageUrl(cardId) } : avatar; + updateState({ offsync, name, handle, node: server, location, description, imageSource, username, cardId, guid, status: detail.status }); } else { const { guid, handle, node, name, location, description, imageSet } = contact || {}; const host = node ? node : server; - const logo = imageSet ? getListingImageUrl(server, guid) : 'avatar'; - updateState({ guid, handle, node: host, name, location, description, logo, offsync: false, status: null }); + + const username = `${handle}/${node}` + const imageSource = imageSet ? { uri: getListingImageUrl(server, guid) } : avatar; + updateState({ guid, handle, node: host, name, location, description, imageSource, username, offsync: false, status: null }); } }, [contact, card.state, profile.state]);