mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-11 17:30:00 +02:00
feat(design): Projector Noir theme - tungsten amber on film-black
Full visual refonte replacing the generic neon-blue glass look: - palette: warm film-black surface ladder, tungsten amber primary, warm taupe secondary, verdigris teal tertiary; semantic and category colors retuned to match (coral live, gold movies) - typography: Syne (display/headlines) + Instrument Sans (body/UI) replace Space Grotesk/Inter/Outfit across all screens - glassmorphism tokens warmed (amber inner glow, warm-white borders) - web player theme.css + index.html loader mirror the new tokens - hardcoded Colors.blue* in streaming settings and recordings tabs now use AppColors tokens - DESIGN_SYSTEM.md updated to v3.0 Projector Noir Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9595afcc99
commit
e332895d7d
33 files changed
+392
-397
No files matched your search
+38
-44
@@ -1,12 +1,12 @@
|
||||
# XtremFlow Apple TV Modern Design System
|
||||
# XtremFlow Projector Noir Design System
|
||||
|
||||
## Overview
|
||||
|
||||
XtremFlow has been completely redesigned with a **premium Apple TV modern aesthetic** inspired by tvOS 18+. The new design system prioritizes:
|
||||
XtremFlow uses a **Projector Noir aesthetic**: warm tungsten light cutting through a dark screening room. The design system prioritizes:
|
||||
|
||||
- **Sophisticated Glassmorphism** - Elegant blur effects with subtle gradients
|
||||
- **Premium Color Palette** - Vibrant accents (Cyan, Mint, Red) on pure black
|
||||
- **Cinematic Typography** - Bold headlines (Outfit) + refined UI text (Inter)
|
||||
- **Sophisticated Glassmorphism** - Elegant blur effects with warm-tinted borders
|
||||
- **Tungsten Palette** - Amber projector-beam accents on deep film-black
|
||||
- **Art-House Typography** - Geometric headlines (Syne) + refined UI text (Instrument Sans)
|
||||
- **Focus-Driven Interactions** - TV-friendly hover states and animations
|
||||
- **Responsive Layouts** - Seamless adaptation from web to mobile
|
||||
|
||||
@@ -14,46 +14,40 @@ XtremFlow has been completely redesigned with a **premium Apple TV modern aesthe
|
||||
|
||||
## Color Palette
|
||||
|
||||
### Backgrounds
|
||||
- **`background`** (#000000) - Pure black, OLED optimized
|
||||
- **`surface`** (#1C1C1E) - Primary dark surface
|
||||
- **`surfaceVariant`** (#2A2A2E) - Secondary surface for hierarchy
|
||||
- **`surfaceTertiary`** (#383838) - Tertiary depth layer
|
||||
### Backgrounds (warm film-black ladder)
|
||||
- **`baseLevel0`** (#0B0A08) - Deepest black, OLED optimized
|
||||
- **`background` / `surface`** (#14110C) - Primary dark surface
|
||||
- **`surfaceContainerLow`** (#1B1812) to **`surfaceContainerHighest`** (#363027) - Warm charcoal hierarchy
|
||||
|
||||
### Primary Accents
|
||||
- **`primary`** (#00D4FF) - Main brand color (Cyan/Sky Blue)
|
||||
- **`secondary`** (#FF6B6B) - Secondary accent (Soft Red)
|
||||
- **`tertiary`** (#00E5BB) - Highlight accent (Mint)
|
||||
- **`accent`** - Alias for primary (for consistency)
|
||||
- **`primary`** (#FFB35C) - Tungsten amber (main brand color)
|
||||
- **`primaryContainer`** (#F39A1F) - Vivid amber (buttons, focus rings)
|
||||
- **`secondary`** (#D3C6B2) - Warm taupe
|
||||
- **`tertiary`** (#A4CCBE) - Verdigris teal (counterpoint accent)
|
||||
|
||||
### Semantic Colors
|
||||
- **`success`** (#34C759) - Success/completed state
|
||||
- **`warning`** (#FF9500) - Warning/caution state
|
||||
- **`error`** (#FF3B30) - Error/danger state
|
||||
- **`info`** (#30B0C0) - Information state
|
||||
- **`disabled`** (#8E8E93) - Disabled/inactive state
|
||||
- **`success`** (#6BD89B) - Success/completed state
|
||||
- **`warning`** (#FFAB00) - Warning/caution state
|
||||
- **`error`** (#FFB4AB) - Error/danger state (Material 3 dark)
|
||||
- **`info`** (#64B6AC) - Information state (soft teal)
|
||||
|
||||
### Text Hierarchy
|
||||
- **`textPrimary`** (#FFFFFF) - Main text (white)
|
||||
- **`textSecondary`** (#999999) - Secondary text (60% grey)
|
||||
- **`textTertiary`** (#666666) - Tertiary text (40% grey)
|
||||
- **`textQuaternary`** (#404040) - Subtle text (25% grey)
|
||||
### Text Hierarchy (warm ivory)
|
||||
- **`textPrimary`** (#ECE6DA) - Main text
|
||||
- **`textSecondary`** (#CDC4B4) - Secondary text
|
||||
- **`textTertiary`** (#998F7C) - Tertiary text
|
||||
|
||||
### Category Colors
|
||||
- **`live`** (#FF3B30) - Live streams (red)
|
||||
- **`movies`** (#00B4E8) - Movie content (blue)
|
||||
- **`series`** (#00E5BB) - Series content (mint)
|
||||
- **`sports`** (#BF5AF0) - Sports content (purple)
|
||||
- **`news`** (#FFC300) - News content (yellow)
|
||||
- **`music`** (#FF2D55) - Music content (pink)
|
||||
- **`live`** (#FF6E5E) - Live streams (signal coral)
|
||||
- **`movies`** (#E8B64C) - Movie content (warm gold)
|
||||
- **`series`** (#5FC9AE) - Series content (teal)
|
||||
|
||||
---
|
||||
|
||||
## Typography
|
||||
|
||||
### Font Stack
|
||||
1. **Outfit** (headings/display) - Bold, geometric, premium feel
|
||||
2. **Inter** (UI/body) - Clean, readable, high contrast
|
||||
1. **Syne** (headings/display) - Geometric, art-house, distinctive
|
||||
2. **Instrument Sans** (UI/body) - Clean, readable, characterful
|
||||
3. Fallback to system fonts
|
||||
|
||||
### Sizes & Weights
|
||||
@@ -287,14 +281,14 @@ TvSideNav(
|
||||
## Usage Guidelines
|
||||
|
||||
### Color Usage
|
||||
- **Primary (Cyan):** Call-to-action buttons, focus states, active indicators
|
||||
- **Secondary (Red):** Alerts, favorite toggles, urgent actions
|
||||
- **Tertiary (Mint):** Accent highlights, success states, featured badges
|
||||
- **Primary (Tungsten Amber):** Call-to-action buttons, focus states, active indicators
|
||||
- **Secondary (Warm Taupe):** Alerts, favorite toggles, urgent actions
|
||||
- **Tertiary (Verdigris Teal):** Accent highlights, success states, featured badges
|
||||
- **White/Grey text:** Maintain WCAG AA contrast ratio (4.5:1 minimum)
|
||||
|
||||
### Typography
|
||||
- **Outfit:** Only for headings/hero text (sizes 20px and above)
|
||||
- **Inter:** All UI, buttons, body text
|
||||
- **Syne:** Only for headings/hero text (sizes 20px and above)
|
||||
- **Instrument Sans:** All UI, buttons, body text
|
||||
- **Letter spacing:** Increase for larger sizes (hero titles: -1.0 to -1.5), decrease for body text
|
||||
|
||||
### Spacing
|
||||
@@ -319,8 +313,8 @@ TvSideNav(
|
||||
## Mobile Adaptations
|
||||
|
||||
### Touch Targets
|
||||
- **Minimum button size:** 48×48px
|
||||
- **Minimum tap area:** 44×44px
|
||||
- **Minimum button size:** 48x48px
|
||||
- **Minimum tap area:** 44x44px
|
||||
- **Between buttons:** 16px spacing minimum
|
||||
|
||||
### Typography Scaling
|
||||
@@ -349,7 +343,7 @@ TvSideNav(
|
||||
2. Extend with custom styling if needed
|
||||
3. Follow spacing/animation guidelines
|
||||
4. Test hover states on desktop, tap on mobile
|
||||
5. Ensure text contrast ≥ 4.5:1
|
||||
5. Ensure text contrast >= 4.5:1
|
||||
|
||||
### Color Customization
|
||||
- Never override `AppColors` constants directly
|
||||
@@ -378,7 +372,7 @@ TvSideNav(
|
||||
## Accessibility
|
||||
|
||||
- **Text Contrast:** All text must meet WCAG AA (4.5:1)
|
||||
- **Touch Targets:** 48×48px minimum on mobile
|
||||
- **Touch Targets:** 48x48px minimum on mobile
|
||||
- **Focus States:** Always visible with 2px border or scale change
|
||||
- **Semantic HTML:** Use proper widget hierarchy
|
||||
- **Tooltips:** Always add for icon-only buttons
|
||||
@@ -435,6 +429,6 @@ Curve animCurve = AppTheme.curveDefault;
|
||||
|
||||
---
|
||||
|
||||
**Design System Version:** 2.0 Apple TV Modern
|
||||
**Last Updated:** 2026-03-26
|
||||
**Status:** Production Ready ✅
|
||||
**Design System Version:** 3.0 Projector Noir
|
||||
**Last Updated:** 2026-06-10
|
||||
**Status:** Production Ready OK
|
||||
@@ -1,10 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Cyber-Cinematic Glass Design System — Material 3 Token Palette
|
||||
/// Projector Noir Design System — Material 3 Token Palette
|
||||
///
|
||||
/// Extracted from the Stitch design system for XtremFlow.
|
||||
/// Warm tungsten light on deep film-black, like a projector beam cutting
|
||||
/// through a dark screening room. Verdigris teal as the counterpoint accent.
|
||||
/// Optimized for OLED displays and low-light environments.
|
||||
/// Primary accent: Neon blue (#4b8eff / #adc6ff)
|
||||
/// Primary accent: Tungsten amber (#F39A1F / #FFB35C)
|
||||
class AppColors {
|
||||
AppColors._();
|
||||
|
||||
@@ -13,58 +14,58 @@ class AppColors {
|
||||
static Color get border => outlineVariant;
|
||||
|
||||
// ============ SURFACE / ON SURFACE ============
|
||||
static const Color onSurface = Color(0xFFe3e2e7);
|
||||
static const Color onSurfaceVariant = Color(0xFFc1c6d7);
|
||||
static const Color onSurface = Color(0xFFECE6DA);
|
||||
static const Color onSurfaceVariant = Color(0xFFCDC4B4);
|
||||
|
||||
// ============ BASE LEVEL 0 ============
|
||||
static const Color baseLevel0 = Color(0xFF0F1014);
|
||||
static const Color baseLevel0 = Color(0xFF0B0A08);
|
||||
|
||||
// ============ BACKGROUNDS ============
|
||||
static const Color background = Color(0xFF121317);
|
||||
static const Color onBackground = Color(0xFFe3e2e7);
|
||||
static const Color background = Color(0xFF14110C);
|
||||
static const Color onBackground = Color(0xFFECE6DA);
|
||||
|
||||
static const Color surface = Color(0xFF121317);
|
||||
static const Color surfaceDim = Color(0xFF121317);
|
||||
static const Color surfaceBright = Color(0xFF38393d);
|
||||
static const Color surface = Color(0xFF14110C);
|
||||
static const Color surfaceDim = Color(0xFF14110C);
|
||||
static const Color surfaceBright = Color(0xFF3E382C);
|
||||
|
||||
// Surface Containers (Material 3 hierarchy)
|
||||
static const Color surfaceContainerLowest = Color(0xFF0d0e12);
|
||||
static const Color surfaceContainerLow = Color(0xFF1a1b20);
|
||||
static const Color surfaceContainer = Color(0xFF1f1f24);
|
||||
static const Color surfaceContainerHigh = Color(0xFF292a2e);
|
||||
static const Color surfaceContainerHighest = Color(0xFF343439);
|
||||
static const Color surfaceVariant = Color(0xFF343439);
|
||||
static const Color surfaceContainerLowest = Color(0xFF0E0C09);
|
||||
static const Color surfaceContainerLow = Color(0xFF1B1812);
|
||||
static const Color surfaceContainer = Color(0xFF211D16);
|
||||
static const Color surfaceContainerHigh = Color(0xFF2B261E);
|
||||
static const Color surfaceContainerHighest = Color(0xFF363027);
|
||||
static const Color surfaceVariant = Color(0xFF363027);
|
||||
|
||||
// ============ PRIMARY (Neon Blue) ============
|
||||
static const Color primary = Color(0xFFadc6ff);
|
||||
static const Color onPrimary = Color(0xFF002e69);
|
||||
static const Color primaryContainer = Color(0xFF4b8eff);
|
||||
static const Color onPrimaryContainer = Color(0xFF00285c);
|
||||
static const Color inversePrimary = Color(0xFF005bc1);
|
||||
static const Color primaryFixed = Color(0xFFd8e2ff);
|
||||
static const Color primaryFixedDim = Color(0xFFadc6ff);
|
||||
static const Color onPrimaryFixed = Color(0xFF001a41);
|
||||
static const Color onPrimaryFixedVariant = Color(0xFF004493);
|
||||
// ============ PRIMARY (Tungsten Amber) ============
|
||||
static const Color primary = Color(0xFFFFB35C);
|
||||
static const Color onPrimary = Color(0xFF452800);
|
||||
static const Color primaryContainer = Color(0xFFF39A1F);
|
||||
static const Color onPrimaryContainer = Color(0xFF2E1B00);
|
||||
static const Color inversePrimary = Color(0xFF8F5B00);
|
||||
static const Color primaryFixed = Color(0xFFFFDDB3);
|
||||
static const Color primaryFixedDim = Color(0xFFFFB35C);
|
||||
static const Color onPrimaryFixed = Color(0xFF2A1700);
|
||||
static const Color onPrimaryFixedVariant = Color(0xFF6B4300);
|
||||
|
||||
// ============ SECONDARY ============
|
||||
static const Color secondary = Color(0xFFc6c5cf);
|
||||
static const Color onSecondary = Color(0xFF2f3037);
|
||||
static const Color secondaryContainer = Color(0xFF4a4b53);
|
||||
static const Color onSecondaryContainer = Color(0xFFbcbbc4);
|
||||
static const Color secondaryFixed = Color(0xFFe3e1eb);
|
||||
static const Color secondaryFixedDim = Color(0xFFc6c5cf);
|
||||
static const Color onSecondaryFixed = Color(0xFF1a1b22);
|
||||
static const Color onSecondaryFixedVariant = Color(0xFF46464e);
|
||||
// ============ SECONDARY (Warm Taupe) ============
|
||||
static const Color secondary = Color(0xFFD3C6B2);
|
||||
static const Color onSecondary = Color(0xFF382F21);
|
||||
static const Color secondaryContainer = Color(0xFF504535);
|
||||
static const Color onSecondaryContainer = Color(0xFFD8CCB9);
|
||||
static const Color secondaryFixed = Color(0xFFF0E4D0);
|
||||
static const Color secondaryFixedDim = Color(0xFFD3C6B2);
|
||||
static const Color onSecondaryFixed = Color(0xFF231B0E);
|
||||
static const Color onSecondaryFixedVariant = Color(0xFF4D4232);
|
||||
|
||||
// ============ TERTIARY ============
|
||||
static const Color tertiary = Color(0xFFc6c6c7);
|
||||
static const Color onTertiary = Color(0xFF2f3131);
|
||||
static const Color tertiaryContainer = Color(0xFF909191);
|
||||
static const Color onTertiaryContainer = Color(0xFF282a2a);
|
||||
static const Color tertiaryFixed = Color(0xFFe2e2e2);
|
||||
static const Color tertiaryFixedDim = Color(0xFFc6c6c7);
|
||||
static const Color onTertiaryFixed = Color(0xFF1a1c1c);
|
||||
static const Color onTertiaryFixedVariant = Color(0xFF454747);
|
||||
// ============ TERTIARY (Verdigris Teal) ============
|
||||
static const Color tertiary = Color(0xFFA4CCBE);
|
||||
static const Color onTertiary = Color(0xFF0F352B);
|
||||
static const Color tertiaryContainer = Color(0xFF2F5A4C);
|
||||
static const Color onTertiaryContainer = Color(0xFFC0E8D9);
|
||||
static const Color tertiaryFixed = Color(0xFFC0E8D9);
|
||||
static const Color tertiaryFixedDim = Color(0xFFA4CCBE);
|
||||
static const Color onTertiaryFixed = Color(0xFF04201A);
|
||||
static const Color onTertiaryFixedVariant = Color(0xFF274B40);
|
||||
|
||||
// ============ ERROR ============
|
||||
static const Color error = Color(0xFFffb4ab);
|
||||
@@ -73,61 +74,61 @@ class AppColors {
|
||||
static const Color onErrorContainer = Color(0xFFffdad6);
|
||||
|
||||
// ============ OUTLINE ============
|
||||
static const Color outline = Color(0xFF8b90a0);
|
||||
static const Color outlineVariant = Color(0xFF414755);
|
||||
static const Color outline = Color(0xFF998F7C);
|
||||
static const Color outlineVariant = Color(0xFF4A4334);
|
||||
|
||||
// ============ INVERSE SURFACE ============
|
||||
static const Color inverseSurface = Color(0xFFe3e2e7);
|
||||
static const Color inverseOnSurface = Color(0xFF2f3035);
|
||||
static const Color inverseSurface = Color(0xFFECE6DA);
|
||||
static const Color inverseOnSurface = Color(0xFF332F26);
|
||||
|
||||
// ============ SURFACE TINT ============
|
||||
static const Color surfaceTint = Color(0xFFadc6ff);
|
||||
static const Color surfaceTint = Color(0xFFFFB35C);
|
||||
|
||||
// ============ TEXT / CONTENT COLORS ============
|
||||
static const Color textPrimary = Color(0xFFe3e2e7);
|
||||
static const Color textSecondary = Color(0xFFc1c6d7);
|
||||
static const Color textTertiary = Color(0xFF8b90a0);
|
||||
static const Color textPrimary = Color(0xFFECE6DA);
|
||||
static const Color textSecondary = Color(0xFFCDC4B4);
|
||||
static const Color textTertiary = Color(0xFF998F7C);
|
||||
|
||||
// ============ STATUS COLORS ============
|
||||
static const Color success = Color(0xFF00E676);
|
||||
static const Color success = Color(0xFF6BD89B);
|
||||
static const Color warning = Color(0xFFFFAB00);
|
||||
static const Color info = Color(0xFF2979FF);
|
||||
static const Color info = Color(0xFF64B6AC);
|
||||
|
||||
// ============ CATEGORY COLORS (kept for semantic meaning) ============
|
||||
static const Color live = Color(0xFFFF5252);
|
||||
static const Color movies = Color(0xFF448AFF);
|
||||
static const Color series = Color(0xFF69F0AE);
|
||||
static const Color live = Color(0xFFFF6E5E);
|
||||
static const Color movies = Color(0xFFE8B64C);
|
||||
static const Color series = Color(0xFF5FC9AE);
|
||||
|
||||
// ============ RATING / PREMIUM ============
|
||||
static const Color ratingGold = Color(0xFFFFD700);
|
||||
static const Color ratingGold = Color(0xFFFFD166);
|
||||
static const Color premiumGold = Color(0xFFFFA000);
|
||||
|
||||
// ============ GLASSMORPHISM LEVELS ============
|
||||
static const Color glassLevel1Bg = Color(0x66121317); // 40% opacity
|
||||
static const Color glassLevel1Border = Color(0x1AFFFFFF); // 10% white
|
||||
static const Color glassLevel1Bg = Color(0x6614110C); // 40% opacity
|
||||
static const Color glassLevel1Border = Color(0x1AFFE9C9); // 10% warm white
|
||||
|
||||
static const Color glassLevel2Bg = Color(0x99121317); // 60% opacity
|
||||
static const Color glassLevel2Border = Color(0x1AFFFFFF); // 10% white
|
||||
static const Color glassLevel2InnerGlow = Color(0x33adc6ff); // 20% primary top-left
|
||||
static const Color glassLevel2Bg = Color(0x9914110C); // 60% opacity
|
||||
static const Color glassLevel2Border = Color(0x1AFFE9C9); // 10% warm white
|
||||
static const Color glassLevel2InnerGlow = Color(0x33FFB35C); // 20% primary top-left
|
||||
|
||||
// ============ GRADIENTS ============
|
||||
static const LinearGradient primaryGradient = LinearGradient(
|
||||
colors: [Color(0xFF007AFF), Color(0xFF00C6FF)],
|
||||
colors: [Color(0xFFE8941A), Color(0xFFFFC36A)],
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
);
|
||||
|
||||
static const LinearGradient backgroundGradient = LinearGradient(
|
||||
colors: [Color(0xFF0F1014), Color(0xFF121317)],
|
||||
colors: [Color(0xFF0B0A08), Color(0xFF14110C)],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
);
|
||||
|
||||
// ============ GLOW / SHADOWS ============
|
||||
static Color glowPrimary(double opacity) =>
|
||||
const Color(0xFF007AFF).withOpacity(opacity);
|
||||
const Color(0xFFF39A1F).withOpacity(opacity);
|
||||
static Color glowPrimaryDim(double opacity) =>
|
||||
const Color(0xFFadc6ff).withOpacity(opacity);
|
||||
const Color(0xFFFFB35C).withOpacity(opacity);
|
||||
|
||||
// ============ COLOR SCHEMES ============
|
||||
static ColorScheme get darkColorScheme => const ColorScheme.dark(
|
||||
@@ -162,24 +163,24 @@ class AppColors {
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
|
||||
// Light scheme is minimal — Stitch is dark-only
|
||||
// Light scheme is minimal — Projector Noir is dark-first
|
||||
static ColorScheme get lightColorScheme => const ColorScheme.light(
|
||||
primary: Color(0xFF005bc1),
|
||||
primary: Color(0xFF8F5B00),
|
||||
onPrimary: Colors.white,
|
||||
primaryContainer: Color(0xFFd8e2ff),
|
||||
onPrimaryContainer: Color(0xFF001a41),
|
||||
secondary: Color(0xFF5e5c68),
|
||||
primaryContainer: Color(0xFFFFDDB3),
|
||||
onPrimaryContainer: Color(0xFF2A1700),
|
||||
secondary: Color(0xFF6F6353),
|
||||
onSecondary: Colors.white,
|
||||
secondaryContainer: Color(0xFFe3e1eb),
|
||||
onSecondaryContainer: Color(0xFF1a1b22),
|
||||
secondaryContainer: Color(0xFFF0E4D0),
|
||||
onSecondaryContainer: Color(0xFF231B0E),
|
||||
error: Color(0xFFba1a1a),
|
||||
onError: Colors.white,
|
||||
errorContainer: Color(0xFFFFdad6),
|
||||
onErrorContainer: Color(0xFF410002),
|
||||
surface: Color(0xFFF9F9FF),
|
||||
onSurface: Color(0xFF1a1b22),
|
||||
outline: Color(0xFF757680),
|
||||
outlineVariant: Color(0xFFc5c6d0),
|
||||
surface: Color(0xFFFFF8F0),
|
||||
onSurface: Color(0xFF1E1B15),
|
||||
outline: Color(0xFF7F766A),
|
||||
outlineVariant: Color(0xFFD0C5B4),
|
||||
brightness: Brightness.light,
|
||||
);
|
||||
}
|
||||
@@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'app_colors.dart';
|
||||
|
||||
/// XtremFlow Cyber-Cinematic Glass Theme
|
||||
/// XtremFlow Projector Noir Theme
|
||||
///
|
||||
/// Design system extracted from Google Stitch.
|
||||
/// Fonts: Space Grotesk (headlines) + Inter (body/labels)
|
||||
/// Style: Dark-only glassmorphism with neon blue accents.
|
||||
/// Warm tungsten light on deep film-black.
|
||||
/// Fonts: Syne (headlines, art-house geometric) + Instrument Sans (body/labels)
|
||||
/// Style: Dark-first glassmorphism with tungsten amber accents.
|
||||
class AppTheme {
|
||||
AppTheme._();
|
||||
|
||||
@@ -39,14 +39,14 @@ class AppTheme {
|
||||
static const Curve curveSmooth = Curves.fastOutSlowIn;
|
||||
|
||||
// ============ TYPOGRAPHY HELPERS ============
|
||||
static TextStyle _spaceGrotesk({
|
||||
static TextStyle _syne({
|
||||
required double fontSize,
|
||||
required FontWeight fontWeight,
|
||||
double? letterSpacing,
|
||||
double? height,
|
||||
Color color = AppColors.onSurface,
|
||||
}) {
|
||||
return GoogleFonts.spaceGrotesk(
|
||||
return GoogleFonts.syne(
|
||||
fontSize: fontSize,
|
||||
fontWeight: fontWeight,
|
||||
letterSpacing: letterSpacing,
|
||||
@@ -55,14 +55,14 @@ class AppTheme {
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle _inter({
|
||||
static TextStyle _instrumentSans({
|
||||
required double fontSize,
|
||||
required FontWeight fontWeight,
|
||||
double? letterSpacing,
|
||||
double? height,
|
||||
Color color = AppColors.onSurface,
|
||||
}) {
|
||||
return GoogleFonts.inter(
|
||||
return GoogleFonts.instrumentSans(
|
||||
fontSize: fontSize,
|
||||
fontWeight: fontWeight,
|
||||
letterSpacing: letterSpacing,
|
||||
@@ -81,85 +81,85 @@ class AppTheme {
|
||||
|
||||
// Typography
|
||||
textTheme: TextTheme(
|
||||
// Display / Headline (Space Grotesk)
|
||||
displayLarge: _spaceGrotesk(
|
||||
// Display / Headline (Syne)
|
||||
displayLarge: _syne(
|
||||
fontSize: 48,
|
||||
fontWeight: FontWeight.w700,
|
||||
letterSpacing: -0.02,
|
||||
height: 1.1,
|
||||
),
|
||||
displayMedium: _spaceGrotesk(
|
||||
displayMedium: _syne(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: -0.01,
|
||||
height: 1.2,
|
||||
),
|
||||
displaySmall: _spaceGrotesk(
|
||||
displaySmall: _syne(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.3,
|
||||
),
|
||||
headlineLarge: _spaceGrotesk(
|
||||
headlineLarge: _syne(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: -0.01,
|
||||
height: 1.2,
|
||||
),
|
||||
headlineMedium: _spaceGrotesk(
|
||||
headlineMedium: _syne(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.3,
|
||||
),
|
||||
headlineSmall: _spaceGrotesk(
|
||||
headlineSmall: _syne(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.3,
|
||||
),
|
||||
titleLarge: _spaceGrotesk(
|
||||
titleLarge: _syne(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
titleMedium: _inter(
|
||||
titleMedium: _instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
titleSmall: _inter(
|
||||
titleSmall: _instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
// Body (Inter)
|
||||
bodyLarge: _inter(
|
||||
// Body (Instrument Sans)
|
||||
bodyLarge: _instrumentSans(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.6,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
),
|
||||
bodyMedium: _inter(
|
||||
bodyMedium: _instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.5,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
),
|
||||
bodySmall: _inter(
|
||||
bodySmall: _instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.4,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
),
|
||||
// Labels (Inter with tracking)
|
||||
labelLarge: _inter(
|
||||
// Labels (Instrument Sans with tracking)
|
||||
labelLarge: _instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: 0.05,
|
||||
height: 1.2,
|
||||
),
|
||||
labelMedium: _inter(
|
||||
labelMedium: _instrumentSans(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
letterSpacing: 0.02,
|
||||
height: 1.2,
|
||||
),
|
||||
labelSmall: _inter(
|
||||
labelSmall: _instrumentSans(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w500,
|
||||
letterSpacing: 0.02,
|
||||
@@ -174,13 +174,13 @@ class AppTheme {
|
||||
elevation: 0,
|
||||
centerTitle: true,
|
||||
scrolledUnderElevation: 0,
|
||||
titleTextStyle: _spaceGrotesk(
|
||||
titleTextStyle: _syne(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
|
||||
// Inputs: Dark filled with blue glow on focus
|
||||
// Inputs: Dark filled with amber glow on focus
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: AppColors.surfaceContainerLow,
|
||||
@@ -204,12 +204,12 @@ class AppTheme {
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
borderSide: const BorderSide(color: AppColors.error, width: 1),
|
||||
),
|
||||
hintStyle: _inter(
|
||||
hintStyle: _instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.outline,
|
||||
),
|
||||
labelStyle: _inter(
|
||||
labelStyle: _instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
@@ -226,7 +226,7 @@ class AppTheme {
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
),
|
||||
textStyle: _inter(
|
||||
textStyle: _instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: 0.05,
|
||||
@@ -253,7 +253,7 @@ class AppTheme {
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
),
|
||||
textStyle: _inter(
|
||||
textStyle: _instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: 0.05,
|
||||
@@ -266,7 +266,7 @@ class AppTheme {
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: AppColors.primary,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||
textStyle: _inter(
|
||||
textStyle: _instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -292,11 +292,11 @@ class AppTheme {
|
||||
borderRadius: BorderRadius.circular(radiusXl),
|
||||
side: const BorderSide(color: AppColors.glassLevel2Border, width: 1),
|
||||
),
|
||||
titleTextStyle: _spaceGrotesk(
|
||||
titleTextStyle: _syne(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
contentTextStyle: _inter(
|
||||
contentTextStyle: _instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
@@ -314,7 +314,7 @@ class AppTheme {
|
||||
// Snackbars
|
||||
snackBarTheme: SnackBarThemeData(
|
||||
backgroundColor: AppColors.surfaceContainerHigh,
|
||||
contentTextStyle: _inter(
|
||||
contentTextStyle: _instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.onSurface,
|
||||
@@ -336,12 +336,12 @@ class AppTheme {
|
||||
shape: StadiumBorder(
|
||||
side: BorderSide(color: AppColors.primary.withOpacity(0.3)),
|
||||
),
|
||||
labelStyle: _inter(
|
||||
labelStyle: _instrumentSans(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
secondaryLabelStyle: _inter(
|
||||
secondaryLabelStyle: _instrumentSans(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.onPrimaryContainer,
|
||||
@@ -353,8 +353,8 @@ class AppTheme {
|
||||
labelColor: AppColors.onSurface,
|
||||
unselectedLabelColor: AppColors.outline,
|
||||
indicatorColor: AppColors.primaryContainer,
|
||||
labelStyle: _inter(fontSize: 14, fontWeight: FontWeight.w600),
|
||||
unselectedLabelStyle: _inter(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
labelStyle: _instrumentSans(fontSize: 14, fontWeight: FontWeight.w600),
|
||||
unselectedLabelStyle: _instrumentSans(fontSize: 14, fontWeight: FontWeight.w500),
|
||||
),
|
||||
|
||||
// Divider
|
||||
@@ -389,10 +389,10 @@ class AppTheme {
|
||||
);
|
||||
}
|
||||
|
||||
// Light theme is minimal — Stitch is dark-only
|
||||
// Light theme is minimal — Projector Noir is dark-first
|
||||
static ThemeData get lightTheme => ThemeData.light(useMaterial3: true).copyWith(
|
||||
colorScheme: AppColors.lightColorScheme,
|
||||
scaffoldBackgroundColor: AppColors.lightColorScheme.surface,
|
||||
textTheme: GoogleFonts.interTextTheme(ThemeData.light().textTheme),
|
||||
textTheme: GoogleFonts.instrumentSansTextTheme(ThemeData.light().textTheme),
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
@@ -140,7 +140,7 @@ class _HeroCarouselState extends State<HeroCarousel> {
|
||||
children: [
|
||||
Text(
|
||||
item.title,
|
||||
style: GoogleFonts.spaceGrotesk(
|
||||
style: GoogleFonts.syne(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.onSurface,
|
||||
@@ -152,7 +152,7 @@ class _HeroCarouselState extends State<HeroCarousel> {
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
item.subtitle!,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 16,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
@@ -245,7 +245,7 @@ class _HeroButtonState extends State<_HeroButton> {
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
widget.label,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurface,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
|
||||
@@ -149,7 +149,7 @@ class _GradientButtonState extends State<GradientButton>
|
||||
],
|
||||
Text(
|
||||
widget.label,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurface,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
@@ -253,7 +253,7 @@ class LiveBadge extends StatelessWidget {
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'LIVE',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w700,
|
||||
@@ -302,7 +302,7 @@ class CategoryChip extends StatelessWidget {
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 13,
|
||||
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500,
|
||||
color: isSelected ? AppColors.primary : AppColors.onSurfaceVariant,
|
||||
@@ -458,7 +458,7 @@ class _MediaCardState extends State<MediaCard>
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
widget.rating!,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w700,
|
||||
@@ -502,7 +502,7 @@ class _MediaCardState extends State<MediaCard>
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: _isHovered
|
||||
? AppColors.primary
|
||||
: AppColors.onSurface,
|
||||
@@ -518,7 +518,7 @@ class _MediaCardState extends State<MediaCard>
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurfaceVariant,
|
||||
fontSize: 11,
|
||||
),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
@@ -38,7 +38,7 @@ class _DigitalClockState extends State<DigitalClock> {
|
||||
),
|
||||
child: Text(
|
||||
timeString,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16,
|
||||
color: AppColors.onSurface,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
@@ -220,7 +220,7 @@ class _HeroCarouselState extends State<HeroCarousel>
|
||||
),
|
||||
child: Text(
|
||||
item.badge!,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primary,
|
||||
@@ -233,7 +233,7 @@ class _HeroCarouselState extends State<HeroCarousel>
|
||||
item.title,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
fontSize: 48,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: AppColors.textPrimary,
|
||||
@@ -247,7 +247,7 @@ class _HeroCarouselState extends State<HeroCarousel>
|
||||
item.subtitle!,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.textSecondary,
|
||||
@@ -292,7 +292,7 @@ class _HeroCarouselState extends State<HeroCarousel>
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Play',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primary,
|
||||
@@ -330,7 +330,7 @@ class _HeroCarouselState extends State<HeroCarousel>
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'More Info',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.textPrimary,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
|
||||
@@ -30,7 +30,7 @@ class ThemedLoading extends StatelessWidget {
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Loading...',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurfaceVariant,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
|
||||
@@ -152,7 +152,7 @@ class _AdminContentState extends ConsumerState<AdminContent>
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
label,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
color: isSelected ? AppColors.textPrimary : AppColors.textSecondary,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -144,7 +144,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
|
||||
// Title
|
||||
Text(
|
||||
'XtremFlow',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 42,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.textPrimary,
|
||||
@@ -154,7 +154,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Sign in to sync your playlists',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 18,
|
||||
color: AppColors.textSecondary,
|
||||
fontWeight: FontWeight.w400,
|
||||
@@ -266,7 +266,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
|
||||
)
|
||||
: Text(
|
||||
'Sign In',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.primary,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -282,7 +282,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
|
||||
const SizedBox(height: 32),
|
||||
Text(
|
||||
'Default: admin / admin',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 14,
|
||||
color: AppColors.textTertiary,
|
||||
),
|
||||
@@ -310,13 +310,13 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
|
||||
return TextFormField(
|
||||
controller: controller,
|
||||
obscureText: obscureText,
|
||||
style: GoogleFonts.inter(fontSize: 18, color: AppColors.textPrimary),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 18, color: AppColors.textPrimary),
|
||||
autofocus: autofocus,
|
||||
textInputAction: nextFocus ? TextInputAction.next : TextInputAction.done,
|
||||
onFieldSubmitted: isLast ? (_) => onSubmitted?.call() : null,
|
||||
decoration: InputDecoration(
|
||||
labelText: label,
|
||||
labelStyle: GoogleFonts.inter(color: AppColors.textSecondary),
|
||||
labelStyle: GoogleFonts.instrumentSans(color: AppColors.textSecondary),
|
||||
prefixIcon: Icon(icon, color: AppColors.textSecondary),
|
||||
suffixIcon: suffix,
|
||||
filled: true,
|
||||
|
||||
@@ -535,7 +535,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
'Unknown')
|
||||
.toString()
|
||||
: widget.title,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -544,7 +544,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
),
|
||||
Text(
|
||||
'Live TV',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.primary,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -706,7 +706,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.title,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
@@ -747,7 +747,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
seconds: _currentPosition.toInt(),
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: Colors.white70,
|
||||
),
|
||||
),
|
||||
@@ -799,7 +799,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
seconds: _totalDuration.toInt(),
|
||||
),
|
||||
),
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: Colors.white70,
|
||||
),
|
||||
),
|
||||
@@ -1060,7 +1060,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
widget.channels != null
|
||||
? widget.channels![_currentIndex].name
|
||||
: widget.title,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -1110,7 +1110,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
children: [
|
||||
Text(
|
||||
currentProgram.title,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white,
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -1121,7 +1121,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
if (currentProgram.description.isNotEmpty)
|
||||
Text(
|
||||
currentProgram.description,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: Colors.white60,
|
||||
fontSize: 12,
|
||||
),
|
||||
@@ -1156,7 +1156,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
widget.channels != null
|
||||
? widget.channels![_currentIndex].name
|
||||
: widget.title,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -1168,7 +1168,7 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
widget.channels != null
|
||||
? widget.channels![_currentIndex].name
|
||||
: widget.title,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -97,7 +97,7 @@ class PlaylistSelectionScreen extends ConsumerWidget {
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Error loading playlists',
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
fontSize: 18,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
@@ -109,7 +109,7 @@ class PlaylistSelectionScreen extends ConsumerWidget {
|
||||
backgroundColor: AppColors.primary,
|
||||
foregroundColor: AppColors.textPrimary,
|
||||
),
|
||||
child: Text('Retry', style: GoogleFonts.inter()),
|
||||
child: Text('Retry', style: GoogleFonts.instrumentSans()),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -128,7 +128,7 @@ class PlaylistSelectionScreen extends ConsumerWidget {
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'No playlists available',
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
fontSize: 18,
|
||||
color: Colors.white60,
|
||||
),
|
||||
@@ -138,7 +138,7 @@ class PlaylistSelectionScreen extends ConsumerWidget {
|
||||
currentUser?.isAdmin ?? false
|
||||
? 'Add playlists in Admin Panel'
|
||||
: 'Contact administrator',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 14,
|
||||
color: Colors.white38,
|
||||
),
|
||||
@@ -269,7 +269,7 @@ class _PlaylistCardState extends State<_PlaylistCard> {
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
widget.playlist.name,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
@@ -281,7 +281,7 @@ class _PlaylistCardState extends State<_PlaylistCard> {
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
Uri.tryParse(widget.playlist.dns)?.host ?? widget.playlist.dns,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 13,
|
||||
color: Colors.white38,
|
||||
letterSpacing: 0.5,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -143,7 +143,7 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
||||
// Title
|
||||
Text(
|
||||
_seriesInfo!.name,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.onSurface,
|
||||
@@ -178,7 +178,7 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
||||
// Season selector
|
||||
Text(
|
||||
'Seasons',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.onSurface,
|
||||
@@ -200,7 +200,7 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
||||
},
|
||||
selectedColor: AppColors.primaryContainer,
|
||||
backgroundColor: AppColors.surfaceContainer,
|
||||
labelStyle: GoogleFonts.inter(
|
||||
labelStyle: GoogleFonts.instrumentSans(
|
||||
color: isSelected ? AppColors.onPrimary : AppColors.onSurfaceVariant,
|
||||
fontSize: 12,
|
||||
),
|
||||
@@ -224,7 +224,7 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Text(
|
||||
'Season $_selectedSeason - ${currentEpisodes.length} Episodes',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.onSurface,
|
||||
@@ -323,7 +323,7 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
||||
? const Icon(Icons.check, color: AppColors.onSurface, size: 20)
|
||||
: Text(
|
||||
'${episode.episodeNum}',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.onSurface,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../../../core/models/playlist_config.dart';
|
||||
@@ -99,7 +99,7 @@ class _EPGWidgetState extends ConsumerState<EPGWidget> {
|
||||
),
|
||||
child: Text(
|
||||
'LIVE',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.onSurface,
|
||||
|
||||
@@ -137,7 +137,7 @@ class _LiveTVTabState extends ConsumerState<LiveTVTab>
|
||||
: _showFavoritesOnly
|
||||
? 'Favorites'
|
||||
: _selectedCategory ?? 'Live TV',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
@@ -157,10 +157,10 @@ class _LiveTVTabState extends ConsumerState<LiveTVTab>
|
||||
),
|
||||
child: TextField(
|
||||
controller: _searchController,
|
||||
style: GoogleFonts.inter(color: Colors.white),
|
||||
style: GoogleFonts.instrumentSans(color: Colors.white),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Search channels...',
|
||||
hintStyle: GoogleFonts.inter(color: Colors.white54),
|
||||
hintStyle: GoogleFonts.instrumentSans(color: Colors.white54),
|
||||
prefixIcon:
|
||||
const Icon(Icons.search, color: Colors.white54),
|
||||
border: InputBorder.none,
|
||||
@@ -235,7 +235,7 @@ class _LiveTVTabState extends ConsumerState<LiveTVTab>
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'No channels found',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: Colors.white54,
|
||||
fontSize: 18,
|
||||
),
|
||||
@@ -319,7 +319,7 @@ class _LiveTVTabState extends ConsumerState<LiveTVTab>
|
||||
child: Text(
|
||||
category,
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
@@ -331,7 +331,7 @@ class _LiveTVTabState extends ConsumerState<LiveTVTab>
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'$count Channels',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 13,
|
||||
color: Colors.white54,
|
||||
),
|
||||
@@ -406,7 +406,7 @@ class _LiveTVTabState extends ConsumerState<LiveTVTab>
|
||||
)
|
||||
: Text(
|
||||
channel.name.characters.first.toUpperCase(),
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
fontSize: 40,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white24,
|
||||
@@ -427,7 +427,7 @@ class _LiveTVTabState extends ConsumerState<LiveTVTab>
|
||||
children: [
|
||||
Text(
|
||||
channel.name,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: Colors.white,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
@@ -452,7 +452,7 @@ class _LiveTVTabState extends ConsumerState<LiveTVTab>
|
||||
if (epgList.isEmpty) {
|
||||
return Text(
|
||||
'No Info',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: Colors.white54,
|
||||
fontSize: 10,
|
||||
),
|
||||
@@ -480,7 +480,7 @@ class _LiveTVTabState extends ConsumerState<LiveTVTab>
|
||||
|
||||
return Text(
|
||||
currentProgram.title,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.ratingGold,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -491,14 +491,14 @@ class _LiveTVTabState extends ConsumerState<LiveTVTab>
|
||||
},
|
||||
loading: () => Text(
|
||||
'...',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: Colors.white24,
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
error: (_, __) => Text(
|
||||
'Err',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: Colors.red,
|
||||
fontSize: 10,
|
||||
),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -219,7 +219,7 @@ class _MoviesTabState extends ConsumerState<MoviesTab> {
|
||||
children: [
|
||||
Text(
|
||||
'Movies',
|
||||
style: GoogleFonts.spaceGrotesk(
|
||||
style: GoogleFonts.syne(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.onSurface,
|
||||
@@ -251,14 +251,14 @@ class _MoviesTabState extends ConsumerState<MoviesTab> {
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _searchController,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 14,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Search movies...',
|
||||
hintStyle:
|
||||
GoogleFonts.inter(color: AppColors.outline),
|
||||
GoogleFonts.instrumentSans(color: AppColors.outline),
|
||||
border: InputBorder.none,
|
||||
isDense: true,
|
||||
contentPadding:
|
||||
@@ -311,7 +311,7 @@ class _MoviesTabState extends ConsumerState<MoviesTab> {
|
||||
title: m.name,
|
||||
imageUrl: _getProxiedImageUrl(m.streamIcon),
|
||||
subtitle: m.rating != null
|
||||
? '${_formatRating(m.rating)} ★'
|
||||
? '${_formatRating(m.rating)} ★'
|
||||
: null,
|
||||
onPlay: () => _playMovie(m),
|
||||
onTap: () => _playMovie(m),
|
||||
@@ -426,7 +426,7 @@ class _MoviesTabState extends ConsumerState<MoviesTab> {
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_formatRating(movie.rating)!,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.onSurface,
|
||||
@@ -448,7 +448,7 @@ class _MoviesTabState extends ConsumerState<MoviesTab> {
|
||||
children: [
|
||||
Text(
|
||||
movie.name,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -467,7 +467,7 @@ class _MoviesTabState extends ConsumerState<MoviesTab> {
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
child: Text(
|
||||
'WATCHED',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.primary,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
||||
@@ -64,7 +64,7 @@ class QualitySelectorButton extends StatelessWidget {
|
||||
Text(
|
||||
q.label,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.textPrimary,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
@@ -73,7 +73,7 @@ class QualitySelectorButton extends StatelessWidget {
|
||||
Text(
|
||||
q.description,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.textTertiary,
|
||||
fontSize: 11,
|
||||
),
|
||||
|
||||
@@ -106,7 +106,7 @@ class _RecordingModalState extends State<RecordingModal> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Programmer un enregistrement',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.onSurface,
|
||||
@@ -120,12 +120,12 @@ class _RecordingModalState extends State<RecordingModal> {
|
||||
// Informations Chaine
|
||||
Text(
|
||||
'Chaîne ciblée :',
|
||||
style: GoogleFonts.inter(color: AppColors.onSurfaceVariant, fontSize: 14),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant, fontSize: 14),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
widget.channel.name,
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface, fontSize: 18),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurface, fontSize: 18),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
@@ -139,7 +139,7 @@ class _RecordingModalState extends State<RecordingModal> {
|
||||
children: [
|
||||
Text(
|
||||
'Date :',
|
||||
style: GoogleFonts.inter(color: AppColors.onSurfaceVariant, fontSize: 14),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant, fontSize: 14),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TvFocusableCard(
|
||||
@@ -173,7 +173,7 @@ class _RecordingModalState extends State<RecordingModal> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${_startTime.day.toString().padLeft(2, '0')}/${_startTime.month.toString().padLeft(2, '0')}/${_startTime.year}',
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurface),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
@@ -193,7 +193,7 @@ class _RecordingModalState extends State<RecordingModal> {
|
||||
children: [
|
||||
Text(
|
||||
'Heure :',
|
||||
style: GoogleFonts.inter(color: AppColors.onSurfaceVariant, fontSize: 14),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant, fontSize: 14),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TvFocusableCard(
|
||||
@@ -236,7 +236,7 @@ class _RecordingModalState extends State<RecordingModal> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${_startTime.hour.toString().padLeft(2, '0')}:${_startTime.minute.toString().padLeft(2, '0')}',
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurface),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -255,7 +255,7 @@ class _RecordingModalState extends State<RecordingModal> {
|
||||
children: [
|
||||
Text(
|
||||
'Durée (min) :',
|
||||
style: GoogleFonts.inter(color: AppColors.onSurfaceVariant, fontSize: 14),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant, fontSize: 14),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
GlassContainer.glass(
|
||||
@@ -277,7 +277,7 @@ class _RecordingModalState extends State<RecordingModal> {
|
||||
child: Text(
|
||||
'$_durationMinutes',
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurface),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
@@ -308,7 +308,7 @@ class _RecordingModalState extends State<RecordingModal> {
|
||||
onPressed: _isLoading ? null : () => Navigator.of(context).pop(),
|
||||
child: Text(
|
||||
'Annuler',
|
||||
style: GoogleFonts.inter(color: AppColors.onSurfaceVariant),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
@@ -328,7 +328,7 @@ class _RecordingModalState extends State<RecordingModal> {
|
||||
)
|
||||
: Text(
|
||||
'Enregistrer de suite',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurface,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
@@ -352,7 +352,7 @@ class _RecordingModalState extends State<RecordingModal> {
|
||||
)
|
||||
: Text(
|
||||
'Programmer',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurface,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
|
||||
@@ -183,7 +183,7 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
children: [
|
||||
Text(
|
||||
'GROUPES',
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white38,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -217,7 +217,7 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
),
|
||||
child: Text(
|
||||
cat,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: isSelected
|
||||
? Colors.white
|
||||
: Colors.white60,
|
||||
@@ -331,7 +331,7 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
Expanded(
|
||||
child: Text(
|
||||
ch.name,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: isSelected
|
||||
? Colors.white
|
||||
: Colors.white70,
|
||||
@@ -370,7 +370,7 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
Text(
|
||||
'Sélectionnez une chaîne\npour voir son guide des programmes',
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white38,
|
||||
fontSize: 15,
|
||||
),
|
||||
@@ -385,7 +385,7 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
children: [
|
||||
Text(
|
||||
_selectedChannel!.name,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
@@ -425,7 +425,7 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
child: Text(
|
||||
'Aucun programme EPG disponible\npour cette chaîne',
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white38,
|
||||
),
|
||||
),
|
||||
@@ -525,7 +525,7 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Enregistrer',
|
||||
style: GoogleFonts.outfit(color: Colors.white),
|
||||
style: GoogleFonts.syne(color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -536,7 +536,7 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
title.isEmpty ? channel.name : title,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
@@ -658,7 +658,7 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
),
|
||||
child: Text(
|
||||
'LIVE',
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white,
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -668,7 +668,7 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
else
|
||||
Text(
|
||||
_fmt(_start),
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: isPast ? Colors.white24 : Colors.white70,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -678,14 +678,14 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
Text(
|
||||
_fmt(_end),
|
||||
style:
|
||||
GoogleFonts.outfit(color: Colors.white24, fontSize: 10),
|
||||
GoogleFonts.syne(color: Colors.white24, fontSize: 10),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
_title.isEmpty ? '—' : _title,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: isPast ? Colors.white38 : Colors.white,
|
||||
fontWeight: isNow ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
@@ -827,7 +827,7 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
backgroundColor: AppColors.surfaceContainer,
|
||||
title: Text(
|
||||
title,
|
||||
style: GoogleFonts.outfit(color: Colors.white, fontSize: 14),
|
||||
style: GoogleFonts.syne(color: Colors.white, fontSize: 14),
|
||||
),
|
||||
content: SizedBox(
|
||||
width: 500,
|
||||
@@ -863,7 +863,7 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
'recording' => Colors.redAccent,
|
||||
'completed' => Colors.green,
|
||||
'failed' => Colors.orangeAccent,
|
||||
_ => Colors.blueAccent,
|
||||
_ => AppColors.primaryContainer,
|
||||
};
|
||||
|
||||
String _statusLabel(String status) => switch (status) {
|
||||
@@ -924,7 +924,7 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Aucun enregistrement',
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white38,
|
||||
fontSize: 16,
|
||||
),
|
||||
@@ -962,7 +962,7 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
),
|
||||
title: Text(
|
||||
rec['title'] ?? '—',
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -1039,7 +1039,7 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.description_outlined,
|
||||
color: Colors.blueAccent,
|
||||
color: AppColors.primaryContainer,
|
||||
size: 20,
|
||||
),
|
||||
tooltip: 'Logs',
|
||||
@@ -1132,7 +1132,7 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Nouveau Season Pass',
|
||||
style: GoogleFonts.outfit(color: Colors.white),
|
||||
style: GoogleFonts.syne(color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -1143,7 +1143,7 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
children: [
|
||||
Text(
|
||||
'Enregistre automatiquement toutes les nouvelles diffusions d\'une émission.',
|
||||
style: GoogleFonts.outfit(color: Colors.white54, fontSize: 13),
|
||||
style: GoogleFonts.syne(color: Colors.white54, fontSize: 13),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildField(
|
||||
@@ -1231,7 +1231,7 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
children: [
|
||||
Text(
|
||||
'Enregistrements automatiques',
|
||||
style: GoogleFonts.outfit(color: Colors.white54, fontSize: 13),
|
||||
style: GoogleFonts.syne(color: Colors.white54, fontSize: 13),
|
||||
),
|
||||
ElevatedButton.icon(
|
||||
style: ElevatedButton.styleFrom(
|
||||
@@ -1262,7 +1262,7 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Scanne l\'EPG toutes les 4h et programme automatiquement les nouvelles diffusions. Seuls les nouveaux épisodes sont enregistrés.',
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.purpleAccent.shade100,
|
||||
fontSize: 12,
|
||||
),
|
||||
@@ -1288,7 +1288,7 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Aucun Season Pass actif',
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white38,
|
||||
fontSize: 16,
|
||||
),
|
||||
@@ -1296,7 +1296,7 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Créez-en un pour enregistrer automatiquement vos émissions préférées',
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white24,
|
||||
fontSize: 12,
|
||||
),
|
||||
@@ -1325,7 +1325,7 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
),
|
||||
title: Text(
|
||||
p['show_title'] ?? '—',
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.syne(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
|
||||
@@ -199,7 +199,7 @@ class _SeriesTabState extends ConsumerState<SeriesTab> {
|
||||
children: [
|
||||
Text(
|
||||
'TV Series',
|
||||
style: GoogleFonts.spaceGrotesk(
|
||||
style: GoogleFonts.syne(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.onSurface,
|
||||
@@ -229,14 +229,14 @@ class _SeriesTabState extends ConsumerState<SeriesTab> {
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _searchController,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 14,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Search series...',
|
||||
hintStyle:
|
||||
GoogleFonts.inter(color: AppColors.outline),
|
||||
GoogleFonts.instrumentSans(color: AppColors.outline),
|
||||
border: InputBorder.none,
|
||||
isDense: true,
|
||||
contentPadding:
|
||||
@@ -397,7 +397,7 @@ class _SeriesTabState extends ConsumerState<SeriesTab> {
|
||||
bottom: 12,
|
||||
child: Text(
|
||||
serie.name,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -440,7 +440,7 @@ class _SeriesTabState extends ConsumerState<SeriesTab> {
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_formatRating(serie.rating)!,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.onSurface,
|
||||
|
||||
@@ -155,7 +155,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
'Thème',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.onSurface,
|
||||
@@ -212,7 +212,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
),
|
||||
title: Text(
|
||||
'Mode actuel',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
@@ -279,7 +279,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isSelected
|
||||
? colorScheme.primary
|
||||
@@ -288,7 +288,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
),
|
||||
Text(
|
||||
subtitle,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 12,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
@@ -327,11 +327,11 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
leading: const Icon(Icons.person, color: AppColors.onSurface),
|
||||
title: Text(
|
||||
'Connecté en tant que',
|
||||
style: GoogleFonts.inter(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
),
|
||||
subtitle: Text(
|
||||
currentUser?.username ?? 'Unknown',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
@@ -340,7 +340,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
? Chip(
|
||||
label: Text(
|
||||
'Admin',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 11,
|
||||
color: AppColors.onPrimaryContainer,
|
||||
),
|
||||
@@ -355,7 +355,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
// Category filters section
|
||||
Text(
|
||||
'Filtres de Catégories',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
color: AppColors.onSurface,
|
||||
@@ -364,7 +364,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Seules les catégories contenant un de ces mots-clés seront affichées. Séparez par des virgules.',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 12,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
),
|
||||
@@ -430,7 +430,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
leading: const Icon(Icons.playlist_play, color: AppColors.onSurface),
|
||||
title: Text(
|
||||
'Changer de Playlist',
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurface),
|
||||
),
|
||||
trailing: const Icon(Icons.chevron_right, color: AppColors.onSurfaceVariant),
|
||||
onTap: () => context.go('/playlists'),
|
||||
@@ -449,11 +449,11 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
leading: const Icon(Icons.info_outline, color: AppColors.onSurface),
|
||||
title: Text(
|
||||
'À propos',
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurface),
|
||||
),
|
||||
subtitle: Text(
|
||||
'XtremFlow IPTV v1.0.0',
|
||||
style: GoogleFonts.inter(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -470,11 +470,11 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
leading: const Icon(Icons.cleaning_services, color: AppColors.warning),
|
||||
title: Text(
|
||||
'Maintenance',
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurface),
|
||||
),
|
||||
subtitle: Text(
|
||||
'En cas de problèmes d\'affichage ou de mise à jour',
|
||||
style: GoogleFonts.inter(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
),
|
||||
trailing: FilledButton.icon(
|
||||
onPressed: () {
|
||||
@@ -573,7 +573,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
title,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 13,
|
||||
color: AppColors.onSurface,
|
||||
@@ -587,7 +587,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Ex: FR,FRANCE,HD,SPORT',
|
||||
hintStyle:
|
||||
GoogleFonts.inter(fontSize: 12, color: AppColors.outline),
|
||||
GoogleFonts.instrumentSans(fontSize: 12, color: AppColors.outline),
|
||||
filled: true,
|
||||
fillColor: AppColors.surfaceContainerHigh,
|
||||
border: OutlineInputBorder(
|
||||
@@ -612,7 +612,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
)
|
||||
: null,
|
||||
),
|
||||
style: GoogleFonts.inter(fontSize: 12, color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 12, color: AppColors.onSurface),
|
||||
onChanged: onChanged,
|
||||
),
|
||||
if (keywords.isNotEmpty) ...[
|
||||
@@ -633,7 +633,7 @@ class _SettingsTabState extends ConsumerState<SettingsTab>
|
||||
child: Text(
|
||||
keyword,
|
||||
style:
|
||||
GoogleFonts.inter(fontSize: 11, color: AppColors.onSurface),
|
||||
GoogleFonts.instrumentSans(fontSize: 11, color: AppColors.onSurface),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
|
||||
@@ -19,7 +19,7 @@ class StreamingSettingsTab extends ConsumerWidget {
|
||||
// Header
|
||||
Text(
|
||||
'Paramètres Streaming Live TV',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.onSurface,
|
||||
@@ -28,7 +28,7 @@ class StreamingSettingsTab extends ConsumerWidget {
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Ces paramètres s\'appliquent uniquement aux flux TV en direct.',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 12,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
),
|
||||
@@ -105,14 +105,14 @@ class StreamingSettingsTab extends ConsumerWidget {
|
||||
SwitchListTile(
|
||||
title: Text(
|
||||
'Reconnexion automatique',
|
||||
style: GoogleFonts.inter(fontSize: 14, color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 14, color: AppColors.onSurface),
|
||||
),
|
||||
subtitle: Text(
|
||||
'Se reconnecter en cas de coupure',
|
||||
style: GoogleFonts.inter(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
),
|
||||
value: settings.autoReconnect,
|
||||
activeThumbColor: Colors.blueAccent,
|
||||
activeThumbColor: AppColors.primaryContainer,
|
||||
onChanged: (v) => notifier.setAutoReconnect(v),
|
||||
),
|
||||
],
|
||||
@@ -141,14 +141,14 @@ class StreamingSettingsTab extends ConsumerWidget {
|
||||
SwitchListTile(
|
||||
title: Text(
|
||||
'Préférer lecture directe',
|
||||
style: GoogleFonts.inter(fontSize: 14, color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 14, color: AppColors.onSurface),
|
||||
),
|
||||
subtitle: Text(
|
||||
'Utiliser le flux original si compatible',
|
||||
style: GoogleFonts.inter(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
),
|
||||
value: settings.preferDirectPlay,
|
||||
activeThumbColor: Colors.blueAccent,
|
||||
activeThumbColor: AppColors.primaryContainer,
|
||||
onChanged: (v) => notifier.setPreferDirectPlay(v),
|
||||
),
|
||||
],
|
||||
@@ -186,11 +186,11 @@ class StreamingSettingsTab extends ConsumerWidget {
|
||||
SwitchListTile(
|
||||
title: Text(
|
||||
'Accélération NVIDIA GPU',
|
||||
style: GoogleFonts.inter(fontSize: 14, color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 14, color: AppColors.onSurface),
|
||||
),
|
||||
subtitle: Text(
|
||||
'Utiliser NVENC/NVDEC pour le transcodage (requiert GPU NVIDIA)',
|
||||
style: GoogleFonts.inter(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
),
|
||||
value: settings.enableNvidiaGpu,
|
||||
activeThumbColor: Colors.green,
|
||||
@@ -204,20 +204,20 @@ class StreamingSettingsTab extends ConsumerWidget {
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.withOpacity(0.1),
|
||||
color: AppColors.primary.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: Colors.blue.withOpacity(0.3)),
|
||||
border: Border.all(color: AppColors.primary.withOpacity(0.3)),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.info_outline, color: Colors.blue),
|
||||
const Icon(Icons.info_outline, color: AppColors.primary),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Les changements prennent effet immédiatement pour les nouveaux flux.',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 12,
|
||||
color: Colors.blue.shade700,
|
||||
color: AppColors.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -247,11 +247,11 @@ class StreamingSettingsTab extends ConsumerWidget {
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, size: 20, color: Colors.blueAccent),
|
||||
Icon(icon, size: 20, color: AppColors.primaryContainer),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
title,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.onSurface,
|
||||
@@ -278,11 +278,11 @@ class StreamingSettingsTab extends ConsumerWidget {
|
||||
return ListTile(
|
||||
title: Text(
|
||||
title,
|
||||
style: GoogleFonts.inter(fontSize: 14, color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 14, color: AppColors.onSurface),
|
||||
),
|
||||
subtitle: Text(
|
||||
subtitle,
|
||||
style: GoogleFonts.inter(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 12, color: AppColors.onSurfaceVariant),
|
||||
),
|
||||
trailing: DropdownButton<T>(
|
||||
value: value,
|
||||
@@ -293,12 +293,12 @@ class StreamingSettingsTab extends ConsumerWidget {
|
||||
value: item,
|
||||
child: Text(
|
||||
labelBuilder(item),
|
||||
style: GoogleFonts.inter(fontSize: 13, color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(fontSize: 13, color: AppColors.onSurface),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: onChanged,
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurface),
|
||||
iconEnabledColor: AppColors.onSurfaceVariant,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -124,7 +124,7 @@ class _MobileLoginScreenState extends ConsumerState<MobileLoginScreen> {
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
'XtremFlow',
|
||||
style: GoogleFonts.spaceGrotesk(
|
||||
style: GoogleFonts.syne(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.onSurface,
|
||||
@@ -133,7 +133,7 @@ class _MobileLoginScreenState extends ConsumerState<MobileLoginScreen> {
|
||||
),
|
||||
Text(
|
||||
'Mobile Edition',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 14,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
letterSpacing: 0.5,
|
||||
@@ -173,7 +173,7 @@ class _MobileLoginScreenState extends ConsumerState<MobileLoginScreen> {
|
||||
),
|
||||
child: Text(
|
||||
authState.errorMessage!,
|
||||
style: GoogleFonts.inter(color: AppColors.error, fontSize: 13),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.error, fontSize: 13),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
@@ -213,7 +213,7 @@ class _MobileLoginScreenState extends ConsumerState<MobileLoginScreen> {
|
||||
)
|
||||
: Text(
|
||||
'Sign In',
|
||||
style: GoogleFonts.inter(fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white),
|
||||
style: GoogleFonts.instrumentSans(fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -243,10 +243,10 @@ class _MobileLoginScreenState extends ConsumerState<MobileLoginScreen> {
|
||||
return TextFormField(
|
||||
controller: controller,
|
||||
obscureText: obscureText,
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurface),
|
||||
decoration: InputDecoration(
|
||||
labelText: label,
|
||||
labelStyle: GoogleFonts.inter(color: AppColors.onSurfaceVariant),
|
||||
labelStyle: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant),
|
||||
prefixIcon: Icon(icon, color: AppColors.onSurfaceVariant),
|
||||
suffixIcon: isPassword
|
||||
? IconButton(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import '../../../../features/iptv/providers/xtream_provider.dart';
|
||||
@@ -70,7 +70,7 @@ class MobilePlaylistSelectionScreen extends ConsumerWidget {
|
||||
color: AppColors.error,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text('Error loading playlists', style: GoogleFonts.inter()),
|
||||
Text('Error loading playlists', style: GoogleFonts.instrumentSans()),
|
||||
TextButton(
|
||||
onPressed: () => ref.refresh(playlistsProvider),
|
||||
child: const Text('Retry'),
|
||||
@@ -92,7 +92,7 @@ class MobilePlaylistSelectionScreen extends ConsumerWidget {
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'No playlists available',
|
||||
style: GoogleFonts.inter(color: AppColors.textSecondary),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.textSecondary),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -177,7 +177,7 @@ class _MobilePlaylistCard extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
playlist.name,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
@@ -188,7 +188,7 @@ class _MobilePlaylistCard extends StatelessWidget {
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
Uri.tryParse(playlist.dns)?.host ?? playlist.dns,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 13,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -110,7 +110,7 @@ class _MobileSeriesDetailScreenState
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Error: $_error',
|
||||
style: GoogleFonts.inter(color: AppColors.onSurfaceVariant),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _loadSeriesInfo,
|
||||
@@ -186,7 +186,7 @@ class _MobileSeriesDetailScreenState
|
||||
children: [
|
||||
Text(
|
||||
_seriesInfo!.name,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.onSurface,
|
||||
@@ -204,7 +204,7 @@ class _MobileSeriesDetailScreenState
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_formatRating(_seriesInfo!.rating!)!,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurfaceVariant,
|
||||
fontSize: 13,
|
||||
),
|
||||
@@ -213,7 +213,7 @@ class _MobileSeriesDetailScreenState
|
||||
],
|
||||
Text(
|
||||
'${_seriesInfo!.episodes.keys.length} Seasons',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurfaceVariant,
|
||||
fontSize: 13,
|
||||
),
|
||||
@@ -235,7 +235,7 @@ class _MobileSeriesDetailScreenState
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
_seriesInfo!.plot!,
|
||||
style: GoogleFonts.inter(color: AppColors.onSurfaceVariant, height: 1.4),
|
||||
style: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant, height: 1.4),
|
||||
maxLines: 4,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -262,7 +262,7 @@ class _MobileSeriesDetailScreenState
|
||||
},
|
||||
backgroundColor: AppColors.surfaceContainer,
|
||||
selectedColor: AppColors.primary,
|
||||
labelStyle: GoogleFonts.inter(
|
||||
labelStyle: GoogleFonts.instrumentSans(
|
||||
color: isSelected ? AppColors.onPrimary : AppColors.onSurfaceVariant,
|
||||
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
|
||||
),
|
||||
@@ -357,7 +357,7 @@ class _MobileSeriesDetailScreenState
|
||||
children: [
|
||||
Text(
|
||||
'E${episode.episodeNum} - ${episode.title}',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurface,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
@@ -369,7 +369,7 @@ class _MobileSeriesDetailScreenState
|
||||
episode.durationSecs! > 0)
|
||||
Text(
|
||||
_formatDuration(episode.durationSecs!),
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurfaceVariant,
|
||||
fontSize: 12,
|
||||
),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../../../../features/iptv/providers/xtream_provider.dart';
|
||||
@@ -80,7 +80,7 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab> {
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Failed to load channels',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -153,11 +153,11 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab> {
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _searchController,
|
||||
style: GoogleFonts.inter(color: Colors.white),
|
||||
style: GoogleFonts.instrumentSans(color: Colors.white),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Search channels...',
|
||||
hintStyle:
|
||||
GoogleFonts.inter(color: Colors.white54),
|
||||
GoogleFonts.instrumentSans(color: Colors.white54),
|
||||
border: InputBorder.none,
|
||||
prefixIcon: const Icon(
|
||||
Icons.search,
|
||||
@@ -207,7 +207,7 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab> {
|
||||
),
|
||||
child: Text(
|
||||
category,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color:
|
||||
isSelected ? Colors.black : Colors.white70,
|
||||
fontWeight: isSelected
|
||||
@@ -233,7 +233,7 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab> {
|
||||
: _showFavoritesOnly
|
||||
? 'Favorites'
|
||||
: _selectedCategory ?? 'Channels',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
@@ -285,7 +285,7 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab> {
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'No channels found',
|
||||
style: GoogleFonts.inter(color: Colors.white38),
|
||||
style: GoogleFonts.instrumentSans(color: Colors.white38),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -382,7 +382,7 @@ class _MobileChannelTile extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Text(
|
||||
channel.name,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -180,7 +180,7 @@ class _MobileMoviesTabState extends ConsumerState<MobileMoviesTab> {
|
||||
id: m.streamId,
|
||||
title: m.name,
|
||||
imageUrl: _getProxiedImageUrl(m.streamIcon, ref),
|
||||
subtitle: m.rating != null ? '${_formatRating(m.rating)} ★' : null,
|
||||
subtitle: m.rating != null ? '${_formatRating(m.rating)} ★' : null,
|
||||
onMoreInfo: () => _playMovie(m, displayMovies),
|
||||
),
|
||||
)
|
||||
@@ -206,13 +206,13 @@ class _MobileMoviesTabState extends ConsumerState<MobileMoviesTab> {
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _searchController,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 14,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Search Movies...',
|
||||
hintStyle: GoogleFonts.inter(color: AppColors.onSurfaceVariant),
|
||||
hintStyle: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant),
|
||||
border: InputBorder.none,
|
||||
isDense: true,
|
||||
contentPadding: const EdgeInsets.only(bottom: 11),
|
||||
@@ -346,7 +346,7 @@ class _MobileMoviesTabState extends ConsumerState<MobileMoviesTab> {
|
||||
children: [
|
||||
Text(
|
||||
movie.name,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -357,7 +357,7 @@ class _MobileMoviesTabState extends ConsumerState<MobileMoviesTab> {
|
||||
if (isWatched)
|
||||
Text(
|
||||
'WATCHED',
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.primary,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -389,7 +389,7 @@ class _MobileMoviesTabState extends ConsumerState<MobileMoviesTab> {
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_formatRating(movie.rating)!,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.onSurface,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -171,7 +171,7 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab> {
|
||||
id: s.seriesId.toString(),
|
||||
title: s.name,
|
||||
imageUrl: _getProxiedImageUrl(s.cover, ref),
|
||||
subtitle: s.rating != null ? '${_formatRating(s.rating)} ★' : null,
|
||||
subtitle: s.rating != null ? '${_formatRating(s.rating)} ★' : null,
|
||||
onMoreInfo: () => _openSeries(s),
|
||||
),
|
||||
)
|
||||
@@ -197,13 +197,13 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab> {
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _searchController,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 14,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Search Series...',
|
||||
hintStyle: GoogleFonts.inter(color: AppColors.onSurfaceVariant),
|
||||
hintStyle: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant),
|
||||
border: InputBorder.none,
|
||||
isDense: true,
|
||||
contentPadding: const EdgeInsets.only(bottom: 11),
|
||||
@@ -332,7 +332,7 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab> {
|
||||
right: 12,
|
||||
child: Text(
|
||||
series.name,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -364,7 +364,7 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab> {
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_formatRating(series.rating)!,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.onSurface,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -398,7 +398,7 @@ class _SectionHeader extends StatelessWidget {
|
||||
padding: const EdgeInsets.only(left: 8, bottom: 8),
|
||||
child: Text(
|
||||
title,
|
||||
style: GoogleFonts.inter(
|
||||
style: GoogleFonts.instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
|
||||
@@ -32,69 +32,69 @@ class MobileTheme {
|
||||
|
||||
// Typography: Scaled down for mobile
|
||||
textTheme: TextTheme(
|
||||
displayLarge: GoogleFonts.spaceGrotesk(
|
||||
displayLarge: GoogleFonts.syne(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w700,
|
||||
letterSpacing: -0.02,
|
||||
height: 1.1,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
displayMedium: GoogleFonts.spaceGrotesk(
|
||||
displayMedium: GoogleFonts.syne(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: -0.01,
|
||||
height: 1.2,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
displaySmall: GoogleFonts.spaceGrotesk(
|
||||
displaySmall: GoogleFonts.syne(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.3,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
headlineMedium: GoogleFonts.spaceGrotesk(
|
||||
headlineMedium: GoogleFonts.syne(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.3,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
titleLarge: GoogleFonts.spaceGrotesk(
|
||||
titleLarge: GoogleFonts.syne(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
titleMedium: GoogleFonts.inter(
|
||||
titleMedium: GoogleFonts.instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
bodyLarge: GoogleFonts.inter(
|
||||
bodyLarge: GoogleFonts.instrumentSans(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.5,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
),
|
||||
bodyMedium: GoogleFonts.inter(
|
||||
bodyMedium: GoogleFonts.instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.5,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
),
|
||||
labelLarge: GoogleFonts.inter(
|
||||
labelLarge: GoogleFonts.instrumentSans(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: 0.05,
|
||||
height: 1.2,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
labelMedium: GoogleFonts.inter(
|
||||
labelMedium: GoogleFonts.instrumentSans(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
letterSpacing: 0.02,
|
||||
height: 1.2,
|
||||
color: AppColors.onSurface,
|
||||
),
|
||||
labelSmall: GoogleFonts.inter(
|
||||
labelSmall: GoogleFonts.instrumentSans(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w500,
|
||||
letterSpacing: 0.02,
|
||||
@@ -110,7 +110,7 @@ class MobileTheme {
|
||||
elevation: 0,
|
||||
centerTitle: true,
|
||||
scrolledUnderElevation: 0,
|
||||
titleTextStyle: GoogleFonts.spaceGrotesk(
|
||||
titleTextStyle: GoogleFonts.syne(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.onSurface,
|
||||
@@ -122,11 +122,11 @@ class MobileTheme {
|
||||
backgroundColor: AppColors.surfaceContainerLow.withOpacity(0.9),
|
||||
selectedItemColor: AppColors.onSurface,
|
||||
unselectedItemColor: AppColors.outline,
|
||||
selectedLabelStyle: GoogleFonts.inter(
|
||||
selectedLabelStyle: GoogleFonts.instrumentSans(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
unselectedLabelStyle: GoogleFonts.inter(
|
||||
unselectedLabelStyle: GoogleFonts.instrumentSans(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
@@ -157,7 +157,7 @@ class MobileTheme {
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
hintStyle: GoogleFonts.inter(
|
||||
hintStyle: GoogleFonts.instrumentSans(
|
||||
color: AppColors.outline,
|
||||
fontSize: 14,
|
||||
),
|
||||
@@ -173,7 +173,7 @@ class MobileTheme {
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radiusMd),
|
||||
),
|
||||
textStyle: GoogleFonts.inter(
|
||||
textStyle: GoogleFonts.instrumentSans(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
@@ -60,9 +60,9 @@ class MobileScaffold extends ConsumerWidget {
|
||||
selectedItemColor: AppColors.primary,
|
||||
unselectedItemColor: AppColors.textSecondary,
|
||||
selectedLabelStyle:
|
||||
GoogleFonts.inter(fontWeight: FontWeight.w600, fontSize: 11),
|
||||
GoogleFonts.instrumentSans(fontWeight: FontWeight.w600, fontSize: 11),
|
||||
unselectedLabelStyle:
|
||||
GoogleFonts.inter(fontWeight: FontWeight.w500, fontSize: 11),
|
||||
GoogleFonts.instrumentSans(fontWeight: FontWeight.w500, fontSize: 11),
|
||||
items: const [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.live_tv_rounded),
|
||||
|
||||
+4
-4
@@ -27,7 +27,7 @@
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(135deg, #0F1014 0%, #181920 100%);
|
||||
background: linear-gradient(135deg, #0B0A08 0%, #1B1812 100%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@@ -55,7 +55,7 @@
|
||||
.logo {
|
||||
font-size: 48px;
|
||||
font-weight: 700;
|
||||
background: linear-gradient(135deg, #007AFF 0%, #00C6FF 100%);
|
||||
background: linear-gradient(135deg, #E8941A 0%, #FFC36A 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
@@ -67,8 +67,8 @@
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 auto 16px;
|
||||
border: 3px solid rgba(0, 122, 255, 0.2);
|
||||
border-top-color: #007AFF;
|
||||
border: 3px solid rgba(243, 154, 31, 0.2);
|
||||
border-top-color: #F39A1F;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
+9
-9
@@ -1,14 +1,14 @@
|
||||
/* XtremFlow web player theme tokens.
|
||||
Mirrors lib/core/theme/app_colors.dart (Cyber-Cinematic Glass).
|
||||
Mirrors lib/core/theme/app_colors.dart (Projector Noir).
|
||||
Keep both files in sync when the palette changes. */
|
||||
:root {
|
||||
--color-bg: #0F1014; /* AppColors.baseLevel0 */
|
||||
--color-surface: #121317; /* AppColors.surface */
|
||||
--color-text: #e3e2e7; /* AppColors.textPrimary */
|
||||
--color-text-secondary: #c1c6d7;/* AppColors.textSecondary */
|
||||
--color-accent: #adc6ff; /* AppColors.primary */
|
||||
--color-accent-strong: #4b8eff; /* AppColors.primaryContainer */
|
||||
--color-bg: #0B0A08; /* AppColors.baseLevel0 */
|
||||
--color-surface: #14110C; /* AppColors.surface */
|
||||
--color-text: #ECE6DA; /* AppColors.textPrimary */
|
||||
--color-text-secondary: #CDC4B4;/* AppColors.textSecondary */
|
||||
--color-accent: #FFB35C; /* AppColors.primary */
|
||||
--color-accent-strong: #F39A1F; /* AppColors.primaryContainer */
|
||||
--color-error: #ffb4ab; /* AppColors.error */
|
||||
--color-overlay: rgba(15, 16, 20, 0.6);
|
||||
--color-border: rgba(255, 255, 255, 0.1); /* glassLevel1Border */
|
||||
--color-overlay: rgba(11, 10, 8, 0.6);
|
||||
--color-border: rgba(255, 233, 201, 0.1); /* glassLevel1Border */
|
||||
}
|
||||
Reference in new issue
Block a user