Mercurial > public > lazybear
changeset 122:2d6df8debf12
Add search history and fix bugs
author | Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com> |
---|---|
date | Sat, 06 Feb 2021 17:45:04 +0100 |
parents | c7532d18d6be |
children | a1acd9f4e8c8 |
files | LazyBear.xcodeproj/project.pbxproj LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate RecentSearch+CoreDataClass.swift RecentSearch+CoreDataProperties.swift lazybear/ContentView.swift lazybear/LazyBear.xcdatamodeld/LazyBear.xcdatamodel/contents lazybear/Persistence.swift lazybear/Views/AddWatchlist.swift lazybear/Views/Company.swift lazybear/Views/CompanyRow.swift lazybear/Views/RecentSearches.swift lazybear/Views/Search.swift lazybear/Views/Watchlist.swift lazybear/Views/WatchlistRow.swift |
diffstat | 14 files changed, 193 insertions(+), 68 deletions(-) [+] |
line wrap: on
line diff
--- a/LazyBear.xcodeproj/project.pbxproj Sat Feb 06 12:33:57 2021 +0100 +++ b/LazyBear.xcodeproj/project.pbxproj Sat Feb 06 17:45:04 2021 +0100 @@ -46,6 +46,9 @@ 95E411A725BEE03000A9C23F /* Watchlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95E411A625BEE03000A9C23F /* Watchlist.swift */; }; 95E411B625BEE84E00A9C23F /* Stock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95E411B525BEE84E00A9C23F /* Stock.swift */; }; 95E411BE25BEEA6C00A9C23F /* WatchlistRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95E411BD25BEEA6C00A9C23F /* WatchlistRow.swift */; }; + 95ED176125CEF14E00AE34B3 /* RecentSearches.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95ED176025CEF14E00AE34B3 /* RecentSearches.swift */; }; + 95ED176B25CEFE1B00AE34B3 /* RecentSearch+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95ED176925CEFE1B00AE34B3 /* RecentSearch+CoreDataClass.swift */; }; + 95ED176C25CEFE1B00AE34B3 /* RecentSearch+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95ED176A25CEFE1B00AE34B3 /* RecentSearch+CoreDataProperties.swift */; }; 95F6C2F025BAE2ED003CF389 /* Company.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95F6C2EF25BAE2ED003CF389 /* Company.swift */; }; 95F6C30925BAF7C2003CF389 /* DateSelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95F6C30825BAF7C2003CF389 /* DateSelection.swift */; }; 95F6F45C25C20D8D002AC66A /* Price.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95F6F45B25C20D8D002AC66A /* Price.swift */; }; @@ -97,6 +100,9 @@ 95E411A625BEE03000A9C23F /* Watchlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Watchlist.swift; sourceTree = "<group>"; }; 95E411B525BEE84E00A9C23F /* Stock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stock.swift; sourceTree = "<group>"; }; 95E411BD25BEEA6C00A9C23F /* WatchlistRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchlistRow.swift; sourceTree = "<group>"; }; + 95ED176025CEF14E00AE34B3 /* RecentSearches.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RecentSearches.swift; path = lazybear/Views/RecentSearches.swift; sourceTree = SOURCE_ROOT; }; + 95ED176925CEFE1B00AE34B3 /* RecentSearch+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RecentSearch+CoreDataClass.swift"; sourceTree = "<group>"; }; + 95ED176A25CEFE1B00AE34B3 /* RecentSearch+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RecentSearch+CoreDataProperties.swift"; sourceTree = "<group>"; }; 95F6C2EF25BAE2ED003CF389 /* Company.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Company.swift; sourceTree = "<group>"; }; 95F6C30825BAF7C2003CF389 /* DateSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateSelection.swift; sourceTree = "<group>"; }; 95F6F45B25C20D8D002AC66A /* Price.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Price.swift; sourceTree = "<group>"; }; @@ -191,6 +197,8 @@ 95B04EA625212369000AD27F = { isa = PBXGroup; children = ( + 95ED176925CEFE1B00AE34B3 /* RecentSearch+CoreDataClass.swift */, + 95ED176A25CEFE1B00AE34B3 /* RecentSearch+CoreDataProperties.swift */, 95FE646525C2DC570052832E /* WatchlistCompany+CoreDataClass.swift */, 95FE646625C2DC570052832E /* WatchlistCompany+CoreDataProperties.swift */, 95B04EB125212369000AD27F /* LazyBear */, @@ -237,6 +245,7 @@ 95E07B6D25CE95A1001718AB /* Search.swift */, 95612C4F2598D48200F7698F /* SearchBar.swift */, 95AB4A8F259DD66D0064C9C1 /* CompanyRow.swift */, + 95ED176025CEF14E00AE34B3 /* RecentSearches.swift */, ); name = Search; sourceTree = "<group>"; @@ -394,6 +403,7 @@ 95FE646B25C30B880052832E /* ApiModel.swift in Sources */, 95B3552F25CD629F00BCDE8E /* TransactionCodes.swift in Sources */, 95612C512598D48200F7698F /* SearchBar.swift in Sources */, + 95ED176125CEF14E00AE34B3 /* RecentSearches.swift in Sources */, 95E411BE25BEEA6C00A9C23F /* WatchlistRow.swift in Sources */, 95078FD125BF4E640004FA75 /* CloudKitManager.swift in Sources */, 95B04EB525212369000AD27F /* ContentView.swift in Sources */, @@ -407,6 +417,8 @@ 958B678525C42B2400BF9F89 /* ApiAccess.swift in Sources */, 95B04EB325212369000AD27F /* LazyBearApp.swift in Sources */, 95E07B6B25CE9398001718AB /* AppView.swift in Sources */, + 95ED176C25CEFE1B00AE34B3 /* RecentSearch+CoreDataProperties.swift in Sources */, + 95ED176B25CEFE1B00AE34B3 /* RecentSearch+CoreDataClass.swift in Sources */, 95AB4A7D259DCC0C0064C9C1 /* CompanyModel.swift in Sources */, 95E411B625BEE84E00A9C23F /* Stock.swift in Sources */, 9520F0B225C712D000692610 /* LineChartShape.swift in Sources */,
Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RecentSearch+CoreDataClass.swift Sat Feb 06 17:45:04 2021 +0100 @@ -0,0 +1,15 @@ +// +// RecentSearch+CoreDataClass.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 6/2/21. +// +// + +import Foundation +import CoreData + +@objc(RecentSearch) +public class RecentSearch: NSManagedObject { + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RecentSearch+CoreDataProperties.swift Sat Feb 06 17:45:04 2021 +0100 @@ -0,0 +1,27 @@ +// +// RecentSearch+CoreDataProperties.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 6/2/21. +// +// + +import Foundation +import CoreData + + +extension RecentSearch { + + @nonobjc public class func fetchRequest() -> NSFetchRequest<RecentSearch> { + return NSFetchRequest<RecentSearch>(entityName: "RecentSearch") + } + + @NSManaged public var name: String? + @NSManaged public var symbol: String? + @NSManaged public var date: Date? + +} + +extension RecentSearch : Identifiable { + +}
--- a/lazybear/ContentView.swift Sat Feb 06 12:33:57 2021 +0100 +++ b/lazybear/ContentView.swift Sat Feb 06 17:45:04 2021 +0100 @@ -24,11 +24,11 @@ } // Second view - //Watchlist() - //.tabItem { - //Image(systemName: "list.bullet") - //Text("Watchlist") - //} + Watchlist() + .tabItem { + Image(systemName: "list.bullet") + Text("Watchlist") + } // Third view //Settings()
--- a/lazybear/LazyBear.xcdatamodeld/LazyBear.xcdatamodel/contents Sat Feb 06 12:33:57 2021 +0100 +++ b/lazybear/LazyBear.xcdatamodeld/LazyBear.xcdatamodel/contents Sat Feb 06 17:45:04 2021 +0100 @@ -1,5 +1,10 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17709" systemVersion="20C69" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier=""> +<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17709" systemVersion="20D64" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier=""> + <entity name="RecentSearch" representedClassName="RecentSearch" syncable="YES"> + <attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/> + <attribute name="name" optional="YES" attributeType="String"/> + <attribute name="symbol" optional="YES" attributeType="String"/> + </entity> <entity name="WatchlistCompany" representedClassName="WatchlistCompany" syncable="YES"> <attribute name="cik" optional="YES" attributeType="String"/> <attribute name="currency" optional="YES" attributeType="String"/> @@ -18,5 +23,6 @@ </entity> <elements> <element name="WatchlistCompany" positionX="-63" positionY="-18" width="128" height="239"/> + <element name="RecentSearch" positionX="-63" positionY="90" width="128" height="74"/> </elements> </model> \ No newline at end of file
--- a/lazybear/Persistence.swift Sat Feb 06 12:33:57 2021 +0100 +++ b/lazybear/Persistence.swift Sat Feb 06 17:45:04 2021 +0100 @@ -30,6 +30,12 @@ newItem.cik = String() newItem.lei = String() } + + for _ in 0..<1 { + let newItem = RecentSearch(context: viewContext) + newItem.name = String() + newItem.symbol = String() + } do { try viewContext.save() } catch {
--- a/lazybear/Views/AddWatchlist.swift Sat Feb 06 12:33:57 2021 +0100 +++ b/lazybear/Views/AddWatchlist.swift Sat Feb 06 17:45:04 2021 +0100 @@ -32,7 +32,7 @@ } } - func addWatchlist(name: String, symbol: String) { + private func addWatchlist(name: String, symbol: String) { let watchlistCompany = WatchlistCompany(context: viewContext) watchlistCompany.name = name watchlistCompany.symbol = symbol
--- a/lazybear/Views/Company.swift Sat Feb 06 12:33:57 2021 +0100 +++ b/lazybear/Views/Company.swift Sat Feb 06 17:45:04 2021 +0100 @@ -12,35 +12,34 @@ var symbol: String @Environment(\.presentationMode) var presentationMode + @Environment(\.managedObjectContext) private var viewContext // Core data var body: some View { - NavigationView { - TabView { - GeometryReader { geo in - ScrollView { - VStack(alignment: .leading) { - Stock(name: name, symbol: symbol, lineChartHeight: geo.size.height*0.2) - .padding(.bottom) - - News(symbol: symbol) - } - } + GeometryReader { geo in + ScrollView { + VStack(alignment: .leading) { + Stock(name: name, symbol: symbol, lineChartHeight: geo.size.height*0.2) + .padding(.bottom) + + News(symbol: symbol) } - .tabItem { - Image(systemName: "magnifyingglass") - Text("Stock") + .onAppear { saveSearch(name: name, symbol: symbol) } } } - .navigationBarTitle(symbol, displayMode: .inline) - .navigationBarItems( - leading: - Button(action: { self.presentationMode.wrappedValue.dismiss() }) { - Image(systemName: "multiply") - } - , - trailing: - AddWatchlist(symbol: symbol, name: name) - ) + .navigationBarTitle(symbol, displayMode: .large) + .navigationBarItems(trailing: AddWatchlist(symbol: symbol, name: name)) + } + + private func saveSearch(name: String, symbol: String) { + let searched = RecentSearch(context: viewContext) + searched.name = name + searched.symbol = symbol + searched.date = Date() + do { + try viewContext.save() + print("Search saved") + } catch { + print(error.localizedDescription) } } }
--- a/lazybear/Views/CompanyRow.swift Sat Feb 06 12:33:57 2021 +0100 +++ b/lazybear/Views/CompanyRow.swift Sat Feb 06 17:45:04 2021 +0100 @@ -8,27 +8,29 @@ import SwiftUI struct CompanyRow: View { - var company: CompanyModel + var company: CompanyModel? + var history: RecentSearch? @State var showingCompany = false @EnvironmentObject var apiAccess: ApiAccess // Env apis info let persistenceController = PersistenceController.shared // Core Data var body: some View { - Button(action: { self.showingCompany.toggle() }) { + let name = company?.name ?? history?.name ?? "" + let symbol = company?.symbol ?? history?.symbol ?? "" + + NavigationLink(destination: Company(name: name, symbol: symbol) + .environment(\.managedObjectContext, persistenceController.container.viewContext) + .environmentObject(apiAccess) // Api info (url and token) + ) { VStack(alignment: .leading) { - Text(company.symbol.uppercased()) + Text(symbol.uppercased()) .fontWeight(.semibold) - Text(company.name.capitalized) + Text(name.capitalized) .font(.subheadline) } } - .fullScreenCover(isPresented: $showingCompany) { - Company(name: company.name, symbol: company.symbol) - .environment(\.managedObjectContext, persistenceController.container.viewContext) - .environmentObject(apiAccess) // Api info (url and token) - } } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lazybear/Views/RecentSearches.swift Sat Feb 06 17:45:04 2021 +0100 @@ -0,0 +1,23 @@ +// +// RecentSearches.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 6/2/21. +// + +import SwiftUI + +struct RecentSearches: View { + var body: some View { + VStack { + Text("Recent searches") + .fontWeight(.semibold) + } + } +} + +struct RecentSearches_Previews: PreviewProvider { + static var previews: some View { + RecentSearches() + } +}
--- a/lazybear/Views/Search.swift Sat Feb 06 12:33:57 2021 +0100 +++ b/lazybear/Views/Search.swift Sat Feb 06 17:45:04 2021 +0100 @@ -10,7 +10,13 @@ struct Search: View { @State var searchedCompany = String() @EnvironmentObject var apiAccess: ApiAccess // Env apis info + + // <--------- Core Data ---------> let persistenceController = PersistenceController.shared // Core Data + @Environment(\.managedObjectContext) private var viewContext + @FetchRequest(entity: RecentSearch.entity(), sortDescriptors: []) + var searches: FetchedResults<RecentSearch> + // <--------- Core Data ---------> var body: some View { NavigationView { @@ -23,6 +29,16 @@ .environment(\.managedObjectContext, persistenceController.container.viewContext) .environmentObject(apiAccess) // Api info (url and token) } + } else { + if searches.count > 0 { + Section(header: Text("History"), + footer: Button(action: { delete() }) { Text("Clear history").foregroundColor(.blue)} + ) { + ForEach(searches) { search in + CompanyRow(history: search) + } + } + } } } .id(UUID()) // Increase speed in search the list @@ -30,6 +46,18 @@ } } .navigationViewStyle(StackNavigationViewStyle()) } + + private func delete() { + for value in searches { + viewContext.delete(value) + } + do { + try viewContext.save() + print("History deleted") + } catch { + print(error.localizedDescription) + } + } } struct Search_Previews: PreviewProvider {
--- a/lazybear/Views/Watchlist.swift Sat Feb 06 12:33:57 2021 +0100 +++ b/lazybear/Views/Watchlist.swift Sat Feb 06 17:45:04 2021 +0100 @@ -16,17 +16,15 @@ var body: some View { NavigationView { List { - Section(header: Text("Watchlist")) { - ForEach(companies) { company in - WatchlistRow(company: company) - } - .onDelete { indexSet in deleteWatchlist(indexSet: indexSet) } // Delete from persistent storage + ForEach(companies) { company in + WatchlistRow(company: company) } + .onDelete { indexSet in deleteWatchlist(indexSet: indexSet) } // Delete from persistent storage } .navigationBarTitle("Watchlist", displayMode: .inline) .toolbar { EditButton() } - } + }.navigationViewStyle(StackNavigationViewStyle()) } func deleteWatchlist(indexSet: IndexSet) {
--- a/lazybear/Views/WatchlistRow.swift Sat Feb 06 12:33:57 2021 +0100 +++ b/lazybear/Views/WatchlistRow.swift Sat Feb 06 17:45:04 2021 +0100 @@ -17,31 +17,40 @@ let persistenceController = PersistenceController.shared var body: some View { - HStack { - let url = apiAccess.results[0].url - let path = "/iex/api/logos/\(company.symbol ?? "").png" - let endpoint = url! + path - - WebImage(url: URL(string: endpoint)) - .resizable() - .placeholder { LogoPlaceholder() } // If there is no logo - .indicator(.activity) - .modifier(LogoModifier()) - - VStack(alignment: .leading) { - Text(company.symbol ?? "".uppercased()) - .fontWeight(.semibold) + NavigationLink(destination: Company(name: company.name ?? "", symbol: company.symbol ?? "") + .environment(\.managedObjectContext, persistenceController.container.viewContext) + .environmentObject(apiAccess) // Api info (url and token) + ) { + HStack { + WebImage(url: URL(string: endpoint())) + .resizable() + .placeholder { LogoPlaceholder() } // If there is no logo + .indicator(.activity) + .modifier(LogoModifier()) - Text(company.name ?? "".capitalized) - .font(.subheadline) + VStack(alignment: .leading) { + Text(company.symbol ?? "".uppercased()) + .fontWeight(.semibold) + + Text(company.name ?? "".capitalized) + .font(.subheadline) + } + + Spacer() + if self.editMode?.wrappedValue.isEditing ?? true { } else { // If EditButton() is not clicked -> show prices + Price(symbol: company.symbol ?? "", showHorizontal: false) + } } - - Spacer() - if self.editMode?.wrappedValue.isEditing ?? true { } else { // If EditButton() is not clicked -> show prices - Price(symbol: company.symbol ?? "", showHorizontal: false) - } + .padding([.top, .bottom], 6) } - .padding([.top, .bottom], 6) + } + + private func endpoint() -> String { + let url = apiAccess.results[0].url + let path = "/iex/api/logos/\(company.symbol ?? "").png" + let endpoint = url! + path + + return endpoint } }