Skip to content

Commit 2185b9c

Browse files
authored
Merge pull request #67 from TaskarCenterAtUW/feature-profileScreen
Feature profile screen
2 parents 00dd682 + 3280fd5 commit 2185b9c

File tree

8 files changed

+211
-12
lines changed

8 files changed

+211
-12
lines changed

GoInfoGame/GoInfoGame.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@
165165
A4E711AC2B58F7C000C9DE08 /* HandRailForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4E711AB2B58F7C000C9DE08 /* HandRailForm.swift */; };
166166
A4E711AE2B59004700C9DE08 /* StepsIncline.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4E711AD2B59004700C9DE08 /* StepsIncline.swift */; };
167167
A4E711B02B59011000C9DE08 /* StepsInclineForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4E711AF2B59011000C9DE08 /* StepsInclineForm.swift */; };
168+
B0CCB98C2B8626AE00AA73DE /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0CCB98B2B8626AE00AA73DE /* ProfileView.swift */; };
169+
B0CCB98E2B8626C600AA73DE /* ProfileViewVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0CCB98D2B8626C600AA73DE /* ProfileViewVM.swift */; };
168170
FA5853C12B21F17F00301CDA /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA5853C02B21F17F00301CDA /* OnboardingView.swift */; };
169171
FA87A8102B68142F000A6BEA /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA87A80F2B68142F000A6BEA /* LoadingView.swift */; };
170172
FA87A8132B6AC019000A6BEA /* StepsRampTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA87A8112B6AC019000A6BEA /* StepsRampTests.swift */; };
@@ -425,6 +427,8 @@
425427
A4E711AD2B59004700C9DE08 /* StepsIncline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepsIncline.swift; sourceTree = "<group>"; };
426428
A4E711AF2B59011000C9DE08 /* StepsInclineForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepsInclineForm.swift; sourceTree = "<group>"; };
427429
AE61EC473200AFDA81C2110A /* Pods-GoInfoGame-GoInfoGameUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GoInfoGame-GoInfoGameUITests.release.xcconfig"; path = "Target Support Files/Pods-GoInfoGame-GoInfoGameUITests/Pods-GoInfoGame-GoInfoGameUITests.release.xcconfig"; sourceTree = "<group>"; };
430+
B0CCB98B2B8626AE00AA73DE /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
431+
B0CCB98D2B8626C600AA73DE /* ProfileViewVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewVM.swift; sourceTree = "<group>"; };
428432
C96303080D26026265099E0E /* Pods-GoInfoGame.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GoInfoGame.release.xcconfig"; path = "Target Support Files/Pods-GoInfoGame/Pods-GoInfoGame.release.xcconfig"; sourceTree = "<group>"; };
429433
D76D8E22AC705A38AFEA78B1 /* Pods-GoInfoGame-GoInfoGameUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GoInfoGame-GoInfoGameUITests.debug.xcconfig"; path = "Target Support Files/Pods-GoInfoGame-GoInfoGameUITests/Pods-GoInfoGame-GoInfoGameUITests.debug.xcconfig"; sourceTree = "<group>"; };
430434
F008D431593E568E75C48C84 /* Pods-GoInfoGame.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GoInfoGame.debug.xcconfig"; path = "Target Support Files/Pods-GoInfoGame/Pods-GoInfoGame.debug.xcconfig"; sourceTree = "<group>"; };
@@ -585,6 +589,7 @@
585589
children = (
586590
FA87A80E2B681416000A6BEA /* Utils */,
587591
970D5BD02B62B61300C20BE7 /* MapViewController.swift */,
592+
B0CBEA902B88980A00C430F3 /* Profile */,
588593
971575152B5FFD5F0044797C /* Map */,
589594
973FC0152B4D562200878269 /* CustomComponents */,
590595
973FBFFF2B46CD4100878269 /* QuestsList */,
@@ -1077,6 +1082,15 @@
10771082
path = StepsIncline;
10781083
sourceTree = "<group>";
10791084
};
1085+
B0CBEA902B88980A00C430F3 /* Profile */ = {
1086+
isa = PBXGroup;
1087+
children = (
1088+
B0CCB98B2B8626AE00AA73DE /* ProfileView.swift */,
1089+
B0CCB98D2B8626C600AA73DE /* ProfileViewVM.swift */,
1090+
);
1091+
path = Profile;
1092+
sourceTree = "<group>";
1093+
};
10801094
FA5853BF2B21E3E000301CDA /* Onboarding */ = {
10811095
isa = PBXGroup;
10821096
children = (
@@ -1719,6 +1733,7 @@
17191733
973FC04C2B5A5F5F00878269 /* RadioItem.swift in Sources */,
17201734
A495DF2D2B6A190400478E44 /* CustomMapView.swift in Sources */,
17211735
05DBBB662B17209600B6F110 /* RealmOPMeta.swift in Sources */,
1736+
B0CCB98E2B8626C600AA73DE /* ProfileViewVM.swift in Sources */,
17221737
0536DD942B0BD59900B04C4B /* OAuthError.swift in Sources */,
17231738
973FC0172B4D567900878269 /* WidthView.swift in Sources */,
17241739
97AC1C082B6A45C9004F0BF4 /* SideWalkValidationForm.swift in Sources */,
@@ -1734,6 +1749,7 @@
17341749
A4E711AC2B58F7C000C9DE08 /* HandRailForm.swift in Sources */,
17351750
A4E711A62B57BBCA00C9DE08 /* QuestProtocols.swift in Sources */,
17361751
973FBFFE2B46BB3800878269 /* Utils.swift in Sources */,
1752+
B0CCB98C2B8626AE00AA73DE /* ProfileView.swift in Sources */,
17371753
FAF44FBD2B3084EC004FE664 /* OnboardingView1.swift in Sources */,
17381754
973FC01D2B4FEE1B00878269 /* YesNoView.swift in Sources */,
17391755
);

GoInfoGame/GoInfoGame/UI/MapViewController.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ class MapViewController: UIHostingController<MapView> {
1717

1818
let questListButton = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(questListButtonTapped))
1919
navigationItem.rightBarButtonItem = questListButton
20+
21+
let profileButton = UIBarButtonItem(image: UIImage(systemName: "person.crop.circle.fill"), style: .plain, target: self, action: #selector(profileButtonTapped))
22+
navigationItem.leftBarButtonItem = profileButton
2023
}
2124

2225
required init?(coder aDecoder: NSCoder) {
@@ -28,4 +31,10 @@ class MapViewController: UIHostingController<MapView> {
2831
let hostingController = UIHostingController(rootView: questListView)
2932
present(hostingController, animated: true, completion: nil)
3033
}
34+
35+
@objc func profileButtonTapped() {
36+
let profileView = ProfileView()
37+
let hostingController = UIHostingController(rootView: profileView)
38+
present(hostingController, animated: true, completion: nil)
39+
}
3140
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//
2+
// ProfileView.swift
3+
// GoInfoGame
4+
//
5+
// Created by Sudula Murali Krishna on 2/21/24.
6+
//
7+
8+
import Foundation
9+
import SwiftUI
10+
11+
struct ProfileView: View {
12+
@ObservedObject private var viewModel = ProfileViewVM()
13+
@Environment(\.dismiss) var dismiss
14+
@Environment(\.openURL) var openURL
15+
16+
var body: some View {
17+
return NavigationView {
18+
VStack {
19+
HStack {
20+
profileImage
21+
VStack (alignment: .leading,spacing: 0){
22+
Text(viewModel.user?.displayName ?? "")
23+
.font(.system(size: 20, weight: .semibold))
24+
HStack {
25+
Image(systemName: "star.fill")
26+
.resizable()
27+
.frame(width: 25, height: 25)
28+
Text("\(viewModel.user?.changesets.count ?? 0)")
29+
.font(.title)
30+
}
31+
}
32+
Spacer()
33+
}
34+
HStack {
35+
profileButton
36+
Spacer()
37+
logOutButton
38+
}
39+
Divider().padding()
40+
Spacer()
41+
}
42+
.padding(20)
43+
.navigationBarItems(leading: backButton)
44+
.navigationBarTitleDisplayMode(.inline)
45+
.navigationTitle("My Profile")
46+
}
47+
48+
}
49+
50+
@ViewBuilder
51+
private var profileImage: some View {
52+
if self.viewModel.imageUrl == nil {
53+
Image(systemName: "person.circle.fill")
54+
.resizable()
55+
.frame(width: 120, height: 120, alignment: .center)
56+
.cornerRadius(60)
57+
}else {
58+
AsyncImage(url: self.viewModel.imageUrl) { phase in
59+
if let image = phase.image {
60+
image.resizable()
61+
} else if phase.error != nil {
62+
Image(systemName: "person.circle.fill")
63+
.resizable()
64+
} else {
65+
ProgressView().progressViewStyle(.circular)
66+
}
67+
}
68+
.frame(width: 120, height: 120, alignment: .center)
69+
.cornerRadius(60)
70+
}
71+
}
72+
73+
private var profileButton: some View {
74+
Button {
75+
if let url = viewModel.profileUrl {
76+
openURL(url)
77+
}
78+
} label: {
79+
HStack {
80+
Image(systemName: "tray.and.arrow.up.fill")
81+
Text("OSM Profile")
82+
}
83+
.foregroundColor(.white)
84+
.font(.system(size: 16, weight: .semibold))
85+
.frame(width: 180, height: 50)
86+
.background(.black)
87+
.cornerRadius(5)
88+
}
89+
}
90+
91+
private var logOutButton: some View {
92+
Button {
93+
//LOGOUT
94+
} label: {
95+
Text("LOGOUT")
96+
.foregroundColor(.black)
97+
.font(.system(size: 16, weight: .semibold))
98+
.frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/, height: 50)
99+
.cornerRadius(15)
100+
.overlay {
101+
RoundedRectangle(cornerRadius: 5)
102+
.stroke(Color.black)
103+
}
104+
}
105+
}
106+
107+
private var backButton: some View {
108+
Button {
109+
dismiss()
110+
} label: {
111+
Image(systemName: "arrow.left")
112+
.font(.system(size: 24, weight: .semibold))
113+
.foregroundColor(.black)
114+
.cornerRadius(15)
115+
}
116+
}
117+
}
118+
119+
#Preview {
120+
ProfileView()
121+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// ProfileViewVM.swift
3+
// GoInfoGame
4+
//
5+
// Created by Sudula Murali Krishna on 2/21/24.
6+
//
7+
8+
import Foundation
9+
import osmapi
10+
11+
class ProfileViewVM: ObservableObject {
12+
@Published var user: OSMUserData?
13+
14+
init() {
15+
let posmConnection = OSMConnection(config: OSMConfig.testOSM,userCreds: OSMLogin.testOSM)
16+
posmConnection.getUserDetails() { [weak self]result in
17+
switch result {
18+
case .success(let userDataResponse):
19+
let user = userDataResponse.user
20+
print(userDataResponse)
21+
DispatchQueue.main.async {
22+
self?.user = user
23+
}
24+
case .failure(let error):
25+
print("---error", error)
26+
}
27+
}
28+
}
29+
30+
var profileUrl: URL? {
31+
if let userName = self.user?.displayName {
32+
return URL(string:OSMConfig.url.appending("user/").appending(userName))
33+
}
34+
return nil
35+
}
36+
37+
var imageUrl: URL? {
38+
if let imageString = self.user?.profileImage?.href {
39+
return URL(string: imageString)
40+
}
41+
return nil
42+
}
43+
}

GoInfoGame/GoInfoGame/quests/CrossingType/CrossingTypeForm.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ struct CrossingTypeForm: View, QuestForm {
2424
var body: some View {
2525
ZStack{
2626
VStack{
27-
QuestionHeader(icon:Image("kerb_tactile_paving"), title: LocalizedStrings.questCrossingTypeTitle.localized, subtitle: "Crossing")
27+
QuestionHeader(icon:Image("pedestrian_crossing"), title: LocalizedStrings.questCrossingTypeTitle.localized, subtitle: "Crossing")
2828
VStack(alignment:.center){
2929
VStack (alignment: .leading){
3030
Text(LocalizedStrings.selectOne.localized).font(.caption).foregroundColor(.gray)

GoInfoGame/osmapi/OSMConfig.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import Foundation
99
public struct OSMConfig {
10-
let baseUrl: String
10+
public let baseUrl: String
1111
//https://waylyticsposm.westus2.cloudapp.azure.com/api/0.6/
1212
// For testing data upload
1313

@@ -21,6 +21,10 @@ public struct OSMConfig {
2121
}
2222

2323
public static var testOSM : OSMConfig {
24-
OSMConfig(baseUrl: "https://master.apis.dev.openstreetmap.org/api/0.6/")
24+
OSMConfig(baseUrl: "\(url)api/0.6/")
25+
}
26+
27+
public static var url: String {
28+
"https://master.apis.dev.openstreetmap.org/"
2529
}
2630
}

GoInfoGame/osmapi/OSMConnection.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public class OSMConnection {
156156
}
157157
BaseNetworkManager.shared.fetchData(url: url, completion: completion)
158158
}
159-
func getUserDetails(_ completion: @escaping (Result<OSMUserDataResponse, Error>)-> Void) {
159+
public func getUserDetails(_ completion: @escaping (Result<OSMUserDataResponse, Error>)-> Void) {
160160
let urlString = self.baseUrl.appending("user/details.json")
161161
guard let url = URL(string: urlString) else {
162162
print("Invalid URL given")

GoInfoGame/osmapi/models/OSMUserData.swift

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,23 @@
77
import Foundation
88

99
// MARK: - OSMUserData
10-
struct OSMUserDataResponse: Codable {
10+
public struct OSMUserDataResponse: Codable {
1111
let version, generator, copyright: String
1212
let attribution, license: String
13-
let user: OSMUserData
13+
public let user: OSMUserData
1414
}
1515

1616
// MARK: - User
17-
struct OSMUserData: Codable {
18-
let id: Int
19-
let displayName: String
17+
public struct OSMUserData: Codable {
18+
public let id: Int
19+
public let displayName: String
2020
let accountCreated: Date
2121
let description: String
2222
let contributorTerms: ContributorTerms
2323
let roles: [String]
24-
let changesets, traces: Changesets
24+
public let changesets, traces: Changesets
2525
let blocks: Blocks
26+
public let profileImage: profileImage?
2627

2728
enum CodingKeys: String, CodingKey {
2829
case id
@@ -31,6 +32,7 @@ struct OSMUserData: Codable {
3132
case description
3233
case contributorTerms = "contributor_terms"
3334
case roles, changesets, traces, blocks
35+
case profileImage = "img"
3436
}
3537
}
3638

@@ -45,11 +47,15 @@ struct Received: Codable {
4547
}
4648

4749
// MARK: - Changesets
48-
struct Changesets: Codable {
49-
let count: Int
50+
public struct Changesets: Codable {
51+
public let count: Int
5052
}
5153

5254
// MARK: - ContributorTerms
5355
struct ContributorTerms: Codable {
5456
let agreed: Bool
5557
}
58+
59+
public struct profileImage: Codable {
60+
public let href: String
61+
}

0 commit comments

Comments
 (0)