mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-03-14 22:22:41 +00:00
Progress flow
This commit is contained in:
parent
409680e9b8
commit
a705a71c45
10 changed files with 72 additions and 17 deletions
|
@ -5,6 +5,7 @@ import Observation
|
|||
import SafariServices
|
||||
import SwiftUI
|
||||
import AppAccount
|
||||
import WebKit
|
||||
|
||||
extension View {
|
||||
@MainActor func withSafariRouter() -> some View {
|
||||
|
@ -19,6 +20,7 @@ private struct SafariRouter: ViewModifier {
|
|||
@Environment(UserPreferences.self) private var preferences
|
||||
@Environment(RouterPath.self) private var routerPath
|
||||
@Environment(AppAccountsManager.self) private var appAccount
|
||||
@Environment(TipedUsers.self) private var tipedUsers
|
||||
|
||||
#if !os(visionOS)
|
||||
@State private var safariManager = InAppSafariManager()
|
||||
|
@ -34,8 +36,9 @@ private struct SafariRouter: ViewModifier {
|
|||
.onOpenURL { url in
|
||||
// Open external URL (from icecubesapp://)
|
||||
guard !isSecondaryColumn else { return }
|
||||
if url.lastPathComponent == "socialproxy" {
|
||||
if url.absoluteString == "icecubesapp://socialproxy" {
|
||||
safariManager.dismiss()
|
||||
TipedUsers.shared.tipedUserCount += 1
|
||||
return
|
||||
}
|
||||
let urlString = url.absoluteString.replacingOccurrences(of: AppInfo.scheme, with: "https://")
|
||||
|
@ -55,8 +58,8 @@ private struct SafariRouter: ViewModifier {
|
|||
}
|
||||
} else if url.host() == "social-proxy.com", let accountName = appAccount.currentAccount.accountName {
|
||||
let newURL = url.appending(queryItems: [
|
||||
.init(name: "callback", value: "icecubesapp"),
|
||||
.init(name: "id", value: accountName)
|
||||
.init(name: "callback", value: "icecubesapp://socialproxy"),
|
||||
.init(name: "id", value: "@\(accountName)")
|
||||
])
|
||||
return safariManager.open(newURL)
|
||||
}
|
||||
|
@ -116,6 +119,9 @@ private struct SafariRouter: ViewModifier {
|
|||
|
||||
func dismiss() {
|
||||
viewController.presentedViewController?.dismiss(animated: true)
|
||||
window?.resignKey()
|
||||
window?.isHidden = false
|
||||
window = nil
|
||||
}
|
||||
|
||||
func setupWindow(windowScene: UIWindowScene) -> UIWindow {
|
||||
|
|
|
@ -22,6 +22,7 @@ let package = Package(
|
|||
.package(name: "StatusKit", path: "../StatusKit"),
|
||||
.package(name: "Env", path: "../Env"),
|
||||
.package(url: "https://github.com/Dean151/ButtonKit", from: "0.1.1"),
|
||||
.package(url: "https://github.com/dkk/WrappingHStack", from: "2.2.11"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
|
@ -32,6 +33,7 @@ let package = Package(
|
|||
.product(name: "StatusKit", package: "StatusKit"),
|
||||
.product(name: "Env", package: "Env"),
|
||||
.product(name: "ButtonKit", package: "ButtonKit"),
|
||||
.product(name: "WrappingHStack", package: "WrappingHStack"),
|
||||
],
|
||||
swiftSettings: [
|
||||
.enableExperimentalFeature("StrictConcurrency"),
|
||||
|
|
|
@ -16,6 +16,7 @@ struct AccountDetailHeaderView: View {
|
|||
@Environment(QuickLook.self) private var quickLook
|
||||
@Environment(RouterPath.self) private var routerPath
|
||||
@Environment(CurrentAccount.self) private var currentAccount
|
||||
@Environment(TipedUsers.self) private var tipedUsers
|
||||
@Environment(\.redactionReasons) private var reasons
|
||||
@Environment(\.isSupporter) private var isSupporter: Bool
|
||||
|
||||
|
@ -45,6 +46,13 @@ struct AccountDetailHeaderView: View {
|
|||
}
|
||||
accountInfoView
|
||||
}
|
||||
.onChange(of: tipedUsers.tipedUserCount, { _, _ in
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
||||
Task {
|
||||
try? await viewModel.followButtonViewModel?.refreshRelationship()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private var headerImageView: some View {
|
||||
|
@ -211,20 +219,17 @@ struct AccountDetailHeaderView: View {
|
|||
.accessibilityRespondsToUserInteraction(false)
|
||||
movedToView
|
||||
joinedAtView
|
||||
tipView
|
||||
if viewModel.isProAccount {
|
||||
tipView
|
||||
}
|
||||
}
|
||||
.accessibilityElement(children: .contain)
|
||||
.accessibilitySortPriority(1)
|
||||
|
||||
Spacer()
|
||||
if let relationship = viewModel.relationship, !viewModel.isCurrentUser {
|
||||
if let followButtonViewModel = viewModel.followButtonViewModel, !viewModel.isCurrentUser {
|
||||
HStack {
|
||||
FollowButton(viewModel: .init(accountId: account.id,
|
||||
relationship: relationship,
|
||||
shouldDisplayNotify: true,
|
||||
relationshipUpdated: { relationship in
|
||||
viewModel.relationship = relationship
|
||||
}))
|
||||
FollowButton(viewModel: followButtonViewModel)
|
||||
}
|
||||
} else if !viewModel.isCurrentUser {
|
||||
ProgressView()
|
||||
|
@ -319,6 +324,9 @@ struct AccountDetailHeaderView: View {
|
|||
private var tipView: some View {
|
||||
Button {
|
||||
isTipSheetPresented = true
|
||||
Task {
|
||||
try? await viewModel.followButtonViewModel?.follow()
|
||||
}
|
||||
} label: {
|
||||
Text("$ Send tip")
|
||||
}
|
||||
|
|
|
@ -79,6 +79,12 @@ import SwiftUI
|
|||
|
||||
var translation: Translation?
|
||||
var isLoadingTranslation = false
|
||||
|
||||
var followButtonViewModel: FollowButtonViewModel?
|
||||
|
||||
var isProAccount: Bool {
|
||||
account?.url?.host() == "social-proxy.com"
|
||||
}
|
||||
|
||||
private(set) var account: Account?
|
||||
private var tabTask: Task<Void, Never>?
|
||||
|
@ -117,6 +123,14 @@ import SwiftUI
|
|||
featuredTags = data.featuredTags
|
||||
featuredTags.sort { $0.statusesCountInt > $1.statusesCountInt }
|
||||
relationship = data.relationships.first
|
||||
if let relationship {
|
||||
followButtonViewModel = .init(accountId: accountId,
|
||||
relationship: relationship,
|
||||
shouldDisplayNotify: true,
|
||||
relationshipUpdated: { [weak self] relationship in
|
||||
self?.relationship = relationship
|
||||
})
|
||||
}
|
||||
} catch {
|
||||
if let account {
|
||||
accountState = .data(account: account)
|
||||
|
|
|
@ -30,7 +30,8 @@ import SwiftUI
|
|||
func follow() async throws {
|
||||
guard let client else { return }
|
||||
do {
|
||||
relationship = try await client.post(endpoint: Accounts.follow(id: accountId, notify: false, reblogs: true))
|
||||
_ = try await client.post(endpoint: Accounts.follow(id: accountId, notify: false, reblogs: true))
|
||||
try await refreshRelationship()
|
||||
relationshipUpdated(relationship)
|
||||
} catch {
|
||||
throw error
|
||||
|
@ -40,12 +41,21 @@ import SwiftUI
|
|||
func unfollow() async throws {
|
||||
guard let client else { return }
|
||||
do {
|
||||
relationship = try await client.post(endpoint: Accounts.unfollow(id: accountId))
|
||||
_ = try await client.post(endpoint: Accounts.unfollow(id: accountId))
|
||||
try await refreshRelationship()
|
||||
relationshipUpdated(relationship)
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
func refreshRelationship() async throws {
|
||||
guard let client else { return }
|
||||
let relationships: [Relationship] = try await client.get(endpoint: Accounts.relationships(ids: [accountId]))
|
||||
if let relationship = relationships.first {
|
||||
self.relationship = relationship
|
||||
}
|
||||
}
|
||||
|
||||
func toggleNotify() async throws {
|
||||
guard let client else { return }
|
||||
|
@ -83,7 +93,7 @@ public struct FollowButton: View {
|
|||
public var body: some View {
|
||||
VStack(alignment: .trailing) {
|
||||
AsyncButton {
|
||||
if viewModel.relationship.following {
|
||||
if viewModel.relationship.following || viewModel.relationship.requested {
|
||||
try await viewModel.unfollow()
|
||||
} else {
|
||||
try await viewModel.follow()
|
||||
|
|
|
@ -3,6 +3,7 @@ import Models
|
|||
import Env
|
||||
import DesignSystem
|
||||
import WrappingHStack
|
||||
import AppAccount
|
||||
|
||||
@MainActor
|
||||
struct TipSheetView: View {
|
||||
|
@ -10,6 +11,8 @@ struct TipSheetView: View {
|
|||
@Environment(\.dismiss) private var dismiss
|
||||
@Environment(Theme.self) private var theme: Theme
|
||||
@Environment(TipedUsers.self) private var tipedUSers: TipedUsers
|
||||
@Environment(\.openURL) private var openURL
|
||||
@Environment(AppAccountsManager.self) private var appAccount: AppAccountsManager
|
||||
|
||||
@State private var selectedTip: String?
|
||||
|
||||
|
@ -122,5 +125,13 @@ struct TipSheetView: View {
|
|||
}
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
.onAppear {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
if let accountName = appAccount.currentAccount.accountName,
|
||||
let url = URL(string: "https://social-proxy.com/subscribe/to/\(account.username)?callback=icecubesapp://socialproxy&id=@\(accountName)") {
|
||||
openURL(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ let package = Package(
|
|||
.package(name: "Env", path: "../Env"),
|
||||
.package(url: "https://github.com/kean/Nuke", from: "12.4.0"),
|
||||
.package(url: "https://github.com/divadretlaw/EmojiText", from: "4.0.0"),
|
||||
.package(url: "https://github.com/dkk/WrappingHStack", from: "2.2.11"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
|
@ -32,7 +31,6 @@ let package = Package(
|
|||
.product(name: "NukeUI", package: "Nuke"),
|
||||
.product(name: "Nuke", package: "Nuke"),
|
||||
.product(name: "EmojiText", package: "EmojiText"),
|
||||
.product(name: "WrappingHStack", package: "WrappingHStack"),
|
||||
],
|
||||
swiftSettings: [
|
||||
.enableExperimentalFeature("StrictConcurrency"),
|
||||
|
|
|
@ -5,6 +5,8 @@ import Foundation
|
|||
public class TipedUsers {
|
||||
public var usersIds: [String] = []
|
||||
|
||||
public var tipedUserCount: Int = 0
|
||||
|
||||
static public let shared = TipedUsers()
|
||||
|
||||
private init() { }
|
||||
|
|
|
@ -70,6 +70,10 @@ public final class Account: Codable, Identifiable, Hashable, Sendable, Equatable
|
|||
public var haveHeader: Bool {
|
||||
header.lastPathComponent != "missing.png"
|
||||
}
|
||||
|
||||
public var fullAccountName: String {
|
||||
"\(acct)@\(url?.host() ?? "")"
|
||||
}
|
||||
|
||||
public init(id: String, username: String, displayName: String?, avatar: URL, header: URL, acct: String, note: HTMLString, createdAt: ServerDate, followersCount: Int, followingCount: Int, statusesCount: Int, lastStatusAt: String? = nil, fields: [Account.Field], locked: Bool, emojis: [Emoji], url: URL? = nil, source: Account.Source? = nil, bot: Bool, discoverable: Bool? = nil, moved: Account? = nil) {
|
||||
self.id = id
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Foundation
|
||||
|
||||
public struct Relationship: Codable {
|
||||
public struct Relationship: Codable, Equatable, Identifiable {
|
||||
public let id: String
|
||||
public let following: Bool
|
||||
public let showingReblogs: Bool
|
||||
|
|
Loading…
Reference in a new issue