Merge pull request #2384 from rizwankce/import-export-subscription
Fix import/export subscriptions
This commit is contained in:
commit
fee08ef187
@ -9,6 +9,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Account
|
import Account
|
||||||
|
import UniformTypeIdentifiers
|
||||||
|
|
||||||
enum FeedsSettingsError: LocalizedError, Equatable {
|
enum FeedsSettingsError: LocalizedError, Equatable {
|
||||||
case none, noActiveAccount, exportFailed(reason: String?), importFailed
|
case none, noActiveAccount, exportFailed(reason: String?), importFailed
|
||||||
@ -51,6 +52,11 @@ class FeedsSettingsModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Published var showError: Bool = false
|
@Published var showError: Bool = false
|
||||||
|
@Published var isImporting: Bool = false
|
||||||
|
@Published var isExporting: Bool = false
|
||||||
|
@Published var selectedAccount: Account? = nil
|
||||||
|
|
||||||
|
let importingContentTypes: [UTType] = [UTType(filenameExtension: "opml"), UTType("public.xml")].compactMap { $0 }
|
||||||
|
|
||||||
func checkForActiveAccount() -> Bool {
|
func checkForActiveAccount() -> Bool {
|
||||||
if AccountManager.shared.activeAccounts.count == 0 {
|
if AccountManager.shared.activeAccounts.count == 0 {
|
||||||
@ -60,7 +66,18 @@ class FeedsSettingsModel: ObservableObject {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateExportURL(for account: Account) -> URL? {
|
func importOPML(account: Account?) {
|
||||||
|
selectedAccount = account
|
||||||
|
isImporting = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportOPML(account: Account?) {
|
||||||
|
selectedAccount = account
|
||||||
|
isExporting = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateExportURL() -> URL? {
|
||||||
|
guard let account = selectedAccount else { return nil }
|
||||||
let accountName = account.nameForDisplay.replacingOccurrences(of: " ", with: "").trimmingCharacters(in: .whitespaces)
|
let accountName = account.nameForDisplay.replacingOccurrences(of: " ", with: "").trimmingCharacters(in: .whitespaces)
|
||||||
let filename = "Subscriptions-\(accountName).opml"
|
let filename = "Subscriptions-\(accountName).opml"
|
||||||
let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(filename)
|
let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(filename)
|
||||||
@ -75,9 +92,9 @@ class FeedsSettingsModel: ObservableObject {
|
|||||||
return tempFile
|
return tempFile
|
||||||
}
|
}
|
||||||
|
|
||||||
func processImportedFiles(_ urls: [URL],_ account: Account?) {
|
func processImportedFiles(_ urls: [URL]) {
|
||||||
urls.forEach{
|
urls.forEach{
|
||||||
account?.importOPML($0, completion: { [weak self] result in
|
selectedAccount?.importOPML($0, completion: { [weak self] result in
|
||||||
switch result {
|
switch result {
|
||||||
case .success:
|
case .success:
|
||||||
break
|
break
|
||||||
|
@ -8,13 +8,10 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Account
|
import Account
|
||||||
import UniformTypeIdentifiers
|
|
||||||
|
|
||||||
struct SettingsView: View {
|
struct SettingsView: View {
|
||||||
|
|
||||||
@Environment(\.presentationMode) var presentationMode
|
@Environment(\.presentationMode) var presentationMode
|
||||||
@Environment(\.exportFiles) var exportAction
|
|
||||||
@Environment(\.importFiles) var importAction
|
|
||||||
|
|
||||||
@StateObject private var viewModel = SettingsModel()
|
@StateObject private var viewModel = SettingsModel()
|
||||||
@StateObject private var feedsSettingsModel = FeedsSettingsModel()
|
@StateObject private var feedsSettingsModel = FeedsSettingsModel()
|
||||||
@ -41,6 +38,18 @@ struct SettingsView: View {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
.fileImporter(
|
||||||
|
isPresented: $feedsSettingsModel.isImporting,
|
||||||
|
allowedContentTypes: feedsSettingsModel.importingContentTypes,
|
||||||
|
allowsMultipleSelection: true,
|
||||||
|
onCompletion: { result in
|
||||||
|
if let urls = try? result.get() {
|
||||||
|
feedsSettingsModel.processImportedFiles(urls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.fileMover(isPresented: $feedsSettingsModel.isExporting,
|
||||||
|
file: feedsSettingsModel.generateExportURL()) { _ in }
|
||||||
.sheet(isPresented: $viewModel.presentSheet, content: {
|
.sheet(isPresented: $viewModel.presentSheet, content: {
|
||||||
SafariView(url: viewModel.selectedWebsite.url!)
|
SafariView(url: viewModel.selectedWebsite.url!)
|
||||||
})
|
})
|
||||||
@ -81,7 +90,7 @@ struct SettingsView: View {
|
|||||||
else {
|
else {
|
||||||
Button(action:{
|
Button(action:{
|
||||||
if feedsSettingsModel.checkForActiveAccount() {
|
if feedsSettingsModel.checkForActiveAccount() {
|
||||||
importOPML(account: viewModel.activeAccounts.first)
|
feedsSettingsModel.importOPML(account: viewModel.activeAccounts.first)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Text("Import Subscriptions")
|
Text("Import Subscriptions")
|
||||||
@ -94,7 +103,7 @@ struct SettingsView: View {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Button(action:{
|
Button(action:{
|
||||||
exportOPML(account: viewModel.accounts.first)
|
feedsSettingsModel.exportOPML(account: viewModel.accounts.first)
|
||||||
}) {
|
}) {
|
||||||
Text("Export Subscriptions")
|
Text("Export Subscriptions")
|
||||||
.foregroundColor(.primary)
|
.foregroundColor(.primary)
|
||||||
@ -118,7 +127,7 @@ struct SettingsView: View {
|
|||||||
Section(header: Text("Choose an account to receive the imported feeds and folders"), content: {
|
Section(header: Text("Choose an account to receive the imported feeds and folders"), content: {
|
||||||
ForEach(0..<viewModel.activeAccounts.count, id: \.hashValue , content: { i in
|
ForEach(0..<viewModel.activeAccounts.count, id: \.hashValue , content: { i in
|
||||||
Button {
|
Button {
|
||||||
importOPML(account: viewModel.activeAccounts[i])
|
feedsSettingsModel.importOPML(account: viewModel.activeAccounts[i])
|
||||||
} label: {
|
} label: {
|
||||||
Text(viewModel.activeAccounts[i].nameForDisplay)
|
Text(viewModel.activeAccounts[i].nameForDisplay)
|
||||||
}
|
}
|
||||||
@ -134,7 +143,7 @@ struct SettingsView: View {
|
|||||||
Section(header: Text("Choose an account with the subscriptions to export"), content: {
|
Section(header: Text("Choose an account with the subscriptions to export"), content: {
|
||||||
ForEach(0..<viewModel.accounts.count, id: \.hashValue , content: { i in
|
ForEach(0..<viewModel.accounts.count, id: \.hashValue , content: { i in
|
||||||
Button {
|
Button {
|
||||||
exportOPML(account: viewModel.accounts[i])
|
feedsSettingsModel.exportOPML(account: viewModel.accounts[i])
|
||||||
} label: {
|
} label: {
|
||||||
Text(viewModel.accounts[i].nameForDisplay)
|
Text(viewModel.accounts[i].nameForDisplay)
|
||||||
}
|
}
|
||||||
@ -226,23 +235,6 @@ struct SettingsView: View {
|
|||||||
return "NetNewsWire \(version) (Build \(build))"
|
return "NetNewsWire \(version) (Build \(build))"
|
||||||
}
|
}
|
||||||
|
|
||||||
private func exportOPML(account: Account?) {
|
|
||||||
guard let account = account,
|
|
||||||
let url = feedsSettingsModel.generateExportURL(for: account) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
exportAction(moving: url) { _ in }
|
|
||||||
}
|
|
||||||
|
|
||||||
private func importOPML(account: Account?) {
|
|
||||||
let types = [UTType(filenameExtension: "opml"), UTType("public.xml")].compactMap { $0 }
|
|
||||||
importAction(multipleOfType: types) { (result: Result<[URL], Error>?) in
|
|
||||||
if let urls = try? result?.get() {
|
|
||||||
feedsSettingsModel.processImportedFiles(urls, account)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SettingsView_Previews: PreviewProvider {
|
struct SettingsView_Previews: PreviewProvider {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user