Skip to content

Commit 481e9f9

Browse files
ZinkxZinkx
authored andcommitted
feat(reminders): add advanced date-based filtering and bottom bar UI
1 parent bade435 commit 481e9f9

12 files changed

Lines changed: 1083 additions & 89 deletions

DevNotes/DevNotes.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@
3232
586260CA2F1D1A7D001F6B2B /* TagManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 586260C92F1D1A7D001F6B2B /* TagManagerView.swift */; };
3333
586260CC2F1D1A8B001F6B2B /* AddTagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 586260CB2F1D1A8A001F6B2B /* AddTagView.swift */; };
3434
586260CE2F1D2B3B001F6B2B /* CDNote+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 586260CD2F1D2B3A001F6B2B /* CDNote+CoreDataClass.swift */; };
35+
58BCBA572F1E63FF002391F5 /* SettingsView 2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58BCBA562F1E63FF002391F5 /* SettingsView 2.swift */; };
3536
58D402312F1D41AC004230EA /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D402302F1D41AB004230EA /* ShareSheet.swift */; };
3637
58D9F6B92F1D49FA00254679 /* MainTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D9F6B82F1D49F900254679 /* MainTabView.swift */; };
3738
58D9F6BB2F1D4A4200254679 /* PinnedNotesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D9F6BA2F1D4A4100254679 /* PinnedNotesView.swift */; };
3839
58D9F6BD2F1D4A9C00254679 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D9F6BC2F1D4A9B00254679 /* SettingsView.swift */; };
3940
58D9F6BF2F1D4AC000254679 /* RemindersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D9F6BE2F1D4ABF00254679 /* RemindersView.swift */; };
41+
58F1A8482F1E927300FA2A59 /* PrivacyPolicyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F1A8472F1E927100FA2A59 /* PrivacyPolicyView.swift */; };
42+
58F1A84A2F1E928300FA2A59 /* TermsOfServiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F1A8492F1E928100FA2A59 /* TermsOfServiceView.swift */; };
43+
58F1A84C2F1E929200FA2A59 /* LicensesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F1A84B2F1E928F00FA2A59 /* LicensesView.swift */; };
4044
/* End PBXBuildFile section */
4145

4246
/* Begin PBXFileReference section */
@@ -66,11 +70,15 @@
6670
586260CB2F1D1A8A001F6B2B /* AddTagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddTagView.swift; sourceTree = "<group>"; };
6771
586260CD2F1D2B3A001F6B2B /* CDNote+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDNote+CoreDataClass.swift"; sourceTree = "<group>"; };
6872
58A63D162F1CF43700381E1B /* DevNotes.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DevNotes.app; sourceTree = BUILT_PRODUCTS_DIR; };
73+
58BCBA562F1E63FF002391F5 /* SettingsView 2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SettingsView 2.swift"; sourceTree = "<group>"; };
6974
58D402302F1D41AB004230EA /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = "<group>"; };
7075
58D9F6B82F1D49F900254679 /* MainTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabView.swift; sourceTree = "<group>"; };
7176
58D9F6BA2F1D4A4100254679 /* PinnedNotesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedNotesView.swift; sourceTree = "<group>"; };
7277
58D9F6BC2F1D4A9B00254679 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
7378
58D9F6BE2F1D4ABF00254679 /* RemindersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersView.swift; sourceTree = "<group>"; };
79+
58F1A8472F1E927100FA2A59 /* PrivacyPolicyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyPolicyView.swift; sourceTree = "<group>"; };
80+
58F1A8492F1E928100FA2A59 /* TermsOfServiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsOfServiceView.swift; sourceTree = "<group>"; };
81+
58F1A84B2F1E928F00FA2A59 /* LicensesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicensesView.swift; sourceTree = "<group>"; };
7482
/* End PBXFileReference section */
7583

7684
/* Begin PBXFrameworksBuildPhase section */
@@ -108,6 +116,9 @@
108116
5801CF5B2F1D5D2800076862 /* AboutDevNotesView.swift */,
109117
58D9F6BA2F1D4A4100254679 /* PinnedNotesView.swift */,
110118
58D9F6BC2F1D4A9B00254679 /* SettingsView.swift */,
119+
58F1A8472F1E927100FA2A59 /* PrivacyPolicyView.swift */,
120+
58F1A8492F1E928100FA2A59 /* TermsOfServiceView.swift */,
121+
58F1A84B2F1E928F00FA2A59 /* LicensesView.swift */,
111122
5801CF5D2F1D72D800076862 /* ThemePickerView.swift */,
112123
58D9F6BE2F1D4ABF00254679 /* RemindersView.swift */,
113124
58330E0F2F1D0CFE000876DC /* EditNoteView.swift */,
@@ -117,6 +128,7 @@
117128
586260CD2F1D2B3A001F6B2B /* CDNote+CoreDataClass.swift */,
118129
58330E132F1D0CFE000876DC /* NoteRepository.swift */,
119130
58330E142F1D0CFE000876DC /* NoteStorage.swift */,
131+
58BCBA562F1E63FF002391F5 /* SettingsView 2.swift */,
120132
);
121133
path = DevNotes;
122134
sourceTree = "<group>";
@@ -209,6 +221,7 @@
209221
isa = PBXSourcesBuildPhase;
210222
buildActionMask = 2147483647;
211223
files = (
224+
58F1A84C2F1E929200FA2A59 /* LicensesView.swift in Sources */,
212225
5801CF5C2F1D5D2900076862 /* AboutDevNotesView.swift in Sources */,
213226
58330E172F1D0CFE000876DC /* AddNoteView.swift in Sources */,
214227
5801CF582F1D4D6500076862 /* PersistenceController.swift in Sources */,
@@ -234,10 +247,13 @@
234247
58330E2B2F1D1086000876DC /* DevNotes.xcdatamodeld in Sources */,
235248
58330E212F1D0CFE000876DC /* NoteStorage.swift in Sources */,
236249
5801CF662F1D99B600076862 /* TagAssets.swift in Sources */,
250+
58F1A8482F1E927300FA2A59 /* PrivacyPolicyView.swift in Sources */,
237251
58D402312F1D41AC004230EA /* ShareSheet.swift in Sources */,
238252
586260CE2F1D2B3B001F6B2B /* CDNote+CoreDataClass.swift in Sources */,
253+
58BCBA572F1E63FF002391F5 /* SettingsView 2.swift in Sources */,
239254
58D9F6B92F1D49FA00254679 /* MainTabView.swift in Sources */,
240255
58D9F6BD2F1D4A9C00254679 /* SettingsView.swift in Sources */,
256+
58F1A84A2F1E928300FA2A59 /* TermsOfServiceView.swift in Sources */,
241257
);
242258
runOnlyForDeploymentPostprocessing = 0;
243259
};

DevNotes/DevNotes/AddNoteView.swift

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -122,16 +122,14 @@ struct RichTextContainer: UIViewRepresentable {
122122
func makeUIView(context: Context) -> UIView {
123123
let container = UIView()
124124

125+
// MARK: Toolbar
125126
let toolbar = UIToolbar()
126127
toolbar.isTranslucent = true
127-
toolbar.setBackgroundImage(UIImage(), forToolbarPosition: .any, barMetrics: .default)
128128

129-
if #available(iOS 15.0, *) {
130-
let appearance = UIToolbarAppearance()
131-
appearance.configureWithTransparentBackground()
132-
toolbar.standardAppearance = appearance
133-
toolbar.scrollEdgeAppearance = appearance
134-
}
129+
let appearance = UIToolbarAppearance()
130+
appearance.configureWithTransparentBackground()
131+
toolbar.standardAppearance = appearance
132+
toolbar.scrollEdgeAppearance = appearance
135133

136134
toolbar.items = [
137135
makeItem("bold", context, #selector(Coordinator.bold)),
@@ -142,10 +140,14 @@ struct RichTextContainer: UIViewRepresentable {
142140
makeItem("checklist", context, #selector(Coordinator.checklist))
143141
]
144142

143+
// MARK: TextView
145144
let textView = UITextView()
146145
textView.font = .systemFont(ofSize: 16)
147146
textView.delegate = context.coordinator
148-
textView.text = text // ⭐ EN KRİTİK SATIR
147+
textView.text = text
148+
textView.backgroundColor = .clear
149+
textView.textContainerInset = UIEdgeInsets(top: 12, left: 8, bottom: 12, right: 8)
150+
149151
context.coordinator.textView = textView
150152

151153
toolbar.translatesAutoresizingMaskIntoConstraints = false
@@ -177,27 +179,57 @@ struct RichTextContainer: UIViewRepresentable {
177179
Coordinator(onTextChange: onTextChange)
178180
}
179181

182+
// MARK: - Toolbar Button Factory
180183
private func makeItem(
181184
_ system: String,
182185
_ context: Context,
183186
_ selector: Selector
184187
) -> UIBarButtonItem {
185188

186-
let image = UIImage(systemName: system,
187-
withConfiguration: UIImage.SymbolConfiguration(pointSize: 13))
189+
let image = UIImage(
190+
systemName: system,
191+
withConfiguration: UIImage.SymbolConfiguration(
192+
pointSize: 14,
193+
weight: .semibold
194+
)
195+
)
188196

189-
var config = UIButton.Configuration.plain()
197+
var config = UIButton.Configuration.filled()
190198
config.image = image
191-
config.contentInsets = .zero
199+
config.cornerStyle = .capsule
200+
config.baseForegroundColor = .tintColor
201+
config.baseBackgroundColor = UIColor.secondarySystemBackground
202+
config.contentInsets = NSDirectionalEdgeInsets(
203+
top: 6,
204+
leading: 10,
205+
bottom: 6,
206+
trailing: 10
207+
)
192208

193209
let button = UIButton(configuration: config)
194-
button.tintColor = .label
195-
button.frame = CGRect(x: 0, y: 0, width: 28, height: 28)
196-
button.addTarget(context.coordinator, action: selector, for: .touchUpInside)
210+
211+
button.addAction(
212+
UIAction { _ in
213+
// 🟡 Accent blink
214+
UIView.animate(withDuration: 0.12, animations: {
215+
button.backgroundColor = UIColor.tintColor.withAlphaComponent(0.25)
216+
}) { _ in
217+
UIView.animate(withDuration: 0.18) {
218+
button.backgroundColor = UIColor.secondarySystemBackground
219+
}
220+
}
221+
222+
// 🎯 Gerçek aksiyon
223+
_ = context.coordinator.perform(selector)
224+
},
225+
for: .touchUpInside
226+
)
197227

198228
return UIBarButtonItem(customView: button)
199229
}
200230

231+
232+
// MARK: - Coordinator
201233
final class Coordinator: NSObject, UITextViewDelegate {
202234

203235
weak var textView: UITextView?
@@ -211,8 +243,10 @@ struct RichTextContainer: UIViewRepresentable {
211243
onTextChange(textView.text)
212244
}
213245

246+
// MARK: Actions
214247
@objc func bold() { toggle(.traitBold) }
215248
@objc func italic() { toggle(.traitItalic) }
249+
216250
@objc func underline() {
217251
guard let tv = textView else { return }
218252
let range = tv.selectedRange
@@ -223,22 +257,30 @@ struct RichTextContainer: UIViewRepresentable {
223257
)
224258
}
225259

226-
@objc func bullet() { textView?.insertText("\n") }
227-
@objc func checklist() { textView?.insertText("\n") }
260+
@objc func bullet() {
261+
textView?.insertText("\n")
262+
}
263+
264+
@objc func checklist() {
265+
textView?.insertText("\n")
266+
}
228267

229268
private func toggle(_ trait: UIFontDescriptor.SymbolicTraits) {
230269
guard let tv = textView else { return }
231270
let font = tv.font ?? .systemFont(ofSize: 16)
271+
232272
let traits = font.fontDescriptor.symbolicTraits.contains(trait)
233273
? font.fontDescriptor.symbolicTraits.subtracting(trait)
234274
: font.fontDescriptor.symbolicTraits.union(trait)
275+
235276
let desc = font.fontDescriptor.withSymbolicTraits(traits) ?? font.fontDescriptor
236277
tv.font = UIFont(descriptor: desc, size: font.pointSize)
237278
}
238279
}
239280
}
240281

241282

283+
242284
private extension UIFont {
243285
func toggle(_ trait: UIFontDescriptor.SymbolicTraits) -> UIFont {
244286
let has = fontDescriptor.symbolicTraits.contains(trait)

DevNotes/DevNotes/ContentView.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ struct ContentView: View {
8686

8787
private func noteRow(_ note: Note) -> some View {
8888
NavigationLink {
89-
EditNoteView(note: note) { updateNote($0) }
89+
EditNoteView(
90+
note: note,
91+
onSave: { updateNote($0) },
92+
onDelete: { deleteNoteDirect($0) }
93+
)
9094
} label: {
9195
noteCard(note)
9296
}

DevNotes/DevNotes/EditNoteView.swift

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,28 @@ struct EditNoteView: View {
1515
// ⏰ Hatırlatma
1616
@State private var hasReminder: Bool
1717
@State private var reminderDate: Date
18+
@State private var showDeleteAlert = false
19+
1820

1921
let note: Note
2022
let onSave: (Note) -> Void
23+
let onDelete: (Note) -> Void
24+
2125

2226
enum Field {
2327
case title
2428
}
2529

2630
// MARK: - INIT
2731

28-
init(note: Note, onSave: @escaping (Note) -> Void) {
32+
init(
33+
note: Note,
34+
onSave: @escaping (Note) -> Void,
35+
onDelete: @escaping (Note) -> Void
36+
) {
2937
self.note = note
3038
self.onSave = onSave
39+
self.onDelete = onDelete
3140

3241
_title = State(initialValue: note.title)
3342
_plainContent = State(initialValue: note.content)
@@ -39,6 +48,7 @@ struct EditNoteView: View {
3948
_reminderDate = State(initialValue: note.reminderDate ?? Date())
4049
}
4150

51+
4252
// MARK: - VIEW
4353

4454
var body: some View {
@@ -105,21 +115,37 @@ struct EditNoteView: View {
105115
.navigationBarTitleDisplayMode(.inline)
106116
.toolbar {
107117

108-
// ❌ İptal
109-
ToolbarItem(placement: .cancellationAction) {
118+
// ⬅️ SOL: İptal + Sil
119+
ToolbarItemGroup(placement: .cancellationAction) {
120+
110121
Button("İptal") {
111122
dismiss()
112123
}
124+
125+
Button(role: .destructive) {
126+
showDeleteAlert = true
127+
} label: {
128+
Image(systemName: "trash")
129+
}
113130
}
114131

115-
// 💾 Kaydet
132+
// ➡️ SAĞ: Kaydet
116133
ToolbarItem(placement: .confirmationAction) {
117134
Button("Kaydet") {
118135
save()
119136
}
120137
.disabled(!canSave)
121138
}
122139
}
140+
.alert("Not silinsin mi?", isPresented: $showDeleteAlert) {
141+
Button("Sil", role: .destructive) {
142+
onDelete(note)
143+
dismiss()
144+
}
145+
Button("Vazgeç", role: .cancel) {}
146+
} message: {
147+
Text("Bu işlem geri alınamaz.")
148+
}
123149
.onAppear {
124150
focusedField = .title
125151
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import SwiftUI
2+
3+
struct LicensesView: View {
4+
5+
var body: some View {
6+
List {
7+
8+
// MARK: - System Frameworks
9+
Section {
10+
licenseRow(
11+
name: "SwiftUI",
12+
owner: "Apple Inc.",
13+
description: "Modern declarative UI framework for Apple platforms."
14+
)
15+
16+
licenseRow(
17+
name: "UIKit",
18+
owner: "Apple Inc.",
19+
description: "UIKit framework used for advanced text editing and system components."
20+
)
21+
22+
licenseRow(
23+
name: "UserNotifications",
24+
owner: "Apple Inc.",
25+
description: "Framework used to schedule and manage local notifications."
26+
)
27+
} header: {
28+
Text("Sistem Frameworkleri")
29+
}
30+
31+
// MARK: - Notes
32+
Section {
33+
Text("""
34+
Bu uygulama, yalnızca Apple tarafından sağlanan sistem frameworklerini kullanmaktadır.
35+
36+
Tüm frameworkler Apple lisansları kapsamında olup, ilgili lisans şartları Apple geliştirici dokümantasyonunda belirtilmiştir.
37+
""")
38+
.font(.footnote)
39+
.foregroundStyle(.secondary)
40+
}
41+
42+
}
43+
.navigationTitle("Lisanslar")
44+
.navigationBarTitleDisplayMode(.inline)
45+
}
46+
47+
// MARK: - Row
48+
49+
private func licenseRow(
50+
name: String,
51+
owner: String,
52+
description: String
53+
) -> some View {
54+
VStack(alignment: .leading, spacing: 4) {
55+
Text(name)
56+
.font(.headline)
57+
58+
Text(owner)
59+
.font(.caption)
60+
.foregroundStyle(.secondary)
61+
62+
Text(description)
63+
.font(.footnote)
64+
.foregroundStyle(.secondary)
65+
}
66+
.padding(.vertical, 4)
67+
}
68+
}

0 commit comments

Comments
 (0)