WIP
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
import { IHTTPConnection } from '@meshtastic/meshtasticjs';
|
||||
|
||||
export const connection = new IHTTPConnection();
|
||||
@@ -0,0 +1,8 @@
|
||||
import { createRouter, defineRoute } from 'type-route';
|
||||
|
||||
export const { RouteProvider, useRoute, routes } = createRouter({
|
||||
messages: defineRoute('/'),
|
||||
nodes: defineRoute('/nodes'),
|
||||
settings: defineRoute('/settings'),
|
||||
about: defineRoute('/about'),
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
export type currentPageName = 'messages' | 'settings';
|
||||
|
||||
interface AppState {
|
||||
mobileNavOpen: boolean;
|
||||
darkMode: boolean;
|
||||
currentPage: currentPageName;
|
||||
}
|
||||
|
||||
const initialState: AppState = {
|
||||
mobileNavOpen: false,
|
||||
darkMode: localStorage.getItem('darkMode') === 'true' ?? false,
|
||||
currentPage: 'messages',
|
||||
};
|
||||
|
||||
export const appSlice = createSlice({
|
||||
name: 'app',
|
||||
initialState,
|
||||
reducers: {
|
||||
openMobileNav(state) {
|
||||
state.mobileNavOpen = true;
|
||||
},
|
||||
closeMobileNav(state) {
|
||||
state.mobileNavOpen = false;
|
||||
},
|
||||
setDarkModeEnabled(state, action: PayloadAction<boolean>) {
|
||||
localStorage.setItem('darkMode', String(action.payload));
|
||||
state.darkMode = action.payload;
|
||||
},
|
||||
setCurrentPage(state, action: PayloadAction<currentPageName>) {
|
||||
state.currentPage = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
openMobileNav,
|
||||
closeMobileNav,
|
||||
setDarkModeEnabled,
|
||||
setCurrentPage,
|
||||
} = appSlice.actions;
|
||||
|
||||
export default appSlice.reducer;
|
||||
@@ -0,0 +1,137 @@
|
||||
import { Protobuf, Types } from '@meshtastic/meshtasticjs';
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
import { connection } from '../connection';
|
||||
|
||||
export interface MessageWithAck {
|
||||
message: Types.TextPacket;
|
||||
ack: boolean;
|
||||
isSender: boolean;
|
||||
received: Date;
|
||||
}
|
||||
|
||||
interface AppState {
|
||||
deviceStatus: Types.DeviceStatusEnum;
|
||||
lastMeshInterraction: number;
|
||||
ready: boolean;
|
||||
myNodeInfo: Protobuf.MyNodeInfo;
|
||||
positionPackets: Types.PositionPacket[];
|
||||
nodes: Protobuf.NodeInfo[];
|
||||
channels: Protobuf.Channel[];
|
||||
preferences: Protobuf.RadioConfig_UserPreferences;
|
||||
messages: MessageWithAck[];
|
||||
hostOverrideEnabled: boolean;
|
||||
hostOverride: string;
|
||||
}
|
||||
|
||||
const initialState: AppState = {
|
||||
deviceStatus: Types.DeviceStatusEnum.DEVICE_DISCONNECTED,
|
||||
lastMeshInterraction: 0,
|
||||
ready: false,
|
||||
myNodeInfo: Protobuf.MyNodeInfo.create(),
|
||||
positionPackets: [],
|
||||
nodes: [],
|
||||
channels: [],
|
||||
preferences: Protobuf.RadioConfig_UserPreferences.create(),
|
||||
messages: [],
|
||||
hostOverrideEnabled:
|
||||
localStorage.getItem('hostOverrideEnabled') === 'true' ?? false,
|
||||
hostOverride: localStorage.getItem('hostOverride') ?? '',
|
||||
};
|
||||
|
||||
export const meshtasticSlice = createSlice({
|
||||
name: 'meshtastic',
|
||||
initialState,
|
||||
reducers: {
|
||||
setDeviceStatus: (state, action: PayloadAction<Types.DeviceStatusEnum>) => {
|
||||
state.deviceStatus = action.payload;
|
||||
},
|
||||
setLastMeshInterraction: (state, action: PayloadAction<number>) => {
|
||||
state.lastMeshInterraction = action.payload;
|
||||
},
|
||||
setReady: (state, action: PayloadAction<boolean>) => {
|
||||
state.ready = action.payload;
|
||||
},
|
||||
setMyNodeInfo: (state, action: PayloadAction<Protobuf.MyNodeInfo>) => {
|
||||
state.myNodeInfo = action.payload;
|
||||
},
|
||||
addPositionPacket: (state, action: PayloadAction<Types.PositionPacket>) => {
|
||||
state.positionPackets.push(action.payload);
|
||||
},
|
||||
addNode: (state, action: PayloadAction<Protobuf.NodeInfo>) => {
|
||||
if (
|
||||
state.nodes.findIndex((node) => node.num === action.payload.num) !== -1
|
||||
) {
|
||||
state.nodes = state.nodes.map((node) => {
|
||||
return node.num === action.payload.num ? action.payload : node;
|
||||
});
|
||||
} else {
|
||||
state.nodes.push(action.payload);
|
||||
}
|
||||
},
|
||||
|
||||
addChannel: (state, action: PayloadAction<Protobuf.Channel>) => {
|
||||
if (
|
||||
state.channels.findIndex(
|
||||
(channel) => channel.index === action.payload.index,
|
||||
) !== -1
|
||||
) {
|
||||
state.channels = state.channels.map((channel) => {
|
||||
return channel.index === action.payload.index
|
||||
? action.payload
|
||||
: channel;
|
||||
});
|
||||
} else {
|
||||
state.channels.push(action.payload);
|
||||
}
|
||||
},
|
||||
setPreferences: (
|
||||
state,
|
||||
action: PayloadAction<Protobuf.RadioConfig_UserPreferences>,
|
||||
) => {
|
||||
state.preferences = action.payload;
|
||||
},
|
||||
addMessage: (state, action: PayloadAction<MessageWithAck>) => {
|
||||
state.messages.push(action.payload);
|
||||
},
|
||||
ackMessage: (state, messageId: PayloadAction<number>) => {
|
||||
state.messages.map((message) => {
|
||||
if (message.message.packet.id === messageId.payload) {
|
||||
message.ack = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
setHostOverrideEnabled: (state, action: PayloadAction<boolean>) => {
|
||||
state.hostOverrideEnabled = action.payload;
|
||||
localStorage.setItem('hostOverrideEnabled', String(action.payload));
|
||||
if (state.hostOverrideEnabled !== action.payload) {
|
||||
connection.disconnect();
|
||||
}
|
||||
},
|
||||
setHostOverride: (state, action: PayloadAction<string>) => {
|
||||
state.hostOverride = action.payload;
|
||||
localStorage.setItem('hostOverride', action.payload);
|
||||
if (state.hostOverride !== action.payload) {
|
||||
connection.disconnect();
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
setDeviceStatus,
|
||||
setLastMeshInterraction,
|
||||
setReady,
|
||||
setMyNodeInfo,
|
||||
addPositionPacket,
|
||||
addNode,
|
||||
addChannel,
|
||||
setPreferences,
|
||||
addMessage,
|
||||
ackMessage,
|
||||
setHostOverrideEnabled,
|
||||
setHostOverride,
|
||||
} = meshtasticSlice.actions;
|
||||
|
||||
export default meshtasticSlice.reducer;
|
||||
@@ -0,0 +1,18 @@
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
|
||||
import appReducer from './slices/appSlice';
|
||||
import meshtasticReducer from './slices/meshtasticSlice';
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
app: appReducer,
|
||||
meshtastic: meshtasticReducer,
|
||||
},
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware({
|
||||
serializableCheck: false,
|
||||
}),
|
||||
});
|
||||
|
||||
export type RootState = ReturnType<typeof store.getState>;
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { Theme } from '@material-ui/core';
|
||||
import { createTheme } from '@material-ui/core/styles';
|
||||
|
||||
export const theme = (darkMode: boolean): Theme => {
|
||||
return createTheme(
|
||||
darkMode
|
||||
? {
|
||||
palette: {
|
||||
mode: 'dark',
|
||||
primary: {
|
||||
main: '#67ea94',
|
||||
},
|
||||
background: {
|
||||
default: '#0F172A',
|
||||
paper: '#0F172A',
|
||||
},
|
||||
},
|
||||
}
|
||||
: {
|
||||
palette: {
|
||||
mode: 'light',
|
||||
primary: {
|
||||
main: '#67ea94',
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import i18n from 'i18next';
|
||||
import detector from 'i18next-browser-languagedetector';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
import { en } from '../translations/en';
|
||||
import { jp } from '../translations/jp';
|
||||
import { pt } from '../translations/pt';
|
||||
|
||||
i18n
|
||||
.use(detector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
fallbackLng: 'en',
|
||||
resources: {
|
||||
en: { translation: en },
|
||||
jp: { translation: jp },
|
||||
pt: { translation: pt },
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
Reference in New Issue
Block a user