implementing new topic modal

This commit is contained in:
Roland Osborne 2024-11-12 11:55:02 -08:00
parent 119fb4f35d
commit ae9f737fa3
3 changed files with 168 additions and 19 deletions

View File

@ -50,6 +50,10 @@ export const styles = StyleSheet.create({
width: '100%',
height: 2,
},
modalDivider: {
width: '100%',
height: 1,
},
inputSurface: {
flexGrow: 1,
height: 40,
@ -66,6 +70,7 @@ export const styles = StyleSheet.create({
height: 40,
maxHeight: 40,
borderRadius: 8,
fontSize: 14,
},
inputUnderline: {
display: 'none',
@ -122,7 +127,7 @@ export const styles = StyleSheet.create({
},
addContainer: {
width: 500,
maxWidth: '80%',
maxWidth: '90%',
},
addHeader: {
display: 'flex',
@ -136,11 +141,82 @@ export const styles = StyleSheet.create({
},
addLabel: {
flexGrow: 1,
fontSize: 20,
fontSize: 18,
paddingLeft: 4,
paddingBottom: 8,
},
sealSwitch: {
transform: [{scaleX: 0.7}, {scaleY: 0.7}],
flexGrow: 1,
},
addControls: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
marginTop: 16,
gap: 8,
},
sealable: {
flexGrow: 1,
flexShrink: 1,
},
sealableContent: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
},
switchLabel: {
fontSize: 14,
flexShrink: 1,
},
cancel: {
borderRadius: 8,
},
cancelLabel: {
fontSize: 14,
marginVertical: 0,
paddingVertical: 6,
},
create: {
borderRadius: 8,
},
createLabel: {
fontSize: 14,
marginVertical: 0,
paddingVertical: 6,
},
members: {
height: 256,
},
membersContainer: {
},
subjectInput: {
flexGrow: 1,
backgroundColor: 'transparent',
paddingTop: 0,
paddingBottom: 0,
display: 'flex',
height: 40,
maxHeight: 40,
borderRadius: 8,
fontSize: 14,
borderBottomWidth: 0,
},
subjectContainer: {
marginBottom: 8,
},
cards: {
display: 'flex',
flexDirection: 'column',
width: '100%',
overscrollBehavior: 'none',
},
card: {
width: '100%',
height: 48,
paddingTop: 8,
paddingBottom: 8,
paddingLeft: 16,
borderBottomWidth: 1,
},
});

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useRef } from 'react';
import {Divider, Switch, Surface, IconButton, Button, Text, TextInput, useTheme} from 'react-native-paper';
import {SafeAreaView, Modal, FlatList, View} from 'react-native';
import {styles} from './Content.styled';
@ -6,12 +6,21 @@ import {useContent} from './useContent.hook';
import {Channel} from '../channel/Channel';
import {Focus} from 'databag-client-sdk';
import {BlurView} from '@react-native-community/blur';
import {Card} from '../card/Card';
export function Content({select}: {select: (focus: Focus) => void}) {
const [add, setAdd] = useState(false);
const [sealable, setSealable] = useState(false);
const [adding, setAdding] = useState(false);
const [sealed, setSealed] = useState(false);
const {state, actions} = useContent();
const theme = useTheme();
const members = useRef(new Set<string>());
const addTopic = async () => {
console.log('add topic');
};
const cards = sealed ? state.sealable : state.connected;
return (
<View style={styles.container}>
@ -102,18 +111,74 @@ export function Content({select}: {select: (focus: Focus) => void}) {
<Surface elevation={5} mode="flat" style={styles.addSurface}>
<Text style={styles.addLabel}>{ state.strings.newTopic }</Text>
<IconButton style={styles.addClose} icon="close" size={24} onPress={() => setAdd(false)} />
<TextInput
dense={true}
style={styles.input}
autoCapitalize={false}
unserlineStyle={styles.inputUnderline}
mode="outlined"
placeholder={state.strings.subjectOptional}
left={<TextInput.Icon style={styles.icon} icon="label-outline" />}
value={state.topic}
onChangeText={value => actions.setTopic(value)}
/>
<Switch style={styles.sealSwitch} value={sealable} onValueChange={flag => setSealable(flag)} />
<Surface elevation={0} style={styles.subjectContainer}>
<TextInput
dense={true}
style={styles.subjectInput}
autoCapitalize={false}
underlineStyle={styles.inputUnderline}
placeholder={state.strings.subjectOptional}
left={<TextInput.Icon style={styles.icon} icon="label-outline" />}
value={state.topic}
onChangeText={value => actions.setTopic(value)}
/>
<Divider style={styles.modalDivider} />
</Surface>
<View style={styles.membersContainer}>
<Divider style={styles.modalDivider} />
<Surface elevation={0} mode="flat" style={styles.members}>
<FlatList
style={styles.cards}
data={cards}
initialNumToRender={32}
renderItem={({item}) => {
const enable = (<Switch style={styles.sealSwitch} value={members.current.has(item.guid)} onValueChange={flag => {
if (flag) {
members.current.add(item.guid);
} else {
members.current.delete(item.guid);
}
}} />)
return (
<Card
containerStyle={{
...styles.card,
borderColor: theme.colors.outlineVariant,
}}
imageUrl={item.imageUrl}
name={item.name}
handle={item.handle}
node={item.node}
placeholder={state.strings.name}
actions={[enable]}
/>
);
}}
keyExtractor={card => card.cardId}
/>
</Surface>
<Divider style={styles.modalDivider} />
</View>
<View style={styles.addControls}>
<View style={styles.sealable}>
{ state.sealSet && (
<View style={styles.sealableContent}>
<Text style={styles.switchLabel}>{ state.strings.sealedTopic }</Text>
<Switch style={styles.sealSwitch} value={sealed} onValueChange={flag => setSealed(flag)} />
</View>
)}
</View>
<Button mode="outlined" compact={true} style={styles.cancel} labelStyle={styles.cancelLabel} onPress={() => setAdd(false)}>
{state.strings.cancel}
</Button>
<Button mode="contained" compact={true} style={styles.create} labelStyle={styles.createLabel} loading={adding} onPress={addTopic}>
{state.strings.create}
</Button>
</View>
</Surface>
</View>
</View>

View File

@ -2,7 +2,7 @@ import {useState, useContext, useEffect, useRef} from 'react';
import {AppContext} from '../context/AppContext';
import {DisplayContext} from '../context/DisplayContext';
import {ContextType} from '../context/ContextType';
import {Channel, Card, Profile} from 'databag-client-sdk';
import {Channel, Card, Profile, Config} from 'databag-client-sdk';
import {notes, unknown, iii_group, iiii_group, iiiii_group, group} from '../constants/Icons';
type ChannelParams = {
@ -24,11 +24,13 @@ export function useContent() {
strings: display.state.strings,
layout: null,
guid: '',
cards: [] as Card[],
connected: [] as Card[],
connectedAndSealable: [] as Cards[],
sorted: [] as Channel[],
filtered: [] as ChannelParams[],
filter: '',
topic: '',
sealable: false,
});
const compare = (a: Card, b: Card) => {
@ -156,6 +158,10 @@ export function useContent() {
}, [state.sorted, state.cards, state.guid, state.filter]);
useEffect(() => {
const setConfig = (config: Config) => {
const { sealSet, sealUnlocked } = config;
updateState({ sealSet: sealSet && sealUnlocked });
};
const setProfile = (profile: Profile) => {
const {guid} = profile;
updateState({guid});
@ -198,15 +204,17 @@ export function useContent() {
updateState({sorted});
};
const {identity, contact, content} = app.state.session;
const {identity, contact, content, settings} = app.state.session;
identity.addProfileListener(setProfile);
contact.addCardListener(setCards);
content.addChannelListener(setChannels);
settings.addConfigListener(setConfig);
return () => {
identity.removeProfileListener(setProfile);
contact.removeCardListener(setCards);
content.removeChannelListener(setChannels);
settings.removeConfigListener(setConfig);
};
}, []);