Last active
September 25, 2023 23:21
-
-
Save mattyoung/b76aa5447429a7ee7a88d63258c934a5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import ComposableArchitecture | |
struct CounterFeature: Reducer { | |
struct State: Equatable { | |
var count = 99 | |
var numberFactAlert: String? | |
} | |
enum Action: Equatable { | |
case decrementButtonTapped | |
case incrementButtonTapped | |
} | |
func reduce(into state: inout State, action: Action) -> Effect<Action> { | |
switch action { | |
case .decrementButtonTapped: | |
state.count -= 1 | |
return .none | |
case .incrementButtonTapped: | |
state.count += 1 | |
return .none | |
} | |
} | |
} | |
struct SymbolButtonStyle: ButtonStyle { | |
func makeBody(configuration: Configuration) -> some View { | |
configuration.label | |
.symbolVariant(.circle.fill) | |
.foregroundStyle(.white) | |
.padding(15) | |
.background( | |
RoundedRectangle(cornerRadius: 15, style: .continuous) | |
.fill(.tint) | |
) | |
.scaleEffect(configuration.isPressed ? 0.95 : 1.0) | |
} | |
} | |
extension ButtonStyle where Self == SymbolButtonStyle { | |
static var symbolButtonStyle: Self { | |
SymbolButtonStyle() | |
} | |
} | |
// MARK - CounterView | |
struct CounterView: View { | |
let store: StoreOf<CounterFeature> | |
let accentColor = Color.pink | |
let counterFont = Font.custom("Digital-7Monoitalic", fixedSize: 45).monospacedDigit() | |
let clockFont = Font.custom("Digital-7Monoitalic", fixedSize: 215).monospacedDigit() | |
var body: some View { | |
WithViewStore(self.store, observe: { $0 }) { store in | |
VStack(spacing: 5) { | |
TimelineView(.periodic(from: .now, by: 0.2)) { context in | |
// this does 24-hour style. Who figured this out? | |
// https://forums.swift.org/t/new-date-formatstyle-anyway-to-do-24-hour/52994/34 | |
Text(context.date, | |
format: Date.VerbatimFormatStyle(format: "\(hour: .twoDigits(clock: .twentyFourHour, hourCycle: .oneBased)):\(minute: .twoDigits):\(second: .twoDigits)", | |
timeZone: .current, | |
calendar: .current) | |
) | |
.font(clockFont) | |
.lineLimit(1) | |
.padding(.horizontal, 20) | |
.minimumScaleFactor(0.2) | |
.foregroundColor(accentColor) | |
.contentTransition(.numericText(value: context.date.timeIntervalSince1970.rounded())) | |
.animation(.spring, value: context.date.timeIntervalSince1970) | |
} | |
HStack(spacing: 15) { | |
Button { | |
store.send(.decrementButtonTapped, animation: .spring) | |
} label: { | |
Image(systemName: "minus") | |
.font(counterFont) | |
} | |
.buttonStyle(.symbolButtonStyle) | |
.buttonRepeatBehavior(.enabled) | |
.sensoryFeedback(.decrease, trigger: store.count) | |
counterDisplay(store: store) | |
Button { | |
store.send(.incrementButtonTapped, animation: .spring) | |
} label: { | |
Image(systemName: "plus") | |
.font(counterFont) | |
} | |
.buttonStyle(.symbolButtonStyle) | |
.buttonRepeatBehavior(.enabled) | |
.sensoryFeedback(.increase, trigger: store.count) | |
} | |
.padding(.horizontal) | |
} | |
} | |
} | |
func counterDisplay(store: ViewStore<CounterFeature.State, CounterFeature.Action>) -> some View { | |
// Use this view for sizing | |
Text("0,000") | |
.font(counterFont) | |
.lineLimit(1) | |
.foregroundColor(.gray) | |
.opacity(0.25) | |
.overlay { | |
Text(store.count, format: .number) | |
.font(counterFont) | |
.foregroundColor(accentColor) | |
.frame(maxWidth: .infinity, alignment: .trailing) | |
.contentTransition(.numericText(value: Double(store.count))) | |
} | |
.padding(.init(top: 15, leading: 20, bottom: 15, trailing: 20)) | |
.background { | |
RoundedRectangle(cornerRadius: 20, style: .continuous) | |
.strokeBorder(accentColor, lineWidth: 2) | |
} | |
} | |
} | |
#Preview { | |
CounterView( | |
store: Store(initialState: CounterFeature.State()) { | |
CounterFeature() | |
} | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment