Mercurial > public > lazybear
changeset 411:681fb377235e
Implementing insider transactions
author | Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com> |
---|---|
date | Mon, 07 Jun 2021 20:59:52 +0200 |
parents | e24c9ca71824 |
children | a7c9dd0c5822 |
files | LazyBear.xcodeproj/project.pbxproj LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate LazyBear/Global Models/InsiderTransactionModel.swift LazyBear/Global functions/ConvertStringToDate.swift LazyBear/Global functions/GetDateComponents.swift LazyBear/Views/Company/Helpers/InsiderList.swift LazyBear/Views/Company/Helpers/TransactionList.swift LazyBear/Views/Company/Helpers/TransactionRow.swift LazyBear/Views/Company/Insiders.swift LazyBear/Views/Company/Networking/InsidersResponse.swift LazyBear/Views/Home/Helpers/TradingDatesItem.swift LazyBear/Views/Home/TradingDates.swift |
diffstat | 12 files changed, 278 insertions(+), 44 deletions(-) [+] |
line wrap: on
line diff
--- a/LazyBear.xcodeproj/project.pbxproj Sun Jun 06 19:07:52 2021 +0200 +++ b/LazyBear.xcodeproj/project.pbxproj Mon Jun 07 20:59:52 2021 +0200 @@ -72,6 +72,12 @@ 95BD2FAE26341BD1008B6752 /* TextfieldAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BD2FAD26341BD1008B6752 /* TextfieldAlert.swift */; }; 95BD2FB326341D36008B6752 /* BlurBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BD2FB226341D36008B6752 /* BlurBackground.swift */; }; 95C8C0E0262A369F0082D1D9 /* ProfileResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95C8C0DF262A369F0082D1D9 /* ProfileResponse.swift */; }; + 95CCFB56266E7A0F00C384A1 /* InsiderTransactionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CCFB55266E7A0F00C384A1 /* InsiderTransactionModel.swift */; }; + 95CCFB58266E7F4F00C384A1 /* InsiderList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CCFB57266E7F4F00C384A1 /* InsiderList.swift */; }; + 95CCFB5A266E841B00C384A1 /* TransactionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CCFB59266E841B00C384A1 /* TransactionRow.swift */; }; + 95CCFB5C266E842000C384A1 /* TransactionList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CCFB5B266E842000C384A1 /* TransactionList.swift */; }; + 95CCFB5E266E855800C384A1 /* GetDateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CCFB5D266E855800C384A1 /* GetDateComponents.swift */; }; + 95CCFB60266E864C00C384A1 /* ConvertStringToDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CCFB5F266E864C00C384A1 /* ConvertStringToDate.swift */; }; 95D308F82624B3A400A39F77 /* CurrencyItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95D308F72624B3A400A39F77 /* CurrencyItem.swift */; }; 95E31C0D26472CA000106B98 /* CompanyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95E31C0C26472CA000106B98 /* CompanyView.swift */; }; 95E31C122647304100106B98 /* PriceViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95E31C112647304100106B98 /* PriceViewStyle.swift */; }; @@ -169,6 +175,12 @@ 95BD2FAD26341BD1008B6752 /* TextfieldAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextfieldAlert.swift; sourceTree = "<group>"; }; 95BD2FB226341D36008B6752 /* BlurBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurBackground.swift; sourceTree = "<group>"; }; 95C8C0DF262A369F0082D1D9 /* ProfileResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileResponse.swift; sourceTree = "<group>"; }; + 95CCFB55266E7A0F00C384A1 /* InsiderTransactionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsiderTransactionModel.swift; sourceTree = "<group>"; }; + 95CCFB57266E7F4F00C384A1 /* InsiderList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsiderList.swift; sourceTree = "<group>"; }; + 95CCFB59266E841B00C384A1 /* TransactionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionRow.swift; sourceTree = "<group>"; }; + 95CCFB5B266E842000C384A1 /* TransactionList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionList.swift; sourceTree = "<group>"; }; + 95CCFB5D266E855800C384A1 /* GetDateComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetDateComponents.swift; sourceTree = "<group>"; }; + 95CCFB5F266E864C00C384A1 /* ConvertStringToDate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvertStringToDate.swift; sourceTree = "<group>"; }; 95D308F72624B3A400A39F77 /* CurrencyItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyItem.swift; sourceTree = "<group>"; }; 95E31C0C26472CA000106B98 /* CompanyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanyView.swift; sourceTree = "<group>"; }; 95E31C112647304100106B98 /* PriceViewStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceViewStyle.swift; sourceTree = "<group>"; }; @@ -266,6 +278,8 @@ children = ( 952045142610C7C600A76362 /* ConvertEpoch.swift */, 95A7C0732616409D003E2EC1 /* ParseJSON.swift */, + 95CCFB5D266E855800C384A1 /* GetDateComponents.swift */, + 95CCFB5F266E864C00C384A1 /* ConvertStringToDate.swift */, ); path = "Global functions"; sourceTree = "<group>"; @@ -300,6 +314,7 @@ 95613ADE264FC6FD00D4CE8F /* LatestNewsModel.swift */, 9594F03F2651355B00CFA8D4 /* HistoricalPricesModel.swift */, 95602703265ABB990046F97E /* InsiderRosterModel.swift */, + 95CCFB55266E7A0F00C384A1 /* InsiderTransactionModel.swift */, ); path = "Global Models"; sourceTree = "<group>"; @@ -477,6 +492,9 @@ 95613AE0264FD34100D4CE8F /* NewsRow.swift */, 950857A8266BD2C6005357BA /* SFSafariViewWrapper.swift */, 950857D0266BE54B005357BA /* InsiderRow.swift */, + 95CCFB57266E7F4F00C384A1 /* InsiderList.swift */, + 95CCFB59266E841B00C384A1 /* TransactionRow.swift */, + 95CCFB5B266E842000C384A1 /* TransactionList.swift */, ); path = Helpers; sourceTree = "<group>"; @@ -673,6 +691,7 @@ 950C36E3260FB6180081CF53 /* HapticsManager.swift in Sources */, 95FBE0DC2619CA7200440386 /* ProfileView.swift in Sources */, 95A5188626186F590002D27C /* PriceView.swift in Sources */, + 95CCFB5C266E842000C384A1 /* TransactionList.swift in Sources */, 95613AE1264FD34100D4CE8F /* NewsRow.swift in Sources */, 95613ADD264FC6A200D4CE8F /* ChartResponse.swift in Sources */, 9550444926111FC9000E0BCB /* StockRow.swift in Sources */, @@ -685,11 +704,13 @@ 950857D1266BE54B005357BA /* InsiderRow.swift in Sources */, 95A7C0742616409D003E2EC1 /* ParseJSON.swift in Sources */, 95E8BAA32656D86E0016AE72 /* RequestType.swift in Sources */, + 95CCFB56266E7A0F00C384A1 /* InsiderTransactionModel.swift in Sources */, 954D7EA8260BBA6600A13C50 /* WatchlistCompany+CoreDataProperties.swift in Sources */, 951566E72613A2B6007C0F36 /* TradingDates.swift in Sources */, 955E73392623568F005652FF /* Home.swift in Sources */, 95E31C122647304100106B98 /* PriceViewStyle.swift in Sources */, 95721DA6262761E700EC527B /* CurrencyRow.swift in Sources */, + 95CCFB58266E7F4F00C384A1 /* InsiderList.swift in Sources */, 9562404C263C766D00C6C511 /* WatchlistCreator.swift in Sources */, 95672B8F25DDA54700DCBE4A /* LazyBearApp.swift in Sources */, 95A7C066261639E0003E2EC1 /* SearchView.swift in Sources */, @@ -722,13 +743,16 @@ 95C8C0E0262A369F0082D1D9 /* ProfileResponse.swift in Sources */, 95A4B935263EA31C0056F036 /* WatchlistCreatorSearchBar.swift in Sources */, 95AD4A2D26078C1400498079 /* ContentView.swift in Sources */, + 95CCFB5A266E841B00C384A1 /* TransactionRow.swift in Sources */, 95629DA02645298E007AF020 /* Profile.swift in Sources */, + 95CCFB5E266E855800C384A1 /* GetDateComponents.swift in Sources */, 95A4B930263E9F530056F036 /* WatchlistCreatorList.swift in Sources */, 9562404E263C7D8800C6C511 /* WatchlistCreatorClass.swift in Sources */, 95721DB4262787EF00EC527B /* ExtensiveList.swift in Sources */, 950857D3266BE55F005357BA /* RowShape.swift in Sources */, 952045152610C7C600A76362 /* ConvertEpoch.swift in Sources */, 95BD2FAE26341BD1008B6752 /* TextfieldAlert.swift in Sources */, + 95CCFB60266E864C00C384A1 /* ConvertStringToDate.swift in Sources */, 95A07F5D26305A8F009865AA /* IntradayPricesModel.swift in Sources */, 95A07F7626305AE3009865AA /* TradingDatesModel.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/LazyBear/Global Models/InsiderTransactionModel.swift Mon Jun 07 20:59:52 2021 +0200 @@ -0,0 +1,19 @@ +// +// InsiderTransactionModel.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 7/6/21. +// + +import SwiftUI + +struct InsiderTransactionModel: Codable { + var filingDate: String + var fullName: String + var postShares: Int + var reportedTitle: String? + var transactionCode: String + var transactionPrice: Float + var transactionShares: Int + var transactionValue: Float +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Global functions/ConvertStringToDate.swift Mon Jun 07 20:59:52 2021 +0200 @@ -0,0 +1,18 @@ +// +// ConvertStringToDate.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 7/6/21. +// + +import SwiftUI + +func convertStringToDate(_ stringDate: String) -> Date { + // Convert string to date + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd" + + let date = dateFormatter.date(from: stringDate)! + + return date +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Global functions/GetDateComponents.swift Mon Jun 07 20:59:52 2021 +0200 @@ -0,0 +1,33 @@ +// +// GetDateComponents.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 7/6/21. +// + +import SwiftUI + +enum Components { + case day, month, year +} + +/* + Get components from a date + */ +func getDateComponents(_ components: Components, _ date: Date) -> String { + let dateComponents = Calendar.current.dateComponents([.year, .month, .day], from: date) + + switch components { + case .year: + return "\(dateComponents.year ?? 2020)" + case .day: + return "\(dateComponents.day ?? 1)" + case .month: + let dateFormatter = DateFormatter() + let monthNumber = dateComponents.month ?? 1 + let monthLetters = dateFormatter.shortMonthSymbols[monthNumber-1] + + return "\(monthLetters)" + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Views/Company/Helpers/InsiderList.swift Mon Jun 07 20:59:52 2021 +0200 @@ -0,0 +1,85 @@ +// +// InsiderList.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 7/6/21. +// + +import SwiftUI + +struct InsiderList: View { + var insiderSummary: [InsiderRosterModel] + var numberOfRows: Int + + @State private var showFullList = false + + var body: some View { + VStack(alignment: .leading) { + HStack { + Text("Top 10 insiders") + .font(.title3) + .fontWeight(.semibold) + + Spacer() + Button("See all", action: { showFullList = true }) + } + + // Get total shares owned by the top 10 insiders + let totalPositions = insiderSummary.map { $0.position }.reduce(0, +) + VStack(alignment: .leading, spacing: 20) { + ForEach(insiderSummary.prefix(numberOfRows), id: \.self) { insider in + + // Compute percentage of ownership for each insider + let percentage = Double(insider.position) / Double(totalPositions) + + InsiderRow(percentageOfWidth: CGFloat(percentage), insiderRoster: insider) + } + } + } + .sheet(isPresented: $showFullList) { + InsiderFullList(insiderSummary: insiderSummary) + } + } +} + +struct InsiderList_Previews: PreviewProvider { + static var previews: some View { + InsiderList(insiderSummary: + [InsiderRosterModel(entityName: "Dennis Concepcion", position: 1234, reportDate: 1234567)], + numberOfRows: 3) + } +} + +struct InsiderFullList: View { + var insiderSummary: [InsiderRosterModel] + @Environment(\.presentationMode) private var presentationInsiderFullList + + var body: some View { + NavigationView { + ScrollView { + // Get total shares owned by the top 10 insiders + let totalPositions = insiderSummary.map { $0.position }.reduce(0, +) + VStack(alignment: .leading, spacing: 20) { + ForEach(insiderSummary, id: \.self) { insider in + + // Compute percentage of ownership for each insider + let percentage = Double(insider.position) / Double(totalPositions) + + InsiderRow(percentageOfWidth: CGFloat(percentage), insiderRoster: insider) + } + } + .padding() + } + .navigationTitle("Top 10 insiders") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .navigationBarLeading) { + Button(action: { presentationInsiderFullList.wrappedValue.dismiss() }) { + Image(systemName: "multiply") + .imageScale(.large) + } + } + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Views/Company/Helpers/TransactionList.swift Mon Jun 07 20:59:52 2021 +0200 @@ -0,0 +1,20 @@ +// +// TransactionList.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 7/6/21. +// + +import SwiftUI + +struct TransactionList: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +struct TransactionList_Previews: PreviewProvider { + static var previews: some View { + TransactionList() + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Views/Company/Helpers/TransactionRow.swift Mon Jun 07 20:59:52 2021 +0200 @@ -0,0 +1,67 @@ +// +// TransactionRow.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 7/6/21. +// + +import SwiftUI + +struct TransactionRow: View { + var transaction: InsiderTransactionModel + + var body: some View { + RowShape() + .frame(height: 105) + .overlay( + HStack { + VStack { + let date = convertStringToDate(transaction.filingDate) + Text(getDateComponents(.month, date)) + .fontWeight(.semibold) + + Text(getDateComponents(.day, date)) + .font(.title) + .fontWeight(.semibold) + .foregroundColor(Color("default")) + + Text(getDateComponents(.year, date)) + .font(.caption) + .fontWeight(.semibold) + } + .padding(.trailing) + + VStack(alignment: .leading) { + Text(transaction.fullName.capitalized) + .lineLimit(1) + .font(.headline) + + Text(transaction.reportedTitle ?? "-") + } + + Spacer() + VStack(alignment: .trailing) { + Text("\(transaction.transactionShares)") + .foregroundColor(transaction.transactionShares < 0 ? Color(.systemRed): Color(.systemGreen)) + } + } + .padding() + ) + } +} + +struct TransactionRow_Previews: PreviewProvider { + static var previews: some View { + TransactionRow(transaction: + InsiderTransactionModel(filingDate: "2020-01-01", + fullName: "Dennis Concepcion", + postShares: 1234, + reportedTitle: "Director", + transactionCode: "S", + transactionPrice: 20.08, + transactionShares: 12345, + transactionValue: 1234567.0 + ) + ) + } +}
--- a/LazyBear/Views/Company/Insiders.swift Sun Jun 06 19:07:52 2021 +0200 +++ b/LazyBear/Views/Company/Insiders.swift Mon Jun 07 20:59:52 2021 +0200 @@ -13,24 +13,12 @@ var body: some View { if company.showInsidersView { - if let insiderSummer = company.insidersData.insiderRoster { - VStack(alignment: .leading) { - Text("Top 10 insiders") - .font(.title3) - .fontWeight(.semibold) + if let insiderSummary = company.insidersData.insiderRoster { + InsiderList(insiderSummary: insiderSummary, numberOfRows: 4) + } + + if let insiderTransactions = company.insidersData.insiderTransactions { - // Get total shares owned by the top 10 insiders - let totalPositions = insiderSummer.map { $0.position }.reduce(0, +) - VStack(alignment: .leading, spacing: 20) { - ForEach(insiderSummer.prefix(10), id: \.self) { insider in - - // Compute percentage of ownership for each insider - let percentage = Double(insider.position) / Double(totalPositions) - - InsiderRow(percentageOfWidth: CGFloat(percentage), insiderRoster: insider) - } - } - } } } else { ProgressView()
--- a/LazyBear/Views/Company/Networking/InsidersResponse.swift Sun Jun 06 19:07:52 2021 +0200 +++ b/LazyBear/Views/Company/Networking/InsidersResponse.swift Mon Jun 07 20:59:52 2021 +0200 @@ -9,8 +9,10 @@ struct InsidersResponse: Codable { var insiderRoster: [InsiderRosterModel]? + var insiderTransactions: [InsiderTransactionModel]? private enum CodingKeys: String, CodingKey { case insiderRoster = "insider_roster" + case insiderTransactions } }
--- a/LazyBear/Views/Home/Helpers/TradingDatesItem.swift Sun Jun 06 19:07:52 2021 +0200 +++ b/LazyBear/Views/Home/Helpers/TradingDatesItem.swift Mon Jun 07 20:59:52 2021 +0200 @@ -17,42 +17,20 @@ .frame(width: 100, height: 100) .overlay( VStack { - Text(get(.month)) + Text(getDateComponents(.month, date)) .fontWeight(.semibold) - Text(get(.day)) + Text(getDateComponents(.day, date)) .font(.title) .fontWeight(.semibold) .foregroundColor(Color("default")) - Text(get(.year)) + Text(getDateComponents(.year, date)) .font(.caption) .fontWeight(.semibold) } ) } - - private enum Components { - case day, month, year - } - - private func get(_ components: Components) -> String { - let dateComponents = Calendar.current.dateComponents([.year, .month, .day], from: date) - - switch components { - case .year: - return "\(dateComponents.year ?? 2020)" - case .day: - return "\(dateComponents.day ?? 1)" - case .month: - let dateFormatter = DateFormatter() - let monthNumber = dateComponents.month ?? 1 - let monthLetters = dateFormatter.shortMonthSymbols[monthNumber-1] - - return "\(monthLetters)" - } - - } } struct TradingDatesItem_Previews: PreviewProvider {
--- a/LazyBear/Views/Home/TradingDates.swift Sun Jun 06 19:07:52 2021 +0200 +++ b/LazyBear/Views/Home/TradingDates.swift Mon Jun 07 20:59:52 2021 +0200 @@ -10,7 +10,7 @@ struct TradingDates: View { var dates: [TradingDatesModel] - @Environment(\.presentationMode) var tradingDatesPresent + @Environment(\.presentationMode) private var presentationTradingDates let columns = [GridItem(.adaptive(minimum: 100))] @@ -28,7 +28,7 @@ .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { - Button(action: { tradingDatesPresent.wrappedValue.dismiss() }) { + Button(action: { presentationTradingDates.wrappedValue.dismiss() }) { Image(systemName: "multiply") .imageScale(.large) }