Skip to content

Commit 39c6182

Browse files
authored
Merge pull request #543 from pennlabs/subletting-bug-fixes
Subletting bug fixes
2 parents 6a61b60 + 47ee30e commit 39c6182

14 files changed

Lines changed: 216 additions & 46 deletions

File tree

PennMobile.xcodeproj/project.pbxproj

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@
116116
426A0B52299034910066C7B7 /* DiningAnalyticsGraphBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 426A0B50299034910066C7B7 /* DiningAnalyticsGraphBox.swift */; };
117117
426FE6182B7023370096B79B /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 426FE6172B7023370096B79B /* SearchBar.swift */; };
118118
42712AB32B94CEB00070C2EC /* SubletMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42712AB22B94CEB00070C2EC /* SubletMapView.swift */; };
119+
4273BCFF2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */; };
120+
4273BD002BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */; };
121+
4273BD012BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */; };
122+
4273BD022BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */; };
119123
429EA1E02B8B96B200824455 /* SubletCandidatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429EA1DF2B8B96B200824455 /* SubletCandidatesView.swift */; };
120124
429EA1E12B8BA18300824455 /* SublettingAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8910678A2B64715E00748FC6 /* SublettingAPI.swift */; };
121125
42CC49D02AAE38C6008C41EE /* PollsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42CC49CF2AAE38C6008C41EE /* PollsViewController.swift */; };
@@ -246,6 +250,7 @@
246250
890DDBC62AA2E4B6006815A3 /* ViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890DDBC42AA2E499006815A3 /* ViewExtensions.swift */; };
247251
8910678B2B64715E00748FC6 /* SublettingModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891067892B64715E00748FC6 /* SublettingModels.swift */; };
248252
891591ED2BA778AE00BC230F /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891591EC2BA778AE00BC230F /* SafariView.swift */; };
253+
892D597A2BD31F50002EEDCF /* BetaBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892D59792BD31F50002EEDCF /* BetaBadge.swift */; };
249254
89325390290F98E7006EE62C /* ConfigurationRepresenting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8932538E290F98BD006EE62C /* ConfigurationRepresenting.swift */; };
250255
89325393291025A8006EE62C /* WidgetBackgroundTypeExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893253912910249B006EE62C /* WidgetBackgroundTypeExtensions.swift */; };
251256
8932693528FC75A5003D4BF9 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8932693428FC75A5003D4BF9 /* WidgetKit.framework */; };
@@ -563,6 +568,7 @@
563568
426A0B50299034910066C7B7 /* DiningAnalyticsGraphBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiningAnalyticsGraphBox.swift; sourceTree = "<group>"; };
564569
426FE6172B7023370096B79B /* SearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = "<group>"; };
565570
42712AB22B94CEB00070C2EC /* SubletMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubletMapView.swift; sourceTree = "<group>"; };
571+
4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = SOURCE_ROOT; };
566572
429EA1DF2B8B96B200824455 /* SubletCandidatesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubletCandidatesView.swift; sourceTree = "<group>"; };
567573
42CC49CF2AAE38C6008C41EE /* PollsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollsViewController.swift; sourceTree = "<group>"; };
568574
42CC49D12AAE3904008C41EE /* PollsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollsView.swift; sourceTree = "<group>"; };
@@ -686,6 +692,7 @@
686692
891067892B64715E00748FC6 /* SublettingModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SublettingModels.swift; sourceTree = "<group>"; };
687693
8910678A2B64715E00748FC6 /* SublettingAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SublettingAPI.swift; sourceTree = "<group>"; };
688694
891591EC2BA778AE00BC230F /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = "<group>"; };
695+
892D59792BD31F50002EEDCF /* BetaBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetaBadge.swift; sourceTree = "<group>"; };
689696
8932538E290F98BD006EE62C /* ConfigurationRepresenting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationRepresenting.swift; sourceTree = "<group>"; };
690697
893253912910249B006EE62C /* WidgetBackgroundTypeExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetBackgroundTypeExtensions.swift; sourceTree = "<group>"; };
691698
8932693328FC75A5003D4BF9 /* WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -993,6 +1000,7 @@
9931000
isa = PBXGroup;
9941001
children = (
9951002
89EA262C290F2667008F26CF /* WidgetExtension.entitlements */,
1003+
4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */,
9961004
6C392E3727B5BDF20097640B /* Config */,
9971005
B6B1E089214442A200CCBBCD /* fastlane */,
9981006
F230FB0F225809E900760499 /* AutomatedScreenshotUITests */,
@@ -1497,6 +1505,7 @@
14971505
6C84D9E426293E680039C57F /* UIKit Views.swift */,
14981506
E7DA7CDC2B64619E00CA2A60 /* CustomPopupView.swift */,
14991507
891591EC2BA778AE00BC230F /* SafariView.swift */,
1508+
892D59792BD31F50002EEDCF /* BetaBadge.swift */,
15001509
);
15011510
path = "SwiftUI Views";
15021511
sourceTree = "<group>";
@@ -2346,6 +2355,7 @@
23462355
6CC88D7327B1BF51006896F6 /* mock_menu.json in Resources */,
23472356
6CC88D6D27B1BF51006896F6 /* sample-dining-venue.json in Resources */,
23482357
6C3F194227A32C29007BCB4F /* GoogleService-Info.plist in Resources */,
2358+
4273BCFF2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */,
23492359
2190FD2F1EBBC8BA00EC683C /* Assets.xcassets in Resources */,
23502360
);
23512361
runOnlyForDeploymentPostprocessing = 0;
@@ -2354,13 +2364,15 @@
23542364
isa = PBXResourcesBuildPhase;
23552365
buildActionMask = 2147483647;
23562366
files = (
2367+
4273BD022BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */,
23572368
);
23582369
runOnlyForDeploymentPostprocessing = 0;
23592370
};
23602371
8932693128FC75A5003D4BF9 /* Resources */ = {
23612372
isa = PBXResourcesBuildPhase;
23622373
buildActionMask = 2147483647;
23632374
files = (
2375+
4273BD012BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */,
23642376
8932694028FC75A6003D4BF9 /* Assets.xcassets in Resources */,
23652377
);
23662378
runOnlyForDeploymentPostprocessing = 0;
@@ -2369,6 +2381,7 @@
23692381
isa = PBXResourcesBuildPhase;
23702382
buildActionMask = 2147483647;
23712383
files = (
2384+
4273BD002BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */,
23722385
);
23732386
runOnlyForDeploymentPostprocessing = 0;
23742387
};
@@ -2622,6 +2635,7 @@
26222635
212B8355222A31B500F835D6 /* HomePostCellItem.swift in Sources */,
26232636
97E79E062100DA1200D3D606 /* BuildingMapCell.swift in Sources */,
26242637
6CC88D7727B1BF51006896F6 /* DiningAnalyticsView.swift in Sources */,
2638+
892D597A2BD31F50002EEDCF /* BetaBadge.swift in Sources */,
26252639
F2770AEA2545E39D001EA1DD /* CourseAlertCreateController.swift in Sources */,
26262640
6CC88D7427B1BF51006896F6 /* DiningViewModelSwiftUI.swift in Sources */,
26272641
97E79E082100DA1200D3D606 /* BuildingHoursCell.swift in Sources */,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//
2+
// BetaBadge.swift
3+
// PennMobile
4+
//
5+
// Created by Anthony Li on 4/19/24.
6+
// Copyright © 2024 PennLabs. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
11+
struct BetaBadge: View {
12+
var body: some View {
13+
// There is a good reason for this trust me
14+
// (It's so that the spacing matches the font size)
15+
Text(" Beta ")
16+
.fixedSize(horizontal: true, vertical: false)
17+
.fontWeight(.medium)
18+
.textCase(.uppercase)
19+
.blendMode(.destinationOut)
20+
.background(.foreground)
21+
.clipShape(.capsule)
22+
.compositingGroup()
23+
.multilineTextAlignment(.leading)
24+
}
25+
}
26+
27+
#Preview {
28+
HStack {
29+
Text("Penn Mobile Sublet")
30+
BetaBadge()
31+
Text("is here!")
32+
}
33+
.font(.title3)
34+
.padding()
35+
}

PennMobile/Home/HomeSublettingBanner.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ struct HomeSublettingBanner: View {
1212
var onStart: () -> Void
1313
var onDismiss: () -> Void
1414

15+
static let gradient = LinearGradient(colors: [Color("Subletting Gradient 1"), Color("Subletting Gradient 2")], startPoint: .topLeading, endPoint: .bottomTrailing)
16+
1517
var body: some View {
1618
HomeCardView {
1719
VStack {
@@ -24,6 +26,7 @@ struct HomeSublettingBanner: View {
2426
} label: {
2527
HStack {
2628
Text("Get started")
29+
BetaBadge()
2730
Image(systemName: "arrow.forward")
2831
}
2932
.font(.title3)
@@ -67,7 +70,7 @@ struct HomeSublettingBanner: View {
6770
}
6871
.padding()
6972
.multilineTextAlignment(.center)
70-
.background(LinearGradient(colors: [Color("Subletting Gradient 1"), Color("Subletting Gradient 2")], startPoint: .topLeading, endPoint: .bottomTrailing))
73+
.background(Self.gradient)
7174
.environment(\.colorScheme, .dark)
7275
}
7376
}

PennMobile/More Tab/MoreView.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ private struct PennLink: View, Identifiable {
1212
let title: LocalizedStringKey
1313
let url: URL
1414

15+
init(title: LocalizedStringKey, url: URL) {
16+
self.title = title
17+
self.url = url
18+
}
19+
1520
init(title: LocalizedStringKey, url: String) {
1621
self.title = title
1722
self.url = URL(string: url)!
@@ -26,9 +31,11 @@ private struct PennLink: View, Identifiable {
2631
}
2732
}
2833

34+
let feedbackURL = URL(string: "https://pennlabs.org/feedback/ios")!
35+
2936
private let pennLinks: [PennLink] = [
3037
PennLink(title: "Penn Labs", url: "https://pennlabs.org"),
31-
PennLink(title: "Share Your Feedback", url: "https://pennlabs.org/feedback/ios")]
38+
PennLink(title: "Share Your Feedback", url: feedbackURL)]
3239

3340
struct MoreView: View {
3441
var features: [AppFeature]
@@ -135,9 +142,6 @@ struct MoreView: View {
135142
}
136143
.navigationTitle(Text("More"))
137144
.navigationBarTitleDisplayMode(.inline)
138-
.navigationDestination(for: FeatureIdentifier.self) { id in
139-
AnyView(features.first { $0.id == id }!.content)
140-
}
141145
.sheet(isPresented: $isPresentingLoginSheet) {
142146
LabsLoginView { success in
143147
if success {

PennMobile/Setup + Navigation/Features.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ let features: [AppFeature] = [
111111
.navigationTitle(Text("Fitness"))
112112
},
113113
AppFeature(.polls, shortName: "Polls", longName: "Polls History", color: .blueDark, image: .app("Polls_Grey"), controller: PollsViewController.self),
114-
AppFeature(.subletting, name: "Subletting", color: .baseOrange, image: .system("building")) {
114+
AppFeature(.subletting, shortName: "Subletting", longName: "Subletting (Beta)", color: .baseOrange, image: .system("building")) {
115115
MarketplaceView()
116116
.navigationTitle(Text("Marketplace"))
117117
},

PennMobile/Setup + Navigation/MainTabView.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ struct MainTabView: View {
5252

5353
NavigationStack(path: $navigationManager.path) {
5454
MoreView(features: features.filter { !tabBarFeatures.contains($0.id) })
55+
.navigationDestination(for: FeatureIdentifier.self) { id in
56+
AnyView(features.first { $0.id == id }!.content)
57+
}
5558
}
5659
.environmentObject(navigationManager)
5760
.tabItem {

PennMobile/Subletting/Listings/NewListingForm.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ struct NewListingForm: View {
100100

101101
TextLineField($subletData.address, placeholder: "Street address", title: "Location")
102102

103-
DateRangeField(lowerDate: $startDate, upperDate: $endDate, title: "Start & End Date")
103+
DateRangeField(lowerDate: $startDate, upperDate: $endDate, in: .now...Date.distantFuture, title: "Start & End Date")
104104
.validator(.required)
105105

106106
PairFields {

PennMobile/Subletting/MarketplaceView.swift

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,56 @@ enum SublettingPage: Hashable, Identifiable, Equatable, Codable {
7272
}
7373
}
7474

75+
struct SublettingTabHint: View {
76+
@AppStorage("sublettingTabHintWasDismissed") var tabHintDismissed = false
77+
@EnvironmentObject var navigationManager: NavigationManager
78+
79+
var body: some View {
80+
if tabHintDismissed {
81+
AnyView(SwiftUI.EmptyView())
82+
} else {
83+
AnyView(HStack {
84+
Text("Want quick access to sublets?")
85+
.fontWeight(.bold)
86+
87+
Spacer()
88+
89+
Button("Pin to tab bar") {
90+
var currentTabFeatures = UserDefaults.standard.getTabPreferences()
91+
92+
tabHintDismissed = true
93+
94+
if !currentTabFeatures.contains(.subletting) {
95+
currentTabFeatures[3] = .subletting
96+
UserDefaults.standard.setTabPreferences(currentTabFeatures)
97+
navigationManager.resetPath()
98+
navigationManager.currentTab = FeatureIdentifier.subletting.rawValue
99+
}
100+
}
101+
.buttonStyle(BorderedButtonStyle())
102+
.buttonBorderShape(.capsule)
103+
104+
Button {
105+
tabHintDismissed = true
106+
} label: {
107+
Label("Dismiss", systemImage: "xmark.circle.fill")
108+
.labelStyle(.iconOnly)
109+
}
110+
}
111+
.tint(.primary)
112+
.padding()
113+
.environment(\.colorScheme, .dark)
114+
.background(HomeSublettingBanner.gradient)
115+
.clipShape(.rect(cornerRadius: 16))
116+
.onAppear {
117+
if UserDefaults.standard.getTabPreferences().contains(.subletting) {
118+
tabHintDismissed = true
119+
}
120+
})
121+
}
122+
}
123+
}
124+
75125
struct MarketplaceView: View {
76126
private var columns: [GridItem] = Array(repeating: .init(.flexible()), count: 2)
77127
@StateObject private var sublettingViewModel = SublettingViewModel()
@@ -117,20 +167,35 @@ struct MarketplaceView: View {
117167
}
118168
.background(Color.uiBackground)
119169
ScrollView {
120-
if sublettingViewModel.sortedFilteredSublets.count > 0 {
121-
LazyVGrid(columns: columns) {
122-
ForEach(sublettingViewModel.sortedFilteredSublets) { sublet in
123-
NavigationLink(value: SublettingPage.subletDetailView(sublet.subletID)) {
124-
SubletDisplayBox(sublet: sublet)
170+
VStack(spacing: 16) {
171+
VStack {
172+
Text("Penn Mobile Sublet is currently in beta. Have feedback? We're happy to hear it!")
173+
.multilineTextAlignment(.center)
174+
.foregroundStyle(.secondary)
175+
176+
Link("Share Feedback...", destination: feedbackURL)
177+
.fontWeight(.medium)
178+
}
179+
.padding(.top, 4)
180+
.font(.callout)
181+
182+
SublettingTabHint()
183+
184+
if sublettingViewModel.sortedFilteredSublets.count > 0 {
185+
LazyVGrid(columns: columns) {
186+
ForEach(sublettingViewModel.sortedFilteredSublets) { sublet in
187+
NavigationLink(value: SublettingPage.subletDetailView(sublet.subletID)) {
188+
SubletDisplayBox(sublet: sublet)
189+
}
190+
.buttonStyle(.plain)
191+
.padding(5)
125192
}
126-
.buttonStyle(.plain)
127-
.padding(5)
128193
}
194+
} else {
195+
Text("No sublets found!")
196+
.foregroundStyle(.tertiary)
197+
.font(.subheadline)
129198
}
130-
} else {
131-
Text("No sublets found!")
132-
.foregroundStyle(.tertiary)
133-
.font(.subheadline)
134199
}
135200
}
136201
.refreshable {
@@ -174,6 +239,7 @@ struct MarketplaceView: View {
174239
.environmentObject(sublettingViewModel)
175240
}
176241
}
242+
.navigationBarTitleDisplayMode(.inline)
177243
}
178244
}
179245

PennMobile/Subletting/SubletCandidatesView.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,30 @@ import PennMobileShared
1111

1212
struct CandidateRow: View {
1313
let offer: SubletOffer
14-
@State var isMessageShowing = false
1514

1615
var body: some View {
1716
VStack(alignment: .leading, spacing: 10) {
18-
Text(offer.email)
19-
.font(.headline)
17+
Button(action: {
18+
guard let url = URL(string: "mailto:\(offer.email)") else { return }
19+
UIApplication.shared.open(url)
20+
}) {
21+
Text(offer.email)
22+
.font(.headline)
23+
}
2024

2125
HStack {
2226
Image(systemName: "phone")
23-
Text(offer.phoneNumber)
24-
if offer.message != nil {
25-
Button(action: {
26-
withAnimation {
27-
isMessageShowing.toggle()
28-
}
29-
}) {
30-
Image(systemName: "ellipsis.message")
31-
}
27+
Button(action: {
28+
guard let url = URL(string: "tel:\(offer.phoneNumber)") else { return }
29+
UIApplication.shared.open(url)
30+
}) {
31+
Text(offer.phoneNumber)
3232
}
3333
}
3434
.font(.subheadline)
3535

36-
if isMessageShowing {
37-
Text("\"\(offer.message ?? "")\"")
36+
if offer.message != nil && !offer.message!.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
37+
Text("\"\(offer.message!)\"")
3838
}
3939

4040
Text("Submitted \(formatDate(offer.createdDate))")

0 commit comments

Comments
 (0)