feat: 多币种支持 + 配置系统优化

## 新增功能 🚀
- 🔗 新增 BNB (币安币) 和 SOL (Solana) 币种支持
- 💰 现在支持 5 种主流虚拟货币: BTC/ETH/BNB/SOL/DOGE
- 🎨 每种币种都有专属的 SF Symbols 图标

## 系统优化 🔧
- 🐛 修复配置初始化逻辑,确保首次运行显示正确的默认值 (BTC + 30秒)
- 📝 改进调试日志输出,移除冗余的 UserDefaults 域信息
- 🏗️ 优化配置加载逻辑,使用更严格的键存在性检查

## 文档更新 📚
- 📖 更新 README.md,添加多币种功能说明
- 📝 完善使用指南,包含币种切换操作
- 🔗 更新 API 文档,列出所有支持的交易对
- 🎯 新增配置文件位置说明

## 技术改进 
- 🔧 AppSettings 配置管理逻辑重构
- 🎯 增强配置初始化的错误处理
- 📱 更新界面预览截图
- 🏷️ 优化代码注释和架构文档

默认配置: BTC/USDT | 30秒刷新间隔 | 支持用户自定义
This commit is contained in:
ZhangLei
2025-10-29 21:17:54 +08:00
parent 370f103507
commit 7e27cfa355
5 changed files with 88 additions and 52 deletions

View File

@@ -7,7 +7,7 @@
![macOS](https://img.shields.io/badge/macOS-12.4+-blue?style=for-the-badge&logo=apple)
![License](https://img.shields.io/badge/License-GPL%20v3-green?style=for-the-badge)
一款 macOS 原生菜单栏应用,用于实时监控 `BTC` 价格之前使用Python写过虽然也蛮好用但最终还是决定用macOS原生语言开发已经编译了`Intel``Apple Silicon`的通用应用,请至`releases`下载。
一款 macOS 原生菜单栏应用,用于实时监控主流虚拟货币价格,支持 BTC/ETH/BNB/SOL/DOGE 多种币种之前使用Python写过虽然也蛮好用但最终还是决定用macOS原生语言开发已经编译了`Intel``Apple Silicon`的通用应用,请至`releases`下载。
</div>
@@ -16,12 +16,13 @@
## 📷︎ 界面预览
![](./assets/iShot_2025-10-29_14.33.17.png)
![](./assets/pingtu-1761743534819@700×299.jpg)
## ✨ 功能特性
### 🚀 核心功能
- **实时价格显示**: 在菜单栏实时显示 BTC/USDT 价格
- **多币种支持**: 支持 BTC/ETH/BNB/SOL/DOGE 主流虚拟货币价格监控
- **实时价格显示**: 在菜单栏实时显示选中币种的 USDT 价格
- **多种刷新机制**: 可选 5、10、30、60 秒自动获取最新价格数据
- **智能错误重试**: 网络异常时自动重试,最多 3 次
- **手动刷新**: 支持快捷键 `Cmd+R` 手动刷新价格
@@ -79,14 +80,18 @@
### 基本操作
1. **启动应用**
- 应用启动后自动在菜单栏显示 BTC 图标
- 应用启动后自动在菜单栏显示默认币种 (BTC) 图标
- 首次启动会显示 "加载中...." 状态
2. **查看价格**
- 菜单栏实时显示当前 BTC 价格
- 菜单栏实时显示当前选中币种的 USDT 价格
- 格式:`$价格` (例如: `$43,250.50`)
3. **交互菜单**
3. **切换币种**
- 点击菜单栏图标 → 币种选择 → 选择想要的币种
- 支持 BTC/ETH/BNB/SOL/DOGE 五种主流币种
4. **交互菜单**
- 点击菜单栏图标显示详细菜单
- 查看更多信息并执行操作
@@ -94,7 +99,8 @@
| 功能 | 描述 | 快捷键 |
|------|------|--------|
| 价格信息 | 显示当前 BTC 价格和状态 | - |
| 价格信息 | 显示当前选中币种的价格和状态 | - |
| 币种选择 | 切换监控的币种 (BTC/ETH/BNB/SOL/DOGE) | - |
| 错误信息 | 显示网络错误详情 (如有) | - |
| 更新时间 | 显示上次成功更新时间 | - |
| 刷新价格 | 手动获取最新价格 | `Cmd+R` |
@@ -131,46 +137,6 @@ BTC价格监控器架构
└── BTCPriceResponse.swift (数据模型)
```
### 核心组件
#### **test1App.swift**
- **职责**: 应用程序入口点
- **功能**:
- 配置应用为后台模式
- 创建和初始化菜单栏应用
- 管理应用生命周期
#### **BTCMenuBarApp.swift**
- **职责**: 菜单栏界面控制器
- **功能**:
- 管理状态栏图标和文本
- 处理用户交互事件
- 显示上下文菜单
- 更新 UI 状态
#### **PriceManager.swift**
- **职责**: 价格数据管理器 (@MainActor)
- **功能**:
- 定时刷新机制 (30秒间隔)
- 智能重试策略 (最多3次)
- Combine 发布者模式
- 状态管理和错误处理
#### **PriceService.swift**
- **职责**: 网络请求服务层
- **功能**:
- 币安 API 集成
- HTTP 网络请求处理
- JSON 数据解析
- 网络错误处理
#### **BTCPriceResponse.swift**
- **职责**: API 响应数据模型
- **功能**:
- Codable 协议支持
- 数据验证和转换
- 类型安全的属性访问
### 设计模式
- **MVVM 架构**: SwiftUI + ObservableObject 模式
@@ -201,15 +167,27 @@ priceManager.$currentPrice
### 币安 API 端点
应用支持多种币种的价格查询:
```http
GET https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT
GET https://api.binance.com/api/v3/ticker/price?symbol={SYMBOL}
```
### 支持的交易对
| 币种 | 交易对符号 | 显示名称 |
|------|------------|----------|
| Bitcoin | BTCUSDT | BTC/USDT |
| Ethereum | ETHUSDT | ETH/USDT |
| BNB | BNBUSDT | BNB/USDT |
| Solana | SOLUSDT | SOL/USDT |
| Dogecoin | DOGEUSDT | DOGE/USDT |
### 请求参数
| 参数 | 类型 | 必需 | 描述 |
|------|------|------|------|
| symbol | String | 是 | 交易对符号 (BTCUSDT) |
| symbol | String | 是 | 交易对符号 (如: BTCUSDT, ETHUSDT, BNBUSDT, SOLUSDT, DOGEUSDT) |
### 响应格式
@@ -269,7 +247,12 @@ ping api.binance.com
2. 验证 API 可用性
```bash
# 测试不同币种的 API 可用性
curl "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT"
curl "https://api.binance.com/api/v3/ticker/price?symbol=ETHUSDT"
curl "https://api.binance.com/api/v3/ticker/price?symbol=BNBUSDT"
curl "https://api.binance.com/api/v3/ticker/price?symbol=SOLUSDT"
curl "https://api.binance.com/api/v3/ticker/price?symbol=DOGEUSDT"
```
3. 检查防火墙设置

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -37,21 +37,61 @@ class AppSettings: ObservableObject {
/// UserDefaults
/// 使30
func loadSettings() {
#if DEBUG
print("🔧 [AppSettings] 开始加载配置...")
#endif
let hasRefreshIntervalKey = defaults.object(forKey: refreshIntervalKey) != nil
let savedIntervalValue = defaults.double(forKey: refreshIntervalKey)
if let savedInterval = RefreshInterval.allCases.first(where: { $0.rawValue == savedIntervalValue }) {
#if DEBUG
print("🔧 [AppSettings] 刷新间隔键是否存在: \(hasRefreshIntervalKey)")
print("🔧 [AppSettings] 从 UserDefaults 读取刷新间隔: \(savedIntervalValue)")
#endif
if hasRefreshIntervalKey,
let savedInterval = RefreshInterval.allCases.first(where: { $0.rawValue == savedIntervalValue }) {
refreshInterval = savedInterval
#if DEBUG
print("🔧 [AppSettings] ✅ 使用保存的刷新间隔: \(savedInterval.displayText)")
#endif
} else {
refreshInterval = .thirtySeconds
#if DEBUG
print("🔧 [AppSettings] ❌ 未找到有效刷新间隔,使用默认值: \(refreshInterval.displayText)")
#endif
saveRefreshInterval(.thirtySeconds)
}
if let savedSymbolRaw = defaults.string(forKey: selectedSymbolKey),
let hasSymbolKey = defaults.object(forKey: selectedSymbolKey) != nil
let savedSymbolRaw = defaults.string(forKey: selectedSymbolKey)
#if DEBUG
print("🔧 [AppSettings] 币种键是否存在: \(hasSymbolKey)")
if let symbol = savedSymbolRaw {
print("🔧 [AppSettings] 从 UserDefaults 读取币种: \(symbol)")
} else {
print("🔧 [AppSettings] 从 UserDefaults 读取币种: nil")
}
#endif
if hasSymbolKey,
let savedSymbolRaw = savedSymbolRaw,
let savedSymbol = CryptoSymbol(rawValue: savedSymbolRaw) {
selectedSymbol = savedSymbol
#if DEBUG
print("🔧 [AppSettings] ✅ 使用保存的币种: \(savedSymbol.displayName)")
#endif
} else {
selectedSymbol = .btc
#if DEBUG
print("🔧 [AppSettings] ❌ 未找到有效币种配置,使用默认值: \(selectedSymbol.displayName)")
#endif
saveSelectedSymbol(.btc)
}
#if DEBUG
print("🔧 [AppSettings] 配置加载完成 - 刷新间隔: \(refreshInterval.displayText), 币种: \(selectedSymbol.displayName)")
#endif
}
///
@@ -65,6 +105,9 @@ class AppSettings: ObservableObject {
/// - Parameter symbol:
func saveSelectedSymbol(_ symbol: CryptoSymbol) {
selectedSymbol = symbol
#if DEBUG
print("🔧 [AppSettings] 保存币种配置: \(symbol.displayName) (\(symbol.rawValue))")
#endif
defaults.set(symbol.rawValue, forKey: selectedSymbolKey)
}
}

View File

@@ -2,7 +2,7 @@
// CryptoSymbol.swift
// Bitcoin Monitoring
//
// Created by GitHub Copilot on 2025/10/29.
// Created by Mark on 2025/10/29.
//
import Foundation
@@ -12,6 +12,8 @@ import Foundation
enum CryptoSymbol: String, CaseIterable, Codable {
case btc = "BTCUSDT"
case eth = "ETHUSDT"
case bnb = "BNBUSDT"
case sol = "SOLUSDT"
case doge = "DOGEUSDT"
///
@@ -21,6 +23,10 @@ enum CryptoSymbol: String, CaseIterable, Codable {
return "BTC"
case .eth:
return "ETH"
case .bnb:
return "BNB"
case .sol:
return "SOL"
case .doge:
return "DOGE"
}
@@ -43,6 +49,10 @@ enum CryptoSymbol: String, CaseIterable, Codable {
return "bitcoinsign.circle.fill"
case .eth:
return "hexagon.fill"
case .bnb:
return "diamond.fill"
case .sol:
return "circle.hexagongrid.fill"
case .doge:
return "pawprint.circle.fill"
}