feat(share): refine image themes and persist settings across clients
This commit is contained in:
1 parent
70d486e4d7
commit
776fc3b566
410 files changed
+5671
-4478
No files matched your search
@@ -57,6 +57,7 @@
|
||||
88A1141343A4E255A8050CB6 /* RevisionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 328A2DAC7E7DC89F4782B5FB /* RevisionsView.swift */; };
|
||||
88C20914237162E295798B54 /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 1B167394120674FECA86D42F /* GRDB */; };
|
||||
8C761DABADB93F2F15E21E80 /* EditFabButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2829CE5DF5C15ACF41CC17DA /* EditFabButton.swift */; };
|
||||
8E1CB597E6534EBFAD4B43FE /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 01D34117A78B1F5C367ACDBB /* assets */; };
|
||||
90FFFFD00B2D19F96EA299C8 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5126510AFB9AFBF7ABADB45 /* Models.swift */; };
|
||||
93556FDCB87BB93990221E01 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8691859094F8C08AE49FE27D /* Assets.xcassets */; };
|
||||
94456E5BCAB7496FAD4685A6 /* Pow in Frameworks */ = {isa = PBXBuildFile; productRef = E37BD605D826474D3E842F31 /* Pow */; };
|
||||
@@ -120,6 +121,7 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
01D34117A78B1F5C367ACDBB /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = assets; path = EdgeEver/Resources/EditorBundle/assets; sourceTree = SOURCE_ROOT; };
|
||||
033565CE2E96EC2D23105188 /* ListActionsSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListActionsSheet.swift; sourceTree = "<group>"; };
|
||||
0531FC6AA81DAF0A55B42362 /* AppDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDatabase.swift; sourceTree = "<group>"; };
|
||||
0EF7E97C950002FA22EFB7C8 /* AiDirectStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AiDirectStream.swift; sourceTree = "<group>"; };
|
||||
@@ -342,6 +344,7 @@
|
||||
821234A55C8B7CF544B28EE6 /* EditorBundle */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
01D34117A78B1F5C367ACDBB /* assets */,
|
||||
AB02424D0412FE36C4BCD116 /* index.html */,
|
||||
);
|
||||
path = EditorBundle;
|
||||
@@ -618,6 +621,7 @@
|
||||
93556FDCB87BB93990221E01 /* Assets.xcassets in Resources */,
|
||||
06D2661CAB0ADED27F322649 /* Localizable.xcstrings in Resources */,
|
||||
C37DA99E090A783562506CDA /* PrivacyInfo.xcprivacy in Resources */,
|
||||
8E1CB597E6534EBFAD4B43FE /* assets in Resources */,
|
||||
08D0159B8F194E04C02B69BF /* index.html in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
||||
@@ -32,6 +32,55 @@ enum AppUILocale {
|
||||
}
|
||||
}
|
||||
|
||||
/// Local image-share choices, independent of the current note or sheet lifetime.
|
||||
struct NoteImageSharePreferences: Codable, Equatable {
|
||||
var theme: String = "gradient"
|
||||
var fontStyle: String = "auto"
|
||||
var fontSize: String = "lg"
|
||||
var cardWidth: String = "wide"
|
||||
var format: String = "png"
|
||||
var showTitle: Bool = true
|
||||
var showNotebook: Bool = false
|
||||
var showTags: Bool = false
|
||||
var showUpdatedAt: Bool = true
|
||||
var showBranding: Bool = true
|
||||
|
||||
init() {}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case theme, fontStyle, fontSize, cardWidth, format, showTitle, showNotebook, showTags, showUpdatedAt, showBranding
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
if let value = try? values.decode(String.self, forKey: .theme),
|
||||
["gradient", "glass", "quote", "book", "memo", "bento", "black-sun", "frame", "handwritten", "code"].contains(value) {
|
||||
theme = value
|
||||
}
|
||||
if let value = try? values.decode(String.self, forKey: .fontStyle),
|
||||
["auto", "serif", "sans", "mono", "kai"].contains(value) {
|
||||
fontStyle = value
|
||||
}
|
||||
if let value = try? values.decode(String.self, forKey: .fontSize),
|
||||
["sm", "md", "lg"].contains(value) {
|
||||
fontSize = value
|
||||
}
|
||||
if let value = try? values.decode(String.self, forKey: .cardWidth),
|
||||
["compact", "standard", "wide"].contains(value) {
|
||||
cardWidth = value
|
||||
}
|
||||
if let value = try? values.decode(String.self, forKey: .format),
|
||||
["png", "jpeg"].contains(value) {
|
||||
format = value
|
||||
}
|
||||
showTitle = (try? values.decode(Bool.self, forKey: .showTitle)) ?? true
|
||||
showNotebook = (try? values.decode(Bool.self, forKey: .showNotebook)) ?? false
|
||||
showTags = (try? values.decode(Bool.self, forKey: .showTags)) ?? false
|
||||
showUpdatedAt = (try? values.decode(Bool.self, forKey: .showUpdatedAt)) ?? true
|
||||
showBranding = (try? values.decode(Bool.self, forKey: .showBranding)) ?? true
|
||||
}
|
||||
}
|
||||
|
||||
@Observable
|
||||
@MainActor
|
||||
final class PreferencesStore {
|
||||
@@ -64,8 +113,22 @@ final class PreferencesStore {
|
||||
didSet { persistAiAssistantLastAction() }
|
||||
}
|
||||
|
||||
var noteImageShare: NoteImageSharePreferences {
|
||||
didSet {
|
||||
if let data = try? JSONEncoder().encode(noteImageShare) {
|
||||
defaults.set(data, forKey: Keys.noteImageShare)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init(defaults: UserDefaults = .standard) {
|
||||
self.defaults = defaults
|
||||
if let data = defaults.data(forKey: Keys.noteImageShare),
|
||||
let saved = try? JSONDecoder().decode(NoteImageSharePreferences.self, from: data) {
|
||||
self.noteImageShare = saved
|
||||
} else {
|
||||
self.noteImageShare = NoteImageSharePreferences()
|
||||
}
|
||||
self.localeCode = defaults.string(forKey: Keys.locale) ?? "system"
|
||||
self.useCompression = defaults.object(forKey: Keys.compression) as? Bool ?? true
|
||||
self.showDescendantNotes = defaults.object(forKey: Keys.showDescendantNotes) as? Bool ?? true
|
||||
@@ -157,6 +220,7 @@ final class PreferencesStore {
|
||||
}
|
||||
|
||||
private enum Keys {
|
||||
static let noteImageShare = "edgeever.ios.noteImagePreferences"
|
||||
static let locale = "edgeever.ios.locale"
|
||||
static let compression = "edgeever.ios.imageCompression"
|
||||
static let showDescendantNotes = "edgeever.ios.showDescendantNotes"
|
||||
|
||||
@@ -23,16 +23,6 @@ struct MemoDetailView: View {
|
||||
@State private var imageExportRequestId: String?
|
||||
@State private var imageExportBuffer = MemoImageExportBuffer()
|
||||
@State private var imageShareOptionsOpen = false
|
||||
@State private var imageShareFormat = "png"
|
||||
@State private var imageShareTheme = "mint"
|
||||
@State private var imageShareFontStyle = "auto"
|
||||
@State private var imageShareFontSize = "lg"
|
||||
@State private var imageShareCardWidth = "wide"
|
||||
@State private var imageShareTitle = true
|
||||
@State private var imageShareNotebook = false
|
||||
@State private var imageShareTags = false
|
||||
@State private var imageShareUpdatedAt = true
|
||||
@State private var imageShareBranding = true
|
||||
@State private var imageExportIntent: MemoImageExportIntent = .share
|
||||
@State private var error: String?
|
||||
@State private var conflictItem: OutboxItem?
|
||||
@@ -56,7 +46,8 @@ struct MemoDetailView: View {
|
||||
@State private var initialShareImageHandled = false
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
@Bindable var preferences = env.preferences
|
||||
return VStack(spacing: 0) {
|
||||
detailHeader
|
||||
if syncStatus == .conflict, memo != nil {
|
||||
conflictBanner
|
||||
@@ -187,19 +178,22 @@ struct MemoDetailView: View {
|
||||
NavigationStack {
|
||||
Form {
|
||||
Section(env.preferences.t("主题风格", en: "Theme", pl: "Motyw")) {
|
||||
Picker(env.preferences.t("主题风格", en: "Theme", pl: "Motyw"), selection: $imageShareTheme) {
|
||||
Text(env.preferences.t("纯白", en: "Pure White", pl: "Czysta biel")).tag("slate")
|
||||
Text(env.preferences.t("薄荷", en: "Mint", pl: "Mięta")).tag("mint")
|
||||
Text(env.preferences.t("极光渐变", en: "Aurora", pl: "Zorza")).tag("aurora")
|
||||
Text(env.preferences.t("暮色晚霞", en: "Sunset", pl: "Zachód słońca")).tag("sunset")
|
||||
Text(env.preferences.t("黑白编辑", en: "Black & White", pl: "Czerń i biel")).tag("editorial")
|
||||
Text(env.preferences.t("极客终端", en: "Terminal", pl: "Terminal")).tag("terminal")
|
||||
Text(env.preferences.t("书页", en: "Book Page", pl: "Strona książki")).tag("film")
|
||||
Picker(env.preferences.t("主题风格", en: "Theme", pl: "Motyw"), selection: $preferences.noteImageShare.theme) {
|
||||
Text(env.preferences.t("默认", en: "Classic", pl: "Klasyczny")).tag("gradient")
|
||||
Text(env.preferences.t("透明", en: "Glass", pl: "Szkło")).tag("glass")
|
||||
Text(env.preferences.t("金句", en: "Quote", pl: "Cytat")).tag("quote")
|
||||
Text(env.preferences.t("书摘", en: "Book excerpt", pl: "Fragment książki")).tag("book")
|
||||
Text(env.preferences.t("备忘录", en: "Memo", pl: "Notatka")).tag("memo")
|
||||
Text(env.preferences.t("便当", en: "Bento", pl: "Bento")).tag("bento")
|
||||
Text(env.preferences.t("黑日", en: "Black Sun", pl: "Czarne słońce")).tag("black-sun")
|
||||
Text(env.preferences.t("框界", en: "Frame", pl: "Ramka")).tag("frame")
|
||||
Text(env.preferences.t("手写", en: "Handwritten", pl: "Pismo odręczne")).tag("handwritten")
|
||||
Text(env.preferences.t("代码", en: "Code", pl: "Kod")).tag("code")
|
||||
}
|
||||
.pickerStyle(.menu)
|
||||
}
|
||||
Section(env.preferences.t("字体风格", en: "Typography", pl: "Typografia")) {
|
||||
Picker(env.preferences.t("字体风格", en: "Typography", pl: "Typografia"), selection: $imageShareFontStyle) {
|
||||
Picker(env.preferences.t("字体风格", en: "Typography", pl: "Typografia"), selection: $preferences.noteImageShare.fontStyle) {
|
||||
Text(env.preferences.t("跟随主题", en: "Follow Theme", pl: "Zgodnie z motywem")).tag("auto")
|
||||
Text(env.preferences.t("文艺衬线", en: "Serif", pl: "Szeryfowa")).tag("serif")
|
||||
Text(env.preferences.t("现代无衬线", en: "Sans", pl: "Bezszeryfowa")).tag("sans")
|
||||
@@ -208,7 +202,7 @@ struct MemoDetailView: View {
|
||||
.pickerStyle(.menu)
|
||||
}
|
||||
Section(env.preferences.t("字号大小", en: "Font size", pl: "Rozmiar czcionki")) {
|
||||
Picker(env.preferences.t("字号大小", en: "Font size", pl: "Rozmiar czcionki"), selection: $imageShareFontSize) {
|
||||
Picker(env.preferences.t("字号大小", en: "Font size", pl: "Rozmiar czcionki"), selection: $preferences.noteImageShare.fontSize) {
|
||||
Text(env.preferences.t("紧凑", en: "Compact", pl: "Kompaktowy")).tag("sm")
|
||||
Text(env.preferences.t("标准", en: "Standard", pl: "Standardowy")).tag("md")
|
||||
Text(env.preferences.t("舒适", en: "Comfortable", pl: "Wygodny")).tag("lg")
|
||||
@@ -216,7 +210,7 @@ struct MemoDetailView: View {
|
||||
.pickerStyle(.segmented)
|
||||
}
|
||||
Section(env.preferences.t("卡片宽度", en: "Card width", pl: "Szerokość karty")) {
|
||||
Picker(env.preferences.t("卡片宽度", en: "Card width", pl: "Szerokość karty"), selection: $imageShareCardWidth) {
|
||||
Picker(env.preferences.t("卡片宽度", en: "Card width", pl: "Szerokość karty"), selection: $preferences.noteImageShare.cardWidth) {
|
||||
Text(env.preferences.t("紧凑", en: "Compact", pl: "Kompaktowy")).tag("compact")
|
||||
Text(env.preferences.t("标准", en: "Standard", pl: "Standardowy")).tag("standard")
|
||||
Text(env.preferences.t("宽屏", en: "Wide", pl: "Szeroka")).tag("wide")
|
||||
@@ -224,14 +218,14 @@ struct MemoDetailView: View {
|
||||
.pickerStyle(.segmented)
|
||||
}
|
||||
Section(env.preferences.t("显示内容", en: "Content elements", pl: "Elementy treści")) {
|
||||
Toggle(env.preferences.t("笔记标题", en: "Note title", pl: "Tytuł notatki"), isOn: $imageShareTitle)
|
||||
Toggle(env.preferences.t("笔记本", en: "Notebook", pl: "Notatnik"), isOn: $imageShareNotebook)
|
||||
Toggle(env.preferences.t("标签", en: "Tags", pl: "Tagi"), isOn: $imageShareTags)
|
||||
Toggle(env.preferences.t("更新时间", en: "Updated time", pl: "Czas aktualizacji"), isOn: $imageShareUpdatedAt)
|
||||
Toggle(env.preferences.t("EdgeEver 品牌标识", en: "EdgeEver branding", pl: "Oznaczenie EdgeEver"), isOn: $imageShareBranding)
|
||||
Toggle(env.preferences.t("笔记标题", en: "Note title", pl: "Tytuł notatki"), isOn: $preferences.noteImageShare.showTitle)
|
||||
Toggle(env.preferences.t("笔记本", en: "Notebook", pl: "Notatnik"), isOn: $preferences.noteImageShare.showNotebook)
|
||||
Toggle(env.preferences.t("标签", en: "Tags", pl: "Tagi"), isOn: $preferences.noteImageShare.showTags)
|
||||
Toggle(env.preferences.t("更新时间", en: "Updated time", pl: "Czas aktualizacji"), isOn: $preferences.noteImageShare.showUpdatedAt)
|
||||
Toggle(env.preferences.t("EdgeEver 品牌标识", en: "EdgeEver branding", pl: "Oznaczenie EdgeEver"), isOn: $preferences.noteImageShare.showBranding)
|
||||
}
|
||||
Section(env.preferences.t("图片格式", en: "Image format", pl: "Format obrazu")) {
|
||||
Picker(env.preferences.t("图片格式", en: "Image format", pl: "Format obrazu"), selection: $imageShareFormat) {
|
||||
Picker(env.preferences.t("图片格式", en: "Image format", pl: "Format obrazu"), selection: $preferences.noteImageShare.format) {
|
||||
Text(env.preferences.t("PNG · 超清无损", en: "PNG · Best for text", pl: "PNG · Najlepszy do tekstu")).tag("png")
|
||||
Text(env.preferences.t("JPEG · 体积小", en: "JPEG · Smaller file", pl: "JPEG · Mniejszy plik")).tag("jpeg")
|
||||
}
|
||||
@@ -250,16 +244,16 @@ struct MemoDetailView: View {
|
||||
imageShareOptionsOpen = false
|
||||
exportMemoImage(
|
||||
memo,
|
||||
format: imageShareFormat,
|
||||
theme: imageShareTheme,
|
||||
fontStyle: imageShareFontStyle,
|
||||
fontSize: imageShareFontSize,
|
||||
cardWidth: imageShareCardWidth,
|
||||
showTitle: imageShareTitle,
|
||||
showNotebook: imageShareNotebook,
|
||||
showTags: imageShareTags,
|
||||
showUpdatedAt: imageShareUpdatedAt,
|
||||
showBranding: imageShareBranding,
|
||||
format: env.preferences.noteImageShare.format,
|
||||
theme: env.preferences.noteImageShare.theme,
|
||||
fontStyle: env.preferences.noteImageShare.fontStyle,
|
||||
fontSize: env.preferences.noteImageShare.fontSize,
|
||||
cardWidth: env.preferences.noteImageShare.cardWidth,
|
||||
showTitle: env.preferences.noteImageShare.showTitle,
|
||||
showNotebook: env.preferences.noteImageShare.showNotebook,
|
||||
showTags: env.preferences.noteImageShare.showTags,
|
||||
showUpdatedAt: env.preferences.noteImageShare.showUpdatedAt,
|
||||
showBranding: env.preferences.noteImageShare.showBranding,
|
||||
intent: .preview
|
||||
)
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loaded 100 of 410 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user