From dc85557d4096fb8bd3561c1ae0da404c6707ecd2 Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Fri, 16 Aug 2024 07:24:19 +0200 Subject: [PATCH 1/3] Tweak to notifications policy --- .../NotificationsPolicyView.swift | 50 ++++++++----------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/Packages/Notifications/Sources/Notifications/NotificationsPolicyView.swift b/Packages/Notifications/Sources/Notifications/NotificationsPolicyView.swift index f9ca29047..fe0749f06 100644 --- a/Packages/Notifications/Sources/Notifications/NotificationsPolicyView.swift +++ b/Packages/Notifications/Sources/Notifications/NotificationsPolicyView.swift @@ -25,12 +25,8 @@ struct NotificationsPolicyView: View { })) { pickerMenu } label: { - VStack(alignment: .leading) { - Text("notifications.content-filter.peopleYouDontFollow") - Text("Until you manually approve them") - .foregroundStyle(.secondary) - .font(.footnote) - } + makePickerLabel(title: "notifications.content-filter.peopleYouDontFollow", + subtitle: "Until you manually approve them") } Picker(selection: .init(get: { @@ -41,12 +37,8 @@ struct NotificationsPolicyView: View { })) { pickerMenu } label: { - VStack(alignment: .leading) { - Text("notifications.content-filter.peopleNotFollowingYou") - Text("And following you for less than 3 days") - .foregroundStyle(.secondary) - .font(.footnote) - } + makePickerLabel(title: "notifications.content-filter.peopleNotFollowingYou", + subtitle: "And following you for less than 3 days") } Picker(selection: .init(get: { @@ -57,12 +49,8 @@ struct NotificationsPolicyView: View { })) { pickerMenu } label: { - VStack(alignment: .leading) { - Text("notifications.content-filter.newAccounts") - Text("Created within the past 30 days") - .foregroundStyle(.secondary) - .font(.footnote) - } + makePickerLabel(title: "notifications.content-filter.newAccounts", + subtitle: "Created within the past 30 days") } Picker(selection: .init(get: { @@ -73,12 +61,8 @@ struct NotificationsPolicyView: View { })) { pickerMenu } label: { - VStack(alignment: .leading) { - Text("notifications.content-filter.privateMentions") - Text("Unless it's in reply to your own mention or if you follow the sender") - .foregroundStyle(.secondary) - .font(.footnote) - } + makePickerLabel(title: "notifications.content-filter.privateMentions", + subtitle: "Unless it's in reply to your own mention or if you follow the sender") } Picker(selection: .init(get: { @@ -90,10 +74,8 @@ struct NotificationsPolicyView: View { pickerMenu } label: { VStack(alignment: .leading) { - Text("Moderated accounts") - Text("Limited by server moderators") - .foregroundStyle(.secondary) - .font(.footnote) + makePickerLabel(title: "Moderated accounts", + subtitle: "Limited by server moderators") } } } @@ -112,7 +94,7 @@ struct NotificationsPolicyView: View { } .redacted(reason: policy == nil ? .placeholder : []) } - .presentationDetents([.medium]) + .presentationDetents([.height(500)]) .presentationBackground(.thinMaterial) } @@ -121,6 +103,16 @@ struct NotificationsPolicyView: View { Text(policy.rawValue.capitalized) } } + + private func makePickerLabel(title: LocalizedStringKey, subtitle: LocalizedStringKey) -> some View { + VStack(alignment: .leading) { + Text(title) + .font(.callout) + Text(subtitle) + .foregroundStyle(.secondary) + .font(.footnote) + } + } private func getPolicy() async { defer { From f80fca91e29a93f9e70ccf0a10c47de8d350859d Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Tue, 20 Aug 2024 09:32:33 +0200 Subject: [PATCH 2/3] Add TelemetryDeck about --- IceCubesApp/App/Tabs/Settings/AboutView.swift | 17 +++++++++++++---- .../Localization/Localizable.xcstrings | 9 +++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/IceCubesApp/App/Tabs/Settings/AboutView.swift b/IceCubesApp/App/Tabs/Settings/AboutView.swift index e75e8461f..2ced0f599 100644 --- a/IceCubesApp/App/Tabs/Settings/AboutView.swift +++ b/IceCubesApp/App/Tabs/Settings/AboutView.swift @@ -30,19 +30,19 @@ struct AboutView: View { #if !targetEnvironment(macCatalyst) && !os(visionOS) HStack { Spacer() - Image(uiImage: .init(named: "AppIconAlternate0")!) + Image(uiImage: .init(named: "AppIconAlternate0") ?? .init()) .resizable() .frame(width: 50, height: 50) .cornerRadius(4) - Image(uiImage: .init(named: "AppIconAlternate4")!) + Image(uiImage: .init(named: "AppIconAlternate4") ?? .init()) .resizable() .frame(width: 50, height: 50) .cornerRadius(4) - Image(uiImage: .init(named: "AppIconAlternate17")!) + Image(uiImage: .init(named: "AppIconAlternate17") ?? .init()) .resizable() .frame(width: 50, height: 50) .cornerRadius(4) - Image(uiImage: .init(named: "AppIconAlternate23")!) + Image(uiImage: .init(named: "AppIconAlternate23") ?? .init()) .resizable() .frame(width: 50, height: 50) .cornerRadius(4) @@ -64,6 +64,15 @@ struct AboutView: View { #endif followAccountsSection + + Section("Telemetry") { + Link(destination: .init(string: "https://telemetrydeck.com")!) { + Label("Telemetry by TelemtryDeck", systemImage: "link") + } + Link(destination: .init(string: "https://telemetrydeck.com/privacy/")!) { + Label("Privacy Policy", systemImage: "checkmark.shield") + } + } Section { Text(""" diff --git a/IceCubesApp/Resources/Localization/Localizable.xcstrings b/IceCubesApp/Resources/Localization/Localizable.xcstrings index 40aea4160..fe0e5fa26 100644 --- a/IceCubesApp/Resources/Localization/Localizable.xcstrings +++ b/IceCubesApp/Resources/Localization/Localizable.xcstrings @@ -41802,6 +41802,9 @@ } } } + }, + "Privacy Policy" : { + }, "Private" : { "localizations" : { @@ -78620,6 +78623,12 @@ } } } + }, + "Telemetry" : { + + }, + "Telemetry by TelemtryDeck" : { + }, "The DeepL API Key is still stored!" : { "extractionState" : "manual", From e0eed97bcff82511269f32ab4af5cc391eacffa4 Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Wed, 21 Aug 2024 18:22:38 +0200 Subject: [PATCH 3/3] Direct subscribe to sub.club --- .../Account/AccountDetailHeaderView.swift | 29 +++++++++++++++---- .../Account/AccountDetailViewModel.swift | 11 +++++++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Packages/Account/Sources/Account/AccountDetailHeaderView.swift b/Packages/Account/Sources/Account/AccountDetailHeaderView.swift index e1cba1617..d64167ac4 100644 --- a/Packages/Account/Sources/Account/AccountDetailHeaderView.swift +++ b/Packages/Account/Sources/Account/AccountDetailHeaderView.swift @@ -4,21 +4,25 @@ import Env import Models import NukeUI import SwiftUI +import AppAccount @MainActor struct AccountDetailHeaderView: View { enum Constants { static let headerHeight: CGFloat = 200 } - + @Environment(\.openWindow) private var openWindow @Environment(Theme.self) private var theme @Environment(QuickLook.self) private var quickLook @Environment(RouterPath.self) private var routerPath @Environment(CurrentAccount.self) private var currentAccount @Environment(StreamWatcher.self) private var watcher + @Environment(AppAccountsManager.self) private var appAccount @Environment(\.redactionReasons) private var reasons @Environment(\.isSupporter) private var isSupporter: Bool + @Environment(\.openURL) private var openURL + @Environment(\.colorScheme) private var colorScheme var viewModel: AccountDetailViewModel let account: Account @@ -241,7 +245,7 @@ struct AccountDetailHeaderView: View { movedToView joinedAtView if viewModel.account?.isPremiumAccount == true && viewModel.relationship?.following == false || viewModel.account?.isLinkedToPremiumAccount == true && viewModel.premiumRelationship?.following == false { - tipView + subscribeButton } } .accessibilityElement(children: .contain) @@ -342,18 +346,31 @@ struct AccountDetailHeaderView: View { } @ViewBuilder - private var tipView: some View { + private var subscribeButton: some View { Button { - isTipSheetPresented = true - shouldListenToPremiumTimer = true + if let subscription = viewModel.subClubUser?.subscription, + let accountName = appAccount.currentAccount.accountName, + let premiumUsername = account.premiumUsername, + let url = URL(string: "https://\(AppInfo.premiumInstance)/@\(premiumUsername)/subscribe?callback=icecubesapp://subclub&id=@\(accountName)&amount=\(subscription.unitAmount)¤cy=\(subscription.currency)&theme=\(colorScheme)") { + openURL(url) + } else { + isTipSheetPresented = true + shouldListenToPremiumTimer = true + } + Task { if viewModel.account?.isLinkedToPremiumAccount == true { try? await viewModel.followPremiumAccount() } try? await viewModel.followButtonViewModel?.follow() } + } label: { - Text("$ Subscribe") + if let subscription = viewModel.subClubUser?.subscription { + Text("Subscribe \(subscription.formattedAmount) / month") + } else { + Text("$ Subscribe") + } } .buttonStyle(.bordered) .padding(.top, 8) diff --git a/Packages/Account/Sources/Account/AccountDetailViewModel.swift b/Packages/Account/Sources/Account/AccountDetailViewModel.swift index 41695c8e2..d77584cd6 100644 --- a/Packages/Account/Sources/Account/AccountDetailViewModel.swift +++ b/Packages/Account/Sources/Account/AccountDetailViewModel.swift @@ -79,8 +79,11 @@ import SwiftUI var fields: [Account.Field] = [] var familiarFollowers: [Account] = [] + // Sub.club stuff var premiumAccount: Account? var premiumRelationship: Relationship? + var subClubUser: SubClubUser? + private let subClubClient = SubClubClient() var selectedTab = Tab.statuses { didSet { @@ -333,9 +336,12 @@ extension AccountDetailViewModel { forceVersion: .v2) if let premiumAccount = results?.accounts.first { self.premiumAccount = premiumAccount + await fetchSubClubAccount(premiumUsername: premiumAccount.username) let relationships: [Relationship] = try await client.get(endpoint: Accounts.relationships(ids: [premiumAccount.id])) self.premiumRelationship = relationships.first } + } else if fromAccount.isPremiumAccount { + await fetchSubClubAccount(premiumUsername: fromAccount.username) } } @@ -346,4 +352,9 @@ extension AccountDetailViewModel { reblogs: true)) } } + + private func fetchSubClubAccount(premiumUsername: String) async { + let user = await subClubClient.getUser(username: premiumUsername) + subClubUser = user + } }