Fix all build errors in Xcode-managed nested source files
The Xcode project was created inside the existing folder structure, producing a second copy of all source files at the deeper nested path that Xcode actually compiles. All fixes are now applied to both paths. Changes: - Add `import Combine` to nested ViewModels (Portfolio, Recommendations, Positions, Alerts) and NotificationHandler — required for @Published - Add `import UIKit` to NotificationPermissions — UIApplication is UIKit - Rewrite APIClient to use `(any Encodable)?` instead of invalid `(some Encodable)?` syntax; add encodeAny() helper to open existential for JSONEncoder; remove private EmptyBody type - Replace all `body: Optional<String>.none` / `Optional<EmptyBody>.none` call sites with plain `nil` across all ViewModels and Views - Sync all fixes between nested Xcode path and outer source path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,6 @@ final class APIClient {
|
||||
d.dateDecodingStrategy = .custom { decoder in
|
||||
let container = try decoder.singleValueContainer()
|
||||
let str = try container.decode(String.self)
|
||||
// Try ISO8601 with fractional seconds first, then without
|
||||
let formatters: [ISO8601DateFormatter] = [
|
||||
{
|
||||
let f = ISO8601DateFormatter()
|
||||
@@ -35,11 +34,12 @@ final class APIClient {
|
||||
for fmt in formatters {
|
||||
if let date = fmt.date(from: str) { return date }
|
||||
}
|
||||
// Try plain date (YYYY-MM-DD) for date-only fields decoded as Date
|
||||
let df = DateFormatter()
|
||||
df.dateFormat = "yyyy-MM-dd"
|
||||
if let date = df.date(from: str) { return date }
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Cannot parse date: \(str)"))
|
||||
throw DecodingError.dataCorrupted(
|
||||
.init(codingPath: decoder.codingPath,
|
||||
debugDescription: "Cannot parse date: \(str)"))
|
||||
}
|
||||
return d
|
||||
}()
|
||||
@@ -54,7 +54,7 @@ final class APIClient {
|
||||
|
||||
func request<T: Decodable>(
|
||||
_ endpoint: Endpoint,
|
||||
body: (some Encodable)? = Optional<EmptyBody>.none
|
||||
body: (any Encodable)? = nil
|
||||
) async throws -> T {
|
||||
guard let token = LocalStore.shared.deviceToken else {
|
||||
throw APIError.noDeviceToken
|
||||
@@ -66,7 +66,7 @@ final class APIClient {
|
||||
}
|
||||
|
||||
/// Version that doesn't return a body (e.g. DELETE 204)
|
||||
func requestVoid(_ endpoint: Endpoint, body: (some Encodable)? = Optional<EmptyBody>.none) async throws {
|
||||
func requestVoid(_ endpoint: Endpoint, body: (any Encodable)? = nil) async throws {
|
||||
guard let token = LocalStore.shared.deviceToken else {
|
||||
throw APIError.noDeviceToken
|
||||
}
|
||||
@@ -76,7 +76,10 @@ final class APIClient {
|
||||
}
|
||||
|
||||
/// For device registration (no token yet)
|
||||
func requestNoAuth<T: Decodable>(_ endpoint: Endpoint, body: (some Encodable)? = Optional<EmptyBody>.none) async throws -> T {
|
||||
func requestNoAuth<T: Decodable>(
|
||||
_ endpoint: Endpoint,
|
||||
body: (any Encodable)? = nil
|
||||
) async throws -> T {
|
||||
let req = try buildRequest(endpoint, deviceToken: nil, body: body)
|
||||
let (data, response) = try await session.data(for: req)
|
||||
try validateResponse(response, data: data)
|
||||
@@ -85,7 +88,11 @@ final class APIClient {
|
||||
|
||||
// ─── Helpers ──────────────────────────────────────────────────────────────
|
||||
|
||||
private func buildRequest(_ endpoint: Endpoint, deviceToken: String?, body: (some Encodable)?) throws -> URLRequest {
|
||||
private func buildRequest(
|
||||
_ endpoint: Endpoint,
|
||||
deviceToken: String?,
|
||||
body: (any Encodable)?
|
||||
) throws -> URLRequest {
|
||||
guard let url = URL(string: Constants.apiBaseURL + endpoint.path) else {
|
||||
throw APIError.invalidURL
|
||||
}
|
||||
@@ -96,11 +103,19 @@ final class APIClient {
|
||||
request.setValue(token, forHTTPHeaderField: "X-Device-Token")
|
||||
}
|
||||
if let body {
|
||||
request.httpBody = try encoder.encode(body)
|
||||
request.httpBody = try encodeAny(body)
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
/// Opens the `any Encodable` existential so JSONEncoder can encode it.
|
||||
private func encodeAny(_ value: any Encodable) throws -> Data {
|
||||
func encode<T: Encodable>(_ v: T) throws -> Data {
|
||||
try encoder.encode(v)
|
||||
}
|
||||
return try encode(value)
|
||||
}
|
||||
|
||||
private func validateResponse(_ response: URLResponse, data: Data) throws {
|
||||
guard let httpResponse = response as? HTTPURLResponse else {
|
||||
throw APIError.invalidResponse
|
||||
@@ -121,8 +136,6 @@ final class APIClient {
|
||||
|
||||
// ─── Supporting types ──────────────────────────────────────────────────────────
|
||||
|
||||
private struct EmptyBody: Encodable {}
|
||||
|
||||
enum APIError: LocalizedError {
|
||||
case noDeviceToken
|
||||
case invalidURL
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import UserNotifications
|
||||
|
||||
@MainActor
|
||||
|
||||
Binary file not shown.
@@ -42,9 +42,7 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
apns_token: token,
|
||||
device_name: UIDevice.current.name
|
||||
)
|
||||
// Temporarily set the token so APIClient has it, but use requestNoAuth
|
||||
// since this is the registration call itself
|
||||
let old = LocalStore.shared.deviceToken
|
||||
// Ensure token is stored before the request so APIClient can use it
|
||||
LocalStore.shared.deviceToken = token
|
||||
let response: DeviceResponse = try await APIClient.shared.requestNoAuth(
|
||||
.registerDevice,
|
||||
|
||||
@@ -19,7 +19,6 @@ final class APIClient {
|
||||
d.dateDecodingStrategy = .custom { decoder in
|
||||
let container = try decoder.singleValueContainer()
|
||||
let str = try container.decode(String.self)
|
||||
// Try ISO8601 with fractional seconds first, then without
|
||||
let formatters: [ISO8601DateFormatter] = [
|
||||
{
|
||||
let f = ISO8601DateFormatter()
|
||||
@@ -35,11 +34,12 @@ final class APIClient {
|
||||
for fmt in formatters {
|
||||
if let date = fmt.date(from: str) { return date }
|
||||
}
|
||||
// Try plain date (YYYY-MM-DD) for date-only fields decoded as Date
|
||||
let df = DateFormatter()
|
||||
df.dateFormat = "yyyy-MM-dd"
|
||||
if let date = df.date(from: str) { return date }
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "Cannot parse date: \(str)"))
|
||||
throw DecodingError.dataCorrupted(
|
||||
.init(codingPath: decoder.codingPath,
|
||||
debugDescription: "Cannot parse date: \(str)"))
|
||||
}
|
||||
return d
|
||||
}()
|
||||
@@ -54,7 +54,7 @@ final class APIClient {
|
||||
|
||||
func request<T: Decodable>(
|
||||
_ endpoint: Endpoint,
|
||||
body: (some Encodable)? = Optional<EmptyBody>.none
|
||||
body: (any Encodable)? = nil
|
||||
) async throws -> T {
|
||||
guard let token = LocalStore.shared.deviceToken else {
|
||||
throw APIError.noDeviceToken
|
||||
@@ -66,7 +66,7 @@ final class APIClient {
|
||||
}
|
||||
|
||||
/// Version that doesn't return a body (e.g. DELETE 204)
|
||||
func requestVoid(_ endpoint: Endpoint, body: (some Encodable)? = Optional<EmptyBody>.none) async throws {
|
||||
func requestVoid(_ endpoint: Endpoint, body: (any Encodable)? = nil) async throws {
|
||||
guard let token = LocalStore.shared.deviceToken else {
|
||||
throw APIError.noDeviceToken
|
||||
}
|
||||
@@ -76,7 +76,10 @@ final class APIClient {
|
||||
}
|
||||
|
||||
/// For device registration (no token yet)
|
||||
func requestNoAuth<T: Decodable>(_ endpoint: Endpoint, body: (some Encodable)? = Optional<EmptyBody>.none) async throws -> T {
|
||||
func requestNoAuth<T: Decodable>(
|
||||
_ endpoint: Endpoint,
|
||||
body: (any Encodable)? = nil
|
||||
) async throws -> T {
|
||||
let req = try buildRequest(endpoint, deviceToken: nil, body: body)
|
||||
let (data, response) = try await session.data(for: req)
|
||||
try validateResponse(response, data: data)
|
||||
@@ -85,7 +88,11 @@ final class APIClient {
|
||||
|
||||
// ─── Helpers ──────────────────────────────────────────────────────────────
|
||||
|
||||
private func buildRequest(_ endpoint: Endpoint, deviceToken: String?, body: (some Encodable)?) throws -> URLRequest {
|
||||
private func buildRequest(
|
||||
_ endpoint: Endpoint,
|
||||
deviceToken: String?,
|
||||
body: (any Encodable)?
|
||||
) throws -> URLRequest {
|
||||
guard let url = URL(string: Constants.apiBaseURL + endpoint.path) else {
|
||||
throw APIError.invalidURL
|
||||
}
|
||||
@@ -96,11 +103,19 @@ final class APIClient {
|
||||
request.setValue(token, forHTTPHeaderField: "X-Device-Token")
|
||||
}
|
||||
if let body {
|
||||
request.httpBody = try encoder.encode(body)
|
||||
request.httpBody = try encodeAny(body)
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
/// Opens the `any Encodable` existential so JSONEncoder can encode it.
|
||||
private func encodeAny(_ value: any Encodable) throws -> Data {
|
||||
func encode<T: Encodable>(_ v: T) throws -> Data {
|
||||
try encoder.encode(v)
|
||||
}
|
||||
return try encode(value)
|
||||
}
|
||||
|
||||
private func validateResponse(_ response: URLResponse, data: Data) throws {
|
||||
guard let httpResponse = response as? HTTPURLResponse else {
|
||||
throw APIError.invalidResponse
|
||||
@@ -121,8 +136,6 @@ final class APIClient {
|
||||
|
||||
// ─── Supporting types ──────────────────────────────────────────────────────────
|
||||
|
||||
private struct EmptyBody: Encodable {}
|
||||
|
||||
enum APIError: LocalizedError {
|
||||
case noDeviceToken
|
||||
case invalidURL
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
import UserNotifications
|
||||
|
||||
/// Handles incoming push notifications — both foreground and background tap.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import UserNotifications
|
||||
|
||||
@MainActor
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
@MainActor
|
||||
final class AlertsViewModel: ObservableObject {
|
||||
@@ -14,7 +15,7 @@ final class AlertsViewModel: ObservableObject {
|
||||
do {
|
||||
alerts = try await APIClient.shared.request(
|
||||
.getAlerts(unreadOnly: unreadOnly),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
LocalStore.shared.unreadAlertCount = unreadCount
|
||||
} catch {
|
||||
@@ -27,7 +28,7 @@ final class AlertsViewModel: ObservableObject {
|
||||
do {
|
||||
let updated: AppAlert = try await APIClient.shared.request(
|
||||
.acknowledgeAlert(alert.id),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
if let idx = alerts.firstIndex(where: { $0.id == alert.id }) {
|
||||
alerts[idx] = updated
|
||||
|
||||
@@ -45,18 +45,18 @@ final class DashboardViewModel: ObservableObject {
|
||||
// ─── Private loaders ──────────────────────────────────────────────────────
|
||||
|
||||
private func loadStocks() async -> [PortfolioPosition] {
|
||||
(try? await APIClient.shared.request(.getPortfolio, body: Optional<String>.none)) ?? []
|
||||
(try? await APIClient.shared.request(.getPortfolio, body: nil)) ?? []
|
||||
}
|
||||
|
||||
private func loadOptions() async -> [OptionPosition] {
|
||||
(try? await APIClient.shared.request(.getPositions(status: "open"), body: Optional<String>.none)) ?? []
|
||||
(try? await APIClient.shared.request(.getPositions(status: "open"), body: nil)) ?? []
|
||||
}
|
||||
|
||||
private func loadRecommendations() async -> [Recommendation] {
|
||||
(try? await APIClient.shared.request(.getRecommendations(timeHorizon: nil), body: Optional<String>.none)) ?? []
|
||||
(try? await APIClient.shared.request(.getRecommendations(timeHorizon: nil), body: nil)) ?? []
|
||||
}
|
||||
|
||||
private func loadAlerts() async -> [AppAlert] {
|
||||
(try? await APIClient.shared.request(.getAlerts(unreadOnly: true), body: Optional<String>.none)) ?? []
|
||||
(try? await APIClient.shared.request(.getAlerts(unreadOnly: true), body: nil)) ?? []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
@MainActor
|
||||
final class PortfolioViewModel: ObservableObject {
|
||||
@@ -10,7 +11,7 @@ final class PortfolioViewModel: ObservableObject {
|
||||
isLoading = true
|
||||
error = nil
|
||||
do {
|
||||
positions = try await APIClient.shared.request(.getPortfolio, body: Optional<String>.none)
|
||||
positions = try await APIClient.shared.request(.getPortfolio, body: nil)
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
}
|
||||
@@ -35,7 +36,7 @@ final class PortfolioViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
func add(ticker: String, shares: Int, costBasis: Double?) async {
|
||||
var updated = positions
|
||||
let updated = positions
|
||||
struct AddBody: Encodable {
|
||||
let ticker: String
|
||||
let shares: Int
|
||||
@@ -57,7 +58,7 @@ final class PortfolioViewModel: ObservableObject {
|
||||
isLoading = true
|
||||
error = nil
|
||||
do {
|
||||
try await APIClient.shared.requestVoid(.deleteTicker(ticker), body: Optional<String>.none)
|
||||
try await APIClient.shared.requestVoid(.deleteTicker(ticker), body: nil)
|
||||
positions.removeAll { $0.ticker == ticker }
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
@MainActor
|
||||
final class PositionsViewModel: ObservableObject {
|
||||
@@ -15,7 +16,7 @@ final class PositionsViewModel: ObservableObject {
|
||||
do {
|
||||
positions = try await APIClient.shared.request(
|
||||
.getPositions(status: nil),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
@MainActor
|
||||
final class RecommendationsViewModel: ObservableObject {
|
||||
@@ -21,7 +22,7 @@ final class RecommendationsViewModel: ObservableObject {
|
||||
do {
|
||||
recommendations = try await APIClient.shared.request(
|
||||
.getRecommendations(timeHorizon: nil),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
@@ -35,7 +36,7 @@ final class RecommendationsViewModel: ObservableObject {
|
||||
do {
|
||||
recommendations = try await APIClient.shared.request(
|
||||
.refreshRecommendations,
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
@@ -47,7 +48,7 @@ final class RecommendationsViewModel: ObservableObject {
|
||||
do {
|
||||
return try await APIClient.shared.request(
|
||||
.getRecommendation(ticker: ticker, strategy: selectedStrategy, timeHorizon: selectedHorizon),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
|
||||
@@ -22,7 +22,7 @@ struct OpenPositionsView: View {
|
||||
if !vm.openPositions.isEmpty {
|
||||
Section("Open") {
|
||||
ForEach(vm.openPositions) { position in
|
||||
NavigationLink(destination: PositionDetailView(position: position, vm: vm)) {
|
||||
NavigationLink(destination: PositionDetailView(position: position, parentVM: vm)) {
|
||||
LoggedPositionRow(position: position)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,17 @@ import SwiftUI
|
||||
|
||||
struct PositionDetailView: View {
|
||||
let position: OptionPosition
|
||||
@ObservedObject var vm: PositionsViewModel
|
||||
/// Pass in from parent (OpenPositionsView) so close/roll updates the parent list.
|
||||
/// If nil, a local vm is used (e.g. when navigating from DashboardView).
|
||||
var parentVM: PositionsViewModel? = nil
|
||||
@StateObject private var localVM = PositionsViewModel()
|
||||
@State private var signals: SignalSnapshot? = nil
|
||||
@State private var isLoadingSignals = false
|
||||
@State private var showCloseConfirm = false
|
||||
@State private var showRollConfirm = false
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
init(position: OptionPosition, vm: PositionsViewModel = PositionsViewModel()) {
|
||||
self.position = position
|
||||
self.vm = vm
|
||||
}
|
||||
private var vm: PositionsViewModel { parentVM ?? localVM }
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
@@ -146,7 +146,7 @@ struct PositionDetailView: View {
|
||||
do {
|
||||
signals = try await APIClient.shared.request(
|
||||
.getSignals(position.ticker),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
} catch {
|
||||
// Non-critical — just don't show signals
|
||||
|
||||
@@ -15,7 +15,7 @@ final class AlertsViewModel: ObservableObject {
|
||||
do {
|
||||
alerts = try await APIClient.shared.request(
|
||||
.getAlerts(unreadOnly: unreadOnly),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
LocalStore.shared.unreadAlertCount = unreadCount
|
||||
} catch {
|
||||
@@ -28,7 +28,7 @@ final class AlertsViewModel: ObservableObject {
|
||||
do {
|
||||
let updated: AppAlert = try await APIClient.shared.request(
|
||||
.acknowledgeAlert(alert.id),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
if let idx = alerts.firstIndex(where: { $0.id == alert.id }) {
|
||||
alerts[idx] = updated
|
||||
|
||||
@@ -45,18 +45,18 @@ final class DashboardViewModel: ObservableObject {
|
||||
// ─── Private loaders ──────────────────────────────────────────────────────
|
||||
|
||||
private func loadStocks() async -> [PortfolioPosition] {
|
||||
(try? await APIClient.shared.request(.getPortfolio, body: Optional<String>.none)) ?? []
|
||||
(try? await APIClient.shared.request(.getPortfolio, body: nil)) ?? []
|
||||
}
|
||||
|
||||
private func loadOptions() async -> [OptionPosition] {
|
||||
(try? await APIClient.shared.request(.getPositions(status: "open"), body: Optional<String>.none)) ?? []
|
||||
(try? await APIClient.shared.request(.getPositions(status: "open"), body: nil)) ?? []
|
||||
}
|
||||
|
||||
private func loadRecommendations() async -> [Recommendation] {
|
||||
(try? await APIClient.shared.request(.getRecommendations(timeHorizon: nil), body: Optional<String>.none)) ?? []
|
||||
(try? await APIClient.shared.request(.getRecommendations(timeHorizon: nil), body: nil)) ?? []
|
||||
}
|
||||
|
||||
private func loadAlerts() async -> [AppAlert] {
|
||||
(try? await APIClient.shared.request(.getAlerts(unreadOnly: true), body: Optional<String>.none)) ?? []
|
||||
(try? await APIClient.shared.request(.getAlerts(unreadOnly: true), body: nil)) ?? []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ final class PortfolioViewModel: ObservableObject {
|
||||
isLoading = true
|
||||
error = nil
|
||||
do {
|
||||
positions = try await APIClient.shared.request(.getPortfolio, body: Optional<String>.none)
|
||||
positions = try await APIClient.shared.request(.getPortfolio, body: nil)
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
}
|
||||
@@ -58,7 +58,7 @@ final class PortfolioViewModel: ObservableObject {
|
||||
isLoading = true
|
||||
error = nil
|
||||
do {
|
||||
try await APIClient.shared.requestVoid(.deleteTicker(ticker), body: Optional<String>.none)
|
||||
try await APIClient.shared.requestVoid(.deleteTicker(ticker), body: nil)
|
||||
positions.removeAll { $0.ticker == ticker }
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
|
||||
@@ -16,7 +16,7 @@ final class PositionsViewModel: ObservableObject {
|
||||
do {
|
||||
positions = try await APIClient.shared.request(
|
||||
.getPositions(status: nil),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
|
||||
@@ -22,7 +22,7 @@ final class RecommendationsViewModel: ObservableObject {
|
||||
do {
|
||||
recommendations = try await APIClient.shared.request(
|
||||
.getRecommendations(timeHorizon: nil),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
@@ -36,7 +36,7 @@ final class RecommendationsViewModel: ObservableObject {
|
||||
do {
|
||||
recommendations = try await APIClient.shared.request(
|
||||
.refreshRecommendations,
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
@@ -48,7 +48,7 @@ final class RecommendationsViewModel: ObservableObject {
|
||||
do {
|
||||
return try await APIClient.shared.request(
|
||||
.getRecommendation(ticker: ticker, strategy: selectedStrategy, timeHorizon: selectedHorizon),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
|
||||
@@ -146,7 +146,7 @@ struct PositionDetailView: View {
|
||||
do {
|
||||
signals = try await APIClient.shared.request(
|
||||
.getSignals(position.ticker),
|
||||
body: Optional<String>.none
|
||||
body: nil
|
||||
)
|
||||
} catch {
|
||||
// Non-critical — just don't show signals
|
||||
|
||||
Reference in New Issue
Block a user