mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-12-01 20:51:25 +00:00
Merge branch 'main' into iOS-18
This commit is contained in:
commit
1f753e49b9
9 changed files with 131 additions and 31 deletions
|
@ -9,6 +9,7 @@ struct ToolbarTab: ToolbarContent {
|
|||
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||
|
||||
@Environment(UserPreferences.self) private var userPreferences
|
||||
@Environment(Theme.self) private var theme
|
||||
|
||||
@Binding var routerPath: RouterPath
|
||||
|
||||
|
@ -35,7 +36,7 @@ struct ToolbarTab: ToolbarContent {
|
|||
(UIDevice.current.userInterfaceIdiom == .pad && horizontalSizeClass == .compact)
|
||||
{
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
AppAccountsSelectorView(routerPath: routerPath)
|
||||
AppAccountsSelectorView(routerPath: routerPath, avatarConfig: theme.avatarShape == .circle ? .badge : .badgeRounded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13465,6 +13465,23 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"account.edit.avatar.delete" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Delete avatar"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Supprimer l'avatar"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"account.edit.display-name" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
|
@ -13941,6 +13958,23 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"account.edit.header.delete" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Delete header"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Supprimer la bannière"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"account.edit.metadata-name-placeholder" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
|
|
|
@ -87,9 +87,8 @@ public struct EditAccountView: View {
|
|||
.frame(height: 150)
|
||||
}
|
||||
}
|
||||
if let avatar = viewModel.avatar {
|
||||
ZStack(alignment: .bottomLeading) {
|
||||
AvatarView(avatar, config: .account)
|
||||
AvatarView(viewModel.avatar, config: .account)
|
||||
Menu {
|
||||
Button("account.edit.avatar") {
|
||||
viewModel.isChangingAvatar = true
|
||||
|
@ -99,6 +98,23 @@ public struct EditAccountView: View {
|
|||
viewModel.isChangingHeader = true
|
||||
viewModel.isPhotoPickerPresented = true
|
||||
}
|
||||
if viewModel.avatar != nil || viewModel.header != nil {
|
||||
Divider()
|
||||
}
|
||||
if viewModel.avatar != nil {
|
||||
Button("account.edit.avatar.delete", role: .destructive) {
|
||||
Task {
|
||||
await viewModel.deleteAvatar()
|
||||
}
|
||||
}
|
||||
}
|
||||
if viewModel.header != nil {
|
||||
Button("account.edit.header.delete", role: .destructive) {
|
||||
Task {
|
||||
await viewModel.deleteHeader()
|
||||
}
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "photo.badge.plus")
|
||||
.foregroundStyle(.white)
|
||||
|
@ -106,9 +122,10 @@ public struct EditAccountView: View {
|
|||
.buttonStyle(.borderedProminent)
|
||||
.clipShape(Circle())
|
||||
.offset(x: -8, y: 8)
|
||||
.padding(EdgeInsets(top: 0, leading: 0, bottom: 8, trailing: 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.overlay {
|
||||
if viewModel.isChangingAvatar || viewModel.isChangingHeader {
|
||||
ZStack(alignment: .center) {
|
||||
|
|
|
@ -82,8 +82,8 @@ import SwiftUI
|
|||
isBot = account.bot
|
||||
isLocked = account.locked
|
||||
isDiscoverable = account.discoverable ?? false
|
||||
avatar = account.avatar
|
||||
header = account.header
|
||||
avatar = account.haveAvatar ? account.avatar : nil
|
||||
header = account.haveHeader ? account.header : nil
|
||||
fields = account.source?.fields.map { .init(name: $0.name, value: $0.value.asRawText) } ?? []
|
||||
withAnimation {
|
||||
isLoading = false
|
||||
|
@ -112,6 +112,28 @@ import SwiftUI
|
|||
}
|
||||
}
|
||||
|
||||
func deleteAvatar() async -> Bool {
|
||||
guard let client else { return false }
|
||||
do {
|
||||
let response = try await client.delete(endpoint: Profile.deleteAvatar)
|
||||
avatar = nil
|
||||
return response?.statusCode == 200
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func deleteHeader() async -> Bool {
|
||||
guard let client else { return false }
|
||||
do {
|
||||
let response = try await client.delete(endpoint: Profile.deleteHeader)
|
||||
header = nil
|
||||
return response?.statusCode == 200
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func uploadHeader(data: Data) async -> Bool {
|
||||
guard let client else { return false }
|
||||
do {
|
||||
|
|
|
@ -53,6 +53,7 @@ public struct AvatarView: View {
|
|||
#endif
|
||||
public static let embed = FrameConfig(width: 34, height: 34)
|
||||
public static let badge = FrameConfig(width: 28, height: 28, cornerRadius: 14)
|
||||
public static let badgeRounded = FrameConfig(width: 28, height: 28)
|
||||
public static let list = FrameConfig(width: 20, height: 20, cornerRadius: 10)
|
||||
public static let boost = FrameConfig(width: 12, height: 12, cornerRadius: 6)
|
||||
}
|
||||
|
|
23
Packages/Network/Sources/Network/Endpoint/Profile.swift
Normal file
23
Packages/Network/Sources/Network/Endpoint/Profile.swift
Normal file
|
@ -0,0 +1,23 @@
|
|||
import Foundation
|
||||
|
||||
public enum Profile: Endpoint {
|
||||
case deleteAvatar
|
||||
case deleteHeader
|
||||
|
||||
|
||||
public func path() -> String {
|
||||
switch self {
|
||||
case .deleteAvatar:
|
||||
"profile/avatar"
|
||||
case .deleteHeader:
|
||||
"profile/header"
|
||||
}
|
||||
}
|
||||
|
||||
public func queryItems() -> [URLQueryItem]? {
|
||||
switch self {
|
||||
case .deleteAvatar, .deleteHeader:
|
||||
nil
|
||||
}
|
||||
}
|
||||
}
|
|
@ -212,6 +212,7 @@ struct StatusRowActionsView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.sheet(isPresented: $showTextForSelection) {
|
||||
let content = viewModel.status.reblog?.content.asSafeMarkdownAttributedString ?? viewModel.status.content.asSafeMarkdownAttributedString
|
||||
SelectTextView(content: content)
|
||||
|
|
|
@ -27,7 +27,7 @@ struct StatusRowHeaderView: View {
|
|||
}
|
||||
}
|
||||
.accessibilityElement(children: .combine)
|
||||
.accessibilityLabel(Text("\(viewModel.finalStatus.account.safeDisplayName)") + Text(", ") + Text(viewModel.finalStatus.createdAt.relativeFormatted))
|
||||
.accessibilityLabel(Text("\(viewModel.finalStatus.account.safeDisplayName), \(viewModel.finalStatus.createdAt.relativeFormatted)"))
|
||||
.accessibilityAction {
|
||||
viewModel.navigateToAccountDetail(account: viewModel.finalStatus.account)
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ struct StatusRowHeaderView: View {
|
|||
Group {
|
||||
EmojiTextApp(viewModel.finalStatus.account.cachedDisplayName,
|
||||
emojis: viewModel.finalStatus.account.emojis)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.font(.scaledSubheadline)
|
||||
.foregroundColor(theme.labelColor)
|
||||
.emojiText.size(Font.scaledSubheadlineFont.emojiSize)
|
||||
|
@ -59,6 +60,7 @@ struct StatusRowHeaderView: View {
|
|||
|
||||
if !redactionReasons.contains(.placeholder) {
|
||||
accountBadgeView
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.font(.footnote)
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +71,7 @@ struct StatusRowHeaderView: View {
|
|||
theme.avatarPosition == .top
|
||||
{
|
||||
Text("@\(theme.displayFullUsername ? viewModel.finalStatus.account.acct : viewModel.finalStatus.account.username)")
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.font(.scaledFootnote)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
|
@ -81,21 +84,18 @@ struct StatusRowHeaderView: View {
|
|||
}
|
||||
}
|
||||
|
||||
private var accountBadgeView: Text {
|
||||
private var accountBadgeView: Text? {
|
||||
if (viewModel.status.reblogAsAsStatus ?? viewModel.status).account.bot {
|
||||
return Text(Image(systemName: "poweroutlet.type.b.fill")) + Text(" ")
|
||||
return Text("\(Image(systemName: "poweroutlet.type.b.fill")) ")
|
||||
} else if (viewModel.status.reblogAsAsStatus ?? viewModel.status).account.locked {
|
||||
return Text(Image(systemName: "lock.fill")) + Text(" ")
|
||||
return Text("\(Image(systemName: "lock.fill")) ")
|
||||
}
|
||||
return Text("")
|
||||
return nil
|
||||
}
|
||||
|
||||
private var dateView: some View {
|
||||
Group {
|
||||
Text(Image(systemName: viewModel.finalStatus.visibility.iconName)) +
|
||||
Text(" ⸱ ") +
|
||||
Text(viewModel.finalStatus.createdAt.relativeFormatted)
|
||||
}
|
||||
Text("\(Image(systemName: viewModel.finalStatus.visibility.iconName)) ⸱ \(viewModel.finalStatus.createdAt.relativeFormatted)")
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.font(.scaledFootnote)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
|
|
|
@ -19,6 +19,7 @@ struct StatusRowTextView: View {
|
|||
emojis: viewModel.finalStatus.emojis,
|
||||
language: viewModel.finalStatus.language,
|
||||
lineLimit: viewModel.lineLimit)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.font(isFocused ? .scaledBodyFocused : .scaledBody)
|
||||
.lineSpacing(CGFloat(theme.lineSpacing))
|
||||
.foregroundColor(viewModel.textDisabled ? .gray : theme.labelColor)
|
||||
|
|
Loading…
Reference in a new issue