owpengram-server/internal/domain/themes.go

185 lines
6.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package domain
import "errors"
// 自定义云主题(account.createTheme 等)相关错误。
var (
ErrThemeNotFound = errors.New("theme not found")
ErrThemeInvalid = errors.New("theme invalid")
ErrThemeSlugTaken = errors.New("theme slug taken")
ErrThemeFormatInvalid = errors.New("theme format invalid")
)
// ThemeBaseKind 对应 TL baseTheme 的五个变体(classic/day/night/tinted/arctic)。
// 客户端按当前 base theme 选取匹配的 ThemeSettings。
type ThemeBaseKind string
const (
ThemeBaseClassic ThemeBaseKind = "classic"
ThemeBaseDay ThemeBaseKind = "day"
ThemeBaseNight ThemeBaseKind = "night"
ThemeBaseTinted ThemeBaseKind = "tinted"
ThemeBaseArctic ThemeBaseKind = "arctic"
)
// ThemeWallpaperSpec 是一份主题设置里的纯渐变墙纸(对应 wallPaperNoFile + wallPaperSettings)。
// 自定义云主题只用纯色渐变(无下载),与静态目录一致。
type ThemeWallpaperSpec struct {
BackgroundColors []int `json:"background_colors,omitempty"` // 最多 4 个
Intensity int `json:"intensity,omitempty"`
Rotation int `json:"rotation,omitempty"`
Blur bool `json:"blur,omitempty"`
Motion bool `json:"motion,omitempty"`
Emoticon string `json:"emoticon,omitempty"`
Dark bool `json:"dark,omitempty"`
}
// WallpaperSettings 是频道/私聊 wallpaper 的 domain-only 设置。Has* 字段保留 TL
// conditional flag 语义,避免黑色(0)这类合法取值在持久化时丢失。
type WallpaperSettings struct {
Blur bool `json:"blur,omitempty"`
Motion bool `json:"motion,omitempty"`
HasBackgroundColor bool `json:"has_background_color,omitempty"`
BackgroundColor int `json:"background_color,omitempty"`
HasSecondBackgroundColor bool `json:"has_second_background_color,omitempty"`
SecondBackgroundColor int `json:"second_background_color,omitempty"`
HasThirdBackgroundColor bool `json:"has_third_background_color,omitempty"`
ThirdBackgroundColor int `json:"third_background_color,omitempty"`
HasFourthBackgroundColor bool `json:"has_fourth_background_color,omitempty"`
FourthBackgroundColor int `json:"fourth_background_color,omitempty"`
HasIntensity bool `json:"has_intensity,omitempty"`
Intensity int `json:"intensity,omitempty"`
HasRotation bool `json:"has_rotation,omitempty"`
Rotation int `json:"rotation,omitempty"`
HasEmoticon bool `json:"has_emoticon,omitempty"`
Emoticon string `json:"emoticon,omitempty"`
}
// Empty reports whether no explicit wallpaper rendering settings are present.
func (s WallpaperSettings) Empty() bool {
return !s.Blur &&
!s.Motion &&
!s.HasBackgroundColor &&
!s.HasSecondBackgroundColor &&
!s.HasThirdBackgroundColor &&
!s.HasFourthBackgroundColor &&
!s.HasIntensity &&
!s.HasRotation &&
!s.HasEmoticon
}
// Wallpaper 是频道/私聊当前 wallpaper 的 domain-only 描述。NoFile=true 对应
// wallPaperNoFile否则 ID+AccessHash/Slug 引用 catalog/document wallpaper。
type Wallpaper struct {
ID int64 `json:"id,omitempty"`
AccessHash int64 `json:"access_hash,omitempty"`
Slug string `json:"slug,omitempty"`
NoFile bool `json:"no_file,omitempty"`
Default bool `json:"default,omitempty"`
Pattern bool `json:"pattern,omitempty"`
Dark bool `json:"dark,omitempty"`
Settings WallpaperSettings `json:"settings,omitempty"`
}
// CloneWallpaperPtr returns a detached wallpaper pointer.
func CloneWallpaperPtr(in *Wallpaper) *Wallpaper {
if in == nil {
return nil
}
out := *in
return &out
}
// WallpaperEqual compares optional wallpapers by value.
func WallpaperEqual(a, b *Wallpaper) bool {
if a == nil || b == nil {
return a == nil && b == nil
}
return *a == *b
}
// ThemeSettingsSpec 是一个 base theme 下的配色(对应 themeSettings/inputThemeSettings)。
// BaseTheme 与 AccentColor 必填(TL 编码器要求 base_theme 非空)。
type ThemeSettingsSpec struct {
BaseTheme ThemeBaseKind `json:"base_theme"`
AccentColor int `json:"accent_color"`
OutboxAccentColor int `json:"outbox_accent_color,omitempty"`
HasOutboxAccent bool `json:"has_outbox_accent,omitempty"`
MessageColors []int `json:"message_colors,omitempty"`
MessageColorsAnimated bool `json:"message_colors_animated,omitempty"`
Wallpaper *ThemeWallpaperSpec `json:"wallpaper,omitempty"`
}
// Theme 是一份持久化的自定义云主题。document_id 软引用 documents(无硬外键),
// settings 仅 accent 主题非空;完整 .attheme 主题靠 DocumentID 下载。
type Theme struct {
ID int64
AccessHash int64
CreatorUserID int64
Slug string
Title string
Emoticon string
ForChat bool
DocumentID int64
Settings []ThemeSettingsSpec
InstallsCount int
CreatedAt int64 // unix 秒
}
// Clone 深拷贝(切片字段),避免内存 store 暴露内部引用。
func (t Theme) Clone() Theme {
out := t
out.Settings = cloneThemeSettings(t.Settings)
return out
}
func cloneThemeSettings(in []ThemeSettingsSpec) []ThemeSettingsSpec {
if in == nil {
return nil
}
out := make([]ThemeSettingsSpec, len(in))
for i, s := range in {
out[i] = s
out[i].MessageColors = append([]int(nil), s.MessageColors...)
if s.Wallpaper != nil {
wp := *s.Wallpaper
wp.BackgroundColors = append([]int(nil), s.Wallpaper.BackgroundColors...)
out[i].Wallpaper = &wp
}
}
return out
}
// IsCreator 报告 userID 是否为该主题的创建者(决定客户端再次上传走 create 还是 update)。
func (t Theme) IsCreator(userID int64) bool {
return t.CreatorUserID != 0 && t.CreatorUserID == userID
}
// ThemeRef 引用一份主题:按 id+access_hash(inputTheme)或 slug(inputThemeSlug,深链)。
type ThemeRef struct {
ID int64
AccessHash int64
Slug string
}
// IsZero 报告该引用是否为空(既无 id 也无 slug)。
func (r ThemeRef) IsZero() bool { return r.ID == 0 && r.Slug == "" }
// ThemeSpec 是 createTheme 的输入。Slug 为空表示由服务端自动分配。
type ThemeSpec struct {
CreatorUserID int64
Slug string
Title string
Emoticon string
ForChat bool
DocumentID int64
Settings []ThemeSettingsSpec
}
// ThemeUpdate 是 updateTheme 的部分更新;nil 字段表示不改。
type ThemeUpdate struct {
Slug *string
Title *string
DocumentID *int64
Settings *[]ThemeSettingsSpec
}