Files
KisaniCal/KisaniCal/Views/SplashView.swift
kutesir 87c999c676 Today menu features, Matrix Move trim, widget auto-advance, Wenza logo (KC-23–26)
- Today ⋯ menu: implemented the placeholder actions.
  - Background: 5 selectable themes (Default/Warm/Cool/Mono/Paper), persisted.
  - Group & Sort: group by Date (default)/Priority/Category/Quadrant and sort by
    Smart/Due/Priority/Title; non-date groupings render via UpcomingSection.
  - Select: multi-select sheet with Select All/Deselect All and bulk
    Complete/Priority/Move/Delete.
  New isolated file TodayMenuFeatures.swift; added TaskViewModel.allActiveRows.
- Matrix "Move" submenu now lists only the other three quadrants (excludes the
  current one) using clear matrix labels.
- Event Countdown (Bars) widget auto-advances: each timeline entry re-resolves
  "nearest to finish" as of its own time and refreshes at the moment the current
  event expires, so it rolls to the next event on expiry/completion.
- Splash wordmark rebranded to "wenza." (regular-weight typewriter + orange dot).
- ISSUES.md: logged KC-23 (Pick Date + time-based reminders), KC-24 (Wenza
  rebrand), KC-25 (Move trim), KC-26 (widget auto-advance).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 19:53:14 +03:00

97 lines
3.0 KiB
Swift

import SwiftUI
// MARK: - Splash View
struct SplashView: View {
@Environment(\.colorScheme) private var cs
var onDismiss: () -> Void
@State private var iconScale: CGFloat = 0.82
@State private var iconOpacity: Double = 0
@State private var markOpacity: Double = 0
@State private var splashOpacity: Double = 1
var body: some View {
ZStack {
AppColors.background(cs).ignoresSafeArea()
VStack(spacing: 18) {
CalendarBadgeIcon()
.scaleEffect(iconScale)
.opacity(iconOpacity)
// wenza. single line, orange dot
HStack(spacing: 0) {
Text("wenza")
.font(AppFonts.mono(22, weight: .regular))
.foregroundColor(AppColors.text(cs))
Text(".")
.font(AppFonts.mono(22, weight: .bold))
.foregroundColor(AppColors.accent)
}
.opacity(markOpacity)
}
}
.opacity(splashOpacity)
.onAppear {
withAnimation(.spring(response: 0.5, dampingFraction: 0.76).delay(0.08)) {
iconScale = 1
iconOpacity = 1
}
withAnimation(.easeOut(duration: 0.3).delay(0.3)) {
markOpacity = 1
}
withAnimation(.easeIn(duration: 0.28).delay(1.6)) {
splashOpacity = 0
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1.95) {
onDismiss()
}
}
}
}
// MARK: - Calendar Badge Icon
private struct CalendarBadgeIcon: View {
@Environment(\.colorScheme) private var cs
private static let cal = Calendar.current
private static var day: Int { cal.component(.day, from: Date()) }
private static var month: String {
let f = DateFormatter(); f.dateFormat = "MMM"
return f.string(from: Date()).uppercased()
}
var body: some View {
VStack(spacing: 0) {
// Month strip
Text(Self.month)
.font(AppFonts.mono(11, weight: .bold))
.foregroundColor(.white)
.kerning(1.5)
.frame(maxWidth: .infinity)
.frame(height: 28)
.background(AppColors.accent)
// Day number
Text("\(Self.day)")
.font(AppFonts.mono(42, weight: .bold))
.foregroundColor(AppColors.text(cs))
.frame(maxWidth: .infinity)
.frame(height: 56)
.background(AppColors.surface(cs))
}
.frame(width: 88)
.clipShape(RoundedRectangle(cornerRadius: 18))
.overlay(
RoundedRectangle(cornerRadius: 18)
.stroke(AppColors.border(cs), lineWidth: 1)
)
.shadow(
color: Color.black.opacity(cs == .dark ? 0.28 : 0.08),
radius: 20, y: 6
)
}
}