diff --git a/VoidLink.xcodeproj/project.pbxproj b/VoidLink.xcodeproj/project.pbxproj index da2f9d46..f7e9d4fc 100644 --- a/VoidLink.xcodeproj/project.pbxproj +++ b/VoidLink.xcodeproj/project.pbxproj @@ -10,6 +10,8 @@ 1829CE3F2E2154DF0074A99A /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1829CE3E2E2154DF0074A99A /* SceneDelegate.m */; }; 18341A042DEB662C0094E5F2 /* FixedTintImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 18341A032DEB662C0094E5F2 /* FixedTintImageView.m */; }; 187F4B282E04658A00EECC59 /* WidgetPanelStackView.m in Sources */ = {isa = PBXBuildFile; fileRef = 187F4B272E04658A00EECC59 /* WidgetPanelStackView.m */; }; + 1888C1922E24C33100108730 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1888C1912E24C33100108730 /* AboutViewController.swift */; }; + 1888C1932E24C41000108730 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1888C1902E24C2C800108730 /* AboutView.swift */; }; 189AD29A2DE7446000E24B88 /* HostCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 189AD2992DE7446000E24B88 /* HostCollectionViewController.m */; }; 840751B32BF49C050096B657 /* CustomTapGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 840751B22BF49C050096B657 /* CustomTapGestureRecognizer.m */; }; 841BAC922DE35D6B00DA639E /* ThemeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 841BAC912DE35D6B00DA639E /* ThemeManager.m */; }; @@ -137,6 +139,8 @@ 18341A032DEB662C0094E5F2 /* FixedTintImageView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FixedTintImageView.m; sourceTree = ""; }; 187F4B232E04633100EECC59 /* WidgetPanelStackView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WidgetPanelStackView.h; sourceTree = ""; }; 187F4B272E04658A00EECC59 /* WidgetPanelStackView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WidgetPanelStackView.m; sourceTree = ""; }; + 1888C1902E24C2C800108730 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = ""; }; + 1888C1912E24C33100108730 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = ""; }; 189AD2962DE743B700E24B88 /* HostCollectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HostCollectionViewController.h; sourceTree = ""; }; 189AD2992DE7446000E24B88 /* HostCollectionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HostCollectionViewController.m; sourceTree = ""; }; 18BF141D2E0D7A00009DEE4F /* VoidLink v1.0.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "VoidLink v1.0.xcdatamodel"; sourceTree = ""; }; @@ -513,6 +517,8 @@ FBDE86DF19F7A837001C18A8 /* UIComputerView.m */, FBDE86E419F82297001C18A8 /* UIAppView.h */, FBDE86E519F82297001C18A8 /* UIAppView.m */, + 1888C1902E24C2C800108730 /* AboutView.swift */, + 1888C1912E24C33100108730 /* AboutViewController.swift */, FB89463719F6473800339C8A /* Launch Screen.xib */, FB290D0819B2C406004C83CF /* Images.xcassets */, FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */, @@ -917,6 +923,7 @@ DC1F5A07206436B20037755F /* ConnectionHelper.m in Sources */, FB89462E19F646E200339C8A /* PairManager.m in Sources */, FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */, + 1888C1932E24C41000108730 /* AboutView.swift in Sources */, FB4678ED1A50C40900377732 /* OnScreenControls.m in Sources */, 84E1CDFA2C4FE83400547904 /* SwiftLocalizationHelper.swift in Sources */, FB290D0019B2C406004C83CF /* main.m in Sources */, @@ -926,6 +933,7 @@ 84351B0E2C29ACCB00A77989 /* LayoutOnScreenControls.m in Sources */, FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */, FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */, + 1888C1922E24C33100108730 /* AboutViewController.swift in Sources */, FBD349621A0089F6002D2A60 /* DataManager.m in Sources */, FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */, FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */, diff --git a/VoidLink/AboutView.swift b/VoidLink/AboutView.swift new file mode 100644 index 00000000..eed30c73 --- /dev/null +++ b/VoidLink/AboutView.swift @@ -0,0 +1,86 @@ +// +// AboutView.swift +// VoidLink +// +// Created by True砖家 on 5/18/25. +// Copyright © 2025 True砖家 @ Bilibili. All rights reserved. +// + + +import SwiftUI + +@available(iOS 13.0, *) +public struct AboutView: View { + @Environment(\.presentationMode) var presentationMode + + public var body: some View { + VStack(spacing: 20) { + // App 图标 + Image(uiImage: UIImage(named: "AppIconMedium") ?? UIImage()) + .resizable() + .frame(width: 100, height: 100) + .clipShape(RoundedRectangle(cornerRadius: 36)) + + // App 名称 + Text(Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? "App Name") + .font(.title) + .bold() + + // 版本号 + if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { + Text("Version \(version)") + .font(.subheadline) + .foregroundColor(.gray) + } + + // 说明文字 + Text(SwiftLocalizationHelper.localizedString(forKey: "From the player community, to the player community.")) + .multilineTextAlignment(.leading) + .lineLimit(nil) + .frame(maxWidth: 570) // ✅ 避免 Text 被拉得太宽无法换行 + .padding() + + // 链接按钮 + if #available(iOS 14.0, *) { + Link(SwiftLocalizationHelper.localizedString(forKey: "Join us"), destination: URL(string: "https://example.com")!) + .padding(.top, 10) + Spacer() + // OK 按钮 + Button("OK") { + presentationMode.wrappedValue.dismiss() + } + .padding() + .background(Color.blue) + .foregroundColor(.white) + .frame(height: 46) + //.frame(width: 100) + .cornerRadius(12) + } else { + HStack(spacing: 20) { + Button(SwiftLocalizationHelper.localizedString(forKey: "Join us")) { + // 打开链接 + if let url = URL(string: "https://example.com") { + UIApplication.shared.open(url) + } + } + .padding() + .background(Color.blue) + .foregroundColor(.white) + .cornerRadius(12) + .frame(minWidth: 100) + + Button("OK") { + presentationMode.wrappedValue.dismiss() + } + .padding() + .background(Color.blue) + .foregroundColor(.white) + .cornerRadius(12) + .frame(minWidth: 100) + } + .padding(.top, 10) + } + } + .padding() + } +} diff --git a/VoidLink/AboutViewController.swift b/VoidLink/AboutViewController.swift new file mode 100644 index 00000000..9b996ae5 --- /dev/null +++ b/VoidLink/AboutViewController.swift @@ -0,0 +1,37 @@ +// +// AboutViewController.swift +// VoidLink +// +// Created by Weimin on 2025/7/14. +// Copyright © 2025 True砖家 @ Bilibili. All rights reserved. +// + + +import SwiftUI + +@available(iOS 13.0, *) +@objc class AboutViewController: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + + let hostingVC = UIHostingController(rootView: AboutView()) + addChild(hostingVC) + hostingVC.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(hostingVC.view) + hostingVC.didMove(toParent: self) + + NSLayoutConstraint.activate([ + hostingVC.view.topAnchor.constraint(equalTo: view.topAnchor), + hostingVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + hostingVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + hostingVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + ]) + + // 🎯 设置弹窗大小 + preferredContentSize = CGSize(width: 600, height: 450) + + // ⚠️ 一定要设置以下样式才会生效 preferredContentSize + modalPresentationStyle = .formSheet + } +} + diff --git a/VoidLink/Images.xcassets/AppIconMedium.imageset/AppIconMedium.png b/VoidLink/Images.xcassets/AppIconMedium.imageset/AppIconMedium.png new file mode 100644 index 00000000..d4218570 Binary files /dev/null and b/VoidLink/Images.xcassets/AppIconMedium.imageset/AppIconMedium.png differ diff --git a/VoidLink/Images.xcassets/AppIconMedium.imageset/Contents.json b/VoidLink/Images.xcassets/AppIconMedium.imageset/Contents.json new file mode 100644 index 00000000..53cad8b1 --- /dev/null +++ b/VoidLink/Images.xcassets/AppIconMedium.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "AppIconMedium.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/VoidLink/Localization/Localizable.xcstrings b/VoidLink/Localization/Localizable.xcstrings index 36b26495..4a40457e 100644 --- a/VoidLink/Localization/Localizable.xcstrings +++ b/VoidLink/Localization/Localizable.xcstrings @@ -1802,6 +1802,29 @@ } } }, + "From the player community, to the player community." : { + "extractionState" : "manual", + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "从玩家社区中来,到玩家社区中去。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "從玩家社群中來,到玩家社群中去。" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "從玩家社群中來,到玩家社群中去。" + } + } + } + }, "Gestures" : { "extractionState" : "manual", "localizations" : { @@ -2078,6 +2101,29 @@ } } }, + "Join us" : { + "extractionState" : "manual", + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "加入我们" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "加入我們" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "加入我們" + } + } + } + }, "Launch" : { "extractionState" : "manual", "localizations" : { @@ -4253,6 +4299,9 @@ } } } + }, + "Version %@" : { + }, "Video" : { "extractionState" : "manual", diff --git a/VoidLink/ViewControllers/MainFrameViewController.m b/VoidLink/ViewControllers/MainFrameViewController.m index 669b973f..d1a97e44 100644 --- a/VoidLink/ViewControllers/MainFrameViewController.m +++ b/VoidLink/ViewControllers/MainFrameViewController.m @@ -1346,13 +1346,23 @@ static NSMutableSet* hostList; button.frame = CGRectMake(0, 0, buttonHeight, buttonHeight); // 添加点击事件 - // [button addTarget:self action:@selector(addDeviceTapped) forControlEvents:UIControlEventTouchUpInside]; + [button addTarget:self action:@selector(helpButtonTapped) forControlEvents:UIControlEventTouchUpInside]; // 创建 UIBarButtonItem UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithCustomView:button]; return barItem; } +- (void)helpButtonTapped{ + if (@available(iOS 13.0, *)) { + AboutViewController *aboutVC = [[AboutViewController alloc] init]; + aboutVC.modalPresentationStyle = UIModalPresentationFormSheet; + [self presentViewController:aboutVC animated:YES completion:nil]; + } else { + // Fallback on earlier versions + } +} + - (CGFloat)getStandardNavBarHeight{ return [self isIPhone] ? UINavigationBarHeightIPhone : UINavigationBarHeightIPad; }