Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
379 changes: 379 additions & 0 deletions src-tauri/Cargo.lock

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,21 @@ base64 = "0.22"
[target.'cfg(not(target_os = "android"))'.dependencies]
tokio-native-tls = "0.3"
native-tls = "0.2"
reqwest = { version = "0.12", default-features = false, features = ["native-tls"] }

[target.'cfg(target_os = "android")'.dependencies]
tokio-rustls = { version = "0.26", default-features = false }
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] }
webpki-roots = "0.26"
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] }
tauri-plugin-dialog = "2"
jni = { version = "0.21", default-features = false }
ndk-context = "0.1"

[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\"))".dependencies]
tauri-plugin-single-instance = { version = "2.0.0", features = ["deep-link"] }
rfd = { version = "0.15", features = ["tokio"] }

[target.'cfg(target_os = "ios")'.dependencies]
tauri-plugin-ios-keyboard = "0.1"
tauri-plugin-share-sheet = { path = "plugins/share-sheet" }
4 changes: 4 additions & 0 deletions src-tauri/gen/apple/ObsidianIRC_iOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>CFBundleURLTypes</key>
<array>
<dict>
Expand Down
10 changes: 10 additions & 0 deletions src-tauri/plugins/share-sheet/.tauri/tauri-api/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
Package.resolved
40 changes: 40 additions & 0 deletions src-tauri/plugins/share-sheet/.tauri/tauri-api/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// swift-tools-version:5.3
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

import PackageDescription

let package = Package(
name: "Tauri",
platforms: [
.macOS(.v10_13),
.iOS(.v11),
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "Tauri",
type: .static,
targets: ["Tauri"])
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(name: "SwiftRs", url: "https://github.com/Brendonovich/swift-rs", from: "1.0.0")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "Tauri",
dependencies: [
.byName(name: "SwiftRs")
],
path: "Sources"
),
.testTarget(
name: "TauriTests",
dependencies: ["Tauri"]
),
]
)
3 changes: 3 additions & 0 deletions src-tauri/plugins/share-sheet/.tauri/tauri-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Tauri

Tauri iOS API.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

import Foundation

let CHANNEL_PREFIX = "__CHANNEL__:"
let channelDataKey = CodingUserInfoKey(rawValue: "sendChannelData")!

public class Channel: Decodable {
public let id: UInt64
let handler: (UInt64, String) -> Void

public required init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let channelDef = try container.decode(String.self)

let components = channelDef.components(separatedBy: CHANNEL_PREFIX)
if components.count < 2 {
throw DecodingError.dataCorruptedError(
in: container,
debugDescription: "Invalid channel definition from \(channelDef)"
)

}
guard let channelId = UInt64(components[1]) else {
throw DecodingError.dataCorruptedError(
in: container,
debugDescription: "Invalid channel ID from \(channelDef)"
)
}

guard let handler = decoder.userInfo[channelDataKey] as? (UInt64, String) -> Void else {
throw DecodingError.dataCorruptedError(
in: container,
debugDescription: "missing userInfo for Channel handler. This is a Tauri issue"
)
}

self.id = channelId
self.handler = handler
}

func serialize(_ data: JsonValue) -> String {
do {
return try data.jsonRepresentation() ?? "\"Failed to serialize payload\""
} catch {
return "\"\(error)\""
}
}

public func send(_ data: JsonObject) {
send(.dictionary(data))
}

public func send(_ data: JsonValue) {
handler(id, serialize(data))
}

public func send<T: Encodable>(_ data: T) throws {
let json = try JSONEncoder().encode(data)
handler(id, String(decoding: json, as: UTF8.self))
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

import Foundation
import UIKit

@objc public class Invoke: NSObject {
public let command: String
let callback: UInt64
let error: UInt64
let data: String
let sendResponse: (UInt64, String?) -> Void
let sendChannelData: (UInt64, String) -> Void

public init(
command: String, callback: UInt64, error: UInt64,
sendResponse: @escaping (UInt64, String?) -> Void,
sendChannelData: @escaping (UInt64, String) -> Void, data: String
) {
self.command = command
self.callback = callback
self.error = error
self.data = data
self.sendResponse = sendResponse
self.sendChannelData = sendChannelData
}

public func getRawArgs() -> String {
return self.data
}

public func getArgs() throws -> JSObject {
let jsonData = self.data.data(using: .utf8)!
let data = try JSONSerialization.jsonObject(with: jsonData, options: [])
return JSTypes.coerceDictionaryToJSObject(
(data as! NSDictionary), formattingDatesAsStrings: true)!
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

public func parseArgs<T: Decodable>(_ type: T.Type) throws -> T {
let jsonData = self.data.data(using: .utf8)!
let decoder = JSONDecoder()
decoder.userInfo[channelDataKey] = sendChannelData
return try decoder.decode(type, from: jsonData)
}

func serialize(_ data: JsonValue) -> String {
do {
return try data.jsonRepresentation() ?? "\"Failed to serialize payload\""
} catch {
return "\"\(error)\""
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
}

public func resolve() {
sendResponse(callback, nil)
}

public func resolve(_ data: JsonObject) {
resolve(.dictionary(data))
}

public func resolve(_ data: JsonValue) {
sendResponse(callback, serialize(data))
}

public func resolve<T: Encodable>(_ data: T) {
do {
let json = try JSONEncoder().encode(data)
sendResponse(callback, String(decoding: json, as: UTF8.self))
} catch {
sendResponse(self.error, "\"\(error)\"")
}
}

public func reject(
_ message: String, code: String? = nil, error: Error? = nil, data: JsonValue? = nil
) {
let payload: NSMutableDictionary = [
"message": message
]

if let code = code {
payload["code"] = code
}

if let error = error {
payload["error"] = error
}

if let data = data {
switch data {
case .dictionary(let dict):
for entry in dict {
payload[entry.key] = entry.value
}
}
}

sendResponse(self.error, serialize(.dictionary(payload as! JsonObject)))
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
}

public func unimplemented() {
unimplemented("not implemented")
}

public func unimplemented(_ message: String) {
reject(message)
}

public func unavailable() {
unavailable("not available")
}

public func unavailable(_ message: String) {
reject(message)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

import Foundation

// declare our empty protocol, and conformance, for typing
public protocol JSValue {}
extension String: JSValue {}
extension Bool: JSValue {}
extension Int: JSValue {}
extension Float: JSValue {}
extension Double: JSValue {}
extension NSNumber: JSValue {}
extension NSNull: JSValue {}
extension Array: JSValue {}
extension Date: JSValue {}
extension Dictionary: JSValue where Key == String, Value == JSValue {}

// convenience aliases
public typealias JSObject = [String: JSValue]
public typealias JSArray = [JSValue]

extension Dictionary where Key == String, Value == JSValue {
public func getValue(_ key: String) -> JSValue? {
return self[key]
}

public func getString(_ key: String) -> String? {
return self[key] as? String
}

public func getBool(_ key: String) -> Bool? {
return self[key] as? Bool
}

public func getInt(_ key: String) -> Int? {
return self[key] as? Int
}

public func getFloat(_ key: String) -> Float? {
if let floatValue = self[key] as? Float {
return floatValue
} else if let doubleValue = self[key] as? Double {
return Float(doubleValue)
}
return nil
}

public func getDouble(_ key: String) -> Double? {
return self[key] as? Double
}

public func getArray(_ key: String) -> JSArray? {
return self[key] as? JSArray
}

public func getObject(_ key: String) -> JSObject? {
return self[key] as? JSObject
}
}

/*
Simply casting objects from foundation class clusters (such as __NSArrayM)
doesn't work with the JSValue protocol and will always fail. So we need to
recursively and explicitly convert each value in the dictionary.
*/
public enum JSTypes {}
extension JSTypes {
public static func coerceDictionaryToJSObject(
_ dictionary: NSDictionary?, formattingDatesAsStrings: Bool = false
) -> JSObject? {
return coerceToJSValue(dictionary, formattingDates: formattingDatesAsStrings) as? JSObject
}

public static func coerceDictionaryToJSObject(
_ dictionary: [AnyHashable: Any]?, formattingDatesAsStrings: Bool = false
) -> JSObject? {
return coerceToJSValue(dictionary, formattingDates: formattingDatesAsStrings) as? JSObject
}
}

private let dateStringFormatter = ISO8601DateFormatter()

// We need a large switch statement because we have a lot of types.
// swiftlint:disable:next cyclomatic_complexity
private func coerceToJSValue(_ value: Any?, formattingDates: Bool) -> JSValue? {
guard let value = value else {
return nil
}
switch value {
case let stringValue as String:
return stringValue
case let numberValue as NSNumber:
return numberValue
case let boolValue as Bool:
return boolValue
case let intValue as Int:
return intValue
case let floatValue as Float:
return floatValue
case let doubleValue as Double:
return doubleValue
case let dateValue as Date:
if formattingDates {
return dateStringFormatter.string(from: dateValue)
}
return dateValue
case let nullValue as NSNull:
return nullValue
case let arrayValue as NSArray:
return arrayValue.compactMap { coerceToJSValue($0, formattingDates: formattingDates) }
case let dictionaryValue as NSDictionary:
let keys = dictionaryValue.allKeys.compactMap { $0 as? String }
var result: JSObject = [:]
for key in keys {
result[key] = coerceToJSValue(dictionaryValue[key], formattingDates: formattingDates)
}
return result
default:
return nil
}
}
Loading
Loading