fix: SystemType(#184) & opt.: ios home widget

This commit is contained in:
lollipopkit
2023-10-14 13:26:15 +08:00
parent 930697d033
commit 9a4a7cef4c
8 changed files with 150 additions and 68 deletions

View File

@@ -47,26 +47,26 @@ If ServerBox app has any bug, please open an [issue](https://github.com/lollipop
<table> <table>
<tr> <tr>
<td> <td>
<img width="200px" src="imgs/server.png"> <img width="277px" src="imgs/server.png">
</td> </td>
<td> <td>
<img width="200px" src="imgs/detail.png"> <img width="277px" src="imgs/detail.png">
</td> </td>
<td> <td>
<img width="200px" src="imgs/sftp.png"> <img width="277px" src="imgs/sftp.png">
</td> </td>
</tr> </tr>
</table> </table>
<table> <table>
<tr> <tr>
<td> <td>
<img width="200px" src="imgs/editor.png"> <img width="277px" src="imgs/editor.png">
</td> </td>
<td> <td>
<img width="200px" src="imgs/ssh.png"> <img width="277px" src="imgs/ssh.png">
</td> </td>
<td> <td>
<img width="200px" src="imgs/docker.png"> <img width="277px" src="imgs/docker.png">
</td> </td>
</tr> </tr>
</table> </table>

View File

@@ -47,26 +47,26 @@
<table> <table>
<tr> <tr>
<td> <td>
<img width="200px" src="imgs/server.png"> <img width="277px" src="imgs/server.png">
</td> </td>
<td> <td>
<img width="200px" src="imgs/detail.png"> <img width="277px" src="imgs/detail.png">
</td> </td>
<td> <td>
<img width="200px" src="imgs/sftp.png"> <img width="277px" src="imgs/sftp.png">
</td> </td>
</tr> </tr>
</table> </table>
<table> <table>
<tr> <tr>
<td> <td>
<img width="200px" src="imgs/editor.png"> <img width="277px" src="imgs/editor.png">
</td> </td>
<td> <td>
<img width="200px" src="imgs/ssh.png"> <img width="277px" src="imgs/ssh.png">
</td> </td>
<td> <td>
<img width="200px" src="imgs/docker.png"> <img width="277px" src="imgs/docker.png">
</td> </td>
</tr> </tr>
</table> </table>

View File

@@ -586,7 +586,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 588; CURRENT_PROJECT_VERSION = 589;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -596,7 +596,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.588; MARKETING_VERSION = 1.0.589;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -720,7 +720,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 588; CURRENT_PROJECT_VERSION = 589;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -730,7 +730,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.588; MARKETING_VERSION = 1.0.589;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -748,7 +748,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 588; CURRENT_PROJECT_VERSION = 589;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -758,7 +758,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.588; MARKETING_VERSION = 1.0.589;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -779,7 +779,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 588; CURRENT_PROJECT_VERSION = 589;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -792,7 +792,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.0.588; MARKETING_VERSION = 1.0.589;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
@@ -818,7 +818,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 588; CURRENT_PROJECT_VERSION = 589;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -831,7 +831,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.0.588; MARKETING_VERSION = 1.0.589;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -854,7 +854,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 588; CURRENT_PROJECT_VERSION = 589;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -867,7 +867,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.0.588; MARKETING_VERSION = 1.0.589;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -890,7 +890,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 588; CURRENT_PROJECT_VERSION = 589;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
@@ -902,7 +902,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.588; MARKETING_VERSION = 1.0.589;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
@@ -931,7 +931,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 588; CURRENT_PROJECT_VERSION = 589;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
@@ -943,7 +943,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.588; MARKETING_VERSION = 1.0.589;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
PRODUCT_NAME = ServerBox; PRODUCT_NAME = ServerBox;
@@ -969,7 +969,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 588; CURRENT_PROJECT_VERSION = 589;
DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
@@ -981,7 +981,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.588; MARKETING_VERSION = 1.0.589;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
PRODUCT_NAME = ServerBox; PRODUCT_NAME = ServerBox;

View File

@@ -7,6 +7,8 @@
import Foundation import Foundation
let accessoryKey = "accessory_widget_url"
extension Date { extension Date {
func toStr() -> String { func toStr() -> String {
let formatter = DateFormatter() let formatter = DateFormatter()

View File

@@ -8,10 +8,11 @@
import WidgetKit import WidgetKit
import SwiftUI import SwiftUI
import Intents import Intents
import Foundation
let demoStatus = Status(name: "Server", cpu: "31.7%", mem: "1.3g / 1.9g", disk: "7.1g / 30.0g", net: "712.3k / 1.2m") let demoStatus = Status(name: "Server", cpu: "31.7%", mem: "1.3g / 1.9g", disk: "7.1g / 30.0g", net: "712.3k / 1.2m")
let domain = "com.lollipopkit.toolbox" let domain = "com.lollipopkit.toolbox"
var url: String? let bgColor = DynamicColor(dark: UIColor.black, light: UIColor.white)
struct Provider: IntentTimelineProvider { struct Provider: IntentTimelineProvider {
func placeholder(in context: Context) -> SimpleEntry { func placeholder(in context: Context) -> SimpleEntry {
@@ -24,11 +25,18 @@ struct Provider: IntentTimelineProvider {
} }
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) { func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
url = configuration.url var url = configuration.url
@Environment(\.widgetFamily) var family: WidgetFamily
if #available(iOSApplicationExtension 16.0, *) {
if family == .accessoryInline || family == .accessoryRectangular {
url = UserDefaults.standard.string(forKey: accessoryKey)
}
}
let currentDate = Date() let currentDate = Date()
let refreshDate = Calendar.current.date(byAdding: .minute, value: 30, to: currentDate)! let refreshDate = Calendar.current.date(byAdding: .minute, value: 30, to: currentDate)!
StatusLoader.fetch { result in StatusLoader.fetch(url: url) { result in
let entry: SimpleEntry let entry: SimpleEntry
switch result { switch result {
case .success(let status): case .success(let status):
@@ -55,36 +63,61 @@ struct SimpleEntry: TimelineEntry {
struct StatusWidgetEntryView : View { struct StatusWidgetEntryView : View {
var entry: Provider.Entry var entry: Provider.Entry
@Environment(\.widgetFamily) var family: WidgetFamily
var body: some View { var body: some View {
switch entry.state { switch entry.state {
case .loading: case .loading:
ProgressView().padding() ProgressView().widgetBackground()
case .error(let descriotion): case .error(let descriotion):
Text(descriotion).padding(.all, 13) Text(descriotion).widgetBackground()
case .normal(let data): case .normal(let data):
let sumColor: Color = .primary.opacity(0.7) let sumColor: Color = .primary.opacity(0.7)
VStack(alignment: .leading, spacing: 3.7) { switch family {
Text(data.name).font(.system(.title3, design: .monospaced)) case .accessoryRectangular:
Spacer() VStack(alignment: .leading, spacing: 2) {
DetailItem(icon: "cpu", text: data.cpu, color: sumColor) HStack {
DetailItem(icon: "memorychip", text: data.mem, color: sumColor) Text(data.name)
DetailItem(icon: "externaldrive", text: data.disk, color: sumColor) .font(.system(size: 15, weight: .semibold, design: .monospaced))
DetailItem(icon: "network", text: data.net, color: sumColor) Spacer()
Spacer() CirclePercent(percent: data.cpu)
DetailItem(icon: "clock", text: entry.date.toStr(), color: sumColor) .padding(.top, 3)
.padding(.trailing, 3)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
Spacer()
DetailItem(icon: "memorychip", text: data.mem, color: sumColor)
DetailItem(icon: "externaldrive", text: data.disk, color: sumColor)
DetailItem(icon: "network", text: data.net, color: sumColor)
}
.widgetBackground()
case .accessoryInline:
Text("\(data.name) \(data.cpu)").widgetBackground()
default:
VStack(alignment: .leading, spacing: 3.7) {
Text(data.name).font(.system(.title3, design: .monospaced))
Spacer()
DetailItem(icon: "cpu", text: data.cpu, color: sumColor)
DetailItem(icon: "memorychip", text: data.mem, color: sumColor)
DetailItem(icon: "externaldrive", text: data.disk, color: sumColor)
DetailItem(icon: "network", text: data.net, color: sumColor)
Spacer()
DetailItem(icon: "clock", text: entry.date.toStr(), color: sumColor)
.padding(.bottom, 3)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
.autoPadding()
.widgetBackground()
} }
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
.autoPadding()
.widgetBackground()
} }
} }
} }
extension View { extension View {
// Set bg to Color.black in Night, Color.white in Day
@ViewBuilder @ViewBuilder
func widgetBackground() -> some View { func widgetBackground() -> some View {
let backgroundView = Color(UIColor.systemBackground) // Set bg to black in Night, white in Day
let backgroundView = Color(bgColor.resolve())
if #available(iOS 17.0, *) { if #available(iOS 17.0, *) {
@Environment(\.showsWidgetContainerBackground) var showsWidgetContainerBackground @Environment(\.showsWidgetContainerBackground) var showsWidgetContainerBackground
containerBackground(for: .widget) { containerBackground(for: .widget) {
@@ -103,10 +136,6 @@ extension View {
// iOS 17 will auto add a SafeArea, so when iOS < 17, add .padding(.all, 17) // iOS 17 will auto add a SafeArea, so when iOS < 17, add .padding(.all, 17)
func autoPadding() -> some View { func autoPadding() -> some View {
if #available(iOS 17.0, *) { if #available(iOS 17.0, *) {
@Environment(\.showsWidgetContainerBackground) var showsWidgetContainerBackground
if (showsWidgetContainerBackground) {
return self.padding(.all, 17)
}
return self return self
} else { } else {
return self.padding(.all, 17) return self.padding(.all, 17)
@@ -123,11 +152,12 @@ struct StatusWidget: Widget {
} }
.configurationDisplayName("Status") .configurationDisplayName("Status")
.description("Status of your servers.") .description("Status of your servers.")
.supportedFamilies([.systemSmall])
if #available(iOS 16.0, *) { if #available(iOSApplicationExtension 16.0, *) {
let _ = cfg.supportedFamilies([.accessoryInline, .accessoryCircular]) return cfg.supportedFamilies([.systemSmall, .accessoryRectangular, .accessoryInline])
} else {
return cfg.supportedFamilies([.systemSmall])
} }
return cfg
} }
} }
@@ -139,7 +169,7 @@ struct StatusWidget_Previews: PreviewProvider {
} }
struct StatusLoader { struct StatusLoader {
static func fetch(completion: @escaping (Result<Status, Error>) -> Void) { static func fetch(url: String?, completion: @escaping (Result<Status, Error>) -> Void) {
guard let url = url, url.count >= 12 else { guard let url = url, url.count >= 12 else {
completion(.failure(NSError(domain: domain, code: 0, userInfo: [NSLocalizedDescriptionKey: "https://github.com/lollipopkit/server_box_monitor/wiki"]))) completion(.failure(NSError(domain: domain, code: 0, userInfo: [NSLocalizedDescriptionKey: "https://github.com/lollipopkit/server_box_monitor/wiki"])))
return return
@@ -148,6 +178,9 @@ struct StatusLoader {
completion(.failure(NSError(domain: domain, code: 1, userInfo: [NSLocalizedDescriptionKey: "url is invalid"]))) completion(.failure(NSError(domain: domain, code: 1, userInfo: [NSLocalizedDescriptionKey: "url is invalid"])))
return return
} }
UserDefaults.standard.set(url.absoluteString, forKey: accessoryKey)
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil { if error != nil {
completion(.failure(error!)) completion(.failure(error!))
@@ -173,7 +206,7 @@ struct StatusLoader {
if (code != 0) { if (code != 0) {
switch (code) { switch (code) {
default: default:
let msg = jsonAll["msg"] as? String ?? "" let msg = jsonAll["msg"] as? String ?? "Empty err"
return .failure(NSError(domain: domain, code: code, userInfo: [NSLocalizedDescriptionKey: msg])) return .failure(NSError(domain: domain, code: code, userInfo: [NSLocalizedDescriptionKey: msg]))
} }
} }
@@ -202,3 +235,49 @@ struct DetailItem: View {
} }
} }
} }
struct DetailItemSmall: View {
let icon: String
let text: String
let color: Color
var body: some View {
HStack(spacing: 6.7) {
Image(systemName: icon).resizable().foregroundColor(color).frame(width: 11, height: 11, alignment: .center)
Text(text)
.font(.system(size: 11, design: .monospaced))
.foregroundColor(color)
}
}
}
//
struct CirclePercent: View {
// eg: 31.7%
let percent: String
var body: some View {
// 31.7% -> 0.317
let percentD = Double(percent.trimmingCharacters(in: .init(charactersIn: "%")))
let double = (percentD ?? 0) / 100
Circle()
.trim(from: 0, to: CGFloat(double))
.stroke(Color.primary, lineWidth: 3)
.animation(.easeInOut(duration: 0.5))
}
}
struct DynamicColor {
let dark: UIColor
let light: UIColor
func resolve() -> UIColor {
if #available(iOS 13, *) { // 13
return UIColor { (traitCollection: UITraitCollection) -> UIColor in
return traitCollection.userInterfaceStyle == UIUserInterfaceStyle.dark ?
self.dark : self.light
}
}
return self.light
}
}

View File

@@ -9,15 +9,16 @@ enum SystemType {
const SystemType._(this.value); const SystemType._(this.value);
static SystemType? parse(String? value) { static SystemType parse(String value) {
if (value == null) return null; switch (value.trim()) {
switch (value) {
case linuxSign: case linuxSign:
return SystemType.linux; return SystemType.linux;
case bsdSign: case bsdSign:
return SystemType.bsd; return SystemType.bsd;
default:
// Fallback to linux
return SystemType.linux;
} }
return null;
} }
bool isSegmentsLenMatch(int len) => len == segmentsLen; bool isSegmentsLenMatch(int len) => len == segmentsLen;

View File

@@ -329,10 +329,10 @@ class ServerProvider extends ChangeNotifier {
} }
final systemType = SystemType.parse(segments[0]); final systemType = SystemType.parse(segments[0]);
if (systemType == null || !systemType.isSegmentsLenMatch(segments.length)) { if (!systemType.isSegmentsLenMatch(segments.length)) {
_limiter.inc(sid); _limiter.inc(sid);
s.status.failedInfo = s.status.failedInfo =
'Segments not match: expect ${systemType?.segmentsLen}, got ${segments.length}'; 'Segments not match: expect ${systemType.segmentsLen}, got ${segments.length}';
_setServerState(s, ServerState.failed); _setServerState(s, ServerState.failed);
return; return;
} }

View File

@@ -2,9 +2,9 @@
class BuildData { class BuildData {
static const String name = "ServerBox"; static const String name = "ServerBox";
static const int build = 588; static const int build = 589;
static const String engine = "3.13.6"; static const String engine = "3.13.6";
static const String buildAt = "2023-10-13 14:38:17"; static const String buildAt = "2023-10-14 12:09:35";
static const int modifications = 5; static const int modifications = 6;
static const int script = 21; static const int script = 21;
} }