Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hugo/feature/Update Settings #604

Merged
merged 8 commits into from
Jan 24, 2024
1,290 changes: 879 additions & 411 deletions Apps/LekaApp/Resources/Localizable.xcstrings

Large diffs are not rendered by default.

9 changes: 3 additions & 6 deletions Apps/LekaApp/Sources/MainApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,20 @@ import SwiftUI
struct LekaApp: App {
@Environment(\.colorScheme) var colorScheme

@StateObject var viewRouter = ViewRouterDeprecated()
@StateObject var styleManager: StyleManager = .init()
@ObservedObject var styleManager: StyleManager = .shared
@ObservedObject var rootOwnerViewModel = RootOwnerViewModel.shared

var body: some Scene {
WindowGroup {
MainView()
.tint(self.styleManager.accentColor)
.preferredColorScheme(self.styleManager.colorScheme)
.environmentObject(self.styleManager)
.environmentObject(self.viewRouter)
.onAppear {
self.styleManager.setDefaultColorScheme(self.colorScheme)
}
.fullScreenCover(isPresented: self.$rootOwnerViewModel.isWelcomeViewPresented) {
WelcomeView()
}
.tint(self.styleManager.accentColor)
.preferredColorScheme(self.styleManager.colorScheme)
}
}
}
45 changes: 25 additions & 20 deletions Apps/LekaApp/Sources/_NEWCodeBase/Views/MainView/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ import LocalizationKit
import RobotKit
import SwiftUI

extension Bundle {
static var version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
static var buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String
}

// MARK: - MainView

struct MainView: View {
@EnvironmentObject var styleManager: StyleManager

@ObservedObject var navigation: Navigation = .shared
@ObservedObject var rootOwnerViewModel: RootOwnerViewModel = .shared
@StateObject var viewModel: ViewModel = .init()

var body: some View {
Expand Down Expand Up @@ -43,28 +47,27 @@ struct MainView: View {
CategoryLabel(category: .remotes)
CategoryLabel(category: .stories)
}

HStack {
Spacer()
VStack(spacing: 20) {
Button {
self.rootOwnerViewModel.isSettingsViewPresented = true
} label: {
SettingsLabel()
}

Text("My Leka App - Version \(Bundle.version!) (\(Bundle.buildNumber!))")
.foregroundColor(.gray)
.font(.caption2)
}
Spacer()
}
}
// TODO: (@ladislas) remove if not necessary
// .disabled(navigation.disableUICompletly)
.navigationTitle(String(l10n.MainView.Sidebar.navigationTitle.characters))
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button {
self.styleManager.toggleAccentColor()
} label: {
Image(systemName: "eyedropper")
}
}

ToolbarItem(placement: .topBarTrailing) {
Button {
self.styleManager.toggleColorScheme()
} label: {
Image(systemName: "circle.lefthalf.filled")
}
}
}
} detail: {
NavigationStack(path: self.$navigation.path) {
switch self.navigation.selectedCategory {
Expand Down Expand Up @@ -106,11 +109,13 @@ struct MainView: View {
.fullScreenCover(isPresented: self.$viewModel.isRobotConnectionPresented) {
RobotConnectionView(viewModel: RobotConnectionViewModel())
}
.sheet(isPresented: self.$rootOwnerViewModel.isSettingsViewPresented) {
SettingsView()
}
}
}

#Preview {
MainView()
.previewInterfaceOrientation(.landscapeLeft)
.environmentObject(StyleManager())
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ class RootOwnerViewModel: ObservableObject {

@Published var currentCompany = Company(email: "", password: "", caregivers: [], carereceivers: [])
@Published var isWelcomeViewPresented = true
@Published var isSettingsViewPresented = false

@Published var showConfirmDisconnection: Bool = false
@Published var showConfirmDeleteAccount: Bool = false

var isCompanyConnected: Bool {
!self.currentCompany.email.isEmpty && !self.currentCompany.password.isEmpty
}

func disconnect() {
self.currentCompany = Company(email: "", password: "", caregivers: [], carereceivers: [])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import DesignKit
import LocalizationKit
import RobotKit
import SwiftUI

// MARK: - SettingsLabel

struct SettingsLabel: View {
// MARK: Internal

var body: some View {
Label(String(l10n.SettingsLabel.buttonLabel.characters), systemImage: "gear")
.frame(width: 200, height: 44)
.background(self.backgroundColor, in: RoundedRectangle(cornerRadius: 10, style: .continuous))
.contentShape(Rectangle())
}

// MARK: Private

private let backgroundColor: Color = .init(light: UIColor.white, dark: UIColor.systemGray5)
}

// MARK: - l10n.SettingsLabel

extension l10n {
enum SettingsLabel {
static let buttonLabel = LocalizedString("lekaapp.settings_label.title", value: "Settings", comment: "Settings button label")
}
}

#Preview {
SettingsLabel()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import LocalizationKit
import SwiftUI

// swiftlint:disable line_length

// MARK: - SettingsView.AccountSection

extension SettingsView {
struct AccountSection: View {
@ObservedObject var rootOwnerViewModel: RootOwnerViewModel = .shared

var body: some View {
Section("") {
Group {
Button {
self.rootOwnerViewModel.showConfirmDisconnection.toggle()
} label: {
Text(l10n.SettingsView.AccountSection.LogOut.buttonLabel)
.foregroundColor(.accentColor)
}

Button(role: .destructive) {
self.rootOwnerViewModel.showConfirmDeleteAccount.toggle()
} label: {
Text(l10n.SettingsView.AccountSection.DeleteAccount.buttonLabel)
}
}
}
.alert(String(l10n.SettingsView.AccountSection.LogOut.alertTitle.characters), isPresented: self.$rootOwnerViewModel.showConfirmDisconnection) {
Button(role: .destructive) {
self.rootOwnerViewModel.isSettingsViewPresented = false
self.rootOwnerViewModel.currentCompany = Company(email: "", password: "")
} label: {
Text(l10n.SettingsView.AccountSection.LogOut.alertButtonLabel)
}
} message: {
Text(l10n.SettingsView.AccountSection.LogOut.alertMessage)
}
.alert(String(l10n.SettingsView.AccountSection.DeleteAccount.alertTitle.characters), isPresented: self.$rootOwnerViewModel.showConfirmDeleteAccount) {
Button(role: .destructive) {
// TODO: (@team) - Replace w/ real implementation
self.rootOwnerViewModel.isSettingsViewPresented = false
self.rootOwnerViewModel.currentCompany = Company(email: "", password: "")
} label: {
Text(l10n.SettingsView.AccountSection.DeleteAccount.alertButtonLabel)
}
} message: {
Text(l10n.SettingsView.AccountSection.DeleteAccount.alertMessage)
}
}
}
}

// swiftlint:enable line_length

#Preview {
SettingsView.AccountSection()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import DesignKit
import LocalizationKit
import SwiftUI

// swiftlint:disable nesting

// MARK: - SettingsView.AppearanceSection.AccentColorRow

extension SettingsView.AppearanceSection {
struct AccentColorRow: View {
// MARK: Internal

// MARK: - ColorCircleView

struct ColorCircleView: View {
let color: Color
let isSelected: Bool

var body: some View {
VStack {
Circle()
.fill(self.color)
.frame(width: 25)
.overlay(Circle().fill(self.isSelected ? .white : .clear).frame(width: 8))
.overlay(Circle().stroke(.gray, lineWidth: 0.5))
}
.animation(.easeIn, value: self.isSelected)
}
}

@ObservedObject var styleManager: StyleManager = .shared

var body: some View {
HStack {
Text(l10n.SettingsView.AppearanceSection.AccentColorRow.title)

Spacer()

ForEach(self.colors, id: \.self) { color in
ColorCircleView(color: color, isSelected: self.selectedColor == color)
.onTapGesture {
self.styleManager.accentColor = color
}
}
}
}

// MARK: Private

private let colors: [Color] = [DesignKitAsset.Colors.lekaDarkBlue.swiftUIColor, .blue, .purple, .red, .orange, .yellow, .green, .gray]

private var selectedColor: Color {
self.styleManager.accentColor ?? .clear
}
}
}

// swiftlint:enable nesting

#Preview {
Form {
SettingsView.AppearanceSection.AccentColorRow()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import DesignKit
import LocalizationKit
import SwiftUI

// MARK: - SettingsView.AppearanceSection

extension SettingsView.AppearanceSection {
struct AppearanceRow: View {
// MARK: Internal

@ObservedObject var styleManager: StyleManager = .shared

var body: some View {
HStack(spacing: 10) {
Text(l10n.SettingsView.AppearanceSection.AppearanceRow.title)

Spacer()

Toggle("", isOn: Binding(
get: { self.styleManager.colorScheme == .dark },
set: { self.styleManager.colorScheme = $0 ? .dark : .light }
))
}
}

// MARK: Private

private var selectedColorScheme: ColorScheme {
self.styleManager.colorScheme
}
}
}

#Preview {
Form {
SettingsView.AppearanceSection()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import DesignKit
import LocalizationKit
import SwiftUI

// MARK: - SettingsView.AppearanceSection

extension SettingsView {
struct AppearanceSection: View {
var body: some View {
Section(String(l10n.SettingsView.AppearanceSection.header.characters)) {
AppearanceRow()
AccentColorRow()
}
}
}
}

#Preview {
Form {
SettingsView.AppearanceSection()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Leka - iOS Monorepo
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

import LocalizationKit
import SwiftUI

// MARK: - SettingsView.CredentialsSection

extension SettingsView {
struct CredentialsSection: View {
@ObservedObject var rootOwnerViewModel: RootOwnerViewModel = .shared

var body: some View {
Section(String(l10n.SettingsView.CredentialsSection.header.characters)) {
LabeledContent {
Text(self.rootOwnerViewModel.currentCompany.email)
// TODO: (@ui/ux) - Design System - replace with Leka font
.font(.footnote)
.multilineTextAlignment(.leading)
} label: {
Text(l10n.SettingsView.CredentialsSection.emailLabel)
}

Text(l10n.SettingsView.CredentialsSection.changeCredentialsButtonLabel)
.foregroundColor(.accentColor)
}
}
}
}

#Preview {
Form {
SettingsView.CredentialsSection()
}
}
Loading
Loading