mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-03-28 12:35:27 +00:00
Migrate drafts to SwiftData
This commit is contained in:
parent
7eec1b8439
commit
0c4bde40af
8 changed files with 123 additions and 61 deletions
|
@ -47,7 +47,7 @@
|
|||
9F35DB4729506F6600B3281A /* NotificationTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F35DB4629506F6600B3281A /* NotificationTab.swift */; };
|
||||
9F35DB4A29506FA100B3281A /* Notifications in Frameworks */ = {isa = PBXBuildFile; productRef = 9F35DB4929506FA100B3281A /* Notifications */; };
|
||||
9F35DB4C2952005C00B3281A /* MessagesTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F35DB4B2952005C00B3281A /* MessagesTab.swift */; };
|
||||
9F398AA62935FE8A00A889F2 /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F398AA52935FE8A00A889F2 /* AppRouter.swift */; };
|
||||
9F398AA62935FE8A00A889F2 /* AppRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F398AA52935FE8A00A889F2 /* AppRegistry.swift */; };
|
||||
9F398AA92935FFDB00A889F2 /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 9F398AA82935FFDB00A889F2 /* Account */; };
|
||||
9F398AAB2935FFDB00A889F2 /* Models in Frameworks */ = {isa = PBXBuildFile; productRef = 9F398AAA2935FFDB00A889F2 /* Models */; };
|
||||
9F398AB329360A4C00A889F2 /* TimelineTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F398AB229360A4C00A889F2 /* TimelineTab.swift */; };
|
||||
|
@ -207,7 +207,7 @@
|
|||
9F35DB4B2952005C00B3281A /* MessagesTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesTab.swift; sourceTree = "<group>"; };
|
||||
9F38C233297D03120018F11E /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
9F398AA32935F90100A889F2 /* Models */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Models; path = Packages/Models; sourceTree = "<group>"; };
|
||||
9F398AA52935FE8A00A889F2 /* AppRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = "<group>"; };
|
||||
9F398AA52935FE8A00A889F2 /* AppRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRegistry.swift; sourceTree = "<group>"; };
|
||||
9F398AAC2936005300A889F2 /* Account */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Account; path = Packages/Account; sourceTree = "<group>"; };
|
||||
9F398AB229360A4C00A889F2 /* TimelineTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTab.swift; sourceTree = "<group>"; };
|
||||
9F4A48182976B21900A1A038 /* ProfileTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileTab.swift; sourceTree = "<group>"; };
|
||||
|
@ -377,7 +377,7 @@
|
|||
9F654BF0299AC46200D27FA5 /* Report */,
|
||||
9FAE4AC9293783A200772766 /* Tabs */,
|
||||
9FBFE63C292A715500C250E9 /* IceCubesApp.swift */,
|
||||
9F398AA52935FE8A00A889F2 /* AppRouter.swift */,
|
||||
9F398AA52935FE8A00A889F2 /* AppRegistry.swift */,
|
||||
639CDF9B296AC82F00C35E58 /* SafariRouter.swift */,
|
||||
9FAD85A7297582F100496AB1 /* QuickLookRepresentable.swift */,
|
||||
9FAD85CE2975B68900496AB1 /* SideBarView.swift */,
|
||||
|
@ -842,7 +842,7 @@
|
|||
FA31A9AB2A66BF7C00D5F662 /* EditTagGroupView.swift in Sources */,
|
||||
FAD203D02A66D8A80030A7FD /* Symbols.swift in Sources */,
|
||||
9F398AB329360A4C00A889F2 /* TimelineTab.swift in Sources */,
|
||||
9F398AA62935FE8A00A889F2 /* AppRouter.swift in Sources */,
|
||||
9F398AA62935FE8A00A889F2 /* AppRegistry.swift in Sources */,
|
||||
9FBFE63D292A715500C250E9 /* IceCubesApp.swift in Sources */,
|
||||
9F4A48192976B21900A1A038 /* ProfileTab.swift in Sources */,
|
||||
9F2B92FA295DA7D700DE16D0 /* AddAccountsView.swift in Sources */,
|
||||
|
|
|
@ -120,6 +120,12 @@ extension View {
|
|||
.environment(PushNotificationsService.shared)
|
||||
.environment(AppAccountsManager.shared.currentClient)
|
||||
}
|
||||
|
||||
func withModelContainer() -> some View {
|
||||
modelContainer(for: [
|
||||
Draft.self,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
struct ActivityView: UIViewControllerRepresentable {
|
|
@ -8,6 +8,7 @@ import Network
|
|||
import RevenueCat
|
||||
import SwiftUI
|
||||
import Timeline
|
||||
import Status
|
||||
|
||||
@main
|
||||
struct IceCubesApp: App {
|
||||
|
@ -75,6 +76,7 @@ struct IceCubesApp: App {
|
|||
}
|
||||
}
|
||||
}
|
||||
.withModelContainer()
|
||||
}
|
||||
.commands {
|
||||
appMenu
|
||||
|
|
|
@ -10,7 +10,6 @@ import SwiftUI
|
|||
@AppStorage("remote_local_timeline") public var remoteLocalTimelines: [String] = []
|
||||
@AppStorage("tag_groups") public var tagGroups: [TagGroup] = []
|
||||
@AppStorage("preferred_browser") public var preferredBrowser: PreferredBrowser = .inAppSafari
|
||||
@AppStorage("draft_posts") public var draftsPosts: [String] = []
|
||||
@AppStorage("show_translate_button_inline") public var showTranslateButton: Bool = true
|
||||
@AppStorage("is_open_ai_enabled") public var isOpenAIEnabled: Bool = true
|
||||
|
||||
|
@ -79,11 +78,7 @@ import SwiftUI
|
|||
storage.preferredBrowser = preferredBrowser
|
||||
}
|
||||
}
|
||||
public var draftsPosts: [String] {
|
||||
didSet {
|
||||
storage.draftsPosts = draftsPosts
|
||||
}
|
||||
}
|
||||
|
||||
public var showTranslateButton: Bool {
|
||||
didSet {
|
||||
storage.showTranslateButton = showTranslateButton
|
||||
|
@ -379,7 +374,6 @@ import SwiftUI
|
|||
remoteLocalTimelines = storage.remoteLocalTimelines
|
||||
tagGroups = storage.tagGroups
|
||||
preferredBrowser = storage.preferredBrowser
|
||||
draftsPosts = storage.draftsPosts
|
||||
showTranslateButton = storage.showTranslateButton
|
||||
isOpenAIEnabled = storage.isOpenAIEnabled
|
||||
recentlyUsedLanguages = storage.recentlyUsedLanguages
|
||||
|
|
|
@ -111,9 +111,10 @@ struct StatusEditorAccessoryView: View {
|
|||
.accessibilityLabel("accessibility.editor.button.drafts")
|
||||
.popover(isPresented: $isDraftsSheetDisplayed) {
|
||||
if UIDevice.current.userInterfaceIdiom == .phone {
|
||||
draftsSheetView
|
||||
draftsListView
|
||||
.presentationDetents([.medium])
|
||||
} else {
|
||||
draftsSheetView
|
||||
draftsListView
|
||||
.frame(width: 400, height: 500)
|
||||
}
|
||||
}
|
||||
|
@ -176,6 +177,16 @@ struct StatusEditorAccessoryView: View {
|
|||
viewModel.setInitialLanguageSelection(preference: preferences.recentlyUsedLanguages.first ?? preferences.serverPreferences?.postLanguage)
|
||||
}
|
||||
}
|
||||
|
||||
private var draftsListView: some View {
|
||||
DraftsListView(selectedDraft: .init(get: {
|
||||
nil
|
||||
}, set: { draft in
|
||||
if let draft {
|
||||
viewModel.insertStatusText(text: draft.content)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func languageTextView(isoCode: String, nativeName: String?, name: String?) -> some View {
|
||||
|
@ -269,38 +280,6 @@ struct StatusEditorAccessoryView: View {
|
|||
}
|
||||
}
|
||||
|
||||
private var draftsSheetView: some View {
|
||||
NavigationStack {
|
||||
List {
|
||||
ForEach(preferences.draftsPosts, id: \.self) { draft in
|
||||
Button {
|
||||
viewModel.insertStatusText(text: draft)
|
||||
isDraftsSheetDisplayed = false
|
||||
} label: {
|
||||
Text(draft)
|
||||
.lineLimit(3)
|
||||
.foregroundStyle(theme.labelColor)
|
||||
}.listRowBackground(theme.primaryBackgroundColor)
|
||||
}
|
||||
.onDelete { indexes in
|
||||
if let index = indexes.first {
|
||||
preferences.draftsPosts.remove(at: index)
|
||||
}
|
||||
}
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button("action.cancel", action: { isDraftsSheetDisplayed = false })
|
||||
}
|
||||
}
|
||||
.scrollContentBackground(.hidden)
|
||||
.background(theme.secondaryBackgroundColor)
|
||||
.navigationTitle("status.editor.drafts.navigation-title")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
.presentationDetents([.medium])
|
||||
}
|
||||
|
||||
private var customEmojisSheet: some View {
|
||||
NavigationStack {
|
||||
ScrollView {
|
||||
|
|
15
Packages/Status/Sources/Status/Editor/Drafts/Draft.swift
Normal file
15
Packages/Status/Sources/Status/Editor/Drafts/Draft.swift
Normal file
|
@ -0,0 +1,15 @@
|
|||
import SwiftData
|
||||
import SwiftUI
|
||||
import Foundation
|
||||
|
||||
@Model public class Draft: Identifiable {
|
||||
@Attribute(.unique) public var id: UUID
|
||||
public var content: String
|
||||
public var creationDate: Date
|
||||
|
||||
public init(content: String) {
|
||||
self.id = UUID()
|
||||
self.content = content
|
||||
self.creationDate = Date()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
import SwiftUI
|
||||
import SwiftData
|
||||
import DesignSystem
|
||||
|
||||
struct DraftsListView: View {
|
||||
@AppStorage("draft_posts") public var legacyDraftPosts: [String] = []
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@Environment(\.modelContext) private var context
|
||||
|
||||
@Environment(Theme.self) private var theme
|
||||
|
||||
@Query(sort: \Draft.creationDate, order: .reverse) var drafts: [Draft]
|
||||
|
||||
@Binding var selectedDraft: Draft?
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
List {
|
||||
ForEach(drafts) { draft in
|
||||
Button {
|
||||
selectedDraft = draft
|
||||
dismiss()
|
||||
} label: {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(draft.content)
|
||||
.font(.body)
|
||||
.lineLimit(3)
|
||||
.foregroundStyle(theme.labelColor)
|
||||
Text(draft.creationDate, style: .relative)
|
||||
.font(.footnote)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
}.listRowBackground(theme.primaryBackgroundColor)
|
||||
}
|
||||
.onDelete { indexes in
|
||||
if let index = indexes.first {
|
||||
context.delete(drafts[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button("action.cancel", action: { dismiss() })
|
||||
}
|
||||
}
|
||||
.scrollContentBackground(.hidden)
|
||||
.background(theme.secondaryBackgroundColor)
|
||||
.navigationTitle("status.editor.drafts.navigation-title")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.onAppear {
|
||||
migrateUserPreferencesDraft()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func migrateUserPreferencesDraft() {
|
||||
for draft in legacyDraftPosts {
|
||||
let newDraft = Draft(content: draft)
|
||||
context.insert(newDraft)
|
||||
}
|
||||
legacyDraftPosts = []
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ public struct StatusEditorView: View {
|
|||
@Environment(Client.self) private var client
|
||||
@Environment(CurrentAccount.self) private var currentAccount
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@Environment(\.modelContext) private var context
|
||||
|
||||
@State private var viewModel: StatusEditorViewModel
|
||||
@FocusState private var isSpoilerTextFocused: Bool
|
||||
|
@ -144,22 +145,23 @@ public struct StatusEditorView: View {
|
|||
Text("action.cancel")
|
||||
}
|
||||
.keyboardShortcut(.cancelAction)
|
||||
.confirmationDialog("",
|
||||
isPresented: $isDismissAlertPresented,
|
||||
actions: {
|
||||
Button("status.draft.delete", role: .destructive) {
|
||||
dismiss()
|
||||
NotificationCenter.default.post(name: NotificationsName.shareSheetClose,
|
||||
object: nil)
|
||||
}
|
||||
Button("status.draft.save") {
|
||||
preferences.draftsPosts.insert(viewModel.statusText.string, at: 0)
|
||||
dismiss()
|
||||
NotificationCenter.default.post(name: NotificationsName.shareSheetClose,
|
||||
object: nil)
|
||||
}
|
||||
Button("action.cancel", role: .cancel) {}
|
||||
})
|
||||
.confirmationDialog(
|
||||
"",
|
||||
isPresented: $isDismissAlertPresented,
|
||||
actions: {
|
||||
Button("status.draft.delete", role: .destructive) {
|
||||
dismiss()
|
||||
NotificationCenter.default.post(name: NotificationsName.shareSheetClose,
|
||||
object: nil)
|
||||
}
|
||||
Button("status.draft.save") {
|
||||
context.insert(Draft(content: viewModel.statusText.string))
|
||||
dismiss()
|
||||
NotificationCenter.default.post(name: NotificationsName.shareSheetClose,
|
||||
object: nil)
|
||||
}
|
||||
Button("action.cancel", role: .cancel) {}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue