mirror of
https://github.com/ilyakooo0/urbit.git
synced 2025-01-07 15:38:45 +03:00
interface: show unread counts on group tiles
This commit is contained in:
parent
ec580cf8c1
commit
fb09c36fbe
@ -61,6 +61,12 @@ export class HarkApi extends BaseApi<StoreState> {
|
|||||||
return this.actOnNotification('read', time, index);
|
return this.actOnNotification('read', time, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readIndex(index: NotifIndex) {
|
||||||
|
return this.harkAction({
|
||||||
|
'read-index': index
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
unread(time: BigInteger, index: NotifIndex) {
|
unread(time: BigInteger, index: NotifIndex) {
|
||||||
return this.actOnNotification('unread', time, index);
|
return this.actOnNotification('unread', time, index);
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,21 @@ import {
|
|||||||
} from "~/types";
|
} from "~/types";
|
||||||
import { makePatDa } from "~/logic/lib/util";
|
import { makePatDa } from "~/logic/lib/util";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import {StoreState} from "../store/type";
|
||||||
|
|
||||||
type HarkState = {
|
type HarkState = Pick<StoreState,
|
||||||
notifications: Notifications;
|
"notificationsChatConfig"
|
||||||
archivedNotifications: Notifications;
|
| "notificationsGroupConfig"
|
||||||
notificationsCount: number;
|
| "notificationsGraphConfig"
|
||||||
notificationsGraphConfig: NotificationGraphConfig;
|
| "notifications"
|
||||||
notificationsGroupConfig: GroupNotificationsConfig;
|
| "notificationsCount"
|
||||||
notificationsChatConfig: string[];
|
| "archivedNotifications"
|
||||||
};
|
| "unreads">;
|
||||||
|
|
||||||
export const HarkReducer = (json: any, state: HarkState) => {
|
export const HarkReducer = (json: any, state: HarkState) => {
|
||||||
const data = _.get(json, "harkUpdate", false);
|
const data = _.get(json, "harkUpdate", false);
|
||||||
if (data) {
|
if (data) {
|
||||||
|
console.log(data);
|
||||||
reduce(data, state);
|
reduce(data, state);
|
||||||
}
|
}
|
||||||
const graphHookData = _.get(json, "hark-graph-hook-update", false);
|
const graphHookData = _.get(json, "hark-graph-hook-update", false);
|
||||||
@ -139,15 +141,30 @@ function reduce(data: any, state: HarkState) {
|
|||||||
timebox(data, state);
|
timebox(data, state);
|
||||||
more(data, state);
|
more(data, state);
|
||||||
dnd(data, state);
|
dnd(data, state);
|
||||||
count(data, state);
|
|
||||||
added(data, state);
|
added(data, state);
|
||||||
graphUnreads(data, state);
|
unreads(data, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
function graphUnreads(json: any, state: HarkState) {
|
function unreads(json: any, state: HarkState) {
|
||||||
const data = _.get(json, 'graph-unreads');
|
const data = _.get(json, 'unreads');
|
||||||
if(data) {
|
if(data) {
|
||||||
state.graphUnreads = data;
|
data.forEach(({ index, unread }) => {
|
||||||
|
updateUnreads(state, index, x => x + unread);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUnreads(state: HarkState, index: NotifIndex, f: (u: number) => number) {
|
||||||
|
state.notificationsCount = f(state.notificationsCount);
|
||||||
|
if('graph' in index) {
|
||||||
|
const curr = state.unreads.graph[index.graph.graph] || 0;
|
||||||
|
state.unreads.graph[index.graph.graph] = f(curr);
|
||||||
|
} else if('group' in index) {
|
||||||
|
const curr = state.unreads.group[index.group.group] || 0;
|
||||||
|
state.unreads.group[index.group.group] = f(curr);
|
||||||
|
} else if('chat' in index) {
|
||||||
|
const curr = state.unreads.chat[index.chat.chat] || 0
|
||||||
|
state.unreads.chat[index.chat.chat] = f(curr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,28 +174,21 @@ function added(json: any, state: HarkState) {
|
|||||||
const { index, notification } = data;
|
const { index, notification } = data;
|
||||||
const time = makePatDa(data.time);
|
const time = makePatDa(data.time);
|
||||||
const timebox = state.notifications.get(time) || [];
|
const timebox = state.notifications.get(time) || [];
|
||||||
|
|
||||||
const arrIdx = timebox.findIndex((idxNotif) =>
|
const arrIdx = timebox.findIndex((idxNotif) =>
|
||||||
notifIdxEqual(index, idxNotif.index)
|
notifIdxEqual(index, idxNotif.index)
|
||||||
);
|
);
|
||||||
if (arrIdx !== -1) {
|
if (arrIdx !== -1) {
|
||||||
|
if(timebox[arrIdx]?.notification?.read) {
|
||||||
|
updateUnreads(state, index, x => x+1);
|
||||||
|
}
|
||||||
timebox[arrIdx] = { index, notification };
|
timebox[arrIdx] = { index, notification };
|
||||||
state.notifications.set(time, timebox);
|
state.notifications.set(time, timebox);
|
||||||
} else {
|
} else {
|
||||||
|
updateUnreads(state, index, x => x+1);
|
||||||
state.notifications.set(time, [...timebox, { index, notification }]);
|
state.notifications.set(time, [...timebox, { index, notification }]);
|
||||||
state.notificationsCount++;
|
|
||||||
if('graph' in index) {
|
|
||||||
const curr = state.graphUnreads[index.graph.graph] || 0;
|
|
||||||
state.graphUnreads[index.graph.graph] = curr+1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function count(json: any, state: HarkState) {
|
|
||||||
const data = _.get(json, "count", false);
|
|
||||||
if (data !== false) {
|
|
||||||
state.notificationsCount = data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const dnd = (json: any, state: HarkState) => {
|
const dnd = (json: any, state: HarkState) => {
|
||||||
@ -254,12 +264,7 @@ function read(json: any, state: HarkState) {
|
|||||||
const data = _.get(json, "read", false);
|
const data = _.get(json, "read", false);
|
||||||
if (data) {
|
if (data) {
|
||||||
const { time, index } = data;
|
const { time, index } = data;
|
||||||
state.notificationsCount--;
|
updateUnreads(state, index, x => x-1);
|
||||||
if('graph' in index) {
|
|
||||||
const curr = state.graphUnreads[index.graph.graph] || 0;
|
|
||||||
state.graphUnreads[index.graph.graph] = curr-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
setRead(time, index, true, state);
|
setRead(time, index, true, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,11 +273,7 @@ function unread(json: any, state: HarkState) {
|
|||||||
const data = _.get(json, "unread", false);
|
const data = _.get(json, "unread", false);
|
||||||
if (data) {
|
if (data) {
|
||||||
const { time, index } = data;
|
const { time, index } = data;
|
||||||
state.notificationsCount++;
|
updateUnreads(state, index, x => x+1);
|
||||||
if('graph' in index) {
|
|
||||||
const curr = state.graphUnreads[index.graph.graph] || 0;
|
|
||||||
state.graphUnreads[index.graph.graph] = curr+1;
|
|
||||||
}
|
|
||||||
setRead(time, index, false, state);
|
setRead(time, index, false, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,9 +293,10 @@ function archive(json: any, state: HarkState) {
|
|||||||
);
|
);
|
||||||
state.notifications.set(time, unarchived);
|
state.notifications.set(time, unarchived);
|
||||||
const archiveBox = state.archivedNotifications.get(time) || [];
|
const archiveBox = state.archivedNotifications.get(time) || [];
|
||||||
state.notificationsCount -= archived.filter(
|
const readCount = archived.filter(
|
||||||
({ notification }) => !notification.read
|
({ notification }) => !notification.read
|
||||||
).length;
|
).length;
|
||||||
|
updateUnreads(state, index, x => x - readCount);
|
||||||
state.archivedNotifications.set(time, [
|
state.archivedNotifications.set(time, [
|
||||||
...archiveBox,
|
...archiveBox,
|
||||||
...archived.map(({ notification, index }) => ({
|
...archived.map(({ notification, index }) => ({
|
||||||
|
@ -107,7 +107,11 @@ export default class GlobalStore extends BaseStore<StoreState> {
|
|||||||
watching: [],
|
watching: [],
|
||||||
},
|
},
|
||||||
notificationsCount: 0,
|
notificationsCount: 0,
|
||||||
graphUnreads: {}
|
unreads: {
|
||||||
|
graph: {},
|
||||||
|
group: {},
|
||||||
|
chat: {},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ import {
|
|||||||
NotificationGraphConfig,
|
NotificationGraphConfig,
|
||||||
GroupNotificationsConfig,
|
GroupNotificationsConfig,
|
||||||
LocalUpdateRemoteContentPolicy,
|
LocalUpdateRemoteContentPolicy,
|
||||||
BackgroundConfig
|
BackgroundConfig,
|
||||||
|
Unreads
|
||||||
} from "~/types";
|
} from "~/types";
|
||||||
|
|
||||||
export interface StoreState {
|
export interface StoreState {
|
||||||
@ -59,11 +60,12 @@ export interface StoreState {
|
|||||||
inbox: Inbox;
|
inbox: Inbox;
|
||||||
pendingMessages: Map<Path, Envelope[]>;
|
pendingMessages: Map<Path, Envelope[]>;
|
||||||
|
|
||||||
|
archivedNotifications: Notifications;
|
||||||
notifications: Notifications;
|
notifications: Notifications;
|
||||||
notificationsGraphConfig: NotificationGraphConfig;
|
notificationsGraphConfig: NotificationGraphConfig;
|
||||||
notificationsGroupConfig: GroupNotificationsConfig;
|
notificationsGroupConfig: GroupNotificationsConfig;
|
||||||
notificationsChatConfig: string[];
|
notificationsChatConfig: string[];
|
||||||
notificationsCount: number,
|
notificationsCount: number,
|
||||||
doNotDisturb: boolean;
|
doNotDisturb: boolean;
|
||||||
graphUnreads: Record<string, number>;
|
unreads: Unreads;
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,11 @@ export interface NotificationGraphConfig {
|
|||||||
watching: WatchedIndex[]
|
watching: WatchedIndex[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Unreads {
|
||||||
|
chat: Record<string, number>;
|
||||||
|
group: Record<string, number>;
|
||||||
|
graph: Record<string, number>;
|
||||||
|
}
|
||||||
|
|
||||||
interface WatchedIndex {
|
interface WatchedIndex {
|
||||||
graph: string;
|
graph: string;
|
||||||
|
@ -181,6 +181,7 @@ export default class ChatWindow extends Component<ChatWindowProps, ChatWindowSta
|
|||||||
if (this.state.fetchPending) return;
|
if (this.state.fetchPending) return;
|
||||||
if (this.props.unreadCount === 0) return;
|
if (this.props.unreadCount === 0) return;
|
||||||
this.props.api.chat.read(this.props.station);
|
this.props.api.chat.read(this.props.station);
|
||||||
|
this.props.api.hark.readIndex({ chat: { chat: this.props.station, mention: false }});
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchMessages(start, end, force = false): Promise<void> {
|
fetchMessages(start, end, force = false): Promise<void> {
|
||||||
|
@ -63,7 +63,7 @@ export default class LaunchApp extends React.Component {
|
|||||||
weather={props.weather}
|
weather={props.weather}
|
||||||
/>
|
/>
|
||||||
<Box display={["none", "block"]} width="100%" gridColumn="1 / -1"></Box>
|
<Box display={["none", "block"]} width="100%" gridColumn="1 / -1"></Box>
|
||||||
<Groups groups={props.groups} associations={props.associations} />
|
<Groups unreads={props.unreads} groups={props.groups} associations={props.associations} />
|
||||||
</Box>
|
</Box>
|
||||||
</ScrollbarLessBox>
|
</ScrollbarLessBox>
|
||||||
<Box
|
<Box
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Box, Text } from "@tlon/indigo-react";
|
import { Box, Text, Col } from "@tlon/indigo-react";
|
||||||
|
import f from "lodash/fp";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
import { Associations, Association } from "~/types";
|
import { Associations, Association, Unreads } from "~/types";
|
||||||
import { alphabeticalOrder } from "~/logic/lib/util";
|
import { alphabeticalOrder } from "~/logic/lib/util";
|
||||||
import Tile from '../components/tiles/tile';
|
import Tile from "../components/tiles/tile";
|
||||||
|
|
||||||
interface GroupsProps {
|
interface GroupsProps {
|
||||||
associations: Associations;
|
associations: Associations;
|
||||||
@ -12,20 +14,57 @@ interface GroupsProps {
|
|||||||
const sortGroupsAlph = (a: Association, b: Association) =>
|
const sortGroupsAlph = (a: Association, b: Association) =>
|
||||||
alphabeticalOrder(a.metadata.title, b.metadata.title);
|
alphabeticalOrder(a.metadata.title, b.metadata.title);
|
||||||
|
|
||||||
|
const getKindUnreads = (associations: Associations) => (path: string) => (
|
||||||
|
kind: "chat" | "graph"
|
||||||
|
): ((unreads: Unreads) => number) =>
|
||||||
|
f.flow(
|
||||||
|
(x) => x[kind],
|
||||||
|
f.pickBy((_v, key) => associations[kind]?.[key]["group-path"] === path),
|
||||||
|
f.values,
|
||||||
|
f.reduce(f.add, 0)
|
||||||
|
);
|
||||||
|
|
||||||
export default function Groups(props: GroupsProps & Parameters<typeof Box>[0]) {
|
export default function Groups(props: GroupsProps & Parameters<typeof Box>[0]) {
|
||||||
const { associations, ...boxProps } = props;
|
const { associations, unreads, ...boxProps } = props;
|
||||||
|
|
||||||
const groups = Object.values(associations?.contacts || {})
|
const groups = Object.values(associations?.contacts || {})
|
||||||
.filter(e => e['group-path'] in props.groups)
|
.filter((e) => e["group-path"] in props.groups)
|
||||||
.sort(sortGroupsAlph);
|
.sort(sortGroupsAlph);
|
||||||
|
const getUnreads = getKindUnreads(associations || {});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{groups.map((group) => (
|
{groups.map((group) => {
|
||||||
<Tile to={`/~landscape${group["group-path"]}`}>
|
const path = group["group-path"];
|
||||||
<Text>{group.metadata.title}</Text>
|
const unreadCount = (["chat", "graph"] as const)
|
||||||
</Tile>
|
.map(getUnreads(path))
|
||||||
))}
|
.map((f) => f(unreads))
|
||||||
|
.reduce(f.add, 0);
|
||||||
|
return (
|
||||||
|
<Group
|
||||||
|
unreads={unreadCount}
|
||||||
|
path={group["group-path"]}
|
||||||
|
title={group.metadata.title}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GroupProps {
|
||||||
|
path: string;
|
||||||
|
title: string;
|
||||||
|
unreads: number;
|
||||||
|
}
|
||||||
|
function Group(props: GroupProps) {
|
||||||
|
const { path, title, unreads } = props;
|
||||||
|
return (
|
||||||
|
<Tile to={`/~landscape${path}`}>
|
||||||
|
<Col height="100%" justifyContent="space-between">
|
||||||
|
<Text>{title}</Text>
|
||||||
|
{unreads > 0 && <Text gray>{unreads} unread </Text>}
|
||||||
|
</Col>
|
||||||
|
</Tile>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -43,7 +43,7 @@ interface SkeletonProps {
|
|||||||
|
|
||||||
export function Skeleton(props: SkeletonProps) {
|
export function Skeleton(props: SkeletonProps) {
|
||||||
const chatConfig = useChat(props.inbox, props.chatSynced);
|
const chatConfig = useChat(props.inbox, props.chatSynced);
|
||||||
const graphConfig = useGraphModule(props.graphKeys, props.graphs, props.graphUnreads);
|
const graphConfig = useGraphModule(props.graphKeys, props.graphs, props.unreads.graph);
|
||||||
const config = useMemo(
|
const config = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
graph: graphConfig,
|
graph: graphConfig,
|
||||||
|
Loading…
Reference in New Issue
Block a user