Add blurhash support for main status image.
This commit is contained in:
parent
8a5552b21a
commit
68351897b0
|
@ -53,6 +53,7 @@
|
||||||
F86B7214296BFDCE00EE59EC /* UserProfileHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7213296BFDCE00EE59EC /* UserProfileHeader.swift */; };
|
F86B7214296BFDCE00EE59EC /* UserProfileHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7213296BFDCE00EE59EC /* UserProfileHeader.swift */; };
|
||||||
F86B7216296BFFDA00EE59EC /* UserProfileStatuses.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7215296BFFDA00EE59EC /* UserProfileStatuses.swift */; };
|
F86B7216296BFFDA00EE59EC /* UserProfileStatuses.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7215296BFFDA00EE59EC /* UserProfileStatuses.swift */; };
|
||||||
F86B7218296C27C100EE59EC /* ActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7217296C27C100EE59EC /* ActionButton.swift */; };
|
F86B7218296C27C100EE59EC /* ActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B7217296C27C100EE59EC /* ActionButton.swift */; };
|
||||||
|
F86B721C296C394000EE59EC /* Status+ImageSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F86B721B296C394000EE59EC /* Status+ImageSize.swift */; };
|
||||||
F88ABD9229686F1C004EF61E /* MemoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88ABD9129686F1C004EF61E /* MemoryCache.swift */; };
|
F88ABD9229686F1C004EF61E /* MemoryCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88ABD9129686F1C004EF61E /* MemoryCache.swift */; };
|
||||||
F88ABD9429687CA4004EF61E /* ComposeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88ABD9329687CA4004EF61E /* ComposeView.swift */; };
|
F88ABD9429687CA4004EF61E /* ComposeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88ABD9329687CA4004EF61E /* ComposeView.swift */; };
|
||||||
F88C246C295C37B80006098B /* VernissageApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88C246B295C37B80006098B /* VernissageApp.swift */; };
|
F88C246C295C37B80006098B /* VernissageApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88C246B295C37B80006098B /* VernissageApp.swift */; };
|
||||||
|
@ -129,6 +130,7 @@
|
||||||
F86B7213296BFDCE00EE59EC /* UserProfileHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileHeader.swift; sourceTree = "<group>"; };
|
F86B7213296BFDCE00EE59EC /* UserProfileHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileHeader.swift; sourceTree = "<group>"; };
|
||||||
F86B7215296BFFDA00EE59EC /* UserProfileStatuses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileStatuses.swift; sourceTree = "<group>"; };
|
F86B7215296BFFDA00EE59EC /* UserProfileStatuses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileStatuses.swift; sourceTree = "<group>"; };
|
||||||
F86B7217296C27C100EE59EC /* ActionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButton.swift; sourceTree = "<group>"; };
|
F86B7217296C27C100EE59EC /* ActionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButton.swift; sourceTree = "<group>"; };
|
||||||
|
F86B721B296C394000EE59EC /* Status+ImageSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Status+ImageSize.swift"; sourceTree = "<group>"; };
|
||||||
F88ABD9129686F1C004EF61E /* MemoryCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryCache.swift; sourceTree = "<group>"; };
|
F88ABD9129686F1C004EF61E /* MemoryCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryCache.swift; sourceTree = "<group>"; };
|
||||||
F88ABD9329687CA4004EF61E /* ComposeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeView.swift; sourceTree = "<group>"; };
|
F88ABD9329687CA4004EF61E /* ComposeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeView.swift; sourceTree = "<group>"; };
|
||||||
F88ABD9529687D4D004EF61E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
F88ABD9529687D4D004EF61E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||||
|
@ -218,6 +220,7 @@
|
||||||
F8210DE62966E1D1001D9973 /* Color+Assets.swift */,
|
F8210DE62966E1D1001D9973 /* Color+Assets.swift */,
|
||||||
F8C14393296AF21B001FE31D /* Double+Round.swift */,
|
F8C14393296AF21B001FE31D /* Double+Round.swift */,
|
||||||
F8984E4C296B648000A2610F /* UIImage+Blurhash.swift */,
|
F8984E4C296B648000A2610F /* UIImage+Blurhash.swift */,
|
||||||
|
F86B721B296C394000EE59EC /* Status+ImageSize.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -456,6 +459,7 @@
|
||||||
F80048082961E6DE00E6868A /* StatusDataHandler.swift in Sources */,
|
F80048082961E6DE00E6868A /* StatusDataHandler.swift in Sources */,
|
||||||
F866F6A0296040A8002E8F88 /* ApplicationSettings+CoreDataClass.swift in Sources */,
|
F866F6A0296040A8002E8F88 /* ApplicationSettings+CoreDataClass.swift in Sources */,
|
||||||
F8210DEA2966E4F9001D9973 /* AnimatePlaceholderModifier.swift in Sources */,
|
F8210DEA2966E4F9001D9973 /* AnimatePlaceholderModifier.swift in Sources */,
|
||||||
|
F86B721C296C394000EE59EC /* Status+ImageSize.swift in Sources */,
|
||||||
F8984E4D296B648000A2610F /* UIImage+Blurhash.swift in Sources */,
|
F8984E4D296B648000A2610F /* UIImage+Blurhash.swift in Sources */,
|
||||||
F897978A2968314A00B22335 /* LoadingIndicator.swift in Sources */,
|
F897978A2968314A00B22335 /* LoadingIndicator.swift in Sources */,
|
||||||
F8210DE52966E160001D9973 /* Color+SystemColors.swift in Sources */,
|
F8210DE52966E160001D9973 /* Color+SystemColors.swift in Sources */,
|
||||||
|
|
|
@ -17,5 +17,13 @@ extension AttachmentData {
|
||||||
self.remoteUrl = attachment.remoteUrl
|
self.remoteUrl = attachment.remoteUrl
|
||||||
self.text = attachment.description
|
self.text = attachment.description
|
||||||
self.type = attachment.type.rawValue
|
self.type = attachment.type.rawValue
|
||||||
|
|
||||||
|
if let width = (attachment.meta as? ImageMetadata)?.original?.width {
|
||||||
|
self.metaImageWidth = Int32(width)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let height = (attachment.meta as? ImageMetadata)?.original?.height {
|
||||||
|
self.metaImageHeight = Int32(height)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,12 @@
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import CoreData
|
import CoreData
|
||||||
|
|
||||||
|
|
||||||
extension AttachmentData {
|
extension AttachmentData {
|
||||||
|
|
||||||
@nonobjc public class func fetchRequest() -> NSFetchRequest<AttachmentData> {
|
@nonobjc public class func fetchRequest() -> NSFetchRequest<AttachmentData> {
|
||||||
|
@ -15,6 +18,10 @@ extension AttachmentData {
|
||||||
|
|
||||||
@NSManaged public var blurhash: String?
|
@NSManaged public var blurhash: String?
|
||||||
@NSManaged public var data: Data
|
@NSManaged public var data: Data
|
||||||
|
@NSManaged public var exifCamera: String?
|
||||||
|
@NSManaged public var exifCreatedDate: String?
|
||||||
|
@NSManaged public var exifExposure: String?
|
||||||
|
@NSManaged public var exifLens: String?
|
||||||
@NSManaged public var id: String
|
@NSManaged public var id: String
|
||||||
@NSManaged public var previewUrl: URL?
|
@NSManaged public var previewUrl: URL?
|
||||||
@NSManaged public var remoteUrl: URL?
|
@NSManaged public var remoteUrl: URL?
|
||||||
|
@ -22,13 +29,12 @@ extension AttachmentData {
|
||||||
@NSManaged public var text: String?
|
@NSManaged public var text: String?
|
||||||
@NSManaged public var type: String
|
@NSManaged public var type: String
|
||||||
@NSManaged public var url: URL
|
@NSManaged public var url: URL
|
||||||
@NSManaged public var exifCamera: String?
|
@NSManaged public var metaImageWidth: Int32
|
||||||
@NSManaged public var exifLens: String?
|
@NSManaged public var metaImageHeight: Int32
|
||||||
@NSManaged public var exifExposure: String?
|
|
||||||
@NSManaged public var exifCreatedDate: String?
|
|
||||||
@NSManaged public var statusRelation: StatusData?
|
@NSManaged public var statusRelation: StatusData?
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AttachmentData : Identifiable {
|
extension AttachmentData : Identifiable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
//
|
||||||
|
// https://mczachurski.dev
|
||||||
|
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import MastodonSwift
|
||||||
|
|
||||||
|
extension Status {
|
||||||
|
public func getImageWidth() -> Int32? {
|
||||||
|
if let width = (self.mediaAttachments.first?.meta as? ImageMetadata)?.original?.width {
|
||||||
|
return Int32(width)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getImageHeight() -> Int32? {
|
||||||
|
if let height = (self.mediaAttachments.first?.meta as? ImageMetadata)?.original?.height {
|
||||||
|
return Int32(height)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,8 @@
|
||||||
<attribute name="exifExposure" optional="YES" attributeType="String"/>
|
<attribute name="exifExposure" optional="YES" attributeType="String"/>
|
||||||
<attribute name="exifLens" optional="YES" attributeType="String"/>
|
<attribute name="exifLens" optional="YES" attributeType="String"/>
|
||||||
<attribute name="id" attributeType="String"/>
|
<attribute name="id" attributeType="String"/>
|
||||||
|
<attribute name="metaImageHeight" optional="YES" attributeType="Integer 32" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||||
|
<attribute name="metaImageWidth" optional="YES" attributeType="Integer 32" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||||
<attribute name="previewUrl" optional="YES" attributeType="URI"/>
|
<attribute name="previewUrl" optional="YES" attributeType="URI"/>
|
||||||
<attribute name="remoteUrl" optional="YES" attributeType="URI"/>
|
<attribute name="remoteUrl" optional="YES" attributeType="URI"/>
|
||||||
<attribute name="statusId" attributeType="String"/>
|
<attribute name="statusId" attributeType="String"/>
|
||||||
|
|
|
@ -22,7 +22,10 @@ struct HomeFeedView: View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVGrid(columns: gridColumns) {
|
LazyVGrid(columns: gridColumns) {
|
||||||
ForEach(dbStatuses, id: \.self) { item in
|
ForEach(dbStatuses, id: \.self) { item in
|
||||||
NavigationLink(destination: StatusView(statusId: item.id)
|
NavigationLink(destination: StatusView(statusId: item.id,
|
||||||
|
imageBlurhash: item.attachments().first?.blurhash,
|
||||||
|
imageWidth: item.attachments().first?.metaImageWidth,
|
||||||
|
imageHeight: item.attachments().first?.metaImageHeight)
|
||||||
.environmentObject(applicationState)) {
|
.environmentObject(applicationState)) {
|
||||||
ImageRow(attachments: item.attachments())
|
ImageRow(attachments: item.attachments())
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@ import AVFoundation
|
||||||
struct StatusView: View {
|
struct StatusView: View {
|
||||||
@EnvironmentObject var applicationState: ApplicationState
|
@EnvironmentObject var applicationState: ApplicationState
|
||||||
@State var statusId: String
|
@State var statusId: String
|
||||||
|
@State var imageBlurhash: String?
|
||||||
|
@State var imageWidth: Int32?
|
||||||
|
@State var imageHeight: Int32?
|
||||||
|
|
||||||
@State private var showCompose = false
|
@State private var showCompose = false
|
||||||
@State private var statusData: StatusData?
|
@State private var statusData: StatusData?
|
||||||
|
@ -84,9 +87,16 @@ struct StatusView: View {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
VStack (alignment: .leading) {
|
VStack (alignment: .leading) {
|
||||||
|
if let imageBlurhash, let uiImage = UIImage(blurHash: imageBlurhash, size: CGSize(width: 32, height: 32)) {
|
||||||
|
Image(uiImage: uiImage)
|
||||||
|
.resizable()
|
||||||
|
.frame(width: UIScreen.main.bounds.width, height: self.getImageHeight())
|
||||||
|
} else {
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.fill(Color.placeholderText)
|
.fill(Color.placeholderText)
|
||||||
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.width)
|
.frame(width: UIScreen.main.bounds.width, height: self.getImageHeight())
|
||||||
|
.redacted(reason: .placeholder)
|
||||||
|
}
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
UsernameRow(accountDisplayName: "Verylong Displayname",
|
UsernameRow(accountDisplayName: "Verylong Displayname",
|
||||||
|
@ -103,12 +113,13 @@ struct StatusView: View {
|
||||||
LabelIcon(iconName: "camera.aperture", value: "Viltrox 24mm F1.8 E")
|
LabelIcon(iconName: "camera.aperture", value: "Viltrox 24mm F1.8 E")
|
||||||
LabelIcon(iconName: "timelapse", value: "24.0 mm, f/1.8, 1/640s, ISO 100")
|
LabelIcon(iconName: "timelapse", value: "24.0 mm, f/1.8, 1/640s, ISO 100")
|
||||||
LabelIcon(iconName: "calendar", value: "2 Oct 2022")
|
LabelIcon(iconName: "calendar", value: "2 Oct 2022")
|
||||||
}.padding(8)
|
|
||||||
}
|
}
|
||||||
|
.padding(8)
|
||||||
.redacted(reason: .placeholder)
|
.redacted(reason: .placeholder)
|
||||||
.animatePlaceholder(isLoading: .constant(true))
|
.animatePlaceholder(isLoading: .constant(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.navigationBarTitle("Details")
|
.navigationBarTitle("Details")
|
||||||
.sheet(isPresented: $showCompose, content: {
|
.sheet(isPresented: $showCompose, content: {
|
||||||
ComposeView()
|
ComposeView()
|
||||||
|
@ -143,6 +154,19 @@ struct StatusView: View {
|
||||||
exifCreatedDate = attachmentData.exifCreatedDate
|
exifCreatedDate = attachmentData.exifCreatedDate
|
||||||
exifLens = attachmentData.exifLens
|
exifLens = attachmentData.exifLens
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func getImageHeight() -> Double {
|
||||||
|
if let imageHeight = self.imageHeight, let imageWidth = self.imageWidth, imageHeight > 0 && imageWidth > 0 {
|
||||||
|
return self.calculateHeight(width: Double(imageWidth), height: Double(imageHeight))
|
||||||
|
}
|
||||||
|
|
||||||
|
return UIScreen.main.bounds.width * 0.75
|
||||||
|
}
|
||||||
|
|
||||||
|
private func calculateHeight(width: Double, height: Double) -> CGFloat {
|
||||||
|
let divider = width / UIScreen.main.bounds.size.width
|
||||||
|
return height / divider
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StatusView_Previews: PreviewProvider {
|
struct StatusView_Previews: PreviewProvider {
|
||||||
|
|
|
@ -20,7 +20,10 @@ struct UserProfileStatuses: View {
|
||||||
VStack(alignment: .center) {
|
VStack(alignment: .center) {
|
||||||
if firstLoadFinished == true {
|
if firstLoadFinished == true {
|
||||||
ForEach(self.statuses, id: \.id) { item in
|
ForEach(self.statuses, id: \.id) { item in
|
||||||
NavigationLink(destination: StatusView(statusId: item.id)
|
NavigationLink(destination: StatusView(statusId: item.id,
|
||||||
|
imageBlurhash: item.mediaAttachments.first?.blurhash,
|
||||||
|
imageWidth: item.getImageWidth(),
|
||||||
|
imageHeight: item.getImageHeight())
|
||||||
.environmentObject(applicationState)) {
|
.environmentObject(applicationState)) {
|
||||||
ImageRowAsync(attachments: item.mediaAttachments)
|
ImageRowAsync(attachments: item.mediaAttachments)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue