aboutsummaryrefslogtreecommitdiff
path: root/Hotline/macOS
diff options
context:
space:
mode:
Diffstat (limited to 'Hotline/macOS')
-rw-r--r--Hotline/macOS/AboutView.swift52
-rw-r--r--Hotline/macOS/ChatView.swift34
-rw-r--r--Hotline/macOS/ServerAgreementView.swift81
-rw-r--r--Hotline/macOS/ServerMessageView.swift26
-rw-r--r--Hotline/macOS/ServerView.swift8
-rw-r--r--Hotline/macOS/SettingsView.swift1
6 files changed, 156 insertions, 46 deletions
diff --git a/Hotline/macOS/AboutView.swift b/Hotline/macOS/AboutView.swift
index 7bd1c54..1cf7dc2 100644
--- a/Hotline/macOS/AboutView.swift
+++ b/Hotline/macOS/AboutView.swift
@@ -77,11 +77,12 @@ struct AboutView: View {
}
}
.frame(height: 40)
-// .padding(.top, 4)
Spacer()
}
- .frame(width: 270)
+ .frame(width: 250)
+
+ Spacer()
ScrollView(.vertical) {
VStack(alignment: .leading, spacing: 16) {
@@ -118,17 +119,38 @@ struct AboutView: View {
Link(destination: contributor.webURL) {
HStack {
if let pictureURL = contributor.pictureURL {
- AsyncImage(url: pictureURL) { img in
- img
- .interpolation(.high)
- .resizable()
- .scaledToFit()
- .background(.white)
- } placeholder: {
- Color.white.opacity(0.2)
+ AsyncImage(url: pictureURL) { phase in
+ if let image = phase.image {
+ image
+ .interpolation(.high)
+ .resizable()
+ .scaledToFit()
+ .background(.white)
+ .frame(width: 32, height: 32)
+ } else if phase.error != nil {
+ Color.clear
+ .frame(width: 32, height: 32)
+ } else {
+ Color.white
+ .opacity(0.2)
+ .frame(width: 32, height: 32)
+ }
}
.frame(width: 32, height: 32)
.clipShape(Circle())
+
+// AsyncImage(url: pictureURL) { img in
+// img
+// .interpolation(.high)
+// .resizable()
+// .scaledToFit()
+// .background(.white)
+// } placeholder: {
+// Color.white.opacity(0.2)
+// .frame(width: 32, height: 32)
+// }
+// .frame(width: 32, height: 32)
+// .clipShape(Circle())
}
VStack(alignment: .leading, spacing: 2) {
@@ -143,16 +165,12 @@ struct AboutView: View {
.font(.system(size: 11))
.foregroundStyle(.white.opacity(0.4))
}
-
- Spacer()
}
}
}
}
}
- .ignoresSafeArea()
.scrollClipDisabled()
- .padding(.leading, 24)
}
.frame(width: 570, height: 330)
.background(
@@ -162,7 +180,7 @@ struct AboutView: View {
Spacer()
}
.frame(height: 330 + 100)
- .offset(x: 270)
+ .offset(x: 250)
}
)
.background(Color.hotlineRed)
@@ -191,7 +209,9 @@ struct AboutView: View {
}
}
- contributors = newContributors
+ withAnimation {
+ contributors = newContributors
+ }
}
func checkForUpdate() async {
diff --git a/Hotline/macOS/ChatView.swift b/Hotline/macOS/ChatView.swift
index 98fb852..0875106 100644
--- a/Hotline/macOS/ChatView.swift
+++ b/Hotline/macOS/ChatView.swift
@@ -44,35 +44,17 @@ struct ChatView: View {
.clipShape(RoundedRectangle(cornerRadius: 3))
}
#endif
- ScrollView(.vertical) {
- HStack {
- Spacer()
- Text(msg.text.convertToAttributedStringWithLinks())
- .font(.system(size: 12))
- .fontDesign(.monospaced)
- .textSelection(.enabled)
- .tint(Color("Link Color"))
- .frame(maxWidth: 400, alignment: .center)
- .padding(16)
- Spacer()
- }
- }
- .frame(maxWidth: .infinity, maxHeight: 375)
- .scrollBounceBehavior(.basedOnSize)
-#if os(iOS)
- .background(Color("Agreement Background"))
-#elseif os(macOS)
- .background(VisualEffectView(material: .titlebar, blendingMode: .withinWindow))
-#endif
- .clipShape(RoundedRectangle(cornerRadius: 8))
- .padding(.bottom, 16)
+ ServerAgreementView(text: msg.text)
+ .padding(.bottom, 16)
}
// MARK: Server Message
else if msg.type == .server {
- Text(msg.text)
- .lineSpacing(4)
- .multilineTextAlignment(.leading)
- .textSelection(.enabled)
+ HStack {
+ Spacer()
+ ServerMessageView(message: msg.text)
+ Spacer()
+ }
+ .padding(EdgeInsets(top: 2, leading: 0, bottom: 2, trailing: 0))
}
// MARK: Status
else if msg.type == .status {
diff --git a/Hotline/macOS/ServerAgreementView.swift b/Hotline/macOS/ServerAgreementView.swift
new file mode 100644
index 0000000..a1f96d9
--- /dev/null
+++ b/Hotline/macOS/ServerAgreementView.swift
@@ -0,0 +1,81 @@
+import SwiftUI
+
+fileprivate let MAX_AGREEMENT_HEIGHT: CGFloat = 280
+
+struct ServerAgreementView: View {
+ let text: String
+
+ @State private var expandable: Bool = false
+ @State private var expanded: Bool = false
+
+ var body: some View {
+ ScrollView(.vertical) {
+ HStack(alignment: .top) {
+ Spacer()
+ Text(text.convertToAttributedStringWithLinks())
+ .font(.system(size: 12))
+ .fontDesign(.monospaced)
+ .textSelection(.enabled)
+ .tint(Color("Link Color"))
+ .frame(maxWidth: 400)
+ .padding(16)
+ .background(
+ GeometryReader { geometry in
+ Color.clear.onAppear {
+ if geometry.size.height > MAX_AGREEMENT_HEIGHT {
+ expandable = true
+ }
+ else {
+ expandable = false
+ }
+ }
+ }
+ )
+ Spacer()
+ }
+ }
+ .scrollIndicators(.never)
+ .frame(maxWidth: .infinity, maxHeight: (expandable && expanded) ? nil : MAX_AGREEMENT_HEIGHT)
+ .scrollBounceBehavior(.basedOnSize)
+#if os(iOS)
+ .background(Color("Agreement Background"))
+#elseif os(macOS)
+ .background(VisualEffectView(material: .titlebar, blendingMode: .withinWindow))
+#endif
+ .overlay(
+ ZStack(alignment: .bottomTrailing) {
+ Group {
+ if !expandable || expanded {
+ EmptyView()
+ }
+ else {
+ Button(action: {
+ withAnimation(.easeOut(duration: 0.15)) {
+ expanded = true
+ }
+ }, label: {
+ Color.black
+ .opacity(0.00001)
+ .frame(width: 32, height: 32)
+ .overlay(
+ Image(systemName: "arrow.up.left.and.arrow.down.right")
+ .resizable()
+ .scaledToFit()
+ .fontWeight(.semibold)
+ .frame(width: 12, height: 12)
+ .foregroundColor(.primary.opacity(0.8))
+ , alignment: .center)
+ })
+ .buttonStyle(.plain)
+ .help("Expand Server Agreement")
+ }
+ }
+ }
+ , alignment: .bottomTrailing)
+ .clipShape(RoundedRectangle(cornerRadius: 8))
+ }
+}
+
+#Preview {
+ ServerAgreementView(text: "Hello there and welcome to this server.")
+}
diff --git a/Hotline/macOS/ServerMessageView.swift b/Hotline/macOS/ServerMessageView.swift
new file mode 100644
index 0000000..373c2a6
--- /dev/null
+++ b/Hotline/macOS/ServerMessageView.swift
@@ -0,0 +1,26 @@
+import SwiftUI
+
+struct ServerMessageView: View {
+ let message: String
+
+ var body: some View {
+ HStack(alignment: .center, spacing: 8) {
+ Image(systemName: "exclamationmark.triangle.fill")
+ .symbolRenderingMode(.multicolor)
+ .resizable()
+ .scaledToFit()
+ .frame(width: 16, height: 16)
+ Text("**\(message)**")
+ .lineSpacing(4)
+ .multilineTextAlignment(.leading)
+ .textSelection(.enabled)
+ }
+ .padding()
+ .background(Color("Agreement Background"))
+ .clipShape(RoundedRectangle(cornerRadius: 8))
+ }
+}
+
+#Preview {
+ ServerMessageView(message: "This server has something important to say.")
+}
diff --git a/Hotline/macOS/ServerView.swift b/Hotline/macOS/ServerView.swift
index 190bcc2..21d7cbb 100644
--- a/Hotline/macOS/ServerView.swift
+++ b/Hotline/macOS/ServerView.swift
@@ -400,19 +400,19 @@ struct ServerView: View {
}
Text(user.name)
- .foregroundStyle(user.isAdmin ? Color(hex: 0xE10000) : .primary)
+ .foregroundStyle(user.isAdmin ? Color.hotlineRed : .primary)
Spacer()
if model.hasUnreadInstantMessages(userID: user.id) {
Circle()
.frame(width: 6, height: 6)
+ .foregroundStyle(user.isAdmin ? Color.hotlineRed : .primary.opacity(0.5))
.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 2))
- .opacity(0.5)
}
}
- .opacity(user.isIdle ? 0.6 : 1.0)
- .opacity(controlActiveState == .inactive ? 0.4 : 1.0)
+ .opacity(user.isIdle ? 0.5 : 1.0)
+ .opacity(controlActiveState == .inactive ? 0.5 : 1.0)
.tag(ServerNavigationType.user(userID: user.id))
}
}
diff --git a/Hotline/macOS/SettingsView.swift b/Hotline/macOS/SettingsView.swift
index 24cfddf..79f0156 100644
--- a/Hotline/macOS/SettingsView.swift
+++ b/Hotline/macOS/SettingsView.swift
@@ -71,6 +71,7 @@ struct IconSettingsView: View {
.interpolation(.none)
.scaledToFit()
.frame(width: 32, height: 16)
+ .help("Icon \(String(iconID))")
}
.tag(iconID)
.frame(width: 32, height: 32)