Skip to content

Commit

Permalink
Restructured onboarding (#613)
Browse files Browse the repository at this point in the history
  • Loading branch information
mormaer authored Sep 18, 2023
1 parent 74875fa commit 8f1f9a9
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 108 deletions.
24 changes: 20 additions & 4 deletions Mlem.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
504106CD2A744D7F000AAEF8 /* CommentRepository+Dependency.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504106CC2A744D7F000AAEF8 /* CommentRepository+Dependency.swift */; };
504ECBAE2AB45B2A006C0B96 /* LemmyURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504ECBAD2AB45B2A006C0B96 /* LemmyURL.swift */; };
504ECBB12AB4B101006C0B96 /* LemmyURLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504ECBB02AB4B101006C0B96 /* LemmyURLTests.swift */; };
504ECBAA2AB27C73006C0B96 /* LandingPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504ECBA92AB27C73006C0B96 /* LandingPage.swift */; };
504ECBAC2AB27CB1006C0B96 /* OnboardingRoute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504ECBAB2AB27CB1006C0B96 /* OnboardingRoute.swift */; };
505240E32A86916500EA4558 /* FavoriteCommunitiesTracker+Dependency.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505240E22A86916500EA4558 /* FavoriteCommunitiesTracker+Dependency.swift */; };
505240E52A86E32700EA4558 /* CommunityListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505240E42A86E32700EA4558 /* CommunityListModel.swift */; };
505240E72A88D36D00EA4558 /* SectionIndexTitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505240E62A88D36D00EA4558 /* SectionIndexTitles.swift */; };
Expand Down Expand Up @@ -384,7 +386,7 @@
CDDCF6512A677E1B003DA3AC /* FancyTabItemPreferenceKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF6502A677E1B003DA3AC /* FancyTabItemPreferenceKeys.swift */; };
CDDCF6532A677F45003DA3AC /* TabSelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF6522A677F45003DA3AC /* TabSelection.swift */; };
CDDCF6572A678298003DA3AC /* FancyTabBarSelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF6562A678298003DA3AC /* FancyTabBarSelection.swift */; };
CDE3BA872A8C25B000B972E2 /* Onboarding View.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDE3BA862A8C25B000B972E2 /* Onboarding View.swift */; };
CDE3BA872A8C25B000B972E2 /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDE3BA862A8C25B000B972E2 /* OnboardingView.swift */; };
CDE3BA892A8C64BD00B972E2 /* Collapsible Text Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDE3BA882A8C64BD00B972E2 /* Collapsible Text Item.swift */; };
CDE6A80B2A43E9F00062D161 /* CommentSortType.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDE6A80A2A43E9F00062D161 /* CommentSortType.swift */; };
CDE6A80D2A45EAB30062D161 /* Embedded Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDE6A80C2A45EAB30062D161 /* Embedded Post.swift */; };
Expand Down Expand Up @@ -489,6 +491,8 @@
504106CC2A744D7F000AAEF8 /* CommentRepository+Dependency.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CommentRepository+Dependency.swift"; sourceTree = "<group>"; };
504ECBAD2AB45B2A006C0B96 /* LemmyURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LemmyURL.swift; sourceTree = "<group>"; };
504ECBB02AB4B101006C0B96 /* LemmyURLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LemmyURLTests.swift; sourceTree = "<group>"; };
504ECBA92AB27C73006C0B96 /* LandingPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandingPage.swift; sourceTree = "<group>"; };
504ECBAB2AB27CB1006C0B96 /* OnboardingRoute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingRoute.swift; sourceTree = "<group>"; };
505240E22A86916500EA4558 /* FavoriteCommunitiesTracker+Dependency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FavoriteCommunitiesTracker+Dependency.swift"; sourceTree = "<group>"; };
505240E42A86E32700EA4558 /* CommunityListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommunityListModel.swift; sourceTree = "<group>"; };
505240E62A88D36D00EA4558 /* SectionIndexTitles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionIndexTitles.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -827,7 +831,7 @@
CDDCF6502A677E1B003DA3AC /* FancyTabItemPreferenceKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FancyTabItemPreferenceKeys.swift; sourceTree = "<group>"; };
CDDCF6522A677F45003DA3AC /* TabSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabSelection.swift; sourceTree = "<group>"; };
CDDCF6562A678298003DA3AC /* FancyTabBarSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FancyTabBarSelection.swift; sourceTree = "<group>"; };
CDE3BA862A8C25B000B972E2 /* Onboarding View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Onboarding View.swift"; sourceTree = "<group>"; };
CDE3BA862A8C25B000B972E2 /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; };
CDE3BA882A8C64BD00B972E2 /* Collapsible Text Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collapsible Text Item.swift"; sourceTree = "<group>"; };
CDE6A80A2A43E9F00062D161 /* CommentSortType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentSortType.swift; sourceTree = "<group>"; };
CDE6A80C2A45EAB30062D161 /* Embedded Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Embedded Post.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1078,6 +1082,16 @@
path = Model;
sourceTree = "<group>";
};
504ECBA82AB27C4C006C0B96 /* Onboarding */ = {
isa = PBXGroup;
children = (
504ECBA92AB27C73006C0B96 /* LandingPage.swift */,
CDE3BA862A8C25B000B972E2 /* OnboardingView.swift */,
504ECBAB2AB27CB1006C0B96 /* OnboardingRoute.swift */,
);
path = Onboarding;
sourceTree = "<group>";
};
5064D03B2A6DE05000B22EE3 /* Notifications */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1364,7 +1378,6 @@
CDCBD7292A8EC06D00387A2C /* Components */,
6332FDCE27EFDD2E0009A98A /* Accounts Page.swift */,
63F0C7B82A0533C700A18C5D /* Add Account View.swift */,
CDE3BA862A8C25B000B972E2 /* Onboarding View.swift */,
CDCBD7252A8D69A200387A2C /* Instance Picker View.swift */,
CDCBD7272A8D6B7700387A2C /* Instance Picker View Logic.swift */,
CDC65D902A86B830007205E5 /* DeleteAccountView.swift */,
Expand Down Expand Up @@ -1515,6 +1528,7 @@
6363D5F327EE1BA900E34822 /* Views */ = {
isa = PBXGroup;
children = (
504ECBA82AB27C4C006C0B96 /* Onboarding */,
6386E03E2A04570F006B3C1D /* Shared */,
6363D5F427EE1BAE00E34822 /* Tabs */,
);
Expand Down Expand Up @@ -2581,6 +2595,7 @@
504ECBAE2AB45B2A006C0B96 /* LemmyURL.swift in Sources */,
CDA217EA2A63093E00BDA173 /* ReportComment.swift in Sources */,
CDA217E82A63029B00BDA173 /* ReportMention.swift in Sources */,
504ECBAA2AB27C73006C0B96 /* LandingPage.swift in Sources */,
508845CF2A3641160088E483 /* JSONDecoder+Default.swift in Sources */,
637218672A3A2AAD008C4816 /* GetPersonDetails.swift in Sources */,
B1A26FE12A44AAB200B91A32 /* Navigation getter.swift in Sources */,
Expand Down Expand Up @@ -2721,6 +2736,7 @@
637218432A3A2AAD008C4816 /* APIClient.swift in Sources */,
CD82A2572A716D7C00111034 /* PersonRepository+Dependency.swift in Sources */,
63DF71F12A02999C002AC14E /* App Constants.swift in Sources */,
504ECBAC2AB27CB1006C0B96 /* OnboardingRoute.swift in Sources */,
CD82A2532A716B8100111034 /* PersonRepository.swift in Sources */,
CD69F55F2A40121D0028D4F7 /* Ellipsis Menu.swift in Sources */,
638535712A1779BC00815781 /* GeneralSettingsView.swift in Sources */,
Expand Down Expand Up @@ -2754,7 +2770,7 @@
CD6483A62A82FAF200A5AE84 /* ProfileTabLabel.swift in Sources */,
CDEBC3252A9A57D200518D9D /* Content Type.swift in Sources */,
6386E0402A045723006B3C1D /* Website Icon Complex.swift in Sources */,
CDE3BA872A8C25B000B972E2 /* Onboarding View.swift in Sources */,
CDE3BA872A8C25B000B972E2 /* OnboardingView.swift in Sources */,
5064D0412A6E63E000B22EE3 /* Task+Notifiable.swift in Sources */,
63F0C7BD2A058CD200A18C5D /* Check if Endpoint Exists.swift in Sources */,
E4D4DBA02A7C7B9D00C4F3DE /* Comments.swift in Sources */,
Expand Down
63 changes: 63 additions & 0 deletions Mlem/Views/Onboarding/LandingPage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// LandingPage.swift
// Mlem
//
// Created by mormaer on 14/09/2023.
//
//

import SwiftUI

struct LandingPage: View {
@State private var navigationPath = NavigationPath()

var body: some View {
NavigationStack(path: $navigationPath) {
VStack(spacing: 40) {
Text("Welcome to Mlem!")
.bold()

LogoView()

VStack {
newUserButton
existingUserButton
}
}
.padding(.horizontal)
.frame(maxHeight: .infinity)
.navigationDestination(for: OnboardingRoute.self) { route in
switch route {
case .onboard:
OnboardingView(navigationPath: $navigationPath)
case let .login(url):
AddSavedInstanceView(onboarding: true, givenInstance: url?.absoluteString)
}
}
}
}

@ViewBuilder
var newUserButton: some View {
Button {
navigationPath.append(OnboardingRoute.onboard)
} label: {
Text("I'm new here")
.padding(.vertical, 5)
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
}

@ViewBuilder
var existingUserButton: some View {
Button {
navigationPath.append(OnboardingRoute.login(nil))
} label: {
Text("I have a Lemmy account")
.padding(.vertical, 5)
.frame(maxWidth: .infinity)
}
.buttonStyle(.bordered)
}
}
14 changes: 14 additions & 0 deletions Mlem/Views/Onboarding/OnboardingRoute.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// OnboardingRoute.swift
// Mlem
//
// Created by mormaer on 14/09/2023.
//
//

import Foundation

enum OnboardingRoute: Hashable {
case onboard
case login(URL?)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Onboarding View.swift
// OnboardingView.swift
// Mlem
//
// Created by Eric Andrews on 2023-08-15.
Expand All @@ -10,93 +10,41 @@ import SwiftUI

struct OnboardingView: View {
enum OnboardingTab {
case welcome, about, instances, addAccount
case about, instances
}

@Binding var flow: AppFlow
@Binding var navigationPath: NavigationPath

@State var selectedTab: OnboardingTab = .welcome
@State var selectedTab: OnboardingTab = .about
@State var hideNav: Bool = true

@State var selectedInstance: InstanceMetadata?

var body: some View {
TabView(selection: $selectedTab) {
onboardingTab
.tag(OnboardingTab.welcome)

aboutTab
.tag(OnboardingTab.about)

instancesTab
.tag(OnboardingTab.instances)

AddSavedInstanceView(onboarding: true, givenInstance: selectedInstance?.url.absoluteString)
.tag(OnboardingTab.addAccount)
}
.onChange(of: selectedInstance) { _ in
selectedTab = .addAccount
.onChange(of: selectedInstance) { instance in
guard let instanceUrl = instance?.url else { return }
navigationPath.append(OnboardingRoute.login(instanceUrl))
}
.animation(.spring(response: 0.5), value: selectedTab)
.tabViewStyle(PageTabViewStyle())
}

// MARK: - Onboarding Tab

@ViewBuilder
var onboardingTab: some View {
VStack(spacing: 40) {
Text("Welcome to Mlem!")
.bold()

LogoView()

VStack {
newUserButton
existingUserButton
}
}
.padding(.horizontal)
.frame(maxHeight: .infinity)
}

@ViewBuilder
var newUserButton: some View {
Button {
selectedTab = .about
} label: {
Text("I'm new here")
.padding(.vertical, 5)
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
.tabViewStyle(.page(indexDisplayMode: .always))
.indexViewStyle(.page(backgroundDisplayMode: .always))
}

@ViewBuilder
var existingUserButton: some View {
Button {
selectedTab = .addAccount
} label: {
Text("I have a Lemmy account")
.padding(.vertical, 5)
.frame(maxWidth: .infinity)
}
.buttonStyle(.bordered)
}


// MARK: - About Tab

@ViewBuilder
var aboutTab: some View {
ScrollView {
VStack(spacing: 40) {
Group {
Text("What is Lemmy?")
.bold()

Text(.init(whatIsLemmy))
}
.padding()
Text(.init(whatIsLemmy))
.padding()

VStack(spacing: 0) {
Divider()
Expand Down Expand Up @@ -125,9 +73,10 @@ struct OnboardingView: View {

// add a little space for the tab selection indicator
Spacer()
.frame(height: 20)
.frame(height: 36)
}
}
.navigationTitle("What is Lemmy?")
}

@ViewBuilder
Expand All @@ -146,5 +95,6 @@ struct OnboardingView: View {

var instancesTab: some View {
InstancePickerView(selectedInstance: $selectedInstance, onboarding: true)
.padding(.bottom, 36)
}
}
30 changes: 17 additions & 13 deletions Mlem/Views/Shared/Accounts/Accounts Page.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,22 @@ struct AccountsPage: View {
let instances = Array(accountsTracker.accountsByInstance.keys).sorted()

Group {
if instances.isEmpty || isShowingInstanceAdditionSheet {
if instances.isEmpty {
AddSavedInstanceView(onboarding: false)
} else {
List {
ForEach(instances, id: \.self) { instance in
Section(header: Text(instance)) {
ForEach(accountsTracker.accountsByInstance[instance] ?? []) { account in
Button(account.username) {
dismiss()
Button(account.nickname) {
setFlow(using: account)
dismiss()
}
.disabled(isActiveAccount(account))
.swipeActions {
Button("Remove", role: .destructive) {
dismiss()
accountsTracker.removeAccount(account: account)
if account == appState.currentActiveAccount {
if isActiveAccount(account) {
// if we just deleted the current account we (currently!) have a decision to make
if let first = accountsTracker.savedAccounts.first {
// if we have another account available, go to that...
Expand All @@ -54,6 +54,8 @@ struct AccountsPage: View {
// no accounts, so go to onboarding
setFlow(using: nil)
}

dismiss()
}
}
}
Expand Down Expand Up @@ -93,15 +95,17 @@ struct AccountsPage: View {
return account == currentAccount ? .secondary : .primary
}

private func isActiveAccount(_ account: SavedAccount) -> Bool {
guard let currentAccount = appState.currentActiveAccount else { return false }
return account == currentAccount
}

private func setFlow(using account: SavedAccount?) {
// this tiny delay prevents the modal dismiss animation from being cancelled
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
if let account {
setFlow(.account(account))
return
}

setFlow(.onboarding)
if let account {
setFlow(.account(account))
return
}

setFlow(.onboarding)
}
}
Loading

0 comments on commit 8f1f9a9

Please sign in to comment.