Initial commit

This commit is contained in:
AnRil
2026-05-16 13:43:29 +07:00
commit 688a86b611
208 changed files with 44350 additions and 0 deletions

47
src/shared/ipc.ts Normal file
View File

@@ -0,0 +1,47 @@
export const IPC = {
getState: 'state:get',
addExercise: 'exercise:add',
updateExercise: 'exercise:update',
deleteExercise: 'exercise:delete',
toggleExercise: 'exercise:toggle',
markDone: 'exercise:markDone',
snooze: 'exercise:snooze',
skip: 'exercise:skip',
updateSettings: 'settings:update',
getAccentColor: 'system:accentColor',
getOsTheme: 'system:osTheme',
pauseAll: 'app:pauseAll',
resumeAll: 'app:resumeAll',
quit: 'app:quit',
minimizeMain: 'window:minimize',
closeMain: 'window:close',
hideMain: 'window:hide',
reminderClose: 'reminder:close',
// Games
gamesList: 'games:list',
gameInstall: 'games:install',
gameUninstall: 'games:uninstall',
gameToggle: 'games:toggle',
gameOpenLaunchOptions: 'games:openLaunchOptions',
// Challenges
addChallenge: 'challenge:add',
updateChallenge: 'challenge:update',
deleteChallenge: 'challenge:delete',
toggleChallenge: 'challenge:toggle',
markChallengeDone: 'challenge:markDone',
closeMatchSummary: 'matchSummary:close',
// events from main → renderer
evtTick: 'evt:tick',
evtFire: 'evt:fire',
evtMatchEnd: 'evt:matchEnd',
evtStateChanged: 'evt:stateChanged',
evtThemeChanged: 'evt:themeChanged',
evtAccentChanged: 'evt:accentChanged',
evtGamesChanged: 'evt:gamesChanged'
} as const

132
src/shared/types.ts Normal file
View File

@@ -0,0 +1,132 @@
export type Exercise = {
id: string
name: string
reps: number
icon: string
intervalMinutes: number
enabled: boolean
nextFireAt: number
lastDoneAt?: number
}
export type NotificationMode = 'toast' | 'modal' | 'both'
export type Theme = 'light' | 'dark' | 'system'
export type Settings = {
globalEnabled: boolean
notificationMode: NotificationMode
soundEnabled: boolean
startWithWindows: boolean
minimizeToTray: boolean
startMinimized: boolean
theme: Theme
snoozeMinutes: number
}
export type AppState = {
exercises: Exercise[]
settings: Settings
challenges: Challenge[]
gamesEnabled: Partial<Record<GameId, boolean>>
}
export type Tick = {
exerciseId: string
msUntilFire: number
enabled: boolean
}
export type FireEvent = {
exercise: Exercise
mode: NotificationMode
}
export type GameId = 'dota2'
export const GAME_STATS: Record<GameId, readonly GameStat[]> = {
dota2: [
'deaths',
'kills',
'assists',
'last_hits',
'denies',
'duration_min'
] as const
}
export type GameStat =
| 'deaths'
| 'kills'
| 'assists'
| 'last_hits'
| 'denies'
| 'duration_min'
export const STAT_LABELS: Record<GameStat, string> = {
deaths: 'смертей',
kills: 'убийств',
assists: 'ассистов',
last_hits: 'ласт-хитов',
denies: 'денаев',
duration_min: 'минут матча'
}
export type Challenge = {
id: string
name: string
gameId: GameId
stat: GameStat
multiplier: number
exerciseName: string
icon: string
enabled: boolean
}
export type LaunchOptionStatus = 'applied' | 'queued' | 'no_user' | 'not_needed'
export type GameStatus = {
id: GameId
name: string
installed: boolean
installPath?: string
integrationActive: boolean // cfg installed + listener running
launchOption?: string // e.g. "-gamestateintegration"
launchOptionStatus: LaunchOptionStatus
steamRunning?: boolean // helps the UI explain queued state
enabled: boolean
}
export type ChallengeResult = {
challengeId: string
name: string
icon: string
exerciseName: string
reps: number
statValue: number
statLabel: string
}
export type MatchSummary = {
gameId: GameId
gameName: string
durationMs: number
won?: boolean
results: ChallengeResult[]
}
export const DEFAULT_SETTINGS: Settings = {
globalEnabled: true,
notificationMode: 'modal',
soundEnabled: true,
startWithWindows: false,
minimizeToTray: true,
startMinimized: false,
theme: 'system',
snoozeMinutes: 5
}
export const SAMPLE_EXERCISES: Omit<Exercise, 'id' | 'nextFireAt'>[] = [
{ name: 'Приседания', reps: 10, icon: 'Activity', intervalMinutes: 30, enabled: true },
{ name: 'Отжимания', reps: 10, icon: 'Dumbbell', intervalMinutes: 45, enabled: true },
{ name: 'Растяжка спины', reps: 1, icon: 'StretchHorizontal', intervalMinutes: 60, enabled: false }
]