latest updates
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import SwiftUI
|
||||
|
||||
struct FlowLayout: Layout {
|
||||
var spacing: CGFloat = 8
|
||||
|
||||
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
|
||||
let width = proposal.width ?? .infinity
|
||||
var x: CGFloat = 0, y: CGFloat = 0, rowHeight: CGFloat = 0
|
||||
for view in subviews {
|
||||
let size = view.sizeThatFits(.unspecified)
|
||||
if x + size.width > width, x > 0 {
|
||||
x = 0
|
||||
y += rowHeight + spacing
|
||||
rowHeight = 0
|
||||
}
|
||||
x += size.width + spacing
|
||||
rowHeight = max(rowHeight, size.height)
|
||||
}
|
||||
return CGSize(width: width.isFinite ? width : x, height: y + rowHeight)
|
||||
}
|
||||
|
||||
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
|
||||
var x = bounds.minX, y = bounds.minY, rowHeight: CGFloat = 0
|
||||
for view in subviews {
|
||||
let size = view.sizeThatFits(.unspecified)
|
||||
if x + size.width > bounds.maxX, x > bounds.minX {
|
||||
x = bounds.minX
|
||||
y += rowHeight + spacing
|
||||
rowHeight = 0
|
||||
}
|
||||
view.place(at: CGPoint(x: x, y: y), proposal: ProposedViewSize(size))
|
||||
x += size.width + spacing
|
||||
rowHeight = max(rowHeight, size.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import SwiftUI
|
||||
|
||||
struct PathField: View {
|
||||
let title: String
|
||||
@Binding var path: String
|
||||
var canBrowse: Bool = true
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(title).font(.headline)
|
||||
HStack {
|
||||
TextField(title, text: $path)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
if canBrowse {
|
||||
Button("Choose…") {
|
||||
if let selected = FilePicker.chooseDirectory() { path = selected }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import SwiftUI
|
||||
|
||||
struct SplashView: View {
|
||||
@State private var animate = false
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
LinearGradient(
|
||||
colors: [Color.accentColor.opacity(0.95), Color.accentColor.opacity(0.62), Color(nsColor: .windowBackgroundColor)],
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
|
||||
VStack(spacing: 22) {
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: 30, style: .continuous)
|
||||
.fill(.ultraThinMaterial)
|
||||
.frame(width: 126, height: 126)
|
||||
.shadow(color: .black.opacity(0.18), radius: 28, y: 14)
|
||||
|
||||
Image(systemName: "arrow.triangle.2.circlepath")
|
||||
.font(.system(size: 58, weight: .semibold))
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.foregroundStyle(.white)
|
||||
.rotationEffect(.degrees(animate ? 360 : 0))
|
||||
}
|
||||
|
||||
VStack(spacing: 6) {
|
||||
Text("Rsync Studio")
|
||||
.font(.system(size: 32, weight: .bold, design: .rounded))
|
||||
Text("Fast, dependable file synchronisation for macOS")
|
||||
.font(.headline)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
ProgressView()
|
||||
.controlSize(.small)
|
||||
.padding(.top, 2)
|
||||
}
|
||||
.padding(48)
|
||||
}
|
||||
.onAppear {
|
||||
withAnimation(.linear(duration: 1.25).repeatForever(autoreverses: false)) {
|
||||
animate = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import SwiftUI
|
||||
|
||||
struct StatusBadge: View {
|
||||
let run: SyncRun
|
||||
|
||||
var body: some View {
|
||||
Label(text, systemImage: icon)
|
||||
.font(.caption.weight(.semibold))
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 4)
|
||||
.background(.quaternary, in: Capsule())
|
||||
}
|
||||
|
||||
private var text: String {
|
||||
if run.isRunning { return "Running" }
|
||||
if run.wasCancelled { return "Cancelled" }
|
||||
return run.succeeded ? "Success" : "Failed"
|
||||
}
|
||||
|
||||
private var icon: String {
|
||||
if run.isRunning { return "arrow.triangle.2.circlepath" }
|
||||
if run.wasCancelled { return "stop.circle" }
|
||||
return run.succeeded ? "checkmark.circle.fill" : "xmark.circle.fill"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user