wip
This commit is contained in:
@@ -3,6 +3,7 @@ import type { LucideIcon } from "lucide-react";
|
|||||||
|
|
||||||
export interface SidebarButtonProps {
|
export interface SidebarButtonProps {
|
||||||
label: string;
|
label: string;
|
||||||
|
count?: number;
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
Icon?: LucideIcon;
|
Icon?: LucideIcon;
|
||||||
element?;
|
element?;
|
||||||
@@ -13,6 +14,7 @@ export const SidebarButton = ({
|
|||||||
label,
|
label,
|
||||||
active,
|
active,
|
||||||
Icon,
|
Icon,
|
||||||
|
count,
|
||||||
element,
|
element,
|
||||||
onClick,
|
onClick,
|
||||||
}: SidebarButtonProps) => (
|
}: SidebarButtonProps) => (
|
||||||
@@ -25,5 +27,6 @@ export const SidebarButton = ({
|
|||||||
{Icon && <Icon size={16} />}
|
{Icon && <Icon size={16} />}
|
||||||
{element && element}
|
{element && element}
|
||||||
<span className="flex flex-1 justify-start shrink-0">{label}</span>
|
<span className="flex flex-1 justify-start shrink-0">{label}</span>
|
||||||
|
{count > 0 && <div className="justify-end notification-count">{count}</div>}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export interface RasterSource {
|
|||||||
tileSize: number;
|
tileSize: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface ErrorState {
|
interface ErrorState {
|
||||||
field: string;
|
field: string;
|
||||||
message: string;
|
message: string;
|
||||||
@@ -19,7 +20,12 @@ interface ErrorState {
|
|||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AppState {
|
export interface App {
|
||||||
|
unreadCounts: Map<number, number>;
|
||||||
|
setUnread: (id: number, count: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AppState {
|
||||||
selectedDevice: number;
|
selectedDevice: number;
|
||||||
devices: {
|
devices: {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -34,6 +40,7 @@ interface AppState {
|
|||||||
activeChat: number;
|
activeChat: number;
|
||||||
chatType: "broadcast" | "direct";
|
chatType: "broadcast" | "direct";
|
||||||
errors: ErrorState[];
|
errors: ErrorState[];
|
||||||
|
unreadCounts: Map<number, number>;
|
||||||
|
|
||||||
setRasterSources: (sources: RasterSource[]) => void;
|
setRasterSources: (sources: RasterSource[]) => void;
|
||||||
addRasterSource: (source: RasterSource) => void;
|
addRasterSource: (source: RasterSource) => void;
|
||||||
@@ -56,6 +63,9 @@ interface AppState {
|
|||||||
removeError: (field: string) => void;
|
removeError: (field: string) => void;
|
||||||
clearErrors: () => void;
|
clearErrors: () => void;
|
||||||
setNewErrors: (newErrors: ErrorState[]) => void;
|
setNewErrors: (newErrors: ErrorState[]) => void;
|
||||||
|
|
||||||
|
// unread counts
|
||||||
|
setUnread: (id: number, count: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAppStore = create<AppState>()((set, get) => ({
|
export const useAppStore = create<AppState>()((set, get) => ({
|
||||||
@@ -70,6 +80,7 @@ export const useAppStore = create<AppState>()((set, get) => ({
|
|||||||
activeChat: Types.ChannelNumber.Primary,
|
activeChat: Types.ChannelNumber.Primary,
|
||||||
chatType: "broadcast",
|
chatType: "broadcast",
|
||||||
errors: [],
|
errors: [],
|
||||||
|
unreadCounts: new Map([[0, 100],[2718471552, 1]]),
|
||||||
|
|
||||||
setRasterSources: (sources: RasterSource[]) => {
|
setRasterSources: (sources: RasterSource[]) => {
|
||||||
set(
|
set(
|
||||||
@@ -178,4 +189,11 @@ export const useAppStore = create<AppState>()((set, get) => ({
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
setUnread: (id: number, count: number) => {
|
||||||
|
set(
|
||||||
|
produce<AppState>((draft) => {
|
||||||
|
draft.unreadCounts.set(id, count);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ export interface Device {
|
|||||||
pkiBackup: boolean;
|
pkiBackup: boolean;
|
||||||
nodeDetails: boolean;
|
nodeDetails: boolean;
|
||||||
};
|
};
|
||||||
|
unreadCounts: Map<number, number>;
|
||||||
|
|
||||||
setStatus: (status: Types.DeviceStatusEnum) => void;
|
setStatus: (status: Types.DeviceStatusEnum) => void;
|
||||||
setConfig: (config: Protobuf.Config.Config) => void;
|
setConfig: (config: Protobuf.Config.Config) => void;
|
||||||
@@ -98,6 +99,7 @@ export interface Device {
|
|||||||
setDialogOpen: (dialog: DialogVariant, open: boolean) => void;
|
setDialogOpen: (dialog: DialogVariant, open: boolean) => void;
|
||||||
processPacket: (data: ProcessPacketParams) => void;
|
processPacket: (data: ProcessPacketParams) => void;
|
||||||
setMessageDraft: (message: string) => void;
|
setMessageDraft: (message: string) => void;
|
||||||
|
setUnread: (id: number, count: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DeviceState {
|
export interface DeviceState {
|
||||||
@@ -149,6 +151,7 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
|
|||||||
},
|
},
|
||||||
pendingSettingsChanges: false,
|
pendingSettingsChanges: false,
|
||||||
messageDraft: "",
|
messageDraft: "",
|
||||||
|
unreadCounts: new Map([[0, 100],[2718471552, 1]]),
|
||||||
|
|
||||||
setStatus: (status: Types.DeviceStatusEnum) => {
|
setStatus: (status: Types.DeviceStatusEnum) => {
|
||||||
set(
|
set(
|
||||||
@@ -631,6 +634,17 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
setUnread: (id: number, count: number) => {
|
||||||
|
set(
|
||||||
|
produce<DeviceState>((draft) => {
|
||||||
|
console.log(id, count);
|
||||||
|
const device = draft.devices.get(id);
|
||||||
|
if (device) {
|
||||||
|
device.unreadCounts.set(id, count);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { Device } from "@core/stores/deviceStore.ts";
|
import type { Device } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf, type Types } from "@meshtastic/core";
|
import { Protobuf, type Types } from "@meshtastic/core";
|
||||||
|
|
||||||
|
|
||||||
export const subscribeAll = (
|
export const subscribeAll = (
|
||||||
device: Device,
|
device: Device,
|
||||||
connection: Types.ConnectionType,
|
connection: Types.ConnectionType,
|
||||||
@@ -84,6 +85,7 @@ export const subscribeAll = (
|
|||||||
...messagePacket,
|
...messagePacket,
|
||||||
state: messagePacket.from !== myNodeNum ? "ack" : "waiting",
|
state: messagePacket.from !== myNodeNum ? "ack" : "waiting",
|
||||||
});
|
});
|
||||||
|
device.unreadCounts.set(messagePacket.from, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.events.onTraceRoutePacket.subscribe((traceRoutePacket) => {
|
connection.events.onTraceRoutePacket.subscribe((traceRoutePacket) => {
|
||||||
|
|||||||
@@ -110,3 +110,11 @@ img {
|
|||||||
.animate-spin-slow {
|
.animate-spin-slow {
|
||||||
animation: spin-slower 2s linear infinite;
|
animation: spin-slower 2s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notification-count {
|
||||||
|
color: white;
|
||||||
|
border-radius: 20%;
|
||||||
|
padding-left: 2%;
|
||||||
|
padding-right: 2%;
|
||||||
|
background-color: rgb(195,0,0);
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@ import { HashIcon, LockIcon, LockOpenIcon } from "lucide-react";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
export const MessagesPage = () => {
|
export const MessagesPage = () => {
|
||||||
const { channels, nodes, hardware, messages } = useDevice();
|
const { channels, nodes, hardware, messages, unreadCounts } = useDevice();
|
||||||
const { activeChat, chatType, setActiveChat, setChatType } = useAppStore();
|
const { activeChat, chatType, setActiveChat, setChatType } = useAppStore();
|
||||||
const [searchTerm, setSearchTerm] = useState<string>("");
|
const [searchTerm, setSearchTerm] = useState<string>("");
|
||||||
const filteredNodes = Array.from(nodes.values()).filter((node) => {
|
const filteredNodes = Array.from(nodes.values()).filter((node) => {
|
||||||
@@ -38,6 +38,7 @@ export const MessagesPage = () => {
|
|||||||
{filteredChannels.map((channel) => (
|
{filteredChannels.map((channel) => (
|
||||||
<SidebarButton
|
<SidebarButton
|
||||||
key={channel.index}
|
key={channel.index}
|
||||||
|
count={unreadCounts.get(channel.index)}
|
||||||
label={channel.settings?.name.length
|
label={channel.settings?.name.length
|
||||||
? channel.settings?.name
|
? channel.settings?.name
|
||||||
: channel.index === 0
|
: channel.index === 0
|
||||||
@@ -47,6 +48,7 @@ export const MessagesPage = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setChatType("broadcast");
|
setChatType("broadcast");
|
||||||
setActiveChat(channel.index);
|
setActiveChat(channel.index);
|
||||||
|
unreadCounts.set(channel.index, 0);
|
||||||
}}
|
}}
|
||||||
element={<HashIcon size={16} className="mr-2" />}
|
element={<HashIcon size={16} className="mr-2" />}
|
||||||
/>
|
/>
|
||||||
@@ -66,12 +68,14 @@ export const MessagesPage = () => {
|
|||||||
{filteredNodes.map((node) => (
|
{filteredNodes.map((node) => (
|
||||||
<SidebarButton
|
<SidebarButton
|
||||||
key={node.num}
|
key={node.num}
|
||||||
|
count={unreadCounts.get(node.num)}
|
||||||
label={node.user?.longName ??
|
label={node.user?.longName ??
|
||||||
`!${numberToHexUnpadded(node.num)}`}
|
`!${numberToHexUnpadded(node.num)}`}
|
||||||
active={activeChat === node.num}
|
active={activeChat === node.num}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setChatType("direct");
|
setChatType("direct");
|
||||||
setActiveChat(node.num);
|
setActiveChat(node.num);
|
||||||
|
unreadCounts.set(node.num, 1)
|
||||||
}}
|
}}
|
||||||
element={
|
element={
|
||||||
<Avatar
|
<Avatar
|
||||||
|
|||||||
Reference in New Issue
Block a user