implement auto reconnect
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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",
|
||||
}
|
||||
|
||||
@@ -4,89 +4,90 @@ import ConnectionModel from "../../Model/Global/connectionModel";
|
||||
import CoreViewModel from "./coreViewModel";
|
||||
|
||||
export default class ConnectionViewModel {
|
||||
connectionModel: ConnectionModel;
|
||||
connectionModel: ConnectionModel;
|
||||
|
||||
// state
|
||||
serverAddressInput: React.State<string> = new React.State("");
|
||||
isConnected: React.State<boolean> = new React.State(false);
|
||||
// state
|
||||
serverAddressInput: React.State<string> = new React.State("");
|
||||
isConnected: React.State<boolean> = new React.State(false);
|
||||
|
||||
isShowingConnectionModal: React.State<boolean> = new React.State(false);
|
||||
isShowingConnectionModal: React.State<boolean> = new React.State(false);
|
||||
|
||||
previousAddresses: React.ListState<string> = new React.ListState();
|
||||
previousAddresses: React.ListState<string> = new React.ListState();
|
||||
|
||||
// guards
|
||||
cannotConnect: React.State<boolean> = React.createProxyState(
|
||||
[this.serverAddressInput, this.isConnected],
|
||||
() =>
|
||||
(this.isConnected.value == true &&
|
||||
this.serverAddressInput.value == this.connectionModel.address) ||
|
||||
this.serverAddressInput.value == ""
|
||||
);
|
||||
cannotDisonnect: React.State<boolean> = React.createProxyState(
|
||||
[this.isConnected],
|
||||
() => this.isConnected.value == false
|
||||
);
|
||||
hasNoPreviousConnections: React.State<boolean> = React.createProxyState(
|
||||
[this.previousAddresses],
|
||||
() => this.previousAddresses.value.size == 0
|
||||
);
|
||||
|
||||
// handlers
|
||||
connectionChangeHandler = (): void => {
|
||||
this.isConnected.value = this.connectionModel.isConnected;
|
||||
|
||||
if (this.connectionModel.isConnected == false) return;
|
||||
if (this.connectionModel.address == undefined) return;
|
||||
|
||||
this.serverAddressInput.value = this.connectionModel.address;
|
||||
|
||||
if (!this.previousAddresses.value.has(this.connectionModel.address)) {
|
||||
this.previousAddresses.add(this.connectionModel.address);
|
||||
}
|
||||
};
|
||||
|
||||
// methods
|
||||
connect = (): void => {
|
||||
this.connectToAddress(this.serverAddressInput.value);
|
||||
};
|
||||
|
||||
connectToAddress = (address: string): void => {
|
||||
this.connectionModel.connect(address);
|
||||
};
|
||||
|
||||
disconnect = (): void => {
|
||||
this.connectionModel.disconnect();
|
||||
};
|
||||
|
||||
removePreviousAddress = (address: string): void => {
|
||||
this.connectionModel.removeAddress(address);
|
||||
this.updatePreviousAddresses();
|
||||
};
|
||||
|
||||
// view
|
||||
showConnectionModal = (): void => {
|
||||
this.isShowingConnectionModal.value = true;
|
||||
};
|
||||
|
||||
hideConnectionModal = (): void => {
|
||||
this.isShowingConnectionModal.value = false;
|
||||
};
|
||||
|
||||
updatePreviousAddresses = (): void => {
|
||||
this.previousAddresses.clear();
|
||||
this.previousAddresses.add(...this.connectionModel.addresses);
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
connectionModel: ConnectionModel
|
||||
) {
|
||||
this.connectionModel = connectionModel;
|
||||
this.updatePreviousAddresses();
|
||||
|
||||
connectionModel.connectionChangeHandlerManager.addHandler(
|
||||
this.connectionChangeHandler
|
||||
// guards
|
||||
cannotConnect: React.State<boolean> = React.createProxyState(
|
||||
[this.serverAddressInput, this.isConnected],
|
||||
() =>
|
||||
(this.isConnected.value == true &&
|
||||
this.serverAddressInput.value ==
|
||||
this.connectionModel.address) ||
|
||||
this.serverAddressInput.value == "",
|
||||
);
|
||||
}
|
||||
cannotDisonnect: React.State<boolean> = React.createProxyState(
|
||||
[this.isConnected],
|
||||
() => this.isConnected.value == false,
|
||||
);
|
||||
hasNoPreviousConnections: React.State<boolean> = React.createProxyState(
|
||||
[this.previousAddresses],
|
||||
() => this.previousAddresses.value.size == 0,
|
||||
);
|
||||
|
||||
// handlers
|
||||
connectionChangeHandler = (): void => {
|
||||
this.isConnected.value = this.connectionModel.isConnected;
|
||||
|
||||
if (this.connectionModel.isConnected == false) return;
|
||||
if (this.connectionModel.address == undefined) return;
|
||||
|
||||
this.serverAddressInput.value = this.connectionModel.address;
|
||||
|
||||
if (!this.previousAddresses.value.has(this.connectionModel.address)) {
|
||||
this.previousAddresses.add(this.connectionModel.address);
|
||||
}
|
||||
};
|
||||
|
||||
// methods
|
||||
connect = (): void => {
|
||||
this.connectToAddress(this.serverAddressInput.value);
|
||||
};
|
||||
|
||||
connectToAddress = (address: string): void => {
|
||||
this.connectionModel.connect(address);
|
||||
};
|
||||
|
||||
disconnect = (): void => {
|
||||
this.connectionModel.disconnect();
|
||||
};
|
||||
|
||||
removePreviousAddress = (address: string): void => {
|
||||
this.connectionModel.removeAddress(address);
|
||||
this.updatePreviousAddresses();
|
||||
};
|
||||
|
||||
// view
|
||||
showConnectionModal = (): void => {
|
||||
this.isShowingConnectionModal.value = true;
|
||||
};
|
||||
|
||||
hideConnectionModal = (): void => {
|
||||
this.isShowingConnectionModal.value = false;
|
||||
};
|
||||
|
||||
updatePreviousAddresses = (): void => {
|
||||
this.previousAddresses.clear();
|
||||
this.previousAddresses.add(...this.connectionModel.addresses);
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
connectionModel: ConnectionModel,
|
||||
) {
|
||||
this.connectionModel = connectionModel;
|
||||
this.updatePreviousAddresses();
|
||||
|
||||
connectionModel.connectionChangeHandlerManager.addHandler(
|
||||
this.connectionChangeHandler,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import * as React from "bloatless-react";
|
||||
|
||||
export default class CoreViewModel {
|
||||
// DRAG & DROP
|
||||
draggedObject: React.State<any> = new React.State<any>(undefined);
|
||||
// DRAG & DROP
|
||||
draggedObject: React.State<any> = new React.State<any>(undefined);
|
||||
|
||||
// SUGGESTIONS
|
||||
// boards & tasks
|
||||
boardSearchSuggestions: React.ListState<string> = new React.ListState();
|
||||
|
||||
taskCategorySuggestions: React.ListState<string> = new React.ListState();
|
||||
taskStatusSuggestions: React.ListState<string> = new React.ListState();
|
||||
// SUGGESTIONS
|
||||
// boards & tasks
|
||||
boardSearchSuggestions: React.ListState<string> = new React.ListState();
|
||||
|
||||
taskCategorySuggestions: React.ListState<string> = new React.ListState();
|
||||
taskStatusSuggestions: React.ListState<string> = new React.ListState();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as React from "bloatless-react";
|
||||
|
||||
import FileTransferModel, {
|
||||
TransferData,
|
||||
TransferData,
|
||||
} from "../../Model/Global/fileTransferModel";
|
||||
import StorageModel, {
|
||||
StorageModelSubPath,
|
||||
filePaths,
|
||||
StorageModelSubPath,
|
||||
filePaths,
|
||||
} from "../../Model/Global/storageModel";
|
||||
|
||||
import ChatListModel from "../../Model/Chat/chatListModel";
|
||||
@@ -13,180 +13,186 @@ import ChatModel from "../../Model/Chat/chatModel";
|
||||
import { translations } from "../../View/translations";
|
||||
|
||||
export default class FileTransferViewModel {
|
||||
fileTransferModel: FileTransferModel;
|
||||
chatListModel: ChatListModel;
|
||||
fileTransferModel: FileTransferModel;
|
||||
chatListModel: ChatListModel;
|
||||
|
||||
// state
|
||||
presentedModal: React.State<FileTransferModal | undefined> =
|
||||
new React.State<any>(undefined);
|
||||
// state
|
||||
presentedModal: React.State<FileTransferModal | undefined> =
|
||||
new React.State<any>(undefined);
|
||||
|
||||
generalFileOptions: React.ListState<FileTransferOption> =
|
||||
new React.ListState();
|
||||
chatFileOptions: React.ListState<FileTransferOption> = new React.ListState();
|
||||
selectedPaths: React.ListState<string[]> = new React.ListState();
|
||||
generalFileOptions: React.ListState<FileTransferOption> =
|
||||
new React.ListState();
|
||||
chatFileOptions: React.ListState<FileTransferOption> =
|
||||
new React.ListState();
|
||||
selectedPaths: React.ListState<string[]> = new React.ListState();
|
||||
|
||||
transferChannel: React.State<string> = new React.State("");
|
||||
transferKey: React.State<string> = new React.State("");
|
||||
transferChannel: React.State<string> = new React.State("");
|
||||
transferKey: React.State<string> = new React.State("");
|
||||
|
||||
receivingTransferChannel: React.State<string> = new React.State("");
|
||||
receivingTransferKey: React.State<string> = new React.State("");
|
||||
receivingTransferChannel: React.State<string> = new React.State("");
|
||||
receivingTransferKey: React.State<string> = new React.State("");
|
||||
|
||||
filePathsSent: React.ListState<string> = new React.ListState();
|
||||
filesSentCount: React.State<number> = React.createProxyState(
|
||||
[this.filePathsSent],
|
||||
() => this.filePathsSent.value.size
|
||||
);
|
||||
filesSentText: React.State<string> = React.createProxyState(
|
||||
[this.filesSentCount],
|
||||
() =>
|
||||
translations.dataTransferModal.filesSentCount(this.filesSentCount.value)
|
||||
);
|
||||
|
||||
filePathsReceived: React.ListState<string> = new React.ListState();
|
||||
filesReceivedCount: React.State<number> = React.createProxyState(
|
||||
[this.filePathsReceived],
|
||||
() => this.filePathsReceived.value.size
|
||||
);
|
||||
filesReceivedText: React.State<string> = React.createProxyState(
|
||||
[this.filesReceivedCount],
|
||||
() =>
|
||||
translations.dataTransferModal.filesReceivedCount(
|
||||
this.filesReceivedCount.value
|
||||
)
|
||||
);
|
||||
|
||||
// guards
|
||||
hasNoPathsSelected: React.State<boolean> = React.createProxyState(
|
||||
[this.selectedPaths],
|
||||
() => this.selectedPaths.value.size == 0
|
||||
);
|
||||
didNotFinishSending: React.State<boolean> = new React.State(true);
|
||||
cannotPrepareToReceive: React.State<boolean> = React.createProxyState(
|
||||
[this.receivingTransferChannel, this.receivingTransferKey],
|
||||
() =>
|
||||
this.receivingTransferChannel.value == "" ||
|
||||
this.receivingTransferKey.value == ""
|
||||
);
|
||||
|
||||
// handlers
|
||||
handleReceivedFile = (path: string): void => {
|
||||
this.filePathsReceived.add(path);
|
||||
};
|
||||
|
||||
// methods
|
||||
getOptions = (): void => {
|
||||
this.generalFileOptions.clear();
|
||||
this.chatFileOptions.clear();
|
||||
this.selectedPaths.clear();
|
||||
|
||||
this.generalFileOptions.add(
|
||||
{
|
||||
label: translations.dataTransferModal.connectionData,
|
||||
path: StorageModel.getPath(
|
||||
StorageModelSubPath.ConnectionModel,
|
||||
filePaths.connectionModel.previousAddresses
|
||||
),
|
||||
},
|
||||
{
|
||||
label: translations.dataTransferModal.settingsData,
|
||||
path: StorageModel.getPath(StorageModelSubPath.SettingsModel, []),
|
||||
}
|
||||
filePathsSent: React.ListState<string> = new React.ListState();
|
||||
filesSentCount: React.State<number> = React.createProxyState(
|
||||
[this.filePathsSent],
|
||||
() => this.filePathsSent.value.size,
|
||||
);
|
||||
filesSentText: React.State<string> = React.createProxyState(
|
||||
[this.filesSentCount],
|
||||
() =>
|
||||
translations.dataTransferModal.filesSentCount(
|
||||
this.filesSentCount.value,
|
||||
),
|
||||
);
|
||||
|
||||
const chatModels: Set<ChatModel> = this.chatListModel.chatModels;
|
||||
for (const chatModel of chatModels) {
|
||||
this.chatFileOptions.add({
|
||||
label: chatModel.info.primaryChannel,
|
||||
path: chatModel.getBasePath(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
getTransferData = (): void => {
|
||||
const transferData: TransferData =
|
||||
this.fileTransferModel.generateTransferData();
|
||||
this.transferChannel.value = transferData.channel;
|
||||
this.transferKey.value = transferData.key;
|
||||
};
|
||||
|
||||
// view
|
||||
showDirectionSelectionModal = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.DirectionSelection;
|
||||
this.getOptions();
|
||||
};
|
||||
|
||||
showFileSelectionModal = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.FileSelection;
|
||||
};
|
||||
|
||||
showTransferDataModal = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.TransferDataDisplay;
|
||||
this.getTransferData();
|
||||
};
|
||||
|
||||
initiateTransfer = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.TransferDisplay;
|
||||
this.didNotFinishSending.value = true;
|
||||
this.filePathsSent.clear();
|
||||
|
||||
this.fileTransferModel.sendFiles(
|
||||
this.selectedPaths.value.values(),
|
||||
(path: string) => {
|
||||
console.log(path);
|
||||
this.filePathsSent.add(path);
|
||||
}
|
||||
filePathsReceived: React.ListState<string> = new React.ListState();
|
||||
filesReceivedCount: React.State<number> = React.createProxyState(
|
||||
[this.filePathsReceived],
|
||||
() => this.filePathsReceived.value.size,
|
||||
);
|
||||
filesReceivedText: React.State<string> = React.createProxyState(
|
||||
[this.filesReceivedCount],
|
||||
() =>
|
||||
translations.dataTransferModal.filesReceivedCount(
|
||||
this.filesReceivedCount.value,
|
||||
),
|
||||
);
|
||||
|
||||
this.didNotFinishSending.value = false;
|
||||
};
|
||||
// guards
|
||||
hasNoPathsSelected: React.State<boolean> = React.createProxyState(
|
||||
[this.selectedPaths],
|
||||
() => this.selectedPaths.value.size == 0,
|
||||
);
|
||||
didNotFinishSending: React.State<boolean> = new React.State(true);
|
||||
cannotPrepareToReceive: React.State<boolean> = React.createProxyState(
|
||||
[this.receivingTransferChannel, this.receivingTransferKey],
|
||||
() =>
|
||||
this.receivingTransferChannel.value == "" ||
|
||||
this.receivingTransferKey.value == "",
|
||||
);
|
||||
|
||||
showTransferDataInputModal = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.TransferDataInput;
|
||||
};
|
||||
|
||||
prepareReceivingData = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.ReceptionDisplay;
|
||||
this.filePathsReceived.clear();
|
||||
|
||||
const transferData: TransferData = {
|
||||
channel: this.receivingTransferChannel.value,
|
||||
key: this.receivingTransferKey.value,
|
||||
// handlers
|
||||
handleReceivedFile = (path: string): void => {
|
||||
this.filePathsReceived.add(path);
|
||||
};
|
||||
this.fileTransferModel.prepareToReceive(transferData);
|
||||
};
|
||||
|
||||
hideModal = (): void => {
|
||||
this.presentedModal.value = undefined;
|
||||
};
|
||||
// methods
|
||||
getOptions = (): void => {
|
||||
this.generalFileOptions.clear();
|
||||
this.chatFileOptions.clear();
|
||||
this.selectedPaths.clear();
|
||||
|
||||
// init
|
||||
constructor(
|
||||
fileTransferModel: FileTransferModel,
|
||||
chatListModel: ChatListModel
|
||||
) {
|
||||
this.fileTransferModel = fileTransferModel;
|
||||
this.chatListModel = chatListModel;
|
||||
this.generalFileOptions.add(
|
||||
{
|
||||
label: translations.dataTransferModal.connectionData,
|
||||
path: StorageModel.getPath(
|
||||
StorageModelSubPath.ConnectionModel,
|
||||
filePaths.connectionModel.previousAddresses,
|
||||
),
|
||||
},
|
||||
{
|
||||
label: translations.dataTransferModal.settingsData,
|
||||
path: StorageModel.getPath(
|
||||
StorageModelSubPath.SettingsModel,
|
||||
[],
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
this.fileTransferModel.fileHandlerManager.addHandler(
|
||||
this.handleReceivedFile
|
||||
);
|
||||
}
|
||||
const chatModels: Set<ChatModel> = this.chatListModel.chatModels;
|
||||
for (const chatModel of chatModels) {
|
||||
this.chatFileOptions.add({
|
||||
label: chatModel.info.primaryChannel,
|
||||
path: chatModel.getBasePath(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
getTransferData = (): void => {
|
||||
const transferData: TransferData =
|
||||
this.fileTransferModel.generateTransferData();
|
||||
this.transferChannel.value = transferData.channel;
|
||||
this.transferKey.value = transferData.key;
|
||||
};
|
||||
|
||||
// view
|
||||
showDirectionSelectionModal = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.DirectionSelection;
|
||||
this.getOptions();
|
||||
};
|
||||
|
||||
showFileSelectionModal = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.FileSelection;
|
||||
};
|
||||
|
||||
showTransferDataModal = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.TransferDataDisplay;
|
||||
this.getTransferData();
|
||||
};
|
||||
|
||||
initiateTransfer = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.TransferDisplay;
|
||||
this.didNotFinishSending.value = true;
|
||||
this.filePathsSent.clear();
|
||||
|
||||
this.fileTransferModel.sendFiles(
|
||||
this.selectedPaths.value.values(),
|
||||
(path: string) => {
|
||||
console.log(path);
|
||||
this.filePathsSent.add(path);
|
||||
},
|
||||
);
|
||||
|
||||
this.didNotFinishSending.value = false;
|
||||
};
|
||||
|
||||
showTransferDataInputModal = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.TransferDataInput;
|
||||
};
|
||||
|
||||
prepareReceivingData = (): void => {
|
||||
this.presentedModal.value = FileTransferModal.ReceptionDisplay;
|
||||
this.filePathsReceived.clear();
|
||||
|
||||
const transferData: TransferData = {
|
||||
channel: this.receivingTransferChannel.value,
|
||||
key: this.receivingTransferKey.value,
|
||||
};
|
||||
this.fileTransferModel.prepareToReceive(transferData);
|
||||
};
|
||||
|
||||
hideModal = (): void => {
|
||||
this.presentedModal.value = undefined;
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
fileTransferModel: FileTransferModel,
|
||||
chatListModel: ChatListModel,
|
||||
) {
|
||||
this.fileTransferModel = fileTransferModel;
|
||||
this.chatListModel = chatListModel;
|
||||
|
||||
this.fileTransferModel.fileHandlerManager.addHandler(
|
||||
this.handleReceivedFile,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export interface FileTransferOption {
|
||||
label: string;
|
||||
path: string[];
|
||||
label: string;
|
||||
path: string[];
|
||||
}
|
||||
|
||||
export enum FileTransferModal {
|
||||
DirectionSelection,
|
||||
DirectionSelection,
|
||||
|
||||
// sending
|
||||
FileSelection,
|
||||
TransferDataDisplay,
|
||||
TransferDisplay,
|
||||
// sending
|
||||
FileSelection,
|
||||
TransferDataDisplay,
|
||||
TransferDisplay,
|
||||
|
||||
// receiving
|
||||
TransferDataInput,
|
||||
ReceptionDisplay,
|
||||
// receiving
|
||||
TransferDataInput,
|
||||
ReceptionDisplay,
|
||||
}
|
||||
|
||||
@@ -4,44 +4,44 @@ import CoreViewModel from "./coreViewModel";
|
||||
import SettingsModel from "../../Model/Global/settingsModel";
|
||||
|
||||
export default class SettingsViewModel {
|
||||
settingsModel: SettingsModel;
|
||||
settingsModel: SettingsModel;
|
||||
|
||||
// state
|
||||
username: React.State<string> = new React.State("");
|
||||
usernameInput: React.State<string> = new React.State("");
|
||||
firstDayOfWeekInput: React.State<string> = new React.State("0");
|
||||
// state
|
||||
username: React.State<string> = new React.State("");
|
||||
usernameInput: React.State<string> = new React.State("");
|
||||
firstDayOfWeekInput: React.State<string> = new React.State("0");
|
||||
|
||||
// guards
|
||||
cannotSetName: React.State<boolean> = React.createProxyState(
|
||||
[this.usernameInput],
|
||||
() =>
|
||||
this.usernameInput.value == "" ||
|
||||
this.usernameInput.value == this.settingsModel.username
|
||||
);
|
||||
// guards
|
||||
cannotSetName: React.State<boolean> = React.createProxyState(
|
||||
[this.usernameInput],
|
||||
() =>
|
||||
this.usernameInput.value == "" ||
|
||||
this.usernameInput.value == this.settingsModel.username,
|
||||
);
|
||||
|
||||
// methods
|
||||
setName = (): void => {
|
||||
this.settingsModel.setName(this.usernameInput.value);
|
||||
this.username.value = this.settingsModel.username;
|
||||
this.usernameInput.callSubscriptions();
|
||||
};
|
||||
// methods
|
||||
setName = (): void => {
|
||||
this.settingsModel.setName(this.usernameInput.value);
|
||||
this.username.value = this.settingsModel.username;
|
||||
this.usernameInput.callSubscriptions();
|
||||
};
|
||||
|
||||
setFirstDayofWeek = (): void => {
|
||||
this.settingsModel.setFirstDayOfWeek(this.firstDayOfWeekInput.value);
|
||||
};
|
||||
setFirstDayofWeek = (): void => {
|
||||
this.settingsModel.setFirstDayOfWeek(this.firstDayOfWeekInput.value);
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
settingsModel: SettingsModel
|
||||
) {
|
||||
this.settingsModel = settingsModel;
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
settingsModel: SettingsModel,
|
||||
) {
|
||||
this.settingsModel = settingsModel;
|
||||
|
||||
this.username.value = settingsModel.username;
|
||||
this.usernameInput.value = settingsModel.username;
|
||||
this.firstDayOfWeekInput.value = settingsModel.firstDayOfWeek;
|
||||
this.username.value = settingsModel.username;
|
||||
this.usernameInput.value = settingsModel.username;
|
||||
this.firstDayOfWeekInput.value = settingsModel.firstDayOfWeek;
|
||||
|
||||
// subscriptions
|
||||
this.firstDayOfWeekInput.subscribe(this.setFirstDayofWeek);
|
||||
}
|
||||
// subscriptions
|
||||
this.firstDayOfWeekInput.subscribe(this.setFirstDayofWeek);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +1,81 @@
|
||||
import * as React from "bloatless-react";
|
||||
|
||||
import StorageModel, {
|
||||
PATH_COMPONENT_SEPARATOR,
|
||||
PATH_COMPONENT_SEPARATOR,
|
||||
} from "../../Model/Global/storageModel";
|
||||
|
||||
import CoreViewModel from "./coreViewModel";
|
||||
import { translations } from "../../View/translations";
|
||||
|
||||
export default class StorageViewModel {
|
||||
storageModel: StorageModel;
|
||||
storageModel: StorageModel;
|
||||
|
||||
// state
|
||||
isShowingStorageModal: React.State<boolean> = new React.State(false);
|
||||
selectedPath: React.State<string> = new React.State(PATH_COMPONENT_SEPARATOR);
|
||||
didMakeChanges: React.State<boolean> = new React.State(false);
|
||||
|
||||
selectedFileName: React.State<string>;
|
||||
selectedFileContent: React.State<string>;
|
||||
|
||||
lastDeletedItemPath: React.State<string> = new React.State("");
|
||||
|
||||
// methods
|
||||
getSelectedItemContent = (): string => {
|
||||
const path = StorageModel.stringToPathComponents(this.selectedPath.value);
|
||||
const content = this.storageModel.read(path);
|
||||
return (
|
||||
(content ?? translations.storage.notAFile) ||
|
||||
translations.storage.contentEmpty
|
||||
// state
|
||||
isShowingStorageModal: React.State<boolean> = new React.State(false);
|
||||
selectedPath: React.State<string> = new React.State(
|
||||
PATH_COMPONENT_SEPARATOR,
|
||||
);
|
||||
};
|
||||
didMakeChanges: React.State<boolean> = new React.State(false);
|
||||
|
||||
deleteSelectedItem = (): void => {
|
||||
const path = StorageModel.stringToPathComponents(this.selectedPath.value);
|
||||
this.lastDeletedItemPath.value = this.selectedPath.value;
|
||||
selectedFileName: React.State<string>;
|
||||
selectedFileContent: React.State<string>;
|
||||
|
||||
this.storageModel.removeRecursively(path);
|
||||
this.didMakeChanges.value = true;
|
||||
};
|
||||
lastDeletedItemPath: React.State<string> = new React.State("");
|
||||
|
||||
removeJunk = (): void => {
|
||||
this.storageModel.removeJunk();
|
||||
this.selectedPath.value = PATH_COMPONENT_SEPARATOR;
|
||||
};
|
||||
// methods
|
||||
getSelectedItemContent = (): string => {
|
||||
const path = StorageModel.stringToPathComponents(
|
||||
this.selectedPath.value,
|
||||
);
|
||||
const content = this.storageModel.read(path);
|
||||
return (
|
||||
(content ?? translations.storage.notAFile) ||
|
||||
translations.storage.contentEmpty
|
||||
);
|
||||
};
|
||||
|
||||
// view
|
||||
showStorageModal = (): void => {
|
||||
this.isShowingStorageModal.value = true;
|
||||
};
|
||||
deleteSelectedItem = (): void => {
|
||||
const path = StorageModel.stringToPathComponents(
|
||||
this.selectedPath.value,
|
||||
);
|
||||
this.lastDeletedItemPath.value = this.selectedPath.value;
|
||||
|
||||
hideStorageModal = (): void => {
|
||||
if (this.didMakeChanges.value == true) {
|
||||
window.location.reload();
|
||||
return;
|
||||
this.storageModel.removeRecursively(path);
|
||||
this.didMakeChanges.value = true;
|
||||
};
|
||||
|
||||
removeJunk = (): void => {
|
||||
this.storageModel.removeJunk();
|
||||
this.selectedPath.value = PATH_COMPONENT_SEPARATOR;
|
||||
};
|
||||
|
||||
// view
|
||||
showStorageModal = (): void => {
|
||||
this.isShowingStorageModal.value = true;
|
||||
};
|
||||
|
||||
hideStorageModal = (): void => {
|
||||
if (this.didMakeChanges.value == true) {
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
this.isShowingStorageModal.value = false;
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
storageModel: StorageModel,
|
||||
) {
|
||||
this.storageModel = storageModel;
|
||||
|
||||
this.selectedFileName = React.createProxyState(
|
||||
[this.selectedPath],
|
||||
() => StorageModel.getFileNameFromString(this.selectedPath.value),
|
||||
);
|
||||
this.selectedFileContent = React.createProxyState(
|
||||
[this.selectedPath],
|
||||
() => this.getSelectedItemContent(),
|
||||
);
|
||||
}
|
||||
this.isShowingStorageModal.value = false;
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(public coreViewModel: CoreViewModel, storageModel: StorageModel) {
|
||||
this.storageModel = storageModel;
|
||||
|
||||
this.selectedFileName = React.createProxyState([this.selectedPath], () =>
|
||||
StorageModel.getFileNameFromString(this.selectedPath.value)
|
||||
);
|
||||
this.selectedFileContent = React.createProxyState([this.selectedPath], () =>
|
||||
this.getSelectedItemContent()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from "bloatless-react";
|
||||
|
||||
import BoardsAndTasksModel, {
|
||||
BoardInfoFileContent,
|
||||
TaskFileContent,
|
||||
BoardInfoFileContent,
|
||||
TaskFileContent,
|
||||
} from "../../Model/Files/boardsAndTasksModel";
|
||||
|
||||
import ChatViewModel from "../Chat/chatViewModel";
|
||||
@@ -15,293 +15,299 @@ import TaskPageViewModel from "./taskPageViewModel";
|
||||
import TaskViewModel from "./taskViewModel";
|
||||
|
||||
export default class BoardViewModel extends TaskContainingPageViewModel {
|
||||
storageModel: StorageModel;
|
||||
boardsAndTasksModel: BoardsAndTasksModel;
|
||||
storageModel: StorageModel;
|
||||
boardsAndTasksModel: BoardsAndTasksModel;
|
||||
|
||||
taskPageViewModel: TaskPageViewModel;
|
||||
taskPageViewModel: TaskPageViewModel;
|
||||
|
||||
// data
|
||||
boardInfo: BoardInfoFileContent;
|
||||
// data
|
||||
boardInfo: BoardInfoFileContent;
|
||||
|
||||
// state
|
||||
name: React.State<string> = new React.State("");
|
||||
color: React.State<Color> = new React.State<any>(Color.Standard);
|
||||
// state
|
||||
name: React.State<string> = new React.State("");
|
||||
color: React.State<Color> = new React.State<any>(Color.Standard);
|
||||
|
||||
index: React.State<number> = new React.State(0);
|
||||
index: React.State<number> = new React.State(0);
|
||||
|
||||
selectedPage: React.State<BoardPageType> = new React.State<any>(
|
||||
BoardPageType.List
|
||||
);
|
||||
|
||||
isSelected: React.State<boolean>;
|
||||
isPresentingSettingsModal: React.State<boolean> = new React.State(false);
|
||||
isPresentingFilterModal: React.State<boolean> = new React.State(false);
|
||||
|
||||
searchViewModel: SearchViewModel<TaskViewModel>;
|
||||
filteredTaskViewModels: React.ListState<TaskViewModel> =
|
||||
new React.ListState();
|
||||
|
||||
// paths
|
||||
getBasePath = (): string[] => {
|
||||
return [...this.taskPageViewModel.getBoardViewPath(this.boardInfo.fileId)];
|
||||
};
|
||||
|
||||
getLastUsedBoardPath = (): string[] => {
|
||||
return [...this.getBasePath(), BoardViewModelSubPath.LastUsedView];
|
||||
};
|
||||
|
||||
getPreviousSearchesPath = (): string[] => {
|
||||
return [...this.getBasePath(), BoardViewModelSubPath.PreviousSearches];
|
||||
};
|
||||
|
||||
getLastSearchPath = (): string[] => {
|
||||
return [...this.getBasePath(), BoardViewModelSubPath.LastSearch];
|
||||
};
|
||||
|
||||
// settings
|
||||
saveSettings = (): void => {
|
||||
const newBoardInfoFileContent: BoardInfoFileContent =
|
||||
BoardsAndTasksModel.createBoardInfoFileContent(
|
||||
this.boardInfo.fileId,
|
||||
this.name.value,
|
||||
this.color.value
|
||||
);
|
||||
this.taskPageViewModel.updateBoard(newBoardInfoFileContent);
|
||||
};
|
||||
|
||||
applyColor = (): void => {
|
||||
this.taskPageViewModel.chatViewModel.setDisplayedColor(this.color.value);
|
||||
};
|
||||
|
||||
deleteBoard = (): void => {
|
||||
this.taskPageViewModel.deleteBoard(this.boardInfo);
|
||||
this.chatViewModel.taskBoardSuggestions.remove(this.boardInfo.fileId);
|
||||
this.close();
|
||||
};
|
||||
|
||||
// methods
|
||||
createTask = (): void => {
|
||||
this.createTaskFromBoardId(this.boardInfo.fileId);
|
||||
};
|
||||
|
||||
handleDropWithinBoard = (category?: string, status?: string): void => {
|
||||
const draggedObject: any = this.coreViewModel.draggedObject.value;
|
||||
if (draggedObject instanceof TaskViewModel == false) return;
|
||||
draggedObject.setCategoryAndStatus(category, status);
|
||||
};
|
||||
|
||||
handleDropBetweenBoards = (): void => {
|
||||
const draggedObject: any = this.coreViewModel.draggedObject.value;
|
||||
if (draggedObject instanceof TaskViewModel == false) return;
|
||||
draggedObject.setBoardId(this.boardInfo.fileId);
|
||||
};
|
||||
|
||||
// storage
|
||||
storeLastUsedView = (): void => {
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedView: string = this.selectedPage.value;
|
||||
this.storageModel.write(path, lastUsedView);
|
||||
};
|
||||
|
||||
restoreLastUsedView = (): void => {
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedView: string | null = this.storageModel.read(path);
|
||||
if (lastUsedView == null) return;
|
||||
|
||||
this.selectedPage.value = lastUsedView as BoardPageType;
|
||||
};
|
||||
|
||||
handleNewSearch = (searchTerm: string): void => {
|
||||
const suggestionPath: string[] = [
|
||||
...this.getPreviousSearchesPath(),
|
||||
searchTerm,
|
||||
];
|
||||
this.storageModel.write(suggestionPath, "");
|
||||
if (!this.coreViewModel.boardSearchSuggestions.value.has(searchTerm)) {
|
||||
this.coreViewModel.boardSearchSuggestions.add(searchTerm);
|
||||
}
|
||||
|
||||
const lastSearchPath: string[] = this.getLastSearchPath();
|
||||
this.storageModel.write(lastSearchPath, searchTerm);
|
||||
};
|
||||
|
||||
// view
|
||||
showTask = (taskFileContent: TaskFileContent): void => {
|
||||
if (taskFileContent.boardId != this.boardInfo.fileId) {
|
||||
// remove task that was moved to different board
|
||||
this.boardsAndTasksModel.deleteTaskReference(
|
||||
this.boardInfo.fileId,
|
||||
taskFileContent.fileId
|
||||
);
|
||||
this.removeTaskFromView(taskFileContent);
|
||||
return;
|
||||
}
|
||||
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent
|
||||
selectedPage: React.State<BoardPageType> = new React.State<any>(
|
||||
BoardPageType.List,
|
||||
);
|
||||
this.taskViewModels.set(taskFileContent.fileId, taskViewModel);
|
||||
};
|
||||
|
||||
removeTaskFromView = (taskFileContent: TaskFileContent): void => {
|
||||
this.taskViewModels.remove(taskFileContent.fileId);
|
||||
this.updateIndex();
|
||||
};
|
||||
isSelected: React.State<boolean>;
|
||||
isPresentingSettingsModal: React.State<boolean> = new React.State(false);
|
||||
isPresentingFilterModal: React.State<boolean> = new React.State(false);
|
||||
|
||||
select = (): void => {
|
||||
this.taskPageViewModel.selectBoard(this);
|
||||
};
|
||||
searchViewModel: SearchViewModel<TaskViewModel>;
|
||||
filteredTaskViewModels: React.ListState<TaskViewModel> =
|
||||
new React.ListState();
|
||||
|
||||
close = (): void => {
|
||||
this.taskPageViewModel.closeBoard();
|
||||
this.taskViewModels.clear();
|
||||
};
|
||||
// paths
|
||||
getBasePath = (): string[] => {
|
||||
return [
|
||||
...this.taskPageViewModel.getBoardViewPath(this.boardInfo.fileId),
|
||||
];
|
||||
};
|
||||
|
||||
showSettings = (): void => {
|
||||
this.isPresentingSettingsModal.value = true;
|
||||
};
|
||||
getLastUsedBoardPath = (): string[] => {
|
||||
return [...this.getBasePath(), BoardViewModelSubPath.LastUsedView];
|
||||
};
|
||||
|
||||
hideSettings = (): void => {
|
||||
this.saveSettings();
|
||||
this.isPresentingSettingsModal.value = false;
|
||||
};
|
||||
getPreviousSearchesPath = (): string[] => {
|
||||
return [...this.getBasePath(), BoardViewModelSubPath.PreviousSearches];
|
||||
};
|
||||
|
||||
showFilterModal = (): void => {
|
||||
this.isPresentingFilterModal.value = true;
|
||||
};
|
||||
getLastSearchPath = (): string[] => {
|
||||
return [...this.getBasePath(), BoardViewModelSubPath.LastSearch];
|
||||
};
|
||||
|
||||
hideFilterModal = (): void => {
|
||||
this.isPresentingFilterModal.value = false;
|
||||
};
|
||||
// settings
|
||||
saveSettings = (): void => {
|
||||
const newBoardInfoFileContent: BoardInfoFileContent =
|
||||
BoardsAndTasksModel.createBoardInfoFileContent(
|
||||
this.boardInfo.fileId,
|
||||
this.name.value,
|
||||
this.color.value,
|
||||
);
|
||||
this.taskPageViewModel.updateBoard(newBoardInfoFileContent);
|
||||
};
|
||||
|
||||
updateIndex = (): void => {
|
||||
const index: number =
|
||||
this.taskPageViewModel.boardIndexManager.getIndex(this);
|
||||
this.index.value = index;
|
||||
};
|
||||
applyColor = (): void => {
|
||||
this.taskPageViewModel.chatViewModel.setDisplayedColor(
|
||||
this.color.value,
|
||||
);
|
||||
};
|
||||
|
||||
// load
|
||||
loadListRelevantData = (): void => {
|
||||
this.name.value = this.boardInfo.name;
|
||||
this.color.value = this.boardInfo.color;
|
||||
};
|
||||
deleteBoard = (): void => {
|
||||
this.taskPageViewModel.deleteBoard(this.boardInfo);
|
||||
this.chatViewModel.taskBoardSuggestions.remove(this.boardInfo.fileId);
|
||||
this.close();
|
||||
};
|
||||
|
||||
loadTasks = (): void => {
|
||||
const taskIds: string[] = this.boardsAndTasksModel.listTaskIds(
|
||||
this.boardInfo.fileId
|
||||
);
|
||||
for (const taskId of taskIds) {
|
||||
if (this.taskViewModels.value.has(taskId)) return;
|
||||
// methods
|
||||
createTask = (): void => {
|
||||
this.createTaskFromBoardId(this.boardInfo.fileId);
|
||||
};
|
||||
|
||||
const taskFileContent: TaskFileContent | null =
|
||||
this.boardsAndTasksModel.getLatestTaskFileContent(taskId);
|
||||
if (taskFileContent == null) continue;
|
||||
handleDropWithinBoard = (category?: string, status?: string): void => {
|
||||
const draggedObject: any = this.coreViewModel.draggedObject.value;
|
||||
if (draggedObject instanceof TaskViewModel == false) return;
|
||||
draggedObject.setCategoryAndStatus(category, status);
|
||||
};
|
||||
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent
|
||||
);
|
||||
this.taskViewModels.set(taskFileContent.fileId, taskViewModel);
|
||||
}
|
||||
handleDropBetweenBoards = (): void => {
|
||||
const draggedObject: any = this.coreViewModel.draggedObject.value;
|
||||
if (draggedObject instanceof TaskViewModel == false) return;
|
||||
draggedObject.setBoardId(this.boardInfo.fileId);
|
||||
};
|
||||
|
||||
this.updateTaskIndices();
|
||||
};
|
||||
// storage
|
||||
storeLastUsedView = (): void => {
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedView: string = this.selectedPage.value;
|
||||
this.storageModel.write(path, lastUsedView);
|
||||
};
|
||||
|
||||
loadSearchSuggestions = (): void => {
|
||||
const dirPath: string[] = this.getPreviousSearchesPath();
|
||||
const searches: string[] = this.storageModel.list(dirPath);
|
||||
this.coreViewModel.boardSearchSuggestions.add(...searches);
|
||||
};
|
||||
restoreLastUsedView = (): void => {
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedView: string | null = this.storageModel.read(path);
|
||||
if (lastUsedView == null) return;
|
||||
|
||||
restoreSearch = (): void => {
|
||||
const lastSearchPath: string[] = this.getLastSearchPath();
|
||||
const lastSearch: string | null = this.storageModel.read(lastSearchPath);
|
||||
if (lastSearch != null) {
|
||||
this.searchViewModel.search(lastSearch);
|
||||
}
|
||||
};
|
||||
this.selectedPage.value = lastUsedView as BoardPageType;
|
||||
};
|
||||
|
||||
loadData = (): void => {
|
||||
this.restoreLastUsedView();
|
||||
this.loadTasks();
|
||||
this.loadSearchSuggestions();
|
||||
};
|
||||
handleNewSearch = (searchTerm: string): void => {
|
||||
const suggestionPath: string[] = [
|
||||
...this.getPreviousSearchesPath(),
|
||||
searchTerm,
|
||||
];
|
||||
this.storageModel.write(suggestionPath, "");
|
||||
if (!this.coreViewModel.boardSearchSuggestions.value.has(searchTerm)) {
|
||||
this.coreViewModel.boardSearchSuggestions.add(searchTerm);
|
||||
}
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
public chatViewModel: ChatViewModel,
|
||||
storageModel: StorageModel,
|
||||
boardsAndTasksModel: BoardsAndTasksModel,
|
||||
taskPageViewModel: TaskPageViewModel,
|
||||
boardInfo: BoardInfoFileContent
|
||||
) {
|
||||
super(coreViewModel, chatViewModel, boardsAndTasksModel);
|
||||
const lastSearchPath: string[] = this.getLastSearchPath();
|
||||
this.storageModel.write(lastSearchPath, searchTerm);
|
||||
};
|
||||
|
||||
// set
|
||||
this.storageModel = storageModel;
|
||||
this.boardsAndTasksModel = boardsAndTasksModel;
|
||||
this.taskPageViewModel = taskPageViewModel;
|
||||
this.boardInfo = boardInfo;
|
||||
// view
|
||||
showTask = (taskFileContent: TaskFileContent): void => {
|
||||
if (taskFileContent.boardId != this.boardInfo.fileId) {
|
||||
// remove task that was moved to different board
|
||||
this.boardsAndTasksModel.deleteTaskReference(
|
||||
this.boardInfo.fileId,
|
||||
taskFileContent.fileId,
|
||||
);
|
||||
this.removeTaskFromView(taskFileContent);
|
||||
return;
|
||||
}
|
||||
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent,
|
||||
);
|
||||
this.taskViewModels.set(taskFileContent.fileId, taskViewModel);
|
||||
};
|
||||
|
||||
removeTaskFromView = (taskFileContent: TaskFileContent): void => {
|
||||
this.taskViewModels.remove(taskFileContent.fileId);
|
||||
this.updateIndex();
|
||||
};
|
||||
|
||||
select = (): void => {
|
||||
this.taskPageViewModel.selectBoard(this);
|
||||
};
|
||||
|
||||
close = (): void => {
|
||||
this.taskPageViewModel.closeBoard();
|
||||
this.taskViewModels.clear();
|
||||
};
|
||||
|
||||
showSettings = (): void => {
|
||||
this.isPresentingSettingsModal.value = true;
|
||||
};
|
||||
|
||||
hideSettings = (): void => {
|
||||
this.saveSettings();
|
||||
this.isPresentingSettingsModal.value = false;
|
||||
};
|
||||
|
||||
showFilterModal = (): void => {
|
||||
this.isPresentingFilterModal.value = true;
|
||||
};
|
||||
|
||||
hideFilterModal = (): void => {
|
||||
this.isPresentingFilterModal.value = false;
|
||||
};
|
||||
|
||||
updateIndex = (): void => {
|
||||
const index: number =
|
||||
this.taskPageViewModel.boardIndexManager.getIndex(this);
|
||||
this.index.value = index;
|
||||
};
|
||||
|
||||
// load
|
||||
this.loadListRelevantData();
|
||||
loadListRelevantData = (): void => {
|
||||
this.name.value = this.boardInfo.name;
|
||||
this.color.value = this.boardInfo.color;
|
||||
};
|
||||
|
||||
// subscriptions
|
||||
this.isSelected = React.createProxyState(
|
||||
[this.taskPageViewModel.selectedBoardId],
|
||||
() =>
|
||||
this.taskPageViewModel.selectedBoardId.value == this.boardInfo.fileId
|
||||
);
|
||||
loadTasks = (): void => {
|
||||
const taskIds: string[] = this.boardsAndTasksModel.listTaskIds(
|
||||
this.boardInfo.fileId,
|
||||
);
|
||||
for (const taskId of taskIds) {
|
||||
if (this.taskViewModels.value.has(taskId)) return;
|
||||
|
||||
this.color.subscribe(() => {
|
||||
if (this.isSelected.value == false) return;
|
||||
this.applyColor();
|
||||
});
|
||||
const taskFileContent: TaskFileContent | null =
|
||||
this.boardsAndTasksModel.getLatestTaskFileContent(taskId);
|
||||
if (taskFileContent == null) continue;
|
||||
|
||||
this.selectedPage.subscribeSilent(() => {
|
||||
this.storeLastUsedView();
|
||||
});
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent,
|
||||
);
|
||||
this.taskViewModels.set(taskFileContent.fileId, taskViewModel);
|
||||
}
|
||||
|
||||
// handlers
|
||||
boardsAndTasksModel.taskHandlerManager.addHandler(
|
||||
(taskFileContent: TaskFileContent) => {
|
||||
if (taskFileContent.boardId != this.boardInfo.fileId) return;
|
||||
this.showTask(taskFileContent);
|
||||
this.updateTaskIndices();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// search
|
||||
this.searchViewModel = new SearchViewModel(
|
||||
this.taskViewModels,
|
||||
this.filteredTaskViewModels,
|
||||
TaskViewModel.getStringsForFilter,
|
||||
this.coreViewModel.boardSearchSuggestions
|
||||
);
|
||||
this.searchViewModel.appliedQuery.subscribeSilent((newQuery) => {
|
||||
this.handleNewSearch(newQuery);
|
||||
});
|
||||
this.restoreSearch();
|
||||
}
|
||||
loadSearchSuggestions = (): void => {
|
||||
const dirPath: string[] = this.getPreviousSearchesPath();
|
||||
const searches: string[] = this.storageModel.list(dirPath);
|
||||
this.coreViewModel.boardSearchSuggestions.add(...searches);
|
||||
};
|
||||
|
||||
restoreSearch = (): void => {
|
||||
const lastSearchPath: string[] = this.getLastSearchPath();
|
||||
const lastSearch: string | null =
|
||||
this.storageModel.read(lastSearchPath);
|
||||
if (lastSearch != null) {
|
||||
this.searchViewModel.search(lastSearch);
|
||||
}
|
||||
};
|
||||
|
||||
loadData = (): void => {
|
||||
this.restoreLastUsedView();
|
||||
this.loadTasks();
|
||||
this.loadSearchSuggestions();
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
public chatViewModel: ChatViewModel,
|
||||
storageModel: StorageModel,
|
||||
boardsAndTasksModel: BoardsAndTasksModel,
|
||||
taskPageViewModel: TaskPageViewModel,
|
||||
boardInfo: BoardInfoFileContent,
|
||||
) {
|
||||
super(coreViewModel, chatViewModel, boardsAndTasksModel);
|
||||
|
||||
// set
|
||||
this.storageModel = storageModel;
|
||||
this.boardsAndTasksModel = boardsAndTasksModel;
|
||||
this.taskPageViewModel = taskPageViewModel;
|
||||
this.boardInfo = boardInfo;
|
||||
|
||||
// load
|
||||
this.loadListRelevantData();
|
||||
|
||||
// subscriptions
|
||||
this.isSelected = React.createProxyState(
|
||||
[this.taskPageViewModel.selectedBoardId],
|
||||
() =>
|
||||
this.taskPageViewModel.selectedBoardId.value ==
|
||||
this.boardInfo.fileId,
|
||||
);
|
||||
|
||||
this.color.subscribe(() => {
|
||||
if (this.isSelected.value == false) return;
|
||||
this.applyColor();
|
||||
});
|
||||
|
||||
this.selectedPage.subscribeSilent(() => {
|
||||
this.storeLastUsedView();
|
||||
});
|
||||
|
||||
// handlers
|
||||
boardsAndTasksModel.taskHandlerManager.addHandler(
|
||||
(taskFileContent: TaskFileContent) => {
|
||||
if (taskFileContent.boardId != this.boardInfo.fileId) return;
|
||||
this.showTask(taskFileContent);
|
||||
this.updateTaskIndices();
|
||||
},
|
||||
);
|
||||
|
||||
// search
|
||||
this.searchViewModel = new SearchViewModel(
|
||||
this.taskViewModels,
|
||||
this.filteredTaskViewModels,
|
||||
TaskViewModel.getStringsForFilter,
|
||||
this.coreViewModel.boardSearchSuggestions,
|
||||
);
|
||||
this.searchViewModel.appliedQuery.subscribeSilent((newQuery) => {
|
||||
this.handleNewSearch(newQuery);
|
||||
});
|
||||
this.restoreSearch();
|
||||
}
|
||||
}
|
||||
|
||||
export enum BoardViewModelSubPath {
|
||||
LastUsedView = "last-used-view",
|
||||
PreviousSearches = "previous-searches",
|
||||
LastSearch = "last-search",
|
||||
LastUsedView = "last-used-view",
|
||||
PreviousSearches = "previous-searches",
|
||||
LastSearch = "last-search",
|
||||
}
|
||||
|
||||
// types
|
||||
export enum BoardPageType {
|
||||
List = "list",
|
||||
Kanban = "kanban",
|
||||
StatusGrid = "status-grid",
|
||||
List = "list",
|
||||
Kanban = "kanban",
|
||||
StatusGrid = "status-grid",
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from "bloatless-react";
|
||||
|
||||
import BoardsAndTasksModel, {
|
||||
TaskFileContent,
|
||||
TaskFileContent,
|
||||
} from "../../Model/Files/boardsAndTasksModel";
|
||||
import CalendarModel, { MonthGrid } from "../../Model/Files/calendarModel";
|
||||
|
||||
@@ -14,201 +14,208 @@ import TaskViewModel from "./taskViewModel";
|
||||
export const CALENDAR_EVENT_BOARD_ID = "events";
|
||||
|
||||
export default class CalendarPageViewModel extends TaskContainingPageViewModel {
|
||||
storageModel: StorageModel;
|
||||
calendarModel: CalendarModel;
|
||||
boardsAndTasksModel: BoardsAndTasksModel;
|
||||
storageModel: StorageModel;
|
||||
calendarModel: CalendarModel;
|
||||
boardsAndTasksModel: BoardsAndTasksModel;
|
||||
|
||||
// data
|
||||
get monthString(): string {
|
||||
return CalendarModel.getMonthString(
|
||||
this.selectedYear.value.toString(),
|
||||
this.selectedMonth.value.toString()
|
||||
);
|
||||
}
|
||||
|
||||
// paths
|
||||
getBasePath = (): string[] => {
|
||||
return [...this.calendarModel.getViewPath()];
|
||||
};
|
||||
|
||||
// state
|
||||
selectedYear: React.State<number> = new React.State(0);
|
||||
selectedMonth: React.State<number> = new React.State(0);
|
||||
selectedDate: React.State<number> = new React.State(0);
|
||||
|
||||
monthGrid: React.State<MonthGrid<React.MapState<TaskViewModel>> | undefined> =
|
||||
new React.State<any>(undefined);
|
||||
|
||||
// methods
|
||||
createEvent = (): void => {
|
||||
const taskFileContent: TaskFileContent =
|
||||
this.boardsAndTasksModel.createTask(CALENDAR_EVENT_BOARD_ID);
|
||||
taskFileContent.date = CalendarModel.getISODateString(
|
||||
this.selectedYear.value.toString(),
|
||||
this.selectedMonth.value.toString(),
|
||||
this.selectedDate.value.toString()
|
||||
);
|
||||
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent
|
||||
);
|
||||
|
||||
this.selectTask(taskViewModel);
|
||||
this.updateTaskIndices();
|
||||
};
|
||||
|
||||
getEventsForDate = (): React.MapState<TaskViewModel> | undefined => {
|
||||
const paddedDate: string = CalendarModel.padDateOrMonth(
|
||||
this.selectedDate.toString()
|
||||
);
|
||||
|
||||
if (this.monthGrid.value == undefined) {
|
||||
return undefined;
|
||||
// data
|
||||
get monthString(): string {
|
||||
return CalendarModel.getMonthString(
|
||||
this.selectedYear.value.toString(),
|
||||
this.selectedMonth.value.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
return this.monthGrid.value.days[paddedDate];
|
||||
};
|
||||
// paths
|
||||
getBasePath = (): string[] => {
|
||||
return [...this.calendarModel.getViewPath()];
|
||||
};
|
||||
|
||||
// view
|
||||
getTaskMapState = (
|
||||
taskFileContent: TaskFileContent
|
||||
): React.MapState<TaskViewModel> | null => {
|
||||
if (this.monthGrid.value == null) return null;
|
||||
// state
|
||||
selectedYear: React.State<number> = new React.State(0);
|
||||
selectedMonth: React.State<number> = new React.State(0);
|
||||
selectedDate: React.State<number> = new React.State(0);
|
||||
|
||||
const date: string = CalendarModel.isoToDateString(
|
||||
taskFileContent.date ?? ""
|
||||
);
|
||||
return this.monthGrid.value.days[date];
|
||||
};
|
||||
monthGrid: React.State<
|
||||
MonthGrid<React.MapState<TaskViewModel>> | undefined
|
||||
> = new React.State<any>(undefined);
|
||||
|
||||
showTask = (taskFileContent: TaskFileContent): void => {
|
||||
const monthString: string | undefined = CalendarModel.isoToMonthString(
|
||||
taskFileContent.date ?? ""
|
||||
);
|
||||
if (monthString == undefined || monthString != this.monthString) {
|
||||
this.removeTaskFromView(taskFileContent);
|
||||
this.calendarModel.deleteTaskReference(
|
||||
this.monthString,
|
||||
taskFileContent.fileId
|
||||
);
|
||||
return;
|
||||
// methods
|
||||
createEvent = (): void => {
|
||||
const taskFileContent: TaskFileContent =
|
||||
this.boardsAndTasksModel.createTask(CALENDAR_EVENT_BOARD_ID);
|
||||
taskFileContent.date = CalendarModel.getISODateString(
|
||||
this.selectedYear.value.toString(),
|
||||
this.selectedMonth.value.toString(),
|
||||
this.selectedDate.value.toString(),
|
||||
);
|
||||
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent,
|
||||
);
|
||||
|
||||
this.selectTask(taskViewModel);
|
||||
this.updateTaskIndices();
|
||||
};
|
||||
|
||||
getEventsForDate = (): React.MapState<TaskViewModel> | undefined => {
|
||||
const paddedDate: string = CalendarModel.padDateOrMonth(
|
||||
this.selectedDate.toString(),
|
||||
);
|
||||
|
||||
if (this.monthGrid.value == undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.monthGrid.value.days[paddedDate];
|
||||
};
|
||||
|
||||
// view
|
||||
getTaskMapState = (
|
||||
taskFileContent: TaskFileContent,
|
||||
): React.MapState<TaskViewModel> | null => {
|
||||
if (this.monthGrid.value == null) return null;
|
||||
|
||||
const date: string = CalendarModel.isoToDateString(
|
||||
taskFileContent.date ?? "",
|
||||
);
|
||||
return this.monthGrid.value.days[date];
|
||||
};
|
||||
|
||||
showTask = (taskFileContent: TaskFileContent): void => {
|
||||
const monthString: string | undefined = CalendarModel.isoToMonthString(
|
||||
taskFileContent.date ?? "",
|
||||
);
|
||||
if (monthString == undefined || monthString != this.monthString) {
|
||||
this.removeTaskFromView(taskFileContent);
|
||||
this.calendarModel.deleteTaskReference(
|
||||
this.monthString,
|
||||
taskFileContent.fileId,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent,
|
||||
);
|
||||
const mapState: React.MapState<TaskViewModel> | null =
|
||||
this.getTaskMapState(taskFileContent);
|
||||
|
||||
this.taskViewModels.handleRemoval(taskViewModel, () => {
|
||||
mapState?.remove(taskFileContent.fileId);
|
||||
});
|
||||
|
||||
this.taskViewModels.remove(taskFileContent.fileId);
|
||||
this.taskViewModels.set(taskFileContent.fileId, taskViewModel);
|
||||
|
||||
mapState?.set(taskFileContent.fileId, taskViewModel);
|
||||
};
|
||||
|
||||
removeTaskFromView = (taskFileContent: TaskFileContent): void => {
|
||||
this.taskViewModels.remove(taskFileContent.fileId);
|
||||
};
|
||||
|
||||
showToday = (): void => {
|
||||
const today: Date = new Date();
|
||||
this.selectedYear.value = today.getFullYear();
|
||||
this.selectedMonth.value = today.getMonth() + 1;
|
||||
this.selectedDate.value = today.getDate();
|
||||
};
|
||||
|
||||
showPreviousMonth = (): void => {
|
||||
this.selectedMonth.value -= 1;
|
||||
|
||||
if (this.selectedMonth.value <= 0) {
|
||||
this.selectedYear.value -= 1;
|
||||
this.selectedMonth.value = 12;
|
||||
}
|
||||
};
|
||||
|
||||
showNextMonth = (): void => {
|
||||
this.selectedMonth.value += 1;
|
||||
|
||||
if (this.selectedMonth.value >= 13) {
|
||||
this.selectedYear.value += 1;
|
||||
this.selectedMonth.value = 1;
|
||||
}
|
||||
};
|
||||
|
||||
handleDrop = (year: string, month: string, date: string): void => {
|
||||
const ISOString: string = CalendarModel.getISODateString(
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
);
|
||||
|
||||
const draggedObject: any = this.coreViewModel.draggedObject.value;
|
||||
if (draggedObject instanceof TaskViewModel == false) return;
|
||||
|
||||
draggedObject.setDate(ISOString);
|
||||
};
|
||||
|
||||
// load
|
||||
loadMonthTasks = (): void => {
|
||||
this.monthGrid.value = this.calendarModel.generateMonthGrid(
|
||||
this.selectedYear.value,
|
||||
this.selectedMonth.value,
|
||||
() => new React.MapState(),
|
||||
);
|
||||
const taskIds: string[] = this.calendarModel.listTaskIds(
|
||||
this.monthString,
|
||||
);
|
||||
|
||||
for (const taskId of taskIds) {
|
||||
const taskFileContent: TaskFileContent | null =
|
||||
this.boardsAndTasksModel.getLatestTaskFileContent(taskId);
|
||||
if (taskFileContent == null) continue;
|
||||
this.showTask(taskFileContent);
|
||||
}
|
||||
|
||||
this.updateTaskIndices();
|
||||
};
|
||||
|
||||
loadData = (): void => {
|
||||
this.loadMonthTasks();
|
||||
this.showToday();
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
public chatViewModel: ChatViewModel,
|
||||
storageModel: StorageModel,
|
||||
calendarModel: CalendarModel,
|
||||
boardsAndTasksModel: BoardsAndTasksModel,
|
||||
) {
|
||||
super(coreViewModel, chatViewModel, boardsAndTasksModel);
|
||||
|
||||
this.storageModel = storageModel;
|
||||
this.calendarModel = calendarModel;
|
||||
this.boardsAndTasksModel = boardsAndTasksModel;
|
||||
|
||||
this.chatViewModel = chatViewModel;
|
||||
|
||||
React.bulkSubscribe([this.selectedYear, this.selectedMonth], () => {
|
||||
this.loadMonthTasks();
|
||||
});
|
||||
|
||||
// handlers
|
||||
boardsAndTasksModel.taskHandlerManager.addHandler(
|
||||
(taskFileContent: TaskFileContent) => {
|
||||
this.showTask(taskFileContent);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent
|
||||
);
|
||||
const mapState: React.MapState<TaskViewModel> | null =
|
||||
this.getTaskMapState(taskFileContent);
|
||||
|
||||
this.taskViewModels.handleRemoval(taskViewModel, () => {
|
||||
mapState?.remove(taskFileContent.fileId);
|
||||
});
|
||||
|
||||
this.taskViewModels.remove(taskFileContent.fileId);
|
||||
this.taskViewModels.set(taskFileContent.fileId, taskViewModel);
|
||||
|
||||
mapState?.set(taskFileContent.fileId, taskViewModel);
|
||||
};
|
||||
|
||||
removeTaskFromView = (taskFileContent: TaskFileContent): void => {
|
||||
this.taskViewModels.remove(taskFileContent.fileId);
|
||||
};
|
||||
|
||||
showToday = (): void => {
|
||||
const today: Date = new Date();
|
||||
this.selectedYear.value = today.getFullYear();
|
||||
this.selectedMonth.value = today.getMonth() + 1;
|
||||
this.selectedDate.value = today.getDate();
|
||||
};
|
||||
|
||||
showPreviousMonth = (): void => {
|
||||
this.selectedMonth.value -= 1;
|
||||
|
||||
if (this.selectedMonth.value <= 0) {
|
||||
this.selectedYear.value -= 1;
|
||||
this.selectedMonth.value = 12;
|
||||
}
|
||||
};
|
||||
|
||||
showNextMonth = (): void => {
|
||||
this.selectedMonth.value += 1;
|
||||
|
||||
if (this.selectedMonth.value >= 13) {
|
||||
this.selectedYear.value += 1;
|
||||
this.selectedMonth.value = 1;
|
||||
}
|
||||
};
|
||||
|
||||
handleDrop = (year: string, month: string, date: string): void => {
|
||||
const ISOString: string = CalendarModel.getISODateString(year, month, date);
|
||||
|
||||
const draggedObject: any = this.coreViewModel.draggedObject.value;
|
||||
if (draggedObject instanceof TaskViewModel == false) return;
|
||||
|
||||
draggedObject.setDate(ISOString);
|
||||
};
|
||||
|
||||
// load
|
||||
loadMonthTasks = (): void => {
|
||||
this.monthGrid.value = this.calendarModel.generateMonthGrid(
|
||||
this.selectedYear.value,
|
||||
this.selectedMonth.value,
|
||||
() => new React.MapState()
|
||||
);
|
||||
const taskIds: string[] = this.calendarModel.listTaskIds(this.monthString);
|
||||
|
||||
for (const taskId of taskIds) {
|
||||
const taskFileContent: TaskFileContent | null =
|
||||
this.boardsAndTasksModel.getLatestTaskFileContent(taskId);
|
||||
if (taskFileContent == null) continue;
|
||||
this.showTask(taskFileContent);
|
||||
}
|
||||
|
||||
this.updateTaskIndices();
|
||||
};
|
||||
|
||||
loadData = (): void => {
|
||||
this.loadMonthTasks();
|
||||
this.showToday();
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
public chatViewModel: ChatViewModel,
|
||||
storageModel: StorageModel,
|
||||
calendarModel: CalendarModel,
|
||||
boardsAndTasksModel: BoardsAndTasksModel
|
||||
) {
|
||||
super(coreViewModel, chatViewModel, boardsAndTasksModel);
|
||||
|
||||
this.storageModel = storageModel;
|
||||
this.calendarModel = calendarModel;
|
||||
this.boardsAndTasksModel = boardsAndTasksModel;
|
||||
|
||||
this.chatViewModel = chatViewModel;
|
||||
|
||||
React.bulkSubscribe([this.selectedYear, this.selectedMonth], () => {
|
||||
this.loadMonthTasks();
|
||||
});
|
||||
|
||||
// handlers
|
||||
boardsAndTasksModel.taskHandlerManager.addHandler(
|
||||
(taskFileContent: TaskFileContent) => {
|
||||
this.showTask(taskFileContent);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export enum TaskPageViewModelSubPath {
|
||||
LastUsedBoard = "last-used-board",
|
||||
LastUsedBoard = "last-used-board",
|
||||
}
|
||||
|
||||
@@ -6,76 +6,83 @@ import ChatViewModel from "../Chat/chatViewModel";
|
||||
import CoreViewModel from "../Global/coreViewModel";
|
||||
|
||||
export default class MessagePageViewModel {
|
||||
chatViewModel: ChatViewModel;
|
||||
chatViewModel: ChatViewModel;
|
||||
|
||||
// state
|
||||
chatMessageViewModels: React.MapState<ChatMessageViewModel> =
|
||||
new React.MapState();
|
||||
composingMessage: React.State<string> = new React.State("");
|
||||
// state
|
||||
chatMessageViewModels: React.MapState<ChatMessageViewModel> =
|
||||
new React.MapState();
|
||||
composingMessage: React.State<string> = new React.State("");
|
||||
|
||||
// guards
|
||||
cannotSendMessage: React.State<boolean>;
|
||||
// guards
|
||||
cannotSendMessage: React.State<boolean>;
|
||||
|
||||
// methods
|
||||
sendMessage = (): void => {
|
||||
if (this.cannotSendMessage.value == true) return;
|
||||
// methods
|
||||
sendMessage = (): void => {
|
||||
if (this.cannotSendMessage.value == true) return;
|
||||
|
||||
this.sendMessageFromBody(this.composingMessage.value);
|
||||
this.composingMessage.value = "";
|
||||
};
|
||||
this.sendMessageFromBody(this.composingMessage.value);
|
||||
this.composingMessage.value = "";
|
||||
};
|
||||
|
||||
sendMessageFromBody = (body: string): void => {
|
||||
this.chatViewModel.chatModel.sendMessage(body);
|
||||
};
|
||||
sendMessageFromBody = (body: string): void => {
|
||||
this.chatViewModel.chatModel.sendMessage(body);
|
||||
};
|
||||
|
||||
decryptMessage = async (
|
||||
messageViewModel: ChatMessageViewModel
|
||||
): Promise<void> => {
|
||||
const chatMessage: ChatMessage = messageViewModel.chatMessage;
|
||||
await this.chatViewModel.chatModel.decryptMessage(chatMessage);
|
||||
this.chatViewModel.chatModel.addMessage(chatMessage);
|
||||
messageViewModel.loadData();
|
||||
};
|
||||
decryptMessage = async (
|
||||
messageViewModel: ChatMessageViewModel,
|
||||
): Promise<void> => {
|
||||
const chatMessage: ChatMessage = messageViewModel.chatMessage;
|
||||
await this.chatViewModel.chatModel.decryptMessage(chatMessage);
|
||||
this.chatViewModel.chatModel.addMessage(chatMessage);
|
||||
messageViewModel.loadData();
|
||||
};
|
||||
|
||||
// view
|
||||
showChatMessage = (chatMessage: ChatMessage): void => {
|
||||
const chatMessageViewModel = new ChatMessageViewModel(
|
||||
this.coreViewModel,
|
||||
this,
|
||||
chatMessage,
|
||||
chatMessage.sender == this.chatViewModel.settingsViewModel.username.value
|
||||
);
|
||||
// view
|
||||
showChatMessage = (chatMessage: ChatMessage): void => {
|
||||
const chatMessageViewModel = new ChatMessageViewModel(
|
||||
this.coreViewModel,
|
||||
this,
|
||||
chatMessage,
|
||||
chatMessage.sender ==
|
||||
this.chatViewModel.settingsViewModel.username.value,
|
||||
);
|
||||
|
||||
const existingChatMessageViewModel: ChatMessageViewModel | undefined =
|
||||
this.chatMessageViewModels.value.get(chatMessage.id);
|
||||
if (existingChatMessageViewModel != undefined) {
|
||||
existingChatMessageViewModel.body.value = chatMessage.body;
|
||||
existingChatMessageViewModel.status.value = chatMessage.status;
|
||||
} else {
|
||||
this.chatMessageViewModels.set(chatMessage.id, chatMessageViewModel);
|
||||
const existingChatMessageViewModel: ChatMessageViewModel | undefined =
|
||||
this.chatMessageViewModels.value.get(chatMessage.id);
|
||||
if (existingChatMessageViewModel != undefined) {
|
||||
existingChatMessageViewModel.body.value = chatMessage.body;
|
||||
existingChatMessageViewModel.status.value = chatMessage.status;
|
||||
} else {
|
||||
this.chatMessageViewModels.set(
|
||||
chatMessage.id,
|
||||
chatMessageViewModel,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// load
|
||||
loadData = (): void => {
|
||||
this.chatMessageViewModels.clear();
|
||||
for (const chatMessage of this.chatViewModel.chatModel.messages) {
|
||||
this.showChatMessage(chatMessage);
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
chatViewModel: ChatViewModel,
|
||||
) {
|
||||
this.chatViewModel = chatViewModel;
|
||||
|
||||
this.cannotSendMessage = React.createProxyState(
|
||||
[
|
||||
this.chatViewModel.settingsViewModel.username,
|
||||
this.composingMessage,
|
||||
],
|
||||
() =>
|
||||
this.chatViewModel.settingsViewModel.username.value == "" ||
|
||||
this.composingMessage.value == "",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// load
|
||||
loadData = (): void => {
|
||||
this.chatMessageViewModels.clear();
|
||||
for (const chatMessage of this.chatViewModel.chatModel.messages) {
|
||||
this.showChatMessage(chatMessage);
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
chatViewModel: ChatViewModel
|
||||
) {
|
||||
this.chatViewModel = chatViewModel;
|
||||
|
||||
this.cannotSendMessage = React.createProxyState(
|
||||
[this.chatViewModel.settingsViewModel.username, this.composingMessage],
|
||||
() =>
|
||||
this.chatViewModel.settingsViewModel.username.value == "" ||
|
||||
this.composingMessage.value == ""
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,128 +5,128 @@ import { Color } from "../../colors";
|
||||
import CoreViewModel from "../Global/coreViewModel";
|
||||
|
||||
export default class SettingsPageViewModel {
|
||||
chatViewModel: ChatViewModel;
|
||||
chatViewModel: ChatViewModel;
|
||||
|
||||
// state
|
||||
primaryChannel: React.State<string> = new React.State("");
|
||||
primaryChannelInput: React.State<string> = new React.State("");
|
||||
// state
|
||||
primaryChannel: React.State<string> = new React.State("");
|
||||
primaryChannelInput: React.State<string> = new React.State("");
|
||||
|
||||
secondaryChannels: React.ListState<string> = new React.ListState();
|
||||
newSecondaryChannelInput: React.State<string> = new React.State("");
|
||||
secondaryChannels: React.ListState<string> = new React.ListState();
|
||||
newSecondaryChannelInput: React.State<string> = new React.State("");
|
||||
|
||||
encryptionKeyInput: React.State<string> = new React.State("");
|
||||
shouldShowEncryptionKey: React.State<boolean> = new React.State(false);
|
||||
encryptionKeyInputType: React.State<"text" | "password"> =
|
||||
React.createProxyState([this.shouldShowEncryptionKey], () =>
|
||||
this.shouldShowEncryptionKey.value == true ? "text" : "password"
|
||||
encryptionKeyInput: React.State<string> = new React.State("");
|
||||
shouldShowEncryptionKey: React.State<boolean> = new React.State(false);
|
||||
encryptionKeyInputType: React.State<"text" | "password"> =
|
||||
React.createProxyState([this.shouldShowEncryptionKey], () =>
|
||||
this.shouldShowEncryptionKey.value == true ? "text" : "password",
|
||||
);
|
||||
|
||||
color: React.State<Color> = new React.State<any>(Color.Standard);
|
||||
|
||||
// guards
|
||||
cannotSetPrimaryChannel: React.State<boolean> = React.createProxyState(
|
||||
[this.primaryChannel, this.primaryChannelInput],
|
||||
() =>
|
||||
this.primaryChannelInput.value == "" ||
|
||||
this.primaryChannelInput.value == this.primaryChannel.value,
|
||||
);
|
||||
|
||||
color: React.State<Color> = new React.State<any>(Color.Standard);
|
||||
|
||||
// guards
|
||||
cannotSetPrimaryChannel: React.State<boolean> = React.createProxyState(
|
||||
[this.primaryChannel, this.primaryChannelInput],
|
||||
() =>
|
||||
this.primaryChannelInput.value == "" ||
|
||||
this.primaryChannelInput.value == this.primaryChannel.value
|
||||
);
|
||||
cannotAddSecondaryChannel: React.State<boolean> = React.createProxyState(
|
||||
[this.newSecondaryChannelInput],
|
||||
() => this.newSecondaryChannelInput.value == ""
|
||||
);
|
||||
cannotSetEncryptionKey: React.State<boolean>;
|
||||
|
||||
// methods
|
||||
setPrimaryChannel = (): void => {
|
||||
this.chatViewModel.chatModel.setPrimaryChannel(
|
||||
this.primaryChannelInput.value
|
||||
cannotAddSecondaryChannel: React.State<boolean> = React.createProxyState(
|
||||
[this.newSecondaryChannelInput],
|
||||
() => this.newSecondaryChannelInput.value == "",
|
||||
);
|
||||
this.primaryChannel.value =
|
||||
this.chatViewModel.chatModel.info.primaryChannel;
|
||||
cannotSetEncryptionKey: React.State<boolean>;
|
||||
|
||||
this.chatViewModel.chatListViewModel.updateIndices();
|
||||
};
|
||||
// methods
|
||||
setPrimaryChannel = (): void => {
|
||||
this.chatViewModel.chatModel.setPrimaryChannel(
|
||||
this.primaryChannelInput.value,
|
||||
);
|
||||
this.primaryChannel.value =
|
||||
this.chatViewModel.chatModel.info.primaryChannel;
|
||||
|
||||
addSecondaryChannel = (): void => {
|
||||
this.secondaryChannels.add(this.newSecondaryChannelInput.value);
|
||||
this.newSecondaryChannelInput.value = "";
|
||||
this.storeSecondaryChannels();
|
||||
this.loadSecondaryChannels();
|
||||
};
|
||||
this.chatViewModel.chatListViewModel.updateIndices();
|
||||
};
|
||||
|
||||
removeSecondaryChannel = (secondaryChannel: string): void => {
|
||||
this.secondaryChannels.remove(secondaryChannel);
|
||||
this.storeSecondaryChannels();
|
||||
};
|
||||
addSecondaryChannel = (): void => {
|
||||
this.secondaryChannels.add(this.newSecondaryChannelInput.value);
|
||||
this.newSecondaryChannelInput.value = "";
|
||||
this.storeSecondaryChannels();
|
||||
this.loadSecondaryChannels();
|
||||
};
|
||||
|
||||
storeSecondaryChannels = (): void => {
|
||||
this.chatViewModel.chatModel.setSecondaryChannels([
|
||||
...this.secondaryChannels.value.values(),
|
||||
]);
|
||||
};
|
||||
removeSecondaryChannel = (secondaryChannel: string): void => {
|
||||
this.secondaryChannels.remove(secondaryChannel);
|
||||
this.storeSecondaryChannels();
|
||||
};
|
||||
|
||||
setEncryptionKey = (): void => {
|
||||
this.chatViewModel.chatModel.setEncryptionKey(
|
||||
this.encryptionKeyInput.value
|
||||
);
|
||||
storeSecondaryChannels = (): void => {
|
||||
this.chatViewModel.chatModel.setSecondaryChannels([
|
||||
...this.secondaryChannels.value.values(),
|
||||
]);
|
||||
};
|
||||
|
||||
// disable button
|
||||
this.encryptionKeyInput.callSubscriptions();
|
||||
};
|
||||
setEncryptionKey = (): void => {
|
||||
this.chatViewModel.chatModel.setEncryptionKey(
|
||||
this.encryptionKeyInput.value,
|
||||
);
|
||||
|
||||
applyColor = (newColor: Color): void => {
|
||||
this.chatViewModel.setColor(newColor);
|
||||
};
|
||||
// disable button
|
||||
this.encryptionKeyInput.callSubscriptions();
|
||||
};
|
||||
|
||||
remove = (): void => {
|
||||
this.chatViewModel.close();
|
||||
this.chatViewModel.chatModel.delete();
|
||||
this.chatViewModel.chatListViewModel.untrackChat(this.chatViewModel);
|
||||
};
|
||||
applyColor = (newColor: Color): void => {
|
||||
this.chatViewModel.setColor(newColor);
|
||||
};
|
||||
|
||||
// load
|
||||
loadListRelevantData = (): void => {
|
||||
this.primaryChannel.value =
|
||||
this.chatViewModel.chatModel.info.primaryChannel;
|
||||
remove = (): void => {
|
||||
this.chatViewModel.close();
|
||||
this.chatViewModel.chatModel.delete();
|
||||
this.chatViewModel.chatListViewModel.untrackChat(this.chatViewModel);
|
||||
};
|
||||
|
||||
this.color.value = this.chatViewModel.chatModel.color;
|
||||
};
|
||||
// load
|
||||
loadListRelevantData = (): void => {
|
||||
this.primaryChannel.value =
|
||||
this.chatViewModel.chatModel.info.primaryChannel;
|
||||
|
||||
loadData = (): void => {
|
||||
this.primaryChannelInput.value =
|
||||
this.chatViewModel.chatModel.info.primaryChannel;
|
||||
this.color.value = this.chatViewModel.chatModel.color;
|
||||
};
|
||||
|
||||
this.loadSecondaryChannels();
|
||||
loadData = (): void => {
|
||||
this.primaryChannelInput.value =
|
||||
this.chatViewModel.chatModel.info.primaryChannel;
|
||||
|
||||
this.encryptionKeyInput.value =
|
||||
this.chatViewModel.chatModel.info.encryptionKey;
|
||||
};
|
||||
this.loadSecondaryChannels();
|
||||
|
||||
loadSecondaryChannels = (): void => {
|
||||
this.secondaryChannels.clear();
|
||||
for (const secondaryChannel of this.chatViewModel.chatModel
|
||||
.secondaryChannels) {
|
||||
this.secondaryChannels.add(secondaryChannel);
|
||||
this.encryptionKeyInput.value =
|
||||
this.chatViewModel.chatModel.info.encryptionKey;
|
||||
};
|
||||
|
||||
loadSecondaryChannels = (): void => {
|
||||
this.secondaryChannels.clear();
|
||||
for (const secondaryChannel of this.chatViewModel.chatModel
|
||||
.secondaryChannels) {
|
||||
this.secondaryChannels.add(secondaryChannel);
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
chatViewModel: ChatViewModel,
|
||||
) {
|
||||
this.chatViewModel = chatViewModel;
|
||||
this.loadListRelevantData();
|
||||
|
||||
this.cannotSetEncryptionKey = React.createProxyState(
|
||||
[this.encryptionKeyInput],
|
||||
() =>
|
||||
this.encryptionKeyInput.value ==
|
||||
this.chatViewModel.chatModel.info.encryptionKey,
|
||||
);
|
||||
|
||||
this.color.subscribe((newColor) => {
|
||||
this.applyColor(newColor);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
chatViewModel: ChatViewModel
|
||||
) {
|
||||
this.chatViewModel = chatViewModel;
|
||||
this.loadListRelevantData();
|
||||
|
||||
this.cannotSetEncryptionKey = React.createProxyState(
|
||||
[this.encryptionKeyInput],
|
||||
() =>
|
||||
this.encryptionKeyInput.value ==
|
||||
this.chatViewModel.chatModel.info.encryptionKey
|
||||
);
|
||||
|
||||
this.color.subscribe((newColor) => {
|
||||
this.applyColor(newColor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from "bloatless-react";
|
||||
|
||||
import BoardsAndTasksModel, {
|
||||
TaskFileContent,
|
||||
TaskFileContent,
|
||||
} from "../../Model/Files/boardsAndTasksModel";
|
||||
|
||||
import ChatViewModel from "../Chat/chatViewModel";
|
||||
@@ -10,58 +10,58 @@ import { IndexManager } from "../../Model/Utility/utility";
|
||||
import TaskViewModel from "./taskViewModel";
|
||||
|
||||
export default class TaskContainingPageViewModel {
|
||||
boardsAndTasksModel: BoardsAndTasksModel;
|
||||
boardsAndTasksModel: BoardsAndTasksModel;
|
||||
|
||||
// state
|
||||
taskIndexManager: IndexManager<TaskViewModel> = new IndexManager(
|
||||
(taskViewModel: TaskViewModel) => taskViewModel.sortingString
|
||||
);
|
||||
|
||||
selectedTaskViewModel: React.State<TaskViewModel | undefined> =
|
||||
new React.State<any>(undefined);
|
||||
|
||||
taskViewModels: React.MapState<TaskViewModel> = new React.MapState();
|
||||
|
||||
// methods
|
||||
createTaskFromBoardId = (boardId: string): void => {
|
||||
const taskFileContent: TaskFileContent =
|
||||
this.boardsAndTasksModel.createTask(boardId);
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent
|
||||
// state
|
||||
taskIndexManager: IndexManager<TaskViewModel> = new IndexManager(
|
||||
(taskViewModel: TaskViewModel) => taskViewModel.sortingString,
|
||||
);
|
||||
this.selectTask(taskViewModel);
|
||||
this.updateTaskIndices();
|
||||
};
|
||||
|
||||
// view
|
||||
showTask = (taskFileContent: TaskFileContent): void => {};
|
||||
removeTaskFromView = (taskFileContent: TaskFileContent): void => {};
|
||||
selectedTaskViewModel: React.State<TaskViewModel | undefined> =
|
||||
new React.State<any>(undefined);
|
||||
|
||||
selectTask = (selectedTask: TaskViewModel): void => {
|
||||
this.selectedTaskViewModel.value = selectedTask;
|
||||
};
|
||||
taskViewModels: React.MapState<TaskViewModel> = new React.MapState();
|
||||
|
||||
closeTask = () => {
|
||||
this.selectedTaskViewModel.value = undefined;
|
||||
};
|
||||
// methods
|
||||
createTaskFromBoardId = (boardId: string): void => {
|
||||
const taskFileContent: TaskFileContent =
|
||||
this.boardsAndTasksModel.createTask(boardId);
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent,
|
||||
);
|
||||
this.selectTask(taskViewModel);
|
||||
this.updateTaskIndices();
|
||||
};
|
||||
|
||||
updateTaskIndices = (): void => {
|
||||
this.taskIndexManager.update([...this.taskViewModels.value.values()]);
|
||||
for (const boardViewModel of this.taskViewModels.value.values()) {
|
||||
boardViewModel.updateIndex();
|
||||
// view
|
||||
showTask = (taskFileContent: TaskFileContent): void => {};
|
||||
removeTaskFromView = (taskFileContent: TaskFileContent): void => {};
|
||||
|
||||
selectTask = (selectedTask: TaskViewModel): void => {
|
||||
this.selectedTaskViewModel.value = selectedTask;
|
||||
};
|
||||
|
||||
closeTask = () => {
|
||||
this.selectedTaskViewModel.value = undefined;
|
||||
};
|
||||
|
||||
updateTaskIndices = (): void => {
|
||||
this.taskIndexManager.update([...this.taskViewModels.value.values()]);
|
||||
for (const boardViewModel of this.taskViewModels.value.values()) {
|
||||
boardViewModel.updateIndex();
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
public chatViewModel: ChatViewModel,
|
||||
boardsAndTasksModel: BoardsAndTasksModel,
|
||||
) {
|
||||
this.boardsAndTasksModel = boardsAndTasksModel;
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
public chatViewModel: ChatViewModel,
|
||||
boardsAndTasksModel: BoardsAndTasksModel
|
||||
) {
|
||||
this.boardsAndTasksModel = boardsAndTasksModel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from "bloatless-react";
|
||||
|
||||
import BoardsAndTasksModel, {
|
||||
BoardInfoFileContent,
|
||||
BoardInfoFileContent,
|
||||
} from "../../Model/Files/boardsAndTasksModel";
|
||||
|
||||
import BoardViewModel from "./boardViewModel";
|
||||
@@ -11,169 +11,169 @@ import { IndexManager } from "../../Model/Utility/utility";
|
||||
import StorageModel from "../../Model/Global/storageModel";
|
||||
|
||||
export default class TaskPageViewModel {
|
||||
storageModel: StorageModel;
|
||||
boardsAndTasksModel: BoardsAndTasksModel;
|
||||
storageModel: StorageModel;
|
||||
boardsAndTasksModel: BoardsAndTasksModel;
|
||||
|
||||
// data
|
||||
boardIndexManager: IndexManager<BoardViewModel> = new IndexManager(
|
||||
(boardViewModel: BoardViewModel) => boardViewModel.name.value
|
||||
);
|
||||
|
||||
// paths
|
||||
getBasePath = (): string[] => {
|
||||
return [...this.boardsAndTasksModel.getViewPath()];
|
||||
};
|
||||
|
||||
getBoardViewPath = (boardId): string[] => {
|
||||
return [...this.getBasePath(), boardId];
|
||||
};
|
||||
|
||||
getLastUsedBoardPath = (): string[] => {
|
||||
return [...this.getBasePath(), TaskPageViewModelSubPath.LastUsedBoard];
|
||||
};
|
||||
|
||||
// state
|
||||
newBoardNameInput: React.State<string> = new React.State("");
|
||||
|
||||
boardViewModels: React.MapState<BoardViewModel> = new React.MapState();
|
||||
|
||||
isShowingBoadList: React.State<boolean> = new React.State(true);
|
||||
|
||||
selectedBoardId: React.State<string | undefined> = new React.State<any>(
|
||||
undefined
|
||||
);
|
||||
|
||||
// guards
|
||||
cannotCreateBoard: React.State<boolean> = React.createProxyState(
|
||||
[this.newBoardNameInput],
|
||||
() => this.newBoardNameInput.value == ""
|
||||
);
|
||||
|
||||
// methods
|
||||
createBoard = (): void => {
|
||||
if (this.cannotCreateBoard.value == true) return;
|
||||
|
||||
const boardInfoFileContent: BoardInfoFileContent =
|
||||
this.boardsAndTasksModel.createBoard(this.newBoardNameInput.value);
|
||||
this.newBoardNameInput.value = "";
|
||||
|
||||
this.showBoardInList(boardInfoFileContent);
|
||||
this.boardsAndTasksModel.updateBoardAndSend(boardInfoFileContent);
|
||||
this.updateBoardIndices();
|
||||
};
|
||||
|
||||
updateBoard = (boardInfoFileContent: BoardInfoFileContent): void => {
|
||||
this.boardsAndTasksModel.updateBoardAndSend(boardInfoFileContent);
|
||||
this.updateBoardIndices();
|
||||
};
|
||||
|
||||
deleteBoard = (boardInfoFileContent: BoardInfoFileContent): void => {
|
||||
this.boardsAndTasksModel.deleteBoard(boardInfoFileContent.fileId);
|
||||
this.boardViewModels.remove(boardInfoFileContent.fileId);
|
||||
this.updateBoardIndices();
|
||||
};
|
||||
|
||||
// view
|
||||
toggleBoardList = (): void => {
|
||||
this.isShowingBoadList.value = !this.isShowingBoadList.value;
|
||||
};
|
||||
|
||||
showBoardInList = (boardInfo: BoardInfoFileContent): void => {
|
||||
const boardViewModel: BoardViewModel = new BoardViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.storageModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
boardInfo
|
||||
// data
|
||||
boardIndexManager: IndexManager<BoardViewModel> = new IndexManager(
|
||||
(boardViewModel: BoardViewModel) => boardViewModel.name.value,
|
||||
);
|
||||
this.boardViewModels.set(boardInfo.fileId, boardViewModel);
|
||||
|
||||
this.chatViewModel.taskBoardSuggestions.set(boardInfo.fileId, [
|
||||
boardInfo.fileId,
|
||||
this.boardsAndTasksModel.getBoardName(boardInfo.fileId),
|
||||
]);
|
||||
};
|
||||
// paths
|
||||
getBasePath = (): string[] => {
|
||||
return [...this.boardsAndTasksModel.getViewPath()];
|
||||
};
|
||||
|
||||
selectBoard = (boardViewModel: BoardViewModel): void => {
|
||||
this.selectedBoardId.value = boardViewModel.boardInfo.fileId;
|
||||
this.chatViewModel.displayedColor.value = boardViewModel.color.value;
|
||||
getBoardViewPath = (boardId): string[] => {
|
||||
return [...this.getBasePath(), boardId];
|
||||
};
|
||||
|
||||
this.storeLastUsedBoard();
|
||||
};
|
||||
getLastUsedBoardPath = (): string[] => {
|
||||
return [...this.getBasePath(), TaskPageViewModelSubPath.LastUsedBoard];
|
||||
};
|
||||
|
||||
closeBoard = (): void => {
|
||||
this.selectedBoardId.value = undefined;
|
||||
this.chatViewModel.resetColor();
|
||||
// state
|
||||
newBoardNameInput: React.State<string> = new React.State("");
|
||||
|
||||
this.storeLastUsedBoard();
|
||||
};
|
||||
boardViewModels: React.MapState<BoardViewModel> = new React.MapState();
|
||||
|
||||
updateBoardIndices = (): void => {
|
||||
this.boardIndexManager.update([...this.boardViewModels.value.values()]);
|
||||
for (const boardViewModel of this.boardViewModels.value.values()) {
|
||||
boardViewModel.updateIndex();
|
||||
}
|
||||
};
|
||||
isShowingBoadList: React.State<boolean> = new React.State(true);
|
||||
|
||||
// storage
|
||||
storeLastUsedBoard = (): void => {
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedBoardId: string = this.selectedBoardId.value ?? "";
|
||||
this.storageModel.write(path, lastUsedBoardId);
|
||||
};
|
||||
selectedBoardId: React.State<string | undefined> = new React.State<any>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
openLastUsedBoard = (): void => {
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedBoardId: string | null = this.storageModel.read(path);
|
||||
if (lastUsedBoardId == null) return;
|
||||
// guards
|
||||
cannotCreateBoard: React.State<boolean> = React.createProxyState(
|
||||
[this.newBoardNameInput],
|
||||
() => this.newBoardNameInput.value == "",
|
||||
);
|
||||
|
||||
const boardViewModel: BoardViewModel | undefined =
|
||||
this.boardViewModels.value.get(lastUsedBoardId);
|
||||
if (boardViewModel == undefined) return;
|
||||
// methods
|
||||
createBoard = (): void => {
|
||||
if (this.cannotCreateBoard.value == true) return;
|
||||
|
||||
this.selectBoard(boardViewModel);
|
||||
};
|
||||
const boardInfoFileContent: BoardInfoFileContent =
|
||||
this.boardsAndTasksModel.createBoard(this.newBoardNameInput.value);
|
||||
this.newBoardNameInput.value = "";
|
||||
|
||||
// load
|
||||
loadData = (): void => {
|
||||
this.boardViewModels.clear();
|
||||
|
||||
const boardIds: string[] = this.boardsAndTasksModel.listBoardIds();
|
||||
for (const boardId of boardIds) {
|
||||
const boardInfo: BoardInfoFileContent | null =
|
||||
this.boardsAndTasksModel.getBoardInfo(boardId);
|
||||
if (boardInfo == null) continue;
|
||||
|
||||
this.showBoardInList(boardInfo);
|
||||
}
|
||||
|
||||
this.updateBoardIndices();
|
||||
this.openLastUsedBoard();
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
public chatViewModel: ChatViewModel,
|
||||
storageModel: StorageModel,
|
||||
boardModel: BoardsAndTasksModel
|
||||
) {
|
||||
this.storageModel = storageModel;
|
||||
this.boardsAndTasksModel = boardModel;
|
||||
|
||||
this.chatViewModel = chatViewModel;
|
||||
|
||||
// handlers
|
||||
boardModel.boardHandlerManager.addHandler(
|
||||
(boardInfoFileContent: BoardInfoFileContent) => {
|
||||
this.showBoardInList(boardInfoFileContent);
|
||||
this.boardsAndTasksModel.updateBoardAndSend(boardInfoFileContent);
|
||||
this.updateBoardIndices();
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
updateBoard = (boardInfoFileContent: BoardInfoFileContent): void => {
|
||||
this.boardsAndTasksModel.updateBoardAndSend(boardInfoFileContent);
|
||||
this.updateBoardIndices();
|
||||
};
|
||||
|
||||
deleteBoard = (boardInfoFileContent: BoardInfoFileContent): void => {
|
||||
this.boardsAndTasksModel.deleteBoard(boardInfoFileContent.fileId);
|
||||
this.boardViewModels.remove(boardInfoFileContent.fileId);
|
||||
this.updateBoardIndices();
|
||||
};
|
||||
|
||||
// view
|
||||
toggleBoardList = (): void => {
|
||||
this.isShowingBoadList.value = !this.isShowingBoadList.value;
|
||||
};
|
||||
|
||||
showBoardInList = (boardInfo: BoardInfoFileContent): void => {
|
||||
const boardViewModel: BoardViewModel = new BoardViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.storageModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
boardInfo,
|
||||
);
|
||||
this.boardViewModels.set(boardInfo.fileId, boardViewModel);
|
||||
|
||||
this.chatViewModel.taskBoardSuggestions.set(boardInfo.fileId, [
|
||||
boardInfo.fileId,
|
||||
this.boardsAndTasksModel.getBoardName(boardInfo.fileId),
|
||||
]);
|
||||
};
|
||||
|
||||
selectBoard = (boardViewModel: BoardViewModel): void => {
|
||||
this.selectedBoardId.value = boardViewModel.boardInfo.fileId;
|
||||
this.chatViewModel.displayedColor.value = boardViewModel.color.value;
|
||||
|
||||
this.storeLastUsedBoard();
|
||||
};
|
||||
|
||||
closeBoard = (): void => {
|
||||
this.selectedBoardId.value = undefined;
|
||||
this.chatViewModel.resetColor();
|
||||
|
||||
this.storeLastUsedBoard();
|
||||
};
|
||||
|
||||
updateBoardIndices = (): void => {
|
||||
this.boardIndexManager.update([...this.boardViewModels.value.values()]);
|
||||
for (const boardViewModel of this.boardViewModels.value.values()) {
|
||||
boardViewModel.updateIndex();
|
||||
}
|
||||
};
|
||||
|
||||
// storage
|
||||
storeLastUsedBoard = (): void => {
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedBoardId: string = this.selectedBoardId.value ?? "";
|
||||
this.storageModel.write(path, lastUsedBoardId);
|
||||
};
|
||||
|
||||
openLastUsedBoard = (): void => {
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedBoardId: string | null = this.storageModel.read(path);
|
||||
if (lastUsedBoardId == null) return;
|
||||
|
||||
const boardViewModel: BoardViewModel | undefined =
|
||||
this.boardViewModels.value.get(lastUsedBoardId);
|
||||
if (boardViewModel == undefined) return;
|
||||
|
||||
this.selectBoard(boardViewModel);
|
||||
};
|
||||
|
||||
// load
|
||||
loadData = (): void => {
|
||||
this.boardViewModels.clear();
|
||||
|
||||
const boardIds: string[] = this.boardsAndTasksModel.listBoardIds();
|
||||
for (const boardId of boardIds) {
|
||||
const boardInfo: BoardInfoFileContent | null =
|
||||
this.boardsAndTasksModel.getBoardInfo(boardId);
|
||||
if (boardInfo == null) continue;
|
||||
|
||||
this.showBoardInList(boardInfo);
|
||||
}
|
||||
|
||||
this.updateBoardIndices();
|
||||
this.openLastUsedBoard();
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
public chatViewModel: ChatViewModel,
|
||||
storageModel: StorageModel,
|
||||
boardModel: BoardsAndTasksModel,
|
||||
) {
|
||||
this.storageModel = storageModel;
|
||||
this.boardsAndTasksModel = boardModel;
|
||||
|
||||
this.chatViewModel = chatViewModel;
|
||||
|
||||
// handlers
|
||||
boardModel.boardHandlerManager.addHandler(
|
||||
(boardInfoFileContent: BoardInfoFileContent) => {
|
||||
this.showBoardInList(boardInfoFileContent);
|
||||
this.updateBoardIndices();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export enum TaskPageViewModelSubPath {
|
||||
LastUsedBoard = "last-used-board",
|
||||
LastUsedBoard = "last-used-board",
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from "bloatless-react";
|
||||
|
||||
import BoardsAndTasksModel, {
|
||||
TaskFileContent,
|
||||
TaskFileContent,
|
||||
} from "../../Model/Files/boardsAndTasksModel";
|
||||
import { localeCompare, padZero } from "../../Model/Utility/utility";
|
||||
|
||||
@@ -11,225 +11,235 @@ import TaskContainingPageViewModel from "./taskContainingPageViewModel";
|
||||
import { allowDrag } from "../../View/utility";
|
||||
|
||||
export default class TaskViewModel {
|
||||
boardsAndTasksModel: BoardsAndTasksModel;
|
||||
boardsAndTasksModel: BoardsAndTasksModel;
|
||||
|
||||
containingModel: TaskContainingPageViewModel;
|
||||
containingModel: TaskContainingPageViewModel;
|
||||
|
||||
// data
|
||||
task: TaskFileContent;
|
||||
// data
|
||||
task: TaskFileContent;
|
||||
|
||||
get sortingString(): string {
|
||||
const splitDate: string[] = this.date.value.split("-");
|
||||
const year = padZero(splitDate[0], 4);
|
||||
const month = padZero(splitDate[1], 2);
|
||||
const date = padZero(splitDate[2], 2);
|
||||
get sortingString(): string {
|
||||
const splitDate: string[] = this.date.value.split("-");
|
||||
const year = padZero(splitDate[0], 4);
|
||||
const month = padZero(splitDate[1], 2);
|
||||
const date = padZero(splitDate[2], 2);
|
||||
|
||||
const splitTime: string[] = this.time.value.split(":");
|
||||
const hour = padZero(splitTime[0], 2);
|
||||
const minute = padZero(splitTime[1], 2);
|
||||
const splitTime: string[] = this.time.value.split(":");
|
||||
const hour = padZero(splitTime[0], 2);
|
||||
const minute = padZero(splitTime[1], 2);
|
||||
|
||||
const priorityNumber = parseInt(this.priority.value);
|
||||
const invertedPriority = 100 - priorityNumber;
|
||||
const priorityNumber = parseInt(this.priority.value);
|
||||
const invertedPriority = 100 - priorityNumber;
|
||||
|
||||
return (
|
||||
year + month + date + hour + minute + invertedPriority + this.name.value
|
||||
);
|
||||
}
|
||||
|
||||
// paths
|
||||
getFilePath = (): string[] => {
|
||||
return this.boardsAndTasksModel.getTaskFilePath(this.task.fileId);
|
||||
};
|
||||
|
||||
// state
|
||||
index: React.State<number> = new React.State(0);
|
||||
|
||||
boardId: React.State<string> = new React.State("");
|
||||
|
||||
name: React.State<string> = new React.State("");
|
||||
description: React.State<string> = new React.State("");
|
||||
|
||||
category: React.State<string> = new React.State("");
|
||||
status: React.State<string> = new React.State("");
|
||||
priority: React.State<string> = new React.State("");
|
||||
|
||||
date: React.State<string> = new React.State("");
|
||||
time: React.State<string> = new React.State("");
|
||||
|
||||
selectedVersionId: React.State<string> = new React.State("");
|
||||
versionIds: React.ListState<string> = new React.ListState();
|
||||
|
||||
// methods
|
||||
dragStart = (event: DragEvent): void => {
|
||||
allowDrag(event);
|
||||
this.coreViewModel.draggedObject.value = this;
|
||||
};
|
||||
|
||||
setCategoryAndStatus = (category?: string, status?: string): void => {
|
||||
if (category != undefined) this.category.value = category;
|
||||
if (status != undefined) this.status.value = status;
|
||||
this.save();
|
||||
};
|
||||
|
||||
setBoardId = (boardId: string): void => {
|
||||
this.boardId.value = boardId;
|
||||
this.save();
|
||||
};
|
||||
|
||||
setDate = (dateISOString: string): void => {
|
||||
this.date.value = dateISOString;
|
||||
this.save();
|
||||
};
|
||||
|
||||
// view
|
||||
open = (): void => {
|
||||
this.containingModel.selectTask(this);
|
||||
};
|
||||
|
||||
close = (): void => {
|
||||
this.containingModel.closeTask();
|
||||
};
|
||||
|
||||
closeAndDiscard = (): void => {
|
||||
this.close();
|
||||
this.loadTaskData();
|
||||
}
|
||||
|
||||
closeAndSave = (): void => {
|
||||
this.close();
|
||||
this.save();
|
||||
};
|
||||
|
||||
updateIndex = (): void => {
|
||||
const index: number = this.containingModel.taskIndexManager.getIndex(this);
|
||||
this.index.value = index;
|
||||
};
|
||||
|
||||
updateSuggestions = (): void => {
|
||||
if (
|
||||
this.coreViewModel.taskCategorySuggestions.value.has(
|
||||
this.category.value
|
||||
) == false
|
||||
) {
|
||||
this.coreViewModel.taskCategorySuggestions.add(this.category.value);
|
||||
return (
|
||||
year +
|
||||
month +
|
||||
date +
|
||||
hour +
|
||||
minute +
|
||||
invertedPriority +
|
||||
this.name.value
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
this.coreViewModel.taskStatusSuggestions.value.has(this.status.value) ==
|
||||
false
|
||||
) {
|
||||
this.coreViewModel.taskStatusSuggestions.add(this.status.value);
|
||||
}
|
||||
};
|
||||
// paths
|
||||
getFilePath = (): string[] => {
|
||||
return this.boardsAndTasksModel.getTaskFilePath(this.task.fileId);
|
||||
};
|
||||
|
||||
// settings
|
||||
save = (): void => {
|
||||
const newTaskFileContent: TaskFileContent =
|
||||
BoardsAndTasksModel.createTaskFileContent(
|
||||
this.task.fileId,
|
||||
this.name.value,
|
||||
this.task.boardId
|
||||
);
|
||||
// state
|
||||
index: React.State<number> = new React.State(0);
|
||||
|
||||
newTaskFileContent.boardId = this.boardId.value;
|
||||
newTaskFileContent.description = this.description.value;
|
||||
newTaskFileContent.status = this.status.value;
|
||||
newTaskFileContent.category = this.category.value;
|
||||
newTaskFileContent.priority = this.priority.value;
|
||||
newTaskFileContent.date = this.date.value;
|
||||
newTaskFileContent.time = this.time.value;
|
||||
boardId: React.State<string> = new React.State("");
|
||||
|
||||
this.boardsAndTasksModel.updateTaskAndSend(newTaskFileContent);
|
||||
name: React.State<string> = new React.State("");
|
||||
description: React.State<string> = new React.State("");
|
||||
|
||||
this.containingModel.showTask(newTaskFileContent);
|
||||
this.containingModel.updateTaskIndices();
|
||||
category: React.State<string> = new React.State("");
|
||||
status: React.State<string> = new React.State("");
|
||||
priority: React.State<string> = new React.State("");
|
||||
|
||||
this.updateSuggestions();
|
||||
};
|
||||
date: React.State<string> = new React.State("");
|
||||
time: React.State<string> = new React.State("");
|
||||
|
||||
deleteTask = (): void => {
|
||||
this.close();
|
||||
this.boardsAndTasksModel.deleteTask(this.task.boardId, this.task.fileId);
|
||||
this.containingModel.removeTaskFromView(this.task);
|
||||
};
|
||||
selectedVersionId: React.State<string> = new React.State("");
|
||||
versionIds: React.ListState<string> = new React.ListState();
|
||||
|
||||
// load
|
||||
loadVersionIds = (): void => {
|
||||
const versionIds: string[] = this.boardsAndTasksModel.listTaskVersionIds(
|
||||
this.task.fileId
|
||||
);
|
||||
const sortedVersionIds = versionIds.sort(localeCompare).reverse();
|
||||
this.versionIds.clear();
|
||||
this.versionIds.add(...sortedVersionIds);
|
||||
};
|
||||
// methods
|
||||
dragStart = (event: DragEvent): void => {
|
||||
allowDrag(event);
|
||||
this.coreViewModel.draggedObject.value = this;
|
||||
};
|
||||
|
||||
switchVersion = (versionId: string): void => {
|
||||
const taskFileContent: TaskFileContent | null =
|
||||
this.boardsAndTasksModel.getSpecificTaskFileContent(
|
||||
this.task.fileId,
|
||||
versionId
|
||||
);
|
||||
if (taskFileContent == null) return;
|
||||
setCategoryAndStatus = (category?: string, status?: string): void => {
|
||||
if (category != undefined) this.category.value = category;
|
||||
if (status != undefined) this.status.value = status;
|
||||
this.save();
|
||||
};
|
||||
|
||||
this.task = taskFileContent;
|
||||
this.loadTaskData();
|
||||
};
|
||||
setBoardId = (boardId: string): void => {
|
||||
this.boardId.value = boardId;
|
||||
this.save();
|
||||
};
|
||||
|
||||
loadAllData = (): void => {
|
||||
this.loadTaskData();
|
||||
this.loadVersionIds();
|
||||
};
|
||||
setDate = (dateISOString: string): void => {
|
||||
this.date.value = dateISOString;
|
||||
this.save();
|
||||
};
|
||||
|
||||
loadTaskData = (): void => {
|
||||
this.boardId.value = this.task.boardId;
|
||||
// view
|
||||
open = (): void => {
|
||||
this.containingModel.selectTask(this);
|
||||
};
|
||||
|
||||
this.name.value = this.task.name;
|
||||
this.description.value = this.task.description ?? "";
|
||||
close = (): void => {
|
||||
this.containingModel.closeTask();
|
||||
};
|
||||
|
||||
this.category.value = this.task.category ?? "";
|
||||
this.status.value = this.task.status ?? "";
|
||||
this.priority.value = this.task.priority ?? "";
|
||||
closeAndDiscard = (): void => {
|
||||
this.close();
|
||||
this.loadTaskData();
|
||||
};
|
||||
|
||||
this.date.value = this.task.date ?? "";
|
||||
this.time.value = this.task.time ?? "";
|
||||
closeAndSave = (): void => {
|
||||
this.close();
|
||||
this.save();
|
||||
};
|
||||
|
||||
this.selectedVersionId.value = this.task.fileContentId;
|
||||
updateIndex = (): void => {
|
||||
const index: number =
|
||||
this.containingModel.taskIndexManager.getIndex(this);
|
||||
this.index.value = index;
|
||||
};
|
||||
|
||||
this.updateSuggestions();
|
||||
};
|
||||
updateSuggestions = (): void => {
|
||||
if (
|
||||
this.coreViewModel.taskCategorySuggestions.value.has(
|
||||
this.category.value,
|
||||
) == false
|
||||
) {
|
||||
this.coreViewModel.taskCategorySuggestions.add(this.category.value);
|
||||
}
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
public chatViewModel: ChatViewModel,
|
||||
boardsAndTasksModel: BoardsAndTasksModel,
|
||||
containingModel: TaskContainingPageViewModel,
|
||||
taskFileContent: TaskFileContent
|
||||
) {
|
||||
this.boardsAndTasksModel = boardsAndTasksModel;
|
||||
this.containingModel = containingModel;
|
||||
if (
|
||||
this.coreViewModel.taskStatusSuggestions.value.has(
|
||||
this.status.value,
|
||||
) == false
|
||||
) {
|
||||
this.coreViewModel.taskStatusSuggestions.add(this.status.value);
|
||||
}
|
||||
};
|
||||
|
||||
this.task = taskFileContent;
|
||||
// settings
|
||||
save = (): void => {
|
||||
const newTaskFileContent: TaskFileContent =
|
||||
BoardsAndTasksModel.createTaskFileContent(
|
||||
this.task.fileId,
|
||||
this.name.value,
|
||||
this.task.boardId,
|
||||
);
|
||||
|
||||
newTaskFileContent.boardId = this.boardId.value;
|
||||
newTaskFileContent.description = this.description.value;
|
||||
newTaskFileContent.status = this.status.value;
|
||||
newTaskFileContent.category = this.category.value;
|
||||
newTaskFileContent.priority = this.priority.value;
|
||||
newTaskFileContent.date = this.date.value;
|
||||
newTaskFileContent.time = this.time.value;
|
||||
|
||||
this.boardsAndTasksModel.updateTaskAndSend(newTaskFileContent);
|
||||
|
||||
this.containingModel.showTask(newTaskFileContent);
|
||||
this.containingModel.updateTaskIndices();
|
||||
|
||||
this.updateSuggestions();
|
||||
};
|
||||
|
||||
deleteTask = (): void => {
|
||||
this.close();
|
||||
this.boardsAndTasksModel.deleteTask(
|
||||
this.task.boardId,
|
||||
this.task.fileId,
|
||||
);
|
||||
this.containingModel.removeTaskFromView(this.task);
|
||||
};
|
||||
|
||||
// load
|
||||
this.loadAllData();
|
||||
loadVersionIds = (): void => {
|
||||
const versionIds: string[] =
|
||||
this.boardsAndTasksModel.listTaskVersionIds(this.task.fileId);
|
||||
const sortedVersionIds = versionIds.sort(localeCompare).reverse();
|
||||
this.versionIds.clear();
|
||||
this.versionIds.add(...sortedVersionIds);
|
||||
};
|
||||
|
||||
// subscriptions
|
||||
this.selectedVersionId.subscribeSilent((selectedVersionId) => {
|
||||
this.switchVersion(selectedVersionId);
|
||||
});
|
||||
}
|
||||
switchVersion = (versionId: string): void => {
|
||||
const taskFileContent: TaskFileContent | null =
|
||||
this.boardsAndTasksModel.getSpecificTaskFileContent(
|
||||
this.task.fileId,
|
||||
versionId,
|
||||
);
|
||||
if (taskFileContent == null) return;
|
||||
|
||||
// utility
|
||||
static getStringsForFilter = (taskViewModel: TaskViewModel): string[] => {
|
||||
return [
|
||||
taskViewModel.task.name,
|
||||
taskViewModel.task.description ?? "",
|
||||
taskViewModel.task.category ?? "",
|
||||
taskViewModel.task.status ?? "",
|
||||
taskViewModel.task.priority ?? "",
|
||||
taskViewModel.task.date ?? "",
|
||||
taskViewModel.task.time ?? "",
|
||||
];
|
||||
};
|
||||
this.task = taskFileContent;
|
||||
this.loadTaskData();
|
||||
};
|
||||
|
||||
loadAllData = (): void => {
|
||||
this.loadTaskData();
|
||||
this.loadVersionIds();
|
||||
};
|
||||
|
||||
loadTaskData = (): void => {
|
||||
this.boardId.value = this.task.boardId;
|
||||
|
||||
this.name.value = this.task.name;
|
||||
this.description.value = this.task.description ?? "";
|
||||
|
||||
this.category.value = this.task.category ?? "";
|
||||
this.status.value = this.task.status ?? "";
|
||||
this.priority.value = this.task.priority ?? "";
|
||||
|
||||
this.date.value = this.task.date ?? "";
|
||||
this.time.value = this.task.time ?? "";
|
||||
|
||||
this.selectedVersionId.value = this.task.fileContentId;
|
||||
|
||||
this.updateSuggestions();
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public coreViewModel: CoreViewModel,
|
||||
public chatViewModel: ChatViewModel,
|
||||
boardsAndTasksModel: BoardsAndTasksModel,
|
||||
containingModel: TaskContainingPageViewModel,
|
||||
taskFileContent: TaskFileContent,
|
||||
) {
|
||||
this.boardsAndTasksModel = boardsAndTasksModel;
|
||||
this.containingModel = containingModel;
|
||||
|
||||
this.task = taskFileContent;
|
||||
|
||||
// load
|
||||
this.loadAllData();
|
||||
|
||||
// subscriptions
|
||||
this.selectedVersionId.subscribeSilent((selectedVersionId) => {
|
||||
this.switchVersion(selectedVersionId);
|
||||
});
|
||||
}
|
||||
|
||||
// utility
|
||||
static getStringsForFilter = (taskViewModel: TaskViewModel): string[] => {
|
||||
return [
|
||||
taskViewModel.task.name,
|
||||
taskViewModel.task.description ?? "",
|
||||
taskViewModel.task.category ?? "",
|
||||
taskViewModel.task.status ?? "",
|
||||
taskViewModel.task.priority ?? "",
|
||||
taskViewModel.task.date ?? "",
|
||||
taskViewModel.task.time ?? "",
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,74 +3,74 @@ import * as React from "bloatless-react";
|
||||
import { checkDoesObjectMatchSearch } from "../../Model/Utility/utility";
|
||||
|
||||
export default class SearchViewModel<T> {
|
||||
// data
|
||||
allObjects: React.ListState<T> | React.MapState<T>;
|
||||
getStringsOfObject: (object: T) => string[];
|
||||
// data
|
||||
allObjects: React.ListState<T> | React.MapState<T>;
|
||||
getStringsOfObject: (object: T) => string[];
|
||||
|
||||
// state
|
||||
appliedQuery: React.State<string> = new React.State("");
|
||||
searchInput: React.State<string> = new React.State("");
|
||||
matchingObjects: React.ListState<T>;
|
||||
// state
|
||||
appliedQuery: React.State<string> = new React.State("");
|
||||
searchInput: React.State<string> = new React.State("");
|
||||
matchingObjects: React.ListState<T>;
|
||||
|
||||
suggestions: React.ListState<string>;
|
||||
suggestions: React.ListState<string>;
|
||||
|
||||
// guards
|
||||
cannotApplySearch: React.State<boolean> = React.createProxyState(
|
||||
[this.searchInput, this.appliedQuery],
|
||||
() => this.searchInput.value == this.appliedQuery.value
|
||||
);
|
||||
|
||||
// methods
|
||||
search = (searchTerm: string): void => {
|
||||
this.searchInput.value = searchTerm;
|
||||
this.applySearch();
|
||||
};
|
||||
|
||||
applySearch = (): void => {
|
||||
this.appliedQuery.value = this.searchInput.value;
|
||||
|
||||
this.matchingObjects.clear();
|
||||
for (const object of this.allObjects.value.values()) {
|
||||
const doesMatch: boolean = this.checkDoesMatchSearch(object);
|
||||
if (doesMatch == false) continue;
|
||||
|
||||
this.matchingObjects.add(object);
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
allObjects: React.ListState<T> | React.MapState<T>,
|
||||
matchingObjects: React.ListState<T>,
|
||||
getStringsOfObject: (object: T) => string[],
|
||||
suggestions: React.ListState<string>
|
||||
) {
|
||||
this.allObjects = allObjects;
|
||||
this.matchingObjects = matchingObjects;
|
||||
this.getStringsOfObject = getStringsOfObject;
|
||||
this.suggestions = suggestions;
|
||||
|
||||
// handle new objects
|
||||
this.allObjects.handleAddition((newObject: T) => {
|
||||
const doesMatch: boolean = this.checkDoesMatchSearch(newObject);
|
||||
if (doesMatch == false) {
|
||||
this.matchingObjects.remove(newObject);
|
||||
} else {
|
||||
if (this.matchingObjects.value.has(newObject)) return;
|
||||
this.matchingObjects.add(newObject);
|
||||
this.allObjects.handleRemoval(newObject, () => {
|
||||
this.matchingObjects.remove(newObject);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// utility
|
||||
checkDoesMatchSearch = (object: T): boolean => {
|
||||
return checkDoesObjectMatchSearch(
|
||||
this.appliedQuery.value,
|
||||
this.getStringsOfObject,
|
||||
object
|
||||
// guards
|
||||
cannotApplySearch: React.State<boolean> = React.createProxyState(
|
||||
[this.searchInput, this.appliedQuery],
|
||||
() => this.searchInput.value == this.appliedQuery.value,
|
||||
);
|
||||
};
|
||||
|
||||
// methods
|
||||
search = (searchTerm: string): void => {
|
||||
this.searchInput.value = searchTerm;
|
||||
this.applySearch();
|
||||
};
|
||||
|
||||
applySearch = (): void => {
|
||||
this.appliedQuery.value = this.searchInput.value;
|
||||
|
||||
this.matchingObjects.clear();
|
||||
for (const object of this.allObjects.value.values()) {
|
||||
const doesMatch: boolean = this.checkDoesMatchSearch(object);
|
||||
if (doesMatch == false) continue;
|
||||
|
||||
this.matchingObjects.add(object);
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
allObjects: React.ListState<T> | React.MapState<T>,
|
||||
matchingObjects: React.ListState<T>,
|
||||
getStringsOfObject: (object: T) => string[],
|
||||
suggestions: React.ListState<string>,
|
||||
) {
|
||||
this.allObjects = allObjects;
|
||||
this.matchingObjects = matchingObjects;
|
||||
this.getStringsOfObject = getStringsOfObject;
|
||||
this.suggestions = suggestions;
|
||||
|
||||
// handle new objects
|
||||
this.allObjects.handleAddition((newObject: T) => {
|
||||
const doesMatch: boolean = this.checkDoesMatchSearch(newObject);
|
||||
if (doesMatch == false) {
|
||||
this.matchingObjects.remove(newObject);
|
||||
} else {
|
||||
if (this.matchingObjects.value.has(newObject)) return;
|
||||
this.matchingObjects.add(newObject);
|
||||
this.allObjects.handleRemoval(newObject, () => {
|
||||
this.matchingObjects.remove(newObject);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// utility
|
||||
checkDoesMatchSearch = (object: T): boolean => {
|
||||
return checkDoesObjectMatchSearch(
|
||||
this.appliedQuery.value,
|
||||
this.getStringsOfObject,
|
||||
object,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,70 +3,72 @@ import * as React from "bloatless-react";
|
||||
import TaskViewModel from "../Pages/taskViewModel";
|
||||
|
||||
export default class TaskPropertyBulkChangeViewModel {
|
||||
taskViewModels: React.ListState<TaskViewModel>;
|
||||
taskViewModels: React.ListState<TaskViewModel>;
|
||||
|
||||
// state
|
||||
inputValue: React.State<string> = new React.State("");
|
||||
// state
|
||||
inputValue: React.State<string> = new React.State("");
|
||||
|
||||
// guards
|
||||
cannotSet: React.State<boolean>;
|
||||
// guards
|
||||
cannotSet: React.State<boolean>;
|
||||
|
||||
// methods
|
||||
set = (): void => {
|
||||
if (this.cannotSet.value == true) return;
|
||||
this.taskViewModels.value.forEach((taskViewModel: TaskViewModel) => {
|
||||
this.setValue(this.inputValue.value, taskViewModel);
|
||||
});
|
||||
};
|
||||
// methods
|
||||
set = (): void => {
|
||||
if (this.cannotSet.value == true) return;
|
||||
this.taskViewModels.value.forEach((taskViewModel: TaskViewModel) => {
|
||||
this.setValue(this.inputValue.value, taskViewModel);
|
||||
});
|
||||
};
|
||||
|
||||
setValue: (newValue: string, taskViewModel: TaskViewModel) => void;
|
||||
setValue: (newValue: string, taskViewModel: TaskViewModel) => void;
|
||||
|
||||
// init
|
||||
constructor(
|
||||
taskViewModels: React.ListState<TaskViewModel>,
|
||||
valueSetter: (newValue: string, taskViewModel: TaskViewModel) => void,
|
||||
initialValue: string
|
||||
) {
|
||||
this.taskViewModels = taskViewModels;
|
||||
this.inputValue.value = initialValue;
|
||||
// init
|
||||
constructor(
|
||||
taskViewModels: React.ListState<TaskViewModel>,
|
||||
valueSetter: (newValue: string, taskViewModel: TaskViewModel) => void,
|
||||
initialValue: string,
|
||||
) {
|
||||
this.taskViewModels = taskViewModels;
|
||||
this.inputValue.value = initialValue;
|
||||
|
||||
this.setValue = valueSetter;
|
||||
this.setValue = valueSetter;
|
||||
|
||||
this.cannotSet = React.createProxyState(
|
||||
[this.inputValue],
|
||||
() => this.inputValue.value == "" || this.inputValue.value == initialValue
|
||||
);
|
||||
}
|
||||
this.cannotSet = React.createProxyState(
|
||||
[this.inputValue],
|
||||
() =>
|
||||
this.inputValue.value == "" ||
|
||||
this.inputValue.value == initialValue,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class TaskCategoryBulkChangeViewModel extends TaskPropertyBulkChangeViewModel {
|
||||
constructor(
|
||||
taskViewModels: React.ListState<TaskViewModel>,
|
||||
initialValue: string
|
||||
) {
|
||||
super(
|
||||
taskViewModels,
|
||||
(newCategory: string, taskViewModel: TaskViewModel) => {
|
||||
taskViewModel.category.value = newCategory;
|
||||
taskViewModel.save();
|
||||
},
|
||||
initialValue
|
||||
);
|
||||
}
|
||||
constructor(
|
||||
taskViewModels: React.ListState<TaskViewModel>,
|
||||
initialValue: string,
|
||||
) {
|
||||
super(
|
||||
taskViewModels,
|
||||
(newCategory: string, taskViewModel: TaskViewModel) => {
|
||||
taskViewModel.category.value = newCategory;
|
||||
taskViewModel.save();
|
||||
},
|
||||
initialValue,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class TaskStatusBulkChangeViewModel extends TaskPropertyBulkChangeViewModel {
|
||||
constructor(
|
||||
taskViewModels: React.ListState<TaskViewModel>,
|
||||
initialValue: string
|
||||
) {
|
||||
super(
|
||||
taskViewModels,
|
||||
(newStatus: string, taskViewModel: TaskViewModel) => {
|
||||
taskViewModel.status.value = newStatus;
|
||||
taskViewModel.save();
|
||||
},
|
||||
initialValue
|
||||
);
|
||||
}
|
||||
constructor(
|
||||
taskViewModels: React.ListState<TaskViewModel>,
|
||||
initialValue: string,
|
||||
) {
|
||||
super(
|
||||
taskViewModels,
|
||||
(newStatus: string, taskViewModel: TaskViewModel) => {
|
||||
taskViewModel.status.value = newStatus;
|
||||
taskViewModel.save();
|
||||
},
|
||||
initialValue,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user