# HG changeset patch # User Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com> # Date 1612629904 -3600 # Node ID 2d6df8debf1271d7af1bdfc70ec4ccb43e9e6b58 # Parent c7532d18d6beb1a90f459a633c6b04bf12846b0d Add search history and fix bugs diff -r c7532d18d6be -r 2d6df8debf12 LazyBear.xcodeproj/project.pbxproj --- 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 = ""; }; 95E411B525BEE84E00A9C23F /* Stock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stock.swift; sourceTree = ""; }; 95E411BD25BEEA6C00A9C23F /* WatchlistRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchlistRow.swift; sourceTree = ""; }; + 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 = ""; }; + 95ED176A25CEFE1B00AE34B3 /* RecentSearch+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RecentSearch+CoreDataProperties.swift"; sourceTree = ""; }; 95F6C2EF25BAE2ED003CF389 /* Company.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Company.swift; sourceTree = ""; }; 95F6C30825BAF7C2003CF389 /* DateSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateSelection.swift; sourceTree = ""; }; 95F6F45B25C20D8D002AC66A /* Price.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Price.swift; sourceTree = ""; }; @@ -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 = ""; @@ -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 */, diff -r c7532d18d6be -r 2d6df8debf12 LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed diff -r c7532d18d6be -r 2d6df8debf12 RecentSearch+CoreDataClass.swift --- /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 { + +} diff -r c7532d18d6be -r 2d6df8debf12 RecentSearch+CoreDataProperties.swift --- /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 { + return NSFetchRequest(entityName: "RecentSearch") + } + + @NSManaged public var name: String? + @NSManaged public var symbol: String? + @NSManaged public var date: Date? + +} + +extension RecentSearch : Identifiable { + +} diff -r c7532d18d6be -r 2d6df8debf12 lazybear/ContentView.swift --- 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() diff -r c7532d18d6be -r 2d6df8debf12 lazybear/LazyBear.xcdatamodeld/LazyBear.xcdatamodel/contents --- 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 @@ - + + + + + + @@ -18,5 +23,6 @@ + \ No newline at end of file diff -r c7532d18d6be -r 2d6df8debf12 lazybear/Persistence.swift --- 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 { diff -r c7532d18d6be -r 2d6df8debf12 lazybear/Views/AddWatchlist.swift --- 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 diff -r c7532d18d6be -r 2d6df8debf12 lazybear/Views/Company.swift --- 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) } } } diff -r c7532d18d6be -r 2d6df8debf12 lazybear/Views/CompanyRow.swift --- 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) - } } } diff -r c7532d18d6be -r 2d6df8debf12 lazybear/Views/RecentSearches.swift --- /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() + } +} diff -r c7532d18d6be -r 2d6df8debf12 lazybear/Views/Search.swift --- 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 + // <--------- 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 { diff -r c7532d18d6be -r 2d6df8debf12 lazybear/Views/Watchlist.swift --- 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) { diff -r c7532d18d6be -r 2d6df8debf12 lazybear/Views/WatchlistRow.swift --- 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 } }