From 6db6a24969064f0e90655c40eea362c7588a8ff8 Mon Sep 17 00:00:00 2001 From: senseiGai Date: Fri, 17 Apr 2026 09:03:47 +0500 Subject: [PATCH] =?UTF-8?q?=D0=91=D0=B0=D0=BD=D0=BD=D0=B5=D1=80=20=D0=B0?= =?UTF-8?q?=D0=B2=D1=82=D0=BE=D1=80=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=BE=D0=B3=D0=BE=20=D1=83=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=B9=D1=81=D1=82=D0=B2=D0=B0=20=D0=B2=20=D1=87=D0=B0?= =?UTF-8?q?=D1=82-=D0=BB=D0=B8=D1=81=D1=82=D0=B5=20(Telegram=20parity)=20+?= =?UTF-8?q?=20=D1=84=D0=B8=D0=BA=D1=81=20=D0=BD=D0=B0=D0=B2=D0=B8=D0=B3?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8=20Backup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Rosetta.xcodeproj/project.pbxproj | 20 ++-- .../xcshareddata/xcschemes/Rosetta.xcscheme | 2 +- Rosetta/Core/Utils/ReleaseNotes.swift | 23 ++-- .../ChatList/UIKit/ChatListUIKitView.swift | 84 +++++++++++++ .../UIKit/DeviceAlertBannerView.swift | 113 ++++++++++++++++++ Rosetta/Features/Settings/SafetyView.swift | 12 +- 6 files changed, 229 insertions(+), 25 deletions(-) create mode 100644 Rosetta/Features/Chats/ChatList/UIKit/DeviceAlertBannerView.swift diff --git a/Rosetta.xcodeproj/project.pbxproj b/Rosetta.xcodeproj/project.pbxproj index 3424f46..b22af0a 100644 --- a/Rosetta.xcodeproj/project.pbxproj +++ b/Rosetta.xcodeproj/project.pbxproj @@ -718,7 +718,7 @@ CODE_SIGN_ENTITLEMENTS = Rosetta/Rosetta.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 38; + CURRENT_PROJECT_VERSION = 39; DEVELOPMENT_TEAM = QN8Z263QGX; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -734,7 +734,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.3.7; + MARKETING_VERSION = 1.3.8; PRODUCT_BUNDLE_IDENTIFIER = com.rosetta.dev; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -758,7 +758,7 @@ CODE_SIGN_ENTITLEMENTS = Rosetta/Rosetta.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 38; + CURRENT_PROJECT_VERSION = 39; DEVELOPMENT_TEAM = QN8Z263QGX; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -774,7 +774,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.3.7; + MARKETING_VERSION = 1.3.8; PRODUCT_BUNDLE_IDENTIFIER = com.rosetta.dev; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -949,7 +949,7 @@ C19929D9466573F31997B2C0 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Debug; + defaultConfigurationName = Release; }; 853F295D2F4B50410092AD05 /* Build configuration list for PBXProject "Rosetta" */ = { isa = XCConfigurationList; @@ -958,7 +958,7 @@ 853F296C2F4B50420092AD05 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Debug; + defaultConfigurationName = Release; }; 853F296D2F4B50420092AD05 /* Build configuration list for PBXNativeTarget "Rosetta" */ = { isa = XCConfigurationList; @@ -967,7 +967,7 @@ 853F296F2F4B50420092AD05 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Debug; + defaultConfigurationName = Release; }; A8D200712F9000010092AD05 /* Build configuration list for PBXNativeTarget "RosettaUITests" */ = { isa = XCConfigurationList; @@ -976,7 +976,7 @@ A8D200622F9000010092AD05 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Debug; + defaultConfigurationName = Release; }; B5D2E60ADEB8AE2E8F7615C6 /* Build configuration list for PBXNativeTarget "RosettaNotificationService" */ = { isa = XCConfigurationList; @@ -985,7 +985,7 @@ 0140D6320A9CF4B5E933E0B1 /* Debug */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Debug; + defaultConfigurationName = Release; }; LA00000062F8D22220092AD05 /* Build configuration list for PBXNativeTarget "RosettaLiveActivityWidget" */ = { isa = XCConfigurationList; @@ -994,7 +994,7 @@ LA00000082F8D22220092AD05 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Debug; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ diff --git a/Rosetta.xcodeproj/xcshareddata/xcschemes/Rosetta.xcscheme b/Rosetta.xcodeproj/xcshareddata/xcschemes/Rosetta.xcscheme index 39a5209..a4e863c 100644 --- a/Rosetta.xcodeproj/xcshareddata/xcschemes/Rosetta.xcscheme +++ b/Rosetta.xcodeproj/xcshareddata/xcschemes/Rosetta.xcscheme @@ -66,7 +66,7 @@ Void)? + var onDecline: (() -> Void)? + + private let glass = TelegramGlassUIView() + private let shieldIcon = UIImageView() + private let titleLabel = UILabel() + private let subtitleLabel = UILabel() + private let acceptButton = UIButton(type: .system) + private let declineButton = UIButton(type: .system) + + static let bannerHeight: CGFloat = 80 + + override init(frame: CGRect) { + super.init(frame: frame) + setupSubviews() + } + + @available(*, unavailable) + required init?(coder: NSCoder) { fatalError() } + + private func setupSubviews() { + // Glass background + glass.fixedCornerRadius = 14 + glass.clipsToBounds = true + addSubview(glass) + + // Shield icon + let config = UIImage.SymbolConfiguration(pointSize: 24, weight: .medium) + shieldIcon.image = UIImage(systemName: "shield.lefthalf.filled", withConfiguration: config) + shieldIcon.tintColor = UIColor(red: 0.14, green: 0.54, blue: 0.9, alpha: 1) // primaryBlue + shieldIcon.contentMode = .center + addSubview(shieldIcon) + + // Title + titleLabel.text = "New device login" + titleLabel.font = .systemFont(ofSize: 15, weight: .semibold) + titleLabel.textColor = UIColor { $0.userInterfaceStyle == .dark ? .white : .black } + addSubview(titleLabel) + + // Subtitle (device name) + subtitleLabel.font = .systemFont(ofSize: 13, weight: .regular) + subtitleLabel.textColor = UIColor { $0.userInterfaceStyle == .dark + ? UIColor.white.withAlphaComponent(0.6) + : UIColor.black.withAlphaComponent(0.5) + } + subtitleLabel.lineBreakMode = .byTruncatingTail + addSubview(subtitleLabel) + + // Accept button + acceptButton.setTitle("Accept", for: .normal) + acceptButton.titleLabel?.font = .systemFont(ofSize: 14, weight: .semibold) + acceptButton.setTitleColor(.white, for: .normal) + acceptButton.backgroundColor = UIColor(red: 0.14, green: 0.54, blue: 0.9, alpha: 1) + acceptButton.layer.cornerRadius = 14 + acceptButton.addTarget(self, action: #selector(acceptTapped), for: .touchUpInside) + addSubview(acceptButton) + + // Decline button + declineButton.setTitle("Decline", for: .normal) + declineButton.titleLabel?.font = .systemFont(ofSize: 14, weight: .medium) + declineButton.setTitleColor(UIColor(red: 0.9, green: 0.25, blue: 0.25, alpha: 1), for: .normal) + declineButton.addTarget(self, action: #selector(declineTapped), for: .touchUpInside) + addSubview(declineButton) + } + + func configure(deviceName: String, deviceOs: String) { + subtitleLabel.text = "\(deviceName) · \(deviceOs)" + } + + override func layoutSubviews() { + super.layoutSubviews() + glass.frame = bounds + + let leftPad: CGFloat = 14 + let iconSize: CGFloat = 36 + + shieldIcon.frame = CGRect( + x: leftPad, + y: (bounds.height - iconSize) / 2, + width: iconSize, + height: iconSize + ) + + let textX = shieldIcon.frame.maxX + 10 + let buttonW: CGFloat = 70 + let declineW: CGFloat = 65 + let rightPad: CGFloat = 12 + let buttonsW = buttonW + 8 + declineW + rightPad + let textW = bounds.width - textX - buttonsW + + titleLabel.frame = CGRect(x: textX, y: 18, width: textW, height: 20) + subtitleLabel.frame = CGRect(x: textX, y: 40, width: textW, height: 18) + + let btnY: CGFloat = (bounds.height - 28) / 2 + acceptButton.frame = CGRect( + x: bounds.width - rightPad - declineW - 8 - buttonW, + y: btnY, width: buttonW, height: 28 + ) + declineButton.frame = CGRect( + x: bounds.width - rightPad - declineW, + y: btnY, width: declineW, height: 28 + ) + } + + @objc private func acceptTapped() { onAccept?() } + @objc private func declineTapped() { onDecline?() } +} diff --git a/Rosetta/Features/Settings/SafetyView.swift b/Rosetta/Features/Settings/SafetyView.swift index 061f771..b1538b3 100644 --- a/Rosetta/Features/Settings/SafetyView.swift +++ b/Rosetta/Features/Settings/SafetyView.swift @@ -9,6 +9,7 @@ struct SafetyView: View { @State private var copiedPublicKey = false @State private var copiedPrivateKey = false @State private var showDeleteConfirmation = false + @State private var navController: UINavigationController? private var publicKey: String { SessionManager.shared.currentPublicKey @@ -38,6 +39,11 @@ struct SafetyView: View { .padding(.leading, 8) .padding(.top, 4) } + .background( + NavigationControllerAccessor { nav in + self.navController = nav + } + ) .background(RosettaColors.Adaptive.background) .scrollContentBackground(.hidden) .navigationBarTitleDisplayMode(.inline) @@ -129,7 +135,11 @@ struct SafetyView: View { VStack(alignment: .leading, spacing: 8) { SettingsCard { VStack(spacing: 0) { - NavigationLink(value: SettingsDestination.backup) { + Button { + let hosting = UIHostingController(rootView: BackupView()) + hosting.view.backgroundColor = UIColor(RosettaColors.Adaptive.background) + navController?.pushViewController(hosting, animated: true) + } label: { HStack { Text("Backup") .font(.system(size: 15))