mirror of
https://github.com/mattermost/focalboard.git
synced 2024-11-19 20:32:00 +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")
|
||||
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
|
||||
rm -rf package
|
||||
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; 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
|
||||
rm -rf linux/temp
|
||||
rm -rf linux/dist
|
||||
|
@ -26,9 +26,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"C"
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@ -37,8 +39,8 @@ import (
|
||||
"github.com/mattermost/focalboard/server/services/config"
|
||||
)
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// WebSocket OnChange listener
|
||||
// Active server used with shared code (dll)
|
||||
var pServer *server.Server
|
||||
|
||||
const (
|
||||
timeBetweenPidMonitoringChecks = 2 * time.Second
|
||||
@ -55,6 +57,7 @@ func isProcessRunning(pid int) bool {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// monitorPid is used to keep the server lifetime in sync with another (client app) process
|
||||
func monitorPid(pid int) {
|
||||
log.Printf("Monitoring PID: %d", pid)
|
||||
|
||||
@ -70,13 +73,17 @@ func monitorPid(pid int) {
|
||||
}()
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Log version
|
||||
func logInfo() {
|
||||
log.Println("Focalboard Server")
|
||||
log.Println("Version: " + model.CurrentVersion)
|
||||
log.Println("Edition: " + model.Edition)
|
||||
log.Println("Build Number: " + model.BuildNumber)
|
||||
log.Println("Build Date: " + model.BuildDate)
|
||||
log.Println("Build Hash: " + model.BuildHash)
|
||||
}
|
||||
|
||||
func main() {
|
||||
logInfo()
|
||||
|
||||
// config.json file
|
||||
config, err := config.ReadConfigFile()
|
||||
@ -89,6 +96,8 @@ func main() {
|
||||
pMonitorPid := flag.Int("monitorpid", -1, "a process ID")
|
||||
pPort := flag.Int("port", config.Port, "the port number")
|
||||
pSingleUser := flag.Bool("single-user", false, "single user mode")
|
||||
pDBType := flag.String("dbtype", "", "Database type")
|
||||
pDBConfig := flag.String("dbconfig", "", "Database config")
|
||||
flag.Parse()
|
||||
|
||||
singleUser := false
|
||||
@ -110,6 +119,19 @@ func main() {
|
||||
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 {
|
||||
// Override port
|
||||
log.Printf("Port from commandline: %d", *pPort)
|
||||
@ -124,4 +146,78 @@ func main() {
|
||||
if err := server.Start(); err != nil {
|
||||
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/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@ -91,21 +89,6 @@ func New(cfg *config.Configuration, singleUserToken string) (*Server, error) {
|
||||
webServer.AddRoutes(wsServer)
|
||||
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
|
||||
settings, err := store.GetSystemSettings()
|
||||
if err != nil {
|
||||
@ -182,10 +165,9 @@ func New(cfg *config.Configuration, singleUserToken string) (*Server, error) {
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
httpServerExitDone := &sync.WaitGroup{}
|
||||
httpServerExitDone.Add(1)
|
||||
s.logger.Info("Server.Start")
|
||||
|
||||
s.webServer.Start(httpServerExitDone)
|
||||
s.webServer.Start()
|
||||
|
||||
if s.config.EnableLocalMode {
|
||||
if err := s.startLocalModeServer(); err != nil {
|
||||
@ -208,8 +190,6 @@ func (s *Server) Start() error {
|
||||
s.telemetry.RunTelemetryJob(firstRun)
|
||||
}
|
||||
|
||||
httpServerExitDone.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -226,6 +206,8 @@ func (s *Server) Shutdown() error {
|
||||
|
||||
s.telemetry.Shutdown()
|
||||
|
||||
defer s.logger.Info("Server.Shutdown")
|
||||
|
||||
return s.store.Shutdown()
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
@ -71,14 +70,13 @@ func (ws *Server) registerRoutes() {
|
||||
}
|
||||
|
||||
// Start runs the web server and start listening for charsetnnections.
|
||||
func (ws *Server) Start(wg *sync.WaitGroup) {
|
||||
func (ws *Server) Start() {
|
||||
ws.registerRoutes()
|
||||
|
||||
isSSL := ws.ssl && fileExists("./cert/cert.pem") && fileExists("./cert/key.pem")
|
||||
if isSSL {
|
||||
log.Printf("https server started on :%d\n", ws.port)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := ws.ListenAndServeTLS("./cert/cert.pem", "./cert/key.pem"); err != nil {
|
||||
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)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := ws.ListenAndServe(); err != http.ErrServerClosed {
|
||||
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