Compare commits

...
27 Commits
Author SHA1 Message Date
vd dfbd20e47a Update README.md 2026-10-12 22:27:10 +00:00
vd 307c114999 build 2026-10-13 00:13:29 +02:00
vd daa600b1f7 Merge pull request '2610r1' (#2) from 2610R1 into main
Reviewed-on: https://viridian.vd/VDMDI/CT/pulls/2
2026-10-13 00:12:26 +02:00
vd 42bd0a59c2 implement legal information translations 2026-10-12 23:53:59 +02:00
vd 4956e26af9 implement legal dialog in english 2026-10-12 22:51:11 +02:00
vd ab1cfbd308 prepare 2610R1 2026-10-12 22:05:16 +02:00
vd 6d6cc5564a fix timezone 2026-10-11 00:12:32 +02:00
vd 050900aa2f update release note 2026-10-11 00:12:03 +02:00
vd 7aefc7e15f 2610 2026-10-11 00:09:46 +02:00
vd 94697f5876 add keystrokes for exiting reply view 2026-10-09 23:09:44 +02:00
vd 6ef6996522 build 2026-10-09 19:40:48 +02:00
vd d5a5132dbd minor adjustments 2026-10-09 19:40:30 +02:00
Viridian 88e415b69f Update README.md 2026-10-09 16:26:39 +02:00
Viridian 346f5c4e1d Update README.md 2026-10-09 16:25:01 +02:00
vd fbbfbedcd7 update README 2026-10-09 16:19:39 +02:00
vd 651c9bd29d add button to share chat, add VDMDI tag, fixes 2026-10-09 16:14:32 +02:00
vd 73344644e7 update instructions 2026-10-09 02:40:28 +02:00
vd ee6454a296 support vdpr url 2026-10-09 02:01:43 +02:00
Marlon Erler 8a275ab51a Delete ; 2026-10-04 22:16:20 +02:00
marlon-erler 4bd9dc25f2 typo 2026-10-04 22:14:32 +02:00
marlon-erler 3d523d5e38 update translations 2026-10-04 22:14:04 +02:00
Marlon Erler 71c454980f Update README.md 2026-10-04 22:11:41 +02:00
marlon-erler 5184d21d13 update readme 2026-10-04 22:06:00 +02:00
marlon-erler f05e5f8f00 add dialog to confirm chat deletion 2026-10-02 18:32:22 +02:00
marlon-erler 6ec3355aeb dist 2026-10-01 22:17:04 +02:00
marlon-erler df99b485a4 fix ribbon overflow 2026-10-01 22:16:53 +02:00
marlon-erler a17cec9a79 fix greetings 2026-10-01 21:27:43 +02:00
23 changed files with 2099 additions and 1020 deletions
+550 -15
View File
@@ -145,10 +145,14 @@ if &shortmess =~ 'A'
else else
set shortmess=aoO set shortmess=aoO
endif endif
badd +21 build/sw.js badd +1 build/sw.js
badd +0 build/version.txt badd +1 build/version.txt
badd +0 src/View/translations.ts
argglobal argglobal
%argdel %argdel
set stal=2
tabnew +setlocal\ bufhidden=wipe
tabrewind
edit build/sw.js edit build/sw.js
let s:save_splitbelow = &splitbelow let s:save_splitbelow = &splitbelow
let s:save_splitright = &splitright let s:save_splitright = &splitright
@@ -169,13 +173,13 @@ set winminheight=0
set winheight=1 set winheight=1
set winminwidth=0 set winminwidth=0
set winwidth=1 set winwidth=1
exe 'vert 1resize ' . ((&columns * 31 + 111) / 223) exe 'vert 1resize ' . ((&columns * 31 + 150) / 300)
exe 'vert 2resize ' . ((&columns * 95 + 111) / 223) exe 'vert 2resize ' . ((&columns * 133 + 150) / 300)
exe 'vert 3resize ' . ((&columns * 95 + 111) / 223) exe 'vert 3resize ' . ((&columns * 134 + 150) / 300)
argglobal argglobal
enew enew
file NERD_tree_tab_1 file NERD_tree_tab_2
balt build/sw.js balt build/version.txt
let s:cpo_save=&cpo let s:cpo_save=&cpo
set cpo&vim set cpo&vim
nnoremap <buffer> <silent> <NL> :call nerdtree#ui_glue#invokeKeyMap("<C-j>") nnoremap <buffer> <silent> <NL> :call nerdtree#ui_glue#invokeKeyMap("<C-j>")
@@ -355,7 +359,6 @@ setlocal nowrap
setlocal wrapmargin=0 setlocal wrapmargin=0
wincmd w wincmd w
argglobal argglobal
balt build/sw.js
let s:cpo_save=&cpo let s:cpo_save=&cpo
set cpo&vim set cpo&vim
nmap <buffer> [c <Plug>(GitGutterPrevHunk) nmap <buffer> [c <Plug>(GitGutterPrevHunk)
@@ -503,7 +506,7 @@ setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let &fdl = &fdl let &fdl = &fdl
let s:l = 1 - ((0 * winheight(0) + 17) / 34) let s:l = 1 - ((0 * winheight(0) + 16) / 32)
if s:l < 1 | let s:l = 1 | endif if s:l < 1 | let s:l = 1 | endif
keepjumps exe s:l keepjumps exe s:l
normal! zt normal! zt
@@ -660,18 +663,551 @@ setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
let &fdl = &fdl let &fdl = &fdl
let s:l = 1 - ((0 * winheight(0) + 17) / 34) let s:l = 1 - ((0 * winheight(0) + 16) / 32)
if s:l < 1 | let s:l = 1 | endif if s:l < 1 | let s:l = 1 | endif
keepjumps exe s:l keepjumps exe s:l
normal! zt normal! zt
keepjumps 1 keepjumps 1
normal! 0 normal! 0
wincmd w wincmd w
exe 'vert 1resize ' . ((&columns * 31 + 150) / 300)
exe 'vert 2resize ' . ((&columns * 133 + 150) / 300)
exe 'vert 3resize ' . ((&columns * 134 + 150) / 300)
tabnext
edit src/View/translations.ts
let s:save_splitbelow = &splitbelow
let s:save_splitright = &splitright
set splitbelow splitright
wincmd _ | wincmd |
vsplit
wincmd _ | wincmd |
vsplit
2wincmd h
wincmd w
wincmd w
let &splitbelow = s:save_splitbelow
let &splitright = s:save_splitright
wincmd t
let s:save_winminheight = &winminheight
let s:save_winminwidth = &winminwidth
set winminheight=0
set winheight=1
set winminwidth=0
set winwidth=1
exe 'vert 1resize ' . ((&columns * 31 + 150) / 300)
exe 'vert 2resize ' . ((&columns * 133 + 150) / 300)
exe 'vert 3resize ' . ((&columns * 134 + 150) / 300)
argglobal
enew
file NERD_tree_tab_3
balt src/View/translations.ts
let s:cpo_save=&cpo
set cpo&vim
nnoremap <buffer> <silent> <NL> :call nerdtree#ui_glue#invokeKeyMap("<C-j>")
nnoremap <buffer> <silent>  :call nerdtree#ui_glue#invokeKeyMap("<C-k>")
nnoremap <buffer> <silent> ␍ :call nerdtree#ui_glue#invokeKeyMap("<CR>")
nnoremap <buffer> <silent> ? :call nerdtree#ui_glue#invokeKeyMap("?")
nnoremap <buffer> <silent> A :call nerdtree#ui_glue#invokeKeyMap("A")
nnoremap <buffer> <silent> B :call nerdtree#ui_glue#invokeKeyMap("B")
nnoremap <buffer> <silent> C :call nerdtree#ui_glue#invokeKeyMap("C")
nnoremap <buffer> <silent> CD :call nerdtree#ui_glue#invokeKeyMap("CD")
nnoremap <buffer> <silent> D :call nerdtree#ui_glue#invokeKeyMap("D")
nnoremap <buffer> <silent> FL :call nerdtree#ui_glue#invokeKeyMap("FL")
nnoremap <buffer> <silent> F :call nerdtree#ui_glue#invokeKeyMap("F")
nnoremap <buffer> <silent> I :call nerdtree#ui_glue#invokeKeyMap("I")
nnoremap <buffer> <silent> J :call nerdtree#ui_glue#invokeKeyMap("J")
nnoremap <buffer> <silent> K :call nerdtree#ui_glue#invokeKeyMap("K")
nnoremap <buffer> <silent> O :call nerdtree#ui_glue#invokeKeyMap("O")
nnoremap <buffer> <silent> P :call nerdtree#ui_glue#invokeKeyMap("P")
nnoremap <buffer> <silent> R :call nerdtree#ui_glue#invokeKeyMap("R")
nnoremap <buffer> <silent> T :call nerdtree#ui_glue#invokeKeyMap("T")
nnoremap <buffer> <silent> U :call nerdtree#ui_glue#invokeKeyMap("U")
nnoremap <buffer> <silent> X :call nerdtree#ui_glue#invokeKeyMap("X")
nmap <buffer> [c <Plug>(GitGutterPrevHunk)
nmap <buffer> \hp <Plug>(GitGutterPreviewHunk)
nmap <buffer> \hu <Plug>(GitGutterUndoHunk)
nmap <buffer> \hs <Plug>(GitGutterStageHunk)
xmap <buffer> \hs <Plug>(GitGutterStageHunk)
nmap <buffer> ]c <Plug>(GitGutterNextHunk)
xmap <buffer> ac <Plug>(GitGutterTextObjectOuterVisual)
omap <buffer> ac <Plug>(GitGutterTextObjectOuterPending)
nnoremap <buffer> <silent> cd :call nerdtree#ui_glue#invokeKeyMap("cd")
nnoremap <buffer> <silent> e :call nerdtree#ui_glue#invokeKeyMap("e")
nnoremap <buffer> <silent> f :call nerdtree#ui_glue#invokeKeyMap("f")
nnoremap <buffer> <silent> go :call nerdtree#ui_glue#invokeKeyMap("go")
nnoremap <buffer> <silent> gb :call nerdtree#ui_glue#invokeKeyMap("gb")
nnoremap <buffer> <silent> gi :call nerdtree#ui_glue#invokeKeyMap("gi")
nnoremap <buffer> <silent> gs :call nerdtree#ui_glue#invokeKeyMap("gs")
nnoremap <buffer> <silent> i :call nerdtree#ui_glue#invokeKeyMap("i")
xmap <buffer> ic <Plug>(GitGutterTextObjectInnerVisual)
omap <buffer> ic <Plug>(GitGutterTextObjectInnerPending)
nnoremap <buffer> <silent> m :call nerdtree#ui_glue#invokeKeyMap("m")
nnoremap <buffer> <silent> o :call nerdtree#ui_glue#invokeKeyMap("o")
nnoremap <buffer> <silent> p :call nerdtree#ui_glue#invokeKeyMap("p")
nnoremap <buffer> <silent> q :call nerdtree#ui_glue#invokeKeyMap("q")
nnoremap <buffer> <silent> r :call nerdtree#ui_glue#invokeKeyMap("r")
nnoremap <buffer> <silent> s :call nerdtree#ui_glue#invokeKeyMap("s")
nnoremap <buffer> <silent> t :call nerdtree#ui_glue#invokeKeyMap("t")
nnoremap <buffer> <silent> u :call nerdtree#ui_glue#invokeKeyMap("u")
nnoremap <buffer> <silent> x :call nerdtree#ui_glue#invokeKeyMap("x")
nnoremap <buffer> <silent> <MiddleMouse> :call nerdtree#ui_glue#invokeKeyMap("<MiddleMouse>")
nnoremap <buffer> <silent> <2-LeftMouse> :call nerdtree#ui_glue#invokeKeyMap("<2-LeftMouse>")
nnoremap <buffer> <silent> <C-K> :call nerdtree#ui_glue#invokeKeyMap("<C-k>")
nnoremap <buffer> <silent> <C-J> :call nerdtree#ui_glue#invokeKeyMap("<C-j>")
nnoremap <buffer> <silent> <LeftRelease> <LeftRelease>:call nerdtree#ui_glue#invokeKeyMap("<LeftRelease>")
let &cpo=s:cpo_save
unlet s:cpo_save
setlocal keymap=
setlocal noarabic
setlocal noautoindent
setlocal backupcopy=
setlocal balloonexpr=
setlocal nobinary
setlocal nobreakindent
setlocal breakindentopt=
setlocal bufhidden=hide
setlocal nobuflisted
setlocal buftype=nofile
setlocal nocindent
setlocal cinkeys=0{,0},0),0],:,0#,!^F,o,O,e
setlocal cinoptions=
setlocal cinscopedecls=public,protected,private
setlocal cinwords=if,else,while,do,for,switch
setlocal colorcolumn=
setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-
setlocal commentstring=/*%s*/
setlocal complete=.,w,b,u,t,i
setlocal concealcursor=nvic
setlocal conceallevel=2
setlocal completefunc=
setlocal nocopyindent
setlocal cryptmethod=
setlocal nocursorbind
setlocal nocursorcolumn
setlocal cursorline
setlocal cursorlineopt=both
setlocal define=
setlocal dictionary=
setlocal nodiff
setlocal equalprg=
setlocal errorformat=
setlocal noexpandtab
if &filetype != 'nerdtree'
setlocal filetype=nerdtree
endif
setlocal fillchars=
setlocal fixendofline
setlocal foldcolumn=0
setlocal nofoldenable
setlocal foldexpr=0
setlocal foldignore=#
setlocal foldlevel=0
setlocal foldmarker={{{,}}}
setlocal foldmethod=manual
setlocal foldminlines=1
setlocal foldnestmax=20
setlocal foldtext=foldtext()
setlocal formatexpr=
setlocal formatoptions=tcq
setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s*
setlocal formatprg=
setlocal grepprg=
setlocal iminsert=0
setlocal imsearch=-1
setlocal include=
setlocal includeexpr=
setlocal indentexpr=
setlocal indentkeys=0{,0},0),0],:,0#,!^F,o,O,e
setlocal noinfercase
setlocal iskeyword=@,48-57,_,192-255
setlocal keywordprg=
setlocal nolinebreak
setlocal nolisp
setlocal lispoptions=
setlocal lispwords=
setlocal nolist
setlocal listchars=
setlocal makeencoding=
setlocal makeprg=
setlocal matchpairs=(:),{:},[:]
setlocal nomodeline
setlocal nomodifiable
setlocal nrformats=bin,octal,hex
set number
setlocal nonumber
setlocal numberwidth=4
setlocal omnifunc=
setlocal path=
setlocal nopreserveindent
setlocal nopreviewwindow
setlocal quoteescape=\\
setlocal readonly
setlocal norelativenumber
setlocal norightleft
setlocal rightleftcmd=search
setlocal noscrollbind
setlocal scrolloff=-1
setlocal shiftwidth=4
setlocal noshortname
setlocal showbreak=
setlocal sidescrolloff=-1
set signcolumn=yes
setlocal signcolumn=yes
setlocal nosmartindent
setlocal nosmoothscroll
setlocal softtabstop=0
setlocal nospell
setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+
setlocal spellfile=
setlocal spelllang=en
setlocal spelloptions=
setlocal statusline=%{exists('b:NERDTree')?b:NERDTree.root.path.str():''}
setlocal suffixesadd=
setlocal noswapfile
setlocal synmaxcol=3000
if &syntax != 'nerdtree'
setlocal syntax=nerdtree
endif
setlocal tabstop=8
setlocal tagcase=
setlocal tagfunc=
setlocal tags=
setlocal termwinkey=
setlocal termwinscroll=10000
setlocal termwinsize=
setlocal textwidth=0
setlocal thesaurus=
setlocal thesaurusfunc=
setlocal noundofile
setlocal undolevels=-123456
setlocal varsofttabstop=
setlocal vartabstop=
setlocal virtualedit=
setlocal wincolor=
setlocal nowinfixheight
setlocal winfixwidth
setlocal nowrap
setlocal wrapmargin=0
wincmd w
argglobal
balt build/version.txt
let s:cpo_save=&cpo
set cpo&vim
nmap <buffer> [c <Plug>(GitGutterPrevHunk)
nmap <buffer> \hp <Plug>(GitGutterPreviewHunk)
nmap <buffer> \hu <Plug>(GitGutterUndoHunk)
nmap <buffer> \hs <Plug>(GitGutterStageHunk)
xmap <buffer> \hs <Plug>(GitGutterStageHunk)
nmap <buffer> ]c <Plug>(GitGutterNextHunk)
xmap <buffer> ac <Plug>(GitGutterTextObjectOuterVisual)
omap <buffer> ac <Plug>(GitGutterTextObjectOuterPending)
xmap <buffer> ic <Plug>(GitGutterTextObjectInnerVisual)
omap <buffer> ic <Plug>(GitGutterTextObjectInnerPending)
let &cpo=s:cpo_save
unlet s:cpo_save
setlocal keymap=
setlocal noarabic
setlocal autoindent
setlocal backupcopy=
setlocal balloonexpr=
setlocal nobinary
setlocal nobreakindent
setlocal breakindentopt=
setlocal bufhidden=
setlocal buflisted
setlocal buftype=
setlocal nocindent
setlocal cinkeys=0{,0},0),0],:,0#,!^F,o,O,e
setlocal cinoptions=
setlocal cinscopedecls=public,protected,private
setlocal cinwords=if,else,while,do,for,switch
setlocal colorcolumn=
setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-
setlocal commentstring=//\ %s
setlocal complete=.,w,b,u,t,i
setlocal concealcursor=
setlocal conceallevel=0
setlocal completefunc=
setlocal nocopyindent
setlocal cryptmethod=
setlocal nocursorbind
setlocal nocursorcolumn
setlocal nocursorline
setlocal cursorlineopt=both
setlocal define=
setlocal dictionary=
setlocal nodiff
setlocal equalprg=
setlocal errorformat=%+A\ %#%f\ %#(%l\\,%c):\ %m,%C%m
setlocal noexpandtab
if &filetype != 'typescript'
setlocal filetype=typescript
endif
setlocal fillchars=
setlocal fixendofline
setlocal foldcolumn=0
setlocal foldenable
setlocal foldexpr=0
setlocal foldignore=#
setlocal foldlevel=0
setlocal foldmarker={{{,}}}
setlocal foldmethod=manual
setlocal foldminlines=1
setlocal foldnestmax=20
setlocal foldtext=foldtext()
setlocal formatexpr=
setlocal formatoptions=croql
setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s*
setlocal formatprg=
setlocal grepprg=
setlocal iminsert=0
setlocal imsearch=-1
setlocal include=
setlocal includeexpr=
setlocal indentexpr=GetTypescriptIndent()
setlocal indentkeys=0{,0},0),0],:,0#,!^F,o,O,e,0],0)
setlocal noinfercase
setlocal iskeyword=@,48-57,_,192-255,$
setlocal keywordprg=
setlocal nolinebreak
setlocal nolisp
setlocal lispoptions=
setlocal lispwords=
setlocal nolist
setlocal listchars=
setlocal makeencoding=
setlocal makeprg=tsc\ \ $*\ %
setlocal matchpairs=(:),{:},[:]
setlocal nomodeline
setlocal modifiable
setlocal nrformats=bin,octal,hex
set number
setlocal number
setlocal numberwidth=4
setlocal omnifunc=
setlocal path=
setlocal nopreserveindent
setlocal nopreviewwindow
setlocal quoteescape=\\
setlocal noreadonly
setlocal norelativenumber
setlocal norightleft
setlocal rightleftcmd=search
setlocal noscrollbind
setlocal scrolloff=-1
setlocal shiftwidth=4
setlocal noshortname
setlocal showbreak=
setlocal sidescrolloff=-1
set signcolumn=yes
setlocal signcolumn=yes
setlocal nosmartindent
setlocal nosmoothscroll
setlocal softtabstop=0
setlocal nospell
setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+
setlocal spellfile=
setlocal spelllang=en
setlocal spelloptions=
setlocal statusline=
setlocal suffixesadd=.ts,.tsx
setlocal swapfile
setlocal synmaxcol=3000
if &syntax != 'typescript'
setlocal syntax=typescript
endif
setlocal tabstop=8
setlocal tagcase=
setlocal tagfunc=
setlocal tags=
setlocal termwinkey=
setlocal termwinscroll=10000
setlocal termwinsize=
setlocal textwidth=0
setlocal thesaurus=
setlocal thesaurusfunc=
setlocal noundofile
setlocal undolevels=-123456
setlocal varsofttabstop=
setlocal vartabstop=
setlocal virtualedit=
setlocal wincolor=
setlocal nowinfixheight
setlocal nowinfixwidth
setlocal wrap
setlocal wrapmargin=0
silent! normal! zE
let &fdl = &fdl
let s:l = 81 - ((20 * winheight(0) + 15) / 31)
if s:l < 1 | let s:l = 1 | endif
keepjumps exe s:l
normal! zt
keepjumps 81
normal! 0
wincmd w
argglobal
if bufexists(fnamemodify("src/View/translations.ts", ":p")) | buffer src/View/translations.ts | else | edit src/View/translations.ts | endif
balt build/version.txt
let s:cpo_save=&cpo
set cpo&vim
nmap <buffer> [c <Plug>(GitGutterPrevHunk)
nmap <buffer> \hp <Plug>(GitGutterPreviewHunk)
nmap <buffer> \hu <Plug>(GitGutterUndoHunk)
nmap <buffer> \hs <Plug>(GitGutterStageHunk)
xmap <buffer> \hs <Plug>(GitGutterStageHunk)
nmap <buffer> ]c <Plug>(GitGutterNextHunk)
xmap <buffer> ac <Plug>(GitGutterTextObjectOuterVisual)
omap <buffer> ac <Plug>(GitGutterTextObjectOuterPending)
xmap <buffer> ic <Plug>(GitGutterTextObjectInnerVisual)
omap <buffer> ic <Plug>(GitGutterTextObjectInnerPending)
let &cpo=s:cpo_save
unlet s:cpo_save
setlocal keymap=
setlocal noarabic
setlocal autoindent
setlocal backupcopy=
setlocal balloonexpr=
setlocal nobinary
setlocal nobreakindent
setlocal breakindentopt=
setlocal bufhidden=
setlocal buflisted
setlocal buftype=
setlocal nocindent
setlocal cinkeys=0{,0},0),0],:,0#,!^F,o,O,e
setlocal cinoptions=
setlocal cinscopedecls=public,protected,private
setlocal cinwords=if,else,while,do,for,switch
setlocal colorcolumn=
setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-
setlocal commentstring=//\ %s
setlocal complete=.,w,b,u,t,i
setlocal concealcursor=
setlocal conceallevel=0
setlocal completefunc=
setlocal nocopyindent
setlocal cryptmethod=
setlocal nocursorbind
setlocal nocursorcolumn
setlocal nocursorline
setlocal cursorlineopt=both
setlocal define=
setlocal dictionary=
setlocal nodiff
setlocal equalprg=
setlocal errorformat=%+A\ %#%f\ %#(%l\\,%c):\ %m,%C%m
setlocal noexpandtab
if &filetype != 'typescript'
setlocal filetype=typescript
endif
setlocal fillchars=
setlocal fixendofline
setlocal foldcolumn=0
setlocal foldenable
setlocal foldexpr=0
setlocal foldignore=#
setlocal foldlevel=0
setlocal foldmarker={{{,}}}
setlocal foldmethod=manual
setlocal foldminlines=1
setlocal foldnestmax=20
setlocal foldtext=foldtext()
setlocal formatexpr=
setlocal formatoptions=croql
setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s*
setlocal formatprg=
setlocal grepprg=
setlocal iminsert=0
setlocal imsearch=-1
setlocal include=
setlocal includeexpr=
setlocal indentexpr=GetTypescriptIndent()
setlocal indentkeys=0{,0},0),0],:,0#,!^F,o,O,e,0],0)
setlocal noinfercase
setlocal iskeyword=@,48-57,_,192-255,$
setlocal keywordprg=
setlocal nolinebreak
setlocal nolisp
setlocal lispoptions=
setlocal lispwords=
setlocal nolist
setlocal listchars=
setlocal makeencoding=
setlocal makeprg=tsc\ \ $*\ %
setlocal matchpairs=(:),{:},[:]
setlocal nomodeline
setlocal modifiable
setlocal nrformats=bin,octal,hex
set number
setlocal number
setlocal numberwidth=4
setlocal omnifunc=
setlocal path=
setlocal nopreserveindent
setlocal nopreviewwindow
setlocal quoteescape=\\
setlocal noreadonly
setlocal norelativenumber
setlocal norightleft
setlocal rightleftcmd=search
setlocal noscrollbind
setlocal scrolloff=-1
setlocal shiftwidth=4
setlocal noshortname
setlocal showbreak=
setlocal sidescrolloff=-1
set signcolumn=yes
setlocal signcolumn=yes
setlocal nosmartindent
setlocal nosmoothscroll
setlocal softtabstop=0
setlocal nospell
setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+
setlocal spellfile=
setlocal spelllang=en
setlocal spelloptions=
setlocal statusline=
setlocal suffixesadd=.ts,.tsx
setlocal swapfile
setlocal synmaxcol=3000
if &syntax != 'typescript'
setlocal syntax=typescript
endif
setlocal tabstop=8
setlocal tagcase=
setlocal tagfunc=
setlocal tags=
setlocal termwinkey=
setlocal termwinscroll=10000
setlocal termwinsize=
setlocal textwidth=0
setlocal thesaurus=
setlocal thesaurusfunc=
setlocal noundofile
setlocal undolevels=-123456
setlocal varsofttabstop=
setlocal vartabstop=
setlocal virtualedit=
setlocal wincolor=
setlocal nowinfixheight
setlocal nowinfixwidth
setlocal wrap
setlocal wrapmargin=0
silent! normal! zE
let &fdl = &fdl
let s:l = 12 - ((11 * winheight(0) + 15) / 31)
if s:l < 1 | let s:l = 1 | endif
keepjumps exe s:l
normal! zt
keepjumps 12
normal! $
wincmd w
3wincmd w 3wincmd w
exe 'vert 1resize ' . ((&columns * 31 + 111) / 223) exe 'vert 1resize ' . ((&columns * 31 + 150) / 300)
exe 'vert 2resize ' . ((&columns * 95 + 111) / 223) exe 'vert 2resize ' . ((&columns * 133 + 150) / 300)
exe 'vert 3resize ' . ((&columns * 95 + 111) / 223) exe 'vert 3resize ' . ((&columns * 134 + 150) / 300)
tabnext 1 tabnext 2
set stal=1
if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0 if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0
silent exe 'bwipe ' . s:wipebuf silent exe 'bwipe ' . s:wipebuf
endif endif
@@ -685,7 +1221,6 @@ if filereadable(s:sx)
exe "source " . fnameescape(s:sx) exe "source " . fnameescape(s:sx)
endif endif
let &g:so = s:so_save | let &g:siso = s:siso_save let &g:so = s:so_save | let &g:siso = s:siso_save
nohlsearch
doautoall SessionLoadPost doautoall SessionLoadPost
unlet SessionLoad unlet SessionLoad
" vim: set ft=vim : " vim: set ft=vim :
+64 -11
View File
@@ -1,16 +1,69 @@
# udn-comms # CT (UDN Coordination Tool)
UDN-Comms is a messenger built for [UDN](https://github.com/marlon-erler/universal-decentralized-network). <img height="128px" src="https://vdpr.org/VDMDI/CT/raw/branch/main/dist/vdmdi-logo.png" />
<img height="128px" src="https://vdpr.org/VDMDI/CT/raw/branch/main/dist/icon.png" />
# Features ---
- Offline support > [!NOTE]
- Encryption > **LOCAL DEVELOPMENT**
- Secondary channels >
> This repository is updated for public releases and announcements only.
# Getting Started > [!NOTE]
> **PUBLIC PROJECT**
>
> This repository is maintained by VDMDI as a public project under the GPL-3.0 license. The software is independent of Viridian infrastructure.
1. Use or install the web app [here](https://udn-comms.onrender.com/) CT is a messenger and task management application built for [UDN](https://vdpr.org/VDMDI/udn).
2. Enter your name
3. Connect to your server -> **VDMDI provides a UDN server on VDPR infrastructure at `wss://udn.vdpr.org`.**
4. Create a chat and start messaging
# Installation
CT is available as a PWA at [https://ct.vdpr.org](https://ct.vdpr.org).
To install, open this website and:
- For Safari: share, then "add to home screen" or "add to dock"
- For Chrome on mobile: ⋮, "install and create shortcut", then install
- For Chrome on desktop: ⋮, "cast, save, and share", then "install page as app"
# Core Features
- Offline support, updates download in background
- Messaging including reactions, inline replies, and message-replies-only view
- Task management with Kanban and Status Grid view
- Calendar for tasks
- Data transfer and export/import for identity, connections, and chats
# Update Cycle
- Updates are published monthly
- Version numbers are a combination of year and months, e.g. 2610 for October 2026
- Specific release dates and notes are published within two weeks of the release
# Changes
## 2610 First Revision
- Add legal information regarding data processing
- Add links to imprint and provider information
## 2610 - Published on 11OCT at 0011 CEST
This application is a rebrand of Comms, whose development started in July 2024. Changelogs or versioning have not been present initially and were never standardised. The CT repository is a fork of Comms. Changes made between the lastest iteration of Comms and CT 2610 include:
- Account and chat identity:
- Use a randomized UUID to identify users instead of manually entered names
- Integrate a contacts model to keep track of who sent messages, and to reflect name changes
- Replace primary channels and namespaces with randomized UUIDs and chat names, sync chat settings (name, colour, secondary channels)
- Add a button to share chat access to the chat settings page
- Messaging:
- Add inline replies and message reactions
- Messages can be filtered based on reactions or content
- Task management and calendar:
- Implement pinch to zoom on kanban and grid view for better overview
- Highlight the next event in the calendar sidebar
- Improve handling of task filters
- Improve layout of tasks settings view
- UI improvements:
- Show how much storage is used and remaining in storage management view
- Show data transfer progress
- Other improvements
+1 -1
View File
@@ -445,7 +445,7 @@ body[showing-chat] #chat-page-wrapper {
justify-content: space-between; justify-content: space-between;
} }
#chat-page > div > #ribbon > span { #chat-page > div > #ribbon > span {
overflow-y: auto; overflow-x: hidden;
flex-direction: column; flex-direction: column;
justify-content: end; justify-content: end;
} }
+203 -25
View File
@@ -348,13 +348,14 @@
greeting: (name) => `Hi ${name}`, greeting: (name) => `Hi ${name}`,
/// ///
serverAddress: "Server address", serverAddress: "Server address",
serverAddressPlaceholder: "wss://192.168.0.69:3000", serverAddressPlaceholder: "wss://udn.vdpr.org",
connectAudioLabel: "connect to server", connectAudioLabel: "connect to server",
disconnectAudioLabel: "disconnect from server", disconnectAudioLabel: "disconnect from server",
manageConnectionsAudioLabel: "manage connections", manageConnectionsAudioLabel: "manage connections",
settingsButton: "Settings", settingsButton: "Settings",
manageStorageButton: "Manage storage", manageStorageButton: "Manage storage",
transferDataButton: "Transfer or export data", transferDataButton: "Transfer or export data",
legalButton: "Legal information",
updateButton: (version) => `Update to ${version}`, updateButton: (version) => `Update to ${version}`,
/// ///
typeChat: "chat", typeChat: "chat",
@@ -385,9 +386,25 @@
}, },
about: { about: {
version: "Version", version: "Version",
checkUpdatesButton: "Check for updates" checkUpdatesButton: "Check for updates",
brand: "Developed by VDMDI",
brandDescription: "Code available on Viridian Public Resources (VDPR)"
} }
}, },
legal: {
legalHeadline: "Legal Information",
legalDescription: "CT is open source software published and distributed under the GPL-3.0 license.",
privacyLabel: "Privacy and Application Data",
privacyDescription: "CT stores data on your device. No data is stored on the server hosting this instance of CT, except for data necessary to provide a website. This data is handled and processed by the infrastructure provider (data processor).",
udnLabel: "UDN Servers and Communications",
udnDescription: "The UDN servers you connect to are separate and independent from CT. After connecting or while connected to a server, chats you create and the entities contained therein, including but not limited to messages, boards, and tasks, are transferred to the respective UDN server. Confer the privacy policy of that server for more information.",
rightsLabel: "Your Rights",
rightsDescription: "You have the right to object to any processing of your data under Art. 21 GDPR, and to request access, changes, and deletion to/of your data under Art. 15, 16, and 17 GDPR by contacting the operator and/or processor. You have the right to lodge a complaint with a data protection supervisory authority under Art. 77 GDPR.",
imprintLabel: "Imprint",
imprintDescription: "Contact information of the data controller (operator) providing this instance of CT",
infrastructureLabel: "Infrastructure",
infrastructureDescription: "Contact information of the data processor (provider) hosting this instance of CT on behalf of the operator"
},
onboarding: { onboarding: {
connectionHeadline: "Connect to UDN", connectionHeadline: "Connect to UDN",
connectionDescription: "To transfer files and send messages, connect to the Universal Decentralized Network (UDN).", connectionDescription: "To transfer files and send messages, connect to the Universal Decentralized Network (UDN).",
@@ -472,6 +489,7 @@
settingsHeadline: "Settings", settingsHeadline: "Settings",
nameLabel: "Chat name", nameLabel: "Chat name",
setNameButtonAudioLabel: "set name", setNameButtonAudioLabel: "set name",
transferLabel: "Share chat",
newSecondaryChannelPlaceholder: "Add secondary channel", newSecondaryChannelPlaceholder: "Add secondary channel",
newSecondaryChannelAudioLabel: "name of new secondary channel", newSecondaryChannelAudioLabel: "name of new secondary channel",
addSecondaryChannelButtonAudioLabel: "add secondary channel", addSecondaryChannelButtonAudioLabel: "add secondary channel",
@@ -480,7 +498,9 @@
showEncryptionKey: "Show encryption key", showEncryptionKey: "Show encryption key",
randomizeKey: "Randomize", randomizeKey: "Randomize",
setColorButtonAudioLabel: "set color", setColorButtonAudioLabel: "set color",
deleteChatButton: "Delete entire chat" deleteChatButton: "Delete entire chat",
deleteChatHeadline: "Delete chat?",
deleteChatDescription: "This will delete all messages, tasks, and other data related to this chat from device."
}, },
message: { message: {
messagesHeadline: "Messages", messagesHeadline: "Messages",
@@ -619,15 +639,16 @@
}, },
homePage: { homePage: {
appName: "Coordination Tool", appName: "Coordination Tool",
greeting: (name) => `Hi ${name}!`, greeting: (name) => `Hallo ${name}`,
serverAddress: "Serveradresse", serverAddress: "Serveradresse",
serverAddressPlaceholder: "wss://192.168.0.69:3000", serverAddressPlaceholder: "wss://udn.vdpr.org",
connectAudioLabel: "mit Server verbinden", connectAudioLabel: "mit Server verbinden",
disconnectAudioLabel: "vom Server trennen", disconnectAudioLabel: "vom Server trennen",
manageConnectionsAudioLabel: "Verbindungen verwalten", manageConnectionsAudioLabel: "Verbindungen verwalten",
settingsButton: "Einstellungen", settingsButton: "Einstellungen",
manageStorageButton: "Daten verwalten", manageStorageButton: "Daten verwalten",
transferDataButton: "Daten \xFCbertragen", transferDataButton: "Daten \xFCbertragen",
legalButton: "Rechtliches",
updateButton: (version) => `Aktualisieren: ${version}`, updateButton: (version) => `Aktualisieren: ${version}`,
typeChat: "Chat", typeChat: "Chat",
noChatsPlaceholder: "Keine Chats" noChatsPlaceholder: "Keine Chats"
@@ -657,9 +678,25 @@
}, },
about: { about: {
version: "Version", version: "Version",
checkUpdatesButton: "Nach Updates suchen" checkUpdatesButton: "Nach Updates suchen",
brand: "Software von VDMDI",
brandDescription: "Code verf\xFCgbar auf Viridian Public Resources (VDPR)"
} }
}, },
legal: {
legalHeadline: "Rechtliche Informationen",
legalDescription: "CT ist open-source Software. Ver\xF6ffentlichung und Verbreitung unterliegen der GPL-3.0 Lizenz.",
privacyLabel: "Privatsph\xE4re und Programmdaten",
privacyDescription: "CT speichert Daten auf deinem Ger\xE4t. Daten werden grunds\xE4tzlich nicht auf dem Server gespeichert, der diese Instanz von CT bereitstellt. Davon ausgenommen sind zum Betrieb der Website notwendigen Daten. Diese Daten werden durch den Auftragsverarbeiter verarbeitet, der die Bereitstellung dieser Website erm\xF6glicht.",
udnLabel: "UDN Server und Kommunikation",
udnDescription: "Die UDN Server mit denen du dich verbindest sind separat und unabh\xE4ngig von CT. Beim Verbinden und wenn du mit einem Server verbunden bist, werden von dir erstellte Chats sowie die darin enthaltenen Objekte wie unter anderem Nachrichten, Boards und Aufgaben an diesen Server \xFCbermittelt. F\xFCr mehr Informationen siehe die Datenschutzerkl\xE4rung des entsprechenden Servers.",
rightsLabel: "Deine Rechte",
rightsDescription: "Du hast das Recht, der Verarbeitung deiner Daten zu widersprechen (Art. 21 DSGVO), oder Auskunft \xFCber sowie Berichtigung oder L\xF6schung deiner Daten zu beantragen (Art. 15-17 DSGVO), indem du den f\xFCr den Betrieb dieser Seite Verantwortlichen oder den entsprechenden Auftragsverarbeiter kontaktierst. Du hast zudem das Recht zur Beschwerde bei einer Datenschutzaufsichtsbeh\xF6rde, wenn du glaubst, dass die Verarbeitung deiner Daten in Widerspruch zur DSGVO steht (Art. 77 DSGVO).",
imprintLabel: "Impressum",
imprintDescription: "Kontaktdaten des f\xFCr den Betrieb dieser Instanz von CT Verantwortlichen",
infrastructureLabel: "Infrastruktur",
infrastructureDescription: "Kontaktdaten des Auftragsverarbeiters, der diese Instanz von CT bereitstellt"
},
onboarding: { onboarding: {
connectionHeadline: "Mit UDN verbinden", connectionHeadline: "Mit UDN verbinden",
connectionDescription: "Um Daten und Nachichten zu verschicken, verbinde dich mit dem Universellen Dezentralen Netzwerk (UDN).", connectionDescription: "Um Daten und Nachichten zu verschicken, verbinde dich mit dem Universellen Dezentralen Netzwerk (UDN).",
@@ -738,15 +775,18 @@
settingsHeadline: "Einstellungen", settingsHeadline: "Einstellungen",
nameLabel: "Name", nameLabel: "Name",
setNameButtonAudioLabel: "namen festlegen", setNameButtonAudioLabel: "namen festlegen",
transferLabel: "Chat teilen",
newSecondaryChannelPlaceholder: "Sekund\xE4ren Kanal hinzuf\xFCgen", newSecondaryChannelPlaceholder: "Sekund\xE4ren Kanal hinzuf\xFCgen",
newSecondaryChannelAudioLabel: "Name des neuen sekund\xE4ren Kanals", newSecondaryChannelAudioLabel: "Name des neuen sekund\xE4ren Kanals",
addSecondaryChannelButtonAudioLabel: "Sekund\xE4ren Kanal hinzuf\xFCgen", addSecondaryChannelButtonAudioLabel: "Sekund\xE4ren Kanal hinzuf\xFCgen",
encryptionKeyLabel: "Schl\xFCssel", encryptionKeyLabel: "Schl\xFCssel",
setEncryptionKeyButtonAudioLabel: "Schl\xFCssel festlegen", setEncryptionKeyButtonAudioLabel: "Schl\xFCssel festlegen",
showEncryptionKey: "Schl\xFCssel anzeigen", showEncryptionKey: "Schl\xFCssel anzeigen",
randomizeKey: "Zuf\xE4llig generieren", randomizeKey: "Generieren",
setColorButtonAudioLabel: "Farbe festlegen", setColorButtonAudioLabel: "Farbe festlegen",
deleteChatButton: "Gesamten Chat l\xF6schen" deleteChatButton: "Gesamten Chat l\xF6schen",
deleteChatHeadline: "Gesamten Chat l\xF6schen?",
deleteChatDescription: "Dies l\xF6scht alle Nachrichten, Aufgaben und alle anderen Daten, die zu diesem Chat geh\xF6ren."
}, },
message: { message: {
messagesHeadline: "Nachrichten", messagesHeadline: "Nachrichten",
@@ -791,7 +831,7 @@
filterTasksButtonAudioLabel: "Aufgaben filtern", filterTasksButtonAudioLabel: "Aufgaben filtern",
createTaskButtonAudioLabel: "Neue Aufgabe erstellen", createTaskButtonAudioLabel: "Neue Aufgabe erstellen",
boardSettingsHeadline: "Board-Einstellungen", boardSettingsHeadline: "Board-Einstellungen",
boardNameInputLabel: "Boardname", boardNameInputLabel: "Name",
deleteBoardButton: "Board und alle Aufgaben l\xF6schen", deleteBoardButton: "Board und alle Aufgaben l\xF6schen",
taskSettingsHeadline: "Aufgabe bearbeiten", taskSettingsHeadline: "Aufgabe bearbeiten",
taskNameLabel: "Titel", taskNameLabel: "Titel",
@@ -872,15 +912,16 @@
}, },
homePage: { homePage: {
appName: "Coordination Tool", appName: "Coordination Tool",
greeting: (name) => `Hola ${name}!`, greeting: (name) => `Hola ${name}`,
serverAddress: "Direcci\xF3n del servidor", serverAddress: "Direcci\xF3n del servidor",
serverAddressPlaceholder: "wss://192.168.0.69:3000", serverAddressPlaceholder: "wss://udn.vdpr.org",
connectAudioLabel: "conectar al servidor", connectAudioLabel: "conectar al servidor",
disconnectAudioLabel: "desconectar del servidor", disconnectAudioLabel: "desconectar del servidor",
manageConnectionsAudioLabel: "gestionar conexiones", manageConnectionsAudioLabel: "gestionar conexiones",
settingsButton: "Ajustes", settingsButton: "Ajustes",
manageStorageButton: "Gestionar almacenamiento", manageStorageButton: "Gestionar almacenamiento",
transferDataButton: "Enviar o exportar archivos", transferDataButton: "Enviar o exportar archivos",
legalButton: "Informaci\xF3n legal",
updateButton: (version) => `Actualizar a ${version}`, updateButton: (version) => `Actualizar a ${version}`,
typeChat: "chat", typeChat: "chat",
noChatsPlaceholder: "No hay chats" noChatsPlaceholder: "No hay chats"
@@ -910,9 +951,25 @@
}, },
about: { about: {
version: "Versi\xF3n", version: "Versi\xF3n",
checkUpdatesButton: "Buscar actualisaciones" checkUpdatesButton: "Buscar actualisaciones",
brand: "Software de VDMDI",
brandDescription: "Code desponible en Viridian Public Resources (VDPR)"
} }
}, },
legal: {
legalHeadline: "Informaci\xF3n legal",
legalDescription: "CT es software de c\xF3digo abierto, publicado y distribuido bajo la licencia GPL-3.0.",
privacyLabel: "Privacidad y datos de la aplicaci\xF3n",
privacyDescription: "CT almacena datos en tu dispositivo. No se env\xEDan ni almacenan datos en el servidor que aloja esta instancia de CT, salvo los datos necesarios para proporcionar el sitio web. Estos datos se procesan por el encargado del tratamiento.",
udnLabel: "Servidores UDN y comunicaci\xF3nes",
udnDescription: "Los servidores UDN a los que te conectas son separados e independientes de CT. Al conectarte o mientras mantengas la conexi\xF3n a un servidor UDN, los chats que creas y los objetos contenidos adentro, incluso mensajes, boards y tareas, se envian al servidor. Mira la pol\xEDtica de privacidad de este servidor para m\xE1s detalles.",
rightsLabel: "Tus derechos",
rightsDescription: "Tienes el derecho a oponerte a cualquier tratamiento de tus datos en virtud del art. 21 del RGPD, as\xED como a solicitar el acceso, la modificaci\xF3n y la supresi\xF3n de tus datos conforme a los arts. 15, 16 y 17 del RGPD, poni\xE9ndote en contacto con el responsable y/o el encargado del tratamiento. Tambi\xE9n tienes el derecho a presentar una reclamaci\xF3n ante una autoridad de control en materia de protecci\xF3n de datos en virtud del art. 77 del RGPD.",
imprintLabel: "Aviso Legal",
imprintDescription: "Informaci\xF3n del contacto del responsable del tratamiento que proporciona esta instancia de CT",
infrastructureLabel: "Infraestructura",
infrastructureDescription: "Informaci\xF3n del contacto del encargado del tratamiento que aloja esta instancia de CT"
},
onboarding: { onboarding: {
connectionHeadline: "Conectar al UDN", connectionHeadline: "Conectar al UDN",
connectionDescription: "Para transferir datos y enviar mensajes, con\xE9ctate a la Red Descentralizada Universal (UDN).", connectionDescription: "Para transferir datos y enviar mensajes, con\xE9ctate a la Red Descentralizada Universal (UDN).",
@@ -991,6 +1048,7 @@
settingsHeadline: "Configuraci\xF3n", settingsHeadline: "Configuraci\xF3n",
nameLabel: "Nombre del chat", nameLabel: "Nombre del chat",
setNameButtonAudioLabel: "establecer nombre", setNameButtonAudioLabel: "establecer nombre",
transferLabel: "Compartir chat",
newSecondaryChannelPlaceholder: "A\xF1adir canal secundario", newSecondaryChannelPlaceholder: "A\xF1adir canal secundario",
newSecondaryChannelAudioLabel: "nombre del nuevo canal secundario", newSecondaryChannelAudioLabel: "nombre del nuevo canal secundario",
addSecondaryChannelButtonAudioLabel: "a\xF1adir canal secundario", addSecondaryChannelButtonAudioLabel: "a\xF1adir canal secundario",
@@ -999,7 +1057,9 @@
showEncryptionKey: "Mostrar clave de encriptaci\xF3n", showEncryptionKey: "Mostrar clave de encriptaci\xF3n",
randomizeKey: "Aleatorizar", randomizeKey: "Aleatorizar",
setColorButtonAudioLabel: "establecer color", setColorButtonAudioLabel: "establecer color",
deleteChatButton: "Eliminar todo el chat" deleteChatButton: "Eliminar todo el chat",
deleteChatHeadline: "\xBFEliminar chat?",
deleteChatDescription: "\xBFQuieres borrar todas las mensajes, tareas y otros datos que pertenecen a este chat?"
}, },
message: { message: {
messagesHeadline: "Mensajes", messagesHeadline: "Mensajes",
@@ -1524,6 +1584,16 @@
window.location.reload(); window.location.reload();
}, 500); }, 500);
}; };
// VDPR
this.openVDPR = () => {
window.open("https://vdpr.org/VDMDI/CT");
};
this.openImprint = () => {
window.open("/imprint");
};
this.openProviderContact = () => {
window.open("/provider");
};
this.translations = allTranslations[settingsModel2.language] || allTranslations.en; this.translations = allTranslations[settingsModel2.language] || allTranslations.en;
this.latestVersion.subscribe((latestVersion) => { this.latestVersion.subscribe((latestVersion) => {
this.updateText.value = this.translations.homePage.updateButton(latestVersion); this.updateText.value = this.translations.homePage.updateButton(latestVersion);
@@ -1642,6 +1712,13 @@
this.fileTransferViewModel = fileTransferViewModel2; this.fileTransferViewModel = fileTransferViewModel2;
this.storageViewModel = storageViewModel2; this.storageViewModel = storageViewModel2;
this.connectionViewModel = connectionViewModel2; this.connectionViewModel = connectionViewModel2;
this.isPresentingLegalModal = new State(false);
this.openLegalModal = () => {
this.isPresentingLegalModal.value = true;
};
this.closeLegalModal = () => {
this.isPresentingLegalModal.value = false;
};
this.coreViewModel.context = this; this.coreViewModel.context = this;
this.registerKeyStroke( this.registerKeyStroke(
"," /* Settings */, "," /* Settings */,
@@ -1651,6 +1728,8 @@
"t", "t",
this.fileTransferViewModel.showDirectionSelectionModal this.fileTransferViewModel.showDirectionSelectionModal
); );
this.registerKeyStroke("i", this.openLegalModal);
this.registerKeyStroke("backspace" /* CloseOrCancel */, this.closeLegalModal);
this.registerKeyStroke("e", this.storageViewModel.showStorageModal); this.registerKeyStroke("e", this.storageViewModel.showStorageModal);
this.registerKeyStroke("x", this.connectionViewModel.disconnect); this.registerKeyStroke("x", this.connectionViewModel.disconnect);
this.registerKeyStroke("c", this.connectionViewModel.connect); this.registerKeyStroke("c", this.connectionViewModel.connect);
@@ -5131,6 +5210,8 @@
this.registerKeyStroke("backspace" /* CloseOrCancel */, () => { this.registerKeyStroke("backspace" /* CloseOrCancel */, () => {
if (this.isFilterModalOpen.value == true) { if (this.isFilterModalOpen.value == true) {
this.hideFilterModal(); this.hideFilterModal();
} else if (this.replyViewSelectedMessage.value != void 0) {
this.resetReplyView();
} else { } else {
this.replyingMessage.value = void 0; this.replyingMessage.value = void 0;
} }
@@ -5144,7 +5225,7 @@
// src/ViewModel/Chat/chatViewModel.ts // src/ViewModel/Chat/chatViewModel.ts
var ChatViewModel6 = class extends ContextHost { var ChatViewModel6 = class extends ContextHost {
// init // init
constructor(coreViewModel2, chatModel, settingsViewModel2, notificationViewModel, connectionViewModel2, chatListViewModel2, contactListViewModel2) { constructor(coreViewModel2, chatModel, settingsViewModel2, notificationViewModel, connectionViewModel2, chatListViewModel2, contactListViewModel2, fileTransferViewModel2) {
super("chat", coreViewModel2); super("chat", coreViewModel2);
this.coreViewModel = coreViewModel2; this.coreViewModel = coreViewModel2;
this.chatModel = chatModel; this.chatModel = chatModel;
@@ -5153,6 +5234,7 @@
this.connectionViewModel = connectionViewModel2; this.connectionViewModel = connectionViewModel2;
this.chatListViewModel = chatListViewModel2; this.chatListViewModel = chatListViewModel2;
this.contactListViewModel = contactListViewModel2; this.contactListViewModel = contactListViewModel2;
this.fileTransferViewModel = fileTransferViewModel2;
// state // state
this.displayedColor = new State("standard" /* Standard */); this.displayedColor = new State("standard" /* Standard */);
this.selectedPage = new State( this.selectedPage = new State(
@@ -5185,6 +5267,9 @@
const index = this.chatListViewModel.chatIndexManager.getIndex(this); const index = this.chatListViewModel.chatIndexManager.getIndex(this);
this.index.value = index; this.index.value = index;
}; };
this.share = () => {
this.fileTransferViewModel.showDirectionSelectionModal();
};
// load // load
this.loadPageSelection = () => { this.loadPageSelection = () => {
const path = StorageModel.getPath( const path = StorageModel.getPath(
@@ -5384,11 +5469,12 @@
// src/ViewModel/Chat/chatListViewModel.ts // src/ViewModel/Chat/chatListViewModel.ts
var ChatListViewModel = class { var ChatListViewModel = class {
// init // init
constructor(coreViewModel2, settingsViewModel2, connectionViewModel2, contactListViewModel2) { constructor(coreViewModel2, settingsViewModel2, connectionViewModel2, contactListViewModel2, fileTransferViewModel2) {
this.coreViewModel = coreViewModel2; this.coreViewModel = coreViewModel2;
this.settingsViewModel = settingsViewModel2; this.settingsViewModel = settingsViewModel2;
this.connectionViewModel = connectionViewModel2; this.connectionViewModel = connectionViewModel2;
this.contactListViewModel = contactListViewModel2; this.contactListViewModel = contactListViewModel2;
this.fileTransferViewModel = fileTransferViewModel2;
// data // data
this.chatIndexManager = new IndexManager( this.chatIndexManager = new IndexManager(
(chatViewModel) => chatViewModel.settingsPageViewModel.name.value (chatViewModel) => chatViewModel.settingsPageViewModel.name.value
@@ -5428,7 +5514,8 @@
this.notificationViewModel, this.notificationViewModel,
this.connectionViewModel, this.connectionViewModel,
this, this,
this.contactListViewModel this.contactListViewModel,
this.fileTransferViewModel
); );
}; };
this.updateIndices = () => { this.updateIndices = () => {
@@ -5549,7 +5636,7 @@
}; };
// src/View/homePage.tsx // src/View/homePage.tsx
function HomePage(coreViewModel2, storageViewModel2, settingsViewModel2, connectionViewModel2, fileTransferViewModel2, chatListViewModel2) { function HomePage(coreViewModel2, homeViewModel2, storageViewModel2, settingsViewModel2, connectionViewModel2, fileTransferViewModel2, chatListViewModel2) {
const greeting = createProxyState( const greeting = createProxyState(
[settingsViewModel2.username], [settingsViewModel2.username],
() => coreViewModel2.translations.homePage.greeting( () => coreViewModel2.translations.homePage.greeting(
@@ -5622,6 +5709,11 @@
coreViewModel2.translations.homePage.manageStorageButton, coreViewModel2.translations.homePage.manageStorageButton,
"hard_drive", "hard_drive",
"e" "e"
), HomePageButton(
homeViewModel2.openLegalModal,
coreViewModel2.translations.homePage.legalButton,
"gavel",
"i"
), /* @__PURE__ */ createElement( ), /* @__PURE__ */ createElement(
"button", "button",
{ {
@@ -6700,6 +6792,18 @@
); );
} }
// src/View/Components/confirmationDialog.tsx
function ConfirmationDialog(coreViewModel2, buttonLabel, icon, headline, description, action) {
const isModalOpen = new State(false);
function openModal() {
isModalOpen.value = true;
}
function closeModal() {
isModalOpen.value = false;
}
return /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("button", { class: "danger width-100", "on:click": openModal }, /* @__PURE__ */ createElement("span", null, buttonLabel), /* @__PURE__ */ createElement("span", { class: "icon" }, icon)), /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isModalOpen }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, headline), /* @__PURE__ */ createElement("p", { class: "secondary" }, description)), /* @__PURE__ */ createElement("div", { class: "flex-row" }, /* @__PURE__ */ createElement("button", { class: "standard width-50", "on:click": closeModal }, coreViewModel2.translations.general.cancelButton), /* @__PURE__ */ createElement("button", { class: "danger width-50", "on:click": action }, /* @__PURE__ */ createElement("span", null, buttonLabel), /* @__PURE__ */ createElement("span", { class: "icon" }, icon))))));
}
// src/View/ChatPages/settingsPage.tsx // src/View/ChatPages/settingsPage.tsx
function SettingsPage(coreViewModel2, settingsPageViewModel) { function SettingsPage(coreViewModel2, settingsPageViewModel) {
settingsPageViewModel.loadData(); settingsPageViewModel.loadData();
@@ -6713,7 +6817,15 @@
} }
); );
}; };
return /* @__PURE__ */ createElement("div", { id: "settings-page" }, /* @__PURE__ */ createElement("div", { class: "pane-wrapper" }, /* @__PURE__ */ createElement("div", { class: "pane" }, /* @__PURE__ */ createElement("div", { class: "toolbar" }, /* @__PURE__ */ createElement("span", { class: "title" }, coreViewModel2.translations.chatPage.settings.settingsHeadline)), /* @__PURE__ */ createElement("div", { class: "content" }, /* @__PURE__ */ createElement("label", { class: "tile flex-no" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "forum"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, coreViewModel2.translations.chatPage.settings.nameLabel), /* @__PURE__ */ createElement( return /* @__PURE__ */ createElement("div", { id: "settings-page" }, /* @__PURE__ */ createElement("div", { class: "pane-wrapper" }, /* @__PURE__ */ createElement("div", { class: "pane" }, /* @__PURE__ */ createElement("div", { class: "toolbar" }, /* @__PURE__ */ createElement("span", { class: "title" }, coreViewModel2.translations.chatPage.settings.settingsHeadline)), /* @__PURE__ */ createElement("div", { class: "content" }, /* @__PURE__ */ createElement(
"button",
{
class: "standard width-input",
"on:click": settingsPageViewModel.chatViewModel.share
},
/* @__PURE__ */ createElement("span", null, coreViewModel2.translations.chatPage.settings.transferLabel),
/* @__PURE__ */ createElement("span", { class: "icon" }, "share")
), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile flex-no" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "forum"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, coreViewModel2.translations.chatPage.settings.nameLabel), /* @__PURE__ */ createElement(
"input", "input",
{ {
"bind:value": settingsPageViewModel.nameInput, "bind:value": settingsPageViewModel.nameInput,
@@ -6796,10 +6908,12 @@
}, },
coreViewModel2.translations.general.setButton, coreViewModel2.translations.general.setButton,
/* @__PURE__ */ createElement("span", { class: "icon" }, "check") /* @__PURE__ */ createElement("span", { class: "icon" }, "check")
)), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "width-input" }, DangerousActionButton( )), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "width-input" }, ConfirmationDialog(
coreViewModel2, coreViewModel2,
coreViewModel2.translations.chatPage.settings.deleteChatButton, coreViewModel2.translations.chatPage.settings.deleteChatButton,
"chat_error", "delete_forever",
coreViewModel2.translations.chatPage.settings.deleteChatHeadline,
coreViewModel2.translations.chatPage.settings.deleteChatDescription,
settingsPageViewModel.remove settingsPageViewModel.remove
)))))); ))))));
} }
@@ -7242,7 +7356,8 @@
{ {
class: "ghost", class: "ghost",
"on:click": messagePageViewModel.resetReplyView, "on:click": messagePageViewModel.resetReplyView,
"toggle:hidden": messagePageViewModel.isReplyViewInactive "toggle:hidden": messagePageViewModel.isReplyViewInactive,
ctkeystroke: getKeySymbol("backspace" /* CloseOrCancel */)
}, },
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_back") /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_back")
), /* @__PURE__ */ createElement( ), /* @__PURE__ */ createElement(
@@ -7958,7 +8073,23 @@
}, },
/* @__PURE__ */ createElement("span", { "subscribe:innerText": coreViewModel2.updateText }), /* @__PURE__ */ createElement("span", { "subscribe:innerText": coreViewModel2.updateText }),
/* @__PURE__ */ createElement("span", { class: "icon" }, "update") /* @__PURE__ */ createElement("span", { class: "icon" }, "update")
), /* @__PURE__ */ createElement("button", { class: "standard", "on:click": coreViewModel2.checkUpdates }, coreViewModel2.translations.settings.about.checkUpdatesButton))); ), /* @__PURE__ */ createElement("button", { class: "standard", "on:click": coreViewModel2.checkUpdates }, coreViewModel2.translations.settings.about.checkUpdatesButton), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement(
"img",
{
class: "width-100",
style: "max-width: 196px",
src: "/vdmdi-logo.png"
}
), /* @__PURE__ */ createElement(
"button",
{
class: "tile flex-row",
"on:click": coreViewModel2.openVDPR
},
/* @__PURE__ */ createElement("span", { class: "icon" }, "code"),
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.settings.about.brand), /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.settings.about.brandDescription)),
/* @__PURE__ */ createElement("span", { class: "icon" }, "open_in_new")
)));
} }
function SettingsRegionalPane(coreViewModel2, settingsViewModel2) { function SettingsRegionalPane(coreViewModel2, settingsViewModel2) {
return /* @__PURE__ */ createElement("div", { class: "slide-up" }, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.settings.pages.regional), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("h3", null, coreViewModel2.translations.settings.regional.language), OptionButtonList( return /* @__PURE__ */ createElement("div", { class: "slide-up" }, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.settings.pages.regional), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("h3", null, coreViewModel2.translations.settings.regional.language), OptionButtonList(
@@ -8237,7 +8368,13 @@
OptionConverter OptionConverter
] ]
} }
), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("h3", null, coreViewModel2.translations.dataTransferModal.chatsHeadline), /* @__PURE__ */ createElement("div", { "children:set": chatList }), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "inline" }, /* @__PURE__ */ createElement("input", { type: "checkbox", "bind:checked": fileTransferViewModel2.allOptionsSelected }), coreViewModel2.translations.general.selectAllLabel)); ), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("h3", null, coreViewModel2.translations.dataTransferModal.chatsHeadline), /* @__PURE__ */ createElement("div", { "children:set": chatList }), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "inline" }, /* @__PURE__ */ createElement(
"input",
{
type: "checkbox",
"bind:checked": fileTransferViewModel2.allOptionsSelected
}
), coreViewModel2.translations.general.selectAllLabel));
} }
function DirectionSelectionModal(coreViewModel2, connectionViewModel2, fileTransferViewModel2) { function DirectionSelectionModal(coreViewModel2, connectionViewModel2, fileTransferViewModel2) {
const isPresented = createProxyState( const isPresented = createProxyState(
@@ -9265,6 +9402,44 @@
} }
}; };
// src/View/Modals/legalModal.tsx
function LegalModal(coreViewModel2, homeViewModel2) {
return /* @__PURE__ */ createElement(
"div",
{
class: "modal",
"toggle:open": homeViewModel2.isPresentingLegalModal
},
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h1", null, coreViewModel2.translations.legal.legalHeadline), /* @__PURE__ */ createElement("p", { class: "secondary" }, coreViewModel2.translations.legal.legalDescription), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap" }, /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "privacy_tip"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.legal.privacyLabel), /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.legal.privacyDescription))), /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "cell_tower"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.legal.udnLabel), /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.legal.udnDescription))), /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "balance"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.legal.rightsLabel), /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.legal.rightsDescription))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement(
"button",
{
class: "tile",
"on:click": coreViewModel2.openImprint
},
/* @__PURE__ */ createElement("span", { class: "icon" }, "contact_page"),
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.legal.imprintLabel), /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.legal.imprintDescription)),
/* @__PURE__ */ createElement("span", { class: "icon" }, "open_in_new")
), /* @__PURE__ */ createElement(
"button",
{
class: "tile",
"on:click": coreViewModel2.openProviderContact
},
/* @__PURE__ */ createElement("span", { class: "icon" }, "domain"),
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.legal.infrastructureLabel), /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.legal.infrastructureDescription)),
/* @__PURE__ */ createElement("span", { class: "icon" }, "open_in_new")
))), /* @__PURE__ */ createElement(
"button",
{
"on:click": homeViewModel2.closeLegalModal,
ctkeystroke: getKeySymbol("backspace" /* CloseOrCancel */)
},
coreViewModel2.translations.general.closeButton,
/* @__PURE__ */ createElement("span", { class: "icon" }, "close")
))
);
}
// src/index.tsx // src/index.tsx
var storageModel = new StorageModel(); var storageModel = new StorageModel();
var settingsModel = new SettingsModel(storageModel); var settingsModel = new SettingsModel(storageModel);
@@ -9291,13 +9466,14 @@
settingsViewModel settingsViewModel
); );
var connectionViewModel = new ConnectionViewModel(coreViewModel); var connectionViewModel = new ConnectionViewModel(coreViewModel);
var fileTransferViewModel = new FileTransferViewModel(coreViewModel);
var chatListViewModel = new ChatListViewModel( var chatListViewModel = new ChatListViewModel(
coreViewModel, coreViewModel,
settingsViewModel, settingsViewModel,
connectionViewModel, connectionViewModel,
contactListViewModel contactListViewModel,
fileTransferViewModel
); );
var fileTransferViewModel = new FileTransferViewModel(coreViewModel);
var onboardingViewModel = new OnboardingViewModel( var onboardingViewModel = new OnboardingViewModel(
connectionViewModel, connectionViewModel,
fileTransferViewModel, fileTransferViewModel,
@@ -9322,6 +9498,7 @@
document.querySelector("main").append( document.querySelector("main").append(
HomePage( HomePage(
coreViewModel, coreViewModel,
homeViewModel,
storageViewModel, storageViewModel,
settingsViewModel, settingsViewModel,
connectionViewModel, connectionViewModel,
@@ -9330,6 +9507,7 @@
), ),
ChatPageWrapper(coreViewModel, chatListViewModel), ChatPageWrapper(coreViewModel, chatListViewModel),
OnboardingModalWrapper(coreViewModel, onboardingViewModel), OnboardingModalWrapper(coreViewModel, onboardingViewModel),
LegalModal(coreViewModel, homeViewModel),
ConnectionModal2(coreViewModel, connectionViewModel), ConnectionModal2(coreViewModel, connectionViewModel),
DataTransferModalWrapper( DataTransferModalWrapper(
coreViewModel, coreViewModel,
+1 -1
View File
@@ -280,7 +280,7 @@ SIZES
body { body {
/* gap */ /* gap */
--gap-between-tiles: 4px; --gap-between-tiles: 4px;
--gap-in-controls: 7px; --gap-in-controls: 9px;
--gap-in-tab-links: 1rem; --gap-in-tab-links: 1rem;
--text-gap: 1.2rem; --text-gap: 1.2rem;
--large-gap: 2rem; --large-gap: 2rem;
Vendored
+1 -1
View File
@@ -1,4 +1,4 @@
const VERSION = "2610 Beta 21.17" const VERSION = "2610 First Revision"
function processUrl(event) { function processUrl(event) {
const url = event.request.url; const url = event.request.url;
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

+1 -1
View File
@@ -1 +1 @@
2610 Beta 21.17 2610 First Revision
+78 -77
View File
@@ -111,83 +111,84 @@ export function MessagePage(
on:click={messagePageViewModel.resetReplyView} on:click={messagePageViewModel.resetReplyView}
toggle:hidden={ toggle:hidden={
messagePageViewModel.isReplyViewInactive messagePageViewModel.isReplyViewInactive
} }
> ctkeystroke={getKeySymbol(CommonKeys.CloseOrCancel)}
<span class="icon">arrow_back</span> >
</button> <span class="icon">arrow_back</span>
<span </button>
class="title ellipsis width-100 flex" <span
subscribe:innerText={title} class="title ellipsis width-100 flex"
></span> subscribe:innerText={title}
<span> ></span>
<button <span>
class="ghost inset-outline" <button
on:click={messagePageViewModel.showFilterModal} class="ghost inset-outline"
aria-label={ on:click={messagePageViewModel.showFilterModal}
coreViewModel.translations.chatPage.message aria-label={
.filterMessagesButtonAudioLabel coreViewModel.translations.chatPage.message
} .filterMessagesButtonAudioLabel
toggle:selected={ }
messagePageViewModel.isFilterActive toggle:selected={
} messagePageViewModel.isFilterActive
ctkeystroke={getKeySymbol(CommonKeys.Filter)} }
> ctkeystroke={getKeySymbol(CommonKeys.Filter)}
<span class="icon">filter_alt</span> >
</button> <span class="icon">filter_alt</span>
</span> </button>
</div> </span>
<div class="content"> </div>
{messageContainer} <div class="content">
<div id="composer"> {messageContainer}
<div class="content-width-constraint"> <div id="composer">
<div <div class="content-width-constraint">
class="reply-preview-wrapper" <div
children:set={replyPreview} class="reply-preview-wrapper"
></div> children:set={replyPreview}
<div class="input-width-constraint"> ></div>
<input <div class="input-width-constraint">
id="focused" <input
class="blur" id="focused"
bind:value={ class="blur"
messagePageViewModel.composingMessage bind:value={
} messagePageViewModel.composingMessage
on:enter={ }
messagePageViewModel.sendMessage on:enter={
} messagePageViewModel.sendMessage
placeholder={ }
coreViewModel.translations.chatPage placeholder={
.message coreViewModel.translations.chatPage
.composerInputPlaceholder .message
} .composerInputPlaceholder
></input> }
<button ></input>
class="primary blur" <button
aria-label={ class="primary blur"
coreViewModel.translations.chatPage aria-label={
.message coreViewModel.translations.chatPage
.sendMessageButtonAudioLabel .message
} .sendMessageButtonAudioLabel
on:click={ }
messagePageViewModel.sendMessage on:click={
} messagePageViewModel.sendMessage
toggle:disabled={ }
messagePageViewModel.cannotSendMessage toggle:disabled={
} messagePageViewModel.cannotSendMessage
> }
<span class="icon">send</span> >
</button> <span class="icon">send</span>
</div> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
{MessageFilterModal( {MessageFilterModal(
coreViewModel, coreViewModel,
messagePageViewModel, messagePageViewModel,
ChatMessageViewModelToView, ChatMessageViewModelToView,
)} )}
</div> </div>
); );
} }
+16 -4
View File
@@ -1,5 +1,5 @@
import { DeletableListItem } from "../Components/deletableListItem"; import { DeletableListItem } from "../Components/deletableListItem";
import { DangerousActionButton } from "../Components/dangerousActionButton"; import { ConfirmationDialog } from "../Components/confirmationDialog";
import { ColorPicker } from "../Components/colorPicker"; import { ColorPicker } from "../Components/colorPicker";
import * as React from "../../react"; import * as React from "../../react";
import SettingsPageViewModel from "../../ViewModel/Pages/settingsPageViewModel"; import SettingsPageViewModel from "../../ViewModel/Pages/settingsPageViewModel";
@@ -36,7 +36,15 @@ export function SettingsPage(
} }
</span> </span>
</div> </div>
<div class="content"> <div class="content">
<button
class="standard width-input"
on:click={settingsPageViewModel.chatViewModel.share}
>
<span>{coreViewModel.translations.chatPage.settings.transferLabel}</span>
<span class="icon">share</span>
</button>
<hr></hr>
<label class="tile flex-no"> <label class="tile flex-no">
<span class="icon">forum</span> <span class="icon">forum</span>
<div> <div>
@@ -203,11 +211,15 @@ export function SettingsPage(
<hr></hr> <hr></hr>
<div class="width-input"> <div class="width-input">
{DangerousActionButton( {ConfirmationDialog(
coreViewModel, coreViewModel,
coreViewModel.translations.chatPage.settings coreViewModel.translations.chatPage.settings
.deleteChatButton, .deleteChatButton,
"chat_error", "delete_forever",
coreViewModel.translations.chatPage.settings
.deleteChatHeadline,
coreViewModel.translations.chatPage.settings
.deleteChatDescription,
settingsPageViewModel.remove, settingsPageViewModel.remove,
)} )}
</div> </div>
@@ -0,0 +1,47 @@
import * as React from "../../react";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
export function ConfirmationDialog(
coreViewModel: CoreViewModel,
buttonLabel: string,
icon: string,
headline: string,
description: string,
action: () => void,
) {
const isModalOpen = new React.State(false);
function openModal() {
isModalOpen.value = true;
}
function closeModal() {
isModalOpen.value = false;
}
return (
<div>
<button class="danger width-100" on:click={openModal}>
<span>{buttonLabel}</span>
<span class="icon">{icon}</span>
</button>
<div class="modal" toggle:open={isModalOpen}>
<div>
<main>
<h2>{headline}</h2>
<p class="secondary">{description}</p>
</main>
<div class="flex-row">
<button class="standard width-50" on:click={closeModal}>
{coreViewModel.translations.general.cancelButton}
</button>
<button class="danger width-50" on:click={action}>
<span>{buttonLabel}</span>
<span class="icon">{icon}</span>
</button>
</div>
</div>
</div>
</div>
);
}
+87
View File
@@ -0,0 +1,87 @@
import { SplitModal } from "./splitModal";
import { languageNames } from "../translations";
import { CommonKeys, getKeySymbol } from "../keystrokes";
import { PlaceholderView } from "../Components/placeholderView";
import { OptionButtonList } from "../Components/optionButtonList";
import { NavigationButton } from "../Components/navigationButton";
import { InfoTile } from "../Components/infoTile";
import * as React from "../../react";
import SettingsViewModel, {
SettingsModalPages,
} from "../../ViewModel/Global/settingsViewModel";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
import { Languages, ThemeSettings } from "../../Model/Global/settingsModel";
import HomeViewModel from "../../ViewModel/Pages/homeViewModel";
export function LegalModal(
coreViewModel: CoreViewModel,
homeViewModel: HomeViewModel,
) {
return (
<div
class="modal"
toggle:open={homeViewModel.isPresentingLegalModal}
>
<div>
<main>
<h1>{coreViewModel.translations.legal.legalHeadline}</h1>
<p class="secondary">{coreViewModel.translations.legal.legalDescription}</p>
<hr></hr>
<div class="flex-column gap">
<div class="tile">
<span class="icon">privacy_tip</span>
<div>
<b>{coreViewModel.translations.legal.privacyLabel}</b>
<span class="secondary">{coreViewModel.translations.legal.privacyDescription}</span>
</div>
</div>
<div class="tile">
<span class="icon">cell_tower</span>
<div>
<b>{coreViewModel.translations.legal.udnLabel}</b>
<span class="secondary">{coreViewModel.translations.legal.udnDescription}</span>
</div>
</div>
<div class="tile">
<span class="icon">balance</span>
<div>
<b>{coreViewModel.translations.legal.rightsLabel}</b>
<span class="secondary">{coreViewModel.translations.legal.rightsDescription}</span>
</div>
</div>
<hr></hr>
<button
class="tile"
on:click={coreViewModel.openImprint}
>
<span class="icon">contact_page</span>
<div>
<b>{coreViewModel.translations.legal.imprintLabel}</b>
<span class="secondary">{coreViewModel.translations.legal.imprintDescription}</span>
</div>
<span class="icon">open_in_new</span>
</button>
<button
class="tile"
on:click={coreViewModel.openProviderContact}
>
<span class="icon">domain</span>
<div>
<b>{coreViewModel.translations.legal.infrastructureLabel}</b>
<span class="secondary">{coreViewModel.translations.legal.infrastructureDescription}</span>
</div>
<span class="icon">open_in_new</span>
</button>
</div>
</main>
<button
on:click={homeViewModel.closeLegalModal}
ctkeystroke={getKeySymbol(CommonKeys.CloseOrCancel)}
>
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
</div>
</div>
);
}
+20 -1
View File
@@ -154,7 +154,26 @@ function SettingsInfoPane(
coreViewModel.translations.settings.about coreViewModel.translations.settings.about
.checkUpdatesButton .checkUpdatesButton
} }
</button> </button>
<hr></hr>
<img
class="width-100"
style="max-width: 196px"
src="/vdmdi-logo.png">
</img>
<button
class="tile flex-row"
on:click={coreViewModel.openVDPR}
>
<span class="icon">code</span>
<div>
<b>{coreViewModel.translations.settings.about.brand}</b>
<span class="secondary">{coreViewModel.translations.settings.about.brandDescription}</span>
</div>
<span class="icon">open_in_new</span>
</button>
</div> </div>
</div> </div>
); );
+1 -1
View File
@@ -137,7 +137,7 @@ body[showing-chat] #chat-page-wrapper {
} }
#chat-page > div > #ribbon > span { #chat-page > div > #ribbon > span {
overflow-y: auto; overflow-x: hidden;
flex-direction: column; flex-direction: column;
justify-content: end; justify-content: end;
} }
+8
View File
@@ -10,9 +10,11 @@ import FileTransferViewModel from "../ViewModel/Global/fileTransferViewModel";
import CoreViewModel from "../ViewModel/Global/coreViewModel"; import CoreViewModel from "../ViewModel/Global/coreViewModel";
import ConnectionViewModel from "../ViewModel/Global/connectionViewModel"; import ConnectionViewModel from "../ViewModel/Global/connectionViewModel";
import ChatListViewModel from "../ViewModel/Chat/chatListViewModel"; import ChatListViewModel from "../ViewModel/Chat/chatListViewModel";
import HomeViewModel from "../ViewModel/Pages/homeViewModel";
export function HomePage( export function HomePage(
coreViewModel: CoreViewModel, coreViewModel: CoreViewModel,
homeViewModel: HomeViewModel,
storageViewModel: StorageViewModel, storageViewModel: StorageViewModel,
settingsViewModel: SettingsViewModel, settingsViewModel: SettingsViewModel,
connectionViewModel: ConnectionViewModel, connectionViewModel: ConnectionViewModel,
@@ -119,6 +121,12 @@ export function HomePage(
"hard_drive", "hard_drive",
"e", "e",
)} )}
{HomePageButton(
homeViewModel.openLegalModal,
coreViewModel.translations.homePage.legalButton,
"gavel",
"i",
)}
<button <button
class="primary" class="primary"
+962 -878
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -7,6 +7,7 @@ import ConnectionViewModel from "../Global/connectionViewModel";
import * as React from "../../react"; import * as React from "../../react";
import implementFilter, { IndexManager } from "../../Model/Utility/utility"; import implementFilter, { IndexManager } from "../../Model/Utility/utility";
import ChatModel from "../../Model/Chat/chatModel"; import ChatModel from "../../Model/Chat/chatModel";
import FileTransferViewModel from "../Global/fileTransferViewModel";
export default class ChatListViewModel { export default class ChatListViewModel {
notificationViewModel: NotificationViewModel; notificationViewModel: NotificationViewModel;
@@ -62,6 +63,7 @@ export default class ChatListViewModel {
this.connectionViewModel, this.connectionViewModel,
this, this,
this.contactListViewModel, this.contactListViewModel,
this.fileTransferViewModel
); );
}; };
@@ -99,6 +101,7 @@ export default class ChatListViewModel {
public readonly settingsViewModel: SettingsViewModel, public readonly settingsViewModel: SettingsViewModel,
public readonly connectionViewModel: ConnectionViewModel, public readonly connectionViewModel: ConnectionViewModel,
public readonly contactListViewModel: ContactListViewModel, public readonly contactListViewModel: ContactListViewModel,
public readonly fileTransferViewModel: FileTransferViewModel,
) { ) {
this.notificationViewModel = new NotificationViewModel( this.notificationViewModel = new NotificationViewModel(
this, this,
+6
View File
@@ -22,6 +22,7 @@ import ChatModel, {
ChatMessage, ChatMessage,
ChatMessageReaction, ChatMessageReaction,
} from "../../Model/Chat/chatModel"; } from "../../Model/Chat/chatModel";
import FileTransferViewModel from "../Global/fileTransferViewModel";
export default class ChatViewModel extends ContextHost<ChatPageTypes> { export default class ChatViewModel extends ContextHost<ChatPageTypes> {
calendarViewModel: CalendarPageViewModel; calendarViewModel: CalendarPageViewModel;
@@ -81,6 +82,10 @@ export default class ChatViewModel extends ContextHost<ChatPageTypes> {
this.index.value = index; this.index.value = index;
}; };
share = (): void => {
this.fileTransferViewModel.showDirectionSelectionModal();
}
// load // load
loadPageSelection = (): void => { loadPageSelection = (): void => {
const path: string[] = StorageModel.getPath( const path: string[] = StorageModel.getPath(
@@ -151,6 +156,7 @@ export default class ChatViewModel extends ContextHost<ChatPageTypes> {
public readonly connectionViewModel: ConnectionViewModel, public readonly connectionViewModel: ConnectionViewModel,
public readonly chatListViewModel: ChatListViewModel, public readonly chatListViewModel: ChatListViewModel,
public readonly contactListViewModel: ContactListViewModel, public readonly contactListViewModel: ContactListViewModel,
public readonly fileTransferViewModel: FileTransferViewModel,
) { ) {
super("chat", coreViewModel); super("chat", coreViewModel);
+13
View File
@@ -153,6 +153,19 @@ export default class CoreViewModel {
}, 500); }, 500);
}; };
// VDPR
openVDPR = (): void => {
window.open("https://vdpr.org/VDMDI/CT");
}
openImprint = (): void => {
window.open("/imprint");
}
openProviderContact = (): void => {
window.open("/provider");
}
// init // init
constructor( constructor(
public readonly storageModel: StorageModel, public readonly storageModel: StorageModel,
+12
View File
@@ -7,6 +7,16 @@ import * as React from "../../react";
import { CommonKeys } from "../../View/keystrokes"; import { CommonKeys } from "../../View/keystrokes";
export default class HomeViewModel extends Context { export default class HomeViewModel extends Context {
isPresentingLegalModal: React.State<boolean> = new React.State<boolean>(false);
openLegalModal = (): void => {
this.isPresentingLegalModal.value = true;
}
closeLegalModal = (): void => {
this.isPresentingLegalModal.value = false;
}
constructor( constructor(
public readonly coreViewModel: CoreViewModel, public readonly coreViewModel: CoreViewModel,
public readonly settingsViewModel: SettingsViewModel, public readonly settingsViewModel: SettingsViewModel,
@@ -26,6 +36,8 @@ export default class HomeViewModel extends Context {
"t", "t",
this.fileTransferViewModel.showDirectionSelectionModal, this.fileTransferViewModel.showDirectionSelectionModal,
); );
this.registerKeyStroke("i", this.openLegalModal);
this.registerKeyStroke(CommonKeys.CloseOrCancel, this.closeLegalModal);
this.registerKeyStroke("e", this.storageViewModel.showStorageModal); this.registerKeyStroke("e", this.storageViewModel.showStorageModal);
this.registerKeyStroke("x", this.connectionViewModel.disconnect); this.registerKeyStroke("x", this.connectionViewModel.disconnect);
this.registerKeyStroke("c", this.connectionViewModel.connect); this.registerKeyStroke("c", this.connectionViewModel.connect);
+3 -1
View File
@@ -245,7 +245,9 @@ export default class MessagePageViewModel extends Context {
this.registerKeyStroke(CommonKeys.CloseOrCancel, () => { this.registerKeyStroke(CommonKeys.CloseOrCancel, () => {
if (this.isFilterModalOpen.value == true) { if (this.isFilterModalOpen.value == true) {
this.hideFilterModal(); this.hideFilterModal();
} else { } else if (this.replyViewSelectedMessage.value != undefined) {
this.resetReplyView();
} else {
this.replyingMessage.value = undefined; this.replyingMessage.value = undefined;
} }
}); });
+7 -3
View File
@@ -24,6 +24,7 @@ import FileTransferModel from "./Model/Global/fileTransferModel";
import ContactListModel from "./Model/Global/contactListModel"; import ContactListModel from "./Model/Global/contactListModel";
import ConnectionModel from "./Model/Global/connectionModel"; import ConnectionModel from "./Model/Global/connectionModel";
import ChatListModel from "./Model/Chat/chatListModel"; import ChatListModel from "./Model/Chat/chatListModel";
import {LegalModal} from "./View/Modals/legalModal";
// models // models
const storageModel = new StorageModel(); const storageModel = new StorageModel();
@@ -54,13 +55,14 @@ const contactListViewModel = new ContactListViewModel(
settingsViewModel, settingsViewModel,
); );
const connectionViewModel = new ConnectionViewModel(coreViewModel); const connectionViewModel = new ConnectionViewModel(coreViewModel);
const fileTransferViewModel = new FileTransferViewModel(coreViewModel);
const chatListViewModel = new ChatListViewModel( const chatListViewModel = new ChatListViewModel(
coreViewModel, coreViewModel,
settingsViewModel, settingsViewModel,
connectionViewModel, connectionViewModel,
contactListViewModel, contactListViewModel,
fileTransferViewModel
); );
const fileTransferViewModel = new FileTransferViewModel(coreViewModel);
const onboardingViewModel = new OnboardingViewModel( const onboardingViewModel = new OnboardingViewModel(
connectionViewModel, connectionViewModel,
fileTransferViewModel, fileTransferViewModel,
@@ -96,7 +98,8 @@ document
.querySelector("main")! .querySelector("main")!
.append( .append(
HomePage( HomePage(
coreViewModel, coreViewModel,
homeViewModel,
storageViewModel, storageViewModel,
settingsViewModel, settingsViewModel,
connectionViewModel, connectionViewModel,
@@ -105,6 +108,7 @@ document
), ),
ChatPageWrapper(coreViewModel, chatListViewModel), ChatPageWrapper(coreViewModel, chatListViewModel),
OnboardingModalWrapper(coreViewModel, onboardingViewModel), OnboardingModalWrapper(coreViewModel, onboardingViewModel),
LegalModal(coreViewModel, homeViewModel),
ConnectionModal(coreViewModel, connectionViewModel), ConnectionModal(coreViewModel, connectionViewModel),
DataTransferModalWrapper( DataTransferModalWrapper(
coreViewModel, coreViewModel,
@@ -112,5 +116,5 @@ document
fileTransferViewModel, fileTransferViewModel,
), ),
StorageModal(coreViewModel, storageViewModel), StorageModal(coreViewModel, storageViewModel),
SettingsModal(coreViewModel, settingsViewModel), SettingsModal(coreViewModel, settingsViewModel),
); );
Executable
+15
View File
@@ -0,0 +1,15 @@
#!/bin/bash
url=""
case $1 in
vd)
url=https://viridian.vd/VDMDI/CT
;;
pr)
url=https://vdpr.org/VDMDI/CT
;;
esac
git remote set-url origin $url
git remote get-url origin