Show individual attachments uncropped inline in statuses
This commit is contained in:
parent
15a7cd5f65
commit
16cd045588
|
@ -14,7 +14,7 @@ extension CollapseState {
|
||||||
func resolveFor(status: StatusMO, height: CGFloat, textLength: Int? = nil) {
|
func resolveFor(status: StatusMO, height: CGFloat, textLength: Int? = nil) {
|
||||||
let longEnoughToCollapse: Bool
|
let longEnoughToCollapse: Bool
|
||||||
if Preferences.shared.collapseLongPosts,
|
if Preferences.shared.collapseLongPosts,
|
||||||
height > 500 || (textLength != nil && textLength! > 500) {
|
height > 600 || (textLength != nil && textLength! > 500) {
|
||||||
longEnoughToCollapse = true
|
longEnoughToCollapse = true
|
||||||
} else {
|
} else {
|
||||||
longEnoughToCollapse = false
|
longEnoughToCollapse = false
|
||||||
|
|
|
@ -61,6 +61,7 @@ class Preferences: Codable, ObservableObject {
|
||||||
}
|
}
|
||||||
self.blurMediaBehindContentWarning = try container.decodeIfPresent(Bool.self, forKey: .blurMediaBehindContentWarning) ?? true
|
self.blurMediaBehindContentWarning = try container.decodeIfPresent(Bool.self, forKey: .blurMediaBehindContentWarning) ?? true
|
||||||
self.automaticallyPlayGifs = try container.decode(Bool.self, forKey: .automaticallyPlayGifs)
|
self.automaticallyPlayGifs = try container.decode(Bool.self, forKey: .automaticallyPlayGifs)
|
||||||
|
self.showUncroppedMediaInline = try container.decodeIfPresent(Bool.self, forKey: .showUncroppedMediaInline) ?? true
|
||||||
|
|
||||||
self.openLinksInApps = try container.decode(Bool.self, forKey: .openLinksInApps)
|
self.openLinksInApps = try container.decode(Bool.self, forKey: .openLinksInApps)
|
||||||
self.useInAppSafari = try container.decode(Bool.self, forKey: .useInAppSafari)
|
self.useInAppSafari = try container.decode(Bool.self, forKey: .useInAppSafari)
|
||||||
|
@ -108,6 +109,7 @@ class Preferences: Codable, ObservableObject {
|
||||||
try container.encode(attachmentBlurMode, forKey: .attachmentBlurMode)
|
try container.encode(attachmentBlurMode, forKey: .attachmentBlurMode)
|
||||||
try container.encode(blurMediaBehindContentWarning, forKey: .blurMediaBehindContentWarning)
|
try container.encode(blurMediaBehindContentWarning, forKey: .blurMediaBehindContentWarning)
|
||||||
try container.encode(automaticallyPlayGifs, forKey: .automaticallyPlayGifs)
|
try container.encode(automaticallyPlayGifs, forKey: .automaticallyPlayGifs)
|
||||||
|
try container.encode(showUncroppedMediaInline, forKey: .showUncroppedMediaInline)
|
||||||
|
|
||||||
try container.encode(openLinksInApps, forKey: .openLinksInApps)
|
try container.encode(openLinksInApps, forKey: .openLinksInApps)
|
||||||
try container.encode(useInAppSafari, forKey: .useInAppSafari)
|
try container.encode(useInAppSafari, forKey: .useInAppSafari)
|
||||||
|
@ -163,6 +165,7 @@ class Preferences: Codable, ObservableObject {
|
||||||
}
|
}
|
||||||
@Published var blurMediaBehindContentWarning = true
|
@Published var blurMediaBehindContentWarning = true
|
||||||
@Published var automaticallyPlayGifs = true
|
@Published var automaticallyPlayGifs = true
|
||||||
|
@Published var showUncroppedMediaInline = true
|
||||||
|
|
||||||
// MARK: Behavior
|
// MARK: Behavior
|
||||||
@Published var openLinksInApps = true
|
@Published var openLinksInApps = true
|
||||||
|
@ -213,6 +216,7 @@ class Preferences: Codable, ObservableObject {
|
||||||
case attachmentBlurMode
|
case attachmentBlurMode
|
||||||
case blurMediaBehindContentWarning
|
case blurMediaBehindContentWarning
|
||||||
case automaticallyPlayGifs
|
case automaticallyPlayGifs
|
||||||
|
case showUncroppedMediaInline
|
||||||
|
|
||||||
case openLinksInApps
|
case openLinksInApps
|
||||||
case useInAppSafari
|
case useInAppSafari
|
||||||
|
|
|
@ -37,6 +37,10 @@ struct MediaPrefsView: View {
|
||||||
Toggle(isOn: $preferences.automaticallyPlayGifs) {
|
Toggle(isOn: $preferences.automaticallyPlayGifs) {
|
||||||
Text("Automatically Play GIFs")
|
Text("Automatically Play GIFs")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Toggle(isOn: $preferences.showUncroppedMediaInline) {
|
||||||
|
Text("Show Uncropped Media Inline")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,17 +141,20 @@ class AttachmentView: GIFImageView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func blurHashSize() -> CGSize {
|
var attachmentAspectRatio: CGFloat? {
|
||||||
if let meta = self.attachment.meta {
|
if let meta = self.attachment.meta {
|
||||||
let aspectRatio: CGFloat
|
|
||||||
if let width = meta.width, let height = meta.height {
|
if let width = meta.width, let height = meta.height {
|
||||||
aspectRatio = CGFloat(width) / CGFloat(height)
|
return CGFloat(width) / CGFloat(height)
|
||||||
} else if let orig = meta.original,
|
} else if let orig = meta.original,
|
||||||
let width = orig.width, let height = orig.height {
|
let width = orig.width, let height = orig.height {
|
||||||
aspectRatio = CGFloat(width) / CGFloat(height)
|
return CGFloat(width) / CGFloat(height)
|
||||||
} else {
|
|
||||||
return CGSize(width: 32, height: 32)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func blurHashSize() -> CGSize {
|
||||||
|
if let aspectRatio = attachmentAspectRatio {
|
||||||
if aspectRatio > 1 {
|
if aspectRatio > 1 {
|
||||||
return CGSize(width: 32, height: 32 / aspectRatio)
|
return CGSize(width: 32, height: 32 / aspectRatio)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -21,6 +21,7 @@ class AttachmentsContainerView: UIView {
|
||||||
let attachmentViews: NSHashTable<AttachmentView> = .weakObjects()
|
let attachmentViews: NSHashTable<AttachmentView> = .weakObjects()
|
||||||
let attachmentStacks: NSHashTable<UIStackView> = .weakObjects()
|
let attachmentStacks: NSHashTable<UIStackView> = .weakObjects()
|
||||||
var moreView: UIView?
|
var moreView: UIView?
|
||||||
|
private var aspectRatioConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
var blurView: UIVisualEffectView?
|
var blurView: UIVisualEffectView?
|
||||||
var hideButtonView: UIVisualEffectView?
|
var hideButtonView: UIVisualEffectView?
|
||||||
|
@ -78,6 +79,8 @@ class AttachmentsContainerView: UIView {
|
||||||
if attachments.count > 0 {
|
if attachments.count > 0 {
|
||||||
self.isHidden = false
|
self.isHidden = false
|
||||||
|
|
||||||
|
var aspectRatio: CGFloat = 16/9
|
||||||
|
|
||||||
switch attachments.count {
|
switch attachments.count {
|
||||||
case 1:
|
case 1:
|
||||||
let attachmentView = createAttachmentView(index: 0, hSize: .full, vSize: .full)
|
let attachmentView = createAttachmentView(index: 0, hSize: .full, vSize: .full)
|
||||||
|
@ -86,6 +89,9 @@ class AttachmentsContainerView: UIView {
|
||||||
fillView(attachmentView)
|
fillView(attachmentView)
|
||||||
sendSubviewToBack(attachmentView)
|
sendSubviewToBack(attachmentView)
|
||||||
accessibilityElements.append(attachmentView)
|
accessibilityElements.append(attachmentView)
|
||||||
|
if let attachmentAspectRatio = attachmentView.attachmentAspectRatio {
|
||||||
|
aspectRatio = attachmentAspectRatio
|
||||||
|
}
|
||||||
case 2:
|
case 2:
|
||||||
let left = createAttachmentView(index: 0, hSize: .half, vSize: .full)
|
let left = createAttachmentView(index: 0, hSize: .half, vSize: .full)
|
||||||
left.layer.cornerRadius = 5
|
left.layer.cornerRadius = 5
|
||||||
|
@ -242,7 +248,19 @@ class AttachmentsContainerView: UIView {
|
||||||
accessibilityElements.append(topRight)
|
accessibilityElements.append(topRight)
|
||||||
accessibilityElements.append(bottomLeft)
|
accessibilityElements.append(bottomLeft)
|
||||||
accessibilityElements.append(moreView)
|
accessibilityElements.append(moreView)
|
||||||
|
}
|
||||||
|
|
||||||
|
if Preferences.shared.showUncroppedMediaInline {
|
||||||
|
if aspectRatioConstraint?.multiplier != aspectRatio {
|
||||||
|
aspectRatioConstraint?.isActive = false
|
||||||
|
aspectRatioConstraint = widthAnchor.constraint(equalTo: heightAnchor, multiplier: aspectRatio)
|
||||||
|
aspectRatioConstraint!.isActive = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if aspectRatioConstraint == nil {
|
||||||
|
aspectRatioConstraint = widthAnchor.constraint(equalTo: heightAnchor, multiplier: 16/9)
|
||||||
|
aspectRatioConstraint!.isActive = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.isHidden = true
|
self.isHidden = true
|
||||||
|
|
|
@ -104,9 +104,6 @@
|
||||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IF9-9U-Gk0" customClass="AttachmentsContainerView" customModule="Tusker" customModuleProvider="target">
|
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IF9-9U-Gk0" customClass="AttachmentsContainerView" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="128.5" width="343" height="0.0"/>
|
<rect key="frame" x="0.0" y="128.5" width="343" height="0.0"/>
|
||||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" secondItem="IF9-9U-Gk0" secondAttribute="width" multiplier="9:16" priority="999" id="5oh-eK-J5d"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
</view>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TLv-Xu-tT1" customClass="StatusPollView" customModule="Tusker" customModuleProvider="target">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TLv-Xu-tT1" customClass="StatusPollView" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="132.5" width="343" height="39.5"/>
|
<rect key="frame" x="0.0" y="132.5" width="343" height="39.5"/>
|
||||||
|
|
|
@ -107,7 +107,7 @@ extension StatusCollectionViewCell {
|
||||||
if statusState.unknown {
|
if statusState.unknown {
|
||||||
// layout so that we can take the content height into consideration when deciding whether to collapse
|
// layout so that we can take the content height into consideration when deciding whether to collapse
|
||||||
layoutIfNeeded()
|
layoutIfNeeded()
|
||||||
statusState.resolveFor(status: status, height: contentContainer.contentTextView.bounds.height)
|
statusState.resolveFor(status: status, height: contentContainer.visibleSubviewHeight)
|
||||||
if statusState.collapsible! && showStatusAutomatically {
|
if statusState.collapsible! && showStatusAutomatically {
|
||||||
statusState.collapsed = false
|
statusState.collapsed = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,11 +24,7 @@ class StatusContentContainer: UIView {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
let attachmentsView = AttachmentsContainerView().configure {
|
let attachmentsView = AttachmentsContainerView()
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
$0.heightAnchor.constraint(equalTo: $0.widthAnchor, multiplier: 9/16),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
let pollView = StatusPollView()
|
let pollView = StatusPollView()
|
||||||
|
|
||||||
|
@ -44,6 +40,10 @@ class StatusContentContainer: UIView {
|
||||||
|
|
||||||
private var isCollapsed = false
|
private var isCollapsed = false
|
||||||
|
|
||||||
|
var visibleSubviewHeight: CGFloat {
|
||||||
|
subviews.filter { !$0.isHidden }.map(\.bounds.height).reduce(0, +)
|
||||||
|
}
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21225" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21207"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
@ -132,9 +132,6 @@
|
||||||
<view hidden="YES" contentMode="scaleToFill" verticalCompressionResistancePriority="1" translatesAutoresizingMaskIntoConstraints="NO" id="nbq-yr-2mA" customClass="AttachmentsContainerView" customModule="Tusker" customModuleProvider="target">
|
<view hidden="YES" contentMode="scaleToFill" verticalCompressionResistancePriority="1" translatesAutoresizingMaskIntoConstraints="NO" id="nbq-yr-2mA" customClass="AttachmentsContainerView" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="171.5" width="277" height="0.0"/>
|
<rect key="frame" x="0.0" y="171.5" width="277" height="0.0"/>
|
||||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" secondItem="nbq-yr-2mA" secondAttribute="width" multiplier="9:16" priority="999" id="Rvt-zs-fkd"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
</view>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="x3b-Zl-9F0" customClass="StatusPollView" customModule="Tusker" customModuleProvider="target">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="x3b-Zl-9F0" customClass="StatusPollView" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="173.5" width="277" height="0.0"/>
|
<rect key="frame" x="0.0" y="173.5" width="277" height="0.0"/>
|
||||||
|
|
Loading…
Reference in New Issue