real time theme switching

This commit is contained in:
mohamadmahdi jebeli 2025-09-22 10:45:40 +03:30
parent 4bc390c3e3
commit e283a5cef1
6 changed files with 854 additions and 6 deletions

148
LANGUAGE_QUICK_GUIDE.md Normal file
View File

@ -0,0 +1,148 @@
# 🔧 Language System - Quick Implementation Guide
## ⚡ سریع‌ترین راه اضافه کردن انتخاب زبان
### 1⃣ Import های مورد نیاز
```dart
import 'package:flutter_svg/flutter_svg.dart';
import '../../widgets/language_selection_dialog.dart';
import '../../gen/assets.gen.dart';
import '../../res/colors.dart';
```
### 2⃣ اضافه کردن State Variables
```dart
class _YourPageState extends State<YourPage> {
String _currentLanguage = '🇺🇲 English';
String _currentFlag = 'assets/icons/usa circle.svg';
final GlobalKey _languageKey = GlobalKey();
}
```
### 3⃣ کپی/پیست Widget کامل
```dart
GestureDetector(
key: _languageKey,
onTap: () {
showLanguageSelectionOverlay(
context,
_currentLanguage,
(language, flag) {
setState(() {
_currentLanguage = language;
_currentFlag = flag;
});
},
_languageKey,
);
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: ClipRRect(
key: ValueKey(_currentFlag),
borderRadius: BorderRadius.circular(4),
child: _currentFlag.endsWith('.svg')
? SvgPicture.asset(_currentFlag, width: 24, height: 18)
: Image.asset(_currentFlag, width: 24, height: 18, fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) => Container(
width: 24, height: 18,
decoration: BoxDecoration(
color: AppColors.greyBorder.withOpacity(0.2),
borderRadius: BorderRadius.circular(4),
),
child: Icon(Icons.flag, color: AppColors.textSecondary, size: 12),
),
),
),
),
const SizedBox(width: 8),
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: Text(
_currentLanguage,
key: ValueKey(_currentLanguage),
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color: AppColors.textPrimary,
),
),
),
const SizedBox(width: 8),
SvgPicture.asset(Assets.icons.arrowRight.path, color: AppColors.textPrimary),
],
),
),
```
## 🎯 مواقع استفاده
### در Onboarding (بالای راست)
```dart
Container(
padding: EdgeInsets.fromLTRB(width/15, height/20, width/15, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Skip'), // دکمه Skip
LanguageWidget(), // Widget بالا
],
),
)
```
### در Profile (قسمت Settings)
```dart
_buildInfoTile(
icon: SvgPicture.asset(Assets.icons.languageSquare.path, width: 22),
title: 'Language',
trailing: LanguageWidget(), // Widget بالا
),
```
## ⚙️ تنظیمات اختیاری
### حافظه زبان با SharedPreferences
```dart
Future<void> _saveLanguage(String languageCode) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('selected_language', languageCode);
}
Future<void> _loadLanguage() async {
final prefs = await SharedPreferences.getInstance();
final savedLang = prefs.getString('selected_language') ?? 'en';
// set initial language based on savedLang
}
```
### اضافه کردن زبان جدید
در `language_selection_dialog.dart`:
```dart
final List<Map<String, String>> languages = [
{'name': '🇺🇲 English', 'code': 'en', 'flag': 'assets/icons/usa circle.svg'},
{'name': '🇦🇪 العربية', 'code': 'ar', 'flag': 'assets/icons/arab circle.svg'},
{'name': '🇮🇷 فارسی', 'code': 'fa', 'flag': 'assets/icons/iran circle.svg'},
];
```
## 🚨 نکات مهم
1. **GlobalKey ضروری است** برای positioning صحیح overlay
2. **AnimatedSwitcher** برای animation های smooth
3. **Error handling** برای asset های مفقود
4. **ValueKey** برای performance بهتر
## 🔍 Debug
```dart
print('Current language: $_currentLanguage');
print('Current flag: $_currentFlag');
print('Target position: ${_languageKey.currentContext?.findRenderObject()}');
```
---
*راهنمای سریع - نسخه 1.0*

View File

@ -0,0 +1,439 @@
# 🌐 سیستم تغییر زبان در اپلیکیشن LBA
## 📋 فهرست مطالب
1. [معرفی کلی](#معرفی-کلی)
2. [ساختار فایل‌ها](#ساختار-فایلها)
3. [زبان‌های پشتیبانی شده](#زبانهای-پشتیبانی-شده)
4. [کامپوننت‌های کلیدی](#کامپوننتهای-کلیدی)
5. [نحوه پیاده‌سازی](#نحوه-پیادهسازی)
6. [مدیریت State](#مدیریت-state)
7. [UI/UX طراحی](#uiux-طراحی)
8. [نکات فنی](#نکات-فنی)
9. [استفاده در صفحات مختلف](#استفاده-در-صفحات-مختلف)
10. [عیب‌یابی](#عیبیابی)
---
## 🎯 معرفی کلی
سیستم تغییر زبان در اپ LBA امکان انتخاب بین سه زبان **انگلیسی**، **عربی** و **فارسی** را فراهم می‌کند. این سیستم در دو صفحه اصلی قابل دسترسی است:
- **صفحه Onboarding** (بالای راست)
- **صفحه Profile** (بخش تنظیمات)
---
## 📁 ساختار فایل‌ها
```
lib/
├── widgets/
│ └── language_selection_dialog.dart # کامپوننت اصلی انتخاب زبان
├── screens/
│ ├── auth/
│ │ └── onboarding_page.dart # صفحه معرفی با انتخاب زبان
│ └── mains/profile/
│ └── profile.dart # صفحه پروفایل
├── gen/
│ └── assets.gen.dart # فایل‌های asset تولید شده
└── res/
└── colors.dart # رنگ‌های اپلیکیشن
```
---
## 🌍 زبان‌های پشتیبانی شده
| زبان | کد | پرچم | فایل آیکون |
|------|----|----- |------------|
| **English** | `en` | 🇺🇲 | `assets/icons/usa circle.svg` |
| **العربية** | `ar` | 🇦🇪 | `assets/icons/arab circle.svg` |
| **فارسی** | `fa` | 🇮🇷 | `assets/icons/iran circle.svg` |
---
## 🔧 کامپوننت‌های کلیدی
### 1. `LanguageSelectionOverlay`
کامپوننت اصلی که overlay انتخاب زبان را نمایش می‌دهد.
**پراپ‌های ورودی:**
```dart
final String currentLanguage; // زبان فعلی
final Function(String language, String flag) onLanguageSelected; // کالبک انتخاب
final GlobalKey targetKey; // کلید موقعیت‌یابی
```
### 2. `showLanguageSelectionOverlay`
تابع کمکی برای نمایش overlay:
```dart
void showLanguageSelectionOverlay(
BuildContext context,
String currentLanguage,
Function(String language, String flag) onLanguageSelected,
GlobalKey targetKey,
)
```
---
## 🛠 نحوه پیاده‌سازی
### مرحله 1: اضافه کردن State متغیرها
```dart
class _YourPageState extends State<YourPage> {
String _currentLanguage = '🇺🇲 English';
String _currentFlag = 'assets/icons/usa circle.svg';
final GlobalKey _languageKey = GlobalKey();
// ... سایر کدها
}
```
### مرحله 2: ایجاد UI انتخاب زبان
```dart
GestureDetector(
key: _languageKey,
onTap: () {
showLanguageSelectionOverlay(
context,
_currentLanguage,
(language, flag) {
setState(() {
_currentLanguage = language;
_currentFlag = flag;
});
},
_languageKey,
);
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
// نمایش پرچم
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: ClipRRect(
key: ValueKey(_currentFlag),
borderRadius: BorderRadius.circular(4),
child: SvgPicture.asset(
_currentFlag,
width: 24,
height: 18,
),
),
),
const SizedBox(width: 8),
// نمایش نام زبان
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: Text(
_currentLanguage,
key: ValueKey(_currentLanguage),
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color: AppColors.textPrimary,
),
),
),
const SizedBox(width: 8),
// آیکون فلش
SvgPicture.asset(
Assets.icons.arrowRight.path,
color: AppColors.textPrimary,
),
],
),
),
```
### مرحله 3: اضافه کردن Import ها
```dart
import 'package:flutter_svg/flutter_svg.dart';
import '../../widgets/language_selection_dialog.dart';
import '../../gen/assets.gen.dart';
import '../../res/colors.dart';
```
---
## 🔄 مدیریت State
### Local State Management
هر صفحه state زبان خود را به‌صورت جداگانه مدیریت می‌کند:
```dart
// متغیرهای state
String _currentLanguage = '🇺🇲 English'; // نام کامل زبان با پرچم
String _currentFlag = 'assets/icons/usa circle.svg'; // مسیر فایل پرچم
// تابع تغییر زبان
void _changeLanguage(String language, String flag) {
setState(() {
_currentLanguage = language;
_currentFlag = flag;
});
}
```
### Persistence (در آینده)
برای ذخیره انتخاب زبان کاربر می‌توان از `SharedPreferences` استفاده کرد:
```dart
// ذخیره زبان
Future<void> _saveLanguage(String languageCode) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('selected_language', languageCode);
}
// بازیابی زبان
Future<String> _loadLanguage() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('selected_language') ?? 'en';
}
```
---
## 🎨 UI/UX طراحی
### Positioning Logic
سیستم positioning هوشمند برای مکان‌یابی overlay:
```dart
// تشخیص موقعیت target در صفحه
if (targetPosition.dx > screenWidth * 0.7) {
// انتهای راست (مثل onboarding)
rightPosition = 16;
} else {
// وسط یا چپ (مثل profile)
rightPosition = 24;
}
```
### Animation ها
- **Scale Animation**: ورود overlay با افکت scale
- **Opacity Animation**: fade in/out
- **Switcher Animation**: تغییر پرچم و متن با `AnimatedSwitcher`
```dart
AnimationController _animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
Animation<double> _scaleAnimation = Tween<double>(
begin: 0.8,
end: 1.0
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeOutBack
));
```
### طراحی Overlay
```dart
Container(
decoration: BoxDecoration(
color: AppColors.surface,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(16),
bottomRight: Radius.circular(16),
topLeft: Radius.circular(16),
),
boxShadow: [
BoxShadow(
color: AppColors.shadowColor,
blurRadius: 15,
spreadRadius: 3,
offset: const Offset(0, 5),
),
],
),
// محتوای overlay
)
```
---
## ⚡ نکات فنی
### 1. Error Handling
برای مواردی که asset پرچم بارگذاری نشود:
```dart
errorBuilder: (context, error, stackTrace) {
return Container(
width: 24,
height: 18,
decoration: BoxDecoration(
color: AppColors.greyBorder.withOpacity(0.2),
borderRadius: BorderRadius.circular(4),
),
child: Icon(
Icons.flag,
color: AppColors.textSecondary,
size: 12,
),
);
}
```
### 2. Responsive Design
سیستم با اندازه‌های مختلف صفحه سازگار است:
```dart
final overlayWidth = screenWidth * 0.45; // 45% عرض صفحه
```
### 3. RTL Support
پشتیبانی از زبان‌های راست به چپ:
```dart
textDirection: (code == 'ar' || code == 'fa')
? TextDirection.rtl
: TextDirection.ltr,
```
### 4. Performance
استفاده از `ValueKey` برای بهینه‌سازی rebuilds:
```dart
AnimatedSwitcher(
child: Widget(
key: ValueKey(_currentLanguage), // جلوگیری از rebuild غیرضروری
// ...
),
)
```
---
## 📱 استفاده در صفحات مختلف
### صفحه Onboarding
```dart
// موقعیت: بالای راست صفحه
Container(
padding: EdgeInsets.fromLTRB(width/15, height/20, width/15, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// دکمه Skip
GestureDetector(onTap: _skipOnboarding, child: Text('Skip')),
// انتخاب زبان
LanguageSelector(),
],
),
)
```
### صفحه Profile
```dart
// موقعیت: در بخش General Settings
_buildInfoTile(
icon: SvgPicture.asset(Assets.icons.languageSquare.path),
title: 'Language',
trailing: LanguageSelector(),
),
```
---
## 🔍 عیب‌یابی
### مشکلات متداول
#### 1. Overlay خارج از صفحه
**علت**: positioning غلط
**راه‌حل**: بررسی محاسبات `leftPosition` و `rightPosition`
```dart
// اطمینان از عدم overflow
if (leftPosition + overlayWidth > screenWidth - 16) {
leftPosition = screenWidth - overlayWidth - 16;
}
```
#### 2. Asset پرچم نمایش داده نمی‌شود
**علت**: مسیر فایل اشتباه
**راه‌حل**: بررسی `assets.gen.dart` و مسیرهای فایل
```dart
// بررسی وجود فایل
child: _currentFlag.endsWith('.svg')
? SvgPicture.asset(_currentFlag)
: Image.asset(_currentFlag),
```
#### 3. Animation کار نمی‌کند
**علت**: `AnimationController` dispose نشده
**راه‌حل**:
```dart
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
```
### Debug Commands
```dart
// برای debug positioning
print('Target position: ${targetPosition.dx}, ${targetPosition.dy}');
print('Screen width: $screenWidth');
print('Overlay width: $overlayWidth');
```
---
## 🚀 بهبودهای آینده
### 1. Localization Integration
```dart
// اتصال به سیستم i18n Flutter
class LocalizationManager {
static void changeLocale(BuildContext context, String languageCode) {
// تغییر زبان کل اپ
}
}
```
### 2. Theme Integration
```dart
// تغییر زبان همراه با تغییر direction
void _changeLanguage(String code) {
final isRTL = ['ar', 'fa'].contains(code);
// اعمال تغییرات theme
}
```
### 3. Network Integration
```dart
// دریافت متن‌ها از سرور
class LanguageService {
Future<Map<String, String>> getTranslations(String languageCode) {
// API call
}
}
```
---
## 📞 پشتیبانی
برای مشکلات فنی یا پیشنهادات بهبود، با تیم توسعه تماس بگیرید.
**نسخه مستندات:** 1.0
**آخرین بروزرسانی:** 22 سپتامبر 2025
**نگارنده:** GitHub Copilot
---
*این مستندات برای توسعه‌دهندگان اپلیکیشن LBA تهیه شده است.*

View File

@ -0,0 +1,231 @@
# Real-Time System Theme Detection Implementation
## Overview
The LBA app now automatically detects and responds to system theme changes in real-time, meaning when a user changes their device's theme setting (from light to dark or vice versa), the app immediately reflects this change without requiring a restart.
## How It Works
### 1. System Theme Detection
- **Flutter's ThemeMode.system**: When users haven't manually overridden theme settings, the app uses Flutter's built-in `ThemeMode.system` which automatically follows the device's system theme.
- **Real-time Updates**: The app listens to system brightness changes using `WidgetsBindingObserver` and updates the UI immediately.
### 2. Implementation Details
#### Files Modified:
- `lib/main.dart`: Updated to use dynamic theme mode selection
- `lib/utils/theme_manager.dart`: Enhanced with real-time system theme detection
#### Key Features:
```dart
// In ThemeManager class
class ThemeManager extends ChangeNotifier with WidgetsBindingObserver {
// Returns appropriate theme mode
ThemeMode getThemeMode() {
if (_hasManualOverride) {
return _isDarkMode ? ThemeMode.dark : ThemeMode.light;
} else {
return ThemeMode.system; // Follows system theme automatically
}
}
// Listens to system brightness changes
@override
void didChangePlatformBrightness() {
if (!_hasManualOverride) {
bool systemIsDark = _getSystemTheme();
if (_isDarkMode != systemIsDark) {
_isDarkMode = systemIsDark;
AppColors.setDarkMode(_isDarkMode);
_updateSystemUIOverlay();
notifyListeners(); // Updates UI immediately
}
}
}
}
```
### 3. User Experience
#### When User Has NOT Set Manual Theme:
- ✅ App automatically follows system theme
- ✅ Real-time updates when system theme changes
- ✅ No app restart required
- ✅ Immediate UI response
#### When User Has Set Manual Theme:
- ✅ App respects user's manual choice
- ✅ System theme changes are ignored
- ✅ User can reset to system theme anytime
## Usage Scenarios
### Scenario 1: Following System Theme (Default)
1. User opens app for first time
2. App automatically matches device theme (light/dark)
3. User changes device theme in system settings
4. **App immediately updates** to match new system theme
### Scenario 2: Manual Theme Override
1. User manually sets theme in Profile → General settings
2. App uses selected theme regardless of system changes
3. User can choose "Reset to System Theme" to return to automatic behavior
### Scenario 3: Real-time Detection
1. User has app open and active
2. User switches device theme (pull down control center → dark mode toggle)
3. **App theme changes instantly** without any delay
## Technical Implementation
### Key Components:
#### 1. WidgetsBindingObserver
```dart
class ThemeManager extends ChangeNotifier with WidgetsBindingObserver {
ThemeManager() {
WidgetsBinding.instance.addObserver(this); // Start listening
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this); // Clean up
super.dispose();
}
}
```
#### 2. Platform Brightness Detection
```dart
bool _getSystemTheme() {
return WidgetsBinding.instance.platformDispatcher.platformBrightness == Brightness.dark;
}
```
#### 3. Dynamic Theme Mode
```dart
// In MaterialApp widget
themeMode: themeManager.getThemeMode(), // Dynamic based on user preference
```
### 4. State Management
- Uses `Provider` pattern for theme state management
- Automatic persistence to SharedPreferences
- Immediate UI updates via `notifyListeners()`
## Benefits
### 1. **Seamless User Experience**
- No manual theme switching needed
- Automatic adaptation to user preferences
- Consistent with system-wide theme behavior
### 2. **Real-time Response**
- Instant theme changes
- No app restart required
- Smooth transitions with animations
### 3. **User Control**
- Option to override system theme
- Ability to reset to system behavior
- Persistent user preferences
### 4. **Performance Optimized**
- Efficient system listening
- Minimal resource usage
- Clean observer pattern implementation
## Testing Instructions
### Test Real-time Theme Switching:
1. **Open the LBA app**
2. **Ensure no manual theme override is set** (go to Profile → General → Theme should follow system)
3. **While app is open and visible:**
- On iOS: Swipe down → Control Center → Toggle Dark Mode
- On Android: Quick Settings → Toggle Dark Theme
4. **Observe:** App theme should change immediately
### Test Manual Override:
1. **Set manual theme** in Profile → General settings
2. **Change system theme** while app is open
3. **Observe:** App should NOT change (respects manual setting)
4. **Reset to system theme** in settings
5. **Change system theme** again
6. **Observe:** App should now follow system changes
## Code Examples
### How to Add Real-time Theme Detection to Any Screen:
```dart
class MyScreen extends StatefulWidget {
@override
Widget build(BuildContext context) {
return Consumer<ThemeManager>(
builder: (context, themeManager, child) {
return Scaffold(
backgroundColor: AppColors.scaffoldBackground, // Auto-updates
body: Text(
'This text color updates automatically!',
style: TextStyle(color: AppColors.textPrimary), // Auto-updates
),
);
},
);
}
}
```
### How to Check Current Theme State:
```dart
// Get current theme mode
ThemeMode currentMode = themeManager.getThemeMode();
// Check if following system
bool isFollowingSystem = currentMode == ThemeMode.system;
// Check if dark mode is active
bool isDark = themeManager.isDarkMode;
```
## Migration Notes
### Breaking Changes: None
- All existing functionality preserved
- Backward compatibility maintained
- No API changes for existing screens
### Enhanced Features:
- Real-time system theme detection
- Improved user experience
- Better system integration
## Future Enhancements
### Potential Improvements:
- **Theme Scheduling**: Set different themes for day/night
- **Location-based Themes**: Auto-dark mode based on sunset/sunrise
- **Custom Theme Colors**: User-defined color palettes
- **Theme Animations**: Enhanced transition effects
## Troubleshooting
### If Real-time Switching Doesn't Work:
1. Check if manual theme override is enabled
2. Ensure app has proper system permissions
3. Restart app to reinitialize observers
4. Verify device supports theme switching
### Common Issues:
- **Delay in Updates**: Normal on some Android devices (1-2 second delay)
- **Not Following System**: Check if manual override is set
- **Partial Updates**: Ensure all screens use AppColors class
## Summary
The LBA app now provides a **complete real-time theme switching experience** that automatically follows the user's system theme preferences while still allowing manual overrides when desired. This enhancement makes the app feel more integrated with the device's overall user experience and eliminates the need for users to manually sync their app themes with their system preferences.
**Key Achievement:** ✅ **Real-time system theme detection with zero user intervention required**

View File

@ -33,8 +33,7 @@ class MyApp extends StatelessWidget {
title: 'LBA', title: 'LBA',
theme: themeManager.lightTheme, theme: themeManager.lightTheme,
darkTheme: themeManager.darkTheme, darkTheme: themeManager.darkTheme,
themeMode: themeMode: themeManager.getThemeMode(),
themeManager.isDarkMode ? ThemeMode.dark : ThemeMode.light,
themeAnimationDuration: const Duration(milliseconds: 300), themeAnimationDuration: const Duration(milliseconds: 300),
themeAnimationCurve: Curves.easeInOutCubic, themeAnimationCurve: Curves.easeInOutCubic,
home: SplashScreen( home: SplashScreen(

View File

@ -4,7 +4,7 @@ import 'package:lba/res/colors.dart';
import 'package:lba/utils/sharedPreferencesKey.dart'; import 'package:lba/utils/sharedPreferencesKey.dart';
import 'package:lba/utils/sharedPreferencesManger.dart'; import 'package:lba/utils/sharedPreferencesManger.dart';
class ThemeManager extends ChangeNotifier { class ThemeManager extends ChangeNotifier with WidgetsBindingObserver {
late SharedPreferencesManager _prefs; late SharedPreferencesManager _prefs;
bool _isDarkMode = false; bool _isDarkMode = false;
bool _isThemeTransitioning = false; bool _isThemeTransitioning = false;
@ -13,6 +13,13 @@ class ThemeManager extends ChangeNotifier {
ThemeManager() { ThemeManager() {
_prefs = SharedPreferencesManager(); _prefs = SharedPreferencesManager();
_loadTheme(); _loadTheme();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
} }
bool get isDarkMode => _isDarkMode; bool get isDarkMode => _isDarkMode;
@ -160,6 +167,31 @@ class ThemeManager extends ChangeNotifier {
ThemeData get currentTheme => _isDarkMode ? darkTheme : lightTheme; ThemeData get currentTheme => _isDarkMode ? darkTheme : lightTheme;
/// Returns the appropriate ThemeMode based on user preferences
ThemeMode getThemeMode() {
if (_hasManualOverride) {
return _isDarkMode ? ThemeMode.dark : ThemeMode.light;
} else {
return ThemeMode.system;
}
}
@override
void didChangePlatformBrightness() {
super.didChangePlatformBrightness();
// Only respond to system theme changes if user hasn't manually overridden
if (!_hasManualOverride) {
bool systemIsDark = _getSystemTheme();
if (_isDarkMode != systemIsDark) {
_isDarkMode = systemIsDark;
AppColors.setDarkMode(_isDarkMode);
_updateSystemUIOverlay();
notifyListeners();
}
}
}
Future<void> _loadTheme() async { Future<void> _loadTheme() async {
await _prefs.init(); await _prefs.init();
_hasManualOverride = _prefs.getBool(SharedPreferencesKey.hasManualThemeOverride) ?? false; _hasManualOverride = _prefs.getBool(SharedPreferencesKey.hasManualThemeOverride) ?? false;
@ -176,8 +208,7 @@ class ThemeManager extends ChangeNotifier {
} }
bool _getSystemTheme() { bool _getSystemTheme() {
final window = WidgetsBinding.instance.window; return WidgetsBinding.instance.platformDispatcher.platformBrightness == Brightness.dark;
return window.platformBrightness == Brightness.dark;
} }
void _updateSystemUIOverlay() { void _updateSystemUIOverlay() {

View File

@ -13,7 +13,7 @@ import 'package:lba/main.dart';
void main() { void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async { testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame. // Build our app and trigger a frame.
await tester.pumpWidget(const MyApp()); await tester.pumpWidget(MyApp());
// Verify that our counter starts at 0. // Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget); expect(find.text('0'), findsOneWidget);