Skip to content

Commit

Permalink
Merge branch 'main' into release-prep-1.6.0
Browse files Browse the repository at this point in the history
  • Loading branch information
EvanCooper9 authored May 20, 2022
2 parents 6e9a065 + db48f85 commit b3fd242
Show file tree
Hide file tree
Showing 14 changed files with 112 additions and 51 deletions.
20 changes: 18 additions & 2 deletions Friendly Competitions.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@
ED927EF827F7ACE0006E78A0 /* FirebaseAnalyticsSwift-Beta in Frameworks */ = {isa = PBXBuildFile; productRef = ED927EF727F7ACE0006E78A0 /* FirebaseAnalyticsSwift-Beta */; };
EDA352902836EFB600390585 /* UserViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA3528F2836EFB600390585 /* UserViewAction.swift */; };
EDA352932836F87600390585 /* CompetitionViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA352922836F87600390585 /* CompetitionViewAction.swift */; };
EDA3529528370F4C00390585 /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA3529428370F4C00390585 /* HomeViewModel.swift */; };
EDA35298283713C200390585 /* DeepLink+Share.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA35297283713C200390585 /* DeepLink+Share.swift */; };
EDBEA170281459D200058A47 /* CompetitionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDBEA16F281459D200058A47 /* CompetitionInfo.swift */; };
EDBF8C5F282D4B3500754165 /* SwiftUIX in Frameworks */ = {isa = PBXBuildFile; productRef = EDBF8C5E282D4B3500754165 /* SwiftUIX */; };
EDC373D027FB39A500318245 /* EmailSignInForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC373CF27FB39A500318245 /* EmailSignInForm.swift */; };
Expand Down Expand Up @@ -325,6 +327,8 @@
ED901B75280265DB00FE619E /* SignInViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInViewModel.swift; sourceTree = "<group>"; };
EDA3528F2836EFB600390585 /* UserViewAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserViewAction.swift; sourceTree = "<group>"; };
EDA352922836F87600390585 /* CompetitionViewAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompetitionViewAction.swift; sourceTree = "<group>"; };
EDA3529428370F4C00390585 /* HomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = "<group>"; };
EDA35297283713C200390585 /* DeepLink+Share.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DeepLink+Share.swift"; sourceTree = "<group>"; };
EDBEA16F281459D200058A47 /* CompetitionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompetitionInfo.swift; sourceTree = "<group>"; };
EDBF8C60282D4B9E00754165 /* SwiftUIX */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = SwiftUIX; path = ../SwiftUIX; sourceTree = "<group>"; };
EDC373CF27FB39A500318245 /* EmailSignInForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailSignInForm.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -683,7 +687,7 @@
isa = PBXGroup;
children = (
C1185A2426D6717C002E2377 /* ActivitySummary.swift */,
C114314127B9B6ED00915757 /* DeepLink.swift */,
EDA35296283713B200390585 /* Deep Link */,
C12D640527A5EDDF00259237 /* Competition */,
C12D63FE27A5E93600259237 /* Permission */,
C16CC40727A73E6200C26208 /* User */,
Expand Down Expand Up @@ -740,7 +744,6 @@
C1884E4726D5894000C21014 /* Dashboard.swift */,
ED901B442802426800FE619E /* DashboardViewModel.swift */,
C123C9DC27A8AF4700375F73 /* About */,
ED48782C282747B100AC1E2C /* Invite Friends */,
C12D63F927A5B5CE00259237 /* Profile */,
EDA352912836F5EA00390585 /* User */,
);
Expand All @@ -761,9 +764,11 @@
isa = PBXGroup;
children = (
C19B7F2727BD8A5E00BCA4B9 /* Home.swift */,
EDA3529428370F4C00390585 /* HomeViewModel.swift */,
C19B7F2E27BEA69200BCA4B9 /* Dashboard */,
C19B7F2927BD8C5C00BCA4B9 /* Explore */,
C1F7DFF226D7F77900B46F91 /* Competitions */,
ED48782C282747B100AC1E2C /* Invite Friends */,
C10E5544272B44B30053BBA6 /* Permissions */,
C12D640227A5EA8700259237 /* Sign In */,
C132335D27BEA96600196D81 /* Styles */,
Expand Down Expand Up @@ -914,6 +919,15 @@
path = User;
sourceTree = "<group>";
};
EDA35296283713B200390585 /* Deep Link */ = {
isa = PBXGroup;
children = (
C114314127B9B6ED00915757 /* DeepLink.swift */,
EDA35297283713C200390585 /* DeepLink+Share.swift */,
);
path = "Deep Link";
sourceTree = "<group>";
};
EDBEA16E281459C000058A47 /* Components */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1136,6 +1150,7 @@
ED901B6B2802525700FE619E /* FirestoreImageViewModel.swift in Sources */,
EDC373D227FB5B0C00318245 /* VerifyEmail.swift in Sources */,
C1ABB21526D6987C00716984 /* NewCompetition.swift in Sources */,
EDA35298283713C200390585 /* DeepLink+Share.swift in Sources */,
C1930E5427C6EB4000DB45C1 /* MockFriendsManager.swift in Sources */,
C13F923327C0099800FC6880 /* MockCompetitionManager.swift in Sources */,
C155CA7627AC1A63005F49F4 /* Competition+Standing.swift in Sources */,
Expand Down Expand Up @@ -1186,6 +1201,7 @@
C19EAFE3272B30E0008BCFDD /* PermissionsView.swift in Sources */,
EDC5FC4127FA7F3700F2882D /* Color+Extensions.swift in Sources */,
ED901B6328024F0400FE619E /* UserDefaults+Extensions.swift in Sources */,
EDA3529528370F4C00390585 /* HomeViewModel.swift in Sources */,
C10E5543272B3BCF0053BBA6 /* PermissionView.swift in Sources */,
ED901B712802618700FE619E /* NewCompetitionViewModel.swift in Sources */,
C1185A2526D6717C002E2377 /* ActivitySummary.swift in Sources */,
Expand Down
1 change: 0 additions & 1 deletion Friendly Competitions/AppState.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Combine

final class AppState: ObservableObject {
@Published var deepLink: DeepLink? = nil
@Published var hudState: HUDState?
}
7 changes: 7 additions & 0 deletions Friendly Competitions/Managers/CompetitionsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class AnyCompetitionsManager: ObservableObject {
func leave(_ competition: Competition) {}
func update(_ competition: Competition) {}
func search(_ searchText: String) async throws -> [Competition] { [] }
func search(byID competitionID: Competition.ID) async throws -> Competition { fatalError("Must be implemented by subclass") }
func updateStandings() async throws {}
}

Expand Down Expand Up @@ -178,6 +179,12 @@ final class CompetitionsManager: AnyCompetitionsManager {
}
.decoded(asArrayOf: Competition.self)
}

override func search(byID competitionID: Competition.ID) async throws -> Competition {
try await database.document("competitions/\(competitionID)")
.getDocument()
.decoded(as: Competition.self)
}

override func updateStandings() async throws {
try await functions
Expand Down
23 changes: 23 additions & 0 deletions Friendly Competitions/Models/Deep Link/DeepLink+Share.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import UIKit

extension DeepLink {
func share() {
let activityVC = UIActivityViewController(
activityItems: itemsForSharing,
applicationActivities: nil
)
activityVC.excludedActivityTypes = [.mail, .addToReadingList, .assignToContact, .markupAsPDF, .openInIBooks, .saveToCameraRoll, .print]

let keyWindow = UIApplication.shared.connectedScenes
.filter { $0.activationState == .foregroundActive }
.compactMap { $0 as? UIWindowScene }
.first?
.windows
.filter(\.isKeyWindow)
.first

keyWindow?.rootViewController?
.topViewController
.present(activityVC, animated: true, completion: nil)
}
}
File renamed without changes.
9 changes: 0 additions & 9 deletions Friendly Competitions/Views/Home/Dashboard/Dashboard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,6 @@ struct Dashboard: View {
.sheet(isPresented: $presentSearchFriendsSheet) { InviteFriends(action: .addFriend) }
.sheet(isPresented: $presentNewCompetition) { NewCompetition() }
.sheet(isPresented: $viewModel.requiresPermissions) { PermissionsView() }
.onOpenURL { url in
appState.deepLink = DeepLink(from: url)
switch appState.deepLink {
case .friendReferral:
presentSearchFriendsSheet.toggle()
default:
break
}
}
.registerScreenView(name: "Home")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ struct Profile: View {
var body: some View {
Form {
UserInfoSection(user: viewModel.user)
Button("Share invite link", systemImage: .personCropCircleBadgePlus) { viewModel.sharedDeepLink.share() }

Section("Statistics") {
StatisticsView(statistics: viewModel.user.statistics ?? .zero)
}

Section {
Toggle("Searchable", isOn: $viewModel.user.searchable ?? true)

} header: {
Text("Privacy")
} footer: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Resolver
final class ProfileViewModel: ObservableObject {

@Published var user: User!
@Published var sharedDeepLink: DeepLink!

@Injected private var authenticationManager: AnyAuthenticationManager
@Injected private var userManager: AnyUserManager
Expand All @@ -13,6 +14,7 @@ final class ProfileViewModel: ObservableObject {

init() {
user = userManager.user
sharedDeepLink = .friendReferral(id: userManager.user.id)

$user
.removeDuplicates()
Expand Down
37 changes: 16 additions & 21 deletions Friendly Competitions/Views/Home/Explore/ExploreViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,32 @@ final class ExploreViewModel: ObservableObject {
@Published var loading = false
@Published var searchText = ""
@Published var searchResults = [Competition]()

@Published var appOwnedCompetitions = [Competition]()
@Published var topCommunityCompetitions = [Competition]()

@Injected private var competitionsManager: AnyCompetitionsManager

private var cancellables = Set<AnyCancellable>()

init() {

competitionsManager.$appOwnedCompetitions.assign(to: &$appOwnedCompetitions)
competitionsManager.$topCommunityCompetitions.assign(to: &$topCommunityCompetitions)

$searchText
.sinkAsync { [weak self] searchText in
guard let self = self else { return }
guard !searchText.isEmpty else {
self.searchResults = []
self.loading = false
return
.handleEvents(receiveOutput: { [weak self] _ in self?.loading = true })
.flatMapLatest { [weak self] searchText -> AnyPublisher<[Competition], Never> in
guard let self = self else { return .just([]) }
let subject = PassthroughSubject<[Competition], Never>()
Task {
let competitions = try await self.competitionsManager
.search(searchText)
.sorted { lhs, rhs in
lhs.appOwned && !rhs.appOwned
}
subject.send(competitions)
}

self.loading = true
let competitions = try await self.competitionsManager
.search(searchText)
.sorted { lhs, rhs in
lhs.appOwned && !rhs.appOwned
}
self.searchResults = competitions
self.loading = false
return subject.eraseToAnyPublisher()
}
.store(in: &cancellables)
.receive(on: RunLoop.main)
.handleEvents(receiveOutput: { [weak self] _ in self?.loading = false })
.assign(to: &$searchResults)
}
}
6 changes: 6 additions & 0 deletions Friendly Competitions/Views/Home/Home.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import Resolver
import SwiftUI

struct Home: View {

@StateObject private var viewModel = HomeViewModel()

var body: some View {
TabView {
Dashboard()
Expand All @@ -12,6 +15,9 @@ struct Home: View {
.embeddedInNavigationView()
.tabItem { Label("Explore", systemImage: .sparkleMagnifyingglass) }
}
.onOpenURL(perform: viewModel.handle(url:))
.sheet(item: $viewModel.deepLinkedCompetition) { CompetitionView(competition: $0).embeddedInNavigationView() }
.sheet(item: $viewModel.deepLinkedUser) { UserView(user: $0).embeddedInNavigationView() }
}
}

Expand Down
37 changes: 37 additions & 0 deletions Friendly Competitions/Views/HomeViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Combine
import Foundation
import Resolver

enum HomeTab {
case dashboard
case explore
}

final class HomeViewModel: ObservableObject {

@Published var deepLinkedCompetition: Competition?
@Published var deepLinkedUser: User?

@Injected private var competitionsManager: AnyCompetitionsManager
@Injected private var friendsManager: AnyFriendsManager

func handle(url: URL) {
guard let deepLink = DeepLink(from: url) else { return }
switch deepLink {
case .friendReferral(let id):
Task {
let user = try await friendsManager.user(withId: id)
DispatchQueue.main.async { [weak self] in
self?.deepLinkedUser = user
}
}
case .competitionInvite(let id):
Task {
let competition = try await competitionsManager.search(byID: id)
DispatchQueue.main.async { [weak self] in
self?.deepLinkedCompetition = competition
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,8 @@ struct InviteFriends: View {
.searchable(text: $viewModel.searchText, placement: .navigationBarDrawer(displayMode: .always))
.navigationTitle("Invite a friend")
.onChange(of: viewModel.sharedDeepLink) { deepLink in
guard let deepLink = deepLink else { return }
deepLink?.share()
viewModel.sharedDeepLink = nil
let activityVC = UIActivityViewController(
activityItems: deepLink.itemsForSharing,
applicationActivities: nil
)
activityVC.excludedActivityTypes = [.mail, .addToReadingList, .assignToContact, .markupAsPDF, .openInIBooks, .saveToCameraRoll, .print]

let keyWindow = UIApplication.shared.connectedScenes
.filter { $0.activationState == .foregroundActive }
.compactMap { $0 as? UIWindowScene }
.first?
.windows
.filter(\.isKeyWindow)
.first

keyWindow?.rootViewController?
.topViewController
.present(activityVC, animated: true, completion: nil)
}
.embeddedInNavigationView()
}
Expand Down

0 comments on commit b3fd242

Please sign in to comment.