closed #113 - import / export
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
<key>Feels (macOS).xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>3</integer>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
<key>FeelsWidgetExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
||||
@@ -7,12 +7,17 @@
|
||||
|
||||
import SwiftUI
|
||||
import CloudKitSyncMonitor
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
struct SettingsView: View {
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
@State private var showOnboarding = false
|
||||
@State private var showingExporter = false
|
||||
@State private var showingImporter = false
|
||||
@State private var importContent = ""
|
||||
|
||||
@State private var showOnboarding = false
|
||||
|
||||
@State private var showSpecialThanks = false
|
||||
@State private var showWhyBGMode = false
|
||||
@ObservedObject var syncMonitor = SyncMonitor.shared
|
||||
@@ -44,6 +49,9 @@ struct SettingsView: View {
|
||||
if useCloudKit {
|
||||
cloudKitStatus
|
||||
}
|
||||
|
||||
exportData
|
||||
importData
|
||||
}
|
||||
Spacer()
|
||||
|
||||
@@ -62,6 +70,57 @@ struct SettingsView: View {
|
||||
theme.currentTheme.bg
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
)
|
||||
.fileExporter(isPresented: $showingExporter,
|
||||
documents: [
|
||||
TextFile()
|
||||
],
|
||||
contentType: .plainText,
|
||||
onCompletion: { result in
|
||||
switch result {
|
||||
case .success(let url):
|
||||
print("Saved to \(url)")
|
||||
case .failure(let error):
|
||||
print(error.localizedDescription)
|
||||
}
|
||||
})
|
||||
.fileImporter(isPresented: $showingImporter, allowedContentTypes: [.text],
|
||||
allowsMultipleSelection: false) { result in
|
||||
do {
|
||||
guard let selectedFile: URL = try result.get().first else { return }
|
||||
if selectedFile.startAccessingSecurityScopedResource() {
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss +0000"
|
||||
|
||||
guard let input = String(data: try Data(contentsOf: selectedFile), encoding: .utf8) else { return }
|
||||
defer { selectedFile.stopAccessingSecurityScopedResource() }
|
||||
|
||||
var rows = input.components(separatedBy: "\n")
|
||||
rows.removeFirst()
|
||||
for row in rows {
|
||||
let columns = row.components(separatedBy: ",")
|
||||
if columns.count != 7 {
|
||||
continue
|
||||
}
|
||||
let moodEntry = MoodEntry(context: PersistenceController.shared.viewContext)
|
||||
moodEntry.canDelete = Bool(columns[0])!
|
||||
moodEntry.canEdit = Bool(columns[1])!
|
||||
moodEntry.entryType = Int16(columns[2])!
|
||||
moodEntry.forDate = dateFormatter.date(from: columns[3])
|
||||
moodEntry.moodValue = Int16(columns[4])!
|
||||
moodEntry.timestamp = dateFormatter.date(from: columns[5])
|
||||
moodEntry.weekDay = Int16(columns[6])!
|
||||
try! PersistenceController.shared.viewContext.save()
|
||||
}
|
||||
PersistenceController.shared.saveAndRunDataListerners()
|
||||
} else {
|
||||
// Handle denied access
|
||||
}
|
||||
} catch {
|
||||
// Handle failure.
|
||||
print("Unable to read file contents")
|
||||
print(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var closeButtonView: some View {
|
||||
@@ -222,6 +281,34 @@ struct SettingsView: View {
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var exportData: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
showingExporter.toggle()
|
||||
}, label: {
|
||||
Text("Export")
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var importData: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
showingImporter.toggle()
|
||||
}, label: {
|
||||
Text("Import")
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(10, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
private var randomIcons: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
@@ -354,6 +441,50 @@ struct SettingsView: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct TextFile: FileDocument {
|
||||
// tell the system we support only plain text
|
||||
static var readableContentTypes = [UTType.plainText]
|
||||
|
||||
// by default our document is empty
|
||||
var text = ""
|
||||
|
||||
// a simple initializer that creates new, empty documents
|
||||
init() {
|
||||
let entries = PersistenceController.shared.getData(startDate: Date(timeIntervalSince1970: 0),
|
||||
endDate: Date(),
|
||||
includedDays: [])
|
||||
|
||||
var csvString = "canDelete,canEdit,entryType,forDate,moodValue,timestamp,weekDay\n"
|
||||
for entry in entries {
|
||||
let canDelete = entry.canDelete
|
||||
let canEdit = entry.canEdit
|
||||
let entryType = entry.entryType
|
||||
let forDate = entry.forDate!
|
||||
let moodValue = entry.moodValue
|
||||
let timestamp = entry.timestamp!
|
||||
let weekDay = entry.weekDay
|
||||
|
||||
let dataString = "\(canDelete),\(canEdit),\(entryType),\(String(describing: forDate)),\(moodValue),\(String(describing:timestamp)),\(weekDay)\n"
|
||||
print("DATA: \(dataString)")
|
||||
csvString = csvString.appending(dataString)
|
||||
}
|
||||
text = csvString
|
||||
}
|
||||
|
||||
// this initializer loads data that has been saved previously
|
||||
init(configuration: ReadConfiguration) throws {
|
||||
if let data = configuration.file.regularFileContents {
|
||||
text = String(decoding: data, as: UTF8.self)
|
||||
}
|
||||
}
|
||||
|
||||
// this will be called when the system wants to write our data to disk
|
||||
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
|
||||
let data = Data(text.utf8)
|
||||
return FileWrapper(regularFileWithContents: data)
|
||||
}
|
||||
}
|
||||
|
||||
struct SettingsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
SettingsView()
|
||||
|
||||
Reference in New Issue
Block a user