update look and feel

main
Laurent 3 years ago
parent 2a89996d8f
commit 32bd299739
  1. 18
      LeCountdown/Stats/Stat.swift
  2. 10
      LeCountdown/Subscription/Store.swift
  3. 4
      LeCountdown/Utils/TimeInterval+Extensions.swift
  4. 3
      LeCountdown/Views/HomeView.swift
  5. 272
      LeCountdown/Views/PresetsView.swift
  6. 38
      LeCountdown/Views/Stats/GraphsView.swift
  7. 11
      LeCountdown/Views/Stats/RecordsView.swift
  8. 8
      LeCountdown/fr.lproj/Localizable.strings

@ -16,7 +16,7 @@ enum Stat: Int, CaseIterable {
var localizedName: String {
switch self {
case .count: return NSLocalizedString("Count", comment: "")
case .totalDuration: return NSLocalizedString("Duration", comment: "")
case .totalDuration: return NSLocalizedString("Total duration", comment: "")
case .averageDuration: return NSLocalizedString("Average duration", comment: "")
}
}
@ -56,14 +56,14 @@ enum Stat: Int, CaseIterable {
}
}
var calendarYUnit: Calendar.Component? {
switch self {
case .totalDuration, .averageDuration:
return .hour
default:
return nil
}
}
// var calendarYUnit: Calendar.Component? {
// switch self {
// case .totalDuration, .averageDuration:
// return .hour
// default:
// return nil
// }
// }
}

@ -8,19 +8,11 @@
import Foundation
import StoreKit
//public enum StoreError: Error {
// case failedVerification
//}
protocol StoreDelegate {
func productsReceived()
func errorDidOccur(error: Error)
}
//extension Notification.Name {
// static let StoreEventHappened = Notification.Name("storePurchaseSucceeded")
//}
class Store: ObservableObject {
@Published private(set) var products: [Product] = []
@ -52,8 +44,6 @@ class Store: ObservableObject {
@MainActor
func requestProducts() async {
do {
let currentPlan = AppGuard.main.currentPlan
let identifiers: [String] = [StorePlan.unlimited.rawValue]
products = try await Product.products(for: identifiers)
Logger.log("products = \(self.products.count)")

@ -9,6 +9,10 @@ import Foundation
extension TimeInterval {
var hourMinuteSecond: String {
return String(format:"%d:%02d:%02d", hour, minute, second)
}
var hourMinuteSecondHS: String {
let h = self.hour
if h > 1 {

@ -22,7 +22,7 @@ struct CompactHomeView: View {
var body: some View {
NavigationView {
NavigationStack {
TabView(selection: $tabSelection) {
PresetsView(tabSelection: $tabSelection)
@ -39,6 +39,7 @@ struct CompactHomeView: View {
.tabItem { Label("Stats", systemImage: "chart.bar.fill") }
.tag(2)
}
.navigationBarTitleDisplayMode(NavigationBarItem.TitleDisplayMode.large)
.tabViewStyle(.page(indexDisplayMode: .never))
}
.onAppear {

@ -7,6 +7,140 @@
import SwiftUI
class PresetModel : ObservableObject {
@Published var selectedPreset: Preset = Preset.hardBoiledEggs
}
struct PresetsView: View {
@Environment(\.managedObjectContext) private var viewContext
@StateObject var model: PresetModel = PresetModel()
@State var isPresented: Bool = false
@State var isShowingNewCountdown = false
@State var isShowingNewStopwatch = false
var tabSelection: Binding<Int>
fileprivate func _columnCount() -> Int {
return 2
// #if os(iOS)
// if UIDevice.isPhoneIdiom {
// return 2
// } else {
// return 3
// }
// #else
// return 3
// #endif
}
fileprivate func _columns() -> [GridItem] {
return (0..<self._columnCount()).map { _ in GridItem(spacing: 10.0) }
}
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 10.0) {
Button {
self.isShowingNewCountdown = true
} label: {
Text("Create countdown".uppercased())
.frame(maxWidth: .infinity)
.frame(height: 40.0)
}
Button {
self.isShowingNewStopwatch = true
} label: {
Text("Create stopwatch".uppercased())
.frame(maxWidth: .infinity)
.frame(height: 40.0)
}
}.padding(.horizontal).monospaced().buttonStyle(.bordered)
VStack(alignment: .leading) {
SeparatorView()
Text("Presets")
.font(.system(.title, weight: .heavy))
Text("You can edit the duration, sound and label before adding")
.foregroundColor(.gray)
.font(.callout)
}.padding(.horizontal)
LazyVGrid(
columns: self._columns(),
alignment: .leading,
spacing: 10.0
) {
ForEach(PresetSection.allCases) { section in
Section(section.localizedName.uppercased()) {
ForEach(section.presets) { preset in
Button {
self.model.selectedPreset = preset
self.isPresented = true
} label: {
TimerItemView(name: preset.localizedName, duration: preset.formattedDuration, sound: preset.soundTitle)
}
}
}
}
}.padding(.horizontal)
Spacer()
}
.sheet(isPresented: $isShowingNewStopwatch, content: {
NewStopwatchView(isPresented: $isShowingNewStopwatch, tabSelection: self.tabSelection)
.environment(\.managedObjectContext, viewContext)
})
.sheet(isPresented: $isShowingNewCountdown, content: {
NewCountdownView(isPresented: $isShowingNewCountdown, tabSelection: self.tabSelection)
.environment(\.managedObjectContext, viewContext)
})
.sheet(isPresented: $isPresented, content: {
CountdownEditView(isPresented: $isPresented, preset: self.model.selectedPreset, tabSelection: self.tabSelection)
.environment(\.managedObjectContext, viewContext)
})
.navigationTitle("Create")
}
}
struct TimerItemView: View {
var name: String
var duration: String
var sound: String
var body: some View {
HStack {
VStack(alignment: .leading) {
Text(self.name.uppercased())
Text(self.duration)
Text(self.sound.uppercased()).foregroundColor(Color(white: 0.7))
}.padding()
.multilineTextAlignment(.leading)
Spacer()
}.background(Color(white: 0.1))
.cornerRadius(16.0)
.monospaced()
.font(Font.system(size: 16.0, weight: .semibold))
.foregroundColor(Color.white)
}
}
enum PresetSection: Int, Identifiable, CaseIterable {
var id: Int { return self.rawValue }
@ -135,144 +269,6 @@ enum Preset: Int, Identifiable, CaseIterable {
}
class PresetModel : ObservableObject {
@Published var selectedPreset: Preset = Preset.hardBoiledEggs
}
struct PresetsView: View {
@Environment(\.managedObjectContext) private var viewContext
@StateObject var model: PresetModel = PresetModel()
@State var isPresented: Bool = false
@State var isShowingNewCountdown = false
@State var isShowingNewStopwatch = false
var tabSelection: Binding<Int>
fileprivate func _columnCount() -> Int {
return 2
// #if os(iOS)
// if UIDevice.isPhoneIdiom {
// return 2
// } else {
// return 3
// }
// #else
// return 3
// #endif
}
fileprivate func _columns() -> [GridItem] {
return (0..<self._columnCount()).map { _ in GridItem(spacing: 10.0) }
}
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 0.0) {
Button {
self.isShowingNewCountdown = true
} label: {
Text(".create countdown")
.font(.system(.title, weight: .heavy))
Spacer()
}.frame(height: 40.0)
Button {
self.isShowingNewStopwatch = true
} label: {
Text(".create stopwatch")
.font(.system(.title, weight: .heavy))
Spacer()
}.frame(height: 40.0)
SeparatorView()
Text("Presets")
.font(.system(.title, weight: .heavy))
Text("You can edit the duration, sound and label before adding")
.font(.callout)
}.padding(.horizontal)
LazyVGrid(
columns: self._columns(),
spacing: 10.0
) {
ForEach(PresetSection.allCases) { section in
Section {
ForEach(section.presets) { preset in
Button {
self.model.selectedPreset = preset
self.isPresented = true
} label: {
TimerItemView(name: preset.localizedName, duration: preset.formattedDuration, sound: preset.soundTitle)
}
}
} header: {
HStack {
Text(section.localizedName.uppercased())
Spacer()
}
}
}
}.padding(.horizontal)
Spacer()
}
.sheet(isPresented: $isShowingNewStopwatch, content: {
NewStopwatchView(isPresented: $isShowingNewStopwatch, tabSelection: self.tabSelection)
.environment(\.managedObjectContext, viewContext)
})
.sheet(isPresented: $isShowingNewCountdown, content: {
NewCountdownView(isPresented: $isShowingNewCountdown, tabSelection: self.tabSelection)
.environment(\.managedObjectContext, viewContext)
})
.sheet(isPresented: $isPresented, content: {
CountdownEditView(isPresented: $isPresented, preset: self.model.selectedPreset, tabSelection: self.tabSelection)
.environment(\.managedObjectContext, viewContext)
})
.navigationTitle("Create")
}
}
struct TimerItemView: View {
var name: String
var duration: String
var sound: String
var body: some View {
HStack {
VStack(alignment: .leading) {
Text(self.name.uppercased())
Text(self.duration)
Text(self.sound.uppercased()).foregroundColor(Color(white: 0.7))
}.padding()
.multilineTextAlignment(.leading)
Spacer()
}.background(Color(white: 0.1))
.cornerRadius(16.0)
.monospaced()
.font(Font.system(size: 16.0, weight: .semibold))
.foregroundColor(Color.white)
}
}
struct PresetsView_Previews: PreviewProvider {
static var previews: some View {
PresetsView(tabSelection: .constant(0))

@ -36,9 +36,7 @@ class StatModel: ObservableObject {
self.statValues = values
self.isComputing = false
}
}
}
}
@ -98,13 +96,13 @@ struct GraphView: View {
var timeFrame: TimeFrame
var body: some View {
VStack {
HStack {
Text(self.statValue.stat.localizedName.uppercased())
// .font(.footnote)
Text(self.statValue.formattedValue)
// .font(.system(.title, weight: .bold))
}
VStack(alignment: .leading) {
StatView(statValue: self.statValue)
// HStack {
// Text(self.statValue.stat.localizedName.uppercased())
// Text(self.statValue.formattedValue)
// }
Chart(self.statValue.chartPoint(timeFrame: self.timeFrame)) { point in
let stat: Stat = self.statValue.stat
@ -117,12 +115,34 @@ struct GraphView: View {
LineMark(x: .value("date", point.index),
y: .value("value", point.value.doubleValue))
}
}.chartXAxis(.hidden)
.chartYAxis {
AxisMarks() { value in
AxisValueLabel {
Text(self.statValue.stat.format(axisValue: value))
}
}
}.frame(height: 200.0)
}
}
}
fileprivate extension Stat {
func format(axisValue: AxisValue) -> String {
let text: String?
switch self {
case .count:
text = axisValue.as(Int.self)?.formatted()
case .totalDuration, .averageDuration:
text = axisValue.as(Double.self)?.hourMinuteSecond
}
return text ?? NSLocalizedString("Formatting failed", comment: "")
}
}
struct StatGraphView_Previews: PreviewProvider {
static let points: [Point] = [Point(date: Date(), value: 1),

@ -26,13 +26,10 @@ struct RecordsView: View {
let filters: [Filter]
var body: some View {
// Section {
ForEach(self.filters) { filter in
RecordsSectionView(activity: self.activity, filter: filter)
.environment(\.managedObjectContext, viewContext)
}
// }
ForEach(self.filters) { filter in
RecordsSectionView(activity: self.activity, filter: filter)
.environment(\.managedObjectContext, viewContext)
}
}
}

@ -1,8 +1,8 @@
/* No comment provided by engineer. */
".create countdown" = ".Créer un minuteur";
"Create countdown" = "Créer un minuteur";
/* No comment provided by engineer. */
".create stopwatch" = ".Créer un chrono";
"Create stopwatch" = "Créer un chrono";
/* No comment provided by engineer. */
"Activities" = "Activités";
@ -65,7 +65,7 @@
"Done" = "Sauver";
/* No comment provided by engineer. */
"Duration" = "Durée";
"Total duration" = "Durée totale";
/* No comment provided by engineer. */
"Edit" = "Editer";
@ -229,7 +229,7 @@
"You can ask Siri to create and launch countdowns and stopwatches" = "Vous pouvez demander à Siri de vous lancer les minuteurs et les chronos";
/* No comment provided by engineer. */
"You can edit the duration, sound and label before adding" = "Vous pouvez changer la durée, le son et le label avant l'ajout";
"You can edit the duration, sound and label before adding" = "Vous pourrez changer la durée, le son et le label avant l'ajout";
/* No comment provided by engineer. */
"You don't have any recorded activity yet" = "Vous n'avez pas encore d'activités enregistrées";

Loading…
Cancel
Save