Merge branch 'main' into iOS-18

This commit is contained in:
Thomas Ricouard 2024-06-24 16:12:44 +02:00
commit 22a7b2a938
7 changed files with 261 additions and 38 deletions

View file

@ -3,10 +3,10 @@
{ {
"identity" : "bodega", "identity" : "bodega",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/Dimillian/Bodega", "location" : "https://github.com/mergesort/Bodega",
"state" : { "state" : {
"branch" : "main", "revision" : "bfd8871e9c2590d31b200e54c75428a71483afdf",
"revision" : "a144ed8afdd760b65b6b9a136ba8bb75cd19387e" "version" : "2.1.3"
} }
}, },
{ {
@ -23,8 +23,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/divadretlaw/EmojiText", "location" : "https://github.com/divadretlaw/EmojiText",
"state" : { "state" : {
"revision" : "415112e5f14619be0fdddd9dc6594bd76702927c", "revision" : "174a7bc7bd75650ad1acb5679dbb754296093de0",
"version" : "4.0.3" "version" : "4.0.0"
} }
}, },
{ {
@ -68,8 +68,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/kean/Nuke", "location" : "https://github.com/kean/Nuke",
"state" : { "state" : {
"revision" : "2efd206503e99dd3a88a4dc433a76f98ce8cc198", "revision" : "311016d972aa751ae8ab0cd5897422ebe7db0501",
"version" : "12.7.1" "version" : "12.7.3"
} }
}, },
{ {
@ -129,10 +129,10 @@
{ {
"identity" : "swiftui-introspect", "identity" : "swiftui-introspect",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/Dimillian/swiftui-introspect", "location" : "https://github.com/siteline/swiftui-introspect",
"state" : { "state" : {
"branch" : "main", "revision" : "668a65735751432b640260c56dfa621cec568368",
"revision" : "e5d36b00e6e437b552aa76ed6d1eca71d6fd8f8b" "version" : "1.2.0"
} }
} }
], ],

View file

@ -332,6 +332,12 @@
"state" : "translated", "state" : "translated",
"value" : "%@" "value" : "%@"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@"
}
} }
} }
}, },
@ -714,6 +720,12 @@
"state" : "translated", "state" : "translated",
"value" : "%@ Mastodon'da yayınlandı" "value" : "%@ Mastodon'da yayınlandı"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ 已在 Mastodon 发布"
}
} }
} }
}, },
@ -8935,6 +8947,12 @@
"state" : "translated", "state" : "translated",
"value" : "Hesap" "value" : "Hesap"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "Account"
}
} }
} }
}, },
@ -20503,6 +20521,12 @@
"state" : "translated", "state" : "translated",
"value" : "Mastodon'a gönderim yapılırken bir hata oluştu, lütfen tekrar deneyin." "value" : "Mastodon'a gönderim yapılırken bir hata oluştu, lütfen tekrar deneyin."
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "在向 Mastodon 发表嘟文时出错,请重试。"
}
} }
} }
}, },
@ -20651,6 +20675,12 @@
"state" : "translated", "state" : "translated",
"value" : "Uygulama Hesabı" "value" : "Uygulama Hesabı"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "AppAccount"
}
} }
} }
}, },
@ -20713,6 +20743,12 @@
"state" : "translated", "state" : "translated",
"value" : "Gönderi oluştur" "value" : "Gönderi oluştur"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "撰写一篇嘟文"
}
} }
} }
}, },
@ -20741,6 +20777,12 @@
"state" : "translated", "state" : "translated",
"value" : "Mastodon'a bir gönderi yazın" "value" : "Mastodon'a bir gönderi yazın"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "向 Mastodon 撰写一篇嘟文"
}
} }
} }
}, },
@ -20769,6 +20811,12 @@
"state" : "translated", "state" : "translated",
"value" : "Mastodon'a gönderilecek gönderinin içeriği" "value" : "Mastodon'a gönderilecek gönderinin içeriği"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "发布到 Mastodon 的嘟文内容"
}
} }
} }
}, },
@ -22338,6 +22386,12 @@
"state" : "translated", "state" : "translated",
"value" : "DeepL'e ulaşılamadı!\nAPI Anahtarı doğru mu?" "value" : "DeepL'e ulaşılamadı!\nAPI Anahtarı doğru mu?"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "无法连接 DeepL\n你的 API 密钥是正确的吗?"
}
} }
} }
}, },
@ -31163,6 +31217,12 @@
"state" : "translated", "state" : "translated",
"value" : "Yalnızca Takipçiler" "value" : "Yalnızca Takipçiler"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "仅关注者"
}
} }
} }
}, },
@ -31294,6 +31354,12 @@
"state" : "translated", "state" : "translated",
"value" : "Örnek" "value" : "Örnek"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "服务器"
}
} }
} }
}, },
@ -32858,6 +32924,12 @@
"state" : "translated", "state" : "translated",
"value" : "Ancak yine de örneğinizin çeviri hizmeti için bir yedek olarak kullanılabilir." "value" : "Ancak yine de örneğinizin çeviri hizmeti için bir yedek olarak kullanılabilir."
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "它仍可用作为你所处服务器的翻译服务的备用。"
}
} }
} }
}, },
@ -32881,6 +32953,12 @@
"state" : "translated", "state" : "translated",
"value" : "Anahtar" "value" : "Anahtar"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "Key"
}
} }
} }
}, },
@ -35469,7 +35547,7 @@
}, },
"zh-Hans" : { "zh-Hans" : {
"stringUnit" : { "stringUnit" : {
"state" : "needs_review", "state" : "translated",
"value" : "设置 ..." "value" : "设置 ..."
} }
}, },
@ -41022,6 +41100,12 @@
"state" : "translated", "state" : "translated",
"value" : "Resim ile bir durum gönder" "value" : "Resim ile bir durum gönder"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "发布带图片的状态"
}
} }
} }
}, },
@ -41176,6 +41260,12 @@
"state" : "translated", "state" : "translated",
"value" : "Gönderi görünürlüğü" "value" : "Gönderi görünürlüğü"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "嘟文可见度"
}
} }
} }
}, },
@ -41204,6 +41294,12 @@
"state" : "translated", "state" : "translated",
"value" : "Özel" "value" : "Özel"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "具体的人"
}
} }
} }
}, },
@ -41300,6 +41396,12 @@
"state" : "translated", "state" : "translated",
"value" : "Herkese Açık" "value" : "Herkese Açık"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "公开"
}
} }
} }
}, },
@ -41328,6 +41430,12 @@
"state" : "translated", "state" : "translated",
"value" : "Oldukça Açık" "value" : "Oldukça Açık"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "悄悄公开"
}
} }
} }
}, },
@ -41864,6 +41972,12 @@
"state" : "translated", "state" : "translated",
"value" : "Post gönder" "value" : "Post gönder"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "发送嘟文"
}
} }
} }
}, },
@ -41892,6 +42006,12 @@
"state" : "translated", "state" : "translated",
"value" : "Ice cubes ile Mastodon'a kısa mesaj gönder" "value" : "Ice cubes ile Mastodon'a kısa mesaj gönder"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "使用 Ice Cubes 向 Mastodon 发布文本嘟文"
}
} }
} }
}, },
@ -41920,6 +42040,12 @@
"state" : "translated", "state" : "translated",
"value" : "Gönderiyi Mastodon'a gönder" "value" : "Gönderiyi Mastodon'a gönder"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "发送嘟文至 Mastodon"
}
} }
} }
}, },
@ -61537,7 +61663,7 @@
}, },
"zh-Hans" : { "zh-Hans" : {
"stringUnit" : { "stringUnit" : {
"state" : "needs_review", "state" : "translated",
"value" : "该功能需要 DeepL API 密钥" "value" : "该功能需要 DeepL API 密钥"
} }
}, },
@ -69630,7 +69756,7 @@
"zh-Hans" : { "zh-Hans" : {
"stringUnit" : { "stringUnit" : {
"state" : "translated", "state" : "translated",
"value" : "Your settings require alt text on all media before posting" "value" : "你的设置要求在发布前为所有媒体添加描述文本"
} }
}, },
"zh-Hant" : { "zh-Hant" : {
@ -76981,8 +77107,8 @@
}, },
"zh-Hans" : { "zh-Hans" : {
"stringUnit" : { "stringUnit" : {
"state" : "needs_review", "state" : "translated",
"value" : "Profile (%@)" "value" : "个人主页 (%@)"
} }
}, },
"zh-Hant" : { "zh-Hant" : {
@ -77845,6 +77971,12 @@
"state" : "translated", "state" : "translated",
"value" : "DeepL API Anahtarı hala saklanıyor!" "value" : "DeepL API Anahtarı hala saklanıyor!"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "DeepL API 密钥已存储!"
}
} }
} }
}, },
@ -77874,6 +78006,12 @@
"state" : "translated", "state" : "translated",
"value" : "Örneğinizin Çeviri Hizmetine ulaşılamadı!" "value" : "Örneğinizin Çeviri Hizmetine ulaşılamadı!"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "无法连接你的服务器的翻译服务!"
}
} }
} }
}, },
@ -81771,6 +81909,12 @@
"state" : "translated", "state" : "translated",
"value" : "Zaman Çizelgesi Filtresi" "value" : "Zaman Çizelgesi Filtresi"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "TimelineFilter"
}
} }
} }
}, },
@ -81800,6 +81944,12 @@
"state" : "translated", "state" : "translated",
"value" : "Çeviri servisi" "value" : "Çeviri servisi"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "翻译服务"
}
} }
} }
}, },
@ -82255,6 +82405,12 @@
"state" : "translated", "state" : "translated",
"value" : "Mastodon için bir gönderi oluşturmak için Ice Cubes kullanın" "value" : "Mastodon için bir gönderi oluşturmak için Ice Cubes kullanın"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "使用 Ice Cubes 向 Mastodon 发布嘟文"
}
} }
} }
}, },
@ -82283,6 +82439,12 @@
"state" : "translated", "state" : "translated",
"value" : "Mastodon'da görsel içeren bir gönderi oluşturmak için Ice Cubes kullanın" "value" : "Mastodon'da görsel içeren bir gönderi oluşturmak için Ice Cubes kullanın"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "使用 Ice Cubes 向 Mastodon 发布带有图片的嘟文"
}
} }
} }
}, },
@ -82369,6 +82531,12 @@
"state" : "translated", "state" : "translated",
"value" : "Görünürlük" "value" : "Görünürlük"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "可见度"
}
} }
} }
}, },
@ -82397,6 +82565,12 @@
"state" : "translated", "state" : "translated",
"value" : "Gönderinizin görünürlüğü" "value" : "Gönderinizin görünürlüğü"
} }
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "嘟文可见度"
}
} }
} }
} }

View file

@ -83,7 +83,7 @@ public struct AccountDetailView: View {
client: client, client: client,
routerPath: routerPath) routerPath: routerPath)
} }
.environment(\.defaultMinListRowHeight, 1) .environment(\.defaultMinListRowHeight, 0)
.listStyle(.plain) .listStyle(.plain)
#if !os(visionOS) #if !os(visionOS)
.scrollContentBackground(.hidden) .scrollContentBackground(.hidden)

View file

@ -51,17 +51,19 @@ import SwiftUI
didSet { didSet {
if let item = mediaPickers.first { if let item = mediaPickers.first {
Task { Task {
if let data = await getItemImageData(item: item) {
if isChangingAvatar { if isChangingAvatar {
_ = await uploadAvatar(data: data) if let data = await getItemImageData(item: item, for: .avatar) {
_ = await uploadAvatar(data: data)
}
isChangingAvatar = false
} else if isChangingHeader { } else if isChangingHeader {
_ = await uploadHeader(data: data) if let data = await getItemImageData(item: item, for: .header) {
_ = await uploadHeader(data: data)
}
isChangingHeader = false
} }
await fetchAccount() await fetchAccount()
isChangingAvatar = false
isChangingHeader = false
mediaPickers = [] mediaPickers = []
}
} }
} }
} }
@ -140,16 +142,48 @@ import SwiftUI
} }
} }
private func getItemImageData(item: PhotosPickerItem) async -> Data? { private func getItemImageData(item: PhotosPickerItem, for type: ItemType) async -> Data? {
guard let imageFile = try? await item.loadTransferable(type: StatusEditor.ImageFileTranseferable.self) else { return nil } guard let imageFile = try? await item.loadTransferable(type: StatusEditor.ImageFileTranseferable.self) else { return nil }
let compressor = StatusEditor.Compressor() let compressor = StatusEditor.Compressor()
guard let compressedData = await compressor.compressImageFrom(url: imageFile.url), guard let compressedData = await compressor.compressImageFrom(url: imageFile.url),
let image = UIImage(data: compressedData), let image = UIImage(data: compressedData),
let uploadData = try? await compressor.compressImageForUpload(image) let uploadData = try? await compressor.compressImageForUpload(
else { return nil } image,
maxSize: 2 * 1024 * 1024, // 2MB
maxHeight: type.maxHeight,
maxWidth: type.maxWidth
)
else {
return nil
}
return uploadData return uploadData
} }
} }
extension EditAccountViewModel {
private enum ItemType {
case avatar
case header
var maxHeight: CGFloat {
switch self {
case .avatar:
400
case .header:
500
}
}
var maxWidth: CGFloat {
switch self {
case .avatar:
400
case .header:
1500
}
}
}
}

View file

@ -19,8 +19,8 @@ let package = Package(
dependencies: [ dependencies: [
.package(name: "Models", path: "../Models"), .package(name: "Models", path: "../Models"),
.package(name: "Env", path: "../Env"), .package(name: "Env", path: "../Env"),
.package(url: "https://github.com/kean/Nuke", from: "12.4.0"), .package(url: "https://github.com/kean/Nuke", exact: "12.7.3"),
.package(url: "https://github.com/divadretlaw/EmojiText", from: "4.0.0"), .package(url: "https://github.com/divadretlaw/EmojiText", exact: "4.0.0"),
], ],
targets: [ targets: [
.target( .target(

View file

@ -57,30 +57,45 @@ public extension StatusEditor {
} }
} }
public func compressImageForUpload(_ image: UIImage) async throws -> Data { public func compressImageForUpload(
_ image: UIImage,
maxSize: Int = 10 * 1024 * 1024,
maxHeight: Double = 5000,
maxWidth: Double = 5000
) async throws -> Data {
var image = image var image = image
if image.size.height > 5000 || image.size.width > 5000 {
image = image.resized(to: .init(width: image.size.width / 4, if image.size.height > maxHeight || image.size.width > maxWidth {
height: image.size.height / 4)) let heightFactor = image.size.height / maxHeight
let widthFactor = image.size.width / maxWidth
let maxFactor = max(heightFactor, widthFactor)
image = image.resized(to: .init(width: image.size.width / maxFactor,
height: image.size.height / maxFactor))
} }
guard var imageData = image.jpegData(compressionQuality: 0.8) else { guard var imageData = image.jpegData(compressionQuality: 0.8) else {
throw CompressorError.noData throw CompressorError.noData
} }
let maxSize = 10 * 1024 * 1024 var compressionQualityFactor: CGFloat = 0.8
if imageData.count > maxSize { if imageData.count > maxSize {
while imageData.count > maxSize { while imageData.count > maxSize && compressionQualityFactor >= 0 {
guard let compressedImage = UIImage(data: imageData), guard let compressedImage = UIImage(data: imageData),
let compressedData = compressedImage.jpegData(compressionQuality: 0.8) let compressedData = compressedImage.jpegData(compressionQuality: compressionQualityFactor)
else { else {
throw CompressorError.noData throw CompressorError.noData
} }
imageData = compressedData imageData = compressedData
compressionQualityFactor -= 0.1
} }
} }
if imageData.count > maxSize && compressionQualityFactor <= 0 {
throw CompressorError.noData
}
return imageData return imageData
} }

View file

@ -22,8 +22,8 @@ let package = Package(
.package(name: "Env", path: "../Env"), .package(name: "Env", path: "../Env"),
.package(name: "StatusKit", path: "../StatusKit"), .package(name: "StatusKit", path: "../StatusKit"),
.package(name: "DesignSystem", path: "../DesignSystem"), .package(name: "DesignSystem", path: "../DesignSystem"),
.package(url: "https://github.com/Dimillian/swiftui-introspect", branch: "main"), .package(url: "https://github.com/siteline/swiftui-introspect", exact: "1.2.0"),
.package(url: "https://github.com/Dimillian/Bodega", branch: "main"), .package(url: "https://github.com/mergesort/Bodega", exact: "2.1.3"),
], ],
targets: [ targets: [
.target( .target(