Compare commits

...

3 Commits

Author SHA1 Message Date
ezequielnick
a8f8cd0fd3 workflow: delete all old assets 2025-08-10 09:33:27 +08:00
ezequielnick
defcbbca5c chore: update version 2025-08-10 09:07:01 +08:00
ezequielnick
dbfd25f481 feat: add floating window Compatibility Mode 2025-08-10 09:04:29 +08:00
9 changed files with 124 additions and 52 deletions

View File

@ -19,13 +19,28 @@ jobs:
- name: Delete Dev Release Assets
continue-on-error: true
run: |
# Delete the entire dev release to clean up old assets
curl -X DELETE -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/releases/tags/dev" || true
# Get release ID for dev tag
RELEASE_ID=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/releases/tags/dev" | \
jq -r '.id // empty')
# Delete the dev tag
curl -X DELETE -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/git/refs/tags/dev" || true
if [ ! -z "$RELEASE_ID" ]; then
echo "Found dev release with ID: $RELEASE_ID"
# Get all assets and delete them
curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/releases/$RELEASE_ID/assets" | \
jq -r '.[].id' | \
while read asset_id; do
echo "Deleting asset: $asset_id"
curl -X DELETE -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/releases/assets/$asset_id"
done
echo "All dev release assets deleted"
else
echo "No existing dev release found"
fi
windows:
needs: [cleanup-dev-release]
if: always() && (startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch')
@ -94,6 +109,7 @@ jobs:
dist/*portable.7z
body: "Development build from ${{ github.sha }}"
prerelease: true
draft: false
token: ${{ secrets.GITHUB_TOKEN }}
windows7:
@ -165,6 +181,7 @@ jobs:
dist/*portable.7z
body: "Development build from ${{ github.sha }}"
prerelease: true
draft: false
token: ${{ secrets.GITHUB_TOKEN }}
linux:
@ -229,6 +246,7 @@ jobs:
dist/*.rpm
body: "Development build from ${{ github.sha }}"
prerelease: true
draft: false
token: ${{ secrets.GITHUB_TOKEN }}
macos:
@ -315,6 +333,7 @@ jobs:
dist/*.pkg
body: "Development build from ${{ github.sha }}"
prerelease: true
draft: false
token: ${{ secrets.GITHUB_TOKEN }}
macos10:
@ -403,6 +422,7 @@ jobs:
dist/*.pkg
body: "Development build from ${{ github.sha }}"
prerelease: true
draft: false
token: ${{ secrets.GITHUB_TOKEN }}
updater:
@ -438,6 +458,7 @@ jobs:
files: latest.yml
body: "Development build updater from ${{ github.sha }}"
prerelease: true
draft: false
token: ${{ secrets.GITHUB_TOKEN }}
aur-release-updater:

View File

@ -1,3 +1,12 @@
## 1.8.4
### 新功能 (Feat)
- 如果当前没有以管理员模式运行TUN 开关保持关闭
### 修复 (Fix)
- 修复某些系统下的悬浮窗开启崩溃的问题
-
## 1.8.3
**本次更新移除了 Windows 下启动必须管理员模式的机制,改为只在启用虚拟网卡模式的时候,申请 UAC 权限重启软件,安全性更好,更灵活,给无法使用管理员模式运行软件的企业用户提供了更大的便利**
@ -18,35 +27,4 @@
### 新功能 (Feat)
- 重构 域名嗅探 卡片模块,改为“覆写”逻辑,当开关打开后,使用 嗅探覆写 设置中的配置覆盖订阅原始配置,关闭开关恢复订阅原始配置
- 订阅/覆写卡片可右键呼出菜单
- MacOS 下“轻触(tap)”触控板可进行开关操作(之前必须“按下(click)”)
### 修复 (Fix)
- **因多国语言带来的在 Windows 下首次安装无法启动的问题**
- 1.8.1升级依赖导致的节点圆角显示失效
- DNS 覆写模块的逻辑冲突
- 点击订阅卡片功能区导致的选中订阅问题
- 覆写卡片可以双击编辑
- 因代码不规范导致的控制台警告
- Linux 下没有设置 Smart 内核权限导致的“外部控制监听错误”
## 1.8.1
### 新功能 (Feat)
- 重构 DNS 卡片模块改为“覆写”逻辑当开关打开后使用DNS 设置中的配置覆盖订阅原始配置,关闭开关恢复订阅原始配置
### 性能提升(Perf)
- 更新依赖,提升页面响应性
- 优化订阅切换逻辑,大幅提升切换速度和稳定性
### 修复 (Fix)
- “使用自动 Smart 规则覆写”没有覆盖兜底的 MATCH 规则
- 移除默认的 Smart "policy-priority" 规则
-
## 1.8.0
### 新功能 (Feat)
**重大更新:本次更新增加了 Smart Core可以根据用户使用习惯和节点质量自动选择符合您的最优节点。并内置了“一键开启”适合不想折腾自定义规则的用户
“一键开启”内置 Smart规则的功能在“内核设置”下的“使用自动 Smart 规则覆写”,原理:当开关开启后,自动载入覆写脚本,新增 Smart Group并替换当前配置文件下的默认出站规则为"Smart Group",您的所有代理流量都将从此分组下的节点流出。如果使用“全局模式”请选择名称为"Smart Group"的节点,以使用该功能。**
注意:本功能还在测试中,如遇到问题请发 issue 反馈
- MacOS 下“轻触(tap)”触控板可进行开关操作(之前必须“按下(click)”)

View File

@ -1,6 +1,6 @@
{
"name": "mihomo-party",
"version": "1.8.3",
"version": "1.8.4-dev",
"description": "Mihomo Party",
"main": "./out/main/index.js",
"author": "mihomo-party-org",

View File

@ -41,11 +41,18 @@ async function createFloatingWindow(): Promise<void> {
file: 'floating-window-state.json'
})
await logFloatingWindow('Window state keeper initialized')
const { customTheme = 'default.css' } = await getAppConfig()
await logFloatingWindow(`App config loaded, theme: ${customTheme}`)
const { customTheme = 'default.css', floatingWindowCompatMode = true } = await getAppConfig()
await logFloatingWindow(`App config loaded, theme: ${customTheme}, compatMode: ${floatingWindowCompatMode}`)
const safeMode = process.env.FLOATING_SAFE_MODE === 'true'
const forceWin10Mode = process.env.FLOATING_WIN10_MODE === 'true'
const useCompatMode = floatingWindowCompatMode || forceWin10Mode || safeMode
await logFloatingWindow(`Safe mode: ${safeMode}`)
await logFloatingWindow(`Force Win10 mode: ${forceWin10Mode}`)
await logFloatingWindow(`Compat mode from config: ${floatingWindowCompatMode}`)
await logFloatingWindow(`Platform: ${process.platform}, System version: ${process.getSystemVersion()}`)
await logFloatingWindow(`Using compatibility mode: ${useCompatMode}`)
const windowOptions: Electron.BrowserWindowConstructorOptions = {
width: 120,
@ -56,13 +63,13 @@ async function createFloatingWindow(): Promise<void> {
frame: safeMode ? true : false,
alwaysOnTop: !safeMode,
resizable: safeMode,
transparent: !safeMode,
transparent: !safeMode && !useCompatMode, // 兼容模式下禁用透明
skipTaskbar: !safeMode,
minimizable: safeMode,
maximizable: safeMode,
fullscreenable: false,
closable: safeMode,
backgroundColor: safeMode ? '#ffffff' : '#00000000',
backgroundColor: safeMode ? '#ffffff' : (useCompatMode ? '#f0f0f0' : '#00000000'), // 兼容模式使用浅灰色
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
spellcheck: false,
@ -79,16 +86,39 @@ async function createFloatingWindow(): Promise<void> {
}
await logFloatingWindow(`Creating BrowserWindow with options: ${JSON.stringify(windowOptions, null, 2)}`)
floatingWindow = new BrowserWindow(windowOptions)
await logFloatingWindow('BrowserWindow created successfully')
floatingWindowState.manage(floatingWindow)
await logFloatingWindow('Window state management attached')
floatingWindow.webContents.on('render-process-gone', async (_, details) => {
await logFloatingWindow('Render process gone', details.reason)
floatingWindow = null
})
try {
floatingWindow = new BrowserWindow(windowOptions)
await logFloatingWindow('BrowserWindow created successfully')
} catch (error) {
await logFloatingWindow('Failed to create BrowserWindow', error)
throw error
}
try {
await logFloatingWindow('Attaching window state management...')
floatingWindowState.manage(floatingWindow)
await logFloatingWindow('Window state management attached')
} catch (error) {
await logFloatingWindow('Failed to attach window state management', error)
throw error
}
await logFloatingWindow('Setting up event listeners...')
try {
await logFloatingWindow('Adding render-process-gone listener...')
floatingWindow.webContents.on('render-process-gone', async (_, details) => {
await logFloatingWindow('Render process gone', details.reason)
floatingWindow = null
})
await logFloatingWindow('Render-process-gone listener added')
} catch (error) {
await logFloatingWindow('Failed to add render-process-gone listener', error)
throw error
}
await logFloatingWindow('Adding ready-to-show listener...')
floatingWindow.on('ready-to-show', async () => {
try {
await logFloatingWindow('Window ready to show, applying theme...')
@ -102,16 +132,21 @@ async function createFloatingWindow(): Promise<void> {
await logFloatingWindow('Error in ready-to-show', error)
}
})
await logFloatingWindow('Ready-to-show listener added')
await logFloatingWindow('Adding moved listener...')
floatingWindow.on('moved', () => {
if (floatingWindow) floatingWindowState.saveState(floatingWindow)
})
await logFloatingWindow('Moved listener added')
await logFloatingWindow('Adding IPC listener...')
ipcMain.on('updateFloatingWindow', () => {
if (floatingWindow) {
floatingWindow?.webContents.send('controledMihomoConfigUpdated')
floatingWindow?.webContents.send('appConfigUpdated')
}
})
await logFloatingWindow('IPC listener added')
await logFloatingWindow('Loading page...')
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
@ -145,7 +180,17 @@ export async function showFloatingWindow(): Promise<void> {
}
} catch (error) {
await logFloatingWindow('Failed to show floating window', error)
await patchAppConfig({ showFloatingWindow: false })
// 如果已经是兼容模式还是崩溃,说明问题很严重,自动禁用悬浮窗
const { floatingWindowCompatMode = true } = await getAppConfig()
if (floatingWindowCompatMode) {
await logFloatingWindow('Compatibility mode was already enabled, disabling floating window completely')
await patchAppConfig({ showFloatingWindow: false })
} else {
await logFloatingWindow('Enabling compatibility mode and retrying')
await patchAppConfig({ floatingWindowCompatMode: true })
}
await logFloatingWindow('Disabled floating window in config due to error')
throw error
}

View File

@ -21,6 +21,7 @@ export const defaultConfig: IAppConfig = {
useNameserverPolicy: false,
controlDns: true,
controlSniff: true,
floatingWindowCompatMode: true,
nameserverPolicy: {},
siderOrder: [
'sysproxy',

View File

@ -48,6 +48,7 @@ const GeneralConfig: React.FC = () => {
disableTray = false,
showFloatingWindow: showFloating = false,
spinFloatingIcon = true,
floatingWindowCompatMode = true,
useWindowFrame = false,
autoQuitWithoutCore = false,
autoQuitWithoutCoreDelay = 60,
@ -236,6 +237,27 @@ const GeneralConfig: React.FC = () => {
}}
/>
</SettingItem>
<SettingItem
title={t('settings.floatingWindowCompatMode')}
divider
>
<div className="flex items-center gap-2">
<Switch
size="sm"
isSelected={floatingWindowCompatMode}
onValueChange={async (v) => {
await patchAppConfig({ floatingWindowCompatMode: v })
closeFloatingWindow()
setTimeout(() => {
showFloatingWindow()
}, 100)
}}
/>
<Tooltip content={t('settings.floatingWindowCompatModeTooltip')}>
<IoIosHelpCircle className="text-default-500 cursor-help" />
</Tooltip>
</div>
</SettingItem>
<SettingItem title={t('settings.disableTray')} divider>
<Switch
size="sm"

View File

@ -54,6 +54,8 @@
"settings.envType": "Environment Variable Type",
"settings.showFloatingWindow": "Show Floating Window",
"settings.spinFloatingIcon": "Spin Floating Icon Based on Network Speed",
"settings.floatingWindowCompatMode": "Floating Window Compatibility Mode (Recommended)",
"settings.floatingWindowCompatModeTooltip": "Disables transparency effects to prevent crashes on some Windows systems. Recommended to keep enabled for stability",
"settings.disableTray": "Disable Tray Icon",
"settings.proxyInTray": "Show Proxy Info in Tray Menu",
"settings.showTraffic_windows": "Show Network Speed in Taskbar",

View File

@ -54,6 +54,8 @@
"settings.envType": "环境变量类型",
"settings.showFloatingWindow": "显示悬浮窗",
"settings.spinFloatingIcon": "根据网速旋转悬浮窗图标",
"settings.floatingWindowCompatMode": "悬浮窗兼容模式(推荐开启)",
"settings.floatingWindowCompatModeTooltip": "禁用透明效果以避免在某些 Windows 系统上崩溃,建议保持开启以确保稳定性",
"settings.disableTray": "禁用托盘图标",
"settings.proxyInTray": "在托盘菜单显示代理信息",
"settings.showTraffic_windows": "在任务栏显示网速",

View File

@ -236,6 +236,7 @@ interface IAppConfig {
spinFloatingIcon?: boolean
disableTray?: boolean
showFloatingWindow?: boolean
floatingWindowCompatMode?: boolean
connectionCardStatus?: CardStatus
dnsCardStatus?: CardStatus
logCardStatus?: CardStatus