438 lines
17 KiB
Swift
438 lines
17 KiB
Swift
|
|
//
|
|||
|
|
// PhotoBrowserControllerExtRole.swift
|
|||
|
|
// Crush
|
|||
|
|
//
|
|||
|
|
// Created by Leon on 2025/7/27.
|
|||
|
|
//
|
|||
|
|
|
|||
|
|
extension PhotoBrowserController {
|
|||
|
|
// MARK: - 🚩My Role
|
|||
|
|
|
|||
|
|
func createOperateViewOfRoleMine() {
|
|||
|
|
bottomGradientContainer?.isHidden = false
|
|||
|
|
|
|||
|
|
rolePhotoUnlockEntry = {
|
|||
|
|
let v = RolePhotoUnlockEntryView()
|
|||
|
|
bottomGradientOperateStackV.addArrangedSubview(v)
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
setDefaultEntry = {
|
|||
|
|
let v = RolePhotoSetDefaultEntryView()
|
|||
|
|
bottomGradientOperateStackV.addArrangedSubview(v)
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
moreButton = {
|
|||
|
|
let v = EPIconGhostButton(radius: .none, iconSize: .medium, iconCode: .more)
|
|||
|
|
v.addTarget(self, action: #selector(tapNaviMoreInMyAIAlbum(sender:)), for: .touchUpInside)
|
|||
|
|
titleView.rightStackH.addArrangedSubview(v)
|
|||
|
|
titleView.paddingRightForRightStack = 16
|
|||
|
|
v.snp.makeConstraints { make in
|
|||
|
|
make.size.equalTo(v.bgImageSize())
|
|||
|
|
}
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
setupRoleEvents()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func setupRoleEvents() {
|
|||
|
|
rolePhotoUnlockEntry.editUnlockWayAction = { [weak self] in
|
|||
|
|
self?.tapToSetupUnlockWay()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setDefaultEntry.setButton.addTarget(self, action: #selector(tapSetRoleDefaultButton), for: .touchUpInside)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: Action
|
|||
|
|
|
|||
|
|
func tapToSetupUnlockWay() {
|
|||
|
|
let vc = RolePhotoUnlockWaySetController()
|
|||
|
|
// 获取当前item
|
|||
|
|
let imageModel = imageModels[currentIndex]
|
|||
|
|
|
|||
|
|
vc.browseModel = imageModel
|
|||
|
|
vc.priceUpdateAction = { [weak self] price in
|
|||
|
|
let unlockPrice = price ?? 0
|
|||
|
|
imageModel.aiAlbum.unlockPrice = unlockPrice
|
|||
|
|
if unlockPrice > 0 {
|
|||
|
|
imageModel.aiAlbum.isDefault = false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
self?.reloadStatesByModel(model: imageModel)
|
|||
|
|
}
|
|||
|
|
navigationController?.pushViewController(vc, animated: true)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@objc func tapNaviMoreInMyAIAlbum(sender: UIButton) {
|
|||
|
|
let pop = CLPopoverListView()
|
|||
|
|
let rect = view.convert(sender.frame, from: sender.superview)
|
|||
|
|
pop.setupDeletePopover(rect.insetBy(dx: 0.0, dy: -6.0), inView: view) { [weak self] in
|
|||
|
|
self?.deleteAlbumOfMyAIRoleTapAction()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@objc private func tapSetRoleDefaultButton() {
|
|||
|
|
let imageModel = imageModels[currentIndex]
|
|||
|
|
let unlockPrice = imageModel.aiAlbum.unlockPrice
|
|||
|
|
|
|||
|
|
if unlockPrice > 0{
|
|||
|
|
let alert = Alert(title: "默认图片", text: "设置为默认图片后,图片的解锁方式只能为“免费”")
|
|||
|
|
let action1 = AlertAction(title: "Confirm", actionStyle: .confirm) {[weak self] in
|
|||
|
|
self?.doRequestSetRoleDefaultAlbum()
|
|||
|
|
}
|
|||
|
|
let action2 = AlertAction(title: "Cancel", actionStyle: .cancel)
|
|||
|
|
alert.addAction(action1)
|
|||
|
|
alert.addAction(action2)
|
|||
|
|
alert.show()
|
|||
|
|
}else{
|
|||
|
|
doRequestSetRoleDefaultAlbum()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: Functions
|
|||
|
|
private func doRequestSetRoleDefaultAlbum(){
|
|||
|
|
let imageModel = imageModels[currentIndex]
|
|||
|
|
|
|||
|
|
let aiUid = imageModel.aiId
|
|||
|
|
let albumId = imageModel.aiAlbum.albumId
|
|||
|
|
|
|||
|
|
Hud.showIndicator()
|
|||
|
|
AIRoleProvider.request(.aiRolePhotoDefaultSet(aiUid: aiUid, albumId: albumId), modelType: AnyCodable.self) { [weak self] result in
|
|||
|
|
Hud.hideIndicator()
|
|||
|
|
switch result {
|
|||
|
|
case .success:
|
|||
|
|
// dlog("set default results")
|
|||
|
|
imageModel.aiAlbum.isDefault = true
|
|||
|
|
self?.reloadStatesByModel(model: imageModel)
|
|||
|
|
self?.setDefaultEntry.setupIsDefault(true)
|
|||
|
|
NotificationCenter.post(name: .aiRoleAlbumPhotoInfoChanged)
|
|||
|
|
NotificationCenter.post(name: .aiRoleInfoChanged) // 主页背景要更新
|
|||
|
|
case .failure:
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@objc func deleteAlbumOfMyAIRoleTapAction() {
|
|||
|
|
guard currentIndex >= 0, currentIndex < imageModels.count else { return }
|
|||
|
|
|
|||
|
|
let model = imageModels[currentIndex]
|
|||
|
|
if model.aiAlbum.isDefault.boolValue{
|
|||
|
|
let alert = Alert(title: "删除图片", text: "不可删除封面默认图片,该图片会作为在个人主页头图,卡片主图,聊天背景")
|
|||
|
|
let action1 = AlertAction(title: "Got it", actionStyle: .confirm)
|
|||
|
|
alert .addAction(action1)
|
|||
|
|
alert.show()
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
let alert = Alert(title: "删除图片", text: "图片删除后不可恢复。已经付费解锁过该图片的用户依然可以在角色的相册中看到该图片。")
|
|||
|
|
let action1 = AlertAction(title: "Delete", actionStyle: .destructive) {[weak self] in
|
|||
|
|
self?.deleteTapActionDone()
|
|||
|
|
}
|
|||
|
|
let action2 = AlertAction(title: "Cancel", actionStyle: .cancel)
|
|||
|
|
|
|||
|
|
alert.addAction(action1)
|
|||
|
|
alert.addAction(action2)
|
|||
|
|
alert.show()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private func deleteTapActionDone() {
|
|||
|
|
let model = imageModels[currentIndex]
|
|||
|
|
model.deleteTapBlock?(model) { [weak self] isSuccess in
|
|||
|
|
guard let self = self else { return }
|
|||
|
|
if isSuccess {
|
|||
|
|
self.imageModels.remove(at: self.currentIndex)
|
|||
|
|
if self.imageModels.isEmpty {
|
|||
|
|
PhotoBrowserManager.shared.hidePhotoBrowser()
|
|||
|
|
} else {
|
|||
|
|
if self.currentIndex >= self.imageModels.count {
|
|||
|
|
self.currentIndex -= 1
|
|||
|
|
}
|
|||
|
|
self.setupViews()
|
|||
|
|
self.reloadCountLabel(hidden: false)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: - 🚩Other's Role
|
|||
|
|
|
|||
|
|
func createOperateViewOfOthers() {
|
|||
|
|
roleOthersContainer = {
|
|||
|
|
let v = SelectiveDeliveryEventsView()
|
|||
|
|
v.backgroundColor = .clear
|
|||
|
|
view.insertSubview(v, belowSubview: titleView)
|
|||
|
|
v.snp.makeConstraints { make in
|
|||
|
|
make.edges.equalToSuperview()
|
|||
|
|
}
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
// roleOthersContainer?.isUserInteractionEnabled = false
|
|||
|
|
|
|||
|
|
roleOthersCenterLock = {
|
|||
|
|
let v = UIImageView()
|
|||
|
|
v.image = MWIconFont.image(fromIcon: .iconPrivate, size: CGSize(width: 40, height: 40), color: .white)
|
|||
|
|
roleOthersContainer?.addSubview(v)
|
|||
|
|
v.snp.makeConstraints { make in
|
|||
|
|
make.center.equalToSuperview()
|
|||
|
|
}
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
let bottomStackH = {
|
|||
|
|
let v = UIStackView()
|
|||
|
|
v.spacing = 48
|
|||
|
|
v.alignment = .center
|
|||
|
|
roleOthersContainer?.addSubview(v)
|
|||
|
|
v.snp.makeConstraints { make in
|
|||
|
|
make.height.equalTo(48)
|
|||
|
|
make.bottom.equalToSuperview().offset(-16 - UIWindow.safeAreaBottom * 0.5)
|
|||
|
|
make.trailing.equalToSuperview().offset(-24)
|
|||
|
|
}
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
iconUnlockButton = {
|
|||
|
|
let v = StyleButton()
|
|||
|
|
v.setContentHuggingPriority(UILayoutPriority(rawValue: 246), for: .horizontal)
|
|||
|
|
v.primary(size: .large)
|
|||
|
|
v.addTarget(self, action: #selector(tapUnlockPhoto), for: .touchUpInside)
|
|||
|
|
bottomStackH.addArrangedSubview(v)
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
iconLabel = {
|
|||
|
|
let v = CLIconLabel()
|
|||
|
|
v.iconImageView.image = UIImage.icon32Diamond
|
|||
|
|
v.iconSize = CGSize(width: 20, height: 20)
|
|||
|
|
roleOthersContainer?.addSubview(v)
|
|||
|
|
v.snp.makeConstraints { make in
|
|||
|
|
make.centerY.equalTo(bottomStackH)
|
|||
|
|
make.leading.equalToSuperview().offset(24)
|
|||
|
|
make.trailing.lessThanOrEqualTo(bottomStackH.snp.leading).offset(-8)
|
|||
|
|
}
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
iconLabel?.contentLabel.text = "1234"
|
|||
|
|
let attributeString = StyleButton.getUnlockAttributeTitleByCoin(coin: 123, string: "unlock")
|
|||
|
|
iconUnlockButton?.setAttributedTitle(attributeString, for: .normal)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@objc func tapUnlockPhoto() {
|
|||
|
|
guard UserCore.shared.checkUserLoginIfNotPushUserToLogin() else{
|
|||
|
|
PhotoBrowserManager.shared.hidePhotoBrowser()
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let photoModel = imageModels[currentIndex]
|
|||
|
|
|
|||
|
|
var params = [String: Any]()
|
|||
|
|
if let album = photoModel.aiAlbum {
|
|||
|
|
if let aiId = photoModel.aiId {
|
|||
|
|
params.updateValue(aiId, forKey: "aiId")
|
|||
|
|
}
|
|||
|
|
let albumId = album.albumId
|
|||
|
|
params.updateValue(albumId, forKey: "albumId")
|
|||
|
|
|
|||
|
|
} else if let model = photoModel.sessionModel {
|
|||
|
|
if let aiId = photoModel.aiId {
|
|||
|
|
params.updateValue(aiId, forKey: "aiId")
|
|||
|
|
}
|
|||
|
|
if let albumId = model.baseRemoteInfo?.customAttachment?.albumId {
|
|||
|
|
params.updateValue(albumId, forKey: "albumId")
|
|||
|
|
}
|
|||
|
|
if let messageServerId = model.v2msg?.messageServerId {
|
|||
|
|
params.updateValue(messageServerId, forKey: "messageServerId")
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试解锁
|
|||
|
|
let imgTest = "https://hhb.crushlevel.ai/dev/role/17581021489486439.jpg"
|
|||
|
|
// if var album = photoModel.aiAlbum{
|
|||
|
|
//
|
|||
|
|
// album.lockStatus = .unlock
|
|||
|
|
// album.imgUrl = nil
|
|||
|
|
// album.img1 = "https://sub.crushlevel.ai/files/b/test/439076604280833/0aec65fdd92c404a9e3f8acac8e2c1ba.jpg?x-oss-process=image/resize,w_468,h_600&v=1&Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9zdWIuY3J1c2hsZXZlbC5haS9maWxlcy9iL3Rlc3QvNDM5MDc2NjA0MjgwODMzLzBhZWM2NWZkZDkyYzQwNGE5ZTNmOGFjYWM4ZTJjMWJhLmpwZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSx3XzQ2OCxoXzYwMCZ2PTEiLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE3NTgyMjgzNjd9fX1dfQ__&Signature=Jv5jE4d072OkFyYq5dxa3unXVaLWSNRddJEIIm42j4zmg36Yq8HGxVXz4X954ERmujm8zCluiVGMbIx-EH9JlQ1s~zbhgOo-lliaDGl977EsCVLBPsf639WFpdCXqnf3QAM7LwhuCbmdi~PBybJhKS31nEKoS53idOB4JyEXXp9wv3RpVjDoL4JF8C22H8k5gJ0hpt3NhfZiTSbsSRJBApNHfCKAFm6PEKQ8dAQ6f7rRxHwPTkbhHi~fRUahuJI10Ti-8t2Hem4akTV4plmgz9chsLCfHBNh5WDrwzoCZRDDljpaNcwpkZ5Mew23seKphb5iLxHgVP3WGAwXb0BoRA__&Key-Pair-Id=K35ZQ246Y37QV8"
|
|||
|
|
// photoModel.imageUrl = album.img1
|
|||
|
|
// album.unlockPrice = 0
|
|||
|
|
// photoModel.aiAlbum = album
|
|||
|
|
// self.reloadStates(index: self.currentIndex)
|
|||
|
|
// self.reloadCurrentZoomImage()
|
|||
|
|
// }
|
|||
|
|
// return
|
|||
|
|
|
|||
|
|
// #warning("test")
|
|||
|
|
// if let model = photoModel.sessionModel {
|
|||
|
|
// Hud.hideInidcator()
|
|||
|
|
// model.baseRemoteInfo?.customAttachment?.unlockPrice = 0
|
|||
|
|
// model.baseRemoteInfo?.customAttachment?.url = imgTest
|
|||
|
|
//
|
|||
|
|
// photoModel.imageUrl = imgTest
|
|||
|
|
// photoModel.sessionModel = model
|
|||
|
|
//
|
|||
|
|
// // Reload
|
|||
|
|
// self.reloadStates(index: self.currentIndex)
|
|||
|
|
// self.reloadCurrentZoomImage()
|
|||
|
|
// }
|
|||
|
|
// return
|
|||
|
|
|
|||
|
|
Hud.showIndicator()
|
|||
|
|
ChatProvider.request(.aiUnlockAlbumImg(params: params), modelType: AIAlbumUnlockImages.self) { [weak self] result in
|
|||
|
|
Hud.hideIndicator()
|
|||
|
|
switch result {
|
|||
|
|
case let .success(unlockData):
|
|||
|
|
guard let img1 = unlockData?.img1 else {
|
|||
|
|
PhotoBrowserManager.shared.hidePhotoBrowser()
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 🚩"1.发送通知、2.更新当前大图UI"
|
|||
|
|
|
|||
|
|
// 更新临时数据
|
|||
|
|
guard let self = self else { return }
|
|||
|
|
if let album = photoModel.aiAlbum {
|
|||
|
|
album.lockStatus = .unlock
|
|||
|
|
album.img1 = img1
|
|||
|
|
album.imgUrl = img1
|
|||
|
|
album.unlockPrice = 0
|
|||
|
|
|
|||
|
|
photoModel.imageUrl = album.img1
|
|||
|
|
photoModel.aiAlbum = album
|
|||
|
|
|
|||
|
|
// Reload
|
|||
|
|
self.reloadStates(index: self.currentIndex)
|
|||
|
|
self.reloadCurrentZoomImage()
|
|||
|
|
|
|||
|
|
NotificationCenter.post(name: .aiRoleAlbumPhotoInfoChanged, object: album)
|
|||
|
|
}else if let model = photoModel.sessionModel {
|
|||
|
|
model.baseRemoteInfo?.customAttachment?.unlockPrice = 0
|
|||
|
|
model.baseRemoteInfo?.customAttachment?.url = img1
|
|||
|
|
|
|||
|
|
photoModel.imageUrl = img1
|
|||
|
|
photoModel.sessionModel = model
|
|||
|
|
|
|||
|
|
// Reload
|
|||
|
|
self.reloadStates(index: self.currentIndex)
|
|||
|
|
self.reloadCurrentZoomImage()
|
|||
|
|
|
|||
|
|
NotificationCenter.post(name: .aiRoleAlbumPhotoInfoChanged, object: model)
|
|||
|
|
}else{
|
|||
|
|
assert(false, "need update")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
WalletCore.shared.refreshWallet()
|
|||
|
|
|
|||
|
|
case .failure:
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@objc func tapOperateChipButton(_ sender: EPChipContrastButton) {
|
|||
|
|
guard UserCore.shared.checkUserLoginIfNotPushUserToLogin() else{
|
|||
|
|
PhotoBrowserManager.shared.hidePhotoBrowser()
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@objc func tapLikeButton() {
|
|||
|
|
guard UserCore.shared.checkUserLoginIfNotPushUserToLogin() else{
|
|||
|
|
PhotoBrowserManager.shared.hidePhotoBrowser()
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let photoModel = imageModels[currentIndex]
|
|||
|
|
guard let likeView = likeView else { return }
|
|||
|
|
// 在主页、IM中,这里是 点赞
|
|||
|
|
|
|||
|
|
if let album = photoModel.aiAlbum {
|
|||
|
|
let albumId = album.albumId
|
|||
|
|
|
|||
|
|
if album.likedStatus == .liked {
|
|||
|
|
// 取消点赞
|
|||
|
|
album.likedStatus = .cancel
|
|||
|
|
album.likedCount = max((album.likedCount ?? 0) - 1, 0)
|
|||
|
|
PhotosViewModel.shared.album = album
|
|||
|
|
likeView.bind(aiAlbum: album)
|
|||
|
|
AIRoleProvider.request(.aiRolePhotoLikeOrNo(albumId: albumId, likedStatus: .cancel), modelType: EmptyModel.self) { [weak self] result in
|
|||
|
|
self?.handleLikeRequestResult(result: result, albumId: albumId, isLike: false)
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 点赞
|
|||
|
|
likeView.playLotteLike { _ in
|
|||
|
|
guard var album = photoModel.aiAlbum else { return }
|
|||
|
|
album.likedStatus = .liked
|
|||
|
|
album.likedCount = (album.likedCount ?? 0) + 1
|
|||
|
|
PhotosViewModel.shared.album = album
|
|||
|
|
likeView.bind(aiAlbum: album)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
AIRoleProvider.request(.aiRolePhotoLikeOrNo(albumId: albumId, likedStatus: .liked), modelType: EmptyModel.self) { [weak self] result in
|
|||
|
|
self?.handleLikeRequestResult(result: result, albumId: albumId, isLike: true)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 统一处理请求结果
|
|||
|
|
private func handleLikeRequestResult(result: Result<EmptyModel?, ResponseError>, albumId: Int, isLike: Bool) {
|
|||
|
|
isRequesting = false
|
|||
|
|
|
|||
|
|
let photoModel = imageModels[currentIndex]
|
|||
|
|
guard let likeView = likeView, let album = photoModel.aiAlbum else { return }
|
|||
|
|
likeView.likeButton.isEnabled = true
|
|||
|
|
|
|||
|
|
switch result {
|
|||
|
|
case .success:
|
|||
|
|
// 请求成功,无需额外处理
|
|||
|
|
break
|
|||
|
|
case .failure:
|
|||
|
|
// 请求失败,恢复状态
|
|||
|
|
|
|||
|
|
if isLike {
|
|||
|
|
// 点赞失败,恢复为未点赞状态
|
|||
|
|
album.likedStatus = .cancel
|
|||
|
|
album.likedCount = max((album.likedCount ?? 0) - 1, 0)
|
|||
|
|
} else {
|
|||
|
|
// 取消点赞失败,恢复为点赞状态
|
|||
|
|
album.likedStatus = .liked
|
|||
|
|
album.likedCount = (album.likedCount ?? 0) + 1
|
|||
|
|
}
|
|||
|
|
PhotosViewModel.shared.album = album
|
|||
|
|
likeView.bind(aiAlbum: album)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: - Helper
|
|||
|
|
|
|||
|
|
/// like : 💎 20 unlock
|
|||
|
|
func getUnlockAttributeTitleByCoin(coin: Int) -> NSAttributedString {
|
|||
|
|
let text = " \(coin) unlock"
|
|||
|
|
let attributedString = NSMutableAttributedString()
|
|||
|
|
if let iconImage = UIImage(named: "icon_32_diamond") { // 替换为你的图标名称
|
|||
|
|
let attachment = NSTextAttachment()
|
|||
|
|
attachment.image = iconImage
|
|||
|
|
|
|||
|
|
let iconSize = CGSize(width: 24, height: 24) // 调整为你需要的大小
|
|||
|
|
attachment.bounds = CGRect(origin: .init(x: 0, y: -4), size: iconSize)
|
|||
|
|
|
|||
|
|
let iconAttributedString = NSAttributedString(attachment: attachment)
|
|||
|
|
attributedString.append(iconAttributedString)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加文字并设置样式
|
|||
|
|
let textAttributedString = text.withAttributes([
|
|||
|
|
.font(.t.tll), // 设置字体
|
|||
|
|
.textColor(.white),
|
|||
|
|
])
|
|||
|
|
attributedString.append(textAttributedString)
|
|||
|
|
return attributedString
|
|||
|
|
}
|
|||
|
|
}
|