FTStore now holds both halves of the product:
ios/ the swift app — the fork of claration/Feather, unchanged apart
from its new home
web/ FTStore Admin, formerly its own repository. serves the
dashboard at /admin, the ftstore.json feed and IPA downloads
app-repo.json and Images/ stay at the repo root on purpose: the former is
a published AltStore source whose raw.githubusercontent URL is what
installed copies resolve updates through, so moving it would break every
subscriber.
The admin server is renamed throughout: package ftstore-admin, images
ghcr.io/<owner>/ftstore-admin-{app,worker}, postgres role/db ftstore,
session cookie ftstore_session, temp dir /tmp/ftstore, backup type
ftstore-settings, outbound user-agent FTStoreAdmin. backups written under the old
name still import, and compose is pinned to name: ftstore so the
volume prefix does not follow the directory name.
apply-rebrand.sh gains a relocation step: upstream's tree is rooted at
the repo root while ours lives in ios/, so a merge drops Feather's files
next to ios/ and the script folds them in before renaming. it never
touches web/. still idempotent.
release tags are namespaced — v* for the app, web-v* for the server —
so a server release no longer triggers a macOS build or rewrites
app-repo.json. workflows are prefixed ios-/web- and path-filtered.
55 lines
1.6 KiB
Swift
55 lines
1.6 KiB
Swift
//
|
|
// UIKitFileImporter.swift
|
|
// Feather
|
|
//
|
|
// Created by samara on 23.04.2025.
|
|
//
|
|
|
|
import SwiftUI
|
|
import UniformTypeIdentifiers
|
|
|
|
public struct FileImporterRepresentableView: UIViewControllerRepresentable {
|
|
public var allowedContentTypes: [UTType]
|
|
public var allowsMultipleSelection: Bool = false
|
|
public var onDocumentsPicked: ([URL]) -> Void
|
|
|
|
public init(
|
|
allowedContentTypes: [UTType],
|
|
allowsMultipleSelection: Bool = false,
|
|
onDocumentsPicked: @escaping ([URL]) -> Void
|
|
) {
|
|
self.allowedContentTypes = allowedContentTypes
|
|
self.allowsMultipleSelection = allowsMultipleSelection
|
|
self.onDocumentsPicked = onDocumentsPicked
|
|
}
|
|
|
|
public func makeCoordinator() -> Coordinator {
|
|
Coordinator(onDocumentsPicked: onDocumentsPicked)
|
|
}
|
|
|
|
public func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
|
|
let picker = UIDocumentPickerViewController(forOpeningContentTypes: allowedContentTypes, asCopy: true)
|
|
picker.delegate = context.coordinator
|
|
picker.allowsMultipleSelection = allowsMultipleSelection
|
|
return picker
|
|
}
|
|
|
|
public func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {}
|
|
|
|
public class Coordinator: NSObject, UIDocumentPickerDelegate {
|
|
var onDocumentsPicked: ([URL]) -> Void
|
|
|
|
init(onDocumentsPicked: @escaping ([URL]) -> Void) {
|
|
self.onDocumentsPicked = onDocumentsPicked
|
|
}
|
|
|
|
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
|
|
onDocumentsPicked(urls)
|
|
}
|
|
|
|
public func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
|
|
onDocumentsPicked([])
|
|
}
|
|
}
|
|
}
|