Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/settings/editor/settingsBlueprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,11 @@ export const settingsBlueprint: SettingsCategory<typeof defaultSettings> = {
description: 'The background color of the widget.',
type: SettingsValueType.COLOR,
},
liquidGlass: {
title: '🪟 Liquid Glass Mode',
description: 'Use slightly transparent backgrounds for better readability on iOS "Clear" homescreens (iOS 26).',
type: SettingsValueType.ON_OFF,
},
},
},
debugSettings: {
Expand Down
1 change: 1 addition & 0 deletions src/settings/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export const defaultSettings = {
fontSize: 14,
footer: true,
backgroundColor: unparsedColors.background.tertiary,
liquidGlass: false,
},

debugSettings: {
Expand Down
69 changes: 64 additions & 5 deletions src/utils/scriptable/componentHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,20 @@ export function addBreak(
showToTime: boolean,
widgetConfig: Settings
) {
// Liquid Glass
const __liquidItemColors = getItemColors(colors.background.primary, widgetConfig, false)
const breakContainer = makeTimelineEntry(to, breakFrom, widgetConfig, {
backgroundColor: colors.background.primary,
backgroundColor: __liquidItemColors.backgroundColor,
showTime: true,
showToTime: showToTime,
toTime: breakTo,
})

breakContainer.cornerRadius = widgetConfig.appearance.cornerRadius

const breakTitle = breakContainer.addText('Break')
breakTitle.font = Font.mediumSystemFont(widgetConfig.appearance.fontSize)
breakTitle.textColor = colors.text.secondary
breakTitle.textColor = __liquidItemColors.secondaryTextColor
breakContainer.addSpacer()
}

Expand Down Expand Up @@ -114,7 +119,7 @@ function makeTimelineEntry(
return lessonContainer
}

function getLessonColors(lesson: TransformedLesson) {
function getLessonColors(lesson: TransformedLesson, widgetConfig: Settings) {
/** Whether the lesson was rescheduled away from here. (isSource)
* The lesson state seems to be CANCELED? */
const isRescheduledAway = lesson.rescheduleInfo?.isSource
Expand All @@ -136,9 +141,63 @@ function getLessonColors(lesson: TransformedLesson) {
secondaryTextColor = colors.text.red
}

// Liquid Glass override
try {
const liquid = !!(widgetConfig && widgetConfig.appearance && widgetConfig.appearance.liquidGlass)
if (liquid) {
// For normal lessons use a slight translucent overlay that adapts to appearance:
// light appearance white 30% overlay, dark appearance black 30% overlay
if (lesson.state !== LessonState.CANCELED && lesson.state !== LessonState.FREE && !isRescheduledAway) {
backgroundColor = Color.dynamic(new Color('#ffffff', 0.30), new Color('#000000', 0.30))
// Ensure high contrast text colors
textColor = Color.dynamic(new Color('#000000'), new Color('#ffffff'))
secondaryTextColor = Color.dynamic(new Color('#666666'), new Color('#999999'))
} else {
// For cancelled/free/rescheduled keep disabled look but ensure contrast
textColor = colors.text.disabled
secondaryTextColor = colors.text.disabled
backgroundColor = colors.background.primary
}
}
} catch (e) {
// if something fails, fall back to default colors
console.warn('Liquid Glass override failed: ' + e)
}

return { backgroundColor, textColor, secondaryTextColor }
}

/**
* Generic color helper that applies the Liquid Glass override when enabled.
* baseBackgroundColor: the original background color that would have been used (may be null)
* widgetConfig: the widget configuration object
* disabled: whether the item should be shown as disabled (uses disabled text/background)
*/
export function getItemColors(baseBackgroundColor: Color, widgetConfig: Settings, disabled = false) {
let backgroundColor = baseBackgroundColor ?? colors.background.primary
let textColor = colors.text.primary
let secondaryTextColor = colors.text.secondary
if (disabled) {
backgroundColor = colors.background.primary
textColor = colors.text.disabled
secondaryTextColor = colors.text.disabled
}
// Liquid Glass override (same approach as lessons)
try {
const liquid = !!(widgetConfig && widgetConfig.appearance && widgetConfig.appearance.liquidGlass)
if (liquid && !disabled) {
// translucent overlay that adapts to appearance
backgroundColor = Color.dynamic(new Color('#ffffff', 0.30), new Color('#000000', 0.30))
// high contrast text colors
textColor = Color.dynamic(new Color('#000000'), new Color('#ffffff'));
secondaryTextColor = Color.dynamic(new Color('#666666'), new Color('#999999'))
}
} catch (e) {
console.warn('getItemColors Liquid Glass override failed: ' + e)
}
return { backgroundColor, textColor, secondaryTextColor }
}

/**
* Adds a lesson to the widget. This includes its subject, additional info (as an icon) and the time.
* The state is also shown as through colors. (canceled, event)
Expand All @@ -162,7 +221,7 @@ export function addWidgetLesson(
}
) {
// get the colors for the lesson based on its state (red, disabled, normal)
const { backgroundColor, textColor, secondaryTextColor } = getLessonColors(lesson)
const { backgroundColor, textColor, secondaryTextColor } = getLessonColors(lesson, widgetConfig)

// consider breaks during the combined lesson
let toTime = lesson.to
Expand Down Expand Up @@ -253,7 +312,7 @@ export function addWidgetLesson(
* @param widgetConfig
*/
export function fillContainerWithSubject(lesson: TransformedLesson, container: WidgetStack, widgetConfig: Settings) {
const { backgroundColor, textColor, secondaryTextColor } = getLessonColors(lesson)
const { backgroundColor, textColor, secondaryTextColor } = getLessonColors(lesson, widgetConfig)

container.backgroundColor = backgroundColor
container.layoutHorizontally()
Expand Down
13 changes: 8 additions & 5 deletions src/views/absences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Duration } from '@/utils/duration'
import { getCharHeight } from '@/utils/helper'
import { StaticLayoutRow } from '@/utils/scriptable/layout/staticLayoutRow'
import { ViewBuildData } from '@/widget'
import { getItemColors } from '@/utils/scriptable/componentHelper'

export function addViewAbsences(
absences: TransformedAbsence[],
Expand Down Expand Up @@ -37,7 +38,9 @@ export function addViewAbsences(
absenceContainer.layoutHorizontally()
absenceContainer.setPadding(padding, padding, padding, padding)
absenceContainer.spacing = widgetConfig.appearance.spacing
absenceContainer.backgroundColor = colors.background.primary
const __liquidItemColors = getItemColors(colors.background.primary, widgetConfig, absence.isExcused);
absenceContainer.backgroundColor = __liquidItemColors.backgroundColor
const textColor = __liquidItemColors.textColor
absenceContainer.cornerRadius = widgetConfig.appearance.cornerRadius

const shortFromDate = absence.from.toLocaleDateString(LOCALE, { day: '2-digit', month: 'short' })
Expand All @@ -58,7 +61,7 @@ export function addViewAbsences(
widgetConfig.appearance.spacing,
Font.mediumSystemFont(widgetConfig.appearance.fontSize),
widgetConfig.appearance.fontSize,
colors.text.primary
textColor
)

/**
Expand All @@ -77,14 +80,14 @@ export function addViewAbsences(
type: 'icon',
icon: 'pills.circle',
size: widgetConfig.appearance.fontSize,
color: colors.text.primary,
color: textColor,
priority: 1,
})

// add the absence date
staticLayoutRow.addItem({
type: 'text',
color: colors.text.secondary,
color: __liquidItemColors.secondaryTextColor,
variants: [
{
text: shortFromDate,
Expand Down Expand Up @@ -115,7 +118,7 @@ export function addViewAbsences(
// add the creator
staticLayoutRow.addItem({
type: 'text',
color: colors.text.secondary,
color: __liquidItemColors.secondaryTextColor,
variants: [
{
// toLoweCase to make it less prominent
Expand Down
15 changes: 9 additions & 6 deletions src/views/exams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getCharHeight, getCharWidth, getTextWidth } from '@/utils/helper'
import { FlowLayoutRow } from '@/utils/scriptable/layout/flowLayoutRow'
import { StaticLayoutRow } from '@/utils/scriptable/layout/staticLayoutRow'
import { ViewBuildData } from '@/widget'
import { getItemColors } from '@/utils/scriptable/componentHelper'

export function addViewExams(
exams: TransformedExam[],
Expand Down Expand Up @@ -75,7 +76,9 @@ export function addViewExams(
examContainer.layoutHorizontally()
examContainer.setPadding(padding, padding, padding, padding)
examContainer.spacing = widgetConfig.appearance.spacing
examContainer.backgroundColor = backgroundColor
const __liquidItemColors = getItemColors(backgroundColor, widgetConfig, false)
examContainer.backgroundColor = __liquidItemColors.backgroundColor
const textColor = __liquidItemColors.textColor
examContainer.cornerRadius = widgetConfig.appearance.cornerRadius

// build the layout row
Expand All @@ -84,7 +87,7 @@ export function addViewExams(
widgetConfig.appearance.spacing,
Font.mediumSystemFont(widgetConfig.appearance.fontSize),
widgetConfig.appearance.fontSize,
colors.text.primary
textColor
)

/**
Expand All @@ -102,7 +105,7 @@ export function addViewExams(
type: 'icon',
icon: 'book.circle',
size: widgetConfig.appearance.fontSize,
color: colors.text.primary,
color: textColor,
priority: 1,
})

Expand All @@ -120,14 +123,14 @@ export function addViewExams(
},
],
fontSize: widgetConfig.appearance.fontSize,
color: colors.text.primary,
color: textColor,
})

// add the exam type
staticLayoutRow.addItem({
type: 'text',
variants: [{ text: exam.type, priority: 4 }],
color: colors.text.secondary,
color: __liquidItemColors.secondaryTextColor,
})

// add the date
Expand All @@ -143,7 +146,7 @@ export function addViewExams(
priority: 6,
},
],
color: colors.text.primary,
color: textColor,
})

staticLayoutRow.build(examContainer)
Expand Down
17 changes: 10 additions & 7 deletions src/views/grades.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { TransformedGrade } from '@/types/transformed'
import { getCharHeight } from '@/utils/helper'
import { StaticLayoutRow } from '@/utils/scriptable/layout/staticLayoutRow'
import { ViewBuildData } from '@/widget'
import { getItemColors } from '@/utils/scriptable/componentHelper'

// TODO: the date of grades matches the date of the exam, not when it was added (breaks scope)
export function addViewGrades(
Expand Down Expand Up @@ -73,7 +74,9 @@ export function addViewGrades(
gradeContainer.layoutHorizontally()
gradeContainer.setPadding(padding, padding, padding, padding)
gradeContainer.spacing = widgetConfig.appearance.spacing
gradeContainer.backgroundColor = backgroundColor
const __liquidItemColors = getItemColors(backgroundColor, widgetConfig, false)
gradeContainer.backgroundColor = __liquidItemColors.backgroundColor
const textColor = __liquidItemColors.textColor
gradeContainer.cornerRadius = widgetConfig.appearance.cornerRadius

// build the layout row
Expand All @@ -82,7 +85,7 @@ export function addViewGrades(
widgetConfig.appearance.spacing,
Font.mediumSystemFont(widgetConfig.appearance.fontSize),
widgetConfig.appearance.fontSize,
colors.text.primary
textColor
)

/**
Expand All @@ -100,7 +103,7 @@ export function addViewGrades(
type: 'icon',
icon: iconName ?? defaultIconName,
size: widgetConfig.appearance.fontSize,
color: colors.text.primary,
color: textColor,
priority: iconName ? 1 : 3,
})

Expand All @@ -115,7 +118,7 @@ export function addViewGrades(
priority: 1,
},
],
color: colors.text.primary,
color: textColor,
})
}

Expand All @@ -128,7 +131,7 @@ export function addViewGrades(
priority: 2,
},
],
color: colors.text.primary,
color: textColor,
})

// add the exam type
Expand All @@ -140,13 +143,13 @@ export function addViewGrades(
priority: 5,
},
],
color: colors.text.secondary,
color: __liquidItemColors.secondaryTextColor,
})

// add the date
staticLayoutRow.addItem({
type: 'text',
color: colors.text.secondary,
color: __liquidItemColors.secondaryTextColor,
variants: [
{
text: shortDate,
Expand Down