Initial commit: suixinkan_ios UIKit rewrite project.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-26 14:33:31 +08:00
commit 9edf993432
297 changed files with 47151 additions and 0 deletions

View File

@ -0,0 +1,156 @@
//
// InviteModels.swift
// suixinkan
//
// Created by Codex on 2026/6/24.
//
import Foundation
///
struct InviteInfoResponse: Decodable, Equatable {
let enableInvite: Bool
let inviteCode: String
let inviteUrl: String
let description: [String]
/// 线
enum CodingKeys: String, CodingKey {
case enableInvite = "enable_invite"
case inviteCode = "invite_code"
case inviteUrl = "invite_url"
case description
}
///
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
enableInvite = try container.decodeInviteLossyBool(forKey: .enableInvite) ?? true
inviteCode = try container.decodeInviteLossyString(forKey: .inviteCode)
inviteUrl = try container.decodeInviteLossyString(forKey: .inviteUrl)
description = (try? container.decodeIfPresent([String].self, forKey: .description)) ?? []
}
}
///
struct InviteUserItem: Decodable, Identifiable, Hashable {
let id: Int
let realName: String
let phone: String
let avatar: String
let createdAt: String
let inviteLevel: Int
/// 线
enum CodingKeys: String, CodingKey {
case id
case realName = "real_name"
case phone
case avatar
case createdAt = "created_at"
case inviteLevel = "invite_level"
}
///
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeInviteLossyInt(forKey: .id) ?? 0
realName = try container.decodeInviteLossyString(forKey: .realName)
phone = try container.decodeInviteLossyString(forKey: .phone)
avatar = try container.decodeInviteLossyString(forKey: .avatar)
createdAt = try container.decodeInviteLossyString(forKey: .createdAt)
inviteLevel = try container.decodeInviteLossyInt(forKey: .inviteLevel) ?? 0
}
}
///
struct InviteDisplayRow: Identifiable, Equatable {
let id: String
let title: String
let subtitle: String
let amount: String
let time: String
let phone: String
let avatar: String
let inviteLevel: Int
///
var levelText: String {
inviteLevel == 1 ? "一级" : "二级"
}
///
var avatarPlaceholder: String {
if let first = title.first {
return String(first)
}
if let first = phone.first {
return String(first)
}
return "?"
}
}
///
enum InviteRecordTab: CaseIterable, Equatable {
case invite
case reward
///
var title: String {
switch self {
case .invite: return "邀请记录"
case .reward: return "奖励记录"
}
}
}
private extension KeyedDecodingContainer {
/// String Bool
func decodeInviteLossyString(forKey key: Key) throws -> String {
if let value = try? decodeIfPresent(String.self, forKey: key) {
return value
}
if let value = try? decodeIfPresent(Int.self, forKey: key) {
return String(value)
}
if let value = try? decodeIfPresent(Double.self, forKey: key) {
return String(value)
}
if let value = try? decodeIfPresent(Bool.self, forKey: key) {
return value ? "1" : "0"
}
return ""
}
/// StringDouble Int Int
func decodeInviteLossyInt(forKey key: Key) throws -> Int? {
if let value = try? decodeIfPresent(Int.self, forKey: key) {
return value
}
if let value = try? decodeIfPresent(Double.self, forKey: key) {
return Int(value)
}
if let value = try? decodeIfPresent(String.self, forKey: key) {
let text = value.trimmingCharacters(in: .whitespacesAndNewlines)
return Int(text) ?? Double(text).map(Int.init)
}
return nil
}
/// String Bool Bool
func decodeInviteLossyBool(forKey key: Key) throws -> Bool? {
if let value = try? decodeIfPresent(Bool.self, forKey: key) {
return value
}
if let value = try? decodeIfPresent(Int.self, forKey: key) {
return value != 0
}
if let value = try? decodeIfPresent(String.self, forKey: key) {
let text = value.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if ["1", "true", "yes"].contains(text) { return true }
if ["0", "false", "no"].contains(text) { return false }
}
return nil
}
}