qwen3.6:35b's first attempt, does not compile (yet).

This commit is contained in:
me committed 2026-11-02 15:28:46 -07:00
1 parent eeda4a18c5
commit 337403721b
17 files changed
+1486 -40

No files matched your search

+166
View File
@@ -0,0 +1,166 @@
package com.hyperling.weather
import androidx.compose.ui.graphics.Color
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
/**
* The 8 positions on the Celtic Season Wheel.
* Based on solar events arranged clockwise starting from Summer at top (12 o'clock).
*/
enum class Season(
val label: String,
val fullName: String,
val color: Color,
/**
* Start of season expressed as month (1-12) and day (1-31).
* Used for the hand pointer position.
*/
val startMonth: Int,
val startDay: Int,
) {
// Summer solstice area - top of wheel (12 o'clock = 0 degrees in Compose arc coords)
SUMMER1("V1", "Summer Cross Quarter to Fall Equinox", Color(0xFFFBBC04), 6, 21),
SUMMER2("V2", "Fall Equinox to Winter Solstice (early)", Color(0xFFFF8F00), 8, 1),
FALL1("F1", "Fall Equinox to Fall Cross Quarter", Color(0xFFE65100), 9, 21),
FALL2("F2", "Winter Solstice to Winter Cross Quarter (early)", Color(0xFF6D4C41), 11, 1),
WINTER1("W1", "Winter Cross Quarter to Spring Equinox (late)", Color(0xFF546E7A), 12, 21),
WINTER2("W2", "Spring Equinox to Summer Solstice (early)", Color(0xFF37474F), 2, 1),
SPRING1("S1", "Summer Cross Quarter to Fall Equinox", Color(0xFF4CAF50), 3, 21),
SPRING2("S2", "Cross Quarter to Summer Solstice", Color(0xFF81C784), 5, 1);
companion object {
val All = values()
val Segments = All.size // 8
/**
* Get the current season based on today's date.
*/
fun current(): Season {
val calendar = java.util.Calendar.getInstance()
val month = calendar.get(java.util.Calendar.MONTH) + 1 // 1-12
val day = calendar.get(java.util.Calendar.DAY_OF_MONTH)
return All.find { season ->
val startStart = season.startMonth * 100 + season.startDay
// Calculate end as next season's start
val idx = season.ordinal
val nextSeason = if (idx < All.size - 1) All[idx + 1] else All[0]
val endStart = nextSeason.startMonth * 100 + nextSeason.startDay
val currentPos = month * 100 + day
when {
startStart <= endStart ->
currentPos in startStart..endStart
else ->
currentPos >= startStart || currentPos <= endStart
}
} ?: SPRING1
}
/**
* Get the hand angle (in radians) for the current date.
* 0 radians = top of wheel (Summer Solstice), increasing clockwise.
*/
fun handAngle(): Double {
val calendar = java.util.Calendar.getInstance()
val month = calendar.get(java.util.Calendar.MONTH) + 1
val day = calendar.get(java.util.Calendar.DAY_OF_MONTH)
// Calculate which season we're in and how far through it
val currentSeason = current()
val idx = currentSeason.ordinal
val nextIdx = (idx + 1) % All.size
val nextSeason = All[nextIdx]
val startPos = currentSeason.startMonth * 100 + currentSeason.startDay
val endPos = nextSeason.startMonth * 100 + nextSeason.startDay
// Handle year wrap for seasons that cross January
var totalDays = if (endPos > startPos) {
daysBetween(currentSeason.startMonth, currentSeason.startDay,
nextSeason.startMonth, nextSeason.startDay)
} else {
// Crosses year boundary
val daysInCurrentMonth = daysInMonth(currentSeason.startMonth, currentSeason.startDay)
val daysRemaining = daysInCurrentMonth - currentSeason.startDay + 1
val daysFromStartNext = nextSeason.startMonth * 30 + nextSeason.startDay - 15
daysRemaining + daysFromStartNext
}
if (totalDays <= 0) totalDays = 90 // fallback
val currentPos = month * 100 + day
var elapsedDays: Int
if (endPos > startPos) {
elapsedDays = daysBetween(currentSeason.startMonth, currentSeason.startDay, month, day)
} else {
val daysInCurrentMonth = daysInMonth(currentSeason.startMonth, 1)
elapsedDays = (daysInCurrentMonth - currentSeason.startDay + 1) + (day - 1)
}
if (elapsedDays < 0) elapsedDays = 0
val fraction = elapsedDays.toDouble() / totalDays.coerceAtLeast(1)
// Map to angle: 0 at top (Summer Solstice), clockwise
return fraction * 2 * PI
}
private fun daysInMonth(month: Int, day: Int): Int {
val cal = java.util.Calendar.getInstance().apply {
set(java.util.Calendar.MONTH, month - 1)
}
return cal.getActualMaximum(java.util.Calendar.DAY_OF_MONTH)
}
private fun daysBetween(m1: Int, d1: Int, m2: Int, d2: Int): Int {
val start = java.util.GregorianCalendar(2024, m1 - 1, d1).timeInMillis
val end = java.util.GregorianCalendar(2024, m2 - 1, d2).timeInMillis
return ((end - start) / (1000 * 60 * 60 * 24)).toInt()
}
/**
* Get the angle for a season's center on the wheel.
* 0 radians = top of wheel, increasing clockwise.
*/
fun angleFor(idx: Int): Double {
return (idx.toDouble() / Segments) * 2 * PI
}
/**
* Get the sweep angle for each wedge (360 degrees / 8 = 45 degrees).
*/
val wedgeSweep: Double
get() = 2 * PI / Segments
}
}
/**
* Color palette for the Celtic Wheel UI.
*/
object SeasonColors {
val Background = Color(0xFF1A1A2E)
val CenterBg = Color(0xFF16213E)
val TextPrimary = Color(0xFFFFFFFF)
val TextSecondary = Color(0xFFB0BEC5)
val Divider = Color(0xFF37474F)
val Shadow = Color(0x4D000000)
}
/**
* Current date/time info for the wheel hand.
*/
data class HandInfo(
val dayOfYear: Int,
val totalDaysInYear: Int,
val fractionThroughSeason: Double,
val currentSeason: Season
) {
val angle: Double
get() = (dayOfYear.toDouble() / totalDaysInYear) * 2 * Math.PI
}