diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 27315f8..8253194 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -13,8 +13,8 @@ android { minSdk = 26 targetSdk = 35 // versionCode = major*1_000_000 + minor*10_000 + patch*100 + build - versionCode = 4_026_001 - versionName = "4.2.6+1" + versionCode = 4_027_001 + versionName = "4.2.7+1" vectorDrawables.useSupportLibrary = true ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64") diff --git a/assets/app.manifest b/assets/app.manifest index ce9a4ee..8e9f6b4 100644 --- a/assets/app.manifest +++ b/assets/app.manifest @@ -1,7 +1,7 @@ diff --git a/cmd/vpnapp/main_windows.go b/cmd/vpnapp/main_windows.go index 73f6e48..cb2235a 100644 --- a/cmd/vpnapp/main_windows.go +++ b/cmd/vpnapp/main_windows.go @@ -76,6 +76,10 @@ func main() { } update.CleanupStaleDownloads() + // Before any HWND: declare DPI awareness so CreateWindow/SetSize sizes + // are physical pixels and we can convert DIPs correctly. + enableProcessDPIAware() + log.SetFlags(log.LstdFlags | log.Lshortfile) cfgPath, err := config.LocateConfig() @@ -114,15 +118,17 @@ func main() { // Do NOT auto-download cores on startup — silent network+write looks like malware to AV. - // Sidebar layout (Hiddify-style) needs a wider window than the old column UI. + // Size from monitor work area in DIPs, converted to physical pixels for + // DPI-aware CreateWindow (fixed 920x680 physical collapses CSS <700px on HiDPI). + initW, initH := initialWindowPhysicalSize() w := webview2.NewWithOptions(webview2.WebViewOptions{ Debug: false, AutoFocus: true, DataPath: dataPath, WindowOptions: webview2.WindowOptions{ Title: "EvilFox", - Width: 920, - Height: 680, + Width: uint(initW), + Height: uint(initH), Center: true, IconId: 1, }, @@ -137,7 +143,7 @@ func main() { }() applyWindowIcon(w.Window()) - w.SetSize(920, 680, webview2.HintNone) + applyAdaptiveWindowSize(w) mustBind(w, "getState", a.getState) mustBind(w, "connect", a.connect) diff --git a/cmd/vpnapp/window_size_windows.go b/cmd/vpnapp/window_size_windows.go new file mode 100644 index 0000000..e359bd4 --- /dev/null +++ b/cmd/vpnapp/window_size_windows.go @@ -0,0 +1,215 @@ +//go:build windows + +package main + +import ( + "unsafe" + + "github.com/jchv/go-webview2" + "golang.org/x/sys/windows" +) + +// DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = (DPI_AWARENESS_CONTEXT)-4 +const dpiAwarenessContextPerMonitorAwareV2 = ^uintptr(3) + +const ( + spiGetWorkArea = 0x0030 + monitorDefaultToNearest = 2 +) + +type monitorInfo struct { + CbSize uint32 + RcMonitor windows.Rect + RcWork windows.Rect + DwFlags uint32 +} + +// enableProcessDPIAware opts into per-monitor DPI before any HWND is created. +// The embedded app.manifest already declares PerMonitorV2; this is a belt-and- +// suspenders call for builds that lose the manifest resource. +func enableProcessDPIAware() { + user32 := windows.NewLazySystemDLL("user32.dll") + if p := user32.NewProc("SetProcessDpiAwarenessContext"); p.Find() == nil { + _, _, _ = p.Call(dpiAwarenessContextPerMonitorAwareV2) + return + } + if p := user32.NewProc("SetProcessDPIAware"); p.Find() == nil { + _, _, _ = p.Call() + } +} + +func systemDPI() int { + user32 := windows.NewLazySystemDLL("user32.dll") + if p := user32.NewProc("GetDpiForSystem"); p.Find() == nil { + if r, _, _ := p.Call(); r >= 72 && r <= 480 { + return int(r) + } + } + return 96 +} + +func windowDPI(hwnd uintptr) int { + if hwnd != 0 { + user32 := windows.NewLazySystemDLL("user32.dll") + if p := user32.NewProc("GetDpiForWindow"); p.Find() == nil { + if r, _, _ := p.Call(hwnd); r >= 72 && r <= 480 { + return int(r) + } + } + } + return systemDPI() +} + +func dipsToPhysical(dips, dpi int) int { + if dpi <= 0 { + dpi = 96 + } + return (dips*dpi + 48) / 96 +} + +func physicalToDIPs(px, dpi int) int { + if dpi <= 0 { + dpi = 96 + } + return (px*96 + dpi/2) / dpi +} + +func primaryWorkAreaPhysical() (w, h int, ok bool) { + var r windows.Rect + user32 := windows.NewLazySystemDLL("user32.dll") + p := user32.NewProc("SystemParametersInfoW") + ret, _, _ := p.Call(spiGetWorkArea, 0, uintptr(unsafe.Pointer(&r)), 0) + if ret == 0 { + return 0, 0, false + } + return int(r.Right - r.Left), int(r.Bottom - r.Top), true +} + +func monitorWorkAreaPhysical(hwnd uintptr) (w, h int, ok bool) { + if hwnd == 0 { + return primaryWorkAreaPhysical() + } + user32 := windows.NewLazySystemDLL("user32.dll") + fromWin := user32.NewProc("MonitorFromWindow") + getInfo := user32.NewProc("GetMonitorInfoW") + if fromWin.Find() != nil || getInfo.Find() != nil { + return primaryWorkAreaPhysical() + } + hmon, _, _ := fromWin.Call(hwnd, monitorDefaultToNearest) + if hmon == 0 { + return primaryWorkAreaPhysical() + } + var mi monitorInfo + mi.CbSize = uint32(unsafe.Sizeof(mi)) + ret, _, _ := getInfo.Call(hmon, uintptr(unsafe.Pointer(&mi))) + if ret == 0 { + return primaryWorkAreaPhysical() + } + return int(mi.RcWork.Right - mi.RcWork.Left), int(mi.RcWork.Bottom - mi.RcWork.Top), true +} + +// computeClientSizeDIPs picks a comfortable client size in DIPs from the +// monitor work area (also expressed as physical px + dpi). +// Target: ~min(1100, workW*0.72) x min(780, workH*0.78), floored near +// 960x680 when the screen allows, always capped with margins. +func computeClientSizeDIPs(workWPhys, workHPhys, dpi int) (w, h int) { + if dpi <= 0 { + dpi = 96 + } + workW := physicalToDIPs(workWPhys, dpi) + workH := physicalToDIPs(workHPhys, dpi) + if workW < 320 { + workW = 320 + } + if workH < 240 { + workH = 240 + } + + const marginX, marginY = 64, 64 + maxW := workW - marginX + maxH := workH - marginY + if maxW < 480 { + maxW = workW + } + if maxH < 360 { + maxH = workH + } + if maxW < 480 { + maxW = 480 + } + if maxH < 360 { + maxH = 360 + } + + prefW := int(float64(workW) * 0.72) + if prefW > 1100 { + prefW = 1100 + } + prefH := int(float64(workH) * 0.78) + if prefH > 780 { + prefH = 780 + } + + if prefW < 960 && maxW >= 960 { + prefW = 960 + } + if prefH < 680 && maxH >= 680 { + prefH = 680 + } + + if prefW > maxW { + prefW = maxW + } + if prefH > maxH { + prefH = maxH + } + if prefW < 640 && maxW >= 640 { + prefW = 640 + } + if prefH < 480 && maxH >= 480 { + prefH = 480 + } + return prefW, prefH +} + +// initialWindowPhysicalSize estimates CreateWindow size before an HWND exists +// (primary work area + system DPI). go-webview2 treats Width/Height as physical +// pixels when the process is DPI-aware. +func initialWindowPhysicalSize() (w, h int) { + dpi := systemDPI() + ww, wh, ok := primaryWorkAreaPhysical() + if !ok || ww <= 0 || wh <= 0 { + return dipsToPhysical(960, dpi), dipsToPhysical(680, dpi) + } + dipW, dipH := computeClientSizeDIPs(ww, wh, dpi) + return dipsToPhysical(dipW, dpi), dipsToPhysical(dipH, dpi) +} + +// applyAdaptiveWindowSize sets HintMin (~720x520 DIPs) then the preferred +// client size from the window's monitor work area, both in physical pixels. +func applyAdaptiveWindowSize(w webview2.WebView) { + if w == nil { + return + } + hwnd := uintptr(w.Window()) + dpi := windowDPI(hwnd) + ww, wh, ok := monitorWorkAreaPhysical(hwnd) + if !ok || ww <= 0 || wh <= 0 { + ww, wh, _ = primaryWorkAreaPhysical() + } + dipW, dipH := computeClientSizeDIPs(ww, wh, dpi) + physW := dipsToPhysical(dipW, dpi) + physH := dipsToPhysical(dipH, dpi) + + minW := dipsToPhysical(720, dpi) + minH := dipsToPhysical(520, dpi) + if minW > physW { + minW = physW + } + if minH > physH { + minH = physH + } + + w.SetSize(minW, minH, webview2.HintMin) + w.SetSize(physW, physH, webview2.HintNone) +} \ No newline at end of file diff --git a/dist/navis-release/update.json b/dist/navis-release/update.json index 4512095..3b8d52a 100644 --- a/dist/navis-release/update.json +++ b/dist/navis-release/update.json @@ -1,11 +1,11 @@ { - "version": "4.2.6", - "notes": "4.2.6: fix sidebar RU/EN and theme toggles — applyTheme param shadowed i18n t(), so init threw and click listeners never bound", + "version": "4.2.7", + "notes": "4.2.7: adaptive window size on HiDPI (DIP work-area sizing + min size); responsive CSS breakpoints so sidebar/power button fit without stretch", "platform": "windows-amd64", "os": "windows", "arch": "amd64", "url": "https://git.de4ima.uk/Evilfox/navi/raw/branch/Windows/dist/navis-release/windows/EvilFox.exe", - "sha256": "843fd62f7fe0ae09261322fb90d7f281a48472b78e6a9c543b6a9637fe1cc83e", + "sha256": "dd867e27845fafa9417e1658919fc6613947db3c4677c1f35a270cdc72b3c762", "mandatory": false, "platforms": { "android": { @@ -40,7 +40,7 @@ }, "windows-amd64": { "url": "https://git.de4ima.uk/Evilfox/navi/raw/branch/Windows/dist/navis-release/windows/EvilFox.exe", - "sha256": "843fd62f7fe0ae09261322fb90d7f281a48472b78e6a9c543b6a9637fe1cc83e", + "sha256": "dd867e27845fafa9417e1658919fc6613947db3c4677c1f35a270cdc72b3c762", "os": "windows", "arch": "amd64" } diff --git a/dist/navis-release/windows/EvilFox.exe b/dist/navis-release/windows/EvilFox.exe index 91171a8..14ef957 100644 Binary files a/dist/navis-release/windows/EvilFox.exe and b/dist/navis-release/windows/EvilFox.exe differ diff --git a/dist/navis-release/windows/Navis.exe b/dist/navis-release/windows/Navis.exe index 91171a8..14ef957 100644 Binary files a/dist/navis-release/windows/Navis.exe and b/dist/navis-release/windows/Navis.exe differ diff --git a/dist/navis-release/windows/evilfox-cli.exe b/dist/navis-release/windows/evilfox-cli.exe index 46b15d8..80f2fd4 100644 Binary files a/dist/navis-release/windows/evilfox-cli.exe and b/dist/navis-release/windows/evilfox-cli.exe differ diff --git a/dist/navis-release/windows/vpnclient.exe b/dist/navis-release/windows/vpnclient.exe index 46b15d8..80f2fd4 100644 Binary files a/dist/navis-release/windows/vpnclient.exe and b/dist/navis-release/windows/vpnclient.exe differ diff --git a/dist/update.json b/dist/update.json index 4512095..3b8d52a 100644 --- a/dist/update.json +++ b/dist/update.json @@ -1,11 +1,11 @@ { - "version": "4.2.6", - "notes": "4.2.6: fix sidebar RU/EN and theme toggles — applyTheme param shadowed i18n t(), so init threw and click listeners never bound", + "version": "4.2.7", + "notes": "4.2.7: adaptive window size on HiDPI (DIP work-area sizing + min size); responsive CSS breakpoints so sidebar/power button fit without stretch", "platform": "windows-amd64", "os": "windows", "arch": "amd64", "url": "https://git.de4ima.uk/Evilfox/navi/raw/branch/Windows/dist/navis-release/windows/EvilFox.exe", - "sha256": "843fd62f7fe0ae09261322fb90d7f281a48472b78e6a9c543b6a9637fe1cc83e", + "sha256": "dd867e27845fafa9417e1658919fc6613947db3c4677c1f35a270cdc72b3c762", "mandatory": false, "platforms": { "android": { @@ -40,7 +40,7 @@ }, "windows-amd64": { "url": "https://git.de4ima.uk/Evilfox/navi/raw/branch/Windows/dist/navis-release/windows/EvilFox.exe", - "sha256": "843fd62f7fe0ae09261322fb90d7f281a48472b78e6a9c543b6a9637fe1cc83e", + "sha256": "dd867e27845fafa9417e1658919fc6613947db3c4677c1f35a270cdc72b3c762", "os": "windows", "arch": "amd64" } diff --git a/internal/appui/index.html b/internal/appui/index.html index 1fabf26..c337f1d 100644 --- a/internal/appui/index.html +++ b/internal/appui/index.html @@ -149,7 +149,9 @@ [hidden] { display: none !important; } html, body { margin: 0; + width: 100%; height: 100%; + height: 100dvh; font-family: Manrope, sans-serif; color: var(--ink); background: var(--page-bg); @@ -158,8 +160,12 @@ .app { display: grid; - grid-template-columns: 216px 1fr; + grid-template-columns: 216px minmax(0, 1fr); + width: 100%; + height: 100%; height: 100vh; + height: 100dvh; + min-height: 0; } /* ==== Sidebar ==== */ @@ -172,6 +178,8 @@ backdrop-filter: blur(18px) saturate(1.15); border-right: 1px solid var(--line); min-width: 0; + min-height: 0; + overflow: hidden; } .side .brand-row { display: flex; @@ -329,15 +337,26 @@ display: flex; flex-direction: column; min-width: 0; + min-height: 0; overflow: hidden; + height: 100%; } .pages { - flex: 1; + flex: 1 1 auto; + min-height: 0; + overflow-x: hidden; overflow-y: auto; - padding: 18px 20px 8px; + padding: 18px clamp(12px, 2.2vw, 20px) 8px; + -webkit-overflow-scrolling: touch; } /* Inactive pages must not paint (WebView2 overflow ghosts from hidden siblings). */ - .page { display: none !important; max-width: 640px; margin: 0 auto; } + .page { + display: none !important; + width: 100%; + max-width: min(720px, 100%); + margin: 0 auto; + box-sizing: border-box; + } .page.active { display: block !important; animation: rise .3s var(--ease) both; } @keyframes rise { from { opacity: 0; transform: translateY(10px); } @@ -381,12 +400,13 @@ border-radius: var(--radius); border: 1px solid var(--line); background: var(--hero-bg); - padding: 26px 16px 20px; + padding: clamp(14px, 2.6vw, 26px) clamp(10px, 2vw, 16px) clamp(12px, 2vw, 20px); margin-bottom: 14px; text-align: center; transition: border-color .25s, box-shadow .25s, background .25s; - min-height: 220px; + min-height: clamp(160px, 28vh, 220px); box-sizing: border-box; + width: 100%; } .hero.on { border-color: rgba(13,138,102,.35); @@ -394,10 +414,11 @@ background: var(--hero-bg-on); } .power-btn { - width: 148px; - height: 148px; - min-width: 148px; - min-height: 148px; + --power-size: clamp(104px, 22vw, 148px); + width: var(--power-size); + height: var(--power-size); + min-width: var(--power-size); + min-height: var(--power-size); border-radius: 50%; border: 0; cursor: pointer; @@ -407,7 +428,7 @@ flex-direction: column; align-items: center; justify-content: center; - gap: 7px; + gap: clamp(4px, 1vw, 7px); margin: 4px auto 14px; transition: background .25s, color .25s, transform .12s, box-shadow .25s; box-shadow: 0 14px 34px rgba(8, 145, 178, .3); @@ -417,10 +438,13 @@ .power-btn:hover { transform: translateY(-2px); } .power-btn:active { transform: none; } .power-btn:disabled { opacity: .6; cursor: not-allowed; transform: none; } - .power-btn svg { width: 40px; height: 40px; } + .power-btn svg { + width: clamp(28px, 6vw, 40px); + height: clamp(28px, 6vw, 40px); + } .power-btn .power-label { font-family: Outfit, sans-serif; - font-size: .64rem; + font-size: clamp(.52rem, 1.5vw, .64rem); font-weight: 800; letter-spacing: .09em; line-height: 1; @@ -526,11 +550,12 @@ /* Current server card (home, bottom) */ .cur-server { display: grid; - grid-template-columns: auto 1fr auto; + grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; - gap: 12px; + gap: clamp(8px, 1.5vw, 12px); width: 100%; - padding: 12px 14px; + max-width: 100%; + padding: clamp(10px, 1.8vw, 12px) clamp(10px, 1.8vw, 14px); border-radius: var(--radius); border: 1px solid var(--line); background: var(--surface-2); @@ -540,6 +565,7 @@ text-align: left; margin-bottom: 12px; transition: border-color .15s, background .15s; + box-sizing: border-box; } .cur-server:hover { border-color: rgba(8,145,178,.35); } .cur-server .flag { @@ -1217,10 +1243,13 @@ border: 1px solid var(--line); border-radius: var(--radius); background: var(--row-bg); - padding: 12px 14px; + padding: clamp(10px, 1.8vw, 12px) clamp(10px, 1.8vw, 14px); margin-bottom: 12px; display: grid; gap: 8px; + width: 100%; + max-width: 100%; + box-sizing: border-box; } .traffic-row { display: flex; @@ -1256,7 +1285,10 @@ border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-2); - padding: 14px; + padding: clamp(10px, 1.8vw, 14px); + width: 100%; + max-width: 100%; + box-sizing: border-box; display: flex; flex-direction: column; gap: 8px; @@ -1371,12 +1403,53 @@ .modal h2 { font-family: Outfit, sans-serif; margin: 0 0 12px; font-size: 1.2rem; letter-spacing: -.02em; } .modal .actions { margin-top: 12px; grid-template-columns: 1fr 1fr; } + /* Medium: keep labels, slightly narrower sidebar */ + @media (max-width: 900px) and (min-width: 701px) { + .app { grid-template-columns: 176px minmax(0, 1fr); } + .side { padding: 14px 8px 10px; } + .nav-btn { gap: 10px; padding: 10px 12px; font-size: .84rem; } + .brand { font-size: 1.2rem; } + } + + /* Narrow: icon sidebar — main pane stays usable (fluid power/cards) */ @media (max-width: 700px) { - .app { grid-template-columns: 64px 1fr; } - .side .brand-row { justify-content: center; padding-left: 0; padding-right: 0; } + .app { grid-template-columns: 64px minmax(0, 1fr); } + .side { + padding: 12px 6px 10px; + align-items: stretch; + } + .side .brand-row { justify-content: center; padding-left: 0; padding-right: 0; padding-bottom: 10px; } .side .brand, .side .badge-ver, .nav-btn .nav-label, .side-foot .ver { display: none; } .nav-btn { justify-content: center; padding: 12px 0; } - .side-foot { justify-content: center; } + .side-foot { + flex-direction: column; + justify-content: center; + align-items: center; + gap: 8px; + padding: 8px 0 0; + } + .side-foot-controls { + flex-direction: column; + align-items: center; + gap: 8px; + width: 100%; + } + .lang-seg { + flex-direction: column; + height: auto; + width: 40px; + } + .lang-seg button { + min-width: 0; + width: 100%; + padding: 7px 0; + } + .theme-toggle { width: 40px; height: 40px; } + .pages { padding: 12px 10px 8px; } + .page { max-width: 100%; } + .hero { min-height: 0; } + .power-btn { --power-size: clamp(96px, 28vw, 132px); } + .update-banner { margin-left: 10px; margin-right: 10px; } details.panel .grid2 { grid-template-columns: 1fr; } .tools { grid-template-columns: 1fr; } } @@ -1392,23 +1465,23 @@ - - - - - diff --git a/internal/update/update.go b/internal/update/update.go index a5a4378..fedb813 100644 --- a/internal/update/update.go +++ b/internal/update/update.go @@ -17,8 +17,8 @@ import ( ) // CurrentVersion is the product/semver used for update eligibility (feed "version"). -// Keep major.minor.patch only — no build suffix here. -const CurrentVersion = "4.2.6" +// Keep major.minor.patch only — no build suffix here. +const CurrentVersion = "4.2.7" // BuildNumber is the monotonic build within CurrentVersion (Windows FileVersion 4th part, // macOS CFBundleVersion suffix, Android versionCode low digits). Bump on every release build. @@ -75,7 +75,7 @@ type Status struct { Checking bool `json:"checking,omitempty"` Error string `json:"error,omitempty"` ManifestURL string `json:"manifest_url"` - StoreManaged bool `json:"store_managed,omitempty"` // MSIX / Microsoft Store — no in-app updates + StoreManaged bool `json:"store_managed,omitempty"` // MSIX / Microsoft Store — no in-app updates } // PlatformKey is "GOOS-GOARCH", e.g. windows-amd64, darwin-arm64. @@ -86,7 +86,7 @@ func PlatformKey() string { // AssetFor returns download URL + checksum for the given platform key. // // Rules (critical): -// - Only the asset for this OS/arch is considered — never another OS. +// - Only the asset for this OS/arch is considered — never another OS. // - If the feed has a newer version but no matching platform asset, ok=false // (caller must treat Available as false). // - Darwin may fall back to "darwin-universal" when the exact arch key is absent. @@ -196,7 +196,7 @@ func Check(ctx context.Context, manifestURL string) (Status, error) { if IsStorePackaged() { st.StoreManaged = true st.Available = false - st.Notes = "Обновления через Microsoft Store" + st.Notes = "Обновления через Microsoft Store" return st, nil } @@ -212,7 +212,7 @@ func Check(ctx context.Context, manifestURL string) (Status, error) { url, sha, ok := m.AssetFor(key) if !ok { // Higher feed version for another OS must NOT count as available here. - st.Error = fmt.Sprintf("нет сборки для %s", key) + st.Error = fmt.Sprintf("нет СЃР±РѕСЂРєРё для %s", key) st.Available = false return st, nil } @@ -254,7 +254,7 @@ func productParts(v string) [3]int { func splitVer(v string) []int { v = strings.TrimPrefix(strings.TrimSpace(v), "v") - // Strip build metadata: 2.7.2+1 / 2.7.2-beta → compare product only. + // Strip build metadata: 2.7.2+1 / 2.7.2-beta в†’ compare product only. if i := strings.IndexAny(v, "+-"); i >= 0 { v = v[:i] } @@ -353,10 +353,10 @@ func prepareDownload(ctx context.Context, manifestURL string) (latest, url, sha, if st.Error != "" { return "", "", "", "", "", fmt.Errorf("%s", st.Error) } - return "", "", "", "", "", fmt.Errorf("уже актуальная версия %s (канал %s)", DisplayVersion(), st.Latest) + return "", "", "", "", "", fmt.Errorf("СѓР¶Рµ актуальная версия %s (канал %s)", DisplayVersion(), st.Latest) } if !allowedDownloadURL(st.URL) { - return "", "", "", "", "", fmt.Errorf("URL обновления должен быть на git.de4ima.uk, git.evilfox.cc или files.de4ima.uk") + return "", "", "", "", "", fmt.Errorf("URL обновления должен быть РЅР° git.de4ima.uk, git.evilfox.cc или files.de4ima.uk") } exe, err := os.Executable() if err != nil { diff --git a/packaging/msix/AppxManifest.xml b/packaging/msix/AppxManifest.xml index 2b1832a..9c097d7 100644 --- a/packaging/msix/AppxManifest.xml +++ b/packaging/msix/AppxManifest.xml @@ -33,7 +33,7 @@ diff --git a/server/update.json b/server/update.json index 4512095..3b8d52a 100644 --- a/server/update.json +++ b/server/update.json @@ -1,11 +1,11 @@ { - "version": "4.2.6", - "notes": "4.2.6: fix sidebar RU/EN and theme toggles — applyTheme param shadowed i18n t(), so init threw and click listeners never bound", + "version": "4.2.7", + "notes": "4.2.7: adaptive window size on HiDPI (DIP work-area sizing + min size); responsive CSS breakpoints so sidebar/power button fit without stretch", "platform": "windows-amd64", "os": "windows", "arch": "amd64", "url": "https://git.de4ima.uk/Evilfox/navi/raw/branch/Windows/dist/navis-release/windows/EvilFox.exe", - "sha256": "843fd62f7fe0ae09261322fb90d7f281a48472b78e6a9c543b6a9637fe1cc83e", + "sha256": "dd867e27845fafa9417e1658919fc6613947db3c4677c1f35a270cdc72b3c762", "mandatory": false, "platforms": { "android": { @@ -40,7 +40,7 @@ }, "windows-amd64": { "url": "https://git.de4ima.uk/Evilfox/navi/raw/branch/Windows/dist/navis-release/windows/EvilFox.exe", - "sha256": "843fd62f7fe0ae09261322fb90d7f281a48472b78e6a9c543b6a9637fe1cc83e", + "sha256": "dd867e27845fafa9417e1658919fc6613947db3c4677c1f35a270cdc72b3c762", "os": "windows", "arch": "amd64" } diff --git a/versioninfo.json b/versioninfo.json index bcab3f5..da819bb 100644 --- a/versioninfo.json +++ b/versioninfo.json @@ -1,7 +1,7 @@ { "FixedFileInfo": { - "FileVersion": { "Major": 4, "Minor": 2, "Patch": 6, "Build": 1 }, - "ProductVersion": { "Major": 4, "Minor": 2, "Patch": 6, "Build": 1 }, + "FileVersion": { "Major": 4, "Minor": 2, "Patch": 7, "Build": 1 }, + "ProductVersion": { "Major": 4, "Minor": 2, "Patch": 7, "Build": 1 }, "FileFlagsMask": "3f", "FileFlags": "00", "FileOS": "40004", @@ -11,12 +11,12 @@ "StringFileInfo": { "CompanyName": "EvilFox", "FileDescription": "EvilFox — VPN client (Naive / Hy2 / AWG / VLESS / VMess / Trojan)", - "FileVersion": "4.2.6.1", + "FileVersion": "4.2.7.1", "InternalName": "EvilFox", "LegalCopyright": "Copyright (c) EvilFox", "OriginalFilename": "EvilFox.exe", "ProductName": "EvilFox", - "ProductVersion": "4.2.6.1", + "ProductVersion": "4.2.7.1", "Comments": "Open-source VPN/proxy client. https://evilfox.win/" }, "VarFileInfo": { @@ -27,4 +27,4 @@ }, "IconPath": "assets/navis.ico", "ManifestPath": "assets/app.manifest" -} +} \ No newline at end of file