127 lines
4.2 KiB
Dart
127 lines
4.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import '../core/providers/locale_provider.dart';
|
|
import '../core/providers/theme_provider.dart';
|
|
|
|
const _orange = Color(0xFFFF6B00);
|
|
|
|
const _langs = [
|
|
('EN', Locale('en')),
|
|
('FR', Locale('fr')),
|
|
('AR', Locale('ar')),
|
|
];
|
|
|
|
/// Compact language dropdown + theme toggle.
|
|
/// [onDark] = true when rendered on a dark background (landing screen).
|
|
class PreferencesBar extends ConsumerWidget {
|
|
final bool onDark;
|
|
|
|
const PreferencesBar({super.key, this.onDark = false});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final currentLocale = ref.watch(localeProvider);
|
|
final themeMode = ref.watch(themeProvider);
|
|
final isDark = themeMode == ThemeMode.dark;
|
|
final cs = Theme.of(context).colorScheme;
|
|
|
|
final chipBg = onDark
|
|
? Colors.white.withValues(alpha: 0.12)
|
|
: cs.surfaceContainerHighest;
|
|
final iconColor = onDark
|
|
? Colors.white.withValues(alpha: 0.8)
|
|
: cs.onSurfaceVariant;
|
|
final langCode = currentLocale.languageCode.toUpperCase();
|
|
|
|
return Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// ── Language dropdown ──────────────────────────────────────────
|
|
PopupMenuButton<Locale>(
|
|
onSelected: (locale) =>
|
|
ref.read(localeProvider.notifier).setLocale(locale),
|
|
color: cs.surfaceContainerHigh,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
side: BorderSide(color: cs.outlineVariant),
|
|
),
|
|
offset: const Offset(0, 36),
|
|
itemBuilder: (_) => _langs.map((item) {
|
|
final (code, locale) = item;
|
|
final selected =
|
|
currentLocale.languageCode == locale.languageCode;
|
|
return PopupMenuItem<Locale>(
|
|
value: locale,
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
code,
|
|
style: TextStyle(
|
|
color: selected ? _orange : cs.onSurface,
|
|
fontWeight: selected
|
|
? FontWeight.bold
|
|
: FontWeight.normal,
|
|
fontSize: 14,
|
|
),
|
|
),
|
|
),
|
|
if (selected)
|
|
const Icon(Icons.check, size: 16, color: _orange),
|
|
],
|
|
),
|
|
);
|
|
}).toList(),
|
|
child: Container(
|
|
padding:
|
|
const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
|
decoration: BoxDecoration(
|
|
color: chipBg,
|
|
borderRadius: BorderRadius.circular(20),
|
|
),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
langCode,
|
|
style: TextStyle(
|
|
color: onDark ? Colors.white : cs.onSurface,
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
const SizedBox(width: 2),
|
|
Icon(
|
|
Icons.expand_more,
|
|
size: 14,
|
|
color: iconColor,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
|
|
const SizedBox(width: 6),
|
|
|
|
// ── Theme toggle ───────────────────────────────────────────────
|
|
GestureDetector(
|
|
onTap: () => ref.read(themeProvider.notifier).toggle(),
|
|
child: Container(
|
|
padding: const EdgeInsets.all(7),
|
|
decoration: BoxDecoration(
|
|
color: chipBg,
|
|
borderRadius: BorderRadius.circular(20),
|
|
),
|
|
child: Icon(
|
|
isDark ? Icons.light_mode_outlined : Icons.dark_mode_outlined,
|
|
size: 15,
|
|
color: iconColor,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|