Add button to enable share extension

This commit is contained in:
Leon Böttger committed 2025-12-26 13:18:54 +01:00
1 parent 46cdec35d5
commit 728385ff95
8 files changed
+1214 -183

No files matched your search

-15
View File
@@ -1,15 +0,0 @@
//
// Localized.swift
// QuickDrop
//
// Created by Leon Böttger on 10.03.25.
//
import Foundation
public extension String {
func localized() -> String {
let localizedString = NSLocalizedString(self, comment: "")
return localizedString
}
}
+6 -14
View File
@@ -82,7 +82,6 @@
EB3B9F222EF7150400D6704E /* TutorialView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7F54112D78E95C00989564 /* TutorialView.swift */; };
EB3B9F232EF7150400D6704E /* sharing_enums.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB99257F2E45D53E00357055 /* sharing_enums.pb.swift */; };
EB3B9F242EF7150400D6704E /* PhotoManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBBEE1452EC9D92F00AA7831 /* PhotoManager.swift */; };
EB3B9F252EF7150400D6704E /* Localized.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8E2D7F8103004B3FF1 /* Localized.swift */; };
EB3B9F262EF7150400D6704E /* AppGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB16B7762E59BA9F007D9792 /* AppGroup.swift */; };
EB3B9F272EF7150400D6704E /* ApIsolationIssueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBC05C7D2E33B58300EECC18 /* ApIsolationIssueView.swift */; };
EB3B9F282EF7150400D6704E /* FirewallIssueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBC05C7E2E33B58300EECC18 /* FirewallIssueView.swift */; };
@@ -109,7 +108,6 @@
EB3B9F3F2EF7150400D6704E /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EB6E6B202ECBA95000E71D57 /* InfoPlist.xcstrings */; };
EB3B9F402EF7150400D6704E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = EB7654772E525ACC006B4AA3 /* MainMenu.xib */; };
EB3B9F4C2EF7151900D6704E /* License.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB886E662E4F2F7C0052B7D9 /* License.swift */; };
EB3B9F4D2EF7151900D6704E /* Localized.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8E2D7F8103004B3FF1 /* Localized.swift */; };
EB3B9F4E2EF7151900D6704E /* SendToExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB1325F72E70287C00FD749C /* SendToExtension.swift */; };
EB3B9F4F2EF7151900D6704E /* TrustStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB16B6162E58B4C8007D9792 /* TrustStore.swift */; };
EB3B9F502EF7151900D6704E /* HKDF.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB886E512E4E19390052B7D9 /* HKDF.swift */; };
@@ -224,7 +222,6 @@
EB5C37FE2E377CE70052EFD7 /* offline_wire_formats.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2B29E18CB500A442DA /* offline_wire_formats.pb.swift */; };
EB5C37FF2E377CE70052EFD7 /* wire_format.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2929E18CB500A442DA /* wire_format.pb.swift */; };
EB5C38002E377CE70052EFD7 /* DataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB5C36E82E3546100052EFD7 /* DataModel.swift */; };
EB5C38012E377DE60052EFD7 /* Localized.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8E2D7F8103004B3FF1 /* Localized.swift */; };
EB5C38392E38C1F60052EFD7 /* justMaybe.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = EB5C38382E38C1F60052EFD7 /* justMaybe.mp3 */; };
EB5C383A2E38C1F60052EFD7 /* justMaybe.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = EB5C38382E38C1F60052EFD7 /* justMaybe.mp3 */; };
EB5C383B2E38C1F60052EFD7 /* justMaybe.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = EB5C38382E38C1F60052EFD7 /* justMaybe.mp3 */; };
@@ -237,6 +234,8 @@
EB6E6B212ECBA95000E71D57 /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EB6E6B202ECBA95000E71D57 /* InfoPlist.xcstrings */; };
EB6E6B222ECBA95000E71D57 /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EB6E6B202ECBA95000E71D57 /* InfoPlist.xcstrings */; };
EB6F62D72D91F4AF00534EC2 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB6F62D62D91F4AC00534EC2 /* SettingsView.swift */; };
EB6FE7CF2EFEB42800FF2BCF /* NoLocalNetworkAccessAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB6FE7CC2EFEAFF000FF2BCF /* NoLocalNetworkAccessAlertView.swift */; };
EB6FE7D02EFEB43000FF2BCF /* NoLocalNetworkAccessAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB6FE7CC2EFEAFF000FF2BCF /* NoLocalNetworkAccessAlertView.swift */; };
EB721F242E75AFA900F2099F /* QuickDropIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = EB721F232E75AFA900F2099F /* QuickDropIcon.icon */; };
EB721F252E75AFA900F2099F /* QuickDropIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = EB721F232E75AFA900F2099F /* QuickDropIcon.icon */; };
EB7654782E525ACC006B4AA3 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = EB7654772E525ACC006B4AA3 /* MainMenu.xib */; };
@@ -269,7 +268,6 @@
EB950B452E520436002D68FA /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB2F9BFA2DA04B67004010A2 /* Helpers.swift */; };
EB950B462E520436002D68FA /* OutboundNearbyConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 691F53BD2ABF03820089FD92 /* OutboundNearbyConnection.swift */; };
EB950B472E520436002D68FA /* sharing_enums.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB99257F2E45D53E00357055 /* sharing_enums.pb.swift */; };
EB950B482E520436002D68FA /* Localized.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8E2D7F8103004B3FF1 /* Localized.swift */; };
EB950B492E520436002D68FA /* device_to_device_messages.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2A29E18CB500A442DA /* device_to_device_messages.pb.swift */; };
EB950B4A2E520436002D68FA /* securegcm.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2C29E18CB500A442DA /* securegcm.pb.swift */; };
EB950B4B2E520436002D68FA /* offline_wire_formats.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69DA9A2B29E18CB500A442DA /* offline_wire_formats.pb.swift */; };
@@ -302,8 +300,6 @@
EB96ED8B2D7F7CF7004B3FF1 /* SmallSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8A2D7F7CF4004B3FF1 /* SmallSheetView.swift */; };
EB96ED8C2D7F7E7B004B3FF1 /* SmallSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ED8A2D7F7CF4004B3FF1 /* SmallSheetView.swift */; };
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 */; };
@@ -531,6 +527,7 @@
EB5C383E2E38C49D0052EFD7 /* LaunchAtLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAtLogin.swift; sourceTree = "<group>"; };
EB6E6B202ECBA95000E71D57 /* InfoPlist.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = InfoPlist.xcstrings; sourceTree = "<group>"; };
EB6F62D62D91F4AC00534EC2 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
EB6FE7CC2EFEAFF000FF2BCF /* NoLocalNetworkAccessAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoLocalNetworkAccessAlertView.swift; sourceTree = "<group>"; };
EB721F232E75AFA900F2099F /* QuickDropIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = QuickDropIcon.icon; sourceTree = "<group>"; };
EB7654772E525ACC006B4AA3 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; };
EB7A95F22EF6E1BE0021111B /* IntroductionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntroductionView.swift; sourceTree = "<group>"; };
@@ -546,7 +543,6 @@
EB950B732E520954002D68FA /* Attachments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachments.swift; sourceTree = "<group>"; };
EB950B762E521712002D68FA /* AttachmentDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentDetails.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>"; };
@@ -762,7 +758,6 @@
EB5C371C2E3669010052EFD7 /* Util */ = {
isa = PBXGroup;
children = (
EB96ED8E2D7F8103004B3FF1 /* Localized.swift */,
EB16B6112E58B4B9007D9792 /* IdentityManager.swift */,
EB2B41E32DC63AC80070FC39 /* SleepManager.swift */,
EB16B6162E58B4C8007D9792 /* TrustStore.swift */,
@@ -820,6 +815,7 @@
isa = PBXGroup;
children = (
EB979F8E2E50CA23008B8C5C /* ContentView.swift */,
EB6FE7CC2EFEAFF000FF2BCF /* NoLocalNetworkAccessAlertView.swift */,
EB979F8F2E50CA23008B8C5C /* FilePicker.swift */,
EB97A0192E51EA9C008B8C5C /* UIAlert.swift */,
EBBEE1452EC9D92F00AA7831 /* PhotoManager.swift */,
@@ -1241,7 +1237,6 @@
buildActionMask = 2147483647;
files = (
EBE5FF442EDB877C0019B380 /* License.swift in Sources */,
EB96ED902D7F8114004B3FF1 /* Localized.swift in Sources */,
EB1325F82E70288300FD749C /* SendToExtension.swift in Sources */,
EB16B6172E58B4C8007D9792 /* TrustStore.swift in Sources */,
EB886E542E4E19390052B7D9 /* HKDF.swift in Sources */,
@@ -1324,7 +1319,6 @@
EB7F54122D78E96000989564 /* TutorialView.swift in Sources */,
EB9925812E45D53E00357055 /* sharing_enums.pb.swift in Sources */,
EB6E6AB42ECBA46D00E71D57 /* PhotoManager.swift in Sources */,
EB96ED8F2D7F8105004B3FF1 /* Localized.swift in Sources */,
EB16B77A2E59BAA1007D9792 /* AppGroup.swift in Sources */,
EBC05C822E33B58300EECC18 /* ApIsolationIssueView.swift in Sources */,
EBC05C832E33B58300EECC18 /* FirewallIssueView.swift in Sources */,
@@ -1379,7 +1373,6 @@
EB3B9F222EF7150400D6704E /* TutorialView.swift in Sources */,
EB3B9F232EF7150400D6704E /* sharing_enums.pb.swift in Sources */,
EB3B9F242EF7150400D6704E /* PhotoManager.swift in Sources */,
EB3B9F252EF7150400D6704E /* Localized.swift in Sources */,
EB3B9F262EF7150400D6704E /* AppGroup.swift in Sources */,
EB3B9F272EF7150400D6704E /* ApIsolationIssueView.swift in Sources */,
EB3B9F282EF7150400D6704E /* FirewallIssueView.swift in Sources */,
@@ -1398,7 +1391,6 @@
buildActionMask = 2147483647;
files = (
EB3B9F4C2EF7151900D6704E /* License.swift in Sources */,
EB3B9F4D2EF7151900D6704E /* Localized.swift in Sources */,
EB3B9F4E2EF7151900D6704E /* SendToExtension.swift in Sources */,
EB3B9F4F2EF7151900D6704E /* TrustStore.swift in Sources */,
EB3B9F502EF7151900D6704E /* HKDF.swift in Sources */,
@@ -1456,7 +1448,6 @@
EB5C37F62E377CE70052EFD7 /* device_to_device_messages.pb.swift in Sources */,
EB886E532E4E19390052B7D9 /* HKDF.swift in Sources */,
EB5C37F82E377CE70052EFD7 /* SleepManager.swift in Sources */,
EB5C38012E377DE60052EFD7 /* Localized.swift in Sources */,
EB5C37F92E377CE70052EFD7 /* securegcm.pb.swift in Sources */,
EB5C37FA2E377CE70052EFD7 /* Helpers.swift in Sources */,
EB5C37FB2E377CE70052EFD7 /* InboundNearbyConnection.swift in Sources */,
@@ -1472,6 +1463,7 @@
EB5C383D2E38C2D90052EFD7 /* AudioManager.swift in Sources */,
EB979F942E50CA23008B8C5C /* Configuration.swift in Sources */,
EB979F952E50CA23008B8C5C /* ContentView.swift in Sources */,
EB6FE7CF2EFEB42800FF2BCF /* NoLocalNetworkAccessAlertView.swift in Sources */,
EBBEE1462EC9D93400AA7831 /* PhotoManager.swift in Sources */,
EB97A01A2E51EAA2008B8C5C /* UIAlert.swift in Sources */,
EB979F962E50CA23008B8C5C /* FilePicker.swift in Sources */,
@@ -1496,7 +1488,6 @@
EB950B572E520591002D68FA /* ErrorAlertHandler.swift in Sources */,
EB950B462E520436002D68FA /* OutboundNearbyConnection.swift in Sources */,
EB950B472E520436002D68FA /* sharing_enums.pb.swift in Sources */,
EB950B482E520436002D68FA /* Localized.swift in Sources */,
EB950B492E520436002D68FA /* device_to_device_messages.pb.swift in Sources */,
EB950B4A2E520436002D68FA /* securegcm.pb.swift in Sources */,
EB950B4B2E520436002D68FA /* offline_wire_formats.pb.swift in Sources */,
@@ -1528,6 +1519,7 @@
EB950B752E52111C002D68FA /* Attachments.swift in Sources */,
EB950B6F2E5206E2002D68FA /* ShareViewController.swift in Sources */,
EB950B432E52038A002D68FA /* ContentView.swift in Sources */,
EB6FE7D02EFEB43000FF2BCF /* NoLocalNetworkAccessAlertView.swift in Sources */,
EB950B442E520414002D68FA /* License.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
File diff suppressed because it is too large. Load diff
+97 -7
View File
@@ -5,14 +5,13 @@
// Created by Leon Böttger on 05.03.25.
//
import SwiftUI
import AppKit
import LUI
import SwiftUI
struct TutorialView: View {
let title: String
let text: String
let showsLicense: Bool
let tab: Tab
let openPlus: () -> Void
@State private var licenseWindow: NSWindow?
@@ -20,15 +19,16 @@ struct TutorialView: View {
var body: some View {
LargeAppIconView(title: title) {
LargeAppIconView(title: tab.title) {
VStack {
Text(text.localized())
Text(tab.text.localized())
.multilineTextAlignment(.leading)
.fixedSize(horizontal: false, vertical: true)
.padding()
.frame(width: 550)
if showsLicense {
if tab == .receive {
HStack(spacing: 30) {
Button {
@@ -67,12 +67,102 @@ struct TutorialView: View {
}
.padding()
}
else if tab == .send {
EnableExtensionView()
}
}
}
}
}
struct EnableExtensionView: View {
@State private var showSharePicker = false
@State private var shareItems: [Any] = []
@State private var isExtensionEnabled = false
@State private var showSuccessCheckmark = false
@State private var animateCheckmark = false
private let timer = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()
init() {
_isExtensionEnabled = State(initialValue: Self.isEnabled())
}
var body: some View {
if !isExtensionEnabled {
Button("EnableQuickDropExtension".localized()) {
shareItems = [
"EnableQuickDropExtensionDescription".localized()
]
showSharePicker = true
}
.background(
SharingPickerPresenter(
isPresented: $showSharePicker,
sharingItems: shareItems
)
)
.padding()
.onReceive(timer) { _ in
updateEnabledState()
}
}
else if showSuccessCheckmark {
Image(systemName: "checkmark.circle.fill")
.font(.system(size: 20))
.foregroundColor(.green)
.background(Circle().foregroundColor(.white).frame(width: 18, height: 18))
.scaleEffect(animateCheckmark ? 1.0 : 0.5)
.animation(.easeOut(duration: 0.4), value: animateCheckmark)
.onAppear {
animateCheckmark = true
}
.padding()
}
}
private func updateEnabledState() {
let enabled = Self.isEnabled()
if enabled != isExtensionEnabled {
withAnimation(.smooth) {
isExtensionEnabled = enabled
if enabled {
showSuccessCheckmark = true
}
}
}
}
private static func isEnabled() -> Bool {
NSSharingService(
named: NSSharingService.Name("com.leonboettger.neardrop.ShareExtension")
) != nil
}
}
private struct SharingPickerPresenter: NSViewRepresentable {
@Binding var isPresented: Bool
let sharingItems: [Any]
func makeNSView(context: Context) -> NSView { NSView() }
func updateNSView(_ nsView: NSView, context: Context) {
guard isPresented else { return }
let picker = NSSharingServicePicker(items: sharingItems)
DispatchQueue.main.async {
picker.show(relativeTo: nsView.bounds, of: nsView, preferredEdge: .minY)
isPresented = false
}
}
}
struct LargeAppIconView<Content: View>: View {
let title: String
+50 -24
View File
@@ -21,14 +21,22 @@ struct WelcomeScreen: View {
let openCableTransmissionView: () -> Void
let checkForNetworkIssues: () -> Void
@State private var selection: Tabs? = Tabs.receive
@State private var selection: Tab = Tab.receive
var body: some View {
HStack(spacing: 0) {
List(selection: $selection) {
ForEach(Tabs.allCases.filter({$0 != .settings }), id: \.self) { tab in
Label(tab.title, systemImage: tab.systemImage)
let listBinding = Binding<Tab?>(
get: { selection },
set: { newValue in
selection = newValue ?? .receive
}
)
List(selection: listBinding) {
ForEach(Tab.allCases.filter({$0 != .settings }), id: \.self) { tab in
Label(tab.sidebarTitle, systemImage: tab.systemImage)
.tag(tab)
.frame(height: 30)
}
@@ -53,8 +61,8 @@ struct WelcomeScreen: View {
Divider()
Label(Tabs.settings.title, systemImage: Tabs.settings.systemImage)
.tag(Tabs.settings)
Label(Tab.settings.sidebarTitle, systemImage: Tab.settings.systemImage)
.tag(Tab.settings)
.frame(height: 30)
}
.minimumScaleFactor(0.5)
@@ -67,22 +75,18 @@ struct WelcomeScreen: View {
ZStack {
Color.defaultBackground.edgesIgnoringSafeArea(.vertical)
switch selection {
case .receive:
TutorialView(title: "ReceiveFiles", text: "UserManualDescription", showsLicense: true, openPlus: openPlusScreen)
case .send:
TutorialView(title: "SendFiles", text: "SendFilesDescription", showsLicense: false, openPlus: openPlusScreen)
case .troubleshooting:
TutorialView(title: "Troubleshooting", text: "TroubleshootingDescription", showsLicense: false, openPlus: openPlusScreen)
.onAppear {
checkForNetworkIssues()
}
default:
SettingsView()
}
if selection == .settings {
SettingsView()
}
else {
TutorialView(tab: selection, openPlus: openPlusScreen)
.onAppear {
if selection == .troubleshooting {
checkForNetworkIssues()
}
}
}
}
}
.onDrop(of: [.fileURL], isTargeted: nil) { providers in
@@ -171,13 +175,13 @@ struct ExternalLinkLabel: View {
}
enum Tabs: CaseIterable {
enum Tab: CaseIterable {
case receive
case send
case troubleshooting
case settings
var title: String {
var sidebarTitle: String {
switch self {
case .receive:
return "ReceiveFiles".localized()
@@ -190,6 +194,28 @@ enum Tabs: CaseIterable {
}
}
var title: String {
switch self {
case .troubleshooting:
return "Troubleshooting"
default:
return sidebarTitle
}
}
var text: String {
switch self {
case .receive:
"UserManualDescription"
case .send:
"SendFilesDescription"
case .troubleshooting:
"TroubleshootingDescription"
case .settings:
""
}
}
var systemImage: String {
switch self {
case .receive:
+1 -8
View File
@@ -95,14 +95,7 @@ struct DeviceListView: View {
}
if !nearbyConnectionManager.hasLocalNetworkPermission {
CardView(backgroundColor: .red, title: "NoNetworkAccess", titleSymbol: "network.slash") {
LUIText("NoLocalNetworkAccessDescription", color: .white)
.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(.bottom, 10)
.onTapGesture {
openAppSettings()
}
NoLocalNetworkAccessAlertView()
}
var availableDevices: [RemoteDeviceInfo] {
-1
View File
@@ -49,7 +49,6 @@ struct SendPickerButton<Label: View>: View {
onPrepare?()
updatedPhotoSelection(content: newItems)
}
// File picker
.fileImporter(isPresented: $showFilePicker,
allowedContentTypes: [.item, .folder], // any file
allowsMultipleSelection: true) { result in
@@ -0,0 +1,24 @@
//
// NoLocalNetworkAccessAlertView.swift
// QuickDrop
//
// Created by Leon Böttger on 26.12.25.
//
import LUI
import SwiftUI
struct NoLocalNetworkAccessAlertView: View {
var body: some View {
CardView(backgroundColor: .red, title: "NoNetworkAccess", titleSymbol: "network.slash") {
LUIText("NoLocalNetworkAccessDescription", color: .white)
.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(.bottom, 10)
.onTapGesture {
#if os(iOS)
openAppSettings()
#endif
}
}
}