Files
arcrun-collector/cmd/arcrun-app/update_api.go
T
Leo 3d13e5a54e t193 二修:側邊欄版面+共用 CSS+App 內更新+兩支視覺機械閘
leo 08-04 看過 v0.17.0 後的四點,逐條回應:

## ① 「不會這裡又寫了一個新的 CSS?」——是,我又寫了一份
真兇:portal 的樣式內嵌在 HTML 裡,沒有獨立檔 ⇒ 四個站各抄一份、本來就在漂移。
解:抽出 InkStoneCo/arcrun-cis/css/arcrun-cis.css 當唯一真相源。
    daemon 的 style.css 現在**一個 hex 都沒有**,顏色全走 var(--...)。

## ② 「完全模仿 gdrive,左方側邊欄,在右方替換頁面」
底部 nav bar 拿掉(leo:「幾乎沒看過這種 nav bar 在下方的」)。
改成左側邊欄四頁:首頁/同步資料夾/AI 設定/版本與更新,右側換頁。
設定不再開 popup;只有「確認移除資料夾」才用覆蓋層。

## ③ 「既然是 Web,你做的時候無法檢視?」——可以,我之前沒做
新增 check-render.sh:headless Chrome 真的渲染一次並**量像素**。
它抓到一個肉眼容易誤判的真 bug:
  arcrun-lockup-h-paper-on-ink.png **自帶不透明 Ink 底板**(實測左上像素 RGBA=23,24,26,255),
  設計前提是貼在純 Ink 表面;我們背景有紙張紋理 ⇒ 出現突兀方塊。
  修:深色模式把品牌區做成純 Ink。實測落差 4(原本會是一個明顯方塊)。
過程中也發現自己對著**舊的 dist**除錯,浪費一輪——這支閘同時防這個。

## ④ 「檢查更新連到 docs,不正確,是直接在這裡進行」
新增「版本與更新」頁:顯示**現在版本 vs 最新版本**,
三段式全在 App 內完成——檢查/下載並安裝/重新啟動套用。
selfupdate 邏輯逐字沿用 arcrun-tray(含 t186 走 raw、t184 蓋正在跑的 .app),不重寫。

## 交貨閘(leo:「你做為檢查有嗎?沒有怎麼交貨?」)
check-cis.sh 擴充:版面檔不准出現任何 hex + 共用底層色票逐項比對。
兩支閘實跑全過。
2026-08-04 23:09:54 +08:00

75 lines
2.3 KiB
Go

package main
// update_api.go — 「版本與更新」頁的後端(t193)
//
// 🔴 leo 2026-08-04:「檢查更新連到 docs 的檢查更新,**不正確**,
// 是**直接在這裡進行檢查更新**,應該是跳到一個頁面顯示**現在版本與最新版本**,
// 然後**下載可以進行安裝**」
//
// ⇒ 三段式,全部在 App 內完成,不把人丟去網頁:
// ① CheckUpdate 查最新版 → 前端顯示「現在版本 vs 最新版本」
// ② DownloadUpdate 下載+sha256 校驗 → 備妥
// ③ ApplyUpdate 覆蓋正在跑的 .app 並重啟
import (
"runtime"
"strings"
)
// UpdateInfo 是「版本與更新」頁要顯示的一切。
type UpdateInfo struct {
Current string `json:"current"`
Latest string `json:"latest"`
Available bool `json:"available"`
Notes string `json:"notes,omitempty"`
Staged bool `json:"staged"` // 已下載備妥、等重啟套用
Err string `json:"err,omitempty"` // 誠實回報,不假裝成功
}
func (a *App) CheckUpdate() UpdateInfo {
info := UpdateInfo{Current: version}
rel, err := fetchLatestRelease()
if err != nil {
info.Err = "暫時連不上更新伺服器:" + err.Error()
return info
}
info.Latest = rel.Version
info.Notes = rel.Notes
info.Available = newerThanCurrent(rel.Version)
if s := loadStaged(); s.Ready && s.Version == rel.Version {
info.Staged = true
}
return info
}
func (a *App) DownloadUpdate() UpdateInfo {
info := UpdateInfo{Current: version}
rel, err := fetchLatestRelease()
if err != nil {
info.Err = "暫時連不上更新伺服器:" + err.Error()
return info
}
info.Latest, info.Notes = rel.Version, rel.Notes
info.Available = newerThanCurrent(rel.Version)
zip, err := downloadUpdate(rel)
if err != nil {
// 誠實:下載/校驗失敗就說失敗,不留下半個檔假裝好了
info.Err = "下載失敗:" + err.Error()
return info
}
currentStaged = stagedUpdate{Version: rel.Version, ZipPath: zip, Ready: true}
saveStaged(currentStaged)
info.Staged = true
return info
}
func (a *App) ApplyUpdate() error {
if err := applyStagedAndRestart(); err != nil {
return err
}
return nil
}
// isWindows 供 selfupdate.go 使用(原本在 arcrun-tray 的 main.go)。
func isWindows() bool { return strings.EqualFold(runtime.GOOS, "windows") }