aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2024-05-02 18:53:56 -0700
committerDustin Mierau <dustin@mierau.me>2024-05-02 18:53:56 -0700
commit73208d70d21db7e526e371fa863acd0327caad9e (patch)
treea93bed8633077e77a576e65f14244c82a32868bb
parent480500a3e7cfe1e2aa8ff261ca6f9e522c3aaf4c (diff)
Add link highlighting to agreements and message board. Add basic markdown styling and link highlighting to chat messages.
-rw-r--r--Hotline.xcodeproj/project.pbxproj14
-rw-r--r--Hotline/Assets.xcassets/Link Color.colorset/Contents.json10
-rw-r--r--Hotline/Shared/AsyncLinkPreview.swift57
-rw-r--r--Hotline/Shared/FileImageView.swift (renamed from Hotline/Shared/AnimatedImageView.swift)2
-rw-r--r--Hotline/Utility/FoundationExtensions.swift43
-rw-r--r--Hotline/macOS/ChatView.swift173
-rw-r--r--Hotline/macOS/FilePreviewImageView.swift2
7 files changed, 210 insertions, 91 deletions
diff --git a/Hotline.xcodeproj/project.pbxproj b/Hotline.xcodeproj/project.pbxproj
index bafcc98..3bd7edb 100644
--- a/Hotline.xcodeproj/project.pbxproj
+++ b/Hotline.xcodeproj/project.pbxproj
@@ -23,6 +23,7 @@
DA4930BD2B4F8DD700822D0B /* NetSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4930BC2B4F8DD700822D0B /* NetSocket.swift */; };
DA4F2BF82B16A17200D8ADDC /* HotlineProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4F2BF72B16A17200D8ADDC /* HotlineProtocol.swift */; };
DA4F2C012B1A558E00D8ADDC /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4F2C002B1A558E00D8ADDC /* ChatView.swift */; platformFilter = ios; };
+ DA55AC732BE42AF000034857 /* AsyncLinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA55AC722BE42AF000034857 /* AsyncLinkPreview.swift */; platformFilters = (macos, ); };
DA5753682B33E88A00FAC277 /* HotlineFileClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA5753672B33E88A00FAC277 /* HotlineFileClient.swift */; };
DA57536C2B36BA1D00FAC277 /* TextDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA57536B2B36BA1D00FAC277 /* TextDocument.swift */; };
DA6300972B24036B0034CBFD /* HotlineClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA6300962B24036B0034CBFD /* HotlineClient.swift */; };
@@ -32,7 +33,7 @@
DA77253F2B21176D006C5ABB /* NewsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA77253E2B21176D006C5ABB /* NewsView.swift */; platformFilter = ios; };
DA7725412B21435B006C5ABB /* ObservableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA7725402B21435B006C5ABB /* ObservableScrollView.swift */; };
DA872B132BDDBF78008B1012 /* HotlinePanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA872B122BDDBF78008B1012 /* HotlinePanel.swift */; platformFilters = (macos, ); };
- DA872B152BDDEE1A008B1012 /* VisualEffectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA872B142BDDEE1A008B1012 /* VisualEffectView.swift */; };
+ DA872B152BDDEE1A008B1012 /* VisualEffectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA872B142BDDEE1A008B1012 /* VisualEffectView.swift */; platformFilters = (macos, ); };
DA9CAFBB2B126D5700CDA197 /* Application-macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9CAFBA2B126D5700CDA197 /* Application-macOS.swift */; platformFilters = (macos, ); };
DA9CAFBD2B126D5700CDA197 /* TrackerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9CAFBC2B126D5700CDA197 /* TrackerView.swift */; platformFilter = ios; };
DA9CAFC12B126D5800CDA197 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA9CAFC02B126D5800CDA197 /* Assets.xcassets */; };
@@ -41,7 +42,7 @@
DAAEE66B2B3FBC2100A5BA07 /* TransferInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAAEE66A2B3FBC2100A5BA07 /* TransferInfo.swift */; };
DAAEE66D2B475F1400A5BA07 /* PreviewFileInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAAEE66C2B475F1400A5BA07 /* PreviewFileInfo.swift */; };
DAAEE66F2B47625600A5BA07 /* FilePreviewImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAAEE66E2B47625600A5BA07 /* FilePreviewImageView.swift */; platformFilters = (macos, ); };
- DAB4D87B2B4B78310048A05C /* AnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB4D87A2B4B78310048A05C /* AnimatedImageView.swift */; platformFilters = (macos, ); };
+ DAB4D87B2B4B78310048A05C /* FileImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB4D87A2B4B78310048A05C /* FileImageView.swift */; platformFilters = (macos, ); };
DAB4D87E2B4C8BCA0048A05C /* FilePreviewTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB4D87D2B4C8BCA0048A05C /* FilePreviewTextView.swift */; platformFilters = (macos, ); };
DAB4D8802B4C8E9A0048A05C /* URLAdditions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB4D87F2B4C8E9A0048A05C /* URLAdditions.swift */; };
DAB4D8822B4C8FED0048A05C /* FileIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB4D8812B4C8FED0048A05C /* FileIconView.swift */; };
@@ -94,6 +95,7 @@
DA4930BC2B4F8DD700822D0B /* NetSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetSocket.swift; sourceTree = "<group>"; };
DA4F2BF72B16A17200D8ADDC /* HotlineProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotlineProtocol.swift; sourceTree = "<group>"; };
DA4F2C002B1A558E00D8ADDC /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = "<group>"; };
+ DA55AC722BE42AF000034857 /* AsyncLinkPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncLinkPreview.swift; sourceTree = "<group>"; };
DA5753672B33E88A00FAC277 /* HotlineFileClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotlineFileClient.swift; sourceTree = "<group>"; };
DA57536B2B36BA1D00FAC277 /* TextDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextDocument.swift; sourceTree = "<group>"; };
DA6300962B24036B0034CBFD /* HotlineClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HotlineClient.swift; sourceTree = "<group>"; };
@@ -112,7 +114,7 @@
DAAEE66A2B3FBC2100A5BA07 /* TransferInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferInfo.swift; sourceTree = "<group>"; };
DAAEE66C2B475F1400A5BA07 /* PreviewFileInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewFileInfo.swift; sourceTree = "<group>"; };
DAAEE66E2B47625600A5BA07 /* FilePreviewImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreviewImageView.swift; sourceTree = "<group>"; };
- DAB4D87A2B4B78310048A05C /* AnimatedImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedImageView.swift; sourceTree = "<group>"; };
+ DAB4D87A2B4B78310048A05C /* FileImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileImageView.swift; sourceTree = "<group>"; };
DAB4D87D2B4C8BCA0048A05C /* FilePreviewTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreviewTextView.swift; sourceTree = "<group>"; };
DAB4D87F2B4C8E9A0048A05C /* URLAdditions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLAdditions.swift; sourceTree = "<group>"; };
DAB4D8812B4C8FED0048A05C /* FileIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileIconView.swift; sourceTree = "<group>"; };
@@ -220,13 +222,14 @@
DAB4D87C2B4B783A0048A05C /* Shared */ = {
isa = PBXGroup;
children = (
- DAB4D87A2B4B78310048A05C /* AnimatedImageView.swift */,
+ DAB4D87A2B4B78310048A05C /* FileImageView.swift */,
DAB4D8812B4C8FED0048A05C /* FileIconView.swift */,
DAB4D8832B4CABEF0048A05C /* DataAdditions.swift */,
DAB4D87F2B4C8E9A0048A05C /* URLAdditions.swift */,
DA4930BC2B4F8DD700822D0B /* NetSocket.swift */,
DA872B122BDDBF78008B1012 /* HotlinePanel.swift */,
DA872B142BDDEE1A008B1012 /* VisualEffectView.swift */,
+ DA55AC722BE42AF000034857 /* AsyncLinkPreview.swift */,
);
path = Shared;
sourceTree = "<group>";
@@ -426,7 +429,8 @@
DAE136BA2B9D1147007D8307 /* HotlinePanelView.swift in Sources */,
11A726082BE0672A000C1DA7 /* FileDetails.swift in Sources */,
DA9CAFBD2B126D5700CDA197 /* TrackerView.swift in Sources */,
- DAB4D87B2B4B78310048A05C /* AnimatedImageView.swift in Sources */,
+ DAB4D87B2B4B78310048A05C /* FileImageView.swift in Sources */,
+ DA55AC732BE42AF000034857 /* AsyncLinkPreview.swift in Sources */,
DAE735032B30C0BB000C56F6 /* MessageView.swift in Sources */,
DABE8C062B57A06100884D28 /* Bookmarks.swift in Sources */,
DA32CD4B2B29318E0053B98B /* FileInfo.swift in Sources */,
diff --git a/Hotline/Assets.xcassets/Link Color.colorset/Contents.json b/Hotline/Assets.xcassets/Link Color.colorset/Contents.json
index 4373edf..e1d527b 100644
--- a/Hotline/Assets.xcassets/Link Color.colorset/Contents.json
+++ b/Hotline/Assets.xcassets/Link Color.colorset/Contents.json
@@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
- "blue" : "0xF1",
- "green" : "0x61",
- "red" : "0x39"
+ "blue" : "0xFF",
+ "green" : "0x86",
+ "red" : "0x1F"
}
},
"idiom" : "universal"
@@ -24,8 +24,8 @@
"components" : {
"alpha" : "1.000",
"blue" : "0xFF",
- "green" : "0xA3",
- "red" : "0x8A"
+ "green" : "0xB0",
+ "red" : "0x6C"
}
},
"idiom" : "universal"
diff --git a/Hotline/Shared/AsyncLinkPreview.swift b/Hotline/Shared/AsyncLinkPreview.swift
new file mode 100644
index 0000000..9f0c4c2
--- /dev/null
+++ b/Hotline/Shared/AsyncLinkPreview.swift
@@ -0,0 +1,57 @@
+import SwiftUI
+import LinkPresentation
+
+fileprivate class CustomLinkView: LPLinkView {
+ override var intrinsicContentSize: CGSize { CGSize(width: 0, height: super.intrinsicContentSize.height) }
+}
+
+struct AsyncLinkPreview: View {
+ @State private var metadata: LPLinkMetadata?
+ @State private var isLoading = true
+ let url: URL?
+
+ func fetchMetadata() async {
+ guard let url else {
+ self.isLoading = false
+ return
+ }
+ do {
+ let provider = LPMetadataProvider()
+ let metadata = try await provider.startFetchingMetadata(for: url)
+ self.metadata = metadata
+ self.isLoading = false
+ } catch {
+ self.isLoading = false
+ }
+ }
+
+ var body: some View {
+ if isLoading {
+ ProgressView()
+ .controlSize(.small)
+ .task {
+ await self.fetchMetadata()
+ }
+ } else if let metadata = metadata {
+ LinkView(metadata: metadata)
+ .frame(width: 200)
+ } else {
+ Text(LocalizedStringKey(url!.absoluteString.convertLinksToMarkdown()))
+ .multilineTextAlignment(.leading)
+ .tint(Color("Link Color"))
+ }
+ }
+}
+
+struct LinkView: NSViewRepresentable {
+ var metadata: LPLinkMetadata
+
+ func makeNSView(context: Context) -> LPLinkView {
+ let linkView = CustomLinkView(metadata: metadata)
+ return linkView
+ }
+
+ func updateNSView(_ nsView: LPLinkView, context: Context) {
+ // Nothing required
+ }
+}
diff --git a/Hotline/Shared/AnimatedImageView.swift b/Hotline/Shared/FileImageView.swift
index 0d92715..0cc50f1 100644
--- a/Hotline/Shared/AnimatedImageView.swift
+++ b/Hotline/Shared/FileImageView.swift
@@ -1,6 +1,6 @@
import SwiftUI
-struct AnimatedImageView: NSViewRepresentable {
+struct FileImageView: NSViewRepresentable {
var image: NSImage?
let minimumSize: CGSize = CGSize(width: 350, height: 350)
diff --git a/Hotline/Utility/FoundationExtensions.swift b/Hotline/Utility/FoundationExtensions.swift
index f2cd39c..9ad0d8b 100644
--- a/Hotline/Utility/FoundationExtensions.swift
+++ b/Hotline/Utility/FoundationExtensions.swift
@@ -6,17 +6,54 @@ enum Endianness {
}
extension String {
+ func convertToAttributedStringWithLinks(relaxed: Bool = false) -> AttributedString {
+ let attributedString: NSMutableAttributedString = NSMutableAttributedString(string: self)
+ let urlPattern = relaxed ?
+ #"(hotline|http|https)?(://)?[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?"# :
+ #"(hotline|http|https)://[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?"#
+
+ guard let regex = try? NSRegularExpression(pattern: urlPattern, options: .caseInsensitive) else {
+ return AttributedString(attributedString)
+ }
+
+ regex.enumerateMatches(in: self, range: NSMakeRange(0, self.count)) { (result: NSTextCheckingResult!, _, _) in
+ let range = result.range
+ if let newRange = Range(result.range, in: self) {
+ let str = String(self[newRange])
+ attributedString.addAttribute(.link, value: str, range: result.range)
+ }
+ }
+
+ return AttributedString(attributedString)
+ }
+
+ func isWebURL() -> Bool {
+ guard let url = URL(string: self) else {
+ return false
+ }
+ switch url.scheme?.lowercased() {
+ case "http", "https":
+ return true
+ default:
+ return false
+ }
+ }
+
func isImageURL() -> Bool {
guard let url = URL(string: self) else {
return false
}
- let validImageExtensions = ["jpg", "jpeg", "png", "gif", "bmp", "tiff", "webp"]
- return validImageExtensions.contains(url.pathExtension.lowercased())
+ switch url.pathExtension.lowercased() {
+ case "jpg", "jpeg", "png", "gif":
+ return true
+ default:
+ return false
+ }
}
func convertLinksToMarkdown() -> String {
- let urlPattern = #"https?://[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?"#
+ let urlPattern = #"(hotline|http|https)?(://)?[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?"#
guard let regex = try? NSRegularExpression(pattern: urlPattern, options: .caseInsensitive) else {
return self
diff --git a/Hotline/macOS/ChatView.swift b/Hotline/macOS/ChatView.swift
index 57814e2..35ff28e 100644
--- a/Hotline/macOS/ChatView.swift
+++ b/Hotline/macOS/ChatView.swift
@@ -24,20 +24,19 @@ struct ChatView: View {
var body: some View {
NavigationStack {
ScrollViewReader { reader in
-
+
VStack(alignment: .leading, spacing: 0) {
// MARK: Scroll View
GeometryReader { gm in
ScrollView(.vertical) {
LazyVStack(alignment: .leading) {
-
+
ForEach(model.chat) { msg in
// MARK: Agreement
if msg.type == .agreement {
- VStack(alignment: .center, spacing: 16) {
- #if os(iOS)
+#if os(iOS)
if let bannerImage = self.model.bannerImage {
Image(uiImage: bannerImage)
.resizable()
@@ -45,35 +44,29 @@ struct ChatView: View {
.frame(maxWidth: 468.0)
.clipShape(RoundedRectangle(cornerRadius: 3))
}
- #endif
- HStack(spacing: 0) {
- Spacer()
-
- ScrollView(.vertical) {
- HStack {
- Text(LocalizedStringKey(msg.text.convertLinksToMarkdown()))
- .font(.system(size: 12))
- .fontDesign(.monospaced)
- .textSelection(.enabled)
- .tint(Color("Link Color"))
- Spacer()
- }
- .padding(16)
+#endif
+ ScrollView(.vertical) {
+ HStack {
+ Spacer()
+ Text(msg.text.convertToAttributedStringWithLinks(relaxed: false))
+ .font(.system(size: 12))
+ .fontDesign(.monospaced)
+ .textSelection(.enabled)
+ .tint(Color("Link Color"))
+ .frame(maxWidth: 400, alignment: .center)
+ .padding(16)
+ Spacer()
}
- .scrollBounceBehavior(.basedOnSize)
- .frame(maxWidth: 468, maxHeight: 375)
-
- Spacer()
}
- #if os(iOS)
+ .frame(maxWidth: .infinity, maxHeight: 375)
+ .scrollBounceBehavior(.basedOnSize)
+#if os(iOS)
.background(Color("Agreement Background"))
- #elseif os(macOS)
+#elseif os(macOS)
.background(VisualEffectView(material: .titlebar, blendingMode: .withinWindow))
- #endif
+#endif
.clipShape(RoundedRectangle(cornerRadius: 8))
- }
- .frame(maxWidth: .infinity)
- .padding()
+ .padding(.bottom, 16)
}
// MARK: Status
else if msg.type == .status {
@@ -86,16 +79,49 @@ struct ChatView: View {
.opacity(0.3)
Spacer()
}
- .padding()
+ .padding(EdgeInsets(top: 2, leading: 0, bottom: 2, trailing: 0))
}
else {
HStack(alignment: .firstTextBaseline) {
if let username = msg.username {
- Text(LocalizedStringKey("**\(username):** \(msg.text)".convertLinksToMarkdown()))
- .lineSpacing(4)
- .multilineTextAlignment(.leading)
- .textSelection(.enabled)
- .tint(Color("Link Color"))
+// if msg.text.isImageURL() {
+// HStack(alignment: .bottom) {
+// Text("**\(username):** ")
+//
+// let imageURL = URL(string: msg.text)!
+// AsyncImage(url: imageURL) { phase in
+// switch phase {
+// case .failure:
+// Text(LocalizedStringKey(msg.text.convertLinksToMarkdown()))
+// .lineSpacing(4)
+// .multilineTextAlignment(.leading)
+// .textSelection(.enabled)
+// .tint(Color("Link Color"))
+// case .success(let img):
+// Link(destination: imageURL) {
+// img
+// .resizable()
+// .scaledToFit()
+// .frame(maxWidth: 250, maxHeight: 150, alignment: .leading)
+// .onAppear {
+// reader.scrollTo(bottomID, anchor: .bottom)
+// }
+// }
+// default:
+// ProgressView().controlSize(.small)
+// }
+// }
+//
+// Spacer()
+// }
+// }
+// else {
+ Text(LocalizedStringKey("**\(username):** \(msg.text)".convertLinksToMarkdown()))
+ .lineSpacing(4)
+ .multilineTextAlignment(.leading)
+ .textSelection(.enabled)
+ .tint(Color("Link Color"))
+// }
}
else {
Text(LocalizedStringKey(msg.text.convertLinksToMarkdown()))
@@ -106,68 +132,63 @@ struct ChatView: View {
}
Spacer()
}
- .padding(EdgeInsets(top: 4, leading: 16, bottom: 4, trailing: 16))
+ .padding(EdgeInsets(top: 2, leading: 0, bottom: 2, trailing: 0))
}
}
EmptyView().id(bottomID)
}
- // .padding(.bottom, 12)
+ .padding()
}
- // .padding(.bottom, 60)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.defaultScrollAnchor(.bottom)
.onChange(of: model.chat.count) {
-// withAnimation {
reader.scrollTo(bottomID, anchor: .bottom)
-// }
}
.onAppear {
reader.scrollTo(bottomID, anchor: .bottom)
-// focusedField = .chatInput
}
.onChange(of: gm.size) {
reader.scrollTo(bottomID, anchor: .bottom)
}
}
- }
-
- // MARK: Input Divider
- Divider()
- .padding([.top, .bottom], 0)
-
- // MARK: Input Bar
- HStack(alignment: .lastTextBaseline, spacing: 0) {
- TextField("", text: $input, axis: .vertical)
- .focused($focusedField, equals: .chatInput)
- .textFieldStyle(.plain)
- .lineLimit(1...5)
- .multilineTextAlignment(.leading)
-// .frame(maxWidth: .infinity)
- .onSubmit {
- if !self.input.isEmpty {
- model.sendChat(self.input)
+
+ // MARK: Input Divider
+ Divider()
+
+ // MARK: Input Bar
+ HStack(alignment: .lastTextBaseline, spacing: 0) {
+ TextField("", text: $input, axis: .vertical)
+ .focused($focusedField, equals: .chatInput)
+ .textFieldStyle(.plain)
+ .lineLimit(1...5)
+ .multilineTextAlignment(.leading)
+ // .frame(maxWidth: .infinity)
+ .onSubmit {
+ if !self.input.isEmpty {
+ model.sendChat(self.input)
+ }
+ self.input = ""
}
- self.input = ""
+ .frame(maxWidth: .infinity)
+ .padding()
+ }
+ .frame(maxWidth: .infinity, minHeight: 28)
+ .padding(EdgeInsets(top: 4, leading: 16, bottom: 4, trailing: 16))
+ .overlay(alignment: .leadingLastTextBaseline) {
+ Image(systemName: "chevron.right").opacity(0.4).offset(x: 16)
+ }
+ .onContinuousHover { phase in
+ switch phase {
+ case .active(_):
+ NSCursor.iBeam.set()
+ case .ended:
+ NSCursor.arrow.set()
+ break
}
- .frame(maxWidth: .infinity)
- .padding()
- }
- .frame(maxWidth: .infinity, minHeight: 28)
- .padding(EdgeInsets(top: 0, leading: 16, bottom: 8, trailing: 16))
- .overlay(alignment: .leadingLastTextBaseline) {
- Image(systemName: "chevron.right").opacity(0.4).offset(x: 16)
- }
- .onContinuousHover { phase in
- switch phase {
- case .active(_):
- NSCursor.iBeam.set()
- case .ended:
- NSCursor.arrow.set()
- break
}
- }
- .onTapGesture {
- focusedField = .chatInput
+ .onTapGesture {
+ focusedField = .chatInput
+ }
}
}
}
diff --git a/Hotline/macOS/FilePreviewImageView.swift b/Hotline/macOS/FilePreviewImageView.swift
index 461f5a4..ae9a825 100644
--- a/Hotline/macOS/FilePreviewImageView.swift
+++ b/Hotline/macOS/FilePreviewImageView.swift
@@ -31,7 +31,7 @@ struct FilePreviewImageView: View {
}
else {
if let image = preview?.image {
- AnimatedImageView(image: image)
+ FileImageView(image: image)
.frame(minWidth: 200, maxWidth: .infinity, minHeight: 200, maxHeight: .infinity)
}
else {