Typography: Manrope headings, Inter body — plus norsk dag/dager pluralization
Manrope (variable wght, instanced at 600/700/800) for display/headline/ title roles; Inter static Regular/Medium/SemiBold for body/label. M3 baseline metrics retained — only family and weight change, so component layouts and accessibility text scaling are untouched. Both fonts are OFL (THIRD_PARTY_LICENSES.md added) with full æøå/µ coverage, verified by emulator screenshot. ScheduleText.daysCount fixes 'lager for 1 dager' spotted in that screenshot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
747a87a570
commit
9b99f2cf62
9 changed files with 63 additions and 3 deletions
13
THIRD_PARTY_LICENSES.md
Normal file
13
THIRD_PARTY_LICENSES.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Third-party licenses
|
||||||
|
|
||||||
|
## Fonts (bundled in `app/src/main/res/font/`)
|
||||||
|
|
||||||
|
- **Inter** (`inter_*.ttf`) — © The Inter Project Authors,
|
||||||
|
<https://github.com/rsms/inter>. Licensed under the SIL Open Font
|
||||||
|
License 1.1 (<https://openfontlicense.org>).
|
||||||
|
- **Manrope** (`manrope_variable.ttf`) — © The Manrope Project Authors,
|
||||||
|
distributed via <https://github.com/google/fonts/tree/main/ofl/manrope>.
|
||||||
|
Licensed under the SIL Open Font License 1.1.
|
||||||
|
|
||||||
|
Library licenses (Apache-2.0 and similar) are declared by their respective
|
||||||
|
artifacts via Gradle metadata.
|
||||||
|
|
@ -50,7 +50,7 @@ class SupplyCheckReceiver : BroadcastReceiver() {
|
||||||
for (med in meds) rate += ScheduleEngine.dailyConsumption(db.doseTimeDao().getForMed(med.med.id))
|
for (med in meds) rate += ScheduleEngine.dailyConsumption(db.doseTimeDao().getForMed(med.med.id))
|
||||||
if (ScheduleEngine.needsRefill(item.stockUnits, rate, item.lowStockLeadDays)) {
|
if (ScheduleEngine.needsRefill(item.stockUnits, rate, item.lowStockLeadDays)) {
|
||||||
val days = ScheduleEngine.daysOfSupply(item.stockUnits, rate)
|
val days = ScheduleEngine.daysOfSupply(item.stockUnits, rate)
|
||||||
lowStock += "${item.name}: lager for ${days?.toInt() ?: 0} dager"
|
lowStock += "${item.name}: lager for ${no.naiv.meddetsamme.domain.ScheduleText.daysCount(days?.toInt() ?: 0)}"
|
||||||
}
|
}
|
||||||
if (ScheduleEngine.needsRenewal(item.rxExpiryEpochDay, today, RX_LEAD_DAYS)) {
|
if (ScheduleEngine.needsRenewal(item.rxExpiryEpochDay, today, RX_LEAD_DAYS)) {
|
||||||
val expired = item.rxExpiryEpochDay!! < today.toEpochDay()
|
val expired = item.rxExpiryEpochDay!! < today.toEpochDay()
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ object ScheduleText {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** "1 dag", "3 dager" — norsk flertall. */
|
||||||
|
fun daysCount(days: Int): String = if (days == 1) "1 dag" else "$days dager"
|
||||||
|
|
||||||
/** "1 tablett", "2,5 ml" — norsk desimalkomma. */
|
/** "1 tablett", "2,5 ml" — norsk desimalkomma. */
|
||||||
fun amountText(amount: Double, unit: String): String {
|
fun amountText(amount: Double, unit: String): String {
|
||||||
val number = if (amount == amount.toLong().toDouble()) {
|
val number = if (amount == amount.toLong().toDouble()) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
|
@file:OptIn(androidx.compose.ui.text.ExperimentalTextApi::class)
|
||||||
|
|
||||||
package no.naiv.meddetsamme.ui
|
package no.naiv.meddetsamme.ui
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Typography
|
||||||
import androidx.compose.material3.darkColorScheme
|
import androidx.compose.material3.darkColorScheme
|
||||||
import androidx.compose.material3.dynamicDarkColorScheme
|
import androidx.compose.material3.dynamicDarkColorScheme
|
||||||
import androidx.compose.material3.dynamicLightColorScheme
|
import androidx.compose.material3.dynamicLightColorScheme
|
||||||
|
|
@ -10,6 +13,11 @@ import androidx.compose.material3.lightColorScheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.text.font.Font
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.font.FontVariation
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import no.naiv.meddetsamme.R
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* App theme: dynamic Material You colors on Android 12+ (follows the user's
|
* App theme: dynamic Material You colors on Android 12+ (follows the user's
|
||||||
|
|
@ -26,7 +34,43 @@ fun MedDetSammeTheme(content: @Composable () -> Unit) {
|
||||||
dark -> DarkScheme
|
dark -> DarkScheme
|
||||||
else -> LightScheme
|
else -> LightScheme
|
||||||
}
|
}
|
||||||
MaterialTheme(colorScheme = scheme, content = content)
|
MaterialTheme(colorScheme = scheme, typography = AppTypography, content = content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manrope for headings/titles (friendly, confident), Inter for body/labels
|
||||||
|
// (built for UI legibility at small sizes). Both OFL, full æøå/µ coverage.
|
||||||
|
private val Manrope = FontFamily(
|
||||||
|
Font(R.font.manrope_variable, FontWeight.SemiBold, variationSettings = FontVariation.Settings(FontVariation.weight(600))),
|
||||||
|
Font(R.font.manrope_variable, FontWeight.Bold, variationSettings = FontVariation.Settings(FontVariation.weight(700))),
|
||||||
|
Font(R.font.manrope_variable, FontWeight.ExtraBold, variationSettings = FontVariation.Settings(FontVariation.weight(800))),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val Inter = FontFamily(
|
||||||
|
Font(R.font.inter_regular, FontWeight.Normal),
|
||||||
|
Font(R.font.inter_medium, FontWeight.Medium),
|
||||||
|
Font(R.font.inter_semibold, FontWeight.SemiBold),
|
||||||
|
)
|
||||||
|
|
||||||
|
// M3 baseline metrics, only family/weight swapped — sizes and line heights
|
||||||
|
// are already tuned for the components.
|
||||||
|
private val AppTypography: Typography = Typography().let { base ->
|
||||||
|
Typography(
|
||||||
|
displayLarge = base.displayLarge.copy(fontFamily = Manrope, fontWeight = FontWeight.ExtraBold),
|
||||||
|
displayMedium = base.displayMedium.copy(fontFamily = Manrope, fontWeight = FontWeight.ExtraBold),
|
||||||
|
displaySmall = base.displaySmall.copy(fontFamily = Manrope, fontWeight = FontWeight.Bold),
|
||||||
|
headlineLarge = base.headlineLarge.copy(fontFamily = Manrope, fontWeight = FontWeight.Bold),
|
||||||
|
headlineMedium = base.headlineMedium.copy(fontFamily = Manrope, fontWeight = FontWeight.Bold),
|
||||||
|
headlineSmall = base.headlineSmall.copy(fontFamily = Manrope, fontWeight = FontWeight.Bold),
|
||||||
|
titleLarge = base.titleLarge.copy(fontFamily = Manrope, fontWeight = FontWeight.Bold),
|
||||||
|
titleMedium = base.titleMedium.copy(fontFamily = Manrope, fontWeight = FontWeight.SemiBold),
|
||||||
|
titleSmall = base.titleSmall.copy(fontFamily = Manrope, fontWeight = FontWeight.SemiBold),
|
||||||
|
bodyLarge = base.bodyLarge.copy(fontFamily = Inter),
|
||||||
|
bodyMedium = base.bodyMedium.copy(fontFamily = Inter),
|
||||||
|
bodySmall = base.bodySmall.copy(fontFamily = Inter),
|
||||||
|
labelLarge = base.labelLarge.copy(fontFamily = Inter, fontWeight = FontWeight.Medium),
|
||||||
|
labelMedium = base.labelMedium.copy(fontFamily = Inter, fontWeight = FontWeight.Medium),
|
||||||
|
labelSmall = base.labelSmall.copy(fontFamily = Inter, fontWeight = FontWeight.Medium),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Green-seeded Material 3 palette (seed ≈ launcher background #1B5E20).
|
// Green-seeded Material 3 palette (seed ≈ launcher background #1B5E20).
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ fun TodayScreen(nav: Nav) {
|
||||||
val rate = ratePerItem[item.id] ?: 0.0
|
val rate = ratePerItem[item.id] ?: 0.0
|
||||||
if (ScheduleEngine.needsRefill(item.stockUnits, rate, item.lowStockLeadDays)) {
|
if (ScheduleEngine.needsRefill(item.stockUnits, rate, item.lowStockLeadDays)) {
|
||||||
val days = ScheduleEngine.daysOfSupply(item.stockUnits, rate)?.toInt() ?: 0
|
val days = ScheduleEngine.daysOfSupply(item.stockUnits, rate)?.toInt() ?: 0
|
||||||
warn += "${item.name}: lager for $days dager"
|
warn += "${item.name}: lager for ${ScheduleText.daysCount(days)}"
|
||||||
}
|
}
|
||||||
if (ScheduleEngine.needsRenewal(item.rxExpiryEpochDay, today)) {
|
if (ScheduleEngine.needsRenewal(item.rxExpiryEpochDay, today)) {
|
||||||
warn += "${item.name}: resept må fornyes"
|
warn += "${item.name}: resept må fornyes"
|
||||||
|
|
|
||||||
BIN
app/src/main/res/font/inter_medium.ttf
Normal file
BIN
app/src/main/res/font/inter_medium.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/inter_regular.ttf
Normal file
BIN
app/src/main/res/font/inter_regular.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/inter_semibold.ttf
Normal file
BIN
app/src/main/res/font/inter_semibold.ttf
Normal file
Binary file not shown.
BIN
app/src/main/res/font/manrope_variable.ttf
Normal file
BIN
app/src/main/res/font/manrope_variable.ttf
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue