# HG changeset patch # User Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com> # Date 1612526174 -3600 # Node ID 2bc9e5c0a7c6b82dcd2a72cce681aea9b9a70f38 # Parent 82ac1ea6526931f6a567e22a752829802938ab1e Implement TransactionDetails diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 LazyBear.xcodeproj/project.pbxproj --- a/LazyBear.xcodeproj/project.pbxproj Fri Feb 05 11:14:05 2021 +0100 +++ b/LazyBear.xcodeproj/project.pbxproj Fri Feb 05 12:56:14 2021 +0100 @@ -35,6 +35,8 @@ 95B04EB525212369000AD27F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B04EB425212369000AD27F /* ContentView.swift */; }; 95B04EB72521236A000AD27F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 95B04EB62521236A000AD27F /* Assets.xcassets */; }; 95B3552825CD4A5600BCDE8E /* NewsDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B3552725CD4A5600BCDE8E /* NewsDetail.swift */; }; + 95B3552C25CD5D7400BCDE8E /* TransactionDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B3552B25CD5D7400BCDE8E /* TransactionDetail.swift */; }; + 95B3552F25CD629F00BCDE8E /* TransactionCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B3552E25CD629F00BCDE8E /* TransactionCodes.swift */; }; 95B395A525BDF42E009A7EB0 /* companies.json in Resources */ = {isa = PBXBuildFile; fileRef = 95B395A425BDF42E009A7EB0 /* companies.json */; }; 95D1BF4925ADCF7700E5D063 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95D1BF4825ADCF7700E5D063 /* Persistence.swift */; }; 95E4118F25BEC35D00A9C23F /* SDWebImageSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 95E4118E25BEC35D00A9C23F /* SDWebImageSwiftUI */; }; @@ -87,6 +89,8 @@ 95B04EB62521236A000AD27F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 95B04EBB2521236A000AD27F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 95B3552725CD4A5600BCDE8E /* NewsDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = NewsDetail.swift; path = lazybear/Views/NewsDetail.swift; sourceTree = SOURCE_ROOT; }; + 95B3552B25CD5D7400BCDE8E /* TransactionDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TransactionDetail.swift; path = lazybear/Views/TransactionDetail.swift; sourceTree = SOURCE_ROOT; }; + 95B3552E25CD629F00BCDE8E /* TransactionCodes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TransactionCodes.swift; path = lazybear/Data/TransactionCodes.swift; sourceTree = SOURCE_ROOT; }; 95B395A425BDF42E009A7EB0 /* companies.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = companies.json; path = lazybear/Data/companies.json; sourceTree = SOURCE_ROOT; }; 95D1BF4825ADCF7700E5D063 /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Persistence.swift; path = LazyBear/Persistence.swift; sourceTree = SOURCE_ROOT; }; 95E4119125BEC56F00A9C23F /* SuperTitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuperTitle.swift; sourceTree = ""; }; @@ -174,6 +178,7 @@ 959D28DE25CC9A1A0029F689 /* News.swift */, 959D28E125CC9B370029F689 /* NewsRow.swift */, 95B3552725CD4A5600BCDE8E /* NewsDetail.swift */, + 95B3552B25CD5D7400BCDE8E /* TransactionDetail.swift */, ); path = Views; sourceTree = ""; @@ -199,6 +204,7 @@ isa = PBXGroup; children = ( 95B395A425BDF42E009A7EB0 /* companies.json */, + 95B3552E25CD629F00BCDE8E /* TransactionCodes.swift */, ); path = Data; sourceTree = ""; @@ -331,6 +337,7 @@ 959D28DF25CC9A1A0029F689 /* News.swift in Sources */, 95FE646B25C30B880052832E /* ApiModel.swift in Sources */, 95363CE625C87FEC00B74131 /* InsiderTransactions.swift in Sources */, + 95B3552F25CD629F00BCDE8E /* TransactionCodes.swift in Sources */, 95F6C30525BAF599003CF389 /* CompanyHeader.swift in Sources */, 95363CEA25C8858800B74131 /* TransactionRow.swift in Sources */, 95612C512598D48200F7698F /* SearchBar.swift in Sources */, @@ -349,6 +356,7 @@ 958B678525C42B2400BF9F89 /* ApiAccess.swift in Sources */, 95E4119225BEC56F00A9C23F /* SuperTitle.swift in Sources */, 95B04EB325212369000AD27F /* LazyBearApp.swift in Sources */, + 95B3552C25CD5D7400BCDE8E /* TransactionDetail.swift in Sources */, 95AB4A7D259DCC0C0064C9C1 /* CompanyModel.swift in Sources */, 95E411B625BEE84E00A9C23F /* Stock.swift in Sources */, 9520F0B225C712D000692610 /* LineChartShape.swift in Sources */, diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 lazybear/Data/TransactionCodes.swift --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lazybear/Data/TransactionCodes.swift Fri Feb 05 12:56:14 2021 +0100 @@ -0,0 +1,32 @@ +// +// TransactionCodes.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 5/2/21. +// + +import Foundation +// General transaction codes for Form 4 + +let transactionCodes: [String: String] = [ + "P": "Open market or private purchase of securities", + "S": "Open market or private sale of securities", + "V": "Transaction voluntarily reported earlier than required", + "A": "Grant, award, or other acquisition", + "D": "Sale (or disposition) back to the issuer of the securities", + "F": "Payment of exercise price or tax liability by delivering or withholding securities", + "I": "Discretionary transaction, which is an order to the broker to execute the transaction at the best possible price", + "M": "Exercise or conversion of derivative security", + "C": "Conversion of derivative security (usually options)", + "E": "Expiration of short derivative position (usually options)", + "H": "Expiration (or cancellation) of long derivative position with value received (usually options)", + "O": "Exercise of out-of-the-money derivative securities (usually options)", + "X": "Exercise of in-the-money or at-the-money derivatives securities (usually options)", + "G": "Bona fide gift form of any clauses", + "L": "Small acquisition", + "W": "Acquisition or disposition by will or laws of descent and distribution", + "Z": "Deposit into or withdrawal from voting trust", + "J": "Other acquisition or disposition (transaction described in footnotes)", + "K": "Transaction in equity swap or similar instrument", + "U": "Disposition due to a tender of shares in a change of control transaction", +] diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 lazybear/Models/InsiderTransactionModel.swift --- a/lazybear/Models/InsiderTransactionModel.swift Fri Feb 05 11:14:05 2021 +0100 +++ b/lazybear/Models/InsiderTransactionModel.swift Fri Feb 05 12:56:14 2021 +0100 @@ -12,7 +12,7 @@ var directIndirect: String? var filingDate: String? var fullName: String? - var postShares: Int? + var postShares: Float? var reportedTitle: String? var transactionCode: String? var transactionDate: String? diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 lazybear/Views/AddWatchlist.swift --- a/lazybear/Views/AddWatchlist.swift Fri Feb 05 11:14:05 2021 +0100 +++ b/lazybear/Views/AddWatchlist.swift Fri Feb 05 12:56:14 2021 +0100 @@ -15,12 +15,7 @@ var body: some View { Button(action: { addWatchlist(name: name, symbol: symbol) }) { - ZStack { - RoundedRectangle(cornerRadius: 10) - Text("Add to watchlist") - .foregroundColor(.white) - } - .frame(width: 150) + Text("Add to watchlist") } } diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 lazybear/Views/Company.swift --- a/lazybear/Views/Company.swift Fri Feb 05 11:14:05 2021 +0100 +++ b/lazybear/Views/Company.swift Fri Feb 05 12:56:14 2021 +0100 @@ -12,6 +12,7 @@ var symbol: String let persistenceController = PersistenceController.shared + @EnvironmentObject var apiAccess: ApiAccess var body: some View { VStack { @@ -23,8 +24,10 @@ VStack(alignment: .leading) { Stock(name: name, symbol: symbol, lineChartHeight: geo.size.height*0.2) .padding(.bottom) + .environmentObject(self.apiAccess) News(symbol: symbol) + .environmentObject(self.apiAccess) } .environment(\.managedObjectContext, persistenceController.container.viewContext) } @@ -37,6 +40,7 @@ // Second view ScrollView { InsiderTransactions(symbol: symbol) + .environmentObject(self.apiAccess) } .tabItem { Image(systemName: "chart.pie.fill") diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 lazybear/Views/InsiderTransactions.swift --- a/lazybear/Views/InsiderTransactions.swift Fri Feb 05 11:14:05 2021 +0100 +++ b/lazybear/Views/InsiderTransactions.swift Fri Feb 05 12:56:14 2021 +0100 @@ -34,7 +34,7 @@ private func getUrl() { // 1 -> Sandbox / 2 -> Production - let baseUrl = apiAccess.results[1].url ?? "" + let baseUrl = apiAccess.results[2].url ?? "" let token = apiAccess.results[1].key ?? "" let path = "/stable/stock/\(symbol)/insider-transactions?token=" diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 lazybear/Views/News.swift --- a/lazybear/Views/News.swift Fri Feb 05 11:14:05 2021 +0100 +++ b/lazybear/Views/News.swift Fri Feb 05 12:56:14 2021 +0100 @@ -37,8 +37,8 @@ private func getUrl() { // 1 -> Sandbox / 2 -> Production - let baseUrl = apiAccess.results[2].url ?? "" - let token = apiAccess.results[2].key ?? "" + let baseUrl = apiAccess.results[1].url ?? "" + let token = apiAccess.results[1].key ?? "" let path = "/stable/stock/\(symbol)/news/last/10?token=" self.url = baseUrl + path + token diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 lazybear/Views/NewsDetail.swift --- a/lazybear/Views/NewsDetail.swift Fri Feb 05 11:14:05 2021 +0100 +++ b/lazybear/Views/NewsDetail.swift Fri Feb 05 12:56:14 2021 +0100 @@ -10,14 +10,14 @@ struct NewsDetail: View { @State var new: NewsModel - @Environment(\.presentationMode) var detailPresentation + @Environment(\.presentationMode) var newDetailPresentation var body: some View { VStack(alignment: .leading) { HStack { Spacer() - Button(action: { self.detailPresentation.wrappedValue.dismiss() }) { + Button(action: { self.newDetailPresentation.wrappedValue.dismiss() }) { Image(systemName: "multiply.circle.fill") } } diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 lazybear/Views/Price.swift --- a/lazybear/Views/Price.swift Fri Feb 05 11:14:05 2021 +0100 +++ b/lazybear/Views/Price.swift Fri Feb 05 12:56:14 2021 +0100 @@ -30,9 +30,11 @@ .fontWeight(.semibold) Text("\(data[0].changePercent ?? 0 * 100, specifier: "%.2f")%") + .padding(1) .font(.subheadline) .foregroundColor(.white) - .background(percentageColor().cornerRadius(5)) + .background(percentageColor().cornerRadius(3)) + } .if(showVertical) { content in HStack { content } diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 lazybear/Views/TransactionDetail.swift --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lazybear/Views/TransactionDetail.swift Fri Feb 05 12:56:14 2021 +0100 @@ -0,0 +1,85 @@ +// +// TransactionDetail.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 5/2/21. +// + +import SwiftUI + +struct TransactionDetail: View { + @State var data: InsiderTransactionModel + @Environment(\.presentationMode) var transactionDetailPresentation + + var body: some View { + NavigationView { + Form { + Section(header: Text("Filling date")) { + HStack { + Image(systemName: "calendar") + Text(data.filingDate ?? "-") + } + } + + Section(header: Text("Owner")) { + HStack { + Image(systemName: "person.fill") + Text(data.fullName ?? "-") + } + let title = data.reportedTitle ?? "" + if !title.isEmpty { + Text(data.reportedTitle ?? "") + } + } + + let postShares = data.postShares ?? 0 + if postShares != 0 { + Section(header: Text("Shares owned after the transaction")) { + HStack { + Image(systemName: "number") + Text(String(postShares)) + } + } + } + + Section(header: Text("Transaction type")) { + let transactionCode = data.transactionCode ?? "" + Text(transactionCodes[transactionCode] ?? "-") + } + + Section(header: Text("Transaction data")) { + let shares = Int(data.transactionShares ?? 0) + if shares != 0 { + Text("Number of shares: \(shares)") + } + let price = data.transactionPrice ?? 0 + if price != 0 { + Text("Price per share: $\(shares, specifier: "%.2f")") + } + let value = data.transactionValue ?? 0 + if value != 0 { + Text("Transaction value: $\(shares, specifier: "%.2f")") + } + } + } + .navigationBarTitle("Transaction detail") + } + } +} + +struct TransactionDetail_Previews: PreviewProvider { + static var previews: some View { + TransactionDetail(data: InsiderTransactionModel( + conversionOrExercisePrice: 100, + directIndirect: "D", + filingDate: "2020-10-09", + fullName: "Tim", + postShares: 100, + reportedTitle: "Some reported title", + transactionCode: "I", + transactionDate: "2020-10-09", + transactionPrice: 50, + transactionShares: 1000, + transactionValue: 50000)) + } +} diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 lazybear/Views/TransactionRow.swift --- a/lazybear/Views/TransactionRow.swift Fri Feb 05 11:14:05 2021 +0100 +++ b/lazybear/Views/TransactionRow.swift Fri Feb 05 12:56:14 2021 +0100 @@ -9,26 +9,48 @@ struct TransactionRow: View { @State var data: InsiderTransactionModel + @State private var showingDetail = false var body: some View { - VStack { - HStack(alignment: .top) { - VStack(alignment: .leading) { - Text(data.fullName ?? "-".capitalized) - .fontWeight(.semibold) - - Text(data.transactionDate ?? "-") - .font(.subheadline) + Button(action: { self.showingDetail.toggle() }) { + VStack { + HStack(alignment: .top) { + VStack(alignment: .leading) { + Text(data.fullName?.capitalized ?? "-") + .fontWeight(.semibold) + + Text(data.transactionDate ?? "-") + .font(.subheadline) + } + Spacer() + VStack { + Text("\(data.transactionShares ?? 0)") + .fontWeight(.semibold) + .foregroundColor(color()) + + Text("Shares") + .font(.subheadline) + } } - Spacer() - Text("$\(data.transactionValue ?? 0, specifier: "%.2f")") - .fontWeight(.semibold) + .padding([.leading, .trailing]) + + Divider() } - .padding([.leading, .trailing]) - - Divider() + } + .buttonStyle(PlainButtonStyle()) + .sheet(isPresented: $showingDetail) { + TransactionDetail(data: self.data) } } + + private func color() -> Color { + var color: Color = .red + if data.transactionShares ?? 0 >= 0 { + color = .green + } + + return color + } } struct TransactionRow_Previews: PreviewProvider { diff -r 82ac1ea65269 -r 2bc9e5c0a7c6 lazybear/Views/WatchlistRow.swift --- a/lazybear/Views/WatchlistRow.swift Fri Feb 05 11:14:05 2021 +0100 +++ b/lazybear/Views/WatchlistRow.swift Fri Feb 05 12:56:14 2021 +0100 @@ -33,6 +33,7 @@ Text(company.name ?? "".capitalized) .font(.subheadline) + .padding(1) } Spacer()