Files
decePubClient/Models/PageSettings.cs
T
thepraandClaude Opus 5.5 70cb389537 Media survive failures: uploaded when attached, the server's limits, alt text asked for
The composer uploads each file as soon as it is attached (streamed from the browser file, under its own ten-minute
timeout), shows it uploading, processing (a 202 followed until ready), ready or failed with Retry, and cancels one
removed; publishing sends the ids, so a failed publish or a retried upload sends nothing twice. Size limits and types
come from /api/v2/instance, a file without a browser type gets one from its extension, and each refusal names the file
and why. Previews are 320 px thumbnails, not whole files in memory. A picture without a description is asked about once
("Publish anyway"; a setting turns it off), descriptions are sent with PUT, and an edit keeps the post's media, language
and sensitive flag.

Profile pictures are checked against the server's types and can be removed. A card shows "Media unavailable" with the
original's link when a picture fails, the blurhash behind a sensitive placeholder, and plays a GIF only on tap under
reduced motion. A failed export says so instead of downloading part of a file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
2026-10-07 11:56:59 +02:00

65 lines
2.6 KiB
C#

using PrivaPub.ClientModels.Resources;
using System.ComponentModel.DataAnnotations;
namespace decePubClient.Models
{
public class PageSettings
{
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ErrorsResource)),
Display(Name = "LanguageId", ResourceType = typeof(FieldsNameResource))]
public string CurrentLanguageCode { get; set; } = "en";
//public bool NativeNotificationsEnabled { get; set; } = false;
[Range(0, 359, ErrorMessageResourceName = nameof(Range), ErrorMessageResourceType = typeof(ErrorsResource))]
public short LightThemeIndexColour { get; set; } = 25;
[Range(0, 359, ErrorMessageResourceName = nameof(Range), ErrorMessageResourceType = typeof(ErrorsResource))]
public short DarkThemeIndexColour { get; set; } = 215;
[Range(-2, 359, ErrorMessageResourceName = nameof(Range), ErrorMessageResourceType = typeof(ErrorsResource))]
public short IconsThemeIndexColour { get; set; } = 25;
public bool PreferSystemTheming { get; set; } = true;
public bool ThemeIsDarkMode { get; set; } = false;
public bool ThemeIsLightGray { get; set; } = true;
public bool ThemeIsDarkGray { get; set; } = false;
public bool ShowDonatorBadge { get; set; } = false;
// before publishing pictures without a description, the composer asks once
public bool RemindAltText { get; set; } = true;
// How the theme flags combine is in wwwroot/js/theme.js: with PreferSystemTheming the OS picks light or dark;
// otherwise ThemeIsDarkGray, then ThemeIsLightGray, then ThemeIsDarkMode decide; either grey flag drops the
// colour. These keep the flags consistent when the UI changes one aspect.
public const short DefaultLightThemeIndexColour = 25;
public const short DefaultDarkThemeIndexColour = 215;
public bool IsGray() => ThemeIsLightGray || ThemeIsDarkGray;
/// <summary>Leaves system theming and shows the light or dark variant, grey or coloured as before.</summary>
public void SetDarkMode(bool isDark)
{
PreferSystemTheming = false;
ThemeIsDarkMode = isDark;
if (IsGray())
SetGray(true, isDark);
}
/// <summary>Switches grey on or off for the variant currently shown.</summary>
public void SetGray(bool isGray, bool isDark)
{
ThemeIsDarkGray = isGray && isDark;
ThemeIsLightGray = isGray && !isDark;
}
/// <summary>Sets the hue of the light or dark variant; picking a hue means colour, so grey goes off.</summary>
public void SetHue(bool isDark, short hue)
{
if (isDark)
DarkThemeIndexColour = hue;
else
LightThemeIndexColour = hue;
SetGray(false, isDark);
}
}
}