mirror of
https://github.com/wavetermdev/wails.git
synced 2026-08-05 13:53:43 -07:00
Merge latest v2 changes
This commit is contained in:
@@ -4,6 +4,7 @@ version: "3"
|
||||
|
||||
tasks:
|
||||
release:
|
||||
summary: Release a new version of Task. Call with `task v2:release -- <version>`
|
||||
dir: tools/release
|
||||
cmds:
|
||||
- go run release.go {{.CLI_ARGS}}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -138,20 +139,6 @@ func Application(f *flags.Dev, logger *clilogger.CLILogger) error {
|
||||
}
|
||||
}
|
||||
|
||||
// create the project files watcher
|
||||
watcher, err := initialiseWatcher(cwd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func(watcher *fsnotify.Watcher) {
|
||||
err := watcher.Close()
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}(watcher)
|
||||
|
||||
logutils.LogGreen("Watching (sub)/directory: %s", cwd)
|
||||
logutils.LogGreen("Using DevServer URL: %s", f.DevServerURL())
|
||||
if f.FrontendDevServerURL != "" {
|
||||
logutils.LogGreen("Using Frontend DevServer URL: %s", f.FrontendDevServerURL)
|
||||
@@ -165,7 +152,10 @@ func Application(f *flags.Dev, logger *clilogger.CLILogger) error {
|
||||
}()
|
||||
|
||||
// Watch for changes and trigger restartApp()
|
||||
debugBinaryProcess = doWatcherLoop(buildOptions, debugBinaryProcess, f, watcher, exitCodeChannel, quitChannel, f.DevServerURL(), legacyUseDevServerInsteadofCustomScheme)
|
||||
debugBinaryProcess, err = doWatcherLoop(cwd, buildOptions, debugBinaryProcess, f, exitCodeChannel, quitChannel, f.DevServerURL(), legacyUseDevServerInsteadofCustomScheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Kill the current program if running and remove dev binary
|
||||
if err := killProcessAndCleanupBinary(debugBinaryProcess, appBinary); err != nil {
|
||||
@@ -318,9 +308,6 @@ func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process
|
||||
os.Setenv("assetdir", f.AssetDir)
|
||||
os.Setenv("devserver", f.DevServer)
|
||||
os.Setenv("frontenddevserverurl", f.FrontendDevServerURL)
|
||||
if legacyUseDevServerInsteadofCustomScheme {
|
||||
os.Setenv("legacyusedevsererinsteadofcustomscheme", "true")
|
||||
}
|
||||
|
||||
// Start up new binary with correct args
|
||||
newProcess := process.NewProcess(appBinary, args...)
|
||||
@@ -340,7 +327,23 @@ func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process
|
||||
}
|
||||
|
||||
// doWatcherLoop is the main watch loop that runs while dev is active
|
||||
func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Process, f *flags.Dev, watcher *fsnotify.Watcher, exitCodeChannel chan int, quitChannel chan os.Signal, devServerURL *url.URL, legacyUseDevServerInsteadofCustomScheme bool) *process.Process {
|
||||
func doWatcherLoop(cwd string, buildOptions *build.Options, debugBinaryProcess *process.Process, f *flags.Dev, exitCodeChannel chan int, quitChannel chan os.Signal, devServerURL *url.URL, legacyUseDevServerInsteadofCustomScheme bool) (*process.Process, error) {
|
||||
// create the project files watcher
|
||||
watcher, err := initialiseWatcher(cwd)
|
||||
if err != nil {
|
||||
logutils.LogRed("Unable to create filesystem watcher. Reloads will not occur.")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func(watcher *fsnotify.Watcher) {
|
||||
err := watcher.Close()
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}(watcher)
|
||||
|
||||
logutils.LogGreen("Watching (sub)/directory: %s", cwd)
|
||||
|
||||
// Main Loop
|
||||
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(f.Extensions, ","))
|
||||
var dirsThatTriggerAReload []string
|
||||
@@ -354,6 +357,12 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc
|
||||
continue
|
||||
}
|
||||
dirsThatTriggerAReload = append(dirsThatTriggerAReload, thePath)
|
||||
err = watcher.Add(thePath)
|
||||
if err != nil {
|
||||
logutils.LogRed("Unable to watch path: %s due to error %v", thePath, err)
|
||||
} else {
|
||||
logutils.LogGreen("Watching (sub)/directory: %s", thePath)
|
||||
}
|
||||
}
|
||||
|
||||
quit := false
|
||||
@@ -502,7 +511,7 @@ func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Proc
|
||||
quit = true
|
||||
}
|
||||
}
|
||||
return debugBinaryProcess
|
||||
return debugBinaryProcess, nil
|
||||
}
|
||||
|
||||
func joinPath(url *url.URL, subPath string) string {
|
||||
|
||||
@@ -38,7 +38,6 @@ func initialiseWatcher(cwd string) (*fsnotify.Watcher, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
println("watching: " + dir)
|
||||
}
|
||||
return watcher, nil
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
v2.5.1
|
||||
v2.6.0
|
||||
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
//go:build devtools
|
||||
|
||||
package app
|
||||
|
||||
func IsDevtoolsEnabled() bool {
|
||||
return true
|
||||
}
|
||||
//go:build devtools
|
||||
|
||||
package app
|
||||
|
||||
func IsDevtoolsEnabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//go:build !devtools
|
||||
|
||||
package app
|
||||
|
||||
func IsDevtoolsEnabled() bool {
|
||||
return false
|
||||
}
|
||||
//go:build !devtools
|
||||
|
||||
package app
|
||||
|
||||
func IsDevtoolsEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ void ShowApplication(void* ctx);
|
||||
void SetBackgroundColour(void* ctx, int r, int g, int b, int a);
|
||||
void ExecJS(void* ctx, const char*);
|
||||
void Quit(void*);
|
||||
void WindowPrint(void* ctx);
|
||||
|
||||
const char* GetSize(void *ctx);
|
||||
const char* GetPosition(void *ctx);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#import "WailsContext.h"
|
||||
#import "Application.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "WindowDelegate.h"
|
||||
#import "WailsMenu.h"
|
||||
#import "WailsMenuItem.h"
|
||||
|
||||
@@ -384,3 +385,36 @@ void ReleaseContext(void *inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
[ctx release];
|
||||
}
|
||||
|
||||
// Credit: https://stackoverflow.com/q/33319295
|
||||
void WindowPrint(void *inctx) {
|
||||
|
||||
// Check if macOS 11.0 or newer
|
||||
if (@available(macOS 11.0, *)) {
|
||||
ON_MAIN_THREAD(
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
WKWebView* webView = ctx.webview;
|
||||
|
||||
// I think this should be exposed as a config
|
||||
// It directly affects the printed output/PDF
|
||||
NSPrintInfo *pInfo = [NSPrintInfo sharedPrintInfo];
|
||||
pInfo.horizontalPagination = NSPrintingPaginationModeAutomatic;
|
||||
pInfo.verticalPagination = NSPrintingPaginationModeAutomatic;
|
||||
pInfo.verticallyCentered = YES;
|
||||
pInfo.horizontallyCentered = YES;
|
||||
pInfo.orientation = NSPaperOrientationLandscape;
|
||||
pInfo.leftMargin = 0;
|
||||
pInfo.rightMargin = 0;
|
||||
pInfo.topMargin = 0;
|
||||
pInfo.bottomMargin = 0;
|
||||
|
||||
NSPrintOperation *po = [webView printOperationWithPrintInfo:pInfo];
|
||||
po.showsPrintPanel = YES;
|
||||
po.showsProgressPanel = YES;
|
||||
|
||||
po.view.frame = webView.bounds;
|
||||
|
||||
[po runOperationModalForWindow:ctx.mainWindow delegate:ctx.mainWindow.delegate didRunSelector:nil contextInfo:nil];
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -286,6 +286,10 @@ func (f *Frontend) Quit() {
|
||||
f.mainWindow.Quit()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowPrint() {
|
||||
f.mainWindow.Print()
|
||||
}
|
||||
|
||||
type EventNotify struct {
|
||||
Name string `json:"name"`
|
||||
Data []interface{} `json:"data"`
|
||||
|
||||
@@ -263,3 +263,7 @@ func (w *Window) SetApplicationMenu(inMenu *menu.Menu) {
|
||||
func (w *Window) UpdateApplicationMenu() {
|
||||
C.UpdateApplicationMenu(w.context)
|
||||
}
|
||||
|
||||
func (w Window) Print() {
|
||||
C.WindowPrint(w.context)
|
||||
}
|
||||
|
||||
@@ -362,6 +362,10 @@ func (f *Frontend) Quit() {
|
||||
f.mainWindow.Quit()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowPrint() {
|
||||
f.ExecJS("window.print();")
|
||||
}
|
||||
|
||||
type EventNotify struct {
|
||||
Name string `json:"name"`
|
||||
Data []interface{} `json:"data"`
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <locale.h>
|
||||
#include "window.h"
|
||||
|
||||
// These are the x,y,time & button of the last mouse down event
|
||||
@@ -145,20 +146,39 @@ void SetBackgroundColour(void *data)
|
||||
{
|
||||
// set webview's background color
|
||||
RGBAOptions *options = (RGBAOptions *)data;
|
||||
|
||||
GdkRGBA colour = {options->r / 255.0, options->g / 255.0, options->b / 255.0, options->a / 255.0};
|
||||
if (options->windowIsTranslucent != NULL && options->windowIsTranslucent == TRUE)
|
||||
{
|
||||
colour.alpha = 0.0;
|
||||
}
|
||||
webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(options->webview), &colour);
|
||||
|
||||
// set window's background color
|
||||
GtkWidget *window = GTK_WIDGET(options->window);
|
||||
gchar *str = g_strdup_printf("window {background-color: rgba(%d, %d, %d, %d);}", options->r, options->g, options->b, options->a);
|
||||
// Get the name of the current locale
|
||||
char *old_locale, *saved_locale;
|
||||
old_locale = setlocale(LC_ALL, NULL);
|
||||
|
||||
// Copy the name so it won’t be clobbered by setlocale.
|
||||
saved_locale = strdup(old_locale);
|
||||
if (saved_locale == NULL)
|
||||
return;
|
||||
|
||||
//Now change the locale to english for so printf always converts floats with a dot decimal separator
|
||||
setlocale(LC_ALL, "en_US.UTF-8");
|
||||
gchar *str = g_strdup_printf("#webview-box {background-color: rgba(%d, %d, %d, %1.1f);}", options->r, options->g, options->b, options->a / 255.0);
|
||||
|
||||
//Restore the original locale.
|
||||
setlocale(LC_ALL, saved_locale);
|
||||
free(saved_locale);
|
||||
|
||||
if (windowCssProvider == NULL)
|
||||
{
|
||||
windowCssProvider = gtk_css_provider_new();
|
||||
gtk_style_context_add_provider(
|
||||
gtk_widget_get_style_context(window),
|
||||
gtk_widget_get_style_context(GTK_WIDGET(options->webviewBox)),
|
||||
GTK_STYLE_PROVIDER(windowCssProvider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
g_object_unref(windowCssProvider);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ type Window struct {
|
||||
webview unsafe.Pointer
|
||||
applicationMenu *menu.Menu
|
||||
menubar *C.GtkWidget
|
||||
webviewBox *C.GtkWidget
|
||||
vbox *C.GtkWidget
|
||||
accels *C.GtkAccelGroup
|
||||
minWidth, minHeight, maxWidth, maxHeight int
|
||||
@@ -72,6 +73,11 @@ func NewWindow(appoptions *options.App, debug bool, devtools bool) *Window {
|
||||
C.g_object_ref_sink(C.gpointer(gtkWindow))
|
||||
result.gtkWindow = unsafe.Pointer(gtkWindow)
|
||||
|
||||
webviewName := C.CString("webview-box")
|
||||
defer C.free(unsafe.Pointer(webviewName))
|
||||
result.webviewBox = C.gtk_box_new(C.GTK_ORIENTATION_VERTICAL, 0)
|
||||
C.gtk_widget_set_name(result.webviewBox, webviewName)
|
||||
|
||||
result.vbox = C.gtk_box_new(C.GTK_ORIENTATION_VERTICAL, 0)
|
||||
C.gtk_container_add(result.asGTKContainer(), result.vbox)
|
||||
|
||||
@@ -265,13 +271,18 @@ func (w *Window) IsNormal() bool {
|
||||
}
|
||||
|
||||
func (w *Window) SetBackgroundColour(r uint8, g uint8, b uint8, a uint8) {
|
||||
windowIsTranslucent := false
|
||||
if w.appoptions.Linux != nil && w.appoptions.Linux.WindowIsTranslucent {
|
||||
windowIsTranslucent = true
|
||||
}
|
||||
data := C.RGBAOptions{
|
||||
r: C.uchar(r),
|
||||
g: C.uchar(g),
|
||||
b: C.uchar(b),
|
||||
a: C.uchar(a),
|
||||
webview: w.webview,
|
||||
window: w.gtkWindow,
|
||||
r: C.uchar(r),
|
||||
g: C.uchar(g),
|
||||
b: C.uchar(b),
|
||||
a: C.uchar(a),
|
||||
webview: w.webview,
|
||||
webviewBox: unsafe.Pointer(w.webviewBox),
|
||||
windowIsTranslucent: gtkBool(windowIsTranslucent),
|
||||
}
|
||||
invokeOnMainThread(func() { C.SetBackgroundColour(unsafe.Pointer(&data)) })
|
||||
|
||||
@@ -288,7 +299,9 @@ func (w *Window) Run(url string) {
|
||||
if w.menubar != nil {
|
||||
C.gtk_box_pack_start(C.GTKBOX(unsafe.Pointer(w.vbox)), w.menubar, 0, 0, 0)
|
||||
}
|
||||
C.gtk_box_pack_start(C.GTKBOX(unsafe.Pointer(w.vbox)), C.GTKWIDGET(w.webview), 1, 1, 0)
|
||||
|
||||
C.gtk_box_pack_start(C.GTKBOX(unsafe.Pointer(w.webviewBox)), C.GTKWIDGET(w.webview), 1, 1, 0)
|
||||
C.gtk_box_pack_start(C.GTKBOX(unsafe.Pointer(w.vbox)), w.webviewBox, 1, 1, 0)
|
||||
_url := C.CString(url)
|
||||
C.LoadIndex(w.webview, _url)
|
||||
defer C.free(unsafe.Pointer(_url))
|
||||
|
||||
@@ -55,7 +55,8 @@ typedef struct RGBAOptions
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
void *webview;
|
||||
void *window;
|
||||
void *webviewBox;
|
||||
gboolean windowIsTranslucent;
|
||||
} RGBAOptions;
|
||||
|
||||
typedef struct SetTitleArgs
|
||||
|
||||
@@ -425,6 +425,10 @@ func (f *Frontend) Quit() {
|
||||
f.mainWindow.Invoke(winc.Exit)
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowPrint() {
|
||||
f.ExecJS("window.print();")
|
||||
}
|
||||
|
||||
func (f *Frontend) setupChromium() {
|
||||
chromium := f.chromium
|
||||
|
||||
|
||||
@@ -121,6 +121,7 @@ type Frontend interface {
|
||||
WindowIsNormal() bool
|
||||
WindowIsFullscreen() bool
|
||||
WindowClose()
|
||||
WindowPrint()
|
||||
|
||||
//Screen
|
||||
ScreenGetAll() ([]Screen, error)
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
//go:build windows
|
||||
|
||||
package win32
|
||||
|
||||
type Menu HMENU
|
||||
type PopupMenu Menu
|
||||
|
||||
func CreatePopupMenu() PopupMenu {
|
||||
ret, _, _ := procCreatePopupMenu.Call(0, 0, 0, 0)
|
||||
return PopupMenu(ret)
|
||||
}
|
||||
|
||||
func (m Menu) Destroy() bool {
|
||||
ret, _, _ := procDestroyMenu.Call(uintptr(m))
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func (p PopupMenu) Destroy() bool {
|
||||
return Menu(p).Destroy()
|
||||
}
|
||||
|
||||
func (p PopupMenu) Track(flags uint, x, y int, wnd HWND) bool {
|
||||
ret, _, _ := procTrackPopupMenu.Call(
|
||||
uintptr(p),
|
||||
uintptr(flags),
|
||||
uintptr(x),
|
||||
uintptr(y),
|
||||
0,
|
||||
uintptr(wnd),
|
||||
0,
|
||||
)
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func (p PopupMenu) Append(flags uintptr, id uintptr, text string) bool {
|
||||
return Menu(p).Append(flags, id, text)
|
||||
}
|
||||
|
||||
func (m Menu) Append(flags uintptr, id uintptr, text string) bool {
|
||||
ret, _, _ := procAppendMenuW.Call(
|
||||
uintptr(m),
|
||||
flags,
|
||||
id,
|
||||
MustStringToUTF16uintptr(text),
|
||||
)
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func (p PopupMenu) Check(id uintptr, checked bool) bool {
|
||||
return Menu(p).Check(id, checked)
|
||||
}
|
||||
|
||||
func (m Menu) Check(id uintptr, check bool) bool {
|
||||
var checkState uint = MF_UNCHECKED
|
||||
if check {
|
||||
checkState = MF_CHECKED
|
||||
}
|
||||
return CheckMenuItem(HMENU(m), id, checkState) != 0
|
||||
}
|
||||
|
||||
func (m Menu) CheckRadio(startID int, endID int, selectedID int) bool {
|
||||
ret, _, _ := procCheckMenuRadioItem.Call(
|
||||
uintptr(m),
|
||||
uintptr(startID),
|
||||
uintptr(endID),
|
||||
uintptr(selectedID),
|
||||
MF_BYCOMMAND)
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func CheckMenuItem(menu HMENU, id uintptr, flags uint) uint {
|
||||
ret, _, _ := procCheckMenuItem.Call(
|
||||
uintptr(menu),
|
||||
id,
|
||||
uintptr(flags),
|
||||
)
|
||||
return uint(ret)
|
||||
}
|
||||
|
||||
func (p PopupMenu) CheckRadio(startID, endID, selectedID int) bool {
|
||||
return Menu(p).CheckRadio(startID, endID, selectedID)
|
||||
}
|
||||
@@ -115,10 +115,6 @@ func (d *AssetServer) processWebViewRequest(r webview.Request) {
|
||||
req.RemoteAddr = "192.0.2.1:1234"
|
||||
}
|
||||
|
||||
if req.RequestURI == "" && req.URL != nil {
|
||||
req.RequestURI = req.URL.String()
|
||||
}
|
||||
|
||||
if req.ContentLength == 0 {
|
||||
req.ContentLength, _ = strconv.ParseInt(req.Header.Get(HeaderContentLength), 10, 64)
|
||||
} else {
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
//go:build linux && purego
|
||||
// +build linux,purego
|
||||
|
||||
package webview
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
// NewRequest creates as new WebViewRequest based on a pointer to an `WebKitURISchemeRequest`
|
||||
//
|
||||
// Please make sure to call Release() when finished using the request.
|
||||
func NewRequest(webKitURISchemeRequest uintptr) Request {
|
||||
webkitReq := webKitURISchemeRequest
|
||||
req := &request{req: webkitReq}
|
||||
req.AddRef()
|
||||
return req
|
||||
}
|
||||
|
||||
var _ Request = &request{}
|
||||
|
||||
type request struct {
|
||||
req uintptr
|
||||
|
||||
header http.Header
|
||||
body io.ReadCloser
|
||||
rw *responseWriter
|
||||
}
|
||||
|
||||
func (r *request) AddRef() error {
|
||||
var objectRef func(uintptr)
|
||||
purego.RegisterLibFunc(&objectRef, gtk, "g_object_ref")
|
||||
objectRef(r.req)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *request) Release() error {
|
||||
var objectUnref func(uintptr)
|
||||
purego.RegisterLibFunc(&objectUnref, gtk, "g_object_unref")
|
||||
objectUnref(r.req)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *request) URL() (string, error) {
|
||||
var getUri func(uintptr) string
|
||||
purego.RegisterLibFunc(&getUri, webkit, "webkit_uri_scheme_request_get_uri")
|
||||
return getUri(r.req), nil
|
||||
}
|
||||
|
||||
func (r *request) Method() (string, error) {
|
||||
return webkit_uri_scheme_request_get_http_method(r.req), nil
|
||||
}
|
||||
|
||||
func (r *request) Header() (http.Header, error) {
|
||||
if r.header != nil {
|
||||
return r.header, nil
|
||||
}
|
||||
|
||||
r.header = webkit_uri_scheme_request_get_http_headers(r.req)
|
||||
return r.header, nil
|
||||
}
|
||||
|
||||
func (r *request) Body() (io.ReadCloser, error) {
|
||||
if r.body != nil {
|
||||
return r.body, nil
|
||||
}
|
||||
|
||||
// WebKit2GTK has currently no support for request bodies.
|
||||
r.body = http.NoBody
|
||||
|
||||
return r.body, nil
|
||||
}
|
||||
|
||||
func (r *request) Response() ResponseWriter {
|
||||
if r.rw != nil {
|
||||
return r.rw
|
||||
}
|
||||
|
||||
r.rw = &responseWriter{req: r.req}
|
||||
return r.rw
|
||||
}
|
||||
|
||||
func (r *request) Close() error {
|
||||
var err error
|
||||
if r.body != nil {
|
||||
err = r.body.Close()
|
||||
}
|
||||
r.Response().Finish()
|
||||
r.Release()
|
||||
return err
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user