Add progress for file transfer

This commit is contained in:
Leon Böttger committed 2025-08-16 21:16:08 +02:00
1 parent de0faad177
commit 6d780d7e9c
3 files changed
+116 -12

No files matched your search

+35 -9
View File
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 70;
objectVersion = 60;
objects = {
/* Begin PBXBuildFile section */
@@ -103,6 +103,12 @@
EB96ED8D2D7F7EA3004B3FF1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69DA9A1329E0BF5200A442DA /* Assets.xcassets */; };
EB96ED8F2D7F8105004B3FF1 /* Localized.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8E2D7F8103004B3FF1 /* Localized.swift */; };
EB96ED902D7F8114004B3FF1 /* Localized.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8E2D7F8103004B3FF1 /* Localized.swift */; };
EB979F942E50CA23008B8C5C /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB979F8D2E50CA23008B8C5C /* Configuration.swift */; };
EB979F952E50CA23008B8C5C /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB979F8E2E50CA23008B8C5C /* ContentView.swift */; };
EB979F962E50CA23008B8C5C /* FilePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB979F8F2E50CA23008B8C5C /* FilePicker.swift */; };
EB979F972E50CA23008B8C5C /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB979F902E50CA23008B8C5C /* Model.swift */; };
EB979F982E50CA23008B8C5C /* QuickDropiOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB979F922E50CA23008B8C5C /* QuickDropiOSApp.swift */; };
EB979F9A2E50CAA6008B8C5C /* PieProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB979F992E50CAA6008B8C5C /* PieProgressView.swift */; };
EB9925802E45D53E00357055 /* sharing_enums.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB99257F2E45D53E00357055 /* sharing_enums.pb.swift */; };
EB9925812E45D53E00357055 /* sharing_enums.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB99257F2E45D53E00357055 /* sharing_enums.pb.swift */; };
EB9925822E45D53E00357055 /* sharing_enums.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB99257F2E45D53E00357055 /* sharing_enums.pb.swift */; };
@@ -231,6 +237,13 @@
EB886E662E4F2F7C0052B7D9 /* License.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = License.swift; sourceTree = "<group>"; };
EB96ED8A2D7F7CF4004B3FF1 /* SmallSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallSheetView.swift; sourceTree = "<group>"; };
EB96ED8E2D7F8103004B3FF1 /* Localized.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Localized.swift; sourceTree = "<group>"; };
EB979F8D2E50CA23008B8C5C /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
EB979F8E2E50CA23008B8C5C /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
EB979F8F2E50CA23008B8C5C /* FilePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePicker.swift; sourceTree = "<group>"; };
EB979F902E50CA23008B8C5C /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
EB979F912E50CA23008B8C5C /* QuickDropiOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QuickDropiOS.entitlements; sourceTree = "<group>"; };
EB979F922E50CA23008B8C5C /* QuickDropiOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickDropiOSApp.swift; sourceTree = "<group>"; };
EB979F992E50CAA6008B8C5C /* PieProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PieProgressView.swift; sourceTree = "<group>"; };
EB99257F2E45D53E00357055 /* sharing_enums.pb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = sharing_enums.pb.swift; sourceTree = "<group>"; };
EBC05C5A2E33936C00EECC18 /* ErrorAlertHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorAlertHandler.swift; sourceTree = "<group>"; };
EBC05C6D2E33B57D00EECC18 /* Converter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Converter.swift; sourceTree = "<group>"; };
@@ -248,10 +261,6 @@
EBD2A2162D2860BE00BCB8E2 /* WelcomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreen.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
EB5C37E32E377C2E0052EFD7 /* QuickDropiOS */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = QuickDropiOS; sourceTree = "<group>"; };
/* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */
699DEB9E2AB0573200115D22 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
@@ -315,7 +324,7 @@
69DA9A1029E0BF5100A442DA /* QuickDrop */,
699DEBA22AB0573200115D22 /* ShareExtension */,
69DCF4822AB70D0600CBE2CC /* NearbyShare */,
EB5C37E32E377C2E0052EFD7 /* QuickDropiOS */,
EB979F932E50CA23008B8C5C /* QuickDropiOS */,
698DFAEC29E353220064F247 /* Frameworks */,
69DA9A0F29E0BF5100A442DA /* Products */,
EBC05C8B2E33B59E00EECC18 /* Resources */,
@@ -423,6 +432,20 @@
path = Model;
sourceTree = "<group>";
};
EB979F932E50CA23008B8C5C /* QuickDropiOS */ = {
isa = PBXGroup;
children = (
EB979F8D2E50CA23008B8C5C /* Configuration.swift */,
EB979F8E2E50CA23008B8C5C /* ContentView.swift */,
EB979F8F2E50CA23008B8C5C /* FilePicker.swift */,
EB979F902E50CA23008B8C5C /* Model.swift */,
EB979F992E50CAA6008B8C5C /* PieProgressView.swift */,
EB979F912E50CA23008B8C5C /* QuickDropiOS.entitlements */,
EB979F922E50CA23008B8C5C /* QuickDropiOSApp.swift */,
);
path = QuickDropiOS;
sourceTree = "<group>";
};
EBC05C6A2E33B55100EECC18 /* View */ = {
isa = PBXGroup;
children = (
@@ -549,9 +572,6 @@
);
dependencies = (
);
fileSystemSynchronizedGroups = (
EB5C37E32E377C2E0052EFD7 /* QuickDropiOS */,
);
name = QuickDropiOS;
packageProductDependencies = (
EB5C37ED2E377C3F0052EFD7 /* SwiftProtobuf */,
@@ -779,6 +799,12 @@
EB886E6A2E4F37B90052B7D9 /* ErrorAlertHandler.swift in Sources */,
EB886E5E2E4F13EB0052B7D9 /* Zip.swift in Sources */,
EB5C383D2E38C2D90052EFD7 /* AudioManager.swift in Sources */,
EB979F942E50CA23008B8C5C /* Configuration.swift in Sources */,
EB979F952E50CA23008B8C5C /* ContentView.swift in Sources */,
EB979F962E50CA23008B8C5C /* FilePicker.swift in Sources */,
EB979F9A2E50CAA6008B8C5C /* PieProgressView.swift in Sources */,
EB979F972E50CA23008B8C5C /* Model.swift in Sources */,
EB979F982E50CA23008B8C5C /* QuickDropiOSApp.swift in Sources */,
EB5C38402E38C49D0052EFD7 /* LaunchAtLogin.swift in Sources */,
EB5C37FF2E377CE70052EFD7 /* wire_format.pb.swift in Sources */,
EB5C38002E377CE70052EFD7 /* DataModel.swift in Sources */,
+12 -3
View File
@@ -63,6 +63,8 @@ struct DeviceListView: View {
CustomSection(header: "AvailableDevices") {
ForEach(model.foundDevices) { device in
let isSelected = model.selectedDevice == device
SendPickerButton {
HStack(spacing: 12) {
@@ -90,15 +92,20 @@ struct DeviceListView: View {
.fontWeight(.medium)
.foregroundColor(Color.primary)
Text(model.selectedDevice == device ? model.progressState ?? "..." : "Available".localized())
Text(isSelected ? model.progressState ?? "..." : "Available".localized())
.font(.system(size: 12))
.foregroundColor(Color.primary.opacity(0.6))
}
Spacer()
Image(systemName: "chevron.right")
.foregroundColor(Color.primary.opacity(0.6))
if isSelected, let progress = model.progressValue {
PieProgressView(progress: progress, size: 20)
}
else {
Image(systemName: "chevron.right")
.foregroundColor(Color.primary.opacity(0.6))
}
}
.padding(.vertical, 13)
} onResult: { urls, text in
@@ -106,6 +113,8 @@ struct DeviceListView: View {
model.textToSend = text
model.selectDevice(device: device)
}
.animation(.easeInOut, value: model.progressValue)
.animation(.easeInOut, value: isSelected)
}
}
}
+69
View File
@@ -0,0 +1,69 @@
//
// PieProgressView.swift
// QuickDrop
//
// Created by Leon Böttger on 16.08.25.
//
import SwiftUI
struct PieProgressView: View {
let progress: CGFloat // value between 0.0 and 1.0
var size: CGFloat = 25.0
var color: Color? = nil
var body: some View {
let color = color ?? .gray
ZStack {
Circle()
.stroke(lineWidth: size * 0.08)
.foregroundColor(color)
ZStack {
PieSlice(progress: progress)
.fill(color)
.rotationEffect(.degrees(-90)) // Start from the top
}
.overlay (
Image(systemName: "checkmark")
.font(.system(size: 12, weight: .bold))
.foregroundColor(color == .white ? .blue : .white)
.opacity(progress >= 1.0 ? 1.0 : 0.0) // Show checkmark only when complete
)
}
.frame(width: size, height: size)
}
}
struct PieSlice: Shape {
var progress: CGFloat // from 0.0 to 1.0
func path(in rect: CGRect) -> Path {
var path = Path()
let center = CGPoint(x: rect.midX, y: rect.midY)
let radius = rect.width / 2
let endAngle = Angle(degrees: 360 * Double(progress))
path.move(to: center)
path.addArc(center: center,
radius: radius,
startAngle: .degrees(0),
endAngle: endAngle,
clockwise: false)
path.closeSubpath()
return path
}
}
#Preview {
PieProgressView(progress: 0.76)
.padding()
}