mirror of
https://github.com/mattermost/focalboard.git
synced 2024-11-24 08:22:29 +02:00
Windows WPF / UWP app
This commit is contained in:
parent
3456aed4b6
commit
da6ffd3eb0
7
Makefile
7
Makefile
@ -43,6 +43,10 @@ server-win:
|
|||||||
$(eval LDFLAGS += -X "github.com/mattermost/focalboard/server/model.Edition=win")
|
$(eval LDFLAGS += -X "github.com/mattermost/focalboard/server/model.Edition=win")
|
||||||
cd server; env GOOS=windows GOARCH=amd64 go build -ldflags '$(LDFLAGS)' -o ../bin/win/focalboard-server.exe ./main
|
cd server; env GOOS=windows GOARCH=amd64 go build -ldflags '$(LDFLAGS)' -o ../bin/win/focalboard-server.exe ./main
|
||||||
|
|
||||||
|
server-dll:
|
||||||
|
$(eval LDFLAGS += -X "github.com/mattermost/focalboard/server/model.Edition=win")
|
||||||
|
cd server; env GOOS=windows GOARCH=amd64 go build -ldflags '$(LDFLAGS)' -buildmode=c-shared -o ../bin/win-dll/focalboard-server.dll ./main
|
||||||
|
|
||||||
server-linux-package: server-linux webapp
|
server-linux-package: server-linux webapp
|
||||||
rm -rf package
|
rm -rf package
|
||||||
mkdir -p package/${PACKAGE_FOLDER}/bin
|
mkdir -p package/${PACKAGE_FOLDER}/bin
|
||||||
@ -117,6 +121,9 @@ win-app: server-win webapp
|
|||||||
# cd win/temp; tar -acf ../dist/focalboard-win.zip .
|
# cd win/temp; tar -acf ../dist/focalboard-win.zip .
|
||||||
cd win/temp; powershell "Compress-Archive * ../dist/focalboard-win.zip"
|
cd win/temp; powershell "Compress-Archive * ../dist/focalboard-win.zip"
|
||||||
|
|
||||||
|
win-wpf-app: server-dll webapp
|
||||||
|
cd win-wpf && ./build.bat && ./package.bat
|
||||||
|
|
||||||
linux-app: server-linux webapp
|
linux-app: server-linux webapp
|
||||||
rm -rf linux/temp
|
rm -rf linux/temp
|
||||||
rm -rf linux/dist
|
rm -rf linux/dist
|
||||||
|
@ -26,9 +26,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"C"
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -37,8 +39,8 @@ import (
|
|||||||
"github.com/mattermost/focalboard/server/services/config"
|
"github.com/mattermost/focalboard/server/services/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------------------
|
// Active server used with shared code (dll)
|
||||||
// WebSocket OnChange listener
|
var pServer *server.Server
|
||||||
|
|
||||||
const (
|
const (
|
||||||
timeBetweenPidMonitoringChecks = 2 * time.Second
|
timeBetweenPidMonitoringChecks = 2 * time.Second
|
||||||
@ -55,6 +57,7 @@ func isProcessRunning(pid int) bool {
|
|||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// monitorPid is used to keep the server lifetime in sync with another (client app) process
|
||||||
func monitorPid(pid int) {
|
func monitorPid(pid int) {
|
||||||
log.Printf("Monitoring PID: %d", pid)
|
log.Printf("Monitoring PID: %d", pid)
|
||||||
|
|
||||||
@ -70,13 +73,17 @@ func monitorPid(pid int) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func logInfo() {
|
||||||
// Log version
|
log.Println("Focalboard Server")
|
||||||
log.Println("Version: " + model.CurrentVersion)
|
log.Println("Version: " + model.CurrentVersion)
|
||||||
log.Println("Edition: " + model.Edition)
|
log.Println("Edition: " + model.Edition)
|
||||||
log.Println("Build Number: " + model.BuildNumber)
|
log.Println("Build Number: " + model.BuildNumber)
|
||||||
log.Println("Build Date: " + model.BuildDate)
|
log.Println("Build Date: " + model.BuildDate)
|
||||||
log.Println("Build Hash: " + model.BuildHash)
|
log.Println("Build Hash: " + model.BuildHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
logInfo()
|
||||||
|
|
||||||
// config.json file
|
// config.json file
|
||||||
config, err := config.ReadConfigFile()
|
config, err := config.ReadConfigFile()
|
||||||
@ -89,6 +96,8 @@ func main() {
|
|||||||
pMonitorPid := flag.Int("monitorpid", -1, "a process ID")
|
pMonitorPid := flag.Int("monitorpid", -1, "a process ID")
|
||||||
pPort := flag.Int("port", config.Port, "the port number")
|
pPort := flag.Int("port", config.Port, "the port number")
|
||||||
pSingleUser := flag.Bool("single-user", false, "single user mode")
|
pSingleUser := flag.Bool("single-user", false, "single user mode")
|
||||||
|
pDBType := flag.String("dbtype", "", "Database type")
|
||||||
|
pDBConfig := flag.String("dbconfig", "", "Database config")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
singleUser := false
|
singleUser := false
|
||||||
@ -110,6 +119,19 @@ func main() {
|
|||||||
monitorPid(*pMonitorPid)
|
monitorPid(*pMonitorPid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Override config from commandline
|
||||||
|
|
||||||
|
if pDBType != nil && len(*pDBType) > 0 {
|
||||||
|
config.DBType = *pDBType
|
||||||
|
log.Printf("DBType from commandline: %s", *pDBType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pDBConfig != nil && len(*pDBConfig) > 0 {
|
||||||
|
config.DBConfigString = *pDBConfig
|
||||||
|
// Don't echo, as the confix string may contain passwords
|
||||||
|
log.Printf("DBConfigString overriden from commandline")
|
||||||
|
}
|
||||||
|
|
||||||
if pPort != nil && *pPort > 0 && *pPort != config.Port {
|
if pPort != nil && *pPort > 0 && *pPort != config.Port {
|
||||||
// Override port
|
// Override port
|
||||||
log.Printf("Port from commandline: %d", *pPort)
|
log.Printf("Port from commandline: %d", *pPort)
|
||||||
@ -124,4 +146,78 @@ func main() {
|
|||||||
if err := server.Start(); err != nil {
|
if err := server.Start(); err != nil {
|
||||||
log.Fatal("server.Start ERROR: ", err)
|
log.Fatal("server.Start ERROR: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setting up signal capturing
|
||||||
|
stop := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(stop, os.Interrupt)
|
||||||
|
|
||||||
|
// Waiting for SIGINT (pkill -2)
|
||||||
|
<-stop
|
||||||
|
|
||||||
|
server.Shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartServer starts the server
|
||||||
|
//export StartServer
|
||||||
|
func StartServer(webPath *C.char, port int, singleUserToken *C.char, dbConfigString *C.char) {
|
||||||
|
startServer(
|
||||||
|
C.GoString(webPath),
|
||||||
|
port,
|
||||||
|
C.GoString(singleUserToken),
|
||||||
|
C.GoString(dbConfigString),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopServer stops the server
|
||||||
|
//export StopServer
|
||||||
|
func StopServer() {
|
||||||
|
stopServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func startServer(webPath string, port int, singleUserToken string, dbConfigString string) {
|
||||||
|
logInfo()
|
||||||
|
|
||||||
|
if pServer != nil {
|
||||||
|
stopServer()
|
||||||
|
pServer = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// config.json file
|
||||||
|
config, err := config.ReadConfigFile()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Unable to read the config file: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(webPath) > 0 {
|
||||||
|
config.WebPath = webPath
|
||||||
|
}
|
||||||
|
|
||||||
|
if port > 0 {
|
||||||
|
config.Port = port
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dbConfigString) > 0 {
|
||||||
|
config.DBConfigString = dbConfigString
|
||||||
|
}
|
||||||
|
|
||||||
|
pServer, err = server.New(config, singleUserToken)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("server.New ERROR: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := pServer.Start(); err != nil {
|
||||||
|
log.Fatal("server.Start ERROR: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stopServer() {
|
||||||
|
if pServer == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := pServer.Shutdown()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("server.Shutdown ERROR: ", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -91,21 +89,6 @@ func New(cfg *config.Configuration, singleUserToken string) (*Server, error) {
|
|||||||
webServer.AddRoutes(wsServer)
|
webServer.AddRoutes(wsServer)
|
||||||
webServer.AddRoutes(api)
|
webServer.AddRoutes(api)
|
||||||
|
|
||||||
// Ctrl+C handling
|
|
||||||
handler := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(handler, os.Interrupt)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for sig := range handler {
|
|
||||||
// sig is a ^C, handle it
|
|
||||||
if sig == os.Interrupt {
|
|
||||||
os.Exit(1)
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Init telemetry
|
// Init telemetry
|
||||||
settings, err := store.GetSystemSettings()
|
settings, err := store.GetSystemSettings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -182,10 +165,9 @@ func New(cfg *config.Configuration, singleUserToken string) (*Server, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Start() error {
|
func (s *Server) Start() error {
|
||||||
httpServerExitDone := &sync.WaitGroup{}
|
s.logger.Info("Server.Start")
|
||||||
httpServerExitDone.Add(1)
|
|
||||||
|
|
||||||
s.webServer.Start(httpServerExitDone)
|
s.webServer.Start()
|
||||||
|
|
||||||
if s.config.EnableLocalMode {
|
if s.config.EnableLocalMode {
|
||||||
if err := s.startLocalModeServer(); err != nil {
|
if err := s.startLocalModeServer(); err != nil {
|
||||||
@ -208,8 +190,6 @@ func (s *Server) Start() error {
|
|||||||
s.telemetry.RunTelemetryJob(firstRun)
|
s.telemetry.RunTelemetryJob(firstRun)
|
||||||
}
|
}
|
||||||
|
|
||||||
httpServerExitDone.Wait()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +206,8 @@ func (s *Server) Shutdown() error {
|
|||||||
|
|
||||||
s.telemetry.Shutdown()
|
s.telemetry.Shutdown()
|
||||||
|
|
||||||
|
defer s.logger.Info("Server.Shutdown")
|
||||||
|
|
||||||
return s.store.Shutdown()
|
return s.store.Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
@ -71,14 +70,13 @@ func (ws *Server) registerRoutes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start runs the web server and start listening for charsetnnections.
|
// Start runs the web server and start listening for charsetnnections.
|
||||||
func (ws *Server) Start(wg *sync.WaitGroup) {
|
func (ws *Server) Start() {
|
||||||
ws.registerRoutes()
|
ws.registerRoutes()
|
||||||
|
|
||||||
isSSL := ws.ssl && fileExists("./cert/cert.pem") && fileExists("./cert/key.pem")
|
isSSL := ws.ssl && fileExists("./cert/cert.pem") && fileExists("./cert/key.pem")
|
||||||
if isSSL {
|
if isSSL {
|
||||||
log.Printf("https server started on :%d\n", ws.port)
|
log.Printf("https server started on :%d\n", ws.port)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
|
||||||
if err := ws.ListenAndServeTLS("./cert/cert.pem", "./cert/key.pem"); err != nil {
|
if err := ws.ListenAndServeTLS("./cert/cert.pem", "./cert/key.pem"); err != nil {
|
||||||
log.Fatalf("ListenAndServeTLS: %v", err)
|
log.Fatalf("ListenAndServeTLS: %v", err)
|
||||||
}
|
}
|
||||||
@ -89,10 +87,10 @@ func (ws *Server) Start(wg *sync.WaitGroup) {
|
|||||||
|
|
||||||
log.Printf("http server started on :%d\n", ws.port)
|
log.Printf("http server started on :%d\n", ws.port)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
|
||||||
if err := ws.ListenAndServe(); err != http.ErrServerClosed {
|
if err := ws.ListenAndServe(); err != http.ErrServerClosed {
|
||||||
log.Fatalf("ListenAndServe: %v", err)
|
log.Fatalf("ListenAndServe: %v", err)
|
||||||
}
|
}
|
||||||
|
log.Println("http server stopped")
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
win-wpf/.gitignore
vendored
Normal file
6
win-wpf/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
packages
|
||||||
|
obj
|
||||||
|
msix
|
||||||
|
*.msix
|
||||||
|
*.suo
|
||||||
|
*.csproj.user
|
26
win-wpf/AppxManifest.xml
Normal file
26
win-wpf/AppxManifest.xml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||||
|
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||||
|
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities">
|
||||||
|
<Identity Name="Mattermost.Focalboard" Publisher="CN=1111111-1111-1111-1111-111111111111" Version="1.0.0.0" ProcessorArchitecture="x64" />
|
||||||
|
<Properties>
|
||||||
|
<DisplayName>Focalboard</DisplayName>
|
||||||
|
<PublisherDisplayName>Mattermost</PublisherDisplayName>
|
||||||
|
<Description>Focalboard Desktop Edition</Description>
|
||||||
|
<Logo>Assets\StoreLogo.png</Logo>
|
||||||
|
</Properties>
|
||||||
|
<Resources>
|
||||||
|
<Resource Language="en-us" />
|
||||||
|
</Resources>
|
||||||
|
<Dependencies>
|
||||||
|
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.1" />
|
||||||
|
</Dependencies>
|
||||||
|
<Capabilities>
|
||||||
|
<rescap:Capability Name="runFullTrust"/>
|
||||||
|
</Capabilities>
|
||||||
|
<Applications>
|
||||||
|
<Application Id="Focalboard" Executable="Focalboard.exe" EntryPoint="Windows.FullTrustApplication">
|
||||||
|
<uap:VisualElements BackgroundColor="#464646" DisplayName="Focalboard" Square150x150Logo="Assets\icon150.png" Square44x44Logo="Assets\icon44.png" Description="Focalboard Desktop Edition" />
|
||||||
|
</Application>
|
||||||
|
</Applications>
|
||||||
|
</Package>
|
31
win-wpf/Focalboard.sln
Normal file
31
win-wpf/Focalboard.sln
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.30907.101
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Focalboard", "Focalboard\Focalboard.csproj", "{7B3F5C74-96AC-4521-9268-28BF2D91FCF4}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{7B3F5C74-96AC-4521-9268-28BF2D91FCF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7B3F5C74-96AC-4521-9268-28BF2D91FCF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7B3F5C74-96AC-4521-9268-28BF2D91FCF4}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{7B3F5C74-96AC-4521-9268-28BF2D91FCF4}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{7B3F5C74-96AC-4521-9268-28BF2D91FCF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7B3F5C74-96AC-4521-9268-28BF2D91FCF4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7B3F5C74-96AC-4521-9268-28BF2D91FCF4}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{7B3F5C74-96AC-4521-9268-28BF2D91FCF4}.Release|x64.Build.0 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {8583DA40-AB6E-4AC4-89EC-F2419CE044D1}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
24
win-wpf/Focalboard/App.config
Normal file
24
win-wpf/Focalboard/App.config
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<configSections>
|
||||||
|
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||||
|
<section name="Focalboard.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
|
||||||
|
</sectionGroup>
|
||||||
|
</configSections>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||||
|
</startup>
|
||||||
|
<userSettings>
|
||||||
|
<Focalboard.Properties.Settings>
|
||||||
|
<setting name="WindowPosition" serializeAs="String">
|
||||||
|
<value>50, 20</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="WindowSize" serializeAs="String">
|
||||||
|
<value>1024, 800</value>
|
||||||
|
</setting>
|
||||||
|
<setting name="WindowMaximized" serializeAs="String">
|
||||||
|
<value>False</value>
|
||||||
|
</setting>
|
||||||
|
</Focalboard.Properties.Settings>
|
||||||
|
</userSettings>
|
||||||
|
</configuration>
|
9
win-wpf/Focalboard/App.xaml
Normal file
9
win-wpf/Focalboard/App.xaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<Application x:Class="Focalboard.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:Focalboard"
|
||||||
|
StartupUri="MainWindow.xaml">
|
||||||
|
<Application.Resources>
|
||||||
|
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
141
win-wpf/Focalboard/App.xaml.cs
Normal file
141
win-wpf/Focalboard/App.xaml.cs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows;
|
||||||
|
using Windows.Storage;
|
||||||
|
|
||||||
|
namespace Focalboard {
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for App.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class App : Application {
|
||||||
|
public string sessionToken = "";
|
||||||
|
public int port;
|
||||||
|
|
||||||
|
private Mutex mutex;
|
||||||
|
|
||||||
|
App() {
|
||||||
|
SingleInstanceCheck();
|
||||||
|
|
||||||
|
Startup += App_Startup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SingleInstanceCheck() {
|
||||||
|
bool isOnlyInstance = false;
|
||||||
|
mutex = new Mutex(true, @"Focalboard", out isOnlyInstance);
|
||||||
|
if (!isOnlyInstance) {
|
||||||
|
ShowExistingWindow();
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("User32.dll")]
|
||||||
|
private static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||||
|
|
||||||
|
// shows the window of the single-instance that is already open
|
||||||
|
private void ShowExistingWindow() {
|
||||||
|
var currentProcess = Process.GetCurrentProcess();
|
||||||
|
var processes = Process.GetProcessesByName(currentProcess.ProcessName);
|
||||||
|
foreach (var process in processes) {
|
||||||
|
// the single-instance already open should have a MainWindowHandle
|
||||||
|
if (process.MainWindowHandle != IntPtr.Zero) {
|
||||||
|
// restores the window in case it was minimized
|
||||||
|
const int SW_SHOWNORMAL = 1;
|
||||||
|
ShowWindow(process.MainWindowHandle, SW_SHOWNORMAL);
|
||||||
|
|
||||||
|
// brings the window to the foreground
|
||||||
|
SetForegroundWindow(process.MainWindowHandle);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void App_Startup(object sender, StartupEventArgs e) {
|
||||||
|
Debug.WriteLine($"App_Startup()");
|
||||||
|
|
||||||
|
try {
|
||||||
|
InitServer();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
MessageBox.Show($"InitServer ERROR: {ex.ToString()}", "Focalboard");
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitServer() {
|
||||||
|
port = FindFreePort();
|
||||||
|
Debug.WriteLine("port: {0}", port);
|
||||||
|
|
||||||
|
sessionToken = CreateSessionToken();
|
||||||
|
|
||||||
|
// Need to set CWD so the server can read the config file
|
||||||
|
var appFolder = Utils.GetAppFolder();
|
||||||
|
Directory.SetCurrentDirectory(appFolder);
|
||||||
|
|
||||||
|
string tempFolder;
|
||||||
|
try {
|
||||||
|
tempFolder = ApplicationData.Current.LocalFolder.Path;
|
||||||
|
} catch {
|
||||||
|
var documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||||
|
tempFolder = documentsFolder;
|
||||||
|
// Not a UWP app, store in Documents
|
||||||
|
}
|
||||||
|
var dbPath = Path.Combine(tempFolder, "focalboard.db");
|
||||||
|
Debug.WriteLine($"dbPath: {dbPath}");
|
||||||
|
|
||||||
|
var cwd = Directory.GetCurrentDirectory();
|
||||||
|
var webFolder = Path.Combine(cwd, @"pack");
|
||||||
|
webFolder = webFolder.Replace(@"\", @"/");
|
||||||
|
dbPath = dbPath.Replace(@"\", @"/");
|
||||||
|
byte[] webFolderBytes = Encoding.UTF8.GetBytes(webFolder);
|
||||||
|
byte[] sessionTokenBytes = Encoding.UTF8.GetBytes(sessionToken);
|
||||||
|
byte[] dbPathBytes = Encoding.UTF8.GetBytes(dbPath);
|
||||||
|
GoFunctions.StartServer(webFolderBytes, port, sessionTokenBytes, dbPathBytes);
|
||||||
|
|
||||||
|
Debug.WriteLine("Server started");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CreateSessionToken() {
|
||||||
|
using (RandomNumberGenerator rng = new RNGCryptoServiceProvider()) {
|
||||||
|
byte[] tokenData = new byte[32];
|
||||||
|
rng.GetBytes(tokenData);
|
||||||
|
|
||||||
|
string token = Convert.ToBase64String(tokenData);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int FindFreePort() {
|
||||||
|
int port = 0;
|
||||||
|
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
try {
|
||||||
|
var localEP = new IPEndPoint(IPAddress.Any, 0);
|
||||||
|
socket.Bind(localEP);
|
||||||
|
localEP = (IPEndPoint)socket.LocalEndPoint;
|
||||||
|
port = localEP.Port;
|
||||||
|
} finally {
|
||||||
|
socket.Close();
|
||||||
|
}
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class GoFunctions {
|
||||||
|
[DllImport(@"focalboard-server.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
|
||||||
|
public static extern void StartServer(byte[] webPath, int port, byte[] singleUserToken, byte[] dbConfigString);
|
||||||
|
|
||||||
|
[DllImport(@"focalboard-server.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
|
||||||
|
public static extern void StopServer();
|
||||||
|
}
|
||||||
|
}
|
190
win-wpf/Focalboard/Focalboard.csproj
Normal file
190
win-wpf/Focalboard/Focalboard.csproj
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{7B3F5C74-96AC-4521-9268-28BF2D91FCF4}</ProjectGuid>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<RootNamespace>Focalboard</RootNamespace>
|
||||||
|
<AssemblyName>Focalboard</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
<NuGetPackageImportStamp>
|
||||||
|
</NuGetPackageImportStamp>
|
||||||
|
<PublishUrl>publish\</PublishUrl>
|
||||||
|
<Install>true</Install>
|
||||||
|
<InstallFrom>Disk</InstallFrom>
|
||||||
|
<UpdateEnabled>false</UpdateEnabled>
|
||||||
|
<UpdateMode>Foreground</UpdateMode>
|
||||||
|
<UpdateInterval>7</UpdateInterval>
|
||||||
|
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||||
|
<UpdatePeriodically>false</UpdatePeriodically>
|
||||||
|
<UpdateRequired>false</UpdateRequired>
|
||||||
|
<MapFileExtensions>true</MapFileExtensions>
|
||||||
|
<ApplicationRevision>0</ApplicationRevision>
|
||||||
|
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||||
|
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||||
|
<UseApplicationTrust>false</UseApplicationTrust>
|
||||||
|
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<LangVersion>7.3</LangVersion>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
|
<OutputPath>bin\x64\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<LangVersion>7.3</LangVersion>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ApplicationIcon>focalboard.ico</ApplicationIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Web.WebView2.Core, Version=1.0.705.50, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.705.50\lib\net45\Microsoft.Web.WebView2.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Web.WebView2.WinForms, Version=1.0.705.50, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.705.50\lib\net45\Microsoft.Web.WebView2.WinForms.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Web.WebView2.Wpf, Version=1.0.705.50, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.Web.WebView2.1.0.705.50\lib\net45\Microsoft.Web.WebView2.Wpf.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Runtime.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>$(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xaml">
|
||||||
|
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Windows">
|
||||||
|
<HintPath>$(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
|
<Reference Include="PresentationCore" />
|
||||||
|
<Reference Include="PresentationFramework" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Include="App.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</ApplicationDefinition>
|
||||||
|
<Compile Include="Utils.cs" />
|
||||||
|
<Compile Include="Webview2Installer.cs" />
|
||||||
|
<Page Include="MainWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="App.xaml.cs">
|
||||||
|
<DependentUpon>App.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="MainWindow.xaml.cs">
|
||||||
|
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\Settings.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
</Compile>
|
||||||
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
<None Include="Properties\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<BootstrapperPackage Include=".NETFramework,Version=v4.7.2">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>Microsoft .NET Framework 4.7.2 %28x86 and x64%29</ProductName>
|
||||||
|
<Install>true</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||||
|
<Install>false</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Resource Include="focalboard.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Import Project="..\packages\Microsoft.Web.WebView2.1.0.705.50\build\Microsoft.Web.WebView2.targets" Condition="Exists('..\packages\Microsoft.Web.WebView2.1.0.705.50\build\Microsoft.Web.WebView2.targets')" />
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.705.50\build\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.705.50\build\Microsoft.Web.WebView2.targets'))" />
|
||||||
|
</Target>
|
||||||
|
<PropertyGroup>
|
||||||
|
<PostBuildEvent>copy "$(ProjectDir)..\..\bin\win-dll\*" "$(TargetDir)"
|
||||||
|
copy "$(ProjectDir)..\..\app-config.json" "$(TargetDir)config.json"
|
||||||
|
rd /s /q "$(TargetDir)pack"
|
||||||
|
md "$(TargetDir)pack"
|
||||||
|
xcopy /E /I /Y "$(ProjectDir)..\..\webapp\pack" "$(TargetDir)pack\"</PostBuildEvent>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
16
win-wpf/Focalboard/MainWindow.xaml
Normal file
16
win-wpf/Focalboard/MainWindow.xaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<Window x:Class="Focalboard.MainWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
|
||||||
|
xmlns:local="clr-namespace:Focalboard"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="Focalboard" Height="800" Width="1024">
|
||||||
|
<DockPanel>
|
||||||
|
<Label Name="installingLabel" Visibility="Collapsed" DockPanel.Dock="Top">Downloading webview2...</Label>
|
||||||
|
<wv2:WebView2
|
||||||
|
Name="webView"
|
||||||
|
/>
|
||||||
|
</DockPanel>
|
||||||
|
</Window>
|
153
win-wpf/Focalboard/MainWindow.xaml.cs
Normal file
153
win-wpf/Focalboard/MainWindow.xaml.cs
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using Microsoft.Web.WebView2.Core;
|
||||||
|
|
||||||
|
namespace Focalboard {
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for MainWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class MainWindow : Window {
|
||||||
|
private int port {
|
||||||
|
get { return ((App)Application.Current).port; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private string sessionToken {
|
||||||
|
get { return ((App)Application.Current).sessionToken; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public MainWindow() {
|
||||||
|
Debug.WriteLine($"MainWindow()");
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
RestoreWindowsState();
|
||||||
|
|
||||||
|
this.Loaded += MainWindow_Loaded;
|
||||||
|
this.Closing += MainWindow_Closing;
|
||||||
|
|
||||||
|
InitializeWebView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainWindow_Loaded(object sender, RoutedEventArgs e) {
|
||||||
|
Activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PromptToInstallWebview2() {
|
||||||
|
var dialogResult = MessageBox.Show(
|
||||||
|
"Focalboard requires the WebView2 runtime to be downloaded and installed. Install now?",
|
||||||
|
"Focalboard",
|
||||||
|
MessageBoxButton.YesNo,
|
||||||
|
MessageBoxImage.Information,
|
||||||
|
MessageBoxResult.OK,
|
||||||
|
MessageBoxOptions.DefaultDesktopOnly);
|
||||||
|
|
||||||
|
if (dialogResult == MessageBoxResult.Yes) {
|
||||||
|
installingLabel.Visibility = Visibility.Visible;
|
||||||
|
webView.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
var installer = new Webview2Installer();
|
||||||
|
installer.InstallProgress += Installer_InstallProgress;
|
||||||
|
installer.InstallCompleted += Installer_InstallCompleted;
|
||||||
|
installer.DownloadAndInstall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Installer_InstallProgress(Webview2Installer sender, EventArgs e) {
|
||||||
|
Application.Current.Dispatcher.Invoke(() => {
|
||||||
|
if (sender.downloadProgress < 100) {
|
||||||
|
installingLabel.Content = $"Downloading Webview2: {sender.downloadProgress}%";
|
||||||
|
} else {
|
||||||
|
installingLabel.Content = "Installing Webview2...";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Installer_InstallCompleted(Webview2Installer sender, EventArgs e) {
|
||||||
|
Application.Current.Dispatcher.Invoke(() => {
|
||||||
|
installingLabel.Content = "Webview2 install completed";
|
||||||
|
Activate();
|
||||||
|
|
||||||
|
if (sender.exitCode != 0) {
|
||||||
|
var message = $"Webview2 install FAILED with code {sender.exitCode}. Try again.";
|
||||||
|
MessageBox.Show(message, "Install failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reopen window
|
||||||
|
var window = new MainWindow();
|
||||||
|
window.Show();
|
||||||
|
Close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveWindowState() {
|
||||||
|
try {
|
||||||
|
Properties.Settings.Default.WindowPosition = new System.Drawing.Point(
|
||||||
|
Convert.ToInt32(RestoreBounds.Location.X),
|
||||||
|
Convert.ToInt32(RestoreBounds.Location.Y));
|
||||||
|
|
||||||
|
Properties.Settings.Default.WindowSize = new System.Drawing.Size(
|
||||||
|
Convert.ToInt32(RestoreBounds.Size.Width),
|
||||||
|
Convert.ToInt32(RestoreBounds.Size.Height));
|
||||||
|
|
||||||
|
Properties.Settings.Default.WindowMaximized = (WindowState == WindowState.Maximized);
|
||||||
|
Properties.Settings.Default.Save();
|
||||||
|
} catch {
|
||||||
|
// Ignore errors, e.g. overflow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RestoreWindowsState() {
|
||||||
|
this.Left = Properties.Settings.Default.WindowPosition.X;
|
||||||
|
this.Top = Properties.Settings.Default.WindowPosition.Y;
|
||||||
|
this.Width = Math.Max(300, Properties.Settings.Default.WindowSize.Width);
|
||||||
|
this.Height = Math.Max(200, Properties.Settings.Default.WindowSize.Height);
|
||||||
|
|
||||||
|
if (Properties.Settings.Default.WindowMaximized) {
|
||||||
|
WindowState = WindowState.Maximized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
|
||||||
|
SaveWindowState();
|
||||||
|
}
|
||||||
|
|
||||||
|
async void InitializeWebView() {
|
||||||
|
string version = GetWebView2Version();
|
||||||
|
var isAltKeyPressed = (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt));
|
||||||
|
if (version == "" || isAltKeyPressed) {
|
||||||
|
PromptToInstallWebview2();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Title = $"Focalboard (port {port} WebView {version})";
|
||||||
|
|
||||||
|
// must create a data folder if running out of a secured folder that can't write like Program Files
|
||||||
|
var env = await CoreWebView2Environment.CreateAsync(
|
||||||
|
userDataFolder: Path.Combine(Path.GetTempPath(), "Focalboard")
|
||||||
|
);
|
||||||
|
await webView.EnsureCoreWebView2Async(env);
|
||||||
|
|
||||||
|
webView.ContentLoading += WebView_ContentLoading;
|
||||||
|
|
||||||
|
var url = String.Format("http://localhost:{0}", port);
|
||||||
|
webView.Source = new Uri(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetWebView2Version() {
|
||||||
|
try {
|
||||||
|
return CoreWebView2Environment.GetAvailableBrowserVersionString();
|
||||||
|
} catch (Exception) { return ""; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WebView_ContentLoading(object sender, CoreWebView2ContentLoadingEventArgs e) {
|
||||||
|
// Set sessionId
|
||||||
|
string script = $"localStorage.setItem('sessionId', '{sessionToken}');";
|
||||||
|
webView.ExecuteScriptAsync(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
win-wpf/Focalboard/Properties/AssemblyInfo.cs
Normal file
55
win-wpf/Focalboard/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("Focalboard")]
|
||||||
|
[assembly: AssemblyDescription("Focalboard Windows App")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("Focalboard")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © Mattermost, Inc. 2021")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
//In order to begin building localizable applications, set
|
||||||
|
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||||
|
//inside a <PropertyGroup>. For example, if you are using US english
|
||||||
|
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||||
|
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||||
|
//the line below to match the UICulture setting in the project file.
|
||||||
|
|
||||||
|
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||||
|
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
||||||
|
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
70
win-wpf/Focalboard/Properties/Resources.Designer.cs
generated
Normal file
70
win-wpf/Focalboard/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
namespace Focalboard.Properties
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources
|
||||||
|
{
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if ((resourceMan == null))
|
||||||
|
{
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Focalboard.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
117
win-wpf/Focalboard/Properties/Resources.resx
Normal file
117
win-wpf/Focalboard/Properties/Resources.resx
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
62
win-wpf/Focalboard/Properties/Settings.Designer.cs
generated
Normal file
62
win-wpf/Focalboard/Properties/Settings.Designer.cs
generated
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Focalboard.Properties {
|
||||||
|
|
||||||
|
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default {
|
||||||
|
get {
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("50, 20")]
|
||||||
|
public global::System.Drawing.Point WindowPosition {
|
||||||
|
get {
|
||||||
|
return ((global::System.Drawing.Point)(this["WindowPosition"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["WindowPosition"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("1024, 800")]
|
||||||
|
public global::System.Drawing.Size WindowSize {
|
||||||
|
get {
|
||||||
|
return ((global::System.Drawing.Size)(this["WindowSize"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["WindowSize"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||||
|
public bool WindowMaximized {
|
||||||
|
get {
|
||||||
|
return ((bool)(this["WindowMaximized"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["WindowMaximized"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
win-wpf/Focalboard/Properties/Settings.settings
Normal file
15
win-wpf/Focalboard/Properties/Settings.settings
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Focalboard.Properties" GeneratedClassName="Settings">
|
||||||
|
<Profiles />
|
||||||
|
<Settings>
|
||||||
|
<Setting Name="WindowPosition" Type="System.Drawing.Point" Scope="User">
|
||||||
|
<Value Profile="(Default)">50, 20</Value>
|
||||||
|
</Setting>
|
||||||
|
<Setting Name="WindowSize" Type="System.Drawing.Size" Scope="User">
|
||||||
|
<Value Profile="(Default)">1024, 800</Value>
|
||||||
|
</Setting>
|
||||||
|
<Setting Name="WindowMaximized" Type="System.Boolean" Scope="User">
|
||||||
|
<Value Profile="(Default)">False</Value>
|
||||||
|
</Setting>
|
||||||
|
</Settings>
|
||||||
|
</SettingsFile>
|
21
win-wpf/Focalboard/Utils.cs
Normal file
21
win-wpf/Focalboard/Utils.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Focalboard {
|
||||||
|
static class Utils {
|
||||||
|
public static string GetAppFolder() {
|
||||||
|
string appFolder;
|
||||||
|
|
||||||
|
try {
|
||||||
|
appFolder = Windows.ApplicationModel.Package.Current.InstalledLocation.Path;
|
||||||
|
} catch {
|
||||||
|
// Not a UWP app
|
||||||
|
string appPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
||||||
|
appFolder = Path.GetDirectoryName(appPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return appFolder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
win-wpf/Focalboard/Webview2Installer.cs
Normal file
67
win-wpf/Focalboard/Webview2Installer.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Windows;
|
||||||
|
using Windows.Storage;
|
||||||
|
|
||||||
|
namespace Focalboard {
|
||||||
|
class Webview2Installer {
|
||||||
|
public int exitCode = -1;
|
||||||
|
public int downloadProgress = 0;
|
||||||
|
|
||||||
|
public delegate void InstallerHandler(Webview2Installer sender, EventArgs e);
|
||||||
|
public event InstallerHandler InstallProgress;
|
||||||
|
public event InstallerHandler InstallCompleted;
|
||||||
|
|
||||||
|
private string filePath;
|
||||||
|
|
||||||
|
public Webview2Installer() {
|
||||||
|
const string filename = "MicrosoftEdgeWebview2Setup.exe";
|
||||||
|
var downloadsFolder = UserDataPaths.GetDefault().Downloads;
|
||||||
|
filePath = Path.Combine(downloadsFolder, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DownloadAndInstall() {
|
||||||
|
const string url = "https://go.microsoft.com/fwlink/p/?LinkId=2124703";
|
||||||
|
var uri = new Uri(url);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (File.Exists(filePath)) {
|
||||||
|
File.Delete(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
WebClient wc = new WebClient();
|
||||||
|
wc.DownloadFileAsync(uri, filePath);
|
||||||
|
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
|
||||||
|
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
MessageBox.Show(ex.Message.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
|
||||||
|
downloadProgress = e.ProgressPercentage;
|
||||||
|
InstallProgress?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) {
|
||||||
|
if (e.Error == null) {
|
||||||
|
var proc = Process.Start(filePath);
|
||||||
|
proc.EnableRaisingEvents = true;
|
||||||
|
proc.Exited += Proc_Exited;
|
||||||
|
} else {
|
||||||
|
MessageBox.Show($"Unable to download webview2 installer, please check your Internet connection. ERROR: {e.Error.Message}", "Download failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Proc_Exited(object sender, EventArgs e) {
|
||||||
|
var proc = (Process)sender;
|
||||||
|
exitCode = proc.ExitCode;
|
||||||
|
InstallCompleted?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
win-wpf/Focalboard/focalboard.ico
Normal file
BIN
win-wpf/Focalboard/focalboard.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 107 KiB |
4
win-wpf/Focalboard/packages.config
Normal file
4
win-wpf/Focalboard/packages.config
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Microsoft.Web.WebView2" version="1.0.705.50" targetFramework="net472" />
|
||||||
|
</packages>
|
BIN
win-wpf/art/StoreLogo.png
Normal file
BIN
win-wpf/art/StoreLogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
BIN
win-wpf/art/icon150.png
Normal file
BIN
win-wpf/art/icon150.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
BIN
win-wpf/art/icon44.png
Normal file
BIN
win-wpf/art/icon44.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
11
win-wpf/build.bat
Normal file
11
win-wpf/build.bat
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
WHERE msbuild.exe > nul 2>&1
|
||||||
|
IF %ERRORLEVEL% NEQ 0 set PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin
|
||||||
|
|
||||||
|
WHERE msbuild.exe > nul
|
||||||
|
IF %ERRORLEVEL% NEQ 0 echo msbuild.exe not found; exit /b 1
|
||||||
|
|
||||||
|
echo Building...
|
||||||
|
|
||||||
|
msbuild.exe Focalboard.sln /t:Rebuild /p:Configuration=Release /p:Platform="x64" /p:DebugSymbols=false /p:DebugType=None
|
19
win-wpf/package.bat
Normal file
19
win-wpf/package.bat
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
WHERE makeappx.exe > nul 2>&1
|
||||||
|
IF %ERRORLEVEL% NEQ 0 set PATH=%PATH%;C:\Program Files (x86)\Windows Kits\10\App Certification Kit
|
||||||
|
|
||||||
|
WHERE makeappx.exe > nul
|
||||||
|
IF %ERRORLEVEL% NEQ 0 echo makeappx.exe not found; exit /b 1
|
||||||
|
|
||||||
|
echo Packaging...
|
||||||
|
|
||||||
|
rd /s /q msix
|
||||||
|
mkdir msix
|
||||||
|
xcopy /e /i /y Focalboard\bin\x64\Release msix
|
||||||
|
mkdir msix\Assets
|
||||||
|
copy art\StoreLogo.png msix\Assets
|
||||||
|
copy art\icon150.png msix\Assets
|
||||||
|
copy art\icon44.png msix\Assets
|
||||||
|
copy AppxManifest.xml msix
|
||||||
|
makeappx.exe pack /o /v /d msix /p Focalboard.msix
|
Loading…
Reference in New Issue
Block a user