Skip to content

Server select in share sheet #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Django Files/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>CFBundleURLTypes</key>
<array>
<dict>
Expand Down
39 changes: 25 additions & 14 deletions UploadAndCopy/Base.lproj/MainInterface.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="UIMenu" message="Requires Xcode 11 or later." minToolsVersion="11.0" requiredIntegratedClassName="UICommandDiff"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
Expand All @@ -16,14 +17,14 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="bottom" id="mZN-4f-xCI">
<rect key="frame" x="509" y="673" width="358" height="339"/>
<rect key="frame" x="509" y="653" width="358" height="359"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<visualEffectView opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GO1-Km-czD">
<rect key="frame" x="0.0" y="0.0" width="358" height="339"/>
<visualEffectView opaque="NO" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GO1-Km-czD">
<rect key="frame" x="0.0" y="0.0" width="358" height="359"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="jkr-JH-ISC">
<rect key="frame" x="0.0" y="0.0" width="358" height="339"/>
<rect key="frame" x="0.0" y="0.0" width="358" height="359"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</view>
<blurEffect style="regular"/>
Expand All @@ -41,24 +42,31 @@
<rect key="frame" x="24" y="37" width="311" height="210"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" showsMenuAsPrimaryAction="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lIw-lC-Qye" userLabel="Servers">
<rect key="frame" x="8" y="258" width="342" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<menu key="menu" id="EuD-Tg-ocz">
<children>
<command title="Item 1" id="Aum-d2-ejp"/>
<command title="Item 2" id="16T-AE-w7d"/>
</children>
</menu>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="tinted" title="Button">
<color key="baseBackgroundColor" systemColor="systemGrayColor"/>
</buttonConfiguration>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" showsMenuAsPrimaryAction="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qbS-Ny-dwp" userLabel="Share">
<rect key="frame" x="205" y="281" width="130" height="50"/>
<rect key="frame" x="205" y="297" width="145" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="filled" title="Share"/>
<connections>
<action selector="onShare:" destination="j1y-V4-xli" eventType="primaryActionTriggered" id="ve5-Ud-qIO"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UXe-96-hUT" userLabel="ServerName">
<rect key="frame" x="24" y="255" width="311" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hrx-Ux-tAw">
<rect key="frame" x="24" y="281" width="130" height="50"/>
<rect key="frame" x="8" y="297" width="146" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonConfiguration key="configuration" style="gray" title="Cancel">
<color key="baseForegroundColor" systemColor="lightTextColor"/>
Expand Down Expand Up @@ -107,9 +115,9 @@
<connections>
<outlet property="CancelButton" destination="hrx-Ux-tAw" id="1w3-yX-eza"/>
<outlet property="ImageView" destination="T3b-pJ-MQ3" id="uTe-ZR-hRh"/>
<outlet property="ServerLabel" destination="UXe-96-hUT" id="ITX-y0-3rY"/>
<outlet property="ShareButton" destination="qbS-Ny-dwp" id="pgM-iP-QEf"/>
<outlet property="activityIndicator" destination="R4J-pt-1BH" id="aTU-cF-bWo"/>
<outlet property="availableServers" destination="lIw-lC-Qye" id="MNJ-N7-UbZ"/>
<outlet property="progressBar" destination="UxW-kr-0i4" id="klH-Vg-pEi"/>
<outlet property="shareLabel" destination="h6M-o6-yR9" id="IY1-ab-l1d"/>
<outlet property="shortText" destination="etx-MM-w5d" id="HZN-xL-9My"/>
Expand All @@ -126,5 +134,8 @@
<systemColor name="lightTextColor">
<color white="1" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemGrayColor">
<color red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>
74 changes: 57 additions & 17 deletions UploadAndCopy/ShareViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class ShareViewController: UIViewController, UITextFieldDelegate, URLSessionTask
@IBOutlet weak var cancelButton: UIButton!
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var serverLabel: UILabel!
@IBOutlet weak var availableServers: UIButton!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
@IBOutlet weak var shortTextLabel: UILabel!
@IBOutlet weak var shortText: UITextField!
Expand All @@ -53,28 +53,16 @@ class ShareViewController: UIViewController, UITextFieldDelegate, URLSessionTask
self.showMessageAndDismiss(message: "Nothing to share.")
return
}
guard let server = getDefaultServer() else {
self.showMessageAndDismiss(message: "No servers configured.")
return
}
session = server

if URL(string: server.url) == nil{
self.showMessageAndDismiss(message: "Server '\(server.url)' is invalid.")
return
}
if URL(string: server.url)?.scheme == nil{
self.showMessageAndDismiss(message: "Server '\(server.url)' scheme (http or https) is invalid.")
return
}
getAvailableServers()

self.progressBar.isHidden = true
var loaded: Bool = false
for extensionItem in extensionItems {
for ele in extensionItem.attachments! {
let itemProvider = ele

if itemProvider.hasItemConformingToTypeIdentifier("public.image"){
if itemProvider.hasItemConformingToTypeIdentifier("public.image") {
itemProvider.loadItem(forTypeIdentifier: "public.image", options: nil, completionHandler: { (item, error) in
DispatchQueue.main.async {
self.shortText.isHidden = true
Expand Down Expand Up @@ -107,6 +95,19 @@ class ShareViewController: UIViewController, UITextFieldDelegate, URLSessionTask
loaded = true
break
}
else if itemProvider.hasItemConformingToTypeIdentifier("public.file-url") {
itemProvider.loadItem(forTypeIdentifier: "public.file-url", options: nil, completionHandler: { (item, error) in
DispatchQueue.main.async {
self.shortText.isHidden = true
self.shareLabel.text = "Upload File"
self.shareURL = item as? URL
self.activityIndicator.stopAnimating()
self.shareButton.isEnabled = true
}
})
loaded = true
break
}
else if itemProvider.hasItemConformingToTypeIdentifier("public.url"){
itemProvider.loadItem(forTypeIdentifier: "public.url", options: nil, completionHandler: { (item, error) in
DispatchQueue.main.async {
Expand Down Expand Up @@ -143,7 +144,46 @@ class ShareViewController: UIViewController, UITextFieldDelegate, URLSessionTask
}
}

serverLabel.text = session.url
}

func getAvailableServers() {
let context = sharedModelContainer.mainContext

do {
let descriptor = FetchDescriptor<DjangoFilesSession>(
predicate: #Predicate { $0.auth == true },
sortBy: [SortDescriptor(\.url)]
)
let sessions = try context.fetch(descriptor)

guard !sessions.isEmpty else {
availableServers.setTitle("No servers available", for: .normal)
return
}

// Pick the default session, or fallback to the first one
let defaultSession = sessions.first(where: { $0.defaultSession }) ?? sessions.first!

// Build menu actions
let actions = sessions.map { session in
UIAction(title: session.url) { _ in
self.session = session
self.availableServers.setTitle(session.url, for: .normal)
}
}

let menu = UIMenu(title: "Select a Server", options: .displayInline, children: actions)
availableServers.menu = menu
availableServers.showsMenuAsPrimaryAction = true

// Set the default selected title and session
availableServers.setTitle(defaultSession.url, for: .normal)
session = defaultSession

} catch {
self.showMessageAndDismiss(message: error.localizedDescription)
availableServers.setTitle("Error loading servers", for: .normal)
}
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
Expand All @@ -165,7 +205,7 @@ class ShareViewController: UIViewController, UITextFieldDelegate, URLSessionTask
}
}
catch {
print(error)
self.showMessageAndDismiss(message: error.localizedDescription)
}
return selectedServer
}
Expand Down