mirror of
https://github.com/PranshulGG/WeatherMaster.git
synced 2026-10-22 02:52:37 -05:00
462 lines
18 KiB
Dart
462 lines
18 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:weather_master_app/utils/preferences_helper.dart';
|
|
import 'home_location.dart';
|
|
import 'package:settings_tiles/settings_tiles.dart';
|
|
import 'settings_unit.dart';
|
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
|
import '../notifiers/unit_settings_notifier.dart';
|
|
import 'package:provider/provider.dart';
|
|
import '../utils/theme_controller.dart';
|
|
import 'languages_page.dart';
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
import 'package:restart_app/restart_app.dart';
|
|
import '../utils/snack_util.dart';
|
|
import 'about_page.dart';
|
|
import 'meteo_models.dart';
|
|
import 'edit_layout_page.dart';
|
|
|
|
class SettingsScreen extends StatefulWidget {
|
|
const SettingsScreen({super.key});
|
|
|
|
@override
|
|
State<SettingsScreen> createState() => _SettingsScreenState();
|
|
}
|
|
|
|
class _SettingsScreenState extends State<SettingsScreen> {
|
|
bool _showTile = PreferencesHelper.getBool("usingCustomSeed") ?? false;
|
|
bool _useCustomTile = PreferencesHelper.getBool("DynamicColors") == true ? false : true;
|
|
String? city;
|
|
String? country;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
loadLocation();
|
|
}
|
|
|
|
void loadLocation() {
|
|
final location = PreferencesHelper.getJson('homeLocation');
|
|
setState(() {
|
|
city = location?['city'];
|
|
country = location?['country'];
|
|
});
|
|
}
|
|
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final themeController = Provider.of<ThemeController>(context);
|
|
final currentMode = themeController.themeMode;
|
|
final isSupported = themeController.isDynamicColorSupported;
|
|
|
|
final optionsTheme = {
|
|
"Dark": "theme_dark".tr(),
|
|
"Light": "theme_light".tr()
|
|
};
|
|
|
|
|
|
|
|
return Scaffold(
|
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
|
body:
|
|
CustomScrollView(
|
|
slivers: [
|
|
SliverAppBar.large(
|
|
title: Text('settings'.tr()),
|
|
titleSpacing: 0,
|
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
|
scrolledUnderElevation: 1,
|
|
),
|
|
|
|
SliverToBoxAdapter(
|
|
child: Column(
|
|
children: [
|
|
SettingSection(
|
|
styleTile: true,
|
|
title: SettingSectionTitle("app_looks".tr(), noPadding: true,),
|
|
tiles: [
|
|
SettingSingleOptionTile(
|
|
icon: Icon(Symbols.routine),
|
|
title: Text('app_theme_dark_light'.tr()),
|
|
dialogTitle: 'app_theme_dark_light'.tr(),
|
|
value: SettingTileValue(optionsTheme[currentMode == ThemeMode.light ? "Light" : "Dark"]!),
|
|
options: optionsTheme.values.toList(),
|
|
initialOption: optionsTheme[currentMode == ThemeMode.light ? "Light" : "Dark"]!,
|
|
onSubmitted: (value) {
|
|
setState(() {
|
|
final selectedKey = optionsTheme.entries.firstWhere((e) => e.value == value).key;
|
|
PreferencesHelper.setString("AppTheme", selectedKey);
|
|
themeController.setThemeMode(selectedKey == "Dark" ? ThemeMode.dark : ThemeMode.light);
|
|
});
|
|
},
|
|
),
|
|
|
|
SettingSwitchTile(
|
|
icon: Icon(Symbols.thermometer_add, fill: 1, weight: 500),
|
|
title: Text("temperature_animation".tr()),
|
|
description: Text("temp_animation_sub_pref".tr()),
|
|
toggled: PreferencesHelper.getBool("useTempAnimation") ?? true,
|
|
onChanged: (value) {
|
|
setState(() {
|
|
PreferencesHelper.setBool("useTempAnimation", value);
|
|
});
|
|
},
|
|
),
|
|
|
|
SettingSwitchTile(
|
|
enabled: _useCustomTile,
|
|
icon: Icon(Symbols.colorize, fill: 1, weight: 500),
|
|
title: Text("Use custom color"),
|
|
toggled: PreferencesHelper.getBool("usingCustomSeed") ?? false,
|
|
onChanged: (value) {
|
|
setState(() {
|
|
PreferencesHelper.setBool("usingCustomSeed", value);
|
|
if(value == true){
|
|
Provider.of<ThemeController>(context, listen: false).setSeedColor(PreferencesHelper.getColor("CustomMaterialColor") ?? Colors.blue);
|
|
} else{
|
|
Provider.of<ThemeController>(context, listen: false).setSeedColor(PreferencesHelper.getColor("weatherThemeColor") ?? Colors.blue);
|
|
}
|
|
});
|
|
_showTile = value;
|
|
},
|
|
),
|
|
|
|
|
|
SettingColorTile(
|
|
enabled: _showTile,
|
|
icon: Icon(Symbols.colors, fill: 1, weight: 500),
|
|
title: Text('Primary color'),
|
|
description: Text('Select a seed color to generate the theme'),
|
|
dialogTitle: 'Color',
|
|
initialColor: PreferencesHelper.getColor("CustomMaterialColor") ?? Colors.blue,
|
|
colorPickers: [ColorPickerType.primary],
|
|
onSubmitted: (value) {
|
|
setState(() {
|
|
PreferencesHelper.setColor("CustomMaterialColor", value);
|
|
Provider.of<ThemeController>(context, listen: false).setSeedColor(value);
|
|
});
|
|
},
|
|
),
|
|
|
|
|
|
SettingSwitchTile(
|
|
enabled: isSupported ? _showTile ? false : true : false,
|
|
icon: Icon(Symbols.wallpaper, fill: 1, weight: 500),
|
|
title: Text("dynamic_colors".tr()),
|
|
|
|
description: Text("${"dynamic_colors_sub".tr()} ${isSupported ? "" : "(Android 12+)"}"),
|
|
toggled: PreferencesHelper.getBool("DynamicColors") ?? false,
|
|
onChanged: (value) async {
|
|
final themeController = context.read<ThemeController>();
|
|
|
|
PreferencesHelper.setBool("DynamicColors", value);
|
|
|
|
if (value) {
|
|
await themeController.loadDynamicColors();
|
|
} else {
|
|
Provider.of<ThemeController>(context, listen: false).setSeedColor(PreferencesHelper.getColor("weatherThemeColor") ?? Colors.blue);
|
|
}
|
|
setState(() {
|
|
if (value) {
|
|
_useCustomTile = false;
|
|
} else{
|
|
_useCustomTile = true;
|
|
}
|
|
});
|
|
},
|
|
|
|
),
|
|
|
|
|
|
SettingSwitchTile(
|
|
icon: Icon(Symbols.palette, fill: 1, weight: 500),
|
|
title: Text("Material scheme only"),
|
|
description: Text('Disables weather effects; uses default Material theme'),
|
|
toggled: PreferencesHelper.getBool("OnlyMaterialScheme") ?? false,
|
|
onChanged: (value) {
|
|
PreferencesHelper.setBool("OnlyMaterialScheme", value);
|
|
setState(() {
|
|
SnackUtil.showSnackBar(
|
|
context: context,
|
|
message: "Restarting app",
|
|
);
|
|
Future.delayed(Duration(seconds: 2), () {
|
|
Restart.restartApp();
|
|
});
|
|
});
|
|
},
|
|
),
|
|
|
|
SettingSwitchTile(
|
|
icon: Icon(Symbols.temp_preferences_eco, fill: 1, weight: 500),
|
|
title: Text("Show froggy"),
|
|
description: Text("Display Froggy images based on weather conditions"),
|
|
toggled: PreferencesHelper.getBool("showFroggy") ?? true,
|
|
onChanged: (value) {
|
|
context.read<UnitSettingsNotifier>().updateShowFroggy(value);
|
|
setState(() {
|
|
});
|
|
},
|
|
),
|
|
|
|
SettingActionTile(
|
|
icon: Icon(Symbols.view_agenda, fill: 1, weight: 500),
|
|
title: Text('edit_layout'.tr()),
|
|
trailing: Icon(Icons.chevron_right),
|
|
onTap: () {
|
|
Navigator.of(context).push(
|
|
|
|
MaterialPageRoute(builder: (_) => EditLayoutPage(), fullscreenDialog: true),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
|
|
SizedBox(height: 10,),
|
|
SettingSection(
|
|
styleTile: true,
|
|
title: SettingSectionTitle('weather'.tr(), noPadding: true,),
|
|
tiles: [
|
|
SettingActionTile(
|
|
icon: Icon(Symbols.home_pin, fill: 1, weight: 500),
|
|
title: Text('home_location'.tr()),
|
|
description: Text("${city ?? 'Unknown City'}, ${country ?? 'Unknown Country'}", style: TextStyle(color: Theme.of(context).colorScheme.secondary, fontWeight: FontWeight.w700),),
|
|
trailing: Icon(Icons.chevron_right),
|
|
onTap: () async{
|
|
final updated = await Navigator.of(context).push(
|
|
MaterialPageRoute(builder: (_) => const HomeLocationScreen()),
|
|
);
|
|
|
|
if (updated == true) {
|
|
loadLocation();
|
|
}
|
|
},
|
|
),
|
|
SettingActionTile(
|
|
icon: Icon(Symbols.page_info, fill: 1, weight: 500),
|
|
title: Text('app_units'.tr()),
|
|
description: Text('temperature_wind_pressure_visibility_precipitation_time_aqi'.tr()),
|
|
trailing: Icon(Icons.chevron_right),
|
|
onTap: () {
|
|
Navigator.of(context).push(
|
|
MaterialPageRoute(builder: (_) => const AppUnitsPage()),
|
|
);
|
|
},
|
|
),
|
|
|
|
SettingSwitchTile(
|
|
icon: Icon(Symbols.assistant_navigation, fill: 1, weight: 500),
|
|
title: Text("Use Device Compass"),
|
|
description: Text("Rotate wind arrow based on your phone's real-world orientation"),
|
|
toggled: PreferencesHelper.getBool("useDeviceCompass") ?? false,
|
|
onChanged: (value) {
|
|
context.read<UnitSettingsNotifier>().updateUseDeviceCompass(value);
|
|
setState(() {
|
|
});
|
|
},
|
|
),
|
|
|
|
SettingSwitchTile(
|
|
icon: Icon(Symbols.taunt, fill: 1, weight: 500),
|
|
title: Text('Froggy insights'),
|
|
description: Text('Shows insights in a playfull format'),
|
|
toggled: PreferencesHelper.getBool("useFroggyInsights") ?? false,
|
|
onChanged: (value) {
|
|
setState(() {
|
|
PreferencesHelper.setBool("useFroggyInsights", value);
|
|
});
|
|
},
|
|
),
|
|
|
|
SettingSwitchTile(
|
|
icon: Icon(Symbols.animation, fill: 1, weight: 500),
|
|
title: Text("background_card_animation".tr()),
|
|
toggled: PreferencesHelper.getBool("CardBackgroundAnimations") ?? true,
|
|
onChanged: (value) {
|
|
context.read<UnitSettingsNotifier>().updateuseCardBackgroundAnimations(value);
|
|
setState(() {
|
|
});
|
|
},
|
|
),
|
|
|
|
SettingActionTile(
|
|
icon: Icon(Symbols.nest_farsight_weather, fill: 1, weight: 500),
|
|
title: Text('weather_models'.tr()),
|
|
description: Text('openmeteo_weather_models'.tr()),
|
|
trailing: Icon(Icons.chevron_right),
|
|
onTap: () {
|
|
Navigator.of(context).push(
|
|
MaterialPageRoute(builder: (_) => const MeteoModelsPage()),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 10,),
|
|
SettingSection(
|
|
styleTile: true,
|
|
title: SettingSectionTitle('additional'.tr(), noPadding: true,),
|
|
tiles: [
|
|
SettingActionTile(
|
|
icon: Icon(Symbols.language, fill: 1, weight: 500),
|
|
title: Text('app_language'.tr()),
|
|
description: Text(getLanguageNamesSettingsView(context.locale)['english'].toString()),
|
|
trailing: Icon(Icons.chevron_right),
|
|
onTap: () {
|
|
Navigator.of(context).push(
|
|
MaterialPageRoute(builder: (_) => const LanguagesScreen()),
|
|
);
|
|
},
|
|
),
|
|
|
|
SettingActionTile(
|
|
icon: Icon(Symbols.info, fill: 1, weight: 500),
|
|
title: Text('${"about".tr()} WeatherMaster'),
|
|
description: Text('learn_about_app'.tr()),
|
|
trailing: Icon(Icons.chevron_right),
|
|
onTap: () {
|
|
Navigator.of(context).push(
|
|
MaterialPageRoute(builder: (_) => AboutPage()),
|
|
);
|
|
},
|
|
),
|
|
|
|
]
|
|
),
|
|
|
|
SizedBox(height: 200,),
|
|
]
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Map<String, String> getLanguageNamesSettingsView(Locale locale) {
|
|
final lang = locale.languageCode;
|
|
final country = locale.countryCode;
|
|
|
|
print("${lang}, ${country}");
|
|
|
|
if (lang == 'ar' && country == 'SA') {
|
|
return {'native': 'العربية (السعودية)', 'english': 'Arabic (Saudi Arabia)'};
|
|
}
|
|
if (lang == 'az' && country == 'AZ') {
|
|
return {'native': 'Azərbaycanca', 'english': 'Azerbaijani'};
|
|
}
|
|
if (lang == 'cs' && country == 'CZ') {
|
|
return {'native': 'Čeština', 'english': 'Czech'};
|
|
}
|
|
if (lang == 'de' && country == 'DE') {
|
|
return {'native': 'Deutsch', 'english': 'German'};
|
|
}
|
|
if (lang == 'el' && country == 'GR') {
|
|
return {'native': 'Ελληνικά', 'english': 'Greek'};
|
|
}
|
|
if (lang == 'en') {
|
|
return {'native': 'English', 'english': 'English (US)'};
|
|
}
|
|
if (lang == 'es' && country == 'ES') {
|
|
return {'native': 'Español', 'english': 'Spanish'};
|
|
}
|
|
if (lang == 'fa' && country == 'IR') {
|
|
return {'native': 'فارسی', 'english': 'Persian'};
|
|
}
|
|
if (lang == 'fi' && country == 'FI') {
|
|
return {'native': 'Suomi', 'english': 'Finnish'};
|
|
}
|
|
if (lang == 'fil' && country == 'PH') {
|
|
return {'native': 'Filipino', 'english': 'Filipino'};
|
|
}
|
|
if (lang == 'fr' && country == 'FR') {
|
|
return {'native': 'Français', 'english': 'French'};
|
|
}
|
|
if (lang == 'hu' && country == 'HU') {
|
|
return {'native': 'Magyar', 'english': 'Hungarian'};
|
|
}
|
|
if (lang == 'id' && country == 'ID') {
|
|
return {'native': 'Bahasa Indonesia', 'english': 'Indonesian'};
|
|
}
|
|
if (lang == 'it' && country == 'IT') {
|
|
return {'native': 'Italiano', 'english': 'Italian'};
|
|
}
|
|
if (lang == 'ja' && country == 'JP') {
|
|
return {'native': '日本語', 'english': 'Japanese'};
|
|
}
|
|
if (lang == 'ko' && country == 'KR') {
|
|
return {'native': '한국어', 'english': 'Korean'};
|
|
}
|
|
if (lang == 'nl' && country == 'NL') {
|
|
return {'native': 'Nederlands', 'english': 'Dutch'};
|
|
}
|
|
if (lang == 'pl' && country == 'PL') {
|
|
return {'native': 'Polski', 'english': 'Polish'};
|
|
}
|
|
if (lang == 'pt' && country == 'BR') {
|
|
return {'native': 'Português (Brasil)', 'english': 'Portuguese (Brazil)'};
|
|
}
|
|
if (lang == 'pt' && country == 'PT') {
|
|
return {'native': 'Português (Portugal)', 'english': 'Portuguese (Portugal)'};
|
|
}
|
|
if (lang == 'ro' && country == 'RO') {
|
|
return {'native': 'Română', 'english': 'Romanian'};
|
|
}
|
|
if (lang == 'ru' && country == 'RU') {
|
|
return {'native': 'Русский', 'english': 'Russian'};
|
|
}
|
|
if (lang == 'sl' && country == 'SI') {
|
|
return {'native': 'Slovenščina', 'english': 'Slovenian'};
|
|
}
|
|
if (lang == 'sr' && country == 'CS') {
|
|
return {'native': 'Српски (Ћирилица)', 'english': 'Serbian (Cyrillic)'};
|
|
}
|
|
if (lang == 'sr'&& country == 'SP') {
|
|
return {'native': 'Српски', 'english': 'Serbian'};
|
|
}
|
|
if (lang == 'sv' && country == 'SE') {
|
|
return {'native': 'Svenska', 'english': 'Swedish'};
|
|
}
|
|
if (lang == 'tr' && country == 'TR') {
|
|
return {'native': 'Türkçe', 'english': 'Turkish'};
|
|
}
|
|
if (lang == 'uk' && country == 'UA') {
|
|
return {'native': 'Українська', 'english': 'Ukrainian'};
|
|
}
|
|
if (lang == 'vi' && country == 'VN') {
|
|
return {'native': 'Tiếng Việt', 'english': 'Vietnamese'};
|
|
}
|
|
if (lang == 'zh' && country == 'CN') {
|
|
return {'native': '简体中文', 'english': 'Simplified Chinese'};
|
|
}
|
|
if (lang == 'zh' && country == 'TW') {
|
|
return {'native': '繁體中文', 'english': 'Traditional Chinese'};
|
|
}
|
|
|
|
return {'native': '$lang${country != null ? "_$country" : ""}', 'english': 'Unknown'};
|
|
}
|
|
|
|
|
|
class MyHeaderDelegate extends SliverPersistentHeaderDelegate {
|
|
@override
|
|
Widget build(
|
|
BuildContext context, double shrinkOffset, bool overlapsContent) {
|
|
// TODO: implement build
|
|
throw UnimplementedError();
|
|
}
|
|
|
|
@override
|
|
double get maxExtent => 264;
|
|
|
|
@override
|
|
double get minExtent => 84;
|
|
|
|
@override
|
|
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
|
|
true;
|
|
}
|