implement onboarding

This commit is contained in:
marlon-erler
2026-09-29 21:15:11 +02:00
parent fbc40b5e3e
commit 7a532bbf5c
13 changed files with 687 additions and 281 deletions
+272 -1
View File
@@ -391,6 +391,24 @@
checkUpdatesButton: "Check for updates"
}
},
onboarding: {
connectionHeadline: "Connect to UDN",
connectionDescription: "To transfer files and send messages, connect to the Universal Decentralized Network (UDN).",
connectButton: "Connect",
connectionNextButton: (isConnected) => isConnected ? "Continue" : "Set up without UDN",
///
transferOptionsHeadline: "Copy Your Data",
transferOptionsDescription: "If you already use the Coordination Tool on another device, copy your identity here. You can use both devices at the same time.",
transferOptionTransfer: "Copy my data here",
transferOptionNew: "Set up as new device",
//
nameHeadline: "Your Name",
nameDescription: "This is what others see when you send messages. You can always change your name in settings.",
//
transferHeadline: "Data Transfer",
transferDescription: "On your other device, prepare to transfer your identity and personal data alongside any chats you wish to copy. Then, enter the displayed data here. You can find the data transfer on the home screen of the other device.",
transferButton: "Copy data"
},
connectionModal: {
connectionModalHeadline: "Manage Connections",
///
@@ -646,6 +664,24 @@
checkUpdatesButton: "Nach Updates suchen"
}
},
onboarding: {
connectionHeadline: "Mit UDN verbinden",
connectionDescription: "Um Daten und Nachichten zu verschicken, verbinde dich mit dem Universellen Dezentralen Netzwerk (UDN).",
connectButton: "Verbinden",
connectionNextButton: (isConnected) => isConnected ? "Weiter" : "Ohne UDN einrichten",
///
transferOptionsHeadline: "Deine Daten kopieren",
transferOptionsDescription: "Wenn du Coordination Tool bereits auf einem anderen Ger\xE4t verwendest, kopiere deine Kontodaten. Du kannst beide Ger\xE4te gleichzeitig verwenden.",
transferOptionTransfer: "Daten \xFCbertragen",
transferOptionNew: "Als neues Ger\xE4t enrichten",
//
nameHeadline: "Dein Name",
nameDescription: "Diesen Namen sehen andere, wenn du Nachrichten versendest. Du kannst deinen Namen jederzeit in den Einstellungen \xE4ndern.",
//
transferHeadline: "Daten\xFCbertragung",
transferDescription: "Verwende die Funktion zur Daten\xFCbertragung auf deinem anderen Get\xE4t, um deine Identit\xE4t und pers\xF6nlichen Daten zu kopieren. Gib die dazu angezeigten Daten unten ein. Du findest die Daten\xFCbertragung auf der Startseite des anderen Ger\xE4ts.",
transferButton: "Daten kopieren"
},
connectionModal: {
connectionModalHeadline: "Verbindungen verwalten",
connectButtonAudioLabel: "verbinden"
@@ -882,6 +918,24 @@
checkUpdatesButton: "Buscar actualisaciones"
}
},
onboarding: {
connectionHeadline: "Conectar al UDN",
connectionDescription: "Para transferir datos y enviar mensajes, con\xE9ctate a la Red Descentralizada Universal (UDN).",
connectButton: "Conectar",
connectionNextButton: (isConnected) => isConnected ? "Continuar" : "Configurar sin UDN",
///
transferOptionsHeadline: "Copiar tus datos",
transferOptionsDescription: "Si ya usas el Coordination Tool en otro disposistivo, copia tu idantidad aqu\xED. Puedes usar ambos dispositivos al mismo tiempo.",
transferOptionTransfer: "Copiar mis datos aqu\xED",
transferOptionNew: "Configurar como dispositivo nuevo",
//
nameHeadline: "Tu nombre",
nameDescription: "Esto es lo que ven otros cuando env\xEDas menajes. Siempre lo puedes cambiar en las ajustes.",
//
transferHeadline: "Transferencia de datos",
transferDescription: "En el otro dispositivo, prepara la transferencia de tu identidad y datos personales. Ingresa los datos que se muestran a continuaci\xF3n. La opci\xF3n de la transferencia de datos se encuentra en la pantalla inicial en el otro dispositivo.",
transferButton: "Copiar datos"
},
connectionModal: {
connectionModalHeadline: "Gestionar Conexiones",
connectButtonAudioLabel: "conectar"
@@ -2165,6 +2219,7 @@
super("file-transfer");
this.coreViewModel = coreViewModel2;
// state
this.exitReception = void 0;
this.presentedModal = new State(void 0);
this.generalFileOptions = new ListState();
this.chatFileOptions = new ListState();
@@ -2328,6 +2383,14 @@
this.getTransferData();
this.coreViewModel.fileTransferModel.prepareToSend();
};
this.correctTransferData = () => {
if (this.exitReception != void 0) {
this.presentedModal.value = void 0;
this.exitReception();
return;
}
this.showTransferDataInputModal();
};
this.initiateTransfer = () => {
this.presentedModal.value = 3 /* TransferDisplay */;
this.didNotFinishSending.value = true;
@@ -7913,7 +7976,7 @@
"button",
{
class: "flex",
"on:click": fileTransferViewModel2.showTransferDataInputModal,
"on:click": fileTransferViewModel2.correctTransferData,
"toggle:disabled": fileTransferViewModel2.cannotExitReception
},
coreViewModel2.translations.general.backButton
@@ -8707,6 +8770,212 @@
}
};
// src/ViewModel/Global/onboardingViewModel.ts
var OnboardingViewModel = class {
// init
constructor(connectionViewmodel, fileTransferViewModel2, settingsViewModel2) {
this.connectionViewmodel = connectionViewmodel;
this.fileTransferViewModel = fileTransferViewModel2;
this.settingsViewModel = settingsViewModel2;
// state
this.presentedModal = new State(void 0);
// guards
this.cannotTransfer = createProxyState([this.connectionViewmodel.isConnected], () => !this.connectionViewmodel.isConnected.value);
// navigation
this.open = () => {
this.presentedModal.value = 0 /* Connection */;
};
this.showTransferOption = () => {
this.presentedModal.value = 1 /* TransferOrNew */;
};
this.setupNew = () => {
this.presentedModal.value = 2 /* Name */;
};
this.showTransferData = () => {
this.presentedModal.value = 3 /* Transfer */;
};
// methods
this.transferData = () => {
this.fileTransferViewModel.exitReception = () => this.showTransferData();
this.fileTransferViewModel.prepareReceivingData();
this.presentedModal.value = void 0;
};
this.finish = () => {
this.settingsViewModel.setName();
this.presentedModal.value = void 0;
};
if (this.settingsViewModel.settingsModel.username == "") this.open();
}
};
// src/View/Modals/onboardingModal.tsx
function OnboardingModalWrapper(coreViewModel2, onboardingViewModel2) {
return /* @__PURE__ */ createElement("div", null, ConnectionModal2(coreViewModel2, onboardingViewModel2), TransferModal(coreViewModel2, onboardingViewModel2), NameModal(coreViewModel2, onboardingViewModel2), TransferDataModal(coreViewModel2, onboardingViewModel2));
}
function ConnectionModal2(coreViewModel2, onboardingViewModel2) {
const isPresented = createProxyState(
[onboardingViewModel2.presentedModal],
() => onboardingViewModel2.presentedModal.value == 0 /* Connection */
);
const connectionViewModel2 = onboardingViewModel2.connectionViewmodel;
const nextButton = createProxyState([connectionViewModel2.isConnected], () => coreViewModel2.translations.onboarding.connectionNextButton(connectionViewModel2.isConnected.value));
return /* @__PURE__ */ createElement(
"div",
{
class: "modal",
"toggle:open": isPresented
},
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.onboarding.connectionHeadline), /* @__PURE__ */ createElement("p", { class: "secondary width-input" }, coreViewModel2.translations.onboarding.connectionDescription), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile flex-no" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "cell_tower"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, coreViewModel2.translations.homePage.serverAddress), /* @__PURE__ */ createElement(
"input",
{
placeholder: coreViewModel2.translations.homePage.serverAddressPlaceholder,
"bind:value": connectionViewModel2.serverAddressInput,
"on:enter": connectionViewModel2.connect
}
))), /* @__PURE__ */ createElement("div", { class: "flex-row width-input justify-end" }, /* @__PURE__ */ createElement(
"button",
{
class: "standard width-50",
"on:click": connectionViewModel2.connect,
"toggle:disabled": connectionViewModel2.cannotConnect
},
coreViewModel2.translations.onboarding.connectButton
))), /* @__PURE__ */ createElement("div", { class: "flex-row justify-end" }, /* @__PURE__ */ createElement(
"button",
{
class: "primary width-50",
"on:click": onboardingViewModel2.showTransferOption
},
/* @__PURE__ */ createElement(
"span",
{
"subscribe:innerText": nextButton
}
),
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
)))
);
}
function TransferModal(coreViewModel2, onboardingViewModel2) {
const isPresented = createProxyState(
[onboardingViewModel2.presentedModal],
() => onboardingViewModel2.presentedModal.value == 1 /* TransferOrNew */
);
return /* @__PURE__ */ createElement(
"div",
{
class: "modal",
"toggle:open": isPresented
},
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.onboarding.transferOptionsHeadline), /* @__PURE__ */ createElement("p", { class: "secondary width-input" }, coreViewModel2.translations.onboarding.transferOptionsDescription), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap" }, /* @__PURE__ */ createElement(
"button",
{
class: "tile",
"on:click": onboardingViewModel2.showTransferData,
"toggle:disabled": onboardingViewModel2.cannotTransfer
},
/* @__PURE__ */ createElement("div", null, coreViewModel2.translations.onboarding.transferOptionTransfer),
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
), /* @__PURE__ */ createElement(
"button",
{
class: "tile",
"on:click": onboardingViewModel2.setupNew
},
/* @__PURE__ */ createElement("div", null, coreViewModel2.translations.onboarding.transferOptionNew),
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
))), /* @__PURE__ */ createElement("div", { class: "flex-row" }, /* @__PURE__ */ createElement(
"button",
{
class: "standard width-50",
"on:click": onboardingViewModel2.open
},
coreViewModel2.translations.general.backButton
)))
);
}
function NameModal(coreViewModel2, onboardingViewModel2) {
const isPresented = createProxyState(
[onboardingViewModel2.presentedModal],
() => onboardingViewModel2.presentedModal.value == 2 /* Name */
);
const settingsViewModel2 = onboardingViewModel2.settingsViewModel;
return /* @__PURE__ */ createElement(
"div",
{
class: "modal",
"toggle:open": isPresented
},
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.onboarding.nameHeadline), /* @__PURE__ */ createElement("p", { class: "secondary width-input" }, coreViewModel2.translations.onboarding.nameDescription), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile flex-no" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "account_circle"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, coreViewModel2.translations.settings.account.yourNameLabel), /* @__PURE__ */ createElement(
"input",
{
placeholder: coreViewModel2.translations.settings.account.yourNamePlaceholder,
"bind:value": settingsViewModel2.usernameInput
}
)))), /* @__PURE__ */ createElement("div", { class: "flex-row" }, /* @__PURE__ */ createElement(
"button",
{
class: "standard width-50",
"on:click": onboardingViewModel2.showTransferOption
},
coreViewModel2.translations.general.backButton
), /* @__PURE__ */ createElement(
"button",
{
class: "primary width-50",
"on:click": onboardingViewModel2.finish
},
coreViewModel2.translations.general.setButton,
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
)))
);
}
function TransferDataModal(coreViewModel2, onboardingViewModel2) {
const isPresented = createProxyState(
[onboardingViewModel2.presentedModal],
() => onboardingViewModel2.presentedModal.value == 3 /* Transfer */
);
const fileTransferViewModel2 = onboardingViewModel2.fileTransferViewModel;
return /* @__PURE__ */ createElement(
"div",
{
class: "modal",
"toggle:open": isPresented
},
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.onboarding.transferHeadline), /* @__PURE__ */ createElement("p", { class: "secondary width-input" }, coreViewModel2.translations.onboarding.transferDescription), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap content-margin-bottom" }, /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "forum"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.dataTransferModal.transferChannelHeadline), /* @__PURE__ */ createElement(
"input",
{
type: "number",
"on:enter": fileTransferViewModel2.prepareReceivingData,
"bind:value": fileTransferViewModel2.receivingTransferChannel
}
))), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "key"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.dataTransferModal.transferKeyHeadline), /* @__PURE__ */ createElement(
"input",
{
type: "number",
"on:enter": fileTransferViewModel2.prepareReceivingData,
"bind:value": fileTransferViewModel2.receivingTransferKey
}
))))), /* @__PURE__ */ createElement("div", { class: "flex-row" }, /* @__PURE__ */ createElement(
"button",
{
class: "standard width-50",
"on:click": onboardingViewModel2.showTransferOption,
"toggle:disabled": fileTransferViewModel2.cannotExitReception
},
coreViewModel2.translations.general.backButton
), /* @__PURE__ */ createElement(
"button",
{
class: "primary width-50",
"on:click": onboardingViewModel2.transferData
},
coreViewModel2.translations.onboarding.transferButton,
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
)))
);
}
// src/index.tsx
var storageModel = new StorageModel();
var settingsModel = new SettingsModel(storageModel);
@@ -8740,6 +9009,7 @@
contactListViewModel
);
var fileTransferViewModel = new FileTransferViewModel(coreViewModel);
var onboardingViewModel = new OnboardingViewModel(connectionViewModel, fileTransferViewModel, settingsViewModel);
var homeViewModel = new HomeViewModel(
coreViewModel,
settingsViewModel,
@@ -8766,6 +9036,7 @@
chatListViewModel
),
ChatPageWrapper(coreViewModel, chatListViewModel),
OnboardingModalWrapper(coreViewModel, onboardingViewModel),
ConnectionModal(coreViewModel, connectionViewModel),
DataTransferModalWrapper(
coreViewModel,
Vendored
+1 -1
View File
@@ -1,4 +1,4 @@
const VERSION = "2610 Beta 18"
const VERSION = "2610 Beta 19"
function processUrl(event) {
const url = event.request.url;
+1 -1
View File
@@ -1 +1 @@
2610 Beta 18
2610 Beta 19
+1 -1
View File
@@ -111,7 +111,7 @@ export default class ChatModel {
this.addMessage(chatMessage);
if (chatMessage.stringifiedFile) return;
if (chatMessage.senderId == this.settingsModel.userid) return;
if (chatMessage.senderId == this.settingsModel.userid) return;
this.setReadStatus(true);
};
+1 -3
View File
@@ -615,9 +615,7 @@ function DataReceptionModal(
<div class="flex-row width-100">
<button
class="flex"
on:click={
fileTransferViewModel.correctTransferData
}
on:click={fileTransferViewModel.correctTransferData}
toggle:disabled={
fileTransferViewModel.cannotExitReception
}
+262 -208
View File
@@ -1,222 +1,275 @@
import { ViewController } from "../viewController";
import * as React from "../../react";
import OnboardingViewModel, {
OnboardingModals,
} from "../../ViewModel/Global/onboardingViewModel";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
import OnboardingViewModel, {OnboardingModals} from "../../ViewModel/Global/onboardingViewModel";
import {ViewController} from "../viewController";
// MAIN
export function OnboardingModalWrapper(coreViewModel: CoreViewModel, onboardingViewModel: OnboardingViewModel) {
return <div>
{ConnectionModal(coreViewModel, onboardingViewModel)}
{TransferModal(coreViewModel, onboardingViewModel)}
{NameModal(coreViewModel, onboardingViewModel)}
{TransferDataModal(coreViewModel, onboardingViewModel)}
</div>
export function OnboardingModalWrapper(
coreViewModel: CoreViewModel,
onboardingViewModel: OnboardingViewModel,
) {
return (
<div>
{ConnectionModal(coreViewModel, onboardingViewModel)}
{TransferModal(coreViewModel, onboardingViewModel)}
{NameModal(coreViewModel, onboardingViewModel)}
{TransferDataModal(coreViewModel, onboardingViewModel)}
</div>
);
}
function ConnectionModal(coreViewModel: CoreViewModel, onboardingViewModel: OnboardingViewModel) {
function ConnectionModal(
coreViewModel: CoreViewModel,
onboardingViewModel: OnboardingViewModel,
) {
const isPresented = React.createProxyState(
[onboardingViewModel.presentedModal],
() =>
onboardingViewModel.presentedModal.value ==
OnboardingModals.Connection
[onboardingViewModel.presentedModal],
() =>
onboardingViewModel.presentedModal.value ==
OnboardingModals.Connection,
);
const connectionViewModel = onboardingViewModel.connectionViewmodel;
const nextButton = React.createProxyState([connectionViewModel.isConnected], ()=>coreViewModel.translations.onboarding.connectionNextButton(connectionViewModel.isConnected.value));
return <div
class="modal"
toggle:open={isPresented}
>
<div>
<main>
<h2>{coreViewModel.translations.onboarding.connectionHeadline}</h2>
<p class="secondary width-input">{coreViewModel.translations.onboarding.connectionDescription}</p>
<hr></hr>
<label class="tile flex-no">
<span class="icon">cell_tower</span>
<div>
<span>
{coreViewModel.translations.homePage.serverAddress}
</span>
<input
placeholder={
coreViewModel.translations.homePage
.serverAddressPlaceholder
}
bind:value={connectionViewModel.serverAddressInput}
on:enter={connectionViewModel.connect}
></input>
</div>
</label>
<div class="flex-row width-input justify-end">
<button
class="standard width-50"
on:click={connectionViewModel.connect}
toggle:disabled={connectionViewModel.cannotConnect}
>
{coreViewModel.translations.onboarding.connectButton}
</button>
</div>
</main>
<div class="flex-row justify-end">
<button
class="primary width-50"
on:click={onboardingViewModel.showTransferOption}
>
<span
subscribe:innerText={nextButton}
></span>
<span class="icon">
arrow_forward
</span>
</button>
</div>
</div>
</div>
}
function TransferModal(coreViewModel: CoreViewModel, onboardingViewModel: OnboardingViewModel) {
const isPresented = React.createProxyState(
[onboardingViewModel.presentedModal],
() =>
onboardingViewModel.presentedModal.value ==
OnboardingModals.TransferOrNew
const nextButton = React.createProxyState(
[connectionViewModel.isConnected],
() =>
coreViewModel.translations.onboarding.connectionNextButton(
connectionViewModel.isConnected.value,
),
);
return <div
class="modal"
toggle:open={isPresented}
>
<div>
<main>
<h2>{coreViewModel.translations.onboarding.transferOptionsHeadline}</h2>
<p class="secondary width-input">{coreViewModel.translations.onboarding.transferOptionsDescription}</p>
return (
<div class="modal" toggle:open={isPresented}>
<div>
<main>
<h2>
{
coreViewModel.translations.onboarding
.connectionHeadline
}
</h2>
<p class="secondary width-input">
{
coreViewModel.translations.onboarding
.connectionDescription
}
</p>
<hr></hr>
<hr></hr>
<div class="flex-column gap">
<button
class="tile"
on:click={onboardingViewModel.showTransferData}
toggle:disabled={onboardingViewModel.cannotTransfer}
>
<div>
{coreViewModel.translations.onboarding.transferOptionTransfer}
</div>
<span class="icon">
arrow_forward
</span>
</button>
<button
class="tile"
on:click={onboardingViewModel.setupNew}
>
<div>
{coreViewModel.translations.onboarding.transferOptionNew}
</div>
<span class="icon">
arrow_forward
</span>
</button>
</div>
</main>
<div class="flex-row">
<button
class="standard width-50"
on:click={onboardingViewModel.open}
>
{coreViewModel.translations.general.backButton}
</button>
</div>
</div>
</div>
<label class="tile flex-no">
<span class="icon">cell_tower</span>
<div>
<span>
{
coreViewModel.translations.homePage
.serverAddress
}
</span>
<input
placeholder={
coreViewModel.translations.homePage
.serverAddressPlaceholder
}
bind:value={
connectionViewModel.serverAddressInput
}
on:enter={connectionViewModel.connect}
></input>
</div>
</label>
<div class="flex-row width-input justify-end">
<button
class="standard width-50"
on:click={connectionViewModel.connect}
toggle:disabled={connectionViewModel.cannotConnect}
>
{
coreViewModel.translations.onboarding
.connectButton
}
</button>
</div>
</main>
<div class="flex-row justify-end">
<button
class="primary width-50"
on:click={onboardingViewModel.showTransferOption}
>
<span subscribe:innerText={nextButton}></span>
<span class="icon">arrow_forward</span>
</button>
</div>
</div>
</div>
);
}
function NameModal(coreViewModel: CoreViewModel, onboardingViewModel: OnboardingViewModel) {
function TransferModal(
coreViewModel: CoreViewModel,
onboardingViewModel: OnboardingViewModel,
) {
const isPresented = React.createProxyState(
[onboardingViewModel.presentedModal],
() =>
onboardingViewModel.presentedModal.value ==
OnboardingModals.Name
[onboardingViewModel.presentedModal],
() =>
onboardingViewModel.presentedModal.value ==
OnboardingModals.TransferOrNew,
);
return (
<div class="modal" toggle:open={isPresented}>
<div>
<main>
<h2>
{
coreViewModel.translations.onboarding
.transferOptionsHeadline
}
</h2>
<p class="secondary width-input">
{
coreViewModel.translations.onboarding
.transferOptionsDescription
}
</p>
<hr></hr>
<div class="flex-column gap">
<button
class="tile"
on:click={onboardingViewModel.showTransferData}
toggle:disabled={onboardingViewModel.cannotTransfer}
>
<div>
{
coreViewModel.translations.onboarding
.transferOptionTransfer
}
</div>
<span class="icon">arrow_forward</span>
</button>
<button
class="tile"
on:click={onboardingViewModel.setupNew}
>
<div>
{
coreViewModel.translations.onboarding
.transferOptionNew
}
</div>
<span class="icon">arrow_forward</span>
</button>
</div>
</main>
<div class="flex-row">
<button
class="standard width-50"
on:click={onboardingViewModel.open}
>
{coreViewModel.translations.general.backButton}
</button>
</div>
</div>
</div>
);
}
function NameModal(
coreViewModel: CoreViewModel,
onboardingViewModel: OnboardingViewModel,
) {
const isPresented = React.createProxyState(
[onboardingViewModel.presentedModal],
() => onboardingViewModel.presentedModal.value == OnboardingModals.Name,
);
const settingsViewModel = onboardingViewModel.settingsViewModel;
return <div
class="modal"
toggle:open={isPresented}
>
<div>
<main>
<h2>{coreViewModel.translations.onboarding.nameHeadline}</h2>
<p class="secondary width-input">{coreViewModel.translations.onboarding.nameDescription}</p>
return (
<div class="modal" toggle:open={isPresented}>
<div>
<main>
<h2>
{coreViewModel.translations.onboarding.nameHeadline}
</h2>
<p class="secondary width-input">
{coreViewModel.translations.onboarding.nameDescription}
</p>
<hr></hr>
<hr></hr>
<label class="tile flex-no">
<span class="icon">account_circle</span>
<div>
<span>
{
coreViewModel.translations.settings.account
.yourNameLabel
}
</span>
<input
placeholder={
coreViewModel.translations.settings.account
.yourNamePlaceholder
}
bind:value={settingsViewModel.usernameInput}
></input>
</div>
</label>
</main>
<div class="flex-row">
<button
class="standard width-50"
on:click={onboardingViewModel.showTransferOption}
>
{coreViewModel.translations.general.backButton}
</button>
<button
class="primary width-50"
on:click={onboardingViewModel.finish}
>
{coreViewModel.translations.general.setButton}
<span class="icon">
arrow_forward
</span>
</button>
</div>
</div>
</div>
<label class="tile flex-no">
<span class="icon">account_circle</span>
<div>
<span>
{
coreViewModel.translations.settings.account
.yourNameLabel
}
</span>
<input
placeholder={
coreViewModel.translations.settings.account
.yourNamePlaceholder
}
bind:value={settingsViewModel.usernameInput}
></input>
</div>
</label>
</main>
<div class="flex-row">
<button
class="standard width-50"
on:click={onboardingViewModel.showTransferOption}
>
{coreViewModel.translations.general.backButton}
</button>
<button
class="primary width-50"
on:click={onboardingViewModel.finish}
>
{coreViewModel.translations.general.setButton}
<span class="icon">arrow_forward</span>
</button>
</div>
</div>
</div>
);
}
function TransferDataModal(coreViewModel: CoreViewModel, onboardingViewModel: OnboardingViewModel) {
function TransferDataModal(
coreViewModel: CoreViewModel,
onboardingViewModel: OnboardingViewModel,
) {
const isPresented = React.createProxyState(
[onboardingViewModel.presentedModal],
() =>
onboardingViewModel.presentedModal.value ==
OnboardingModals.Transfer
[onboardingViewModel.presentedModal],
() =>
onboardingViewModel.presentedModal.value ==
OnboardingModals.Transfer,
);
const fileTransferViewModel = onboardingViewModel.fileTransferViewModel;
return <div
class="modal"
toggle:open={isPresented}
>
<div>
<main>
<h2>{coreViewModel.translations.onboarding.transferHeadline}</h2>
<p class="secondary width-input">{coreViewModel.translations.onboarding.transferDescription}</p>
return (
<div class="modal" toggle:open={isPresented}>
<div>
<main>
<h2>
{coreViewModel.translations.onboarding.transferHeadline}
</h2>
<p class="secondary width-input">
{
coreViewModel.translations.onboarding
.transferDescription
}
</p>
<hr></hr>
<hr></hr>
<div class="flex-column gap content-margin-bottom">
<label class="tile">
@@ -262,25 +315,26 @@ function TransferDataModal(coreViewModel: CoreViewModel, onboardingViewModel: On
</div>
</label>
</div>
</main>
<div class="flex-row">
<button
class="standard width-50"
on:click={onboardingViewModel.showTransferOption}
toggle:disabled={fileTransferViewModel.cannotExitReception}
>
{coreViewModel.translations.general.backButton}
</button>
<button
class="primary width-50"
on:click={onboardingViewModel.transferData}
>
{coreViewModel.translations.onboarding.transferButton}
<span class="icon">
check
</span>
</button>
</div>
</div>
</div>
</main>
<div class="flex-row">
<button
class="standard width-50"
on:click={onboardingViewModel.showTransferOption}
toggle:disabled={
fileTransferViewModel.cannotExitReception
}
>
{coreViewModel.translations.general.backButton}
</button>
<button
class="primary width-50"
on:click={onboardingViewModel.transferData}
>
{coreViewModel.translations.onboarding.transferButton}
<span class="icon">arrow_forward</span>
</button>
</div>
</div>
</div>
);
}
+82 -16
View File
@@ -113,28 +113,33 @@ const englishTranslations = {
},
onboarding: {
connectionHeadline: "Connect to UDN",
connectionDescription: "To transfer files and send messages, connect to the Universal Decentralized Network (UDN).",
connectButton: "Connect",
connectionNextButton: (isConnected: boolean) => isConnected ? "Continue" : "Continue without UDN",
connectionHeadline: "Connect to UDN",
connectionDescription:
"To transfer files and send messages, connect to the Universal Decentralized Network (UDN).",
connectButton: "Connect",
connectionNextButton: (isConnected: boolean): string =>
isConnected ? "Continue" : "Set up without UDN",
///
///
transferOptionsHeadline: "Copy Your Data",
transferOptionsDescription: "If you already use the Coordination Tool on another device, copy your identity here. You can use both devices at the same time.",
transferOptionTransfer: "Copy here",
transferOptionNew: "Set up as new device",
transferOptionsHeadline: "Copy Your Data",
transferOptionsDescription:
"If you already use the Coordination Tool on another device, copy your identity here. You can use both devices at the same time.",
transferOptionTransfer: "Copy my data here",
transferOptionNew: "Set up as new device",
//
//
nameHeadline: "Your Name",
nameDescription: "This is what others see when you send messages. You can always change your name in settings.",
nameHeadline: "Your Name",
nameDescription:
"This is what others see when you send messages. You can always change your name in settings.",
//
//
transferHeadline: "Data Transfer",
transferDescription: 'On your other device, prepare to transfer your identity and personal data alongside any chats you wish to copy. Then, enter the displayed data here.',
transferButton: "Copy data",
transferHeadline: "Data Transfer",
transferDescription:
"On your other device, prepare to transfer your identity and personal data alongside any chats you wish to copy. Then, enter the displayed data here. You can find the data transfer on the home screen of the other device.",
transferButton: "Copy data",
},
connectionModal: {
@@ -487,6 +492,36 @@ export const allTranslations: {
},
},
onboarding: {
connectionHeadline: "Mit UDN verbinden",
connectionDescription:
"Um Daten und Nachichten zu verschicken, verbinde dich mit dem Universellen Dezentralen Netzwerk (UDN).",
connectButton: "Verbinden",
connectionNextButton: (isConnected: boolean) =>
isConnected ? "Weiter" : "Ohne UDN einrichten",
///
transferOptionsHeadline: "Deine Daten kopieren",
transferOptionsDescription:
"Wenn du Coordination Tool bereits auf einem anderen Gerät verwendest, kopiere deine Kontodaten. Du kannst beide Geräte gleichzeitig verwenden.",
transferOptionTransfer: "Daten übertragen",
transferOptionNew: "Als neues Gerät enrichten",
//
nameHeadline: "Dein Name",
nameDescription:
"Diesen Namen sehen andere, wenn du Nachrichten versendest. Du kannst deinen Namen jederzeit in den Einstellungen ändern.",
//
transferHeadline: "Datenübertragung",
transferDescription:
"Verwende die Funktion zur Datenübertragung auf deinem anderen Getät, um deine Identität und persönlichen Daten zu kopieren. Gib die dazu angezeigten Daten unten ein. Du findest die Datenübertragung auf der Startseite des anderen Geräts.",
transferButton: "Daten kopieren",
},
connectionModal: {
connectionModalHeadline: "Verbindungen verwalten",
@@ -804,6 +839,37 @@ export const allTranslations: {
checkUpdatesButton: "Buscar actualisaciones",
},
},
onboarding: {
connectionHeadline: "Conectar al UDN",
connectionDescription:
"Para transferir datos y enviar mensajes, conéctate a la Red Descentralizada Universal (UDN).",
connectButton: "Conectar",
connectionNextButton: (isConnected: boolean): string =>
isConnected ? "Continuar" : "Configurar sin UDN",
///
transferOptionsHeadline: "Copiar tus datos",
transferOptionsDescription:
"Si ya usas el Coordination Tool en otro disposistivo, copia tu idantidad aquí. Puedes usar ambos dispositivos al mismo tiempo.",
transferOptionTransfer: "Copiar mis datos aquí",
transferOptionNew: "Configurar como dispositivo nuevo",
//
nameHeadline: "Tu nombre",
nameDescription:
"Esto es lo que ven otros cuando envías menajes. Siempre lo puedes cambiar en las ajustes.",
//
transferHeadline: "Transferencia de datos",
transferDescription:
"En el otro dispositivo, prepara la transferencia de tu identidad y datos personales. Ingresa los datos que se muestran a continuación. La opción de la transferencia de datos se encuentra en la pantalla inicial en el otro dispositivo.",
transferButton: "Copiar datos",
},
connectionModal: {
connectionModalHeadline: "Gestionar Conexiones",
+4 -1
View File
@@ -101,7 +101,10 @@ export default class ChatListViewModel {
public readonly connectionViewModel: ConnectionViewModel,
public readonly contactListViewModel: ContactListViewModel,
) {
this.notificationViewModel = new NotificationViewModel(this, this.settingsViewModel);
this.notificationViewModel = new NotificationViewModel(
this,
this.settingsViewModel,
);
this.loadChats();
}
+2 -1
View File
@@ -150,7 +150,8 @@ export default class ChatMessageViewModel {
hideForReplyView = false;
else if (
this.inlineReply != undefined &&
selectedMessage.chatMessage.fileId == this.inlineReply.chatMessage.fileId
selectedMessage.chatMessage.fileId ==
this.inlineReply.chatMessage.fileId
)
hideForReplyView = false;
else hideForReplyView = true;
@@ -11,7 +11,7 @@ import ChatModel from "../../Model/Chat/chatModel";
export default class FileTransferViewModel extends Context {
// state
exitReception: ()=>void|undefined = undefined;
exitReception: () => void | undefined = undefined;
presentedModal: React.State<FileTransferModals | undefined> =
new React.State<any>(undefined);
@@ -219,13 +219,13 @@ export default class FileTransferViewModel extends Context {
};
correctTransferData = (): void => {
if (this.exitReception != undefined) {
this.presentedModal.value = undefined;
this.exitReception();
return;
}
this.showTransferDataInputModal()
}
if (this.exitReception != undefined) {
this.presentedModal.value = undefined;
this.exitReception();
return;
}
this.showTransferDataInputModal();
};
initiateTransfer = (): void => {
this.presentedModal.value = FileTransferModals.TransferDisplay;
@@ -1,8 +1,8 @@
import SettingsViewModel from "./settingsViewModel";
import { ChatPageTypes } from "../Chat/chatViewModel";
import ChatListViewModel from "../Chat/chatListViewModel";
import * as React from "../../react";
import ChatModel, { ChatMessage } from "../../Model/Chat/chatModel";
import SettingsViewModel from "./settingsViewModel";
export default class NotificationViewModel {
// data
@@ -16,7 +16,8 @@ export default class NotificationViewModel {
showNotification = (message: ChatMessage): void => {
if (this.seenMessageIds.has(message.fileId)) return;
if (this.chatListViewModel.selectedChat.value == undefined) return;
if (message.senderId == this.settingsViewModel.settingsModel.userid) return;
if (message.senderId == this.settingsViewModel.settingsModel.userid)
return;
const notification: Notification = this.createNotification(message);
const currentChat =
@@ -79,7 +80,10 @@ export default class NotificationViewModel {
};
// init
constructor(public chatListViewModel: ChatListViewModel, public settingsViewModel: SettingsViewModel) {}
constructor(
public chatListViewModel: ChatListViewModel,
public settingsViewModel: SettingsViewModel,
) {}
// util
createNotification(message: ChatMessage): Notification {
+30 -25
View File
@@ -1,52 +1,57 @@
import CoreViewModel from "./coreViewModel";
import * as React from "../../react";
import FileTransferViewModel from "./fileTransferViewModel";
import ConnectionViewModel from "./connectionViewModel";
import SettingsViewModel from "./settingsViewModel";
import FileTransferViewModel from "./fileTransferViewModel";
import CoreViewModel from "./coreViewModel";
import ConnectionViewModel from "./connectionViewModel";
import * as React from "../../react";
export default class OnboardingViewModel {
// state
presentedModal: React.State<OnboardingModals | undefined> = new React.State<any>(undefined);
presentedModal: React.State<OnboardingModals | undefined> =
new React.State<any>(undefined);
// guards
cannotTransfer: React.State<boolean> = React.createProxyState([this.connectionViewmodel.isConnected], ()=>!this.connectionViewmodel.isConnected.value)
cannotTransfer: React.State<boolean> = React.createProxyState(
[this.connectionViewmodel.isConnected],
() => !this.connectionViewmodel.isConnected.value,
);
// navigation
open = (): void => {
this.presentedModal.value = OnboardingModals.Connection;
}
this.presentedModal.value = OnboardingModals.Connection;
};
showTransferOption = (): void => {
this.presentedModal.value = OnboardingModals.TransferOrNew;
}
this.presentedModal.value = OnboardingModals.TransferOrNew;
};
setupNew = (): void => {
this.presentedModal.value = OnboardingModals.Name;
}
this.presentedModal.value = OnboardingModals.Name;
};
showTransferData = (): void => {
this.presentedModal.value = OnboardingModals.Transfer;
}
this.presentedModal.value = OnboardingModals.Transfer;
};
// methods
transferData = (): void => {
this.fileTransferViewModel.exitReception = ()=>this.showTransferData();
this.fileTransferViewModel.prepareReceivingData();
this.presentedModal.value = undefined;
}
this.fileTransferViewModel.exitReception = () =>
this.showTransferData();
this.fileTransferViewModel.prepareReceivingData();
this.presentedModal.value = undefined;
};
finish = (): void => {
this.settingsViewModel.setName();
this.presentedModal.value = undefined;
}
this.settingsViewModel.setName();
this.presentedModal.value = undefined;
};
// init
constructor(
public connectionViewmodel: ConnectionViewModel,
public fileTransferViewModel: FileTransferViewModel,
public settingsViewModel: SettingsViewModel,
public connectionViewmodel: ConnectionViewModel,
public fileTransferViewModel: FileTransferViewModel,
public settingsViewModel: SettingsViewModel,
) {
if (this.settingsViewModel.settingsModel.username == "") this.open();
if (this.settingsViewModel.settingsModel.username == "") this.open();
}
}
+10 -6
View File
@@ -5,6 +5,7 @@ import "./base.css";
import HomeViewModel from "./ViewModel/Pages/homeViewModel";
import StorageViewModel from "./ViewModel/Global/storageViewModel";
import SettingsViewModel from "./ViewModel/Global/settingsViewModel";
import OnboardingViewModel from "./ViewModel/Global/onboardingViewModel";
import FileTransferViewModel from "./ViewModel/Global/fileTransferViewModel";
import CoreViewModel from "./ViewModel/Global/coreViewModel";
import ContactListViewModel from "./ViewModel/Global/contactViewModel";
@@ -14,6 +15,7 @@ import { HomePage } from "./View/homePage";
import { ChatPageWrapper } from "./View/chatPageWrapper";
import { StorageModal } from "./View/Modals/storageModal";
import { SettingsModal } from "./View/Modals/settingsModal";
import { OnboardingModalWrapper } from "./View/Modals/onboardingModal";
import { DataTransferModalWrapper } from "./View/Modals/dataTransferModal";
import { ConnectionModal } from "./View/Modals/connectionModal";
import StorageModel from "./Model/Global/storageModel";
@@ -22,8 +24,6 @@ import FileTransferModel from "./Model/Global/fileTransferModel";
import ContactListModel from "./Model/Global/contactListModel";
import ConnectionModel from "./Model/Global/connectionModel";
import ChatListModel from "./Model/Chat/chatListModel";
import OnboardingViewModel from "./ViewModel/Global/onboardingViewModel";
import {OnboardingModalWrapper} from "./View/Modals/onboardingModal";
// models
const storageModel = new StorageModel();
@@ -61,7 +61,11 @@ const chatListViewModel = new ChatListViewModel(
contactListViewModel,
);
const fileTransferViewModel = new FileTransferViewModel(coreViewModel);
const onboardingViewModel = new OnboardingViewModel(connectionViewModel, fileTransferViewModel, settingsViewModel);
const onboardingViewModel = new OnboardingViewModel(
connectionViewModel,
fileTransferViewModel,
settingsViewModel,
);
const homeViewModel = new HomeViewModel(
coreViewModel,
@@ -97,8 +101,8 @@ document
fileTransferViewModel,
chatListViewModel,
),
ChatPageWrapper(coreViewModel, chatListViewModel),
OnboardingModalWrapper(coreViewModel, onboardingViewModel),
ChatPageWrapper(coreViewModel, chatListViewModel),
OnboardingModalWrapper(coreViewModel, onboardingViewModel),
ConnectionModal(coreViewModel, connectionViewModel),
DataTransferModalWrapper(
coreViewModel,
@@ -106,5 +110,5 @@ document
fileTransferViewModel,
),
StorageModal(coreViewModel, storageViewModel),
SettingsModal(coreViewModel, settingsViewModel),
SettingsModal(coreViewModel, settingsViewModel),
);