Skip to content

Commit

Permalink
Merge pull request #165 from kishikawakatsumi/visionos
Browse files Browse the repository at this point in the history
Support visionOS
  • Loading branch information
kishikawakatsumi authored Nov 21, 2024
2 parents 78ecf6c + 38b15d8 commit c2943a8
Show file tree
Hide file tree
Showing 37 changed files with 1,468 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class FilesViewController: UIViewController, UITableViewDataSource, UITableViewD
do {
let files = try await treeAccessor.listDirectory(path: path)
.filter { $0.name != "." && $0.name != ".." && !$0.isHidden }
.sorted { $0.name < $1.name }
.sorted { $0.name.localizedStandardCompare($1.name) == .orderedAscending }
self.files.append(contentsOf: files)
tableView.reloadData()
} catch let error as LocalizedError {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class ServersViewController: UIViewController, UITableViewDataSource, UITableVie
private let tableView = UITableView(frame: .zero, style: .insetGrouped)

private var services = [Service]()
private var sessions = [String: SMBClient]()
private var sessions = [ID: SMBClient]()

override func viewDidLoad() {
super.viewDidLoad()
Expand Down Expand Up @@ -123,7 +123,7 @@ class ServersViewController: UIViewController, UITableViewDataSource, UITableVie
let service = services[indexPath.row]

cell.textLabel?.text = service.name
if let _ = sessions[service.id.rawValue] {
if let _ = sessions[service.id] {
cell.accessoryType = .disclosureIndicator
} else {
cell.accessoryType = .none
Expand All @@ -133,7 +133,7 @@ class ServersViewController: UIViewController, UITableViewDataSource, UITableVie
let server = servers[indexPath.row]

cell.textLabel?.text = server.displayName
if let _ = sessions[server.id.rawValue] {
if let _ = sessions[server.id] {
cell.accessoryType = .disclosureIndicator
} else {
cell.accessoryType = .none
Expand All @@ -151,7 +151,7 @@ class ServersViewController: UIViewController, UITableViewDataSource, UITableVie
case 0:
let service = services[indexPath.row]

if let client = sessions[service.id.rawValue] {
if let client = sessions[service.id] {
let viewController = SharesViewController(client: client)
navigationController?.pushViewController(viewController, animated: true)
return
Expand Down Expand Up @@ -186,7 +186,7 @@ class ServersViewController: UIViewController, UITableViewDataSource, UITableVie
let servers = ServerManager.shared.servers
let server = servers[indexPath.row]

if let client = sessions[server.id.rawValue] {
if let client = sessions[server.id] {
let viewController = SharesViewController(client: client)
navigationController?.pushViewController(viewController, animated: true)
return
Expand Down Expand Up @@ -261,7 +261,7 @@ class ServersViewController: UIViewController, UITableViewDataSource, UITableVie
let store = CredentialStore.shared
store.save(server: server, securityDomain: securityDomain, username: username, password: password)

sessions[securityDomain] = client
sessions[ID(securityDomain)] = client

tableView.reloadData()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"images" : [
{
"filename" : "back.png",
"idiom" : "vision",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"layers" : [
{
"filename" : "Front.solidimagestacklayer"
},
{
"filename" : "Middle.solidimagestacklayer"
},
{
"filename" : "Back.solidimagestacklayer"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"images" : [
{
"filename" : "front.png",
"idiom" : "vision",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"images" : [
{
"filename" : "middle.png",
"idiom" : "vision",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
119 changes: 119 additions & 0 deletions Examples/FileBrowser/FileBrowser (visionOS)/ConnectServiceView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import SwiftUI
import SMBClient

struct ConnectServiceView: View {
private enum FocusedField {
case username
case password
}

@State private var server: String

@State private var username: String
@State private var password: String

private var canSubmit: Bool {
!username.isEmpty && !password.isEmpty
}

@FocusState
private var focusedField: FocusedField?

@State private var presentLocalizedAlert: Bool = false
@State private var localizedError: ErrorResponse? = nil

@State private var presentAlert: Bool = false
@State private var error: Error? = nil

@Environment(\.dismiss) private var dismiss

private let onSuccess: (String, String, SMBClient) -> Void
private let onCancel: () -> Void

init(
server: String,
username: String,
password: String,
onSuccess: @escaping (_ username: String, _ password: String, _ client: SMBClient) -> Void,
onCancel: @escaping () -> Void
) {
self.server = server
self.username = username
self.password = password
self.onSuccess = onSuccess
self.onCancel = onCancel
}

var body: some View {
NavigationStack {
Form {
Section {
Label(server, systemImage: "server.rack")
}
Section {
TextField("Username", text: $username)
.autocorrectionDisabled()
.textInputAutocapitalization(.never)
.textContentType(.username)
.focused($focusedField, equals: .username)
SecureField("Password", text: $password)
.textContentType(.password)
.focused($focusedField, equals: .password)
} header: {
Text("Login")
}
Section {
Button("Connect") {
submit()
}
.frame(maxWidth: .infinity)
.disabled(!canSubmit)
}
}
.foregroundStyle(.primary)
.navigationTitle("Connect to Server")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
Button("Cancel") {
onCancel()
dismiss()
}
}
.onAppear {
focusedField = .username
}
.onSubmit {
guard canSubmit else { return }
submit()
}
.alert(isPresented: $presentLocalizedAlert, error: localizedError) { _ in
Button("Close") {}
} message: { error in
Text(error.failureReason ?? error.recoverySuggestion ?? "")
}
.alert("", isPresented: $presentAlert) {
Button("Close") {}
} message: {
Text(error?.localizedDescription ?? "")
}
}
}

private func submit() {
Task { @MainActor in
do {
let client = SMBClient(host: server)
try await client.login(username: username, password: password)

dismiss()
onSuccess(username, password, client)
} catch let error as ErrorResponse {
self.localizedError = error
presentLocalizedAlert = true
} catch {
self.error = error
presentAlert = true
}
}
}
}
82 changes: 82 additions & 0 deletions Examples/FileBrowser/FileBrowser (visionOS)/ContentView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import SwiftUI
import SMBClient

struct FileBrowserView: View {
@State
private var services = [Service]()
@State
private var selection: Service?
@State
private var sessions = [ID: SMBClient]()
@State
private var showingLoginSheet: Bool = false

let publisher = NotificationCenter.default.publisher(for: ServiceDiscovery.serviceDidDiscover)

var body: some View {
NavigationSplitView {
List(services, id: \.self, selection: $selection) { (service) in
NavigationLink(value: service) {
Label(service.name, systemImage: "server.rack")
.foregroundStyle(.primary)
}
}
.onChange(of: selection, initial: false) { (oldValue, newValue) in
if let selection, sessions[selection.id] == nil {
showingLoginSheet = true
}
}
.onReceive(publisher) { (notification) in
services = ServiceDiscovery.shared.services.sorted { $0.name.localizedStandardCompare($1.name) == .orderedAscending }
}
.navigationTitle("Services")
} detail: {
if let selection {
if let client = sessions[selection.id] {
SharesView(client: client)
.id(selection)
}
}
}
.sheet(isPresented: $showingLoginSheet) {
return
} content: {
if let selection = selection {
let (username, password) = {
let store = CredentialStore.shared
if let credential = store.load(server: selection.name) {
return (credential.username, credential.password)
} else {
return ("", "")
}
}()

ConnectServiceView(server: selection.name, username: username, password: password) { (username, password, client) in
loginSucceeded(server: selection.name, securityDomain: selection.id.rawValue, username: username, password: password, client: client)
showingLoginSheet = false
} onCancel: {
showingLoginSheet = false
}
}
}
}

private func loginSucceeded(
server: String,
securityDomain: String,
username: String,
password: String,
client: SMBClient
) {
let store = CredentialStore.shared
store.save(server: server, securityDomain: securityDomain, username: username, password: password)

sessions[ID(securityDomain)] = client
}
}

extension Service: Identifiable {}

#Preview(windowStyle: .automatic) {
FileBrowserView()
}
Loading

0 comments on commit c2943a8

Please sign in to comment.