mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-10-31 16:24:11 +00:00
pr suggestions
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
enum Avatars {
|
||||
enum Size {
|
||||
@@ -39,33 +38,6 @@ enum Avatars {
|
||||
}
|
||||
}
|
||||
|
||||
/// Media repo thumbnails are scaled, not cropped, so they keep the source's aspect
|
||||
/// ratio. System UI (share sheet suggestions, notifications) stretches non-square
|
||||
/// images to fill its circle, so centre-crop to a square before donating them.
|
||||
nonisolated static func squareAvatarImageData(from data: Data) -> Data? {
|
||||
guard let image = UIImage(data: data) else { return nil }
|
||||
|
||||
let side = min(image.size.width, image.size.height)
|
||||
guard side > 0 else { return nil }
|
||||
|
||||
if image.size.width == image.size.height {
|
||||
return data
|
||||
}
|
||||
|
||||
let format = UIGraphicsImageRendererFormat()
|
||||
// UIImage(data:) decodes at scale 1; pin the renderer to that so the
|
||||
// output isn't silently multiplied by the device's screen scale.
|
||||
format.scale = image.scale
|
||||
|
||||
return UIGraphicsImageRenderer(size: CGSize(width: side, height: side), format: format)
|
||||
.pngData { _ in
|
||||
// Round the offsets to pixel boundaries so the crop is a straight
|
||||
// copy rather than resampling (and softening) the whole image.
|
||||
image.draw(at: CGPoint(x: ((side - image.size.width) / 2).rounded(),
|
||||
y: ((side - image.size.height) / 2).rounded()))
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
static func generatePlaceholderAvatarImageData(name: String, id: String, size: CGSize) -> Data? {
|
||||
let image = PlaceholderAvatarImage(name: name, contentID: id)
|
||||
|
||||
@@ -652,7 +652,7 @@ class TimelineController: TimelineControllerProtocol {
|
||||
if let avatarURL, let mediaSource = try? MediaSourceProxy(url: avatarURL, mimeType: nil) {
|
||||
// Request a generous size so the square crop of a non-square avatar keeps enough resolution.
|
||||
if case let .success(avatarData) = await mediaProvider.loadThumbnailForSource(source: mediaSource, size: .init(width: 256, height: 256)) {
|
||||
if let squareAvatarData = Avatars.squareAvatarImageData(from: avatarData) {
|
||||
if let squareAvatarData = Self.squareAvatarImageData(from: avatarData) {
|
||||
sendMessageIntent.setImage(INImage(imageData: squareAvatarData), forParameterNamed: \.speakableGroupName)
|
||||
} else {
|
||||
MXLog.error("Failed processing the room avatar for the send message intent, using a placeholder.")
|
||||
@@ -675,6 +675,35 @@ class TimelineController: TimelineControllerProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
private extension TimelineController {
|
||||
/// Media repo thumbnails are scaled, not cropped, so they keep the source's aspect
|
||||
/// ratio. The share sheet's conversation suggestions stretch the donated image to fill
|
||||
/// their circle, so centre-crop it to a square first.
|
||||
static func squareAvatarImageData(from data: Data) -> Data? {
|
||||
guard let image = UIImage(data: data) else { return nil }
|
||||
|
||||
let side = min(image.size.width, image.size.height)
|
||||
guard side > 0 else { return nil }
|
||||
|
||||
if image.size.width == image.size.height {
|
||||
return data
|
||||
}
|
||||
|
||||
let format = UIGraphicsImageRendererFormat()
|
||||
// UIImage(data:) decodes at scale 1; pin the renderer to that so the
|
||||
// output isn't silently multiplied by the device's screen scale.
|
||||
format.scale = image.scale
|
||||
|
||||
return UIGraphicsImageRenderer(size: CGSize(width: side, height: side), format: format)
|
||||
.pngData { _ in
|
||||
// Round the offsets to pixel boundaries so the crop is a straight
|
||||
// copy rather than resampling (and softening) the whole image.
|
||||
image.draw(at: CGPoint(x: ((side - image.size.width) / 2).rounded(),
|
||||
y: ((side - image.size.height) / 2).rounded()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private nonisolated extension TimelineItemProxy {
|
||||
var isItemCollapsible: Bool {
|
||||
if case let .event(eventItem) = self {
|
||||
|
||||
@@ -257,14 +257,9 @@ nonisolated struct NotificationContentBuilder {
|
||||
let image: INImage
|
||||
if !forcePlaceholder,
|
||||
let mediaSource = icon.mediaSource {
|
||||
// Request a generous size so the square crop of a non-square avatar keeps enough resolution.
|
||||
switch await mediaProvider.loadThumbnailForSource(source: mediaSource, size: .init(width: 256, height: 256)) {
|
||||
switch await mediaProvider.loadThumbnailForSource(source: mediaSource, size: .init(width: 100, height: 100)) {
|
||||
case .success(let data):
|
||||
if let squareData = Avatars.squareAvatarImageData(from: data) {
|
||||
fetchedImage = INImage(imageData: squareData)
|
||||
} else {
|
||||
MXLog.error("Couldn't decode the fetched sender icon, using a placeholder.")
|
||||
}
|
||||
fetchedImage = INImage(imageData: data)
|
||||
case .failure(let error):
|
||||
MXLog.error("Couldn't add sender icon: \(error)")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user