Skip to content

Commit

Permalink
🔀️ Merge branch 'release/LekaApp/1.13.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
ladislas committed Oct 24, 2024
2 parents 39127c0 + a3c6c66 commit 90b8330
Show file tree
Hide file tree
Showing 394 changed files with 3,954 additions and 772 deletions.
2 changes: 1 addition & 1 deletion Apps/LekaApp/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ let kLekaAppVersion: String = {
}

// ? App version
return "1.12.0"
return "1.13.0"
}()

let project = Project.app(
Expand Down
4 changes: 4 additions & 0 deletions Apps/LekaApp/Sources/Navigation/Navigation+Category.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ extension Navigation {
case vectorImageList
case news
case demo
case libraryCurriculums
case libraryActivities
case libraryStories
case libraryGamepads

// MARK: Internal

Expand Down
2 changes: 2 additions & 0 deletions Apps/LekaApp/Sources/Views/ConnectionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ struct ConnectionView: View {
if newValue == .loggedIn {
self.caregiverManager.initializeCaregiversListener()
self.carereceiverManager.initializeCarereceiversListener()
self.rootAccountManager.initializeRootAccountListener()
self.authManagerViewModel.userAction = .none
self.navigation.fullScreenCoverContent = nil
}
Expand All @@ -99,6 +100,7 @@ struct ConnectionView: View {
@State private var showResetPassword: Bool = false

private var authManager: AuthManager = .shared
private var rootAccountManager: RootAccountManager = .shared
private var caregiverManager: CaregiverManager = .shared
private var carereceiverManager: CarereceiverManager = .shared

Expand Down
20 changes: 20 additions & 0 deletions Apps/LekaApp/Sources/Views/MainView/MainView+CategoryLabel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ extension MainView {
struct CategoryLabel: View {
// MARK: Lifecycle

// swiftlint:disable cyclomatic_complexity body_length

init(category: Navigation.Category) {
self.category = category

Expand Down Expand Up @@ -84,9 +86,27 @@ extension MainView {
case .demo:
self.title = "Demo"
self.systemImage = "play.rectangle"

case .libraryCurriculums:
self.title = String(l10n.MainView.Sidebar.CategoryLabel.curriculums.characters)
self.systemImage = "graduationcap.fill"

case .libraryActivities:
self.title = String(l10n.MainView.Sidebar.CategoryLabel.activities.characters)
self.systemImage = "dice.fill"

case .libraryStories:
self.title = String(l10n.MainView.Sidebar.CategoryLabel.stories.characters)
self.systemImage = "text.book.closed.fill"

case .libraryGamepads:
self.title = String(l10n.MainView.Sidebar.CategoryLabel.gamepads.characters)
self.systemImage = "gamecontroller.fill"
}
}

// swiftlint:enable cyclomatic_complexity body_length

// MARK: Internal

let category: Navigation.Category
Expand Down
23 changes: 23 additions & 0 deletions Apps/LekaApp/Sources/Views/MainView/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ struct MainView: View {
CategoryLabel(category: .vectorImageList)
CategoryLabel(category: .news)
}

Section("Library") {
CategoryLabel(category: .libraryCurriculums)
CategoryLabel(category: .libraryActivities)
CategoryLabel(category: .libraryStories)
CategoryLabel(category: .libraryGamepads)
}
} else {
Section("Demo mode") {
CategoryLabel(category: .demo)
Expand Down Expand Up @@ -173,6 +180,22 @@ struct MainView: View {
case .demo:
DiscoverLekaView(demoMode: self.navigation.demoMode)

case .libraryCurriculums:
Text("Curriculums")
.navigationTitle("Curriculums")

case .libraryActivities:
Text("Activities")
.navigationTitle("Activities")

case .libraryStories:
Text("Stories")
.navigationTitle("Stories")

case .libraryGamepads:
Text("Gamepads")
.navigationTitle("Gamepads")

case .none:
Text(l10n.MainView.Sidebar.CategoryLabel.home)
.font(.largeTitle)
Expand Down
3 changes: 3 additions & 0 deletions Apps/LekaApp/Sources/Views/Settings/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,12 @@ struct SettingsView: View {
@ObservedObject private var styleManager: StyleManager = .shared
@ObservedObject private var navigation = Navigation.shared

@StateObject private var rootAccountViewModel = RootAccountManagerViewModel()

private func reset() {
self.caregiverManager.resetData()
self.carereceiverManager.resetData()
self.rootAccountViewModel.resetData()
self.styleManager.accentColor = DesignKitAsset.Colors.lekaDarkBlue.swiftUIColor
self.styleManager.colorScheme = .light
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ struct CreateCarereceiverView: View {
}
}

Section {
LabeledContent(String(l10n.ReinforcerPicker.header.characters)) {
ReinforcerPicker(carereceiver: self.$newCarereceiver)
}
} footer: {
Text(l10n.ReinforcerPicker.description)
}

Button(String(l10n.CarereceiverCreation.createProfileButtonLabel.characters)) {
if self.newCarereceiver.avatar.isEmpty {
self.newCarereceiver.avatar = Avatars.categories.first!.avatars.randomElement()!
Expand Down
39 changes: 39 additions & 0 deletions Modules/AccountKit/Sources/Database/DatabaseOperations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,45 @@ public class DatabaseOperations {
return subject.eraseToAnyPublisher()
}

public func getCurrentRootAccount() -> AnyPublisher<RootAccount, Error> {
let subject = PassthroughSubject<RootAccount, Error>()

guard let currentUserID = Auth.auth().currentUser?.uid else {
subject.send(completion: .failure(DatabaseError.customError("User not authenticated")))
return subject.eraseToAnyPublisher()
}

if let existingListener = listenerRegistrations["ROOT_ACCOUNTS_\(currentUserID)"] {
existingListener.remove()
self.listenerRegistrations.removeValue(forKey: "ROOT_ACCOUNTS_\(currentUserID)")
}

let listener = self.database.collection(DatabaseCollection.rootAccounts.rawValue)
.whereField("root_owner_uid", isEqualTo: currentUserID)
.addSnapshotListener { querySnapshot, error in
if let error {
log.error("\(error.localizedDescription)")
subject.send(completion: .failure(error))
} else if let querySnapshot, let document = querySnapshot.documents.first {
do {
let rootAccount = try document.data(as: RootAccount.self)
log.info("Root account document fetched successfully for user \(currentUserID). 🎉")
subject.send(rootAccount)
} catch {
log.error("\(error.localizedDescription)")
subject.send(completion: .failure(error))
}
} else {
log.error("Root account document not found for user \(currentUserID).")
subject.send(completion: .failure(DatabaseError.documentNotFound))
}
}

self.listenerRegistrations["ROOT_ACCOUNTS_\(currentUserID)"] = listener

return subject.eraseToAnyPublisher()
}

public func clearAllListeners() {
for (_, registration) in self.listenerRegistrations {
registration.remove()
Expand Down
34 changes: 34 additions & 0 deletions Modules/AccountKit/Sources/Extensions/Library+Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import FirebaseFirestore
import SwiftUI

extension Library: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.id = try container.decodeIfPresent(String.self, forKey: .id)
self.rootOwnerUid = try container.decode(String.self, forKey: .rootOwnerUid)
self.savedActivities = try container.decodeIfPresent([SavedActivity].self, forKey: .savedActivities) ?? []
self.savedCurriculums = try container.decodeIfPresent([SavedCurriculum].self, forKey: .savedCurriculums) ?? []
self.savedStories = try container.decodeIfPresent([SavedStory].self, forKey: .savedStories) ?? []
self.savedGamepads = try container.decodeIfPresent([SavedGamepad].self, forKey: .savedGamepads) ?? []
self.createdAt = try container.decodeIfPresent(Timestamp.self, forKey: .createdAt)?.dateValue()
self.lastEditedAt = try container.decodeIfPresent(Timestamp.self, forKey: .lastEditedAt)?.dateValue()
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encodeIfPresent(self.id, forKey: .id)
try container.encode(self.rootOwnerUid, forKey: .rootOwnerUid)
try container.encode(self.savedActivities, forKey: .savedActivities)
try container.encode(self.savedCurriculums, forKey: .savedCurriculums)
try container.encode(self.savedStories, forKey: .savedStories)
try container.encode(self.savedGamepads, forKey: .savedGamepads)
try container.encodeIfPresent(self.createdAt.map { Timestamp(date: $0) }, forKey: .createdAt)
try container.encodeIfPresent(self.lastEditedAt.map { Timestamp(date: $0) }, forKey: .lastEditedAt)
}
}
16 changes: 16 additions & 0 deletions Modules/AccountKit/Sources/Extensions/RootAccount+Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import SwiftUI

public extension RootAccount {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decodeIfPresent(String.self, forKey: .id)
self.rootOwnerUid = try container.decode(String.self, forKey: .rootOwnerUid)
self.library = try container.decodeIfPresent(Library.self, forKey: .library) ?? Library()
self.createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt)
self.lastEditedAt = try container.decodeIfPresent(Date.self, forKey: .lastEditedAt)
}
}
28 changes: 28 additions & 0 deletions Modules/AccountKit/Sources/Extensions/SavedActivity+Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import FirebaseFirestore
import SwiftUI

extension SavedActivity: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.id = try container.decodeIfPresent(String.self, forKey: .id)
self.rootOwnerUid = try container.decode(String.self, forKey: .rootOwnerUid)
self.caregiverID = try container.decodeIfPresent(String.self, forKey: .caregiverID) ?? ""
self.createdAt = try container.decodeIfPresent(Timestamp.self, forKey: .createdAt)?.dateValue()
self.lastEditedAt = try container.decodeIfPresent(Timestamp.self, forKey: .lastEditedAt)?.dateValue()
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encodeIfPresent(self.id, forKey: .id)
try container.encode(self.rootOwnerUid, forKey: .rootOwnerUid)
try container.encode(self.caregiverID, forKey: .caregiverID)
try container.encodeIfPresent(self.createdAt.map { Timestamp(date: $0) }, forKey: .createdAt)
try container.encodeIfPresent(self.lastEditedAt.map { Timestamp(date: $0) }, forKey: .lastEditedAt)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import FirebaseFirestore
import SwiftUI

extension SavedCurriculum: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.id = try container.decodeIfPresent(String.self, forKey: .id)
self.rootOwnerUid = try container.decode(String.self, forKey: .rootOwnerUid)
self.caregiverID = try container.decodeIfPresent(String.self, forKey: .caregiverID) ?? ""
self.createdAt = try container.decodeIfPresent(Timestamp.self, forKey: .createdAt)?.dateValue()
self.lastEditedAt = try container.decodeIfPresent(Timestamp.self, forKey: .lastEditedAt)?.dateValue()
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encodeIfPresent(self.id, forKey: .id)
try container.encode(self.rootOwnerUid, forKey: .rootOwnerUid)
try container.encode(self.caregiverID, forKey: .caregiverID)
try container.encodeIfPresent(self.createdAt.map { Timestamp(date: $0) }, forKey: .createdAt)
try container.encodeIfPresent(self.lastEditedAt.map { Timestamp(date: $0) }, forKey: .lastEditedAt)
}
}
28 changes: 28 additions & 0 deletions Modules/AccountKit/Sources/Extensions/SavedGamepad+Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import FirebaseFirestore
import SwiftUI

extension SavedGamepad: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.id = try container.decodeIfPresent(String.self, forKey: .id)
self.rootOwnerUid = try container.decode(String.self, forKey: .rootOwnerUid)
self.caregiverID = try container.decodeIfPresent(String.self, forKey: .caregiverID) ?? ""
self.createdAt = try container.decodeIfPresent(Timestamp.self, forKey: .createdAt)?.dateValue()
self.lastEditedAt = try container.decodeIfPresent(Timestamp.self, forKey: .lastEditedAt)?.dateValue()
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encodeIfPresent(self.id, forKey: .id)
try container.encode(self.rootOwnerUid, forKey: .rootOwnerUid)
try container.encode(self.caregiverID, forKey: .caregiverID)
try container.encodeIfPresent(self.createdAt.map { Timestamp(date: $0) }, forKey: .createdAt)
try container.encodeIfPresent(self.lastEditedAt.map { Timestamp(date: $0) }, forKey: .lastEditedAt)
}
}
28 changes: 28 additions & 0 deletions Modules/AccountKit/Sources/Extensions/SavedStory+Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import FirebaseFirestore
import SwiftUI

extension SavedStory: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.id = try container.decodeIfPresent(String.self, forKey: .id)
self.rootOwnerUid = try container.decode(String.self, forKey: .rootOwnerUid)
self.caregiverID = try container.decodeIfPresent(String.self, forKey: .caregiverID) ?? ""
self.createdAt = try container.decodeIfPresent(Timestamp.self, forKey: .createdAt)?.dateValue()
self.lastEditedAt = try container.decodeIfPresent(Timestamp.self, forKey: .lastEditedAt)?.dateValue()
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encodeIfPresent(self.id, forKey: .id)
try container.encode(self.rootOwnerUid, forKey: .rootOwnerUid)
try container.encode(self.caregiverID, forKey: .caregiverID)
try container.encodeIfPresent(self.createdAt.map { Timestamp(date: $0) }, forKey: .createdAt)
try container.encodeIfPresent(self.lastEditedAt.map { Timestamp(date: $0) }, forKey: .lastEditedAt)
}
}
Loading

0 comments on commit 90b8330

Please sign in to comment.