mirror of
https://github.com/balzack/databag.git
synced 2025-05-05 07:55:15 +00:00
building details screen
This commit is contained in:
parent
f551e6b5f5
commit
03f64e8257
@ -2018,9 +2018,9 @@ SPEC CHECKSUMS:
|
|||||||
DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5
|
DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5
|
||||||
FBLazyVector: 38bb611218305c3bc61803e287b8a81c6f63b619
|
FBLazyVector: 38bb611218305c3bc61803e287b8a81c6f63b619
|
||||||
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
|
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
|
||||||
glog: fdfdfe5479092de0c4bdbebedd9056951f092c4f
|
glog: 69ef571f3de08433d766d614c73a9838a06bf7eb
|
||||||
hermes-engine: 3b6e0717ca847e2fc90a201e59db36caf04dee88
|
hermes-engine: 3b6e0717ca847e2fc90a201e59db36caf04dee88
|
||||||
RCT-Folly: 02617c592a293bd6d418e0a88ff4ee1f88329b47
|
RCT-Folly: 4464f4d875961fce86008d45f4ecf6cef6de0740
|
||||||
RCTDeprecation: 34cbf122b623037ea9facad2e92e53434c5c7422
|
RCTDeprecation: 34cbf122b623037ea9facad2e92e53434c5c7422
|
||||||
RCTRequired: 24c446d7bcd0f517d516b6265d8df04dc3eb1219
|
RCTRequired: 24c446d7bcd0f517d516b6265d8df04dc3eb1219
|
||||||
RCTTypeSafety: ef5e91bd791abd3a99b2c75fd565791102a66352
|
RCTTypeSafety: ef5e91bd791abd3a99b2c75fd565791102a66352
|
||||||
@ -2094,7 +2094,7 @@ SPEC CHECKSUMS:
|
|||||||
RNVectorIcons: 6382277afab3c54658e9d555ee0faa7a37827136
|
RNVectorIcons: 6382277afab3c54658e9d555ee0faa7a37827136
|
||||||
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
|
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
|
||||||
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
|
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
|
||||||
Yoga: 2a45d7e59592db061217551fd3bbe2dd993817ae
|
Yoga: a1d7895431387402a674fd0d1c04ec85e87909b8
|
||||||
|
|
||||||
PODFILE CHECKSUM: 8461018d8deceb200962c829584af7c2eb345c80
|
PODFILE CHECKSUM: 8461018d8deceb200962c829584af7c2eb345c80
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
const scale = useAnimatedValue(0)
|
const scale = useAnimatedValue(0)
|
||||||
|
|
||||||
const alertParams = {
|
const alertParams = {
|
||||||
title: state.strings.error,
|
title: state.strings.operationFailed,
|
||||||
prompt: state.strings.tryAgain,
|
prompt: state.strings.tryAgain,
|
||||||
cancel: {
|
cancel: {
|
||||||
label: state.strings.close,
|
label: state.strings.close,
|
||||||
|
@ -23,6 +23,8 @@ export const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
|
flexGrow: 1,
|
||||||
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
close: {
|
close: {
|
||||||
width: 32,
|
width: 32,
|
||||||
@ -39,4 +41,37 @@ export const styles = StyleSheet.create({
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
height: 2,
|
height: 2,
|
||||||
},
|
},
|
||||||
|
info: {
|
||||||
|
width: '80%',
|
||||||
|
},
|
||||||
|
subject: {
|
||||||
|
width: '100%',
|
||||||
|
height: 52,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'row',
|
||||||
|
paddingRight: 4,
|
||||||
|
marginTop: 16,
|
||||||
|
borderRadius: 8,
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
flexGrow: 1,
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
},
|
||||||
|
underline: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
padding: 0,
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
|
inputControl: {
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
backgroundColor: 'yellow',
|
||||||
|
},
|
||||||
|
members: {
|
||||||
|
flexGrow: 1,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,38 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { SafeAreaView, View } from 'react-native';
|
import { SafeAreaView, ScrollView, View } from 'react-native';
|
||||||
import {Divider, IconButton, Text} from 'react-native-paper';
|
import {Surface, Divider, IconButton, Text, TextInput} from 'react-native-paper';
|
||||||
import {styles} from './Details.styled';
|
import {styles} from './Details.styled';
|
||||||
import {useDetails} from './useDetails.hook';
|
import {useDetails} from './useDetails.hook';
|
||||||
|
import { Confirm } from '../confirm/Confirm';
|
||||||
|
|
||||||
export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}) {
|
export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}) {
|
||||||
const { state, actions } = useDetails();
|
const { state, actions } = useDetails();
|
||||||
|
const [alert, setAlert] = useState(false);
|
||||||
|
const [saving, setSaving] = useState(false);
|
||||||
|
|
||||||
|
const alertParams = {
|
||||||
|
title: state.strings.operationFailer,
|
||||||
|
prompt: state.strings.tryAgain,
|
||||||
|
cancel: {
|
||||||
|
label: state.strings.close,
|
||||||
|
action: () => {
|
||||||
|
setAlert(false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveSubject = async () => {
|
||||||
|
if (!saving) {
|
||||||
|
setSaving(true);
|
||||||
|
try {
|
||||||
|
await actions.saveSubject();
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
setAlert(true);
|
||||||
|
}
|
||||||
|
setSaving(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.details}>
|
<View style={styles.details}>
|
||||||
@ -21,6 +48,38 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
|
|||||||
)}
|
)}
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
<Divider style={styles.divider} />
|
<Divider style={styles.divider} />
|
||||||
|
<View style={styles.info}>
|
||||||
|
{ state.host && (
|
||||||
|
<Surface style={styles.subject} elevation={4}>
|
||||||
|
<TextInput
|
||||||
|
style={styles.input}
|
||||||
|
underlineStyle={styles.underline}
|
||||||
|
mode="flat"
|
||||||
|
autoCapitalize="none"
|
||||||
|
autoComplete="off"
|
||||||
|
autoCorrect={false}
|
||||||
|
value={state.editSubject}
|
||||||
|
label={state.strings.subject}
|
||||||
|
disabled={state.locked}
|
||||||
|
left={<TextInput.Icon style={styles.icon} icon="label-outline" />}
|
||||||
|
onChangeText={value => actions.setEditSubject(value)}
|
||||||
|
/>
|
||||||
|
{ state.subject !== state.editSubject && (
|
||||||
|
<IconButton style={styles.icon} icon="undo-variant" onPress={actions.undoSubject} />
|
||||||
|
)}
|
||||||
|
{ state.subject !== state.editSubject && (
|
||||||
|
<IconButton style={styles.icon} icon="content-save-outline" loading={saving} onPress={saveSubject} />
|
||||||
|
)}
|
||||||
|
</Surface>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<ScrollView style={styles.members}>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
<Confirm show={alert} params={alertParams} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// input if host and unsealed
|
||||||
|
// text otherwise
|
||||||
|
@ -1,19 +1,164 @@
|
|||||||
import {useState, useContext, useEffect, useRef} from 'react';
|
import { useState, useContext, useEffect } from 'react'
|
||||||
import {DisplayContext} from '../context/DisplayContext';
|
import { AppContext } from '../context/AppContext'
|
||||||
import {ContextType} from '../context/ContextType';
|
import { DisplayContext } from '../context/DisplayContext'
|
||||||
|
import { ContextType } from '../context/ContextType'
|
||||||
|
import { FocusDetail, Card, Profile } from 'databag-client-sdk';
|
||||||
|
|
||||||
export function useDetails() {
|
export function useDetails() {
|
||||||
const display = useContext(DisplayContext) as ContextType;
|
const display = useContext(DisplayContext) as ContextType
|
||||||
|
const app = useContext(AppContext) as ContextType
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
|
cardId: null as null | string,
|
||||||
|
channelId: '',
|
||||||
|
detail: undefined as undefined | FocusDetail,
|
||||||
|
access: false,
|
||||||
|
host: false,
|
||||||
|
sealed: false,
|
||||||
|
locked: false,
|
||||||
strings: display.state.strings,
|
strings: display.state.strings,
|
||||||
});
|
timeFormat: display.state.timeFormat,
|
||||||
|
dateFormat: display.state.dateFormat,
|
||||||
|
subject: '',
|
||||||
|
editSubject: '',
|
||||||
|
created: '',
|
||||||
|
profile: null as null | Profile,
|
||||||
|
cards: [] as Card[],
|
||||||
|
hostCard: null as null | Card,
|
||||||
|
channelCards: [] as Card[],
|
||||||
|
unknownContacts: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState(s => ({...s, ...value}));
|
setState((s) => ({ ...s, ...value }))
|
||||||
};
|
}
|
||||||
|
|
||||||
|
const getTimestamp = (created: number) => {
|
||||||
|
const now = Math.floor((new Date()).getTime() / 1000)
|
||||||
|
const date = new Date(created * 1000);
|
||||||
|
const offset = now - created;
|
||||||
|
if(offset < 43200) {
|
||||||
|
if (state.timeFormat === '12h') {
|
||||||
|
return date.toLocaleTimeString("en-US", {hour: 'numeric', minute:'2-digit'});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return date.toLocaleTimeString("en-GB", {hour: 'numeric', minute:'2-digit'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (offset < 31449600) {
|
||||||
|
if (state.dateFormat === 'mm/dd') {
|
||||||
|
return date.toLocaleDateString("en-US", {day: 'numeric', month:'numeric'});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return date.toLocaleDateString("en-GB", {day: 'numeric', month:'numeric'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (state.dateFormat === 'mm/dd') {
|
||||||
|
return date.toLocaleDateString("en-US");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return date.toLocaleDateString("en-GB");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const { strings, timeFormat, dateFormat } = display.state;
|
||||||
|
updateState({ strings, timeFormat, dateFormat });
|
||||||
|
}, [display.state]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const hostCard = state.cards.find(entry => entry.cardId == state.cardId);
|
||||||
|
const profileRemoved = state.detail?.members ? state.detail.members.filter(member => state.profile?.guid != member.guid) : [];
|
||||||
|
const contactCards = profileRemoved.map(member => state.cards.find(card => card.guid === member.guid));
|
||||||
|
const channelCards = contactCards.filter(member => Boolean(member));
|
||||||
|
const unknownContacts = contactCards.length - channelCards.length;
|
||||||
|
updateState({ hostCard, channelCards, unknownContacts });
|
||||||
|
}, [state.detail, state.cards, state.profile, state.cardId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const focus = app.state.focus;
|
||||||
|
const { contact, identity } = app.state.session || { };
|
||||||
|
if (focus && contact && identity) {
|
||||||
|
const setCards = (cards: Card[]) => {
|
||||||
|
const filtered = cards.filter(card => !card.blocked);
|
||||||
|
const sorted = filtered.sort((a, b) => {
|
||||||
|
if (a.handle > b.handle) {
|
||||||
|
return 1;
|
||||||
|
} else if (a.handle < b.handle) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
updateState({ cards: sorted });
|
||||||
|
}
|
||||||
|
const setProfile = (profile: Profile) => {
|
||||||
|
updateState({ profile });
|
||||||
|
}
|
||||||
|
const setDetail = (focused: { cardId: string | null, channelId: string, detail: FocusDetail | null }) => {
|
||||||
|
const detail = focused ? focused.detail : null;
|
||||||
|
const cardId = focused.cardId;
|
||||||
|
const channelId = focused.channelId;
|
||||||
|
const access = Boolean(detail);
|
||||||
|
const sealed = detail?.sealed;
|
||||||
|
const locked = detail?.locked;
|
||||||
|
const host = cardId == null;
|
||||||
|
const subject = detail?.data?.subject ? detail.data.subject : '';
|
||||||
|
const created = detail?.created ? getTimestamp(detail.created) : '';
|
||||||
|
updateState({ detail, editSubject: subject, subject, channelId, cardId, access, sealed, locked, host, created });
|
||||||
|
}
|
||||||
|
focus.addDetailListener(setDetail);
|
||||||
|
contact.addCardListener(setCards);
|
||||||
|
identity.addProfileListener(setProfile);
|
||||||
|
return () => {
|
||||||
|
focus.removeDetailListener(setDetail);
|
||||||
|
contact.removeCardListener(setCards);
|
||||||
|
identity.removeProfileListener(setProfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [app.state.focus, state.timeFormat, state.dateFormat]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
};
|
remove: async () => {
|
||||||
|
const content = app.state.session.getContent()
|
||||||
|
await content.removeChannel(state.channelId);
|
||||||
|
app.actions.clearFocus();
|
||||||
|
},
|
||||||
|
leave: async () => {
|
||||||
|
const content = app.state.session.getContent()
|
||||||
|
await content.leaveChannel(state.cardId, state.channelId);
|
||||||
|
app.actions.clearFocus();
|
||||||
|
},
|
||||||
|
block: async () => {
|
||||||
|
const content = app.state.session.getContent();
|
||||||
|
await content.setBlockedChannel(state.cardId, state.channelId, true);
|
||||||
|
app.actions.clearFocus();
|
||||||
|
},
|
||||||
|
report: async () => {
|
||||||
|
const content = app.state.session.getContent();
|
||||||
|
await content.flagChannel(state.cardId, state.channelId);
|
||||||
|
},
|
||||||
|
setMember: async (cardId: string) => {
|
||||||
|
const content = app.state.session.getContent();
|
||||||
|
await content.setChannelCard(state.channelId, cardId);
|
||||||
|
},
|
||||||
|
clearMember: async (cardId: string) => {
|
||||||
|
const content = app.state.session.getContent();
|
||||||
|
await content.clearChannelCard(state.channelId, cardId);
|
||||||
|
},
|
||||||
|
setEditSubject: (editSubject: string) => {
|
||||||
|
updateState({ editSubject });
|
||||||
|
},
|
||||||
|
undoSubject: () => {
|
||||||
|
updateState({ editSubject: state.subject });
|
||||||
|
},
|
||||||
|
saveSubject: async () => {
|
||||||
|
const content = app.state.session.getContent()
|
||||||
|
await content.setChannelSubject(state.channelId, state.sealed ? 'sealed' : 'superbasic', { subject: state.editSubject });
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
return {state, actions};
|
return { state, actions }
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
const [authMessage, setAuthMessage] = useState('');
|
const [authMessage, setAuthMessage] = useState('');
|
||||||
|
|
||||||
const alertParams = {
|
const alertParams = {
|
||||||
title: state.strings.error,
|
title: state.strings.operationFailed,
|
||||||
prompt: state.strings.tryAgain,
|
prompt: state.strings.tryAgain,
|
||||||
cancel: {
|
cancel: {
|
||||||
label: state.strings.close,
|
label: state.strings.close,
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user