Skip to content

Commit d9c678b

Browse files
committed
Update
1 parent 849979a commit d9c678b

File tree

6 files changed

+85
-91
lines changed

6 files changed

+85
-91
lines changed

PG5602_H24-4/Entities/Search.swift

+13-13
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
// Created by Karima Thingvold on 04/12/2024.
66
//
77

8-
//import Foundation
9-
//import SwiftData
10-
//
11-
//@Model
12-
//class Search: Identifiable {
13-
// @Attribute(.unique) var query: String
14-
// var timestamp: Date
15-
//
16-
// init(query: String, timestamp: Date = Date()) {
17-
// self.query = query
18-
// self.timestamp = timestamp
19-
// }
20-
//}
8+
import Foundation
9+
import SwiftData
10+
11+
@Model
12+
class Search: Identifiable {
13+
@Attribute(.unique) var query: String
14+
var timestamp: Date
15+
16+
init(query: String, timestamp: Date = Date()) {
17+
self.query = query
18+
self.timestamp = timestamp
19+
}
20+
}
2121

PG5602_H24-4/Launch Screen.storyboard

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2-
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
3+
<device id="retina6_12" orientation="portrait" appearance="light"/>
34
<dependencies>
4-
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
5-
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
5+
<deployment version="5696" identifier="iOS"/>
6+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
67
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
78
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
89
</dependencies>
@@ -12,32 +13,32 @@
1213
<objects>
1314
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
1415
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
15-
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
16+
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
1617
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
1718
<subviews>
1819
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
19-
<rect key="frame" x="0.0" y="626.5" width="375" height="20.5"/>
20+
<rect key="frame" x="0.0" y="832" width="393" height="0.0"/>
2021
<fontDescription key="fontDescription" type="system" pointSize="17"/>
2122
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
2223
<nil key="highlightedColor"/>
2324
</label>
24-
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="PG5602_H24-4" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
25-
<rect key="frame" x="0.0" y="202" width="375" height="43"/>
26-
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
27-
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
25+
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="GLOBEWIRE" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
26+
<rect key="frame" x="0.0" y="255" width="393" height="60"/>
27+
<fontDescription key="fontDescription" type="boldSystem" pointSize="50"/>
28+
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
2829
<nil key="highlightedColor"/>
2930
</label>
3031
</subviews>
31-
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
32+
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
33+
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
3234
<constraints>
3335
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="obG-Y5-kRd" secondAttribute="centerX" id="5cz-MP-9tL"/>
3436
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
3537
<constraint firstItem="obG-Y5-kRd" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" constant="20" symbolic="YES" id="SfN-ll-jLj"/>
3638
<constraint firstAttribute="bottom" secondItem="obG-Y5-kRd" secondAttribute="bottom" constant="20" id="Y44-ml-fuU"/>
3739
<constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
38-
<constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" constant="20" symbolic="YES" id="x7j-FC-K8j"/>
40+
<constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" symbolic="YES" id="x7j-FC-K8j"/>
3941
</constraints>
40-
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
4142
</view>
4243
</viewController>
4344
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>

PG5602_H24-4/PG5602_H24_4App.swift

+9-9
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@ import SwiftData
1010

1111
@main
1212
struct PG5602_H24_4App: App {
13-
var sharedModelContainer: ModelContainer = {
14-
do {
15-
let schema = Schema([Article.self, Category.self, Country.self])
16-
return try ModelContainer(for: schema)
17-
} catch {
18-
fatalError("Could not create model container: \(error)")
19-
}
20-
}()
21-
2213
var body: some Scene {
2314
WindowGroup {
2415
SplashScreen()
2516
.modelContainer(sharedModelContainer)
2617
}
2718
}
2819
}
20+
21+
var sharedModelContainer: ModelContainer = {
22+
do {
23+
let schema = Schema([Article.self, Search.self, Category.self, Country.self])
24+
return try ModelContainer(for: schema)
25+
} catch {
26+
fatalError("Could not create model container: \(error)")
27+
}
28+
}()

PG5602_H24-4/Services/NewsAPIService.swift

+11-7
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,10 @@ class NewsApiService {
136136
}
137137

138138
func searchArticles(query: String, sortBy: String, completion: @escaping (Result<[NewsArticle], Error>) -> Void) {
139-
//#if DEBUG
140-
// completion(.success(MockData.articles))
141-
// return
142-
// #endif
139+
#if DEBUG
140+
completion(.success(MockData.articles))
141+
return
142+
#endif
143143

144144
guard !query.isEmpty else {
145145
completion(.failure(NSError(domain: "", code: 400, userInfo: [NSLocalizedDescriptionKey: "Query is empty"])))
@@ -192,10 +192,14 @@ class NewsApiService {
192192

193193
struct MockData {
194194
static let articles = [
195-
NewsArticle(author: "Mock Author",title: "Mock Title 1", description: "This is a mock description 1", url: "https://example.com/1", urlToImage: "https://seeklogo.com/images/N/new-york-times-logo-EE0F194CA3-seeklogo.com.png", publishedAt: "2024-12-01T10:00:00Z"),
195+
NewsArticle(author: "Mock Author",title: "Mock Title 1", description: "This is a mock description 1", url: "https://example.com/1", urlToImage: "https://thumbs.dreamstime.com/b/cute-kawaii-christmas-ghost-festive-holiday-cartoon-hand-drawing-adorable-pose-297512032.jpg", publishedAt: "2024-12-01T10:00:00Z"),
196196

197-
NewsArticle(author: "Mock Author 2",title: "Mock Title 2", description: "This is a mock description 2", url: "https://example.com/2", urlToImage: "https://seeklogo.com/images/B/bbc-news-logo-8648ABD044-seeklogo.com.png", publishedAt: "2024-12-01T10:00:00Z"),
197+
NewsArticle(author: "Mock Author 2",title: "Mock Title 2", description: "This is a mock description 2", url: "https://example.com/2", urlToImage: "https://thumbs.dreamstime.com/b/cute-kawaii-christmas-ghost-festive-holiday-cartoon-hand-drawing-adorable-pose-297512032.jpg", publishedAt: "2024-12-01T10:00:00Z"),
198+
199+
NewsArticle(author: "Mock Author 3",title: "Mock Title 3", description: "This is a mock description 2", url: "https://example.com/3", urlToImage: "https://thumbs.dreamstime.com/b/cute-kawaii-christmas-ghost-festive-holiday-cartoon-hand-drawing-adorable-pose-297512032.jpg", publishedAt: "2024-12-01T10:00:00Z"),
200+
201+
NewsArticle(author: "Mock Author 3",title: "Mock Title 4", description: "This is a mock description 2", url: "https://example.com/3", urlToImage: "https://thumbs.dreamstime.com/b/cute-kawaii-christmas-ghost-festive-holiday-cartoon-hand-drawing-adorable-pose-297512032.jpg", publishedAt: "2024-12-01T10:00:00Z"),
198202

199-
NewsArticle(author: "Mock Author 3",title: "Mock Title 3", description: "This is a mock description 2", url: "https://example.com/3", urlToImage: "https://download.logo.wine/logo/CNN/CNN-Logo.wine.png", publishedAt: "2024-12-01T10:00:00Z"),
203+
NewsArticle(author: "Mock Author 3",title: "Mock Title 5", description: "This is a mock description 2", url: "https://example.com/3", urlToImage: "https://thumbs.dreamstime.com/b/cute-kawaii-christmas-ghost-festive-holiday-cartoon-hand-drawing-adorable-pose-297512032.jpg", publishedAt: "2024-12-01T10:00:00Z"),
200204
]
201205
}

PG5602_H24-4/Views/ArticleDetailedView.swift

+5-24
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import SwiftData
1010

1111
struct ArticleDetailView: View {
1212
let article: NewsArticle
13-
@Environment(\.modelContext) private var modelContext
13+
@Environment(\.modelContext) var modelContext
1414
@State var isArticleSaved = false
1515
@State var isCategoryChosen = false
1616
@State var showMessage = false
@@ -105,7 +105,7 @@ struct ArticleDetailView: View {
105105
}
106106
}
107107
.onChange(of: selectedCategory) { oldValue, newValue in
108-
guard oldValue != newValue else { return } // Unngå unødvendige oppdateringer
108+
guard oldValue != newValue else { return }
109109
print("Changed from \(oldValue?.name ?? "None") to \(newValue?.name ?? "None")")
110110
isCategoryChosen = newValue != nil
111111
}
@@ -124,7 +124,7 @@ struct ArticleDetailView: View {
124124
if isArticleSaved {
125125
let savedArticles = Article.fetchAll(in: modelContext)
126126
if let storedArticle = savedArticles.first(where: { $0.url == article.url }) {
127-
selectedCategory = storedArticle.category // Sett til lagret kategori
127+
selectedCategory = storedArticle.category
128128
}
129129
}
130130
}
@@ -145,36 +145,31 @@ struct ArticleDetailView: View {
145145

146146
func toggleSaveArticle() {
147147
if isArticleSaved {
148-
// Slette artikkelen
149148
let savedArticles = Article.fetchAll(in: modelContext)
150149
if let storedArticle = savedArticles.first(where: { $0.url == article.url }) {
151150
storedArticle.deleteFromDatabase(context: modelContext)
152151
isArticleSaved = false
153152
saveMessasge = "Article removed from saved articles."
154153
}
155154
} else {
156-
// Lagre artikkelen og kategorien
157155
saveArticleWithCategory()
158156
}
159157
}
160158

161159
func saveArticleWithCategory() {
162-
// Opprette en ny artikkel
163160
let storedArticle = Article(
164161
article: article,
165162
category: selectedCategory,
166163
note: "Optional user note"
167164
)
168165

169-
// Oppdatere kategorien hvis en er valgt
170166
if let category = selectedCategory {
171-
category.articles.append(storedArticle) // Oppdater relasjonen
172-
modelContext.insert(category) // Sørg for at kategorien blir lagret
167+
category.articles.append(storedArticle);
168+
modelContext.insert(category);
173169
print("Saved article in category: \(category.name)")
174170
print("Category now has \(category.articles.count) articles.")
175171
}
176172

177-
// Legge artikkelen til databasen
178173
modelContext.insert(storedArticle)
179174
do {
180175
try modelContext.save()
@@ -186,17 +181,3 @@ struct ArticleDetailView: View {
186181
showMessage = true
187182
}
188183
}
189-
190-
//#Preview {
191-
// let exampleArticle = NewsArticle(
192-
// author: "John Doe",
193-
// title: "Breaking News: Swift is Awesome!",
194-
// description: "SwiftUI helps you build great-looking apps across all Apple platforms with the power of Swift — and surprisingly little code. You can bring even better experiences to everyone, on any Apple device, using just one set of tools and APIs.",
195-
// url: "https://developer.apple.com/xcode/swiftui/",
196-
// urlToImage: "https://developer.apple.com/xcode/swiftui/images/hero-lockup-swiftui-large_2x.webp",
197-
// publishedAt: "2024-11-25T12:10:00Z"
198-
// )
199-
//
200-
// ArticleDetailView(article: exampleArticle)
201-
// .modelContainer(for: [Article.self]) // Mock ModelContext for SwiftData
202-
//}

PG5602_H24-4/Views/SearchView.swift

+33-25
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Created by Karima Thingvold on 01/12/2024.
66
//
77

8+
import Foundation
89
import SwiftUI
910
import SwiftData
1011

@@ -15,10 +16,10 @@ enum SortOption: String, CaseIterable {
1516
}
1617

1718
struct SearchView: View {
18-
@Environment(\.modelContext) private var modelContext
19-
//@Query(sort: \Search.timestamp, order: .reverse) var searchHistory: [Search]
20-
//@State var searchHistory: [Search] = []
21-
19+
@Environment(\.modelContext) var modelContext
20+
@Query(sort: \Search.timestamp, order: .reverse) var searchHistory: [Search]
21+
//@State var searchHistory: [Search] = []
22+
2223
@State var query: String = ""
2324
@State var articles: [NewsArticle] = []
2425
@State var isLoading = false
@@ -36,20 +37,20 @@ struct SearchView: View {
3637
search()
3738
})
3839
.textFieldStyle(PlainTextFieldStyle())
39-
// Menu {
40-
// ForEach(searchHistory) { search in
41-
// Button(action: {
42-
// query = search.query // Sett søkefeltet til valgt søkeord
43-
// performSearch() // Utfør søket
44-
// }) {
45-
// Text(search.query)
46-
// }
47-
// }
48-
// } label: {
49-
// Image(systemName: "arrowtriangle.down.fill")
50-
// .foregroundColor(.blue)
51-
// .padding(.horizontal, 8)
52-
// }
40+
Menu {
41+
ForEach(searchHistory) { search in
42+
Button(action: {
43+
query = search.query
44+
performSearch()
45+
}) {
46+
Text(search.query)
47+
}
48+
}
49+
} label: {
50+
Image(systemName: "arrowtriangle.down.fill")
51+
.foregroundColor(.blue)
52+
.padding(.horizontal, 8)
53+
}
5354
}
5455
.padding(10)
5556
.background(Color(.systemGray6))
@@ -134,7 +135,7 @@ struct SearchView: View {
134135
guard !query.isEmpty else { return }
135136
isLoading = true
136137
errorMessage = nil
137-
//saveSearch(query: query)
138+
saveSearch(query: query)
138139

139140
let newsService = NewsApiService()
140141
newsService.searchArticles(query: query, sortBy: "relevance") { result in
@@ -149,14 +150,21 @@ struct SearchView: View {
149150
}
150151
}
151152
}
152-
// func saveSearch(query: String) {
153-
// if !searchHistory.contains(where: { $0.query == query }) {
154-
// let newSearch = Search(query: query)
155-
// modelContext.insert(newSearch)
156-
// }
157-
// }
153+
func saveSearch(query: String) {
154+
if !searchHistory.contains(where: { $0.query == query }) {
155+
let newSearch = Search(query: query)
156+
modelContext.insert(newSearch)
157+
do {
158+
try modelContext.save()
159+
160+
} catch {
161+
print("Error saving search: \(error)")
162+
}
163+
}
164+
}
158165
}
159166

167+
160168
#Preview {
161169
SearchView()
162170
}

0 commit comments

Comments
 (0)