implement auto reconnect

This commit is contained in:
marlon-erler
2026-04-01 08:29:39 +00:00
parent c52d7b7685
commit 9d400a9929
82 changed files with 8340 additions and 7641 deletions
+88 -87
View File
@@ -9,98 +9,99 @@ import SettingsViewModel from "../Global/settingsViewModel";
import StorageModel from "../../Model/Global/storageModel";
export default class ChatListViewModel {
storageModel: StorageModel;
chatListModel: ChatListModel;
settingsViewModel: SettingsViewModel;
storageModel: StorageModel;
chatListModel: ChatListModel;
settingsViewModel: SettingsViewModel;
// data
chatIndexManager: IndexManager<ChatViewModel> = new IndexManager(
(chatViewModel: ChatViewModel) =>
chatViewModel.settingsPageViewModel.primaryChannel.value
);
// state
newChatPrimaryChannel: React.State<string> = new React.State("");
chatViewModels: React.ListState<ChatViewModel> = new React.ListState();
selectedChat: React.State<ChatViewModel | undefined> = new React.State<any>(
undefined
);
// guards
cannotCreateChat = React.createProxyState(
[this.newChatPrimaryChannel],
() => this.newChatPrimaryChannel.value == ""
);
// methods
createChat = (): void => {
const chatModel: ChatModel = this.chatListModel.createChat(
this.newChatPrimaryChannel.value
// data
chatIndexManager: IndexManager<ChatViewModel> = new IndexManager(
(chatViewModel: ChatViewModel) =>
chatViewModel.settingsPageViewModel.primaryChannel.value,
);
this.newChatPrimaryChannel.value = "";
const chatViewModel: ChatViewModel = this.createChatViewModel(chatModel);
this.trackChat(chatViewModel);
this.updateIndices();
};
// state
newChatPrimaryChannel: React.State<string> = new React.State("");
chatViewModels: React.ListState<ChatViewModel> = new React.ListState();
trackChat = (chatViewModel: ChatViewModel): void => {
this.chatViewModels.add(chatViewModel);
};
untrackChat = (chatViewModel: ChatViewModel): void => {
this.chatListModel.untrackChat(chatViewModel.chatModel);
this.chatViewModels.remove(chatViewModel);
};
createChatViewModel = (chatModel: ChatModel): ChatViewModel => {
return new ChatViewModel(
this.coreViewModel,
this.storageModel,
chatModel,
this.settingsViewModel,
this
selectedChat: React.State<ChatViewModel | undefined> = new React.State<any>(
undefined,
);
};
updateIndices = (): void => {
this.chatIndexManager.update([...this.chatViewModels.value.values()]);
for (const chatViewModel of this.chatViewModels.value) {
chatViewModel.updateIndex();
// guards
cannotCreateChat = React.createProxyState(
[this.newChatPrimaryChannel],
() => this.newChatPrimaryChannel.value == "",
);
// methods
createChat = (): void => {
const chatModel: ChatModel = this.chatListModel.createChat(
this.newChatPrimaryChannel.value,
);
this.newChatPrimaryChannel.value = "";
const chatViewModel: ChatViewModel =
this.createChatViewModel(chatModel);
this.trackChat(chatViewModel);
this.updateIndices();
};
trackChat = (chatViewModel: ChatViewModel): void => {
this.chatViewModels.add(chatViewModel);
};
untrackChat = (chatViewModel: ChatViewModel): void => {
this.chatListModel.untrackChat(chatViewModel.chatModel);
this.chatViewModels.remove(chatViewModel);
};
createChatViewModel = (chatModel: ChatModel): ChatViewModel => {
return new ChatViewModel(
this.coreViewModel,
this.storageModel,
chatModel,
this.settingsViewModel,
this,
);
};
updateIndices = (): void => {
this.chatIndexManager.update([...this.chatViewModels.value.values()]);
for (const chatViewModel of this.chatViewModels.value) {
chatViewModel.updateIndex();
}
};
// view
openChat = (chatViewModel: ChatViewModel): void => {
this.selectedChat.value = chatViewModel;
};
closeChat = (): void => {
this.selectedChat.value = undefined;
};
// load
loadChats = (): void => {
this.chatViewModels.clear();
for (const chatModel of this.chatListModel.chatModels.values()) {
const chatViewModel = this.createChatViewModel(chatModel);
this.trackChat(chatViewModel);
}
this.updateIndices();
};
// init
constructor(
public coreViewModel: CoreViewModel,
storageModel: StorageModel,
chatListModel: ChatListModel,
settingsViewModel: SettingsViewModel,
) {
this.storageModel = storageModel;
this.chatListModel = chatListModel;
this.settingsViewModel = settingsViewModel;
this.loadChats();
}
};
// view
openChat = (chatViewModel: ChatViewModel): void => {
this.selectedChat.value = chatViewModel;
};
closeChat = (): void => {
this.selectedChat.value = undefined;
};
// load
loadChats = (): void => {
this.chatViewModels.clear();
for (const chatModel of this.chatListModel.chatModels.values()) {
const chatViewModel = this.createChatViewModel(chatModel);
this.trackChat(chatViewModel);
}
this.updateIndices();
};
// init
constructor(
public coreViewModel: CoreViewModel,
storageModel: StorageModel,
chatListModel: ChatListModel,
settingsViewModel: SettingsViewModel
) {
this.storageModel = storageModel;
this.chatListModel = chatListModel;
this.settingsViewModel = settingsViewModel;
this.loadChats();
}
}
+50 -50
View File
@@ -6,62 +6,62 @@ import CoreViewModel from "../Global/coreViewModel";
import MessagePageViewModel from "../Pages/messagePageViewModel";
export default class ChatMessageViewModel {
messagePageViewModel: MessagePageViewModel;
messagePageViewModel: MessagePageViewModel;
// data
chatMessage: ChatMessage;
channel: string;
sender: string;
dateSent: string;
body: React.State<string> = new React.State("");
status: React.State<ChatMessageStatus | any> = new React.State<any>(
undefined
);
sentByUser: boolean;
// data
chatMessage: ChatMessage;
channel: string;
sender: string;
dateSent: string;
body: React.State<string> = new React.State("");
status: React.State<ChatMessageStatus | any> = new React.State<any>(
undefined,
);
sentByUser: boolean;
// state
isPresentingInfoModal: React.State<boolean> = new React.State(false);
// state
isPresentingInfoModal: React.State<boolean> = new React.State(false);
// methods
copyMessage = (): void => {
navigator.clipboard.writeText(this.body.value);
};
resendMessage = (): void => {
this.messagePageViewModel.sendMessageFromBody(this.body.value);
};
decryptMessage = (): void => {
this.messagePageViewModel.decryptMessage(this);
};
// methods
copyMessage = (): void => {
navigator.clipboard.writeText(this.body.value);
};
resendMessage = (): void => {
this.messagePageViewModel.sendMessageFromBody(this.body.value);
};
decryptMessage = (): void => {
this.messagePageViewModel.decryptMessage(this);
};
// view
showInfoModal = (): void => {
this.isPresentingInfoModal.value = true;
};
// view
showInfoModal = (): void => {
this.isPresentingInfoModal.value = true;
};
hideInfoModal = (): void => {
this.isPresentingInfoModal.value = false;
};
hideInfoModal = (): void => {
this.isPresentingInfoModal.value = false;
};
// load
loadData = (): void => {
this.channel = this.chatMessage.channel;
this.sender = this.chatMessage.sender;
this.dateSent = new Date(this.chatMessage.dateSent).toLocaleString();
this.body.value = this.chatMessage.body;
this.status.value = this.chatMessage.status;
};
// load
loadData = (): void => {
this.channel = this.chatMessage.channel;
this.sender = this.chatMessage.sender;
this.dateSent = new Date(this.chatMessage.dateSent).toLocaleString();
this.body.value = this.chatMessage.body;
this.status.value = this.chatMessage.status;
};
// init
constructor(
public coreViewModel: CoreViewModel,
messagePageViewModel: MessagePageViewModel,
chatMessage: ChatMessage,
sentByUser: boolean
) {
this.messagePageViewModel = messagePageViewModel;
// init
constructor(
public coreViewModel: CoreViewModel,
messagePageViewModel: MessagePageViewModel,
chatMessage: ChatMessage,
sentByUser: boolean,
) {
this.messagePageViewModel = messagePageViewModel;
this.chatMessage = chatMessage;
this.sentByUser = sentByUser;
this.loadData();
}
this.chatMessage = chatMessage;
this.sentByUser = sentByUser;
this.loadData();
}
}
+133 -133
View File
@@ -1,12 +1,12 @@
import * as React from "bloatless-react";
import CalendarPageViewModel, {
CALENDAR_EVENT_BOARD_ID,
CALENDAR_EVENT_BOARD_ID,
} from "../Pages/calendarPageViewModel";
import ChatModel, { ChatMessage } from "../../Model/Chat/chatModel";
import StorageModel, {
StorageModelSubPath,
filePaths,
StorageModelSubPath,
filePaths,
} from "../../Model/Global/storageModel";
import ChatListViewModel from "./chatListViewModel";
@@ -20,145 +20,145 @@ import TaskPageViewModel from "../Pages/taskPageViewModel";
import { translations } from "../../View/translations";
export default class ChatViewModel {
chatModel: ChatModel;
storageModel: StorageModel;
settingsViewModel: SettingsViewModel;
chatListViewModel: ChatListViewModel;
chatModel: ChatModel;
storageModel: StorageModel;
settingsViewModel: SettingsViewModel;
chatListViewModel: ChatListViewModel;
calendarViewModel: CalendarPageViewModel;
taskPageViewModel: TaskPageViewModel;
messagePageViewModel: MessagePageViewModel;
settingsPageViewModel: SettingsPageViewModel;
calendarViewModel: CalendarPageViewModel;
taskPageViewModel: TaskPageViewModel;
messagePageViewModel: MessagePageViewModel;
settingsPageViewModel: SettingsPageViewModel;
// state
displayedColor: React.State<Color> = new React.State<any>(Color.Standard);
selectedPage: React.State<ChatPageType> = new React.State<any>(
ChatPageType.Messages
);
index: React.State<number> = new React.State(0);
hasUnreadMessages: React.State<boolean> = new React.State(false);
taskBoardSuggestions: React.MapState<Entry> = new React.MapState();
// view
open = (): void => {
this.chatListViewModel.openChat(this);
this.markRead();
};
close = (): void => {
this.chatListViewModel.closeChat();
};
closeSubPages = (): void => {};
setColor = (color: Color): void => {
this.setDisplayedColor(color);
this.chatModel.setColor(color);
};
setDisplayedColor = (color: Color): void => {
this.displayedColor.value = color;
};
resetColor = (): void => {
this.displayedColor.value = this.settingsPageViewModel.color.value;
};
updateIndex = (): void => {
const index: number =
this.chatListViewModel.chatIndexManager.getIndex(this);
this.index.value = index;
};
markRead = (): void => {
this.hasUnreadMessages.value = false;
this.chatModel.markRead();
};
// load
loadPageSelection = (): void => {
const path: string[] = StorageModel.getPath(
StorageModelSubPath.Chat,
filePaths.chat.lastUsedPage(this.chatModel.id)
);
const lastUsedPage: string | null = this.storageModel.read(path);
if (lastUsedPage != null) {
this.selectedPage.value = lastUsedPage as any;
}
this.selectedPage.subscribeSilent((newPage) => {
this.storageModel.write(path, newPage);
this.resetColor();
});
};
loadInfo = (): void => {
this.hasUnreadMessages.value = this.chatModel.info.hasUnreadMessages;
this.taskBoardSuggestions.set(CALENDAR_EVENT_BOARD_ID, [
CALENDAR_EVENT_BOARD_ID,
translations.chatPage.calendar.eventsBoard,
]);
};
// init
constructor(
public coreViewModel: CoreViewModel,
storageModel: StorageModel,
chatModel: ChatModel,
settingsViewModel: SettingsViewModel,
chatListViewModel: ChatListViewModel
) {
// models
this.storageModel = storageModel;
this.chatModel = chatModel;
this.settingsViewModel = settingsViewModel;
this.chatListViewModel = chatListViewModel;
// page viewModels
this.calendarViewModel = new CalendarPageViewModel(
coreViewModel,
this,
this.storageModel,
this.chatModel.fileModel.boardsAndTasksModel.calendarModel,
this.chatModel.fileModel.boardsAndTasksModel
);
this.taskPageViewModel = new TaskPageViewModel(
this.coreViewModel,
this,
this.storageModel,
this.chatModel.fileModel.boardsAndTasksModel
);
this.messagePageViewModel = new MessagePageViewModel(
this.coreViewModel,
this
);
this.settingsPageViewModel = new SettingsPageViewModel(
this.coreViewModel,
this
// state
displayedColor: React.State<Color> = new React.State<any>(Color.Standard);
selectedPage: React.State<ChatPageType> = new React.State<any>(
ChatPageType.Messages,
);
// handlers
chatModel.chatMessageHandlerManager.addHandler(
(chatMessage: ChatMessage) => {
this.messagePageViewModel.showChatMessage(chatMessage);
index: React.State<number> = new React.State(0);
hasUnreadMessages: React.State<boolean> = new React.State(false);
taskBoardSuggestions: React.MapState<Entry> = new React.MapState();
// view
open = (): void => {
this.chatListViewModel.openChat(this);
this.markRead();
}
);
};
close = (): void => {
this.chatListViewModel.closeChat();
};
closeSubPages = (): void => {};
setColor = (color: Color): void => {
this.setDisplayedColor(color);
this.chatModel.setColor(color);
};
setDisplayedColor = (color: Color): void => {
this.displayedColor.value = color;
};
resetColor = (): void => {
this.displayedColor.value = this.settingsPageViewModel.color.value;
};
updateIndex = (): void => {
const index: number =
this.chatListViewModel.chatIndexManager.getIndex(this);
this.index.value = index;
};
markRead = (): void => {
this.hasUnreadMessages.value = false;
this.chatModel.markRead();
};
// load
this.loadPageSelection();
this.resetColor();
this.loadInfo();
}
loadPageSelection = (): void => {
const path: string[] = StorageModel.getPath(
StorageModelSubPath.Chat,
filePaths.chat.lastUsedPage(this.chatModel.id),
);
const lastUsedPage: string | null = this.storageModel.read(path);
if (lastUsedPage != null) {
this.selectedPage.value = lastUsedPage as any;
}
this.selectedPage.subscribeSilent((newPage) => {
this.storageModel.write(path, newPage);
this.resetColor();
});
};
loadInfo = (): void => {
this.hasUnreadMessages.value = this.chatModel.info.hasUnreadMessages;
this.taskBoardSuggestions.set(CALENDAR_EVENT_BOARD_ID, [
CALENDAR_EVENT_BOARD_ID,
translations.chatPage.calendar.eventsBoard,
]);
};
// init
constructor(
public coreViewModel: CoreViewModel,
storageModel: StorageModel,
chatModel: ChatModel,
settingsViewModel: SettingsViewModel,
chatListViewModel: ChatListViewModel,
) {
// models
this.storageModel = storageModel;
this.chatModel = chatModel;
this.settingsViewModel = settingsViewModel;
this.chatListViewModel = chatListViewModel;
// page viewModels
this.calendarViewModel = new CalendarPageViewModel(
coreViewModel,
this,
this.storageModel,
this.chatModel.fileModel.boardsAndTasksModel.calendarModel,
this.chatModel.fileModel.boardsAndTasksModel,
);
this.taskPageViewModel = new TaskPageViewModel(
this.coreViewModel,
this,
this.storageModel,
this.chatModel.fileModel.boardsAndTasksModel,
);
this.messagePageViewModel = new MessagePageViewModel(
this.coreViewModel,
this,
);
this.settingsPageViewModel = new SettingsPageViewModel(
this.coreViewModel,
this,
);
// handlers
chatModel.chatMessageHandlerManager.addHandler(
(chatMessage: ChatMessage) => {
this.messagePageViewModel.showChatMessage(chatMessage);
this.markRead();
},
);
// load
this.loadPageSelection();
this.resetColor();
this.loadInfo();
}
}
// types
export enum ChatPageType {
Settings = "settings",
Messages = "messages",
Tasks = "tasks",
Calendar = "calendar",
Settings = "settings",
Messages = "messages",
Tasks = "tasks",
Calendar = "calendar",
}