Files
suixinkan_uikit/suixinkan/Features/Invite/ViewModels/InviteViewModels.swift

219 lines
7.1 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// InviteViewModels.swift
// suixinkan
//
import Foundation
import UIKit
/// ViewModel
final class PhotographerInviteViewModel {
private(set) var isLoading = false
private(set) var inviteCode = ""
private(set) var inviteUrl = ""
private(set) var rules: [String] = []
private(set) var qrImage: UIImage?
private(set) var errorMessage: String?
var onStateChange: (() -> Void)?
///
func reload(api: any InviteServing) async {
isLoading = true
errorMessage = nil
notifyStateChange()
do {
let response = try await api.inviteInfo()
inviteCode = response.inviteCode
inviteUrl = response.inviteUrl
rules = response.description
qrImage = QRCodeGenerator.generateStyledQRCode(
content: response.inviteUrl,
pixelSize: 560,
backgroundColor: .white,
cornerRadius: 0
)
} catch {
clear()
errorMessage = error.localizedDescription
}
isLoading = false
notifyStateChange()
}
///
func inviteCodeForCopy() -> String {
inviteCode
}
///
func inviteUrlForCopy() -> String {
inviteUrl
}
private func clear() {
inviteCode = ""
inviteUrl = ""
rules = []
qrImage = nil
}
private func notifyStateChange() {
onStateChange?()
}
}
/// ViewModel
final class InviteRecordViewModel {
private(set) var selectedTab: InviteRecordTab = .invite
private(set) var totalRewardText = "0.00"
private(set) var withdrawableText = "0.00"
private(set) var inviteRows: [InviteDisplayRow] = []
private(set) var rewardRows: [WalletTransactionItem] = []
private(set) var isInviteRefreshing = false
private(set) var isRewardRefreshing = false
private(set) var canLoadMoreInvite = false
private(set) var canLoadMoreReward = false
private(set) var errorMessage: String?
var onStateChange: (() -> Void)?
private var invitePage = 1
private let invitePageSize = 20
private var rewardPage = 1
private let rewardPageSize = 10
private var isLoadingInvite = false
private var isLoadingReward = false
///
func loadInitial(inviteAPI: any InviteServing, walletAPI: any WalletServing) async {
await refreshInvite(inviteAPI: inviteAPI, walletAPI: walletAPI)
}
///
func selectTab(_ tab: InviteRecordTab, inviteAPI: any InviteServing, walletAPI: any WalletServing) async {
guard tab != selectedTab else { return }
selectedTab = tab
notifyStateChange()
if tab == .reward, rewardRows.isEmpty {
await refreshReward(walletAPI: walletAPI)
}
}
///
func refreshInvite(inviteAPI: any InviteServing, walletAPI: any WalletServing) async {
await loadSummary(walletAPI: walletAPI)
await loadInviteRows(inviteAPI: inviteAPI, refresh: true)
}
///
func loadMoreInvite(inviteAPI: any InviteServing) async {
guard canLoadMoreInvite, !isInviteRefreshing else { return }
await loadInviteRows(inviteAPI: inviteAPI, refresh: false)
}
///
func refreshReward(walletAPI: any WalletServing) async {
await loadSummary(walletAPI: walletAPI)
await loadRewardRows(walletAPI: walletAPI, refresh: true)
}
///
func loadMoreReward(walletAPI: any WalletServing) async {
guard canLoadMoreReward, !isRewardRefreshing else { return }
await loadRewardRows(walletAPI: walletAPI, refresh: false)
}
private func loadSummary(walletAPI: any WalletServing) async {
do {
let summary = try await walletAPI.walletSummary(type: 2)
totalRewardText = summary.amountTotal.isEmpty ? "0.00" : summary.amountTotal
withdrawableText = summary.amountWithdrawable.isEmpty ? "0.00" : summary.amountWithdrawable
} catch {
errorMessage = error.localizedDescription
}
notifyStateChange()
}
private func loadInviteRows(inviteAPI: any InviteServing, refresh: Bool) async {
if isLoadingInvite && !refresh { return }
if refresh { invitePage = 1 }
isLoadingInvite = true
isInviteRefreshing = refresh
errorMessage = nil
notifyStateChange()
do {
let users = try await inviteAPI.inviteUserList(page: invitePage, pageSize: invitePageSize)
let mapped = users.map { user in
InviteDisplayRow(
id: "invite_\(user.id)",
title: user.realName.isEmpty ? "**\(user.phone.suffix(4))" : user.realName,
phone: user.phone,
avatar: user.avatar,
time: user.createdAt,
inviteLevel: user.inviteLevel
)
}
inviteRows = refresh ? mapped : inviteRows + mapped
invitePage += 1
canLoadMoreInvite = users.count >= invitePageSize
} catch {
if refresh {
inviteRows = []
canLoadMoreInvite = false
}
errorMessage = error.localizedDescription
}
isLoadingInvite = false
isInviteRefreshing = false
notifyStateChange()
}
private func loadRewardRows(walletAPI: any WalletServing, refresh: Bool) async {
if isLoadingReward && !refresh { return }
if refresh { rewardPage = 1 }
isLoadingReward = true
isRewardRefreshing = refresh
errorMessage = nil
notifyStateChange()
do {
let response = try await walletAPI.walletTransactionList(
startDate: "2025-01-01",
endDate: Self.dayFormatter.string(from: Date()),
page: rewardPage,
pageSize: rewardPageSize,
type: 2
)
rewardRows = refresh ? response.list : rewardRows + response.list
rewardPage += 1
canLoadMoreReward = response.list.count >= rewardPageSize && rewardRows.count < response.total
} catch {
if refresh {
rewardRows = []
canLoadMoreReward = false
}
errorMessage = error.localizedDescription
}
isLoadingReward = false
isRewardRefreshing = false
notifyStateChange()
}
private func notifyStateChange() {
onStateChange?()
}
private static let dayFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "zh_CN")
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
}