- m8logo.svg: inline fills (flutter_svg ignores <style> blocks; logo rendered black) - theme.dart v2.0.0: purple -> site palette (#1265ED / #3B8BFF / navy darks) - app_config.dart: appVersion 1.3.0 -> 1.6.0 (profile screen showed stale version) - manifest.json: theme/background colours to match - Remove em-dashes from user-visible UI strings (global style rule) - chat_screen.dart: fix use_build_context_synchronously in _leaveRoom - Deployed to app2.m8chat.au after full functionality audit (all green) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
140 lines
4.7 KiB
Dart
140 lines
4.7 KiB
Dart
// Version: 2.0.0 | Created: 2026-04-01 | Updated: 2026-07-03
|
|
// M8Chat brand theme — dark and light variants.
|
|
// Palette from the m8chat.au Elementor kit (kit post 8):
|
|
// Accent #1 "#1265ED", Blue Element "#3B8BFF", Ancop Blue "#010B46".
|
|
// v2.0.0 replaces the old purple scheme, which did not match the website.
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
/// M8Chat brand colours.
|
|
abstract final class M8Colours {
|
|
static const Color brandBlue = Color(0xFF1265ED);
|
|
static const Color accentBlue = Color(0xFF3B8BFF);
|
|
static const Color darkBackground = Color(0xFF0A0F2E);
|
|
static const Color darkSurface = Color(0xFF131A42);
|
|
static const Color darkSurfaceVariant = Color(0xFF1C2452);
|
|
static const Color onDarkSurface = Color(0xFFE8ECF5);
|
|
static const Color subtleText = Color(0xFF96A0C2);
|
|
static const Color errorRed = Color(0xFFCF6679);
|
|
static const Color unreadGreen = Color(0xFF4CAF50);
|
|
}
|
|
|
|
/// Dark theme — default for M8Chat.
|
|
ThemeData buildDarkTheme() {
|
|
const seed = M8Colours.brandBlue;
|
|
|
|
final scheme =
|
|
ColorScheme.fromSeed(
|
|
seedColor: seed,
|
|
brightness: Brightness.dark,
|
|
).copyWith(
|
|
surface: M8Colours.darkBackground,
|
|
surfaceContainerHighest: M8Colours.darkSurface,
|
|
primary: M8Colours.accentBlue,
|
|
onSurface: M8Colours.onDarkSurface,
|
|
error: M8Colours.errorRed,
|
|
);
|
|
|
|
return ThemeData(
|
|
useMaterial3: true,
|
|
colorScheme: scheme,
|
|
scaffoldBackgroundColor: M8Colours.darkBackground,
|
|
appBarTheme: AppBarTheme(
|
|
backgroundColor: M8Colours.darkSurface,
|
|
foregroundColor: M8Colours.onDarkSurface,
|
|
elevation: 0,
|
|
surfaceTintColor: Colors.transparent,
|
|
),
|
|
navigationBarTheme: NavigationBarThemeData(
|
|
backgroundColor: M8Colours.darkSurface,
|
|
indicatorColor: M8Colours.accentBlue.withAlpha(51),
|
|
labelTextStyle: WidgetStateProperty.all(
|
|
const TextStyle(fontSize: 12, color: M8Colours.onDarkSurface),
|
|
),
|
|
),
|
|
inputDecorationTheme: InputDecorationTheme(
|
|
filled: true,
|
|
fillColor: M8Colours.darkSurfaceVariant,
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
borderSide: BorderSide.none,
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
borderSide: const BorderSide(color: M8Colours.accentBlue, width: 2),
|
|
),
|
|
labelStyle: const TextStyle(color: M8Colours.subtleText),
|
|
hintStyle: const TextStyle(color: M8Colours.subtleText),
|
|
),
|
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: M8Colours.accentBlue,
|
|
foregroundColor: Colors.white,
|
|
minimumSize: const Size.fromHeight(52),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
|
textStyle: const TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
letterSpacing: 0.5,
|
|
),
|
|
),
|
|
),
|
|
cardTheme: CardThemeData(
|
|
color: M8Colours.darkSurface,
|
|
elevation: 0,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
|
),
|
|
dividerTheme: const DividerThemeData(
|
|
color: M8Colours.darkSurfaceVariant,
|
|
thickness: 1,
|
|
),
|
|
snackBarTheme: SnackBarThemeData(
|
|
backgroundColor: M8Colours.darkSurfaceVariant,
|
|
contentTextStyle: const TextStyle(color: M8Colours.onDarkSurface),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Light theme — follows system preference if user selects it.
|
|
ThemeData buildLightTheme() {
|
|
const seed = M8Colours.brandBlue;
|
|
|
|
final scheme = ColorScheme.fromSeed(
|
|
seedColor: seed,
|
|
brightness: Brightness.light,
|
|
);
|
|
|
|
return ThemeData(
|
|
useMaterial3: true,
|
|
colorScheme: scheme,
|
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
style: ElevatedButton.styleFrom(
|
|
minimumSize: const Size.fromHeight(52),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
|
textStyle: const TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
letterSpacing: 0.5,
|
|
),
|
|
),
|
|
),
|
|
inputDecorationTheme: InputDecorationTheme(
|
|
filled: true,
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
borderSide: BorderSide.none,
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
borderSide: BorderSide(color: scheme.primary, width: 2),
|
|
),
|
|
),
|
|
snackBarTheme: SnackBarThemeData(
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
}
|