mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
rendering card items
This commit is contained in:
parent
911744daa4
commit
55debaba7c
@ -13,13 +13,20 @@ export function Cards() {
|
||||
<View style={styles.container}>
|
||||
{ state.tabbed && (
|
||||
<View style={styles.topbar}>
|
||||
<TouchableOpacity style={styles.sort}>
|
||||
<Ionicons style={styles.icon} name="menufold" size={18} color={Colors.text} />
|
||||
</TouchableOpacity>
|
||||
{ state.sorting && (
|
||||
<TouchableOpacity style={styles.sort} onPress={actions.unsort}>
|
||||
<Ionicons style={styles.icon} name="menufold" size={18} color={Colors.text} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{ !state.sorting && (
|
||||
<TouchableOpacity style={styles.sort} onPress={actions.sort}>
|
||||
<Ionicons style={styles.icon} name="menufold" size={18} color={Colors.disabled} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="search1" size={16} color={Colors.text} />
|
||||
<TextInput style={styles.inputfield} value={state.topic} onChangeText={actions.setTopic}
|
||||
autoCapitalize="none" placeholderTextColor={Colors.text} placeholder="Contacts" />
|
||||
<Ionicons style={styles.icon} name="search1" size={16} color={Colors.disabled} />
|
||||
<TextInput style={styles.inputfield} value={state.filter} onChangeText={actions.setFilter}
|
||||
autoCapitalize="none" placeholderTextColor={Colors.disabled} placeholder="Contacts" />
|
||||
<View style={styles.space} />
|
||||
</View>
|
||||
<TouchableOpacity style={styles.add}>
|
||||
|
@ -48,7 +48,7 @@ export const styles = StyleSheet.create({
|
||||
textAlign: 'center',
|
||||
padding: 4,
|
||||
color: Colors.text,
|
||||
fontSize: 16,
|
||||
fontSize: 14,
|
||||
},
|
||||
icon: {
|
||||
paddingLeft: 8,
|
||||
|
@ -1,4 +1,35 @@
|
||||
import { Text, TouchableOpacity, View } from 'react-native';
|
||||
import { Logo } from 'utils/Logo';
|
||||
import { styles } from './CardItem.styled';
|
||||
import { useCardItem } from './useCardItem.hook';
|
||||
|
||||
export function CardItem({ item }) {
|
||||
return <></>;
|
||||
|
||||
const { state, actions } = useCardItem(item);
|
||||
|
||||
return (
|
||||
<TouchableOpacity style={styles.container} activeOpacity={1}>
|
||||
<Logo src={item.logo} width={32} height={32} radius={6} />
|
||||
<View style={styles.detail}>
|
||||
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ item.name }</Text>
|
||||
<Text style={styles.handle} numberOfLines={1} ellipsizeMode={'tail'}>{ item.handle }</Text>
|
||||
</View>
|
||||
{ item.status === 'connected' && (
|
||||
<View style={styles.confirmed} />
|
||||
)}
|
||||
{ item.status === 'requested' && (
|
||||
<View style={styles.requested} />
|
||||
)}
|
||||
{ item.status === 'connecting' && (
|
||||
<View style={styles.connecting} />
|
||||
)}
|
||||
{ item.status === 'pending' && (
|
||||
<View style={styles.pending} />
|
||||
)}
|
||||
{ item.status === 'confirmed' && (
|
||||
<View style={styles.confirmed} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
|
61
app/mobile/src/session/cards/cardItem/CardItem.styled.js
Normal file
61
app/mobile/src/session/cards/cardItem/CardItem.styled.js
Normal file
@ -0,0 +1,61 @@
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { Colors } from 'constants/Colors';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
height: 48,
|
||||
alignItems: 'center',
|
||||
borderBottomWidth: 1,
|
||||
borderColor: Colors.itemDivider,
|
||||
},
|
||||
detail: {
|
||||
paddingLeft: 12,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
},
|
||||
name: {
|
||||
color: Colors.text,
|
||||
fontSize: 14,
|
||||
},
|
||||
handle: {
|
||||
color: Colors.text,
|
||||
fontSize: 12,
|
||||
},
|
||||
connected: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: Colors.connected,
|
||||
},
|
||||
requested: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: Colors.requested,
|
||||
},
|
||||
connecting: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: Colors.connecting,
|
||||
},
|
||||
pending: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: Colors.pending,
|
||||
},
|
||||
confirmed: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: Colors.confirmed,
|
||||
},
|
||||
})
|
||||
|
17
app/mobile/src/session/cards/cardItem/useCardItem.hook.js
Normal file
17
app/mobile/src/session/cards/cardItem/useCardItem.hook.js
Normal file
@ -0,0 +1,17 @@
|
||||
import { useState, useEffect, useRef, useContext } from 'react';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
|
||||
export function useCardItem(item) {
|
||||
|
||||
const [state, setState] = useState({});
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
const actions = {
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ export function useCards() {
|
||||
const [state, setState] = useState({
|
||||
tabbed: null,
|
||||
cards: [],
|
||||
filter: null,
|
||||
sorting: false,
|
||||
});
|
||||
|
||||
const dimensions = useWindowDimensions();
|
||||
@ -27,10 +29,74 @@ export function useCards() {
|
||||
}
|
||||
}, [dimensions]);
|
||||
|
||||
const setCardItem = (item) => {
|
||||
const { profile, detail } = item;
|
||||
|
||||
return {
|
||||
cardId: item.cardId,
|
||||
name: profile.name,
|
||||
handle: `${profile.handle}@${profile.node}`,
|
||||
status: detail.status,
|
||||
updated: detail.statusUpdated,
|
||||
logo: profile.imageSet ? card.actions.getCardLogo(item.cardId, profile.revision) : 'avatar',
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
}, [card]);
|
||||
const cards = Array.from(card.state.cards.values());
|
||||
const items = cards.map(setCardItem);
|
||||
const filtered = items.filter(item => {
|
||||
if (!state.filter) {
|
||||
return true;
|
||||
}
|
||||
const lower = state.filter.toLowerCase();
|
||||
if (item.name) {
|
||||
if (item.name.toLowerCase().includes(lower)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (item.handle) {
|
||||
if (item.handle.toLowerCase().includes(lower)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})
|
||||
if (state.sorting) {
|
||||
filtered.sort((a, b) => {
|
||||
if (a.name === b.name) {
|
||||
return 0;
|
||||
}
|
||||
if (!a.name || (a.name < b.name)) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
else {
|
||||
filtered.sort((a, b) => {
|
||||
if (a.updated === b.updated) {
|
||||
return 0;
|
||||
}
|
||||
if (!a.updated || (a.updated < b.updated)) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
}
|
||||
updateState({ cards: filtered });
|
||||
}, [card, state.filter, state.sorting]);
|
||||
|
||||
const actions = {
|
||||
setFilter: (filter) => {
|
||||
updateState({ filter });
|
||||
},
|
||||
sort: () => {
|
||||
updateState({ sorting: true });
|
||||
},
|
||||
unsort: () => {
|
||||
updateState({ sorting: false });
|
||||
},
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
|
@ -15,9 +15,9 @@ export function Channels() {
|
||||
<>
|
||||
<View style={styles.topbar}>
|
||||
<View style={styles.inputwrapper}>
|
||||
<Ionicons style={styles.icon} name="search1" size={16} color={Colors.text} />
|
||||
<TextInput style={styles.inputfield} value={state.topic} onChangeText={actions.setTopic}
|
||||
autoCapitalize="none" placeholderTextColor={Colors.text} placeholder="Topic" />
|
||||
<Ionicons style={styles.icon} name="search1" size={16} color={Colors.disabled} />
|
||||
<TextInput style={styles.inputfield} value={state.filter} onChangeText={actions.setFilter}
|
||||
autoCapitalize="none" placeholderTextColor={Colors.disabled} placeholder="Topic" />
|
||||
<View style={styles.space} />
|
||||
</View>
|
||||
<TouchableOpacity style={styles.add}>
|
||||
|
@ -38,7 +38,7 @@ export const styles = StyleSheet.create({
|
||||
textAlign: 'center',
|
||||
padding: 4,
|
||||
color: Colors.text,
|
||||
fontSize: 16,
|
||||
fontSize: 14,
|
||||
},
|
||||
icon: {
|
||||
paddingLeft: 8,
|
||||
|
@ -9,7 +9,7 @@ export function ChannelItem({ item }) {
|
||||
|
||||
return (
|
||||
<TouchableOpacity style={styles.container} activeOpacity={1} onPress={actions.setRead}>
|
||||
<Logo src={item.logo} width={40} height={40} radius={6} />
|
||||
<Logo src={item.logo} width={32} height={32} radius={6} />
|
||||
<View style={styles.detail}>
|
||||
<Text style={styles.subject} numberOfLines={1} ellipsizeMode={'tail'}>{ item.subject }</Text>
|
||||
<Text style={styles.message} numberOfLines={1} ellipsizeMode={'tail'}>{ item.message }</Text>
|
||||
|
@ -21,9 +21,11 @@ export const styles = StyleSheet.create({
|
||||
},
|
||||
subject: {
|
||||
color: Colors.text,
|
||||
fontSize: 14,
|
||||
},
|
||||
message: {
|
||||
color: Colors.disabled,
|
||||
fontSize: 12,
|
||||
},
|
||||
dot: {
|
||||
width: 8,
|
||||
|
@ -13,6 +13,7 @@ export function useChannels() {
|
||||
topic: null,
|
||||
channels: [],
|
||||
tabbed: null,
|
||||
filter: null,
|
||||
});
|
||||
|
||||
const items = useRef([]);
|
||||
@ -133,7 +134,22 @@ export function useChannels() {
|
||||
});
|
||||
merged.push(...Array.from(channel.state.channels.values()));
|
||||
|
||||
merged.sort((a, b) => {
|
||||
const items = merged.map(setChannelEntry);
|
||||
|
||||
const filtered = items.filter(item => {
|
||||
if (!state.filter) {
|
||||
return true;
|
||||
}
|
||||
const lower = state.filter.toLowerCase();
|
||||
if (item.subject) {
|
||||
if (item.subject.toLowerCase().includes(lower)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const sorted = filtered.sort((a, b) => {
|
||||
const aCreated = a?.summary?.lastTopic?.created;
|
||||
const bCreated = b?.summary?.lastTopic?.created;
|
||||
if (aCreated === bCreated) {
|
||||
@ -145,13 +161,16 @@ export function useChannels() {
|
||||
return -1;
|
||||
});
|
||||
|
||||
updateState({ channels: merged.map(item => setChannelEntry(item)) });
|
||||
}, [channel, card]);
|
||||
updateState({ channels: sorted });
|
||||
}, [channel, card, state.filter]);
|
||||
|
||||
const actions = {
|
||||
setTopic: (topic) => {
|
||||
updateState({ topic });
|
||||
},
|
||||
setFilter: (filter) => {
|
||||
updateState({ filter });
|
||||
},
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
|
@ -107,7 +107,9 @@ export function Profile() {
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
<View style={styles.visible}>
|
||||
<Text style={styles.visibleText}>Visible in Registry</Text>
|
||||
<TouchableOpacity onPress={() => setVisible(!state.searchable)} activeOpacity={1}>
|
||||
<Text style={styles.visibleText}>Visible in Registry</Text>
|
||||
</TouchableOpacity>
|
||||
<Switch style={styles.visibleSwitch} value={state.searchable} onValueChange={setVisible} trackColor={styles.switch}/>
|
||||
</View>
|
||||
<TouchableOpacity style={styles.logout} onPress={actions.logout}>
|
||||
|
Loading…
Reference in New Issue
Block a user