Skip to content

Commit

Permalink
Merge pull request #22 from vespinola/14-save-login-session
Browse files Browse the repository at this point in the history
14 save login session
  • Loading branch information
vespinola authored Jun 24, 2024
2 parents 9393bdd + 823d518 commit 3f709b9
Show file tree
Hide file tree
Showing 23 changed files with 353 additions and 42 deletions.
30 changes: 25 additions & 5 deletions mobile-courier-app.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
1B4047192C2782B300101DF4 /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B4047182C2782B300101DF4 /* HomeViewModel.swift */; };
1B40471B2C27854200101DF4 /* AddressEntityMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B40471A2C27854200101DF4 /* AddressEntityMock.swift */; };
1B40471D2C27C3CB00101DF4 /* GroupedPackageStyleModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B40471C2C27C3CB00101DF4 /* GroupedPackageStyleModifier.swift */; };
1B4047242C27DF9600101DF4 /* ConfigurationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B4047232C27DF9600101DF4 /* ConfigurationView.swift */; };
1B4047282C27E04600101DF4 /* AppDIContainerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B4047272C27E04600101DF4 /* AppDIContainerMock.swift */; };
1B40472A2C27E99D00101DF4 /* AppDataMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B4047292C27E99D00101DF4 /* AppDataMock.swift */; };
1B58EF772BE6BBE90066F447 /* MobileCourierApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B58EF762BE6BBE90066F447 /* MobileCourierApp.swift */; };
1B58EF792BE6BBE90066F447 /* CoordinatorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B58EF782BE6BBE90066F447 /* CoordinatorRootView.swift */; };
1B58EF7B2BE6BBEA0066F447 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1B58EF7A2BE6BBEA0066F447 /* Assets.xcassets */; };
Expand Down Expand Up @@ -110,7 +113,10 @@
1B4047182C2782B300101DF4 /* HomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = "<group>"; };
1B40471A2C27854200101DF4 /* AddressEntityMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressEntityMock.swift; sourceTree = "<group>"; };
1B40471C2C27C3CB00101DF4 /* GroupedPackageStyleModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupedPackageStyleModifier.swift; sourceTree = "<group>"; };
1B58EF732BE6BBE90066F447 /* mobile-courier-app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "mobile-courier-app.app"; sourceTree = BUILT_PRODUCTS_DIR; };
1B4047232C27DF9600101DF4 /* ConfigurationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationView.swift; sourceTree = "<group>"; };
1B4047272C27E04600101DF4 /* AppDIContainerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDIContainerMock.swift; sourceTree = "<group>"; };
1B4047292C27E99D00101DF4 /* AppDataMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDataMock.swift; sourceTree = "<group>"; };
1B58EF732BE6BBE90066F447 /* JustACourierApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JustACourierApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
1B58EF762BE6BBE90066F447 /* MobileCourierApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MobileCourierApp.swift; sourceTree = "<group>"; };
1B58EF782BE6BBE90066F447 /* CoordinatorRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoordinatorRootView.swift; sourceTree = "<group>"; };
1B58EF7A2BE6BBEA0066F447 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
Expand Down Expand Up @@ -216,6 +222,14 @@
path = WithdrawnPackages;
sourceTree = "<group>";
};
1B40471E2C27DF3100101DF4 /* Configurations */ = {
isa = PBXGroup;
children = (
1B4047232C27DF9600101DF4 /* ConfigurationView.swift */,
);
path = Configurations;
sourceTree = "<group>";
};
1B58EF6A2BE6BBE90066F447 = {
isa = PBXGroup;
children = (
Expand All @@ -230,7 +244,7 @@
1B58EF742BE6BBE90066F447 /* Products */ = {
isa = PBXGroup;
children = (
1B58EF732BE6BBE90066F447 /* mobile-courier-app.app */,
1B58EF732BE6BBE90066F447 /* JustACourierApp.app */,
1B58EF842BE6BBEA0066F447 /* mobile-courier-appTests.xctest */,
1B58EF8E2BE6BBEA0066F447 /* mobile-courier-appUITests.xctest */,
);
Expand Down Expand Up @@ -430,6 +444,7 @@
isa = PBXGroup;
children = (
1B58EF782BE6BBE90066F447 /* CoordinatorRootView.swift */,
1B40471E2C27DF3100101DF4 /* Configurations */,
1B6D751A2C23DF820067BB56 /* ShipmentDetail */,
1B6D75152C23BDA40067BB56 /* PackagesForWithdrawal */,
1B2DDEF02C1E652A003EC97C /* WithdrawnPackages */,
Expand Down Expand Up @@ -472,6 +487,7 @@
1BE58CA42C05725500C7DF63 /* Previews */ = {
isa = PBXGroup;
children = (
1B4047272C27E04600101DF4 /* AppDIContainerMock.swift */,
1BE58CA52C05727500C7DF63 /* AuthRepositoryMock.swift */,
1BE58CA72C0572B400C7DF63 /* StorageMock.swift */,
1BE58CA92C05731B00C7DF63 /* LoginViewModelMock.swift */,
Expand All @@ -481,6 +497,7 @@
1B2DDF032C1E9B12003EC97C /* PackagesRepositoryMock.swift */,
1B6590E32C228DD700D46A27 /* PackagesForWithdrawalViewModelMock.swift */,
1B40471A2C27854200101DF4 /* AddressEntityMock.swift */,
1B4047292C27E99D00101DF4 /* AppDataMock.swift */,
);
path = Previews;
sourceTree = "<group>";
Expand Down Expand Up @@ -531,7 +548,7 @@
packageProductDependencies = (
);
productName = "mobile-courier-app";
productReference = 1B58EF732BE6BBE90066F447 /* mobile-courier-app.app */;
productReference = 1B58EF732BE6BBE90066F447 /* JustACourierApp.app */;
productType = "com.apple.product-type.application";
};
1B58EF832BE6BBEA0066F447 /* mobile-courier-appTests */ = {
Expand Down Expand Up @@ -672,9 +689,11 @@
buildActionMask = 2147483647;
files = (
1B99600F2C12992F00976BBC /* AddressRespository.swift in Sources */,
1B4047242C27DF9600101DF4 /* ConfigurationView.swift in Sources */,
1B58EFB92BE729D20066F447 /* Endpoint.swift in Sources */,
1B2DDEF42C1E7DD4003EC97C /* PackagePlaceholderView.swift in Sources */,
1B07BC8D2BFD677900D8B149 /* RippleSpinnerView.swift in Sources */,
1B4047282C27E04600101DF4 /* AppDIContainerMock.swift in Sources */,
1B9274D02C115AF1008F4FA3 /* AddressesModel.swift in Sources */,
1BE58CA82C0572B400C7DF63 /* StorageMock.swift in Sources */,
1B8B0A442C1BDDE600D1A7AC /* HeaderView.swift in Sources */,
Expand Down Expand Up @@ -721,6 +740,7 @@
1B85E8E72BFC4E24003040CC /* LoginEntity.swift in Sources */,
1B58EF772BE6BBE90066F447 /* MobileCourierApp.swift in Sources */,
1B2DDF022C1E9AC8003EC97C /* WithdrawnPackagesViewModelMock.swift in Sources */,
1B40472A2C27E99D00101DF4 /* AppDataMock.swift in Sources */,
1B2DDEFE2C1E95D3003EC97C /* PackagesRepository.swift in Sources */,
1B5EBFFE2C081DDA003BC2D9 /* AuthData.swift in Sources */,
1BC0717A2C140C6A006EC08E /* HomeViewModelMock.swift in Sources */,
Expand Down Expand Up @@ -912,7 +932,7 @@
MACOSX_DEPLOYMENT_TARGET = 14.4;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.just.another.mobile-courier-app";
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_NAME = JustACourierApp;
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
Expand Down Expand Up @@ -953,7 +973,7 @@
MACOSX_DEPLOYMENT_TARGET = 14.4;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.just.another.mobile-courier-app";
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_NAME = JustACourierApp;
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1B58EF722BE6BBE90066F447"
BuildableName = "mobile-courier-app.app"
BuildableName = "JustACourierApp.app"
BlueprintName = "mobile-courier-app"
ReferencedContainer = "container:mobile-courier-app.xcodeproj">
</BuildableReference>
Expand Down Expand Up @@ -69,7 +69,7 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1B58EF722BE6BBE90066F447"
BuildableName = "mobile-courier-app.app"
BuildableName = "JustACourierApp.app"
BlueprintName = "mobile-courier-app"
ReferencedContainer = "container:mobile-courier-app.xcodeproj">
</BuildableReference>
Expand All @@ -86,7 +86,7 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "1B58EF722BE6BBE90066F447"
BuildableName = "mobile-courier-app.app"
BuildableName = "JustACourierApp.app"
BlueprintName = "mobile-courier-app"
ReferencedContainer = "container:mobile-courier-app.xcodeproj">
</BuildableReference>
Expand Down
Binary file added mobile-courier-app/.DS_Store
Binary file not shown.
9 changes: 7 additions & 2 deletions mobile-courier-app/App/AppDIContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ final class AppDIContainer: DIContainerProtocol {
register(AddressRespository(), for: AddressRepositoryProtocol.self)
register(PackagesRepository(), for: PackagesRepositoryProtocol.self)

//Helpers
register(UserDefaultsStorage(), for: Storage.self)

// ViewModels
register(
LoginViewModel(authRepository: resolve(AuthRepositoryProtocol.self)),
LoginViewModel(
authRepository: resolve(AuthRepositoryProtocol.self),
storage: resolve(Storage.self)),
for: LoginViewModel.self
)
register(
Expand All @@ -39,7 +44,7 @@ final class AppDIContainer: DIContainerProtocol {
let key = String(describing: type)
services[key] = service
}

func resolve<T>(_ type: T.Type) -> T {
let key = String(describing: type)
guard let service = services[key] as? T else {
Expand Down
4 changes: 4 additions & 0 deletions mobile-courier-app/App/MobileCourierApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import SwiftUI

@main
struct MobileCourierApp: App {
@AppStorage("isDarkMode") var isDarkMode: Bool = true

@StateObject var coordinator = Coordinator(diContainer: AppDIContainer())
@StateObject var appData = AppData.shared

Expand All @@ -21,6 +23,8 @@ struct MobileCourierApp: App {
CoordinatorRootView()
.environmentObject(coordinator)
.environmentObject(appData)
.environment(\.colorScheme, isDarkMode ? .dark : .light)
.preferredColorScheme(isDarkMode ? .dark : .light)
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"images" : [
{
"filename" : "App_Icon.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
Expand Down
17 changes: 17 additions & 0 deletions mobile-courier-app/Domain/Entities/PackageEntity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@ enum ShipmentStatus: String, CaseIterable, Identifiable {
case unknown = "Unknown Status"

var id: String { self.rawValue }

var localized: String {
switch self {
case .readyForPickup:
return NSLocalizedString("Ready for Pickup", comment: "")
case .processing:
return NSLocalizedString("Processing", comment: "")
case .onTheWay:
return NSLocalizedString("On the Way", comment: "")
case .inLocker:
return NSLocalizedString("In Locker", comment: "")
case .inconsistent:
return NSLocalizedString("Inconsistent", comment: "")
case .unknown:
return NSLocalizedString("Unknown Status", comment: "")
}
}
}

struct GroupedPackageEntity: Identifiable {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// ConfigurationView.swift
// mobile-courier-app
//
// Created by Vladimir Espinola on 2024-06-23.
//

import SwiftUI

struct ConfigurationView: View {
@AppStorage("isDarkMode") var darkModeOn: Bool = false
@EnvironmentObject var coordinator: Coordinator

var body: some View {
VStack {
List {
Section {
Toggle("Dark Mode", isOn: $darkModeOn)
}

Section {
Button("Log out", role: .destructive) {
coordinator.popToRoot()
}
}
}
}
}
}

#Preview {
ConfigurationView()
.environmentObject(Coordinator(diContainer: AppDIContainerMock()))
}
2 changes: 1 addition & 1 deletion mobile-courier-app/Presentation/Helpers/HeaderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct HeaderView: View {
}

#Preview {
let appData = AppData()
let appData = AppData.mock
appData.username = "John Doe"
return HeaderView()
.environmentObject(appData)
Expand Down
9 changes: 8 additions & 1 deletion mobile-courier-app/Presentation/Home/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ struct HomeView: View {
Label("Profile", systemImage: "person")
}
.tag(2)

coordinator.build(page: .configurations)
.tabItem {
Label("Settings", systemImage: "gear")
}
.tag(3)
}
.navigationTitle("")
.toolbar(.hidden)
Expand Down Expand Up @@ -61,5 +67,6 @@ struct HomeView: View {

#Preview {
HomeView(viewModel: .previewInstance())
.environmentObject(Coordinator(diContainer: AppDIContainer()))
.environmentObject(Coordinator(diContainer: AppDIContainerMock()))
.environmentObject(AppData.mock)
}
8 changes: 7 additions & 1 deletion mobile-courier-app/Presentation/Login/LoginViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,22 @@ final class LoginViewModel: ObservableObject {
}

private let authRepository: AuthRepositoryProtocol
private let storage: Storage

init(authRepository: AuthRepositoryProtocol) {
init(authRepository: AuthRepositoryProtocol, storage: Storage) {
self.authRepository = authRepository
self.storage = storage

guard let savedEmail = storage.getString(forKey: "userEmail"), !savedEmail.isEmpty else { return }
self.email = savedEmail
}

@MainActor
func doLogin() async -> Bool {
do {
isLoading = true
try await authRepository.performLogin(email: email, password: password)
storage.setString(email, forKey: "userEmail")
isLoading = false
return true
} catch {
Expand Down
3 changes: 3 additions & 0 deletions mobile-courier-app/Presentation/Navigation/Coordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum Page: String, Identifiable {
case profile
case withdrawnPackages
case packagesForWithdrawl
case configurations

var id: String {
self.rawValue
Expand Down Expand Up @@ -83,6 +84,8 @@ final class Coordinator: ObservableObject {
PackagesForWithdrawalView(
viewModel: diContainer.resolve(PackagesForWithdrawalViewModel.self)
)
case .configurations:
ConfigurationView()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct GroupedPackageReadyView: View {

Spacer()

Text("Gs. \(groupedPackage.formattedTotalCost)")
Text("Gs \(groupedPackage.formattedTotalCost)")
.foregroundStyle(.accent)
.font(.title2)
.fontWeight(.bold)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct PackagesForWithdrawalView: View {
List {
ForEach(ShipmentStatus.allCases) { status in
if !groupedPackages.filterGroupedPackages(by: status).isEmpty {
Section(header: Text(status.rawValue)) {
Section(header: Text(status.localized)) {
ForEach(groupedPackages.filter { $0.packageCurrentStatus == status }) { currentGroupedPackage in
getGroupedPackageView(for: currentGroupedPackage)
.groupedPackageRowStyle()
Expand Down Expand Up @@ -72,5 +72,5 @@ struct PackagesForWithdrawalView: View {

#Preview {
PackagesForWithdrawalView(viewModel: .previewInstance())
.environmentObject(Coordinator(diContainer: AppDIContainer()))
.environmentObject(Coordinator(diContainer: AppDIContainerMock()))
}
45 changes: 45 additions & 0 deletions mobile-courier-app/Presentation/Previews/AppDIContainerMock.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// AppDIContainerMock.swift
// mobile-courier-app
//
// Created by Vladimir Espinola on 2024-06-23.
//

import Foundation

final class AppDIContainerMock: DIContainerProtocol {
private var services: [String: Any] = [:]

init() {
// ViewModels
register(
LoginViewModel.previewInstance(),
for: LoginViewModel.self
)
register(
HomeViewModel.previewInstance(),
for: HomeViewModel.self
)
register(
WithdrawnPackagesViewModel.previewInstance(),
for: WithdrawnPackagesViewModel.self
)
register(
PackagesForWithdrawalViewModel.previewInstance(),
for: PackagesForWithdrawalViewModel.self
)
}

func register<T>(_ service: T, for type: T.Type) {
let key = String(describing: type)
services[key] = service
}

func resolve<T>(_ type: T.Type) -> T {
let key = String(describing: type)
guard let service = services[key] as? T else {
fatalError("Service for \(type) not found")
}
return service
}
}
Loading

0 comments on commit 3f709b9

Please sign in to comment.