Fix flickering issues when resizing window (#1644)

* Fix flickering issues when resizing window, or hiding notifications on macOS

* Restore processor and add debouncing to the processor updates

* Fix indentation

* Add LazyResizableImage to the Design system module
This commit is contained in:
Hugo Saynac 2023-11-01 18:57:13 +01:00 committed by GitHub
parent b2550d28ac
commit b2933b8c75
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 23 deletions

View file

@ -0,0 +1,42 @@
//
// LazyResizableImage.swift
//
//
// Created by Hugo Saynac on 28/10/2023.
//
import Nuke
import NukeUI
import SwiftUI
/// A LazyImage (Nuke) with a geometry reader under the hood in order to use a Resize Processor to optimize performances on lists.
/// This views also allows smooth resizing of the images by debouncing the update of the ImageProcessor.
struct LazyResizableImage<Content: View>: View {
init(url: URL?, @ViewBuilder content: @escaping (LazyImageState, GeometryProxy) -> Content) {
self.imageURL = url
self.content = content
}
let imageURL: URL?
@State private var resizeProcessor: ImageProcessors.Resize?
@State private var debouncedTask: Task<Void, Never>?
@ViewBuilder
private var content: (LazyImageState, _ proxy: GeometryProxy) -> Content
var body: some View {
GeometryReader { proxy in
LazyImage(url: imageURL) { state in
content(state, proxy)
}
.processors([resizeProcessor == nil ? .resize(size: proxy.size) : resizeProcessor!])
.onChange(of: proxy.size, initial: true) { oldValue, newValue in
debouncedTask?.cancel()
debouncedTask = Task {
do { try await Task.sleep(for: .milliseconds(200)) } catch { return }
resizeProcessor = .resize(size: newValue)
}
}
}
}
}

View file

@ -47,27 +47,23 @@ public struct StatusRowCardView: View {
if let title = card.title, let url = URL(string: card.url) { if let title = card.title, let url = URL(string: card.url) {
VStack(alignment: .leading) { VStack(alignment: .leading) {
if let imageURL = card.image, !isInCaptureMode { if let imageURL = card.image, !isInCaptureMode {
GeometryReader { proxy in LazyResizableImage(url: imageURL) { state, proxy in
let width = imageWidthFor(proxy: proxy) let width = imageWidthFor(proxy: proxy)
let processors: [ImageProcessing] = [.resize(size: .init(width: width, height: imageHeight))] if let image = state.image {
LazyImage(url: imageURL) { state in image
if let image = state.image { .resizable()
image .aspectRatio(contentMode: .fill)
.resizable() .frame(height: imageHeight)
.aspectRatio(contentMode: .fill) .frame(maxWidth: width)
.frame(height: imageHeight) .clipped()
.frame(maxWidth: width) } else if state.isLoading {
.clipped() Rectangle()
} else if state.isLoading { .fill(Color.gray)
Rectangle() .frame(height: imageHeight)
.fill(Color.gray)
.frame(height: imageHeight)
}
} }
.processors(processors)
// This image is decorative
.accessibilityHidden(true)
} }
// This image is decorative
.accessibilityHidden(true)
.frame(height: imageHeight) .frame(height: imageHeight)
} }
HStack { HStack {

View file

@ -29,7 +29,7 @@ public struct StatusRowMediaPreviewView: View {
var availableWidth: CGFloat { var availableWidth: CGFloat {
if UIDevice.current.userInterfaceIdiom == .phone && if UIDevice.current.userInterfaceIdiom == .phone &&
(UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight) || theme.statusDisplayStyle == .medium (UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight) || theme.statusDisplayStyle == .medium
{ {
return sceneDelegate.windowWidth * 0.80 return sceneDelegate.windowWidth * 0.80
} }
@ -217,10 +217,9 @@ public struct StatusRowMediaPreviewView: View {
GeometryReader { proxy in GeometryReader { proxy in
switch type { switch type {
case .image: case .image:
let width = isCompact ? imageMaxHeight : proxy.frame(in: .local).width
let processors: [ImageProcessing] = [.resize(size: .init(width: width, height: imageMaxHeight))]
ZStack(alignment: .bottomTrailing) { ZStack(alignment: .bottomTrailing) {
LazyImage(url: attachment.previewUrl ?? attachment.url) { state in LazyResizableImage(url: attachment.previewUrl ?? attachment.url) { state, proxy in
let width = isCompact ? imageMaxHeight : proxy.frame(in: .local).width
if let image = state.image { if let image = state.image {
image image
.resizable() .resizable()
@ -240,7 +239,6 @@ public struct StatusRowMediaPreviewView: View {
.frame(maxWidth: width) .frame(maxWidth: width)
} }
} }
.processors(processors)
if sensitive, !isInCaptureMode { if sensitive, !isInCaptureMode {
cornerSensitiveButton cornerSensitiveButton
} }