mirror of
https://github.com/balzack/databag.git
synced 2025-03-13 00:50:03 +00:00
adding channel read indicator
This commit is contained in:
parent
61cb4fc903
commit
433781c5fa
@ -13,6 +13,7 @@ import { ChannelContext } from 'context/ChannelContext';
|
||||
export function useAppContext() {
|
||||
const [state, setState] = useState({
|
||||
session: null,
|
||||
loginTimestamp: null,
|
||||
disconnected: null,
|
||||
});
|
||||
const store = useContext(StoreContext);
|
||||
@ -47,7 +48,7 @@ export function useAppContext() {
|
||||
await profile.actions.setSession(access);
|
||||
await card.actions.setSession(access);
|
||||
await channel.actions.setSession(access);
|
||||
updateState({ session: true });
|
||||
updateState({ session: true, loginTimestamp: access.created });
|
||||
setWebsocket(access.server, access.appToken);
|
||||
}
|
||||
|
||||
|
@ -21,18 +21,21 @@ export function useChannelContext() {
|
||||
}
|
||||
|
||||
const setChannel = (channelId, channel) => {
|
||||
channels.current.set(channelId, {
|
||||
channelId: channel?.id,
|
||||
revision: channel?.revision,
|
||||
detail: channel?.data?.channelDetail,
|
||||
summary: channel?.data?.channelSummary,
|
||||
detailRevision: channel?.data?.detailRevision,
|
||||
topicRevision: channel?.data?.topicRevision,
|
||||
});
|
||||
let update = channels.current.get(channelId);
|
||||
if (!update) {
|
||||
update = { readRevision: 0 };
|
||||
}
|
||||
update.channelId = channel?.id;
|
||||
update.revision = channel?.revision;
|
||||
update.detail = channel?.data?.channelDetail;
|
||||
update.summary = channel?.data?.channelSummary;
|
||||
update.detailRevision = channel?.data?.detailRevision;
|
||||
update.topicRevision = channel?.data?.topicRevision;
|
||||
channels.current.set(channelId, channel);
|
||||
}
|
||||
const setChannelDetails = (channelId, detail, revision) => {
|
||||
let channel = channels.current.get(channelId);
|
||||
if (channel?.data) {
|
||||
if (channel) {
|
||||
channel.detail = detail;
|
||||
channel.detailRevision = revision;
|
||||
channels.current.set(channelId, channel);
|
||||
@ -53,6 +56,13 @@ export function useChannelContext() {
|
||||
channels.current.set(channelId, channel);
|
||||
}
|
||||
}
|
||||
const setChannelReadRevision = (channelId, revision) => {
|
||||
let channel = channels.current.get(channelId);
|
||||
if (channel) {
|
||||
channel.readRevision = revision;
|
||||
channels.current.set(channelId, channel);
|
||||
}
|
||||
}
|
||||
|
||||
const sync = async () => {
|
||||
|
||||
@ -141,6 +151,11 @@ export function useChannelContext() {
|
||||
curRevision.current = rev;
|
||||
sync();
|
||||
},
|
||||
setReadRevision: async (channelId, rev) => {
|
||||
await store.actions.setChannelItemReadRevision(session.current.guid, channelId, rev);
|
||||
setChannelReadRevision(channelId, rev);
|
||||
updateState({ channels: channels.current });
|
||||
}
|
||||
}
|
||||
|
||||
return { state, actions }
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useEffect, useState, useRef, useContext } from 'react';
|
||||
import SQLite from "react-native-sqlite-storage";
|
||||
|
||||
const DATABAG_DB = 'databag_v025.db';
|
||||
const DATABAG_DB = 'databag_v026.db';
|
||||
|
||||
export function useStoreContext() {
|
||||
const [state, setState] = useState({});
|
||||
@ -12,10 +12,10 @@ export function useStoreContext() {
|
||||
}
|
||||
|
||||
const initSession = async (guid) => {
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS channel_${guid} (channel_id text, revision integer, detail_revision integer, topic_revision integer, detail text, summary text, offsync integer, unique(channel_id))`);
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS channel_${guid} (channel_id text, revision integer, detail_revision integer, topic_revision integer, detail text, summary text, offsync integer, read_revision integer, unique(channel_id))`);
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS channel_topic_${guid} (channel_id text, topic_id text, revision integer, detail_revision integer, detail text, unique(channel_id, topic_id))`);
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS card_${guid} (card_id text, revision integer, detail_revision integer, profile_revision integer, detail text, profile text, notified_view integer, notified_article integer, notified_profile integer, notified_channel integer, offsync integer, unique(card_id))`);
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS card_channel_${guid} (card_id text, channel_id text, revision integer, detail_revision integer, topic_revision integer, detail text, summary text, offsync integer, unique(card_id, channel_id))`);
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS card_channel_${guid} (card_id text, channel_id text, revision integer, detail_revision integer, topic_revision integer, detail text, summary text, offsync integer, read_revision integer, unique(card_id, channel_id))`);
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS card_channel_topic_${guid} (card_id text, channel_id text, topic_id text, revision integer, detail_revision integer, detail text, unique(card_id, channel_id, topic_id))`);
|
||||
}
|
||||
|
||||
@ -174,6 +174,9 @@ export function useStoreContext() {
|
||||
setChannelItemRevision: async (guid, channelId, revision) => {
|
||||
await db.current.executeSql(`UPDATE channel_${guid} set revision=? where channel_id=?`, [revision, channelId]);
|
||||
},
|
||||
setChannelItemReadRevision: async (guid, channelId, revision) => {
|
||||
await db.current.executeSql(`UPDATE channel_${guid} set read_revision=? where channel_id=?`, [revision, channelId]);
|
||||
},
|
||||
setChannelItemDetail: async (guid, channelId, revision, detail) => {
|
||||
await db.current.executeSql(`UPDATE channel_${guid} set detail_revision=?, detail=? where channel_id=?`, [revision, encodeObject(detail), channelId]);
|
||||
},
|
||||
@ -192,10 +195,11 @@ export function useStoreContext() {
|
||||
};
|
||||
},
|
||||
getChannelItems: async (guid) => {
|
||||
const values = await getAppValues(db.current, `SELECT channel_id, revision, detail_revision, topic_revision, detail, summary FROM channel_${guid}`, []);
|
||||
const values = await getAppValues(db.current, `SELECT channel_id, read_revision, revision, detail_revision, topic_revision, detail, summary FROM channel_${guid}`, []);
|
||||
return values.map(channel => ({
|
||||
channelId: channel.channel_id,
|
||||
revision: channel.revision,
|
||||
readRevision: channel.read_revision,
|
||||
detailRevision: channel.detail_revision,
|
||||
topicRevision: channel.topic_revision,
|
||||
detail: decodeObject(channel.detail),
|
||||
@ -213,6 +217,9 @@ export function useStoreContext() {
|
||||
setCardChannelItemRevision: async (guid, cardId, channelId, revision) => {
|
||||
await db.current.executeSql(`UPDATE card_channel_${guid} set revision=? where card_id=? and channel_id=?`, [revision, cardId, channelId]);
|
||||
},
|
||||
setCardChannelItemReadRevision: async (guid, cardId, channelId, revision) => {
|
||||
await db.current.executeSql(`UPDATE card_channel_${guid} set read_revision=? where card_id=? and channel_id=?`, [revision, cardId, channelId]);
|
||||
},
|
||||
setCardChannelItemDetail: async (guid, cardId, channelId, revision, detail) => {
|
||||
await db.current.executeSql(`UPDATE card_channel_${guid} set detail_revision=?, detail=? where card_id=? and channel_id=?`, [revision, encodeObject(detail), cardId, channelId]);
|
||||
},
|
||||
@ -231,11 +238,12 @@ export function useStoreContext() {
|
||||
};
|
||||
},
|
||||
getCardChannelItems: async (guid) => {
|
||||
const values = await getAppValues(db.current, `SELECT card_id, channel_id, revision, detail_revision, topic_revision, detail, summary FROM card_channel_${guid}`, []);
|
||||
const values = await getAppValues(db.current, `SELECT card_id, channel_id, read_revision, revision, detail_revision, topic_revision, detail, summary FROM card_channel_${guid}`, []);
|
||||
return values.map(channel => ({
|
||||
cardId: channel.card_id,
|
||||
channelId: channel.channel_id,
|
||||
revision: channel.revision,
|
||||
readRevision: channel.read_revision,
|
||||
detailRevision: channel.detail_revision,
|
||||
topicRevision: channel.topic_revision,
|
||||
detail: decodeObject(channel.detail),
|
||||
|
@ -3,7 +3,7 @@ import { FlatList, ScrollView, View, TextInput, TouchableOpacity, Text } from 'r
|
||||
import { styles } from './Channels.styled';
|
||||
import { useChannels } from './useChannels.hook';
|
||||
import Ionicons from '@expo/vector-icons/AntDesign';
|
||||
import { MemoizedChannelItem } from './channelItem/ChannelItem';
|
||||
import { ChannelItem } from './channelItem/ChannelItem';
|
||||
|
||||
export function Channels() {
|
||||
const { state, actions } = useChannels();
|
||||
@ -17,7 +17,7 @@ export function Channels() {
|
||||
</View>
|
||||
<FlatList style={styles.channels}
|
||||
data={state.channels}
|
||||
renderItem={({ item }) => <MemoizedChannelItem item={item} />}
|
||||
renderItem={({ item }) => <ChannelItem item={item} />}
|
||||
keyExtractor={item => (`${item.cardId}:${item.channelId}`)}
|
||||
/>
|
||||
</View>
|
||||
|
@ -1,18 +1,23 @@
|
||||
import { Text, TouchableOpacity, View } from 'react-native';
|
||||
import React from 'react';
|
||||
import { Logo } from 'utils/Logo';
|
||||
import { styles } from './ChannelItem.styled';
|
||||
import { useChannelItem } from './useChannelItem.hook';
|
||||
|
||||
export function ChannelItem({ item }) {
|
||||
|
||||
const { state, actions } = useChannelItem(item);
|
||||
|
||||
return (
|
||||
<TouchableOpacity style={styles.container} activeOpacity={1}>
|
||||
<TouchableOpacity style={styles.container} activeOpacity={1} onPress={actions.setRead}>
|
||||
<Logo src={item.logo} width={40} height={40} 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>
|
||||
</View>
|
||||
{ item.updated && (
|
||||
<View style={styles.dot} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
export const MemoizedChannelItem = React.memo(ChannelItem);
|
||||
|
@ -20,9 +20,16 @@ export const styles = StyleSheet.create({
|
||||
flexShrink: 1,
|
||||
},
|
||||
subject: {
|
||||
color: Colors.text,
|
||||
},
|
||||
message: {
|
||||
color: Colors.disabled,
|
||||
},
|
||||
dot: {
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: Colors.background,
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
import { useState, useEffect, useRef, useContext } from 'react';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
import { CardContext } from 'context/CardContext';
|
||||
import { ChannelContext } from 'context/ChannelContext';
|
||||
|
||||
export function useChannelItem(item) {
|
||||
|
||||
const [state, setState] = useState({});
|
||||
|
||||
const channel = useContext(ChannelContext);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
const actions = {
|
||||
setRead: () => {
|
||||
channel.actions.setReadRevision(item.channelId, item.revision);
|
||||
},
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { useWindowDimensions } from 'react-native';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { CardContext } from 'context/CardContext';
|
||||
import { ChannelContext } from 'context/ChannelContext';
|
||||
import { AppContext } from 'context/AppContext';
|
||||
import config from 'constants/Config';
|
||||
|
||||
export function useChannels() {
|
||||
@ -15,6 +16,7 @@ export function useChannels() {
|
||||
const items = useRef([]);
|
||||
const channel = useContext(ChannelContext);
|
||||
const card = useContext(CardContext);
|
||||
const app = useContext(AppContext);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
@ -31,6 +33,16 @@ export function useChannels() {
|
||||
}
|
||||
|
||||
const setChannelEntry = (item) => {
|
||||
|
||||
let updated = false;
|
||||
const login = app.state.loginTimestamp;
|
||||
const update = item?.summary?.lastTopic?.created;
|
||||
if (update && login && login < update) {
|
||||
if (!item.readRevision || item.readRevision < item.revision) {
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
let contacts = [];
|
||||
if (item?.detail?.members) {
|
||||
item.detail.members.forEach(guid => {
|
||||
@ -91,18 +103,23 @@ export function useChannels() {
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
channelId: item.channelId,
|
||||
contacts: contacts,
|
||||
logo: logo,
|
||||
subject: subject,
|
||||
message: message,
|
||||
}
|
||||
return { channelId: item.channelId, contacts, logo, subject, message, updated, revision: item.revision };
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const channels = Array.from(channel.state.channels.values()).map(item => setChannelEntry(item));
|
||||
updateState({ channels: channels });
|
||||
let channels = Array.from(channel.state.channels.values())
|
||||
channels.sort((a, b) => {
|
||||
const aCreated = a?.summary?.lastTopic?.created;
|
||||
const bCreated = b?.summary?.lastTopic?.created;
|
||||
if (aCreated === bCreated) {
|
||||
return 0;
|
||||
}
|
||||
if (!aCreated || aCreated < bCreated) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
updateState({ channels: channels.map(item => setChannelEntry(item)) });
|
||||
}, [channel, card]);
|
||||
|
||||
const actions = {
|
||||
|
Loading…
Reference in New Issue
Block a user