Fix isues on iPad
This commit is contained in:
parent
ed94179b1d
commit
3171022870
|
@ -18,6 +18,7 @@ public class ImageSizeService {
|
||||||
|
|
||||||
/// Cache with orginal image sizes.
|
/// Cache with orginal image sizes.
|
||||||
private var memoryCacheData = MemoryCache<URL, CGSize>(entryLifetime: 3600)
|
private var memoryCacheData = MemoryCache<URL, CGSize>(entryLifetime: 3600)
|
||||||
|
private let staticImageHeight = 500.0
|
||||||
|
|
||||||
public func get(for url: URL) -> CGSize? {
|
public func get(for url: URL) -> CGSize? {
|
||||||
return self.memoryCacheData[url]
|
return self.memoryCacheData[url]
|
||||||
|
@ -37,6 +38,12 @@ public class ImageSizeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ImageSizeService {
|
extension ImageSizeService {
|
||||||
|
public func calculate(for url: URL) -> CGSize {
|
||||||
|
return UIDevice.current.userInterfaceIdiom == .phone
|
||||||
|
? ImageSizeService.shared.calculate(for: url, andContainerWidth: UIScreen.main.bounds.size.width)
|
||||||
|
: ImageSizeService.shared.calculate(for: url, andContainerHeight: self.staticImageHeight)
|
||||||
|
}
|
||||||
|
|
||||||
public func calculate(for url: URL, andContainerWidth containerWidth: Double) -> CGSize {
|
public func calculate(for url: URL, andContainerWidth containerWidth: Double) -> CGSize {
|
||||||
guard let size = self.get(for: url) else {
|
guard let size = self.get(for: url) else {
|
||||||
return CGSize(width: containerWidth, height: containerWidth)
|
return CGSize(width: containerWidth, height: containerWidth)
|
||||||
|
@ -45,6 +52,20 @@ extension ImageSizeService {
|
||||||
return self.calculate(width: size.width, height: size.height, andContainerWidth: containerWidth)
|
return self.calculate(width: size.width, height: size.height, andContainerWidth: containerWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func calculate(for url: URL, andContainerHeight containerHeight: Double) -> CGSize {
|
||||||
|
guard let size = self.get(for: url) else {
|
||||||
|
return CGSize(width: containerHeight, height: containerHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.calculate(width: size.width, height: size.height, andContainerHeight: containerHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func calculate(width: Double, height: Double) -> CGSize {
|
||||||
|
return UIDevice.current.userInterfaceIdiom == .phone
|
||||||
|
? ImageSizeService.shared.calculate(width: width, height: height, andContainerWidth: UIScreen.main.bounds.size.width)
|
||||||
|
: ImageSizeService.shared.calculate(width: width, height: height, andContainerHeight: self.staticImageHeight)
|
||||||
|
}
|
||||||
|
|
||||||
public func calculate(width: Double, height: Double, andContainerWidth containerWidth: Double) -> CGSize {
|
public func calculate(width: Double, height: Double, andContainerWidth containerWidth: Double) -> CGSize {
|
||||||
let divider = Double(width) / containerWidth
|
let divider = Double(width) / containerWidth
|
||||||
let calculatedHeight = Double(height) / divider
|
let calculatedHeight = Double(height) / divider
|
||||||
|
@ -56,4 +77,16 @@ extension ImageSizeService {
|
||||||
|
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func calculate(width: Double, height: Double, andContainerHeight containerHeight: Double) -> CGSize {
|
||||||
|
let divider = Double(height) / containerHeight
|
||||||
|
let calculatedWidth = Double(width) / divider
|
||||||
|
|
||||||
|
let size = CGSize(
|
||||||
|
width: (calculatedWidth > 0 && calculatedWidth < .infinity) ? calculatedWidth : containerHeight,
|
||||||
|
height: containerHeight
|
||||||
|
)
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,6 +200,7 @@
|
||||||
F8F6E44D29BCC1F90004795E /* PhotoMediumWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44829BCC0F00004795E /* PhotoMediumWidgetView.swift */; };
|
F8F6E44D29BCC1F90004795E /* PhotoMediumWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44829BCC0F00004795E /* PhotoMediumWidgetView.swift */; };
|
||||||
F8F6E44E29BCC1FB0004795E /* PhotoLargeWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44A29BCC0FF0004795E /* PhotoLargeWidgetView.swift */; };
|
F8F6E44E29BCC1FB0004795E /* PhotoLargeWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E44A29BCC0FF0004795E /* PhotoLargeWidgetView.swift */; };
|
||||||
F8F6E45129BCE9190004795E /* UIImage+Resize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E45029BCE9190004795E /* UIImage+Resize.swift */; };
|
F8F6E45129BCE9190004795E /* UIImage+Resize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6E45029BCE9190004795E /* UIImage+Resize.swift */; };
|
||||||
|
F8FAA0AD2AB0BCB400FD78BD /* View+ContainerBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FAA0AC2AB0BCB400FD78BD /* View+ContainerBackground.swift */; };
|
||||||
F8FB8ABA29EB2ED400342C04 /* NavigationMenuButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FB8AB929EB2ED400342C04 /* NavigationMenuButtons.swift */; };
|
F8FB8ABA29EB2ED400342C04 /* NavigationMenuButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FB8AB929EB2ED400342C04 /* NavigationMenuButtons.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
@ -407,6 +408,7 @@
|
||||||
F8F6E44829BCC0F00004795E /* PhotoMediumWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoMediumWidgetView.swift; sourceTree = "<group>"; };
|
F8F6E44829BCC0F00004795E /* PhotoMediumWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoMediumWidgetView.swift; sourceTree = "<group>"; };
|
||||||
F8F6E44A29BCC0FF0004795E /* PhotoLargeWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLargeWidgetView.swift; sourceTree = "<group>"; };
|
F8F6E44A29BCC0FF0004795E /* PhotoLargeWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoLargeWidgetView.swift; sourceTree = "<group>"; };
|
||||||
F8F6E45029BCE9190004795E /* UIImage+Resize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Resize.swift"; sourceTree = "<group>"; };
|
F8F6E45029BCE9190004795E /* UIImage+Resize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Resize.swift"; sourceTree = "<group>"; };
|
||||||
|
F8FAA0AC2AB0BCB400FD78BD /* View+ContainerBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+ContainerBackground.swift"; sourceTree = "<group>"; };
|
||||||
F8FB8AB929EB2ED400342C04 /* NavigationMenuButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationMenuButtons.swift; sourceTree = "<group>"; };
|
F8FB8AB929EB2ED400342C04 /* NavigationMenuButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationMenuButtons.swift; sourceTree = "<group>"; };
|
||||||
F8FFBD4929E99BEE0047EE80 /* Vernissage-009.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-009.xcdatamodel"; sourceTree = "<group>"; };
|
F8FFBD4929E99BEE0047EE80 /* Vernissage-009.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Vernissage-009.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
@ -909,6 +911,7 @@
|
||||||
children = (
|
children = (
|
||||||
F815F60B29E49CF20044566B /* Avatar.swift */,
|
F815F60B29E49CF20044566B /* Avatar.swift */,
|
||||||
F8F6E45029BCE9190004795E /* UIImage+Resize.swift */,
|
F8F6E45029BCE9190004795E /* UIImage+Resize.swift */,
|
||||||
|
F8FAA0AC2AB0BCB400FD78BD /* View+ContainerBackground.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1121,6 +1124,7 @@
|
||||||
F864F78229BB9A6500B13921 /* StatusData+CoreDataClass.swift in Sources */,
|
F864F78229BB9A6500B13921 /* StatusData+CoreDataClass.swift in Sources */,
|
||||||
F864F78329BB9A6800B13921 /* StatusData+CoreDataProperties.swift in Sources */,
|
F864F78329BB9A6800B13921 /* StatusData+CoreDataProperties.swift in Sources */,
|
||||||
F864F78429BB9A6E00B13921 /* ApplicationSettings+CoreDataClass.swift in Sources */,
|
F864F78429BB9A6E00B13921 /* ApplicationSettings+CoreDataClass.swift in Sources */,
|
||||||
|
F8FAA0AD2AB0BCB400FD78BD /* View+ContainerBackground.swift in Sources */,
|
||||||
F864F78629BB9A7400B13921 /* AccountData+CoreDataClass.swift in Sources */,
|
F864F78629BB9A7400B13921 /* AccountData+CoreDataClass.swift in Sources */,
|
||||||
F8705A7B29FF872F00DA818A /* QRCodeGenerator.swift in Sources */,
|
F8705A7B29FF872F00DA818A /* QRCodeGenerator.swift in Sources */,
|
||||||
F865B4CE2A024AD8008ACDFC /* StatusData+Faulty.swift in Sources */,
|
F865B4CE2A024AD8008ACDFC /* StatusData+Faulty.swift in Sources */,
|
||||||
|
@ -1552,7 +1556,7 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 143;
|
CURRENT_PROJECT_VERSION = 200;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = B2U9FEKYP8;
|
DEVELOPMENT_TEAM = B2U9FEKYP8;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
|
@ -1571,7 +1575,7 @@
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.9.0;
|
MARKETING_VERSION = 1.10.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
@ -1594,7 +1598,7 @@
|
||||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||||
CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Vernissage/Vernissage.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 143;
|
CURRENT_PROJECT_VERSION = 200;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = B2U9FEKYP8;
|
DEVELOPMENT_TEAM = B2U9FEKYP8;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
|
@ -1613,7 +1617,7 @@
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.9.0;
|
MARKETING_VERSION = 1.10.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
|
|
|
@ -56,7 +56,7 @@ struct StatusView: View {
|
||||||
private func mainBody() -> some View {
|
private func mainBody() -> some View {
|
||||||
switch state {
|
switch state {
|
||||||
case .loading:
|
case .loading:
|
||||||
StatusPlaceholderView(imageHeight: self.getImageHeight(), imageBlurhash: self.imageBlurhash)
|
StatusPlaceholderView(imageWidth: self.getImageWidth(), imageHeight: self.getImageHeight(), imageBlurhash: self.imageBlurhash)
|
||||||
.task {
|
.task {
|
||||||
await self.loadData()
|
await self.loadData()
|
||||||
}
|
}
|
||||||
|
@ -236,13 +236,12 @@ struct StatusView: View {
|
||||||
|
|
||||||
private func getImageHeight() -> Double {
|
private func getImageHeight() -> Double {
|
||||||
if let highestImageUrl = self.highestImageUrl, let imageSize = ImageSizeService.shared.get(for: highestImageUrl) {
|
if let highestImageUrl = self.highestImageUrl, let imageSize = ImageSizeService.shared.get(for: highestImageUrl) {
|
||||||
return imageSize.height
|
let calculatedSize = ImageSizeService.shared.calculate(width: imageSize.width, height: imageSize.height)
|
||||||
|
return calculatedSize.height
|
||||||
}
|
}
|
||||||
|
|
||||||
if let imageHeight = self.imageHeight, let imageWidth = self.imageWidth, imageHeight > 0 && imageWidth > 0 {
|
if let imageHeight = self.imageHeight, let imageWidth = self.imageWidth, imageHeight > 0 && imageWidth > 0 {
|
||||||
let calculatedSize = ImageSizeService.shared.calculate(width: Double(imageWidth),
|
let calculatedSize = ImageSizeService.shared.calculate(width: Double(imageWidth), height: Double(imageHeight))
|
||||||
height: Double(imageHeight),
|
|
||||||
andContainerWidth: UIScreen.main.bounds.size.width)
|
|
||||||
return calculatedSize.height
|
return calculatedSize.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,6 +249,21 @@ struct StatusView: View {
|
||||||
return UIScreen.main.bounds.width * 0.75
|
return UIScreen.main.bounds.width * 0.75
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func getImageWidth() -> Double {
|
||||||
|
if let highestImageUrl = self.highestImageUrl, let imageSize = ImageSizeService.shared.get(for: highestImageUrl) {
|
||||||
|
let calculatedSize = ImageSizeService.shared.calculate(width: imageSize.width, height: imageSize.height)
|
||||||
|
return calculatedSize.width
|
||||||
|
}
|
||||||
|
|
||||||
|
if let imageHeight = self.imageHeight, let imageWidth = self.imageWidth, imageHeight > 0 && imageWidth > 0 {
|
||||||
|
let calculatedSize = ImageSizeService.shared.calculate(width: Double(imageWidth), height: Double(imageHeight))
|
||||||
|
return calculatedSize.width
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we don't have image height and width in metadata, we have to use some constant height.
|
||||||
|
return UIScreen.main.bounds.width * 0.75
|
||||||
|
}
|
||||||
|
|
||||||
private func getMainStatus(status: StatusModel) async throws -> StatusModel {
|
private func getMainStatus(status: StatusModel) async throws -> StatusModel {
|
||||||
guard let inReplyToId = status.inReplyToId else {
|
guard let inReplyToId = status.inReplyToId else {
|
||||||
return status
|
return status
|
||||||
|
|
|
@ -8,6 +8,7 @@ import SwiftUI
|
||||||
import WidgetsKit
|
import WidgetsKit
|
||||||
|
|
||||||
struct StatusPlaceholderView: View {
|
struct StatusPlaceholderView: View {
|
||||||
|
@State var imageWidth: Double
|
||||||
@State var imageHeight: Double
|
@State var imageHeight: Double
|
||||||
@State var imageBlurhash: String?
|
@State var imageBlurhash: String?
|
||||||
|
|
||||||
|
@ -17,11 +18,11 @@ struct StatusPlaceholderView: View {
|
||||||
if let imageBlurhash, let uiImage = UIImage(blurHash: imageBlurhash, size: CGSize(width: 32, height: 32)) {
|
if let imageBlurhash, let uiImage = UIImage(blurHash: imageBlurhash, size: CGSize(width: 32, height: 32)) {
|
||||||
Image(uiImage: uiImage)
|
Image(uiImage: uiImage)
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: UIScreen.main.bounds.width, height: imageHeight)
|
.frame(width: self.imageWidth, height: self.imageHeight)
|
||||||
} else {
|
} else {
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.fill(Color.placeholderText)
|
.fill(Color.placeholderText)
|
||||||
.frame(width: UIScreen.main.bounds.width, height: imageHeight)
|
.frame(width: self.imageWidth, height: self.imageHeight)
|
||||||
.redacted(reason: .placeholder)
|
.redacted(reason: .placeholder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,6 @@ struct StatusesView: View {
|
||||||
ImageRowAsync(statusViewModel: item, containerWidth: $containerWidth)
|
ImageRowAsync(statusViewModel: item, containerWidth: $containerWidth)
|
||||||
} onLoadMore: {
|
} onLoadMore: {
|
||||||
do {
|
do {
|
||||||
print("load more......")
|
|
||||||
try await self.loadMoreStatuses()
|
try await self.loadMoreStatuses()
|
||||||
} catch {
|
} catch {
|
||||||
ErrorService.shared.handle(error, message: "statuses.error.loadingStatusesFailed", showToastr: !Task.isCancelled)
|
ErrorService.shared.handle(error, message: "statuses.error.loadingStatusesFailed", showToastr: !Task.isCancelled)
|
||||||
|
|
|
@ -57,6 +57,8 @@ struct UserProfileHeaderView: View {
|
||||||
.opacity(0.6)
|
.opacity(0.6)
|
||||||
}
|
}
|
||||||
}.foregroundColor(.mainTextColor)
|
}.foregroundColor(.mainTextColor)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
}
|
}
|
||||||
|
|
||||||
HStack(alignment: .center) {
|
HStack(alignment: .center) {
|
||||||
|
|
|
@ -12,11 +12,29 @@ import WidgetsKit
|
||||||
struct ImageCarouselPicture: View {
|
struct ImageCarouselPicture: View {
|
||||||
@ObservedObject public var attachment: AttachmentModel
|
@ObservedObject public var attachment: AttachmentModel
|
||||||
|
|
||||||
|
@State private var blurredImageHeight: Double
|
||||||
|
@State private var blurredImageWidth: Double
|
||||||
|
|
||||||
private let onImageDownloaded: (AttachmentModel, Data) -> Void
|
private let onImageDownloaded: (AttachmentModel, Data) -> Void
|
||||||
|
|
||||||
init(attachment: AttachmentModel, onImageDownloaded: @escaping (_: AttachmentModel, _: Data) -> Void) {
|
init(attachment: AttachmentModel, onImageDownloaded: @escaping (_: AttachmentModel, _: Data) -> Void) {
|
||||||
self.attachment = attachment
|
self.attachment = attachment
|
||||||
self.onImageDownloaded = onImageDownloaded
|
self.onImageDownloaded = onImageDownloaded
|
||||||
|
|
||||||
|
if let size = ImageSizeService.shared.get(for: attachment.url) {
|
||||||
|
let imageSize = ImageSizeService.shared.calculate(width: size.width, height: size.height)
|
||||||
|
|
||||||
|
self.blurredImageHeight = imageSize.height
|
||||||
|
self.blurredImageWidth = imageSize.width
|
||||||
|
} else if let imageWidth = attachment.metaImageWidth, let imageHeight = attachment.metaImageHeight {
|
||||||
|
let imageSize = ImageSizeService.shared.calculate(width: Double(imageWidth), height: Double(imageHeight))
|
||||||
|
|
||||||
|
self.blurredImageHeight = imageSize.height
|
||||||
|
self.blurredImageWidth = imageSize.width
|
||||||
|
} else {
|
||||||
|
self.blurredImageHeight = 100.0
|
||||||
|
self.blurredImageWidth = 100.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -26,6 +44,7 @@ struct ImageCarouselPicture: View {
|
||||||
.aspectRatio(contentMode: .fit)
|
.aspectRatio(contentMode: .fit)
|
||||||
} else {
|
} else {
|
||||||
BlurredImage(blurhash: attachment.blurhash)
|
BlurredImage(blurhash: attachment.blurhash)
|
||||||
|
.frame(width: self.blurredImageWidth, height: self.blurredImageHeight)
|
||||||
.task {
|
.task {
|
||||||
do {
|
do {
|
||||||
// Download image and recalculate exif data.
|
// Download image and recalculate exif data.
|
||||||
|
|
|
@ -47,9 +47,7 @@ struct ImagesCarousel: View {
|
||||||
|
|
||||||
// Calculate size of frame (first from cache, then from metadata).
|
// Calculate size of frame (first from cache, then from metadata).
|
||||||
if let highestImage, let size = ImageSizeService.shared.get(for: highestImage.url) {
|
if let highestImage, let size = ImageSizeService.shared.get(for: highestImage.url) {
|
||||||
let calculatedSize = ImageSizeService.shared.calculate(width: size.width,
|
let calculatedSize = ImageSizeService.shared.calculate(width: size.width, height: size.height)
|
||||||
height: size.height,
|
|
||||||
andContainerWidth: UIScreen.main.bounds.size.width)
|
|
||||||
|
|
||||||
self.imageWidth = calculatedSize.width
|
self.imageWidth = calculatedSize.width
|
||||||
self.imageHeight = calculatedSize.height
|
self.imageHeight = calculatedSize.height
|
||||||
|
@ -57,7 +55,8 @@ struct ImagesCarousel: View {
|
||||||
self.heightWasPrecalculated = true
|
self.heightWasPrecalculated = true
|
||||||
} else if let highestImage, imgHeight > 0 && imgWidth > 0 {
|
} else if let highestImage, imgHeight > 0 && imgWidth > 0 {
|
||||||
ImageSizeService.shared.save(for: highestImage.url, width: imgWidth, height: imgHeight)
|
ImageSizeService.shared.save(for: highestImage.url, width: imgWidth, height: imgHeight)
|
||||||
let size = ImageSizeService.shared.calculate(for: highestImage.url, andContainerWidth: UIScreen.main.bounds.size.width)
|
let size = ImageSizeService.shared.calculate(for: highestImage.url)
|
||||||
|
|
||||||
self.imageWidth = size.width
|
self.imageWidth = size.width
|
||||||
self.imageHeight = size.height
|
self.imageHeight = size.height
|
||||||
|
|
||||||
|
@ -70,33 +69,37 @@ struct ImagesCarousel: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
TabView(selection: $selected) {
|
HStack {
|
||||||
ForEach(attachments, id: \.id) { attachment in
|
Spacer()
|
||||||
ImageCarouselPicture(attachment: attachment) { (attachment, imageData) in
|
TabView(selection: $selected) {
|
||||||
withAnimation {
|
ForEach(attachments, id: \.id) { attachment in
|
||||||
self.recalculateImageHeight(attachment: attachment, imageData: imageData)
|
ImageCarouselPicture(attachment: attachment) { (attachment, imageData) in
|
||||||
}
|
withAnimation {
|
||||||
|
self.recalculateImageHeight(attachment: attachment, imageData: imageData)
|
||||||
|
}
|
||||||
|
|
||||||
self.asyncAfter(0.4) {
|
self.asyncAfter(0.4) {
|
||||||
attachment.set(data: imageData)
|
attachment.set(data: imageData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.tag(attachment.id)
|
||||||
}
|
}
|
||||||
.tag(attachment.id)
|
|
||||||
}
|
}
|
||||||
|
.frame(height: self.imageHeight)
|
||||||
|
.tabViewStyle(PageTabViewStyle())
|
||||||
|
.onChange(of: selected, perform: { index in
|
||||||
|
if let attachment = attachments.first(where: { item in item.id == index }) {
|
||||||
|
self.selectedAttachment = attachment
|
||||||
|
self.exifCamera = attachment.exifCamera
|
||||||
|
self.exifExposure = attachment.exifExposure
|
||||||
|
self.exifCreatedDate = attachment.exifCreatedDate
|
||||||
|
self.exifLens = attachment.exifLens
|
||||||
|
self.description = attachment.description
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Spacer()
|
||||||
}
|
}
|
||||||
.frame(height: self.imageHeight)
|
|
||||||
.tabViewStyle(PageTabViewStyle())
|
|
||||||
.onChange(of: selected, perform: { index in
|
|
||||||
if let attachment = attachments.first(where: { item in item.id == index }) {
|
|
||||||
self.selectedAttachment = attachment
|
|
||||||
self.exifCamera = attachment.exifCamera
|
|
||||||
self.exifExposure = attachment.exifExposure
|
|
||||||
self.exifCreatedDate = attachment.exifCreatedDate
|
|
||||||
self.exifLens = attachment.exifLens
|
|
||||||
self.description = attachment.description
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.onAppear {
|
.onAppear {
|
||||||
self.selected = self.attachments.first?.id ?? String.empty()
|
self.selected = self.attachments.first?.id ?? String.empty()
|
||||||
}
|
}
|
||||||
|
@ -107,28 +110,41 @@ struct ImagesCarousel: View {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageHeight = 0.0
|
var maxImageHeight = 0.0
|
||||||
var imageWidth = 0.0
|
var maxImageWidth = 0.0
|
||||||
|
|
||||||
for item in attachments {
|
for item in attachments {
|
||||||
if let data = item.data, let image = UIImage(data: data) {
|
// Get attachment sizes from cache.
|
||||||
ImageSizeService.shared.save(for: attachment.url, width: image.size.width, height: image.size.height)
|
if let attachmentSize = ImageSizeService.shared.get(for: item.url) {
|
||||||
|
if attachmentSize.height > maxImageHeight {
|
||||||
|
maxImageHeight = attachmentSize.height
|
||||||
|
maxImageWidth = attachmentSize.width
|
||||||
|
}
|
||||||
|
|
||||||
if image.size.height > imageHeight {
|
continue
|
||||||
imageHeight = image.size.height
|
}
|
||||||
imageWidth = image.size.width
|
|
||||||
|
// When we don't have in cache read from data and add to cache.
|
||||||
|
if let data = item.data, let image = UIImage(data: data) {
|
||||||
|
ImageSizeService.shared.save(for: item.url, width: image.size.width, height: image.size.height)
|
||||||
|
|
||||||
|
if image.size.height > maxImageHeight {
|
||||||
|
maxImageHeight = image.size.height
|
||||||
|
maxImageWidth = image.size.width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let image = UIImage(data: imageData) {
|
if let image = UIImage(data: imageData) {
|
||||||
if image.size.height > imageHeight {
|
ImageSizeService.shared.save(for: attachment.url, width: image.size.width, height: image.size.height)
|
||||||
imageHeight = image.size.height
|
|
||||||
imageWidth = image.size.width
|
if image.size.height > maxImageHeight {
|
||||||
|
maxImageHeight = image.size.height
|
||||||
|
maxImageWidth = image.size.width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = ImageSizeService.shared.calculate(for: attachment.url, andContainerWidth: UIScreen.main.bounds.size.width)
|
let size = ImageSizeService.shared.calculate(width: maxImageWidth, height: maxImageHeight)
|
||||||
self.imageWidth = size.width
|
self.imageWidth = size.width
|
||||||
self.imageHeight = size.height
|
self.imageHeight = size.height
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
//
|
||||||
|
// https://mczachurski.dev
|
||||||
|
// Copyright © 2023 Marcin Czachurski and the repository contributors.
|
||||||
|
// Licensed under the Apache License 2.0.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
// func widgetBackground(backgroundView: some View) -> some View {
|
||||||
|
// if #available(iOSApplicationExtension 17.0, *) {
|
||||||
|
// return containerBackground(for: .widget) {
|
||||||
|
// backgroundView
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// return background(backgroundView)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
func widgetBackground<V>(@ViewBuilder content: @escaping () -> V) -> some View where V: View {
|
||||||
|
if #available(iOSApplicationExtension 17.0, *) {
|
||||||
|
return containerBackground(for: .widget) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return background(content())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,5 +17,6 @@ struct PhotoWidget: Widget {
|
||||||
.configurationDisplayName("Vernissage")
|
.configurationDisplayName("Vernissage")
|
||||||
.description("widget.title.photoDescription")
|
.description("widget.title.photoDescription")
|
||||||
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
|
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
|
||||||
|
.contentMarginsDisabled()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ struct PhotoLargeWidgetView: View {
|
||||||
.padding(.leading, 8)
|
.padding(.leading, 8)
|
||||||
.padding(.bottom, 8)
|
.padding(.bottom, 8)
|
||||||
}
|
}
|
||||||
.background {
|
.widgetBackground {
|
||||||
uiImage
|
uiImage
|
||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fill)
|
||||||
|
|
|
@ -38,7 +38,7 @@ struct PhotoMediumWidgetView: View {
|
||||||
.padding(.leading, 8)
|
.padding(.leading, 8)
|
||||||
.padding(.bottom, 8)
|
.padding(.bottom, 8)
|
||||||
}
|
}
|
||||||
.background {
|
.widgetBackground {
|
||||||
uiImage
|
uiImage
|
||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fill)
|
||||||
|
|
|
@ -33,7 +33,7 @@ struct PhotoSmallWidgetView: View {
|
||||||
.padding(.leading, 8)
|
.padding(.leading, 8)
|
||||||
.padding(.bottom, 8)
|
.padding(.bottom, 8)
|
||||||
}
|
}
|
||||||
.background {
|
.widgetBackground {
|
||||||
uiImage
|
uiImage
|
||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fill)
|
||||||
|
|
|
@ -17,5 +17,6 @@ struct QRCodeWidget: Widget {
|
||||||
.configurationDisplayName("Vernissage")
|
.configurationDisplayName("Vernissage")
|
||||||
.description("widget.title.qrCodeDescription")
|
.description("widget.title.qrCodeDescription")
|
||||||
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
|
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
|
||||||
|
.contentMarginsDisabled()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,8 @@ struct QRCodeLargeWidgetView: View {
|
||||||
.offset(y: -8)
|
.offset(y: -8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.widgetBackground {
|
||||||
|
}
|
||||||
.padding([.leading, .trailing, .top], 24)
|
.padding([.leading, .trailing, .top], 24)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,8 @@ struct QRCodeMediumWidgetView: View {
|
||||||
.padding(.leading, 3)
|
.padding(.leading, 3)
|
||||||
.offset(y: -4)
|
.offset(y: -4)
|
||||||
}
|
}
|
||||||
|
.widgetBackground {
|
||||||
|
}
|
||||||
.padding([.leading, .trailing, .top], 12)
|
.padding([.leading, .trailing, .top], 12)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,8 @@ struct QRCodeSmallWidgetView: View {
|
||||||
.frame(height: 24)
|
.frame(height: 24)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.widgetBackground {
|
||||||
|
}
|
||||||
.padding(8)
|
.padding(8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,10 +52,10 @@ struct DeviceImageGallery: ViewModifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
asyncAfter(0.1) {
|
// asyncAfter(0.1) {
|
||||||
let galleryProperties = self.getGalleryProperties(geometry: geometry, horizontalSize: self.horizontalSizeClass ?? .compact)
|
let galleryProperties = self.getGalleryProperties(geometry: geometry, horizontalSize: self.horizontalSizeClass ?? .compact)
|
||||||
self.action(galleryProperties)
|
self.action(galleryProperties)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,6 @@ struct DeviceImageGallery: ViewModifier {
|
||||||
} else {
|
} else {
|
||||||
// View like on iPad.
|
// View like on iPad.
|
||||||
let imageColumns = geometry.size.width > geometry.size.height ? 3 : 2
|
let imageColumns = geometry.size.width > geometry.size.height ? 3 : 2
|
||||||
print("\(geometry.size.width ):\(geometry.size.height)")
|
|
||||||
|
|
||||||
return GalleryProperties(imageColumns: imageColumns,
|
return GalleryProperties(imageColumns: imageColumns,
|
||||||
containerWidth: geometry.size.width / Double(imageColumns),
|
containerWidth: geometry.size.width / Double(imageColumns),
|
||||||
|
|
Loading…
Reference in New Issue