Skip to content

Commit b889e98

Browse files
committed
feat: 应用内自定义缩放
1 parent b3be3a7 commit b889e98

18 files changed

Lines changed: 155 additions & 32 deletions

File tree

MaiChartManager/Browser.cs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
using System.Diagnostics;
2+
using System.Text.Json;
23
using Microsoft.Web.WebView2.Core;
34

45
namespace MaiChartManager;
56

67
public sealed partial class Browser : Form
78
{
89
private Uri? loopbackUrl;
10+
private double _currentZoomFactor = 1.0;
911
private static ILogger logger = AppMain.GetLogger<Browser>();
1012

1113
private static bool IsRunningAsUwp()
@@ -28,6 +30,45 @@ public Browser(string? loopbackUrl = null)
2830
StartPosition = FormStartPosition.Manual;
2931
Location = WebViewHelper.CalculatePosition(Width, Height);
3032
}
33+
34+
public static double TargetDpiScale { get; private set; }
35+
36+
/// <summary>
37+
/// 根据配置和屏幕信息计算 WebView2 的 ZoomFactor。
38+
/// UiZoom=0 表示自动模式:等效宽度 < 1440 时,将目标缩放 clamp 到 100%~150%,
39+
/// 然后除以系统缩放得到 ZoomFactor。
40+
/// UiZoom>0 表示用户指定的百分比(相对于物理分辨率的缩放比例),
41+
/// ZoomFactor = UiZoom / 100.0 / dpiScale。
42+
/// </summary>
43+
private double CalculateZoomFactor()
44+
{
45+
var dpiScale = DeviceDpi / 96.0;
46+
var screen = Screen.FromControl(this);
47+
var physicalWidth = screen.Bounds.Width;
48+
var effectiveWidth = physicalWidth / dpiScale;
49+
50+
// 始终计算 auto 模式下的目标缩放,供前端显示
51+
TargetDpiScale = effectiveWidth >= 1440
52+
? dpiScale
53+
: Math.Clamp(physicalWidth / 1440.0, 1.0, 1.5);
54+
55+
var uiZoom = StaticSettings.Config.UiZoom;
56+
if (uiZoom > 0)
57+
{
58+
// 用户指定的百分比是 Windows 缩放意义上的,需要除以当前系统缩放
59+
return uiZoom / 100.0 / dpiScale;
60+
}
61+
62+
// auto 模式
63+
return TargetDpiScale / dpiScale;
64+
}
65+
66+
private void ApplyZoomFactor()
67+
{
68+
_currentZoomFactor = CalculateZoomFactor();
69+
webView21.ZoomFactor = _currentZoomFactor;
70+
}
71+
3172
private void webView21_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
3273
{
3374
if (IsRunningAsUwp())
@@ -42,11 +83,12 @@ private void webView21_CoreWebView2InitializationCompleted(object sender, CoreWe
4283

4384
WebViewHelper.SetupCoreWebView2(webView21.CoreWebView2, loopbackUrl);
4485

45-
// webView21.CoreWebView2.AddWebResourceRequestedFilter("*://mcm.invalid/MaiChartManagerServlet/*", CoreWebView2WebResourceContext.All);
46-
// webView21.CoreWebView2.WebResourceRequested += OnWebResourceRequested;
86+
// 应用缩放
87+
ApplyZoomFactor();
4788

4889
webView21.CoreWebView2.PermissionRequested += WebViewHelper.OnPermissionRequested;
4990
webView21.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
91+
webView21.CoreWebView2.WebMessageReceived += OnWebMessageReceived;
5092
}
5193

5294
private async void CoreWebView2_NewWindowRequested(object? sender, CoreWebView2NewWindowRequestedEventArgs e)
@@ -81,13 +123,35 @@ private async void CoreWebView2_NewWindowRequested(object? sender, CoreWebView2N
81123
e.NewWindow = webView.CoreWebView2;
82124
webView.CoreWebView2.DocumentTitleChanged += (_, _) => form.Text = webView.CoreWebView2.DocumentTitle;
83125
form.FormClosed += (_, _) => webView.Dispose();
126+
webView.ZoomFactor = _currentZoomFactor;
84127
}
85128
finally
86129
{
87130
deferral.Complete();
88131
}
89132
}
90133

134+
private void OnWebMessageReceived(object? sender, CoreWebView2WebMessageReceivedEventArgs e)
135+
{
136+
try
137+
{
138+
var message = e.WebMessageAsJson;
139+
using var doc = JsonDocument.Parse(message);
140+
var root = doc.RootElement;
141+
142+
if (root.GetProperty("type").GetString() != "setZoom") return;
143+
144+
var value = root.GetProperty("value").GetInt32();
145+
StaticSettings.Config.UiZoom = value;
146+
StaticSettings.Config.Save();
147+
ApplyZoomFactor();
148+
}
149+
catch (Exception ex)
150+
{
151+
logger.LogError(ex, "处理 WebMessage 失败");
152+
}
153+
}
154+
91155

92156
private async void OnWebResourceRequested(object? sender, CoreWebView2WebResourceRequestedEventArgs args)
93157
{

MaiChartManager/Config.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class Config
2626
public bool NoScale { get; set; } = false;
2727
public bool IgnoreLevel { get; set; } = false;
2828
public bool DisableBga { get; set; } = false;
29+
public int UiZoom { get; set; } = 0;
2930

3031
public void Save()
3132
{

MaiChartManager/Controllers/App/SettingsController.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ public class SettingsDto
1010
public bool NoScale { get; set; }
1111
public bool IgnoreLevel { get; set; }
1212
public bool DisableBga { get; set; }
13+
public int UiZoom { get; set; }
14+
public double TargetDpiScale { get; set; }
1315
}
1416

1517
[ApiController]
@@ -26,6 +28,8 @@ public SettingsDto GetSettings()
2628
NoScale = StaticSettings.Config.NoScale,
2729
IgnoreLevel = StaticSettings.Config.IgnoreLevel,
2830
DisableBga = StaticSettings.Config.DisableBga,
31+
UiZoom = StaticSettings.Config.UiZoom,
32+
TargetDpiScale = Browser.TargetDpiScale,
2933
};
3034
}
3135

@@ -37,7 +41,6 @@ public void SetSettings([FromBody] SettingsDto dto)
3741
StaticSettings.Config.NoScale = dto.NoScale;
3842
StaticSettings.Config.IgnoreLevel = dto.IgnoreLevel;
3943
StaticSettings.Config.DisableBga = dto.DisableBga;
40-
4144
StaticSettings.Config.Save();
4245
}
4346
}

MaiChartManager/Front/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"@iconify/json": "^2.2.443",
1717
"@microsoft/fetch-event-source": "^2.0.1",
1818
"@modyfi/vite-plugin-yaml": "^1.1.1",
19-
"@munet/ui": "^1.0.9",
19+
"@munet/ui": "^1.0.10",
2020
"@sentry/vite-plugin": "^5.1.0",
2121
"@sentry/vue": "^10.40.0",
2222
"@types/color": "^4.2.0",

MaiChartManager/Front/pnpm-lock.yaml

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

MaiChartManager/Front/src/client/api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ declare global {
66
}
77
// 在 WebView2 环境中,域名是 mcm.invalid,backendUrl 会通过 PostWebMessageAsString 注入
88
// 在远程浏览器(export 模式)中,直接用相对路径(当前 origin)
9-
export const isWebView2 = location.hostname === 'mcm.invalid';
10-
const getBaseUrl = () => (globalThis as any).backendUrl ?? (isWebView2 ? undefined : '');
9+
export const isWebView = location.hostname === 'mcm.invalid';
10+
const getBaseUrl = () => (globalThis as any).backendUrl ?? (isWebView ? undefined : '');
1111

1212
export const apiClient = new Api({
1313
// @ts-ignore

MaiChartManager/Front/src/client/apiGen.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,10 @@ export interface SettingsDto {
364364
noScale?: boolean;
365365
ignoreLevel?: boolean;
366366
disableBga?: boolean;
367+
/** @format int32 */
368+
uiZoom?: number;
369+
/** @format double */
370+
targetDpiScale?: number;
367371
}
368372

369373
export interface UploadAssetDirResult {

MaiChartManager/Front/src/components/Sidebar/RefreshAllButton.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ export default defineComponent({
3535
<span class={['i-ic-baseline-refresh text-6', load.value && 'animate-spin']} />
3636
<span class={[
3737
'absolute px-3 py-1.5 rounded-lg bg-[oklch(0.7_0.13_var(--hue))] text-white text-sm whitespace-nowrap opacity-0 group-hover:opacity-100 pointer-events-none transition-opacity duration-200 z-100',
38+
'max-[439px]:hidden',
3839
'bottom-full mb-2 left-1/2 -translate-x-1/2',
39-
'min-[768px]:bottom-auto min-[768px]:left-full min-[768px]:ml-2 min-[768px]:mb-0 min-[768px]:translate-x-0',
40+
'md:bottom-auto md:left-full md:ml-2 md:mb-0 md:translate-x-0',
4041
]}>
4142
{t('sidebar.refreshData')}
4243
</span>

MaiChartManager/Front/src/components/Sidebar/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default defineComponent({
4949
<span class={[icon, 'text-6']} />
5050
<span class={[
5151
'absolute px-3 py-1.5 rounded-lg bg-[oklch(0.7_0.13_var(--hue))] text-white text-sm whitespace-nowrap opacity-0 group-hover:opacity-100 pointer-events-none transition-opacity duration-200 z-100',
52-
desktop ? 'left-full ml-2' : 'bottom-full mb-2 left-1/2 -translate-x-1/2',
52+
desktop ? 'left-full ml-2' : 'max-[439px]:hidden bottom-full mb-2 left-1/2 -translate-x-1/2',
5353
]}>{t(labelKey)}</span>
5454
</div>
5555
);
@@ -69,7 +69,8 @@ export default defineComponent({
6969
<div class={[
7070
'md:hidden fixed bottom-0 left-0 right-0 z-50',
7171
'flex items-center h-14 gap-1 px-1',
72-
'justify-center',
72+
'max-[439px]:of-x-auto max-[439px]:of-y-hidden max-[439px]:cst',
73+
'min-[440px]:justify-center',
7374
'bg-[oklch(0.98_0.01_var(--hue))] border-t border-t-[oklch(0.9_0.02_var(--hue))] border-t-solid',
7475
]}>
7576
{items.map((item) => renderItem(item.key, item.icon, item.labelKey, false))}

MaiChartManager/Front/src/components/StorePurchaseButton.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { defineComponent } from "vue";
22
import { Button, showTransactionalDialog } from "@munet/ui";
3-
import api from "@/client/api";
3+
import api, { isWebView } from "@/client/api";
44
import { useI18n } from 'vue-i18n';
55

66
export default defineComponent({
77
setup(props) {
8+
const { t } = useI18n();
9+
810
const onClick = async () => {
9-
if (location.hostname !== 'mcm.invalid') {
11+
if (!isWebView) {
1012
const confirmed = await showTransactionalDialog(
1113
t('message.notice'),
1214
t('purchase.needServerSide'),

0 commit comments

Comments
 (0)