Skip to content

Commit d9e5da3

Browse files
committed
Add configuration loading and memorization functionality to ContentView; update AppDelegate to load new words based on user activity
1 parent 9775c6c commit d9e5da3

File tree

3 files changed

+88
-41
lines changed

3 files changed

+88
-41
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,4 @@ fastlane/test_output
7373
# App Secrets
7474
Secrets.swift
7575
GoogleService-Info.plist
76+
VocabularyApp/Config.plist

VocabularyApp/ContentView.swift

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,36 @@
1+
//
2+
// ContentView.swift
3+
// VocabularyApp
4+
//
5+
// Created by Parth Desai on 1/10/25.
6+
//
7+
18
import SwiftUI
29
import AppKit
310

411
struct ContentView: View {
512
@State private var word: String = "Loading..."
613
@State private var meaning: String = "Loading..."
714
@State private var example: String = "Loading..."
8-
@State private var wordID: String? = nil
15+
@State private var memorizedWords: [String] = []
16+
private var apiKey: String
17+
private var sheetID: String
18+
19+
init() {
20+
if let path = Bundle.main.path(forResource: "Config", ofType: "plist"),
21+
let config = NSDictionary(contentsOfFile: path),
22+
let apiKey = config["API_KEY"] as? String,
23+
let sheetID = config["SHEET_ID"] as? String {
24+
self.apiKey = apiKey
25+
self.sheetID = sheetID
26+
} else {
27+
fatalError("API_KEY or SHEET_ID not found in Config.plist")
28+
}
29+
}
930

1031
var body: some View {
1132
VStack(spacing: 16) {
12-
// Word Section
33+
1334
Text(word)
1435
.font(.system(size: 28, weight: .bold))
1536
.foregroundColor(.primary)
@@ -28,7 +49,7 @@ struct ContentView: View {
2849
}
2950
.frame(maxWidth: .infinity, alignment: .center)
3051

31-
// Meaning Section
52+
3253
VStack(alignment: .leading, spacing: 8) {
3354
Text("Meaning:")
3455
.font(.headline)
@@ -37,15 +58,15 @@ struct ContentView: View {
3758
.font(.body)
3859
.foregroundColor(.primary)
3960
.multilineTextAlignment(.leading)
40-
.fixedSize(horizontal: false, vertical: true) // Add this
61+
.fixedSize(horizontal: false, vertical: true)
4162
.padding()
4263
.background(Color.gray.opacity(0.1))
4364
.cornerRadius(8)
4465
}
4566
.padding(.horizontal)
4667
.frame(maxWidth: .infinity, alignment: .leading)
4768

48-
// Example Section
69+
4970
VStack(alignment: .leading, spacing: 8) {
5071
Text("Example:")
5172
.font(.headline)
@@ -55,7 +76,7 @@ struct ContentView: View {
5576
.italic()
5677
.foregroundColor(.primary)
5778
.multilineTextAlignment(.leading)
58-
.fixedSize(horizontal: false, vertical: true) // Add this
79+
.fixedSize(horizontal: false, vertical: true)
5980
.padding()
6081
.background(Color.gray.opacity(0.1))
6182
.cornerRadius(8)
@@ -65,7 +86,7 @@ struct ContentView: View {
6586

6687
Divider()
6788

68-
// Buttons Section
89+
6990
HStack {
7091
Button("Memorized it") {
7192
markAsMemorized()
@@ -87,6 +108,7 @@ struct ContentView: View {
87108
.cornerRadius(12)
88109
.shadow(radius: 8)
89110
.onAppear {
111+
loadMemorizedWords()
90112
loadRandomWord()
91113
}
92114
}
@@ -97,8 +119,6 @@ struct ContentView: View {
97119
}
98120

99121
func loadRandomWord() {
100-
let sheetID = "1U66wi1O42CeuC_7QuMTbF2hlewJinCAmgTOJpZFbV1k"
101-
let apiKey = "AIzaSyBjNi7cYMOO_RL_qPqI4wuVP71UZPs72Jg"
102122
let url = URL(string: "https://sheets.googleapis.com/v4/spreadsheets/\(sheetID)/values/Sheet1?key=\(apiKey)")!
103123

104124
var request = URLRequest(url: url)
@@ -114,7 +134,10 @@ struct ContentView: View {
114134
let decodedResponse = try JSONDecoder().decode(GoogleSheetResponse.self, from: data)
115135
let rows = decodedResponse.values.dropFirst()
116136

117-
if let randomRow = rows.randomElement() {
137+
138+
let unmemorizedRows = rows.filter { !memorizedWords.contains($0[0]) }
139+
140+
if let randomRow = unmemorizedRows.randomElement() {
118141
DispatchQueue.main.async {
119142
word = randomRow[0]
120143
meaning = randomRow[1]
@@ -123,7 +146,7 @@ struct ContentView: View {
123146
} else {
124147
DispatchQueue.main.async {
125148
word = "No more words!"
126-
meaning = "All words are marked as memorized."
149+
meaning = "You have memorized all words."
127150
example = ""
128151
}
129152
}
@@ -134,37 +157,39 @@ struct ContentView: View {
134157
}
135158

136159
func markAsMemorized() {
137-
guard let wordID = wordID else { return }
160+
guard !word.isEmpty, !memorizedWords.contains(word) else { return }
161+
memorizedWords.append(word)
138162

139-
let sheetID = "1U66wi1O42CeuC_7QuMTbF2hlewJinCAmgTOJpZFbV1k"
140-
let apiKey = "AIzaSyBjNi7cYMOO_RL_qPqI4wuVP71UZPs72Jg"
141-
let url = URL(string: "https://sheets.googleapis.com/v4/spreadsheets/\(sheetID)/values/Sheet1!D\(wordID):D\(wordID)?key=\(apiKey)")!
142163

143-
var request = URLRequest(url: url)
144-
request.httpMethod = "PUT"
145-
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
146-
147-
let body: [String: Any] = [
148-
"range": "Sheet1!D\(wordID):D\(wordID)",
149-
"values": [["TRUE"]]
150-
]
164+
saveMemorizedWords()
165+
loadRandomWord()
166+
}
151167

152-
request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: [])
168+
func saveMemorizedWords() {
169+
let fileURL = getFileURL()
170+
do {
171+
let data = try JSONEncoder().encode(memorizedWords)
172+
try data.write(to: fileURL)
173+
print("Memorized words saved to file.")
174+
} catch {
175+
print("Failed to save memorized words: \(error.localizedDescription)")
176+
}
177+
}
153178

154-
URLSession.shared.dataTask(with: request) { data, response, error in
155-
guard let data = data, error == nil else {
156-
print("Error updating data: \(error?.localizedDescription ?? "Unknown error")")
157-
return
158-
}
179+
func loadMemorizedWords() {
180+
let fileURL = getFileURL()
181+
do {
182+
let data = try Data(contentsOf: fileURL)
183+
memorizedWords = try JSONDecoder().decode([String].self, from: data)
184+
print("Loaded memorized words: \(memorizedWords)")
185+
} catch {
186+
print("No existing file found, starting fresh.")
187+
}
188+
}
159189

160-
if let response = response as? HTTPURLResponse, response.statusCode == 200 {
161-
print("Marked as memorized successfully")
162-
DispatchQueue.main.async {
163-
loadRandomWord()
164-
}
165-
} else {
166-
print("Failed to mark as memorized")
167-
}
168-
}.resume()
190+
func getFileURL() -> URL {
191+
let fileManager = FileManager.default
192+
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
193+
return documentsURL.appendingPathComponent("memorized_words.json")
169194
}
170-
}
195+
}

VocabularyApp/VocabularyAppApp.swift

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,16 @@ class AppDelegate: NSObject, NSApplicationDelegate {
2222
var statusItem: NSStatusItem?
2323
var popover: NSPopover?
2424
var eventMonitor: EventMonitor?
25+
var contentView: ContentView?
2526

2627
func applicationDidFinishLaunching(_ notification: Notification) {
27-
let contentView = ContentView()
28+
contentView = ContentView()
2829

2930
popover = NSPopover()
3031
popover?.contentSize = NSSize(width: 360, height: 0)
3132
popover?.behavior = .transient
3233

33-
let hostingController = NSHostingController(rootView: contentView)
34+
let hostingController = NSHostingController(rootView: contentView!)
3435
hostingController.view.setFrameSize(NSSize(width: 360, height: 1))
3536

3637
hostingController.view.autoresizingMask = [.height]
@@ -48,6 +49,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
4849
strongSelf.closePopover(event)
4950
}
5051
}
52+
53+
// Load a new word when the app is opened
54+
loadNewWordIfNeeded()
5155
}
5256

5357
@objc func togglePopover(_ sender: Any?) {
@@ -56,6 +60,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
5660
closePopover(sender)
5761
} else {
5862
showPopover(sender)
63+
// Load a new word every time the popover is shown
64+
contentView?.loadRandomWord()
5965
}
6066
}
6167
}
@@ -71,6 +77,21 @@ class AppDelegate: NSObject, NSApplicationDelegate {
7177
popover?.performClose(sender)
7278
eventMonitor?.stop()
7379
}
80+
81+
func loadNewWordIfNeeded() {
82+
let lastLoadedDateKey = "lastLoadedDate"
83+
let userDefaults = UserDefaults.standard
84+
85+
if let lastLoadedDate = userDefaults.object(forKey: lastLoadedDateKey) as? Date {
86+
if !Calendar.current.isDateInToday(lastLoadedDate) {
87+
contentView?.loadRandomWord()
88+
userDefaults.set(Date(), forKey: lastLoadedDateKey)
89+
}
90+
} else {
91+
contentView?.loadRandomWord()
92+
userDefaults.set(Date(), forKey: lastLoadedDateKey)
93+
}
94+
}
7495
}
7596

7697
class EventMonitor {

0 commit comments

Comments
 (0)