Skip to content

Commit

Permalink
Merge pull request #543 from pennlabs/subletting-bug-fixes
Browse files Browse the repository at this point in the history
Subletting bug fixes
  • Loading branch information
JHawk0224 authored Apr 22, 2024
2 parents 6a61b60 + 47ee30e commit 39c6182
Show file tree
Hide file tree
Showing 14 changed files with 216 additions and 46 deletions.
14 changes: 14 additions & 0 deletions PennMobile.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@
426A0B52299034910066C7B7 /* DiningAnalyticsGraphBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 426A0B50299034910066C7B7 /* DiningAnalyticsGraphBox.swift */; };
426FE6182B7023370096B79B /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 426FE6172B7023370096B79B /* SearchBar.swift */; };
42712AB32B94CEB00070C2EC /* SubletMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42712AB22B94CEB00070C2EC /* SubletMapView.swift */; };
4273BCFF2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */; };
4273BD002BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */; };
4273BD012BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */; };
4273BD022BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */; };
429EA1E02B8B96B200824455 /* SubletCandidatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429EA1DF2B8B96B200824455 /* SubletCandidatesView.swift */; };
429EA1E12B8BA18300824455 /* SublettingAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8910678A2B64715E00748FC6 /* SublettingAPI.swift */; };
42CC49D02AAE38C6008C41EE /* PollsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42CC49CF2AAE38C6008C41EE /* PollsViewController.swift */; };
Expand Down Expand Up @@ -246,6 +250,7 @@
890DDBC62AA2E4B6006815A3 /* ViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890DDBC42AA2E499006815A3 /* ViewExtensions.swift */; };
8910678B2B64715E00748FC6 /* SublettingModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891067892B64715E00748FC6 /* SublettingModels.swift */; };
891591ED2BA778AE00BC230F /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891591EC2BA778AE00BC230F /* SafariView.swift */; };
892D597A2BD31F50002EEDCF /* BetaBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892D59792BD31F50002EEDCF /* BetaBadge.swift */; };
89325390290F98E7006EE62C /* ConfigurationRepresenting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8932538E290F98BD006EE62C /* ConfigurationRepresenting.swift */; };
89325393291025A8006EE62C /* WidgetBackgroundTypeExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893253912910249B006EE62C /* WidgetBackgroundTypeExtensions.swift */; };
8932693528FC75A5003D4BF9 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8932693428FC75A5003D4BF9 /* WidgetKit.framework */; };
Expand Down Expand Up @@ -563,6 +568,7 @@
426A0B50299034910066C7B7 /* DiningAnalyticsGraphBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiningAnalyticsGraphBox.swift; sourceTree = "<group>"; };
426FE6172B7023370096B79B /* SearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = "<group>"; };
42712AB22B94CEB00070C2EC /* SubletMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubletMapView.swift; sourceTree = "<group>"; };
4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = SOURCE_ROOT; };
429EA1DF2B8B96B200824455 /* SubletCandidatesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubletCandidatesView.swift; sourceTree = "<group>"; };
42CC49CF2AAE38C6008C41EE /* PollsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollsViewController.swift; sourceTree = "<group>"; };
42CC49D12AAE3904008C41EE /* PollsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollsView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -686,6 +692,7 @@
891067892B64715E00748FC6 /* SublettingModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SublettingModels.swift; sourceTree = "<group>"; };
8910678A2B64715E00748FC6 /* SublettingAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SublettingAPI.swift; sourceTree = "<group>"; };
891591EC2BA778AE00BC230F /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = "<group>"; };
892D59792BD31F50002EEDCF /* BetaBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BetaBadge.swift; sourceTree = "<group>"; };
8932538E290F98BD006EE62C /* ConfigurationRepresenting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationRepresenting.swift; sourceTree = "<group>"; };
893253912910249B006EE62C /* WidgetBackgroundTypeExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetBackgroundTypeExtensions.swift; sourceTree = "<group>"; };
8932693328FC75A5003D4BF9 /* WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -993,6 +1000,7 @@
isa = PBXGroup;
children = (
89EA262C290F2667008F26CF /* WidgetExtension.entitlements */,
4273BCFE2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy */,
6C392E3727B5BDF20097640B /* Config */,
B6B1E089214442A200CCBBCD /* fastlane */,
F230FB0F225809E900760499 /* AutomatedScreenshotUITests */,
Expand Down Expand Up @@ -1497,6 +1505,7 @@
6C84D9E426293E680039C57F /* UIKit Views.swift */,
E7DA7CDC2B64619E00CA2A60 /* CustomPopupView.swift */,
891591EC2BA778AE00BC230F /* SafariView.swift */,
892D59792BD31F50002EEDCF /* BetaBadge.swift */,
);
path = "SwiftUI Views";
sourceTree = "<group>";
Expand Down Expand Up @@ -2346,6 +2355,7 @@
6CC88D7327B1BF51006896F6 /* mock_menu.json in Resources */,
6CC88D6D27B1BF51006896F6 /* sample-dining-venue.json in Resources */,
6C3F194227A32C29007BCB4F /* GoogleService-Info.plist in Resources */,
4273BCFF2BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */,
2190FD2F1EBBC8BA00EC683C /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -2354,13 +2364,15 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4273BD022BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
8932693128FC75A5003D4BF9 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4273BD012BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */,
8932694028FC75A6003D4BF9 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -2369,6 +2381,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4273BD002BD2D8D80070C1B8 /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2622,6 +2635,7 @@
212B8355222A31B500F835D6 /* HomePostCellItem.swift in Sources */,
97E79E062100DA1200D3D606 /* BuildingMapCell.swift in Sources */,
6CC88D7727B1BF51006896F6 /* DiningAnalyticsView.swift in Sources */,
892D597A2BD31F50002EEDCF /* BetaBadge.swift in Sources */,
F2770AEA2545E39D001EA1DD /* CourseAlertCreateController.swift in Sources */,
6CC88D7427B1BF51006896F6 /* DiningViewModelSwiftUI.swift in Sources */,
97E79E082100DA1200D3D606 /* BuildingHoursCell.swift in Sources */,
Expand Down
35 changes: 35 additions & 0 deletions PennMobile/General/SwiftUI Views/BetaBadge.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// BetaBadge.swift
// PennMobile
//
// Created by Anthony Li on 4/19/24.
// Copyright © 2024 PennLabs. All rights reserved.
//

import SwiftUI

struct BetaBadge: View {
var body: some View {
// There is a good reason for this trust me
// (It's so that the spacing matches the font size)
Text(" Beta ")
.fixedSize(horizontal: true, vertical: false)
.fontWeight(.medium)
.textCase(.uppercase)
.blendMode(.destinationOut)
.background(.foreground)
.clipShape(.capsule)
.compositingGroup()
.multilineTextAlignment(.leading)
}
}

#Preview {
HStack {
Text("Penn Mobile Sublet")
BetaBadge()
Text("is here!")
}
.font(.title3)
.padding()
}
5 changes: 4 additions & 1 deletion PennMobile/Home/HomeSublettingBanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ struct HomeSublettingBanner: View {
var onStart: () -> Void
var onDismiss: () -> Void

static let gradient = LinearGradient(colors: [Color("Subletting Gradient 1"), Color("Subletting Gradient 2")], startPoint: .topLeading, endPoint: .bottomTrailing)

var body: some View {
HomeCardView {
VStack {
Expand All @@ -24,6 +26,7 @@ struct HomeSublettingBanner: View {
} label: {
HStack {
Text("Get started")
BetaBadge()
Image(systemName: "arrow.forward")
}
.font(.title3)
Expand Down Expand Up @@ -67,7 +70,7 @@ struct HomeSublettingBanner: View {
}
.padding()
.multilineTextAlignment(.center)
.background(LinearGradient(colors: [Color("Subletting Gradient 1"), Color("Subletting Gradient 2")], startPoint: .topLeading, endPoint: .bottomTrailing))
.background(Self.gradient)
.environment(\.colorScheme, .dark)
}
}
Expand Down
12 changes: 8 additions & 4 deletions PennMobile/More Tab/MoreView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ private struct PennLink: View, Identifiable {
let title: LocalizedStringKey
let url: URL

init(title: LocalizedStringKey, url: URL) {
self.title = title
self.url = url
}

init(title: LocalizedStringKey, url: String) {
self.title = title
self.url = URL(string: url)!
Expand All @@ -26,9 +31,11 @@ private struct PennLink: View, Identifiable {
}
}

let feedbackURL = URL(string: "https://pennlabs.org/feedback/ios")!

private let pennLinks: [PennLink] = [
PennLink(title: "Penn Labs", url: "https://pennlabs.org"),
PennLink(title: "Share Your Feedback", url: "https://pennlabs.org/feedback/ios")]
PennLink(title: "Share Your Feedback", url: feedbackURL)]

struct MoreView: View {
var features: [AppFeature]
Expand Down Expand Up @@ -135,9 +142,6 @@ struct MoreView: View {
}
.navigationTitle(Text("More"))
.navigationBarTitleDisplayMode(.inline)
.navigationDestination(for: FeatureIdentifier.self) { id in
AnyView(features.first { $0.id == id }!.content)
}
.sheet(isPresented: $isPresentingLoginSheet) {
LabsLoginView { success in
if success {
Expand Down
2 changes: 1 addition & 1 deletion PennMobile/Setup + Navigation/Features.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ let features: [AppFeature] = [
.navigationTitle(Text("Fitness"))
},
AppFeature(.polls, shortName: "Polls", longName: "Polls History", color: .blueDark, image: .app("Polls_Grey"), controller: PollsViewController.self),
AppFeature(.subletting, name: "Subletting", color: .baseOrange, image: .system("building")) {
AppFeature(.subletting, shortName: "Subletting", longName: "Subletting (Beta)", color: .baseOrange, image: .system("building")) {
MarketplaceView()
.navigationTitle(Text("Marketplace"))
},
Expand Down
3 changes: 3 additions & 0 deletions PennMobile/Setup + Navigation/MainTabView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ struct MainTabView: View {

NavigationStack(path: $navigationManager.path) {
MoreView(features: features.filter { !tabBarFeatures.contains($0.id) })
.navigationDestination(for: FeatureIdentifier.self) { id in
AnyView(features.first { $0.id == id }!.content)
}
}
.environmentObject(navigationManager)
.tabItem {
Expand Down
2 changes: 1 addition & 1 deletion PennMobile/Subletting/Listings/NewListingForm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ struct NewListingForm: View {

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

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

PairFields {
Expand Down
88 changes: 77 additions & 11 deletions PennMobile/Subletting/MarketplaceView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,56 @@ enum SublettingPage: Hashable, Identifiable, Equatable, Codable {
}
}

struct SublettingTabHint: View {
@AppStorage("sublettingTabHintWasDismissed") var tabHintDismissed = false
@EnvironmentObject var navigationManager: NavigationManager

var body: some View {
if tabHintDismissed {
AnyView(SwiftUI.EmptyView())
} else {
AnyView(HStack {
Text("Want quick access to sublets?")
.fontWeight(.bold)

Spacer()

Button("Pin to tab bar") {
var currentTabFeatures = UserDefaults.standard.getTabPreferences()

tabHintDismissed = true

if !currentTabFeatures.contains(.subletting) {
currentTabFeatures[3] = .subletting
UserDefaults.standard.setTabPreferences(currentTabFeatures)
navigationManager.resetPath()
navigationManager.currentTab = FeatureIdentifier.subletting.rawValue
}
}
.buttonStyle(BorderedButtonStyle())
.buttonBorderShape(.capsule)

Button {
tabHintDismissed = true
} label: {
Label("Dismiss", systemImage: "xmark.circle.fill")
.labelStyle(.iconOnly)
}
}
.tint(.primary)
.padding()
.environment(\.colorScheme, .dark)
.background(HomeSublettingBanner.gradient)
.clipShape(.rect(cornerRadius: 16))
.onAppear {
if UserDefaults.standard.getTabPreferences().contains(.subletting) {
tabHintDismissed = true
}
})
}
}
}

struct MarketplaceView: View {
private var columns: [GridItem] = Array(repeating: .init(.flexible()), count: 2)
@StateObject private var sublettingViewModel = SublettingViewModel()
Expand Down Expand Up @@ -117,20 +167,35 @@ struct MarketplaceView: View {
}
.background(Color.uiBackground)
ScrollView {
if sublettingViewModel.sortedFilteredSublets.count > 0 {
LazyVGrid(columns: columns) {
ForEach(sublettingViewModel.sortedFilteredSublets) { sublet in
NavigationLink(value: SublettingPage.subletDetailView(sublet.subletID)) {
SubletDisplayBox(sublet: sublet)
VStack(spacing: 16) {
VStack {
Text("Penn Mobile Sublet is currently in beta. Have feedback? We're happy to hear it!")
.multilineTextAlignment(.center)
.foregroundStyle(.secondary)

Link("Share Feedback...", destination: feedbackURL)
.fontWeight(.medium)
}
.padding(.top, 4)
.font(.callout)

SublettingTabHint()

if sublettingViewModel.sortedFilteredSublets.count > 0 {
LazyVGrid(columns: columns) {
ForEach(sublettingViewModel.sortedFilteredSublets) { sublet in
NavigationLink(value: SublettingPage.subletDetailView(sublet.subletID)) {
SubletDisplayBox(sublet: sublet)
}
.buttonStyle(.plain)
.padding(5)
}
.buttonStyle(.plain)
.padding(5)
}
} else {
Text("No sublets found!")
.foregroundStyle(.tertiary)
.font(.subheadline)
}
} else {
Text("No sublets found!")
.foregroundStyle(.tertiary)
.font(.subheadline)
}
}
.refreshable {
Expand Down Expand Up @@ -174,6 +239,7 @@ struct MarketplaceView: View {
.environmentObject(sublettingViewModel)
}
}
.navigationBarTitleDisplayMode(.inline)
}
}

Expand Down
28 changes: 14 additions & 14 deletions PennMobile/Subletting/SubletCandidatesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,30 @@ import PennMobileShared

struct CandidateRow: View {
let offer: SubletOffer
@State var isMessageShowing = false

var body: some View {
VStack(alignment: .leading, spacing: 10) {
Text(offer.email)
.font(.headline)
Button(action: {
guard let url = URL(string: "mailto:\(offer.email)") else { return }
UIApplication.shared.open(url)
}) {
Text(offer.email)
.font(.headline)
}

HStack {
Image(systemName: "phone")
Text(offer.phoneNumber)
if offer.message != nil {
Button(action: {
withAnimation {
isMessageShowing.toggle()
}
}) {
Image(systemName: "ellipsis.message")
}
Button(action: {
guard let url = URL(string: "tel:\(offer.phoneNumber)") else { return }
UIApplication.shared.open(url)
}) {
Text(offer.phoneNumber)
}
}
.font(.subheadline)

if isMessageShowing {
Text("\"\(offer.message ?? "")\"")
if offer.message != nil && !offer.message!.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
Text("\"\(offer.message!)\"")
}

Text("Submitted \(formatDate(offer.createdDate))")
Expand Down
Loading

0 comments on commit 39c6182

Please sign in to comment.