Merge pull request #2384 from rizwankce/import-export-subscription

Fix import/export subscriptions
This commit is contained in:
Maurice Parker 2020-08-28 14:12:40 -05:00 committed by GitHub
commit fee08ef187
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 27 deletions

View File

@ -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

View File

@ -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 {