mirror of
https://github.com/PranshulGG/WeatherMaster.git
synced 2026-10-22 02:52:37 -05:00
cleaned up settings page, added strings
This commit is contained in:
1 parent
4c0771dd05
commit
72cfba953e
18 files changed
+1027
-490
No files matched your search
@@ -549,5 +549,11 @@
|
||||
"system_font": "System",
|
||||
"use_ai_for_summary": "Use AI for summary",
|
||||
"use_ai_for_summary_sub": "GPT-4o Mini generates summaries of hourly, daily, and current weather, refreshing every 2 hours",
|
||||
"restart_for_changes": "Restart to apply changes"
|
||||
"restart_for_changes": "Restart to apply changes",
|
||||
"appearance": "Appearance",
|
||||
"appearance_sub": "Themes, animations, and app layout",
|
||||
"background_updates_sub": "Widget updates, update interval, and scheduled updates",
|
||||
"animations": "Animations",
|
||||
"layout": "Layout",
|
||||
"use_expressive_palette": "Use expressive palette"
|
||||
}
|
||||
@@ -218,44 +218,45 @@ class _DailyForecastPageState extends State<DailyForecastPage> {
|
||||
.toString()))))
|
||||
? SizedBox(
|
||||
child: ConditionsWidgets(
|
||||
selectedContainerBgIndex: Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainerLowest
|
||||
.toARGB32(),
|
||||
currentHumidity:
|
||||
current['relative_humidity_2m'] ??
|
||||
0.0000001,
|
||||
currentDewPoint:
|
||||
hourly['dew_point_2m'][0].toDouble() ??
|
||||
0.0000001,
|
||||
currentSunrise:
|
||||
daily['sunrise'][0] ?? 0.0000001,
|
||||
currentSunset: daily['sunset'][0] ?? 0.0000001,
|
||||
currentPressure:
|
||||
current['pressure_msl'] ?? 0.0000001,
|
||||
currentVisibility:
|
||||
hourly['visibility'][0] ?? 0.0000001,
|
||||
currentWindSpeed:
|
||||
current['wind_speed_10m'] ?? 0.0000001,
|
||||
currentWindDirc:
|
||||
current['wind_direction_10m'] ?? 0.0000001,
|
||||
timezone: weather['timezone'].toString(),
|
||||
utcOffsetSeconds:
|
||||
weather['utc_offset_seconds'].toString(),
|
||||
currentUvIndex:
|
||||
daily['uv_index_max'][0] ?? 0.0000001,
|
||||
currentAQIUSA: weather['air_quality']['current']
|
||||
['us_aqi'] ??
|
||||
0.0000001,
|
||||
currentAQIEURO: weather['air_quality']
|
||||
['current']['european_aqi'] ??
|
||||
0.0000001,
|
||||
currentTotalPrec:
|
||||
daily['precipitation_sum'][0] ?? 0.0000001,
|
||||
currentDayLength:
|
||||
daily['daylight_duration'][0] ?? 0.0000001,
|
||||
isFromHome: false,
|
||||
),
|
||||
selectedContainerBgIndex: Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainerLowest
|
||||
.toARGB32(),
|
||||
currentHumidity: current['relative_humidity_2m'] ??
|
||||
0.0000001,
|
||||
currentDewPoint:
|
||||
hourly['dew_point_2m'][0].toDouble() ??
|
||||
0.0000001,
|
||||
currentSunrise:
|
||||
daily['sunrise'][0] ?? 0.0000001,
|
||||
currentSunset:
|
||||
daily['sunset'][0] ?? 0.0000001,
|
||||
currentPressure:
|
||||
current['pressure_msl'] ?? 0.0000001,
|
||||
currentVisibility:
|
||||
hourly['visibility'][0] ?? 0.0000001,
|
||||
currentWindSpeed:
|
||||
current['wind_speed_10m'] ?? 0.0000001,
|
||||
currentWindDirc: current['wind_direction_10m'] ??
|
||||
0.0000001,
|
||||
timezone: weather['timezone'].toString(),
|
||||
utcOffsetSeconds:
|
||||
weather['utc_offset_seconds'].toString(),
|
||||
currentUvIndex:
|
||||
daily['uv_index_max'][0] ?? 0.0000001,
|
||||
currentAQIUSA: weather['air_quality']
|
||||
['current']['us_aqi'] ??
|
||||
0.0000001,
|
||||
currentAQIEURO: weather['air_quality']
|
||||
['current']['european_aqi'] ??
|
||||
0.0000001,
|
||||
currentTotalPrec: daily['precipitation_sum'][0] ?? 0.0000001,
|
||||
currentDayLength: daily['daylight_duration'][0] ?? 0.0000001,
|
||||
isFromHome: false,
|
||||
moonrise: weather['astronomy']['astronomy']['astro']['moonrise'],
|
||||
moonset: weather['astronomy']['astronomy']['astro']['moonset'],
|
||||
moonPhase: weather['astronomy']['astronomy']['astro']['moon_phase'],
|
||||
cloudCover: current['cloud_cover'].toString()),
|
||||
)
|
||||
: SizedBox(
|
||||
child: ConditionsWidgetsForecast(
|
||||
|
||||
@@ -69,6 +69,10 @@ class _ExtendWidgetState extends State<ExtendWidget> {
|
||||
child = buildPrecipExtended();
|
||||
extendedTitle = 'precipitation'.tr();
|
||||
iconData = Symbols.rainy_heavy;
|
||||
} else if (widget.widgetType == 'moon_widget') {
|
||||
child = buildMoonExtended();
|
||||
extendedTitle = 'moon'.tr();
|
||||
iconData = Symbols.nightlight;
|
||||
} else {
|
||||
child = const Center(child: Text('Unknown widget type'));
|
||||
extendedTitle = 'Error';
|
||||
@@ -1216,6 +1220,7 @@ class _ExtendWidgetState extends State<ExtendWidget> {
|
||||
.round()
|
||||
: windUnit == 'Kt'
|
||||
? UnitConverter.kmhToKt(windSpeed)
|
||||
.toStringAsFixed(1)
|
||||
: windSpeed.toStringAsFixed(1);
|
||||
|
||||
Widget windArrow = Transform.rotate(
|
||||
@@ -2299,6 +2304,89 @@ class _ExtendWidgetState extends State<ExtendWidget> {
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
// MOON
|
||||
|
||||
Widget buildMoonExtended() {
|
||||
return FutureBuilder<Map<String, dynamic>?>(
|
||||
future: getWeatherWidgets(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (snapshot.hasError) {
|
||||
return Center(child: Text('Error: ${snapshot.error}'));
|
||||
} else if (!snapshot.hasData || snapshot.data == null) {
|
||||
return Center(child: Text('no_data_available'.tr()));
|
||||
}
|
||||
|
||||
final data = snapshot.data!;
|
||||
final weather = data['data'];
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
height: 305,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
),
|
||||
padding: EdgeInsets.only(top: 12, bottom: 0),
|
||||
margin: EdgeInsets.fromLTRB(12, 0, 12, 0),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.fromLTRB(20, 10, 20, 0),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("current_conditions".tr(),
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color:
|
||||
Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.w500)),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
"",
|
||||
style: TextStyle(
|
||||
fontSize: 50,
|
||||
color:
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 11, left: 8),
|
||||
child: Text(
|
||||
"",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurfaceVariant,
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildAirQualityBox(String label, double value, String type) {
|
||||
|
||||
+37
-41
@@ -938,7 +938,6 @@ class _WeatherHomeState extends State<WeatherHome> {
|
||||
maybeUpdateWeatherAnimation(current);
|
||||
}
|
||||
});
|
||||
print("CODEEEEEEEEEEEEEEEEE: ${weatherCodeFroggy}");
|
||||
} else {
|
||||
_isLoadingFroggy == true;
|
||||
_loadWeatherIconFroggy(weatherCodeFroggy, isDayFroggy,
|
||||
@@ -1145,46 +1144,43 @@ class _WeatherHomeState extends State<WeatherHome> {
|
||||
return SizedBox(
|
||||
// width: 380,
|
||||
child: ConditionsWidgets(
|
||||
selectedContainerBgIndex: useFullMaterialScheme
|
||||
? Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainerLowest
|
||||
.toARGB32()
|
||||
: weatherContainerColors[selectedContainerBgIndex],
|
||||
currentHumidity:
|
||||
current['relative_humidity_2m'] ?? 0.0000001,
|
||||
currentDewPoint: hourly['dew_point_2m'][getStartIndex(
|
||||
weather['utc_offset_seconds'].toString(),
|
||||
hourlyTime)]
|
||||
.toDouble() ??
|
||||
0.0000001,
|
||||
currentSunrise: daily['sunrise'][0] ?? 0.0000001,
|
||||
currentSunset: daily['sunset'][0] ?? 0.0000001,
|
||||
currentPressure: current['pressure_msl'] ?? 0.0000001,
|
||||
currentVisibility: hourly['visibility'][getStartIndex(
|
||||
weather['utc_offset_seconds'].toString(),
|
||||
hourlyTime)] ??
|
||||
0.0000001,
|
||||
currentWindSpeed: current['wind_speed_10m'] ?? 0.0000001,
|
||||
currentWindDirc: current['wind_direction_10m'] ?? 0.0000001,
|
||||
timezone: weather['timezone'].toString(),
|
||||
utcOffsetSeconds: weather['utc_offset_seconds'].toString(),
|
||||
currentUvIndex: hourly['uv_index'][getStartIndex(
|
||||
weather['utc_offset_seconds'].toString(),
|
||||
hourlyTime)] ??
|
||||
0.0000001,
|
||||
currentAQIUSA: weather['air_quality']['current']
|
||||
['us_aqi'] ??
|
||||
0.0000001,
|
||||
currentAQIEURO: weather['air_quality']['current']
|
||||
['european_aqi'] ??
|
||||
0.0000001,
|
||||
currentTotalPrec:
|
||||
daily['precipitation_sum'][0] ?? 0.0000001,
|
||||
currentDayLength:
|
||||
daily['daylight_duration'][0] ?? 0.0000001,
|
||||
isFromHome: true,
|
||||
),
|
||||
selectedContainerBgIndex: useFullMaterialScheme
|
||||
? Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainerLowest
|
||||
.toARGB32()
|
||||
: weatherContainerColors[selectedContainerBgIndex],
|
||||
currentHumidity:
|
||||
current['relative_humidity_2m'] ?? 0.0000001,
|
||||
currentDewPoint:
|
||||
hourly['dew_point_2m'][getStartIndex(weather['utc_offset_seconds'].toString(), hourlyTime)]
|
||||
.toDouble() ??
|
||||
0.0000001,
|
||||
currentSunrise: daily['sunrise'][0] ?? 0.0000001,
|
||||
currentSunset: daily['sunset'][0] ?? 0.0000001,
|
||||
currentPressure: current['pressure_msl'] ?? 0.0000001,
|
||||
currentVisibility: hourly['visibility'][getStartIndex(
|
||||
weather['utc_offset_seconds'].toString(),
|
||||
hourlyTime)] ??
|
||||
0.0000001,
|
||||
currentWindSpeed: current['wind_speed_10m'] ?? 0.0000001,
|
||||
currentWindDirc:
|
||||
current['wind_direction_10m'] ?? 0.0000001,
|
||||
timezone: weather['timezone'].toString(),
|
||||
utcOffsetSeconds:
|
||||
weather['utc_offset_seconds'].toString(),
|
||||
currentUvIndex: hourly['uv_index']
|
||||
[getStartIndex(weather['utc_offset_seconds'].toString(), hourlyTime)] ??
|
||||
0.0000001,
|
||||
currentAQIUSA: weather['air_quality']['current']['us_aqi'] ?? 0.0000001,
|
||||
currentAQIEURO: weather['air_quality']['current']['european_aqi'] ?? 0.0000001,
|
||||
currentTotalPrec: daily['precipitation_sum'][0] ?? 0.0000001,
|
||||
currentDayLength: daily['daylight_duration'][0] ?? 0.0000001,
|
||||
isFromHome: true,
|
||||
moonrise: weather['astronomy']['astronomy']['astro']['moonrise'],
|
||||
moonset: weather['astronomy']['astronomy']['astro']['moonset'],
|
||||
moonPhase: weather['astronomy']['astronomy']['astro']['moon_phase'],
|
||||
cloudCover: current['cloud_cover'].toString()),
|
||||
);
|
||||
|
||||
case LayoutBlockType.pollen:
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
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';
|
||||
import '../../services/data_backup_service.dart';
|
||||
import '../../screens/background_updates.dart';
|
||||
|
||||
class AppearanceScreen extends StatefulWidget {
|
||||
const AppearanceScreen({super.key});
|
||||
|
||||
@override
|
||||
State<AppearanceScreen> createState() => _AppearanceScreenState();
|
||||
}
|
||||
|
||||
class _AppearanceScreenState extends State<AppearanceScreen> {
|
||||
bool _showTile = PreferencesHelper.getBool("usingCustomSeed") ?? false;
|
||||
bool _useCustomTile =
|
||||
PreferencesHelper.getBool("DynamicColors") == true ? false : true;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final themeController = Provider.of<ThemeController>(context);
|
||||
final currentMode = themeController.themeMode;
|
||||
|
||||
final isSupported = themeController.isDynamicColorSupported;
|
||||
|
||||
final optionsTheme = {
|
||||
"Auto": "theme_auto".tr(),
|
||||
"Dark": "theme_dark".tr(),
|
||||
"Light": "theme_light".tr(),
|
||||
};
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
body: CustomScrollView(slivers: [
|
||||
SliverAppBar.large(
|
||||
title: Text('Appearance'),
|
||||
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"
|
||||
: currentMode == ThemeMode.system
|
||||
? "Auto"
|
||||
: "Dark"]!,
|
||||
),
|
||||
options: optionsTheme.values.toList(),
|
||||
initialOption: optionsTheme[currentMode == ThemeMode.light
|
||||
? "Light"
|
||||
: currentMode == ThemeMode.system
|
||||
? "Auto"
|
||||
: "Dark"]!,
|
||||
onSubmitted: (value) {
|
||||
setState(() {
|
||||
final selectedKey = optionsTheme.entries
|
||||
.firstWhere((e) => e.value == value)
|
||||
.key;
|
||||
PreferencesHelper.setString("AppTheme", selectedKey);
|
||||
themeController.setThemeMode(
|
||||
selectedKey == "Dark"
|
||||
? ThemeMode.dark
|
||||
: selectedKey == "Auto"
|
||||
? ThemeMode.system
|
||||
: ThemeMode.light,
|
||||
);
|
||||
});
|
||||
},
|
||||
),
|
||||
SettingSwitchTile(
|
||||
enabled: _useCustomTile,
|
||||
icon: Icon(Symbols.colorize, fill: 1, weight: 500),
|
||||
title: Text("use_custom_color".tr()),
|
||||
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'.tr()),
|
||||
description: Text('primary_color_sub'.tr()),
|
||||
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".tr()),
|
||||
description: Text('material_scheme_only_sub'.tr()),
|
||||
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.cards, fill: 1, weight: 500),
|
||||
title: Text('make_the_card_background_darker'.tr()),
|
||||
toggled: PreferencesHelper.getBool(
|
||||
"useDarkerCardBackground",
|
||||
) ??
|
||||
false,
|
||||
onChanged: (value) {
|
||||
context
|
||||
.read<UnitSettingsNotifier>()
|
||||
.updateUseDarkerBackground(value);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
]),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SettingSection(
|
||||
styleTile: true,
|
||||
title: SettingSectionTitle("Animations", noPadding: true),
|
||||
tiles: [
|
||||
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(
|
||||
icon: Icon(
|
||||
Symbols.assistant_navigation,
|
||||
fill: 1,
|
||||
weight: 500,
|
||||
),
|
||||
title: Text("use_device_compass".tr()),
|
||||
description: Text("use_device_compass_sub".tr()),
|
||||
toggled:
|
||||
PreferencesHelper.getBool("useDeviceCompass") ?? false,
|
||||
onChanged: (value) {
|
||||
context
|
||||
.read<UnitSettingsNotifier>()
|
||||
.updateUseDeviceCompass(value);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
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(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SettingSection(
|
||||
styleTile: true,
|
||||
title: SettingSectionTitle("Layout", noPadding: true),
|
||||
tiles: [
|
||||
SettingSwitchTile(
|
||||
icon: Icon(
|
||||
Symbols.responsive_layout,
|
||||
fill: 1,
|
||||
weight: 500,
|
||||
),
|
||||
title: Text("froggy_layout".tr()),
|
||||
toggled: PreferencesHelper.getBool("showFroggy") ?? true,
|
||||
onChanged: (value) {
|
||||
context.read<UnitSettingsNotifier>().updateShowFroggy(
|
||||
value,
|
||||
);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
SettingSwitchTile(
|
||||
icon: Icon(Symbols.taunt, fill: 1, weight: 500),
|
||||
title: Text('froggy_insights'.tr()),
|
||||
description: Text('froggy_insights_sub'.tr()),
|
||||
toggled:
|
||||
PreferencesHelper.getBool("useFroggyInsights") ?? false,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
PreferencesHelper.setBool("useFroggyInsights", value);
|
||||
});
|
||||
},
|
||||
),
|
||||
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: 200),
|
||||
]))
|
||||
]));
|
||||
}
|
||||
}
|
||||
+21
-283
@@ -16,6 +16,7 @@ import 'meteo_models.dart';
|
||||
import 'edit_layout_page.dart';
|
||||
import '../services/data_backup_service.dart';
|
||||
import '../screens/background_updates.dart';
|
||||
import 'setting_screens/appearance_screen.dart';
|
||||
|
||||
class SettingsScreen extends StatefulWidget {
|
||||
const SettingsScreen({super.key});
|
||||
@@ -25,9 +26,6 @@ class SettingsScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SettingsScreenState extends State<SettingsScreen> {
|
||||
bool _showTile = PreferencesHelper.getBool("usingCustomSeed") ?? false;
|
||||
bool _useCustomTile =
|
||||
PreferencesHelper.getBool("DynamicColors") == true ? false : true;
|
||||
String? city;
|
||||
String? country;
|
||||
|
||||
@@ -47,17 +45,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final themeController = Provider.of<ThemeController>(context);
|
||||
final currentMode = themeController.themeMode;
|
||||
|
||||
final isSupported = themeController.isDynamicColorSupported;
|
||||
|
||||
final optionsTheme = {
|
||||
"Auto": "theme_auto".tr(),
|
||||
"Dark": "theme_dark".tr(),
|
||||
"Light": "theme_light".tr(),
|
||||
};
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
body: CustomScrollView(
|
||||
@@ -73,214 +60,29 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
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"
|
||||
: currentMode == ThemeMode.system
|
||||
? "Auto"
|
||||
: "Dark"]!,
|
||||
),
|
||||
options: optionsTheme.values.toList(),
|
||||
initialOption: optionsTheme[currentMode == ThemeMode.light
|
||||
? "Light"
|
||||
: currentMode == ThemeMode.system
|
||||
? "Auto"
|
||||
: "Dark"]!,
|
||||
onSubmitted: (value) {
|
||||
setState(() {
|
||||
final selectedKey = optionsTheme.entries
|
||||
.firstWhere((e) => e.value == value)
|
||||
.key;
|
||||
PreferencesHelper.setString("AppTheme", selectedKey);
|
||||
themeController.setThemeMode(
|
||||
selectedKey == "Dark"
|
||||
? ThemeMode.dark
|
||||
: selectedKey == "Auto"
|
||||
? ThemeMode.system
|
||||
: 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".tr()),
|
||||
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'.tr()),
|
||||
description: Text('primary_color_sub'.tr()),
|
||||
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".tr()),
|
||||
description: Text('material_scheme_only_sub'.tr()),
|
||||
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.responsive_layout,
|
||||
fill: 1,
|
||||
weight: 500,
|
||||
),
|
||||
title: Text("froggy_layout".tr()),
|
||||
toggled: PreferencesHelper.getBool("showFroggy") ?? true,
|
||||
onChanged: (value) {
|
||||
context.read<UnitSettingsNotifier>().updateShowFroggy(
|
||||
value,
|
||||
);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
SettingSwitchTile(
|
||||
icon: Icon(Symbols.cards, fill: 1, weight: 500),
|
||||
title: Text('make_the_card_background_darker'.tr()),
|
||||
toggled: PreferencesHelper.getBool(
|
||||
"useDarkerCardBackground",
|
||||
) ??
|
||||
false,
|
||||
onChanged: (value) {
|
||||
context
|
||||
.read<UnitSettingsNotifier>()
|
||||
.updateUseDarkerBackground(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,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
icon: Icon(
|
||||
Symbols.format_paint,
|
||||
fill: 1,
|
||||
weight: 500,
|
||||
),
|
||||
title: Text("Appearance"),
|
||||
description: Text("Themes, animations, and app layout"),
|
||||
trailing: Icon(Icons.chevron_right),
|
||||
onTap: () async {
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => const AppearanceScreen(),
|
||||
),
|
||||
);
|
||||
})
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
SizedBox(height: 16),
|
||||
SettingSection(
|
||||
styleTile: true,
|
||||
title: SettingSectionTitle('weather'.tr(), noPadding: true),
|
||||
// title: SettingSectionTitle('weather'.tr(), noPadding: true),
|
||||
tiles: [
|
||||
SettingActionTile(
|
||||
icon: Icon(Symbols.home_pin, fill: 1, weight: 500),
|
||||
@@ -324,6 +126,8 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
SettingActionTile(
|
||||
icon: Icon(Symbols.update, fill: 1, weight: 500),
|
||||
title: Text('background_updates'.tr()),
|
||||
description: Text(
|
||||
"Widget updates, update interval, and scheduled updates"),
|
||||
trailing: Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
@@ -333,68 +137,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
);
|
||||
},
|
||||
),
|
||||
SettingSwitchTile(
|
||||
icon: Icon(
|
||||
Symbols.text_ad,
|
||||
fill: 1,
|
||||
weight: 500,
|
||||
),
|
||||
title: Text("Use AI for summary"),
|
||||
description: Text(
|
||||
"GPT-4o Mini generates summaries of hourly, daily, and current weather, refreshing every 2 hours"),
|
||||
toggled:
|
||||
PreferencesHelper.getBool("useAISummary") ?? false,
|
||||
onChanged: (value) {
|
||||
PreferencesHelper.setBool("useAISummary", value);
|
||||
SnackUtil.showSnackBar(
|
||||
context: context,
|
||||
message: "Restart to apply changes");
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
SettingSwitchTile(
|
||||
icon: Icon(
|
||||
Symbols.assistant_navigation,
|
||||
fill: 1,
|
||||
weight: 500,
|
||||
),
|
||||
title: Text("use_device_compass".tr()),
|
||||
description: Text("use_device_compass_sub".tr()),
|
||||
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'.tr()),
|
||||
description: Text('froggy_insights_sub'.tr()),
|
||||
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,
|
||||
@@ -414,13 +156,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
SizedBox(height: 16),
|
||||
SettingSection(
|
||||
styleTile: true,
|
||||
title: SettingSectionTitle(
|
||||
'additional'.tr(),
|
||||
noPadding: true,
|
||||
),
|
||||
tiles: [
|
||||
SettingActionTile(
|
||||
icon: Icon(Symbols.language, fill: 1, weight: 500),
|
||||
|
||||
@@ -55,10 +55,14 @@ class WeatherService {
|
||||
'forecast_hours': '1',
|
||||
});
|
||||
|
||||
// Prepare list of HTTP requests (always include weather and air quality)
|
||||
final astronomyUri = Uri.parse(
|
||||
'https://api.weatherapi.com/v1/astronomy.json?key=${dotenv.env['API_KEY_WEATHERAPI']!.toString()}&q=$lat,$lon');
|
||||
|
||||
// Prepare list of HTTP requests
|
||||
final requests = <Future<http.Response>>[
|
||||
http.get(uri),
|
||||
http.get(airQualityUri),
|
||||
http.get(astronomyUri),
|
||||
];
|
||||
|
||||
final responses = await Future.wait(requests);
|
||||
@@ -67,6 +71,8 @@ class WeatherService {
|
||||
final weatherData = json.decode(responses[0].body) as Map<String, dynamic>;
|
||||
final airQualityData =
|
||||
json.decode(responses[1].body) as Map<String, dynamic>;
|
||||
final astronomyData =
|
||||
json.decode(responses[2].body) as Map<String, dynamic>;
|
||||
|
||||
// Check if we need fallback data for missing fields
|
||||
Map<String, dynamic> finalWeatherData = weatherData;
|
||||
@@ -79,11 +85,13 @@ class WeatherService {
|
||||
finalWeatherData['hourly'] = sanitizeHourly(finalWeatherData['hourly']);
|
||||
finalWeatherData['daily'] = sanitizeDaily(finalWeatherData['daily']);
|
||||
|
||||
if (finalWeatherData['error'] == true || airQualityData['error'] == true) {
|
||||
if (finalWeatherData['error'] == true ||
|
||||
airQualityData['error'] == true ||
|
||||
astronomyData['error'] == true) {
|
||||
final reason = finalWeatherData['reason'] ??
|
||||
airQualityData['reason'] ??
|
||||
astronomyData['reason'] ??
|
||||
'Unknown error';
|
||||
|
||||
if (context != null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
@@ -107,6 +115,7 @@ class WeatherService {
|
||||
final combinedDataForView = {
|
||||
...finalWeatherData,
|
||||
'air_quality': airQualityData,
|
||||
'astronomy': astronomyData,
|
||||
};
|
||||
|
||||
final nowForView = DateTime.now().toIso8601String();
|
||||
@@ -129,7 +138,9 @@ class WeatherService {
|
||||
if (json.encode(cachedData['current']) ==
|
||||
json.encode(finalWeatherData['current']) &&
|
||||
json.encode(cachedData['air_quality'] ?? {}) ==
|
||||
json.encode(airQualityData)) {
|
||||
json.encode(airQualityData) &&
|
||||
json.encode(cachedData['astronomy'] ?? {}) ==
|
||||
json.encode(astronomyData)) {
|
||||
log("Hive: No update needed for $key");
|
||||
return {
|
||||
'data': cachedData,
|
||||
@@ -143,6 +154,7 @@ class WeatherService {
|
||||
final combinedData = {
|
||||
...finalWeatherData,
|
||||
'air_quality': airQualityData,
|
||||
'astronomy': astronomyData,
|
||||
};
|
||||
|
||||
final wrappedData = {
|
||||
|
||||
@@ -4,33 +4,38 @@ import '../utils/preferences_helper.dart';
|
||||
import 'package:dynamic_color/dynamic_color.dart';
|
||||
|
||||
class ThemeController extends ChangeNotifier {
|
||||
Color? _seedColor;
|
||||
Color? _seedColor;
|
||||
CorePalette? _corePalette;
|
||||
|
||||
ThemeMode _themeMode = PreferencesHelper.getString("AppTheme") == "Light"
|
||||
? ThemeMode.light : PreferencesHelper.getString("AppTheme") == "Auto" ? ThemeMode.system
|
||||
: ThemeMode.dark;
|
||||
? ThemeMode.light
|
||||
: PreferencesHelper.getString("AppTheme") == "Auto"
|
||||
? ThemeMode.system
|
||||
: ThemeMode.dark;
|
||||
|
||||
bool isCustom = PreferencesHelper.getBool("usingCustomSeed") ?? false;
|
||||
bool _isUsingDynamicColor = false;
|
||||
|
||||
bool _isDynamicColorSupported = false;
|
||||
|
||||
bool get isDynamicColorSupported => _isDynamicColorSupported;
|
||||
bool get isDynamicColorSupported => _isDynamicColorSupported;
|
||||
|
||||
Future<void> checkDynamicColorSupport() async {
|
||||
_isDynamicColorSupported = (await DynamicColorPlugin.getCorePalette()) != null;
|
||||
}
|
||||
Future<void> checkDynamicColorSupport() async {
|
||||
_isDynamicColorSupported =
|
||||
(await DynamicColorPlugin.getCorePalette()) != null;
|
||||
}
|
||||
|
||||
ThemeController();
|
||||
|
||||
Future<void> initialize({Color fallbackColor = const Color(0xFF012E7C)}) async {
|
||||
Future<void> initialize(
|
||||
{Color fallbackColor = const Color(0xFF012E7C)}) async {
|
||||
bool useDynamicColors = PreferencesHelper.getBool("DynamicColors") ?? false;
|
||||
|
||||
if (useDynamicColors) {
|
||||
await loadDynamicColors();
|
||||
} else if (isCustom) {
|
||||
setSeedColor(PreferencesHelper.getColor("CustomMaterialColor") ?? Colors.blue);
|
||||
setSeedColor(
|
||||
PreferencesHelper.getColor("CustomMaterialColor") ?? Colors.blue);
|
||||
} else {
|
||||
setSeedColor(fallbackColor);
|
||||
}
|
||||
@@ -48,12 +53,11 @@ Future<void> checkDynamicColorSupport() async {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void setSeedColorSilently(Color newColor) {
|
||||
_seedColor = newColor;
|
||||
_corePalette = CorePalette.of(newColor.value);
|
||||
_isUsingDynamicColor = false;
|
||||
}
|
||||
|
||||
void setSeedColorSilently(Color newColor) {
|
||||
_seedColor = newColor;
|
||||
_corePalette = CorePalette.of(newColor.value);
|
||||
_isUsingDynamicColor = false;
|
||||
}
|
||||
|
||||
void setThemeMode(ThemeMode mode) {
|
||||
_themeMode = mode;
|
||||
@@ -75,7 +79,13 @@ void setSeedColorSilently(Color newColor) {
|
||||
final corePalette = await DynamicColorPlugin.getCorePalette();
|
||||
if (corePalette != null) {
|
||||
_corePalette = corePalette;
|
||||
_seedColor = Color(corePalette.primary.get(40));
|
||||
|
||||
final brightness = currentBrightness;
|
||||
|
||||
int primaryTone = brightness == Brightness.light ? 40 : 80;
|
||||
int secondaryTone = brightness == Brightness.light ? 40 : 80;
|
||||
|
||||
_seedColor = Color(corePalette.primary.get(primaryTone));
|
||||
_isUsingDynamicColor = true;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -227,6 +227,19 @@ String buildHumidity(Color color, int humidityValue) {
|
||||
return returnSvg;
|
||||
}
|
||||
|
||||
// Build cloud svg
|
||||
|
||||
String buildCloudCoverSvg(Color color) {
|
||||
final hexColor =
|
||||
'#${color.value.toRadixString(16).padLeft(8, '0').substring(2)}';
|
||||
|
||||
return '''<svg width="180" height="180" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M63.5616 25.8468C78.2888 11.595 101.711 11.595 116.438 25.8468C120.945 30.2077 126.466 33.3858 132.508 35.0962C152.251 40.6859 163.962 60.9091 158.946 80.7506C157.411 86.822 157.411 93.1781 158.946 99.2495C163.962 119.091 152.251 139.314 132.508 144.904C126.466 146.614 120.945 149.792 116.438 154.153C101.711 168.405 78.2888 168.405 63.5616 154.153C59.0552 149.792 53.5339 146.614 47.4926 144.904C27.7492 139.314 16.0379 119.091 21.0541 99.2495C22.5891 93.1781 22.5891 86.822 21.0541 80.7506C16.0379 60.9091 27.7492 40.6859 47.4926 35.0962C53.5339 33.3858 59.0552 30.2077 63.5616 25.8468Z" fill="$hexColor"/>
|
||||
</svg>
|
||||
|
||||
''';
|
||||
}
|
||||
|
||||
// Return SVG representing the sun's path from sunrise to sunset
|
||||
|
||||
String buildSunPathWithIcon({
|
||||
@@ -294,3 +307,43 @@ String buildNowHourSvg(Color colorPrimary) {
|
||||
|
||||
return returnSvg;
|
||||
}
|
||||
|
||||
// Moon path
|
||||
|
||||
String buildMoonPathWithIcon({
|
||||
required Color pathColor,
|
||||
required double percent,
|
||||
required Color outLineColor,
|
||||
bool showMoon = true,
|
||||
int moonIllumination = 100,
|
||||
}) {
|
||||
final hexColor =
|
||||
'#${pathColor.value.toRadixString(16).padLeft(8, '0').substring(2)}';
|
||||
final hexColoroutLine =
|
||||
'#${outLineColor.value.toRadixString(16).padLeft(8, '0').substring(2)}';
|
||||
|
||||
const svgWidth = 176.0;
|
||||
|
||||
final shift = -0.0;
|
||||
final stretch = 1.0;
|
||||
final t = ((percent + shift) * stretch).clamp(0.0, 1.0);
|
||||
final moonX = t * svgWidth;
|
||||
final moonY = 70 - 70 * sin(pi * t);
|
||||
final moonYEndStart = 60 - 70 * sin(pi * t);
|
||||
|
||||
final moonFill = showMoon
|
||||
? 'radialGradient(circle at center, white ${moonIllumination}%, transparent 100%)'
|
||||
: 'transparent';
|
||||
|
||||
return '''
|
||||
|
||||
<svg width="176" height="110" viewBox="0 0 176 110" style="overflow: visible;" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="$hexColor" d="M176.5,54.44V89.86C176.5,100.91 167.52,109.86 156.44,109.86H20.06C8.98,109.86 0,100.91 0,89.86V52.57C7.79,51.81 15.41,48.77 21.78,43.46L62.06,9.91C76.95,-2.49 98.6,-2.49 113.49,9.91L156.22,45.51C162.18,50.47 169.23,53.45 176.49,54.44H176.5Z"/>
|
||||
|
||||
<circle cx="$moonX" cy="${percent == 0 || percent == 1 ? '$moonYEndStart' : '$moonY'}"
|
||||
fill="${showMoon ? 'white' : 'transparent'}"
|
||||
r="10" stroke="$hexColoroutLine"
|
||||
stroke-width="${showMoon ? '3' : '0'} "/>
|
||||
</svg>
|
||||
''';
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:weather_master_app/utils/preferences_helper.dart';
|
||||
import '../notifiers/unit_settings_notifier.dart';
|
||||
import '../utils/unit_converter.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -16,6 +17,7 @@ import '../screens/extended_widgets.dart';
|
||||
import '../helper/locale_helper.dart';
|
||||
import '../utils/visual_utils.dart';
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:moon_phase/moon_widget.dart';
|
||||
|
||||
class ConditionsWidgets extends StatefulWidget {
|
||||
final int selectedContainerBgIndex;
|
||||
@@ -35,6 +37,10 @@ class ConditionsWidgets extends StatefulWidget {
|
||||
final double currentTotalPrec;
|
||||
final double currentDayLength;
|
||||
final bool isFromHome;
|
||||
final String moonrise;
|
||||
final String moonset;
|
||||
final String moonPhase;
|
||||
final String cloudCover;
|
||||
|
||||
const ConditionsWidgets(
|
||||
{super.key,
|
||||
@@ -54,7 +60,11 @@ class ConditionsWidgets extends StatefulWidget {
|
||||
required this.currentAQIEURO,
|
||||
required this.currentTotalPrec,
|
||||
required this.currentDayLength,
|
||||
required this.isFromHome});
|
||||
required this.isFromHome,
|
||||
required this.moonrise,
|
||||
required this.moonset,
|
||||
required this.moonPhase,
|
||||
required this.cloudCover});
|
||||
|
||||
@override
|
||||
State<ConditionsWidgets> createState() => _ConditionsWidgetsState();
|
||||
@@ -64,11 +74,12 @@ class _ConditionsWidgetsState extends State<ConditionsWidgets> {
|
||||
List<int> itemOrder = [];
|
||||
|
||||
final String orderPrefsKey = 'tile_order';
|
||||
|
||||
bool _initialized = false;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadTileOrder();
|
||||
_initializePreferences();
|
||||
}
|
||||
|
||||
Future<void> _loadTileOrder() async {
|
||||
@@ -80,13 +91,34 @@ class _ConditionsWidgetsState extends State<ConditionsWidgets> {
|
||||
itemOrder = savedList.map(int.parse).toList();
|
||||
});
|
||||
} else {
|
||||
// Default order
|
||||
setState(() {
|
||||
itemOrder = List.generate(8, (index) => index);
|
||||
itemOrder = List.generate(10, (index) => index);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _initializePreferences() async {
|
||||
if (_initialized) return;
|
||||
_initialized = true;
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
List<String>? savedList = prefs.getStringList(orderPrefsKey);
|
||||
|
||||
if (savedList != null) {
|
||||
List<int> intList = savedList.map(int.parse).toList();
|
||||
List<int> zeroToSeven = List.generate(8, (i) => i);
|
||||
|
||||
if (intList.toSet().containsAll(zeroToSeven) &&
|
||||
intList.every((e) => e >= 0 && e <= 7)) {
|
||||
await prefs.remove(orderPrefsKey);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> newList = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
await prefs.setStringList(orderPrefsKey, newList);
|
||||
print('New list saved');
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// return const Placeholder();
|
||||
@@ -109,6 +141,8 @@ class _ConditionsWidgetsState extends State<ConditionsWidgets> {
|
||||
DateTime now = utcNow.add(Duration(seconds: offsetSeconds));
|
||||
DateTime sunrise = DateTime.parse(widget.currentSunrise);
|
||||
DateTime sunset = DateTime.parse(widget.currentSunset);
|
||||
DateTime moonrise = DateFormat.jm().parse(widget.moonrise);
|
||||
DateTime moonset = DateFormat.jm().parse(widget.moonset);
|
||||
|
||||
now = DateTime(
|
||||
now.year,
|
||||
@@ -131,6 +165,12 @@ class _ConditionsWidgetsState extends State<ConditionsWidgets> {
|
||||
? DateFormat.Hm().format(sunset)
|
||||
: DateFormat.jm().format(sunset);
|
||||
|
||||
final moonriseFormat = timeUnit == '24 hr'
|
||||
? DateFormat.Hm().format(moonrise)
|
||||
: DateFormat.jm().format(moonrise);
|
||||
final moonsetFormat = timeUnit == '24 hr'
|
||||
? DateFormat.Hm().format(moonset)
|
||||
: DateFormat.jm().format(moonset);
|
||||
final pressureUnit = context.watch<UnitSettingsNotifier>().pressureUnit;
|
||||
final precipitationUnit =
|
||||
context.watch<UnitSettingsNotifier>().precipitationUnit;
|
||||
@@ -153,6 +193,18 @@ class _ConditionsWidgetsState extends State<ConditionsWidgets> {
|
||||
? UnitConverter.mToMiles(widget.currentVisibility.toDouble())
|
||||
: UnitConverter.mToKm(widget.currentVisibility.toDouble());
|
||||
|
||||
final windUnit = context.watch<UnitSettingsNotifier>().windUnit;
|
||||
|
||||
final formattedWindSpeed = windUnit == 'Mph'
|
||||
? UnitConverter.kmhToMph(widget.currentWindSpeed)
|
||||
: windUnit == 'M/s'
|
||||
? UnitConverter.kmhToMs(widget.currentWindSpeed)
|
||||
: windUnit == 'Bft'
|
||||
? UnitConverter.kmhToBeaufort(widget.currentWindSpeed)
|
||||
: windUnit == 'Kt'
|
||||
? UnitConverter.kmhToKt(widget.currentWindSpeed)
|
||||
: widget.currentWindSpeed;
|
||||
|
||||
if (sunset.isBefore(sunrise)) {
|
||||
sunset = sunset.add(Duration(days: 1));
|
||||
}
|
||||
@@ -166,6 +218,21 @@ class _ConditionsWidgetsState extends State<ConditionsWidgets> {
|
||||
|
||||
final colorTheme = Theme.of(context).colorScheme;
|
||||
|
||||
moonrise =
|
||||
DateTime(now.year, now.month, now.day, moonrise.hour, moonrise.minute);
|
||||
moonset =
|
||||
DateTime(now.year, now.month, now.day, moonset.hour, moonset.minute);
|
||||
|
||||
if (moonset.isBefore(moonrise)) {
|
||||
moonset = moonset.add(Duration(days: 1));
|
||||
}
|
||||
|
||||
double moonPercent = ((now.difference(moonrise).inSeconds) /
|
||||
(moonset.difference(moonrise).inSeconds))
|
||||
.clamp(0, 1);
|
||||
|
||||
// int moonIllumination = int.parse(widget.moonPhase);
|
||||
|
||||
List<Widget> gridItems = itemOrder.map((i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
@@ -689,7 +756,7 @@ class _ConditionsWidgetsState extends State<ConditionsWidgets> {
|
||||
child: Text(
|
||||
widget.currentWindSpeed == 0.0000001
|
||||
? '--'
|
||||
: getWindSpeedType(widget.currentWindSpeed),
|
||||
: '${windUnit == 'M/s' ? formattedWindSpeed.toStringAsFixed(1) : formattedWindSpeed.round()} ${localizeWindUnit(windUnit, context.locale)}',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
@@ -1071,6 +1138,239 @@ class _ConditionsWidgetsState extends State<ConditionsWidgets> {
|
||||
);
|
||||
},
|
||||
);
|
||||
case 8:
|
||||
return OpenContainer(
|
||||
transitionType: ContainerTransitionType.fadeThrough,
|
||||
closedElevation: 0,
|
||||
closedShape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
openShape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
openElevation: 0,
|
||||
transitionDuration: Duration(milliseconds: 500),
|
||||
closedColor: Color(widget.selectedContainerBgIndex),
|
||||
openColor: colorTheme.surface,
|
||||
openBuilder: (context, _) {
|
||||
return ExtendWidget('moon_widget');
|
||||
},
|
||||
closedBuilder: (context, openContainer) {
|
||||
return GestureDetector(
|
||||
child: Container(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(widget.selectedContainerBgIndex),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: MoonWidget(
|
||||
date: now,
|
||||
resolution: 128,
|
||||
size: 22,
|
||||
moonColor: Colors.amber,
|
||||
earthshineColor: Colors.blueGrey.shade900,
|
||||
),
|
||||
horizontalTitleGap: 5,
|
||||
contentPadding: EdgeInsets.only(left: 10, bottom: 0),
|
||||
title: Text("moon".tr(),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).brightness ==
|
||||
Brightness.dark
|
||||
? Colors.white
|
||||
: Colors.black),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
Positioned(
|
||||
bottom: -1,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.12,
|
||||
child: SvgPicture.string(
|
||||
clipBehavior: Clip.none,
|
||||
buildMoonPathWithIcon(
|
||||
pathColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondaryContainer,
|
||||
percent: moonPercent,
|
||||
outLineColor:
|
||||
Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
allowDrawingOutsideViewBox: true,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
left: -1,
|
||||
child: Container(
|
||||
height: 65,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
color: const Color.fromRGBO(0, 0, 0, 0.5),
|
||||
// borderRadius: BorderRadius.only(bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20))
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
spacing: 5,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.vertical_align_top,
|
||||
weight: 500,
|
||||
size: 17,
|
||||
color: Colors.white,
|
||||
),
|
||||
Text(moonriseFormat,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 14,
|
||||
))
|
||||
],
|
||||
),
|
||||
Row(
|
||||
spacing: 5,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.vertical_align_bottom,
|
||||
weight: 500,
|
||||
size: 17,
|
||||
color: Colors.white,
|
||||
),
|
||||
Text(moonsetFormat,
|
||||
style: TextStyle(
|
||||
color: Colors.white, fontSize: 14)),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
)
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
widget.isFromHome ? openContainer() : null;
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
case 9:
|
||||
return OpenContainer(
|
||||
transitionType: ContainerTransitionType.fadeThrough,
|
||||
closedElevation: 0,
|
||||
closedShape: const CircleBorder(),
|
||||
openShape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
openElevation: 0,
|
||||
transitionDuration: Duration(milliseconds: 500),
|
||||
closedColor: Color(widget.selectedContainerBgIndex),
|
||||
openColor: colorTheme.surface,
|
||||
openBuilder: (context, _) {
|
||||
return SizedBox.shrink();
|
||||
},
|
||||
closedBuilder: (context, openContainer) {
|
||||
return GestureDetector(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
child: Container(
|
||||
height: 160,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(widget.selectedContainerBgIndex),
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: SvgPicture.string(
|
||||
buildCloudCoverSvg(Theme.of(context)
|
||||
.colorScheme
|
||||
.tertiaryContainer),
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
headerWidgetConditions(
|
||||
headerText: "cloudiness".tr(),
|
||||
headerIcon: Symbols.cloud,
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
widget.currentVisibility == 0.0000001
|
||||
? '--'
|
||||
: widget.cloudCover,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onTertiaryContainer,
|
||||
fontSize:
|
||||
MediaQuery.of(context).size.width * 0.1,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 30),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Text(
|
||||
"%",
|
||||
style: TextStyle(
|
||||
color:
|
||||
Theme.of(context).colorScheme.onSurface,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (widget.isFromHome) {
|
||||
if (widget.currentVisibility == 0.0000001) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Row(
|
||||
spacing: 10,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.error,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onInverseSurface,
|
||||
),
|
||||
Text("No data available")
|
||||
],
|
||||
)));
|
||||
} else {
|
||||
openContainer();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
default:
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
@@ -334,8 +334,7 @@ class _SummaryCardState extends State<SummaryCard> {
|
||||
Text(
|
||||
_headline ?? '',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
color: Theme.of(context).colorScheme.onSurface, fontSize: 14.5),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
// ),
|
||||
@@ -537,32 +536,10 @@ class _SummaryCardState extends State<SummaryCard> {
|
||||
isSummaryLoaded = true;
|
||||
}
|
||||
|
||||
final windUnit = context.watch<UnitSettingsNotifier>().windUnit;
|
||||
// final windUnit = context.watch<UnitSettingsNotifier>().windUnit;
|
||||
|
||||
final gustRaw = widget.currentData['wind_gusts_10m'];
|
||||
final gustValue = (gustRaw is num) ? gustRaw.toDouble() : 0.000000001;
|
||||
|
||||
final formattedWindGust = windUnit == 'Mph'
|
||||
? UnitConverter.kmhToMph(gustValue)
|
||||
: windUnit == 'M/s'
|
||||
? UnitConverter.kmhToMs(gustValue)
|
||||
: windUnit == 'Bft'
|
||||
? UnitConverter.kmhToBeaufort(gustValue)
|
||||
: windUnit == 'Kt'
|
||||
? UnitConverter.kmhToKt(gustValue)
|
||||
: gustValue;
|
||||
|
||||
final formattedWindSpeed = windUnit == 'Mph'
|
||||
? UnitConverter.kmhToMph(widget.currentData['wind_speed_10m'])
|
||||
: windUnit == 'M/s'
|
||||
? UnitConverter.kmhToMs(widget.currentData['wind_speed_10m'])
|
||||
: windUnit == 'Bft'
|
||||
? UnitConverter.kmhToBeaufort(
|
||||
widget.currentData['wind_speed_10m'])
|
||||
: windUnit == 'Kt'
|
||||
? UnitConverter.kmhToKt(
|
||||
widget.currentData['wind_speed_10m'])
|
||||
: widget.currentData['wind_speed_10m'];
|
||||
// final gustRaw = widget.currentData['wind_gusts_10m'];
|
||||
// final gustValue = (gustRaw is num) ? gustRaw.toDouble() : 0.000000001;
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
@@ -625,72 +602,72 @@ class _SummaryCardState extends State<SummaryCard> {
|
||||
},
|
||||
child: buildWeatherSummaryWidget(context, isExpanded),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 10, right: 10, top: 5, bottom: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 4,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.air,
|
||||
weight: 500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
size: 19,
|
||||
),
|
||||
Text(
|
||||
'${windUnit == 'M/s' ? formattedWindSpeed.toStringAsFixed(1) : formattedWindSpeed.round()} ${localizeWindUnit(windUnit, context.locale)}',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontSize: 15,
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 4,
|
||||
children: [
|
||||
Icon(Symbols.wind_power,
|
||||
weight: 500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
size: 19),
|
||||
Text(
|
||||
gustValue == 0.000000001
|
||||
? '--'
|
||||
: "${windUnit == 'M/s' ? formattedWindGust.toStringAsFixed(1) : formattedWindGust.round()} ${localizeWindUnit(windUnit, context.locale)}",
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontSize: 15,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 4,
|
||||
children: [
|
||||
Icon(Symbols.cloud,
|
||||
weight: 500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
size: 19),
|
||||
Text("${widget.currentData['cloud_cover']}%",
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontSize: 15,
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
))
|
||||
// Padding(
|
||||
// padding: EdgeInsets.only(left: 10, right: 10, top: 5, bottom: 8),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Expanded(
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// spacing: 4,
|
||||
// children: [
|
||||
// Icon(
|
||||
// Symbols.air,
|
||||
// weight: 500,
|
||||
// color: Theme.of(context).colorScheme.onSurface,
|
||||
// size: 19,
|
||||
// ),
|
||||
// Text(
|
||||
// '${windUnit == 'M/s' ? formattedWindSpeed.toStringAsFixed(1) : formattedWindSpeed.round()} ${localizeWindUnit(windUnit, context.locale)}',
|
||||
// style: TextStyle(
|
||||
// color: Theme.of(context).colorScheme.onSurface,
|
||||
// fontSize: 15,
|
||||
// ))
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// Expanded(
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// spacing: 4,
|
||||
// children: [
|
||||
// Icon(Symbols.wind_power,
|
||||
// weight: 500,
|
||||
// color: Theme.of(context).colorScheme.onSurface,
|
||||
// size: 19),
|
||||
// Text(
|
||||
// gustValue == 0.000000001
|
||||
// ? '--'
|
||||
// : "${windUnit == 'M/s' ? formattedWindGust.toStringAsFixed(1) : formattedWindGust.round()} ${localizeWindUnit(windUnit, context.locale)}",
|
||||
// style: TextStyle(
|
||||
// color: Theme.of(context).colorScheme.onSurface,
|
||||
// fontSize: 15,
|
||||
// ),
|
||||
// maxLines: 1,
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// Expanded(
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// spacing: 4,
|
||||
// children: [
|
||||
// Icon(Symbols.cloud,
|
||||
// weight: 500,
|
||||
// color: Theme.of(context).colorScheme.onSurface,
|
||||
// size: 19),
|
||||
// Text("${widget.currentData['cloud_cover']}%",
|
||||
// style: TextStyle(
|
||||
// color: Theme.of(context).colorScheme.onSurface,
|
||||
// fontSize: 15,
|
||||
// ))
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ))
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:moon_phase/moon_phase.dart';
|
||||
import '../utils/icon_map.dart';
|
||||
import '../utils/condition_label_map.dart';
|
||||
import '../utils/preferences_helper.dart';
|
||||
@@ -7,6 +8,8 @@ import '../utils/unit_converter.dart';
|
||||
import '../notifiers/unit_settings_notifier.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:moon_phase/moon_widget.dart';
|
||||
import 'package:moon_phase/moon_phase.dart';
|
||||
|
||||
class WeatherTopCard extends StatefulWidget {
|
||||
final num currentTemp;
|
||||
@@ -101,6 +104,15 @@ class _WeatherTopCardState extends State<WeatherTopCard> {
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// MoonWidget(
|
||||
// date: ,
|
||||
// resolution: 128,
|
||||
// size: 64,
|
||||
// moonColor: Colors.amber,
|
||||
// earthshineColor: Colors.blueGrey.shade900,
|
||||
|
||||
// ),
|
||||
|
||||
Text(
|
||||
"now".tr(),
|
||||
style: TextStyle(
|
||||
|
||||
+8
-8
@@ -437,6 +437,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.16.0"
|
||||
moon_phase:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: moon_phase
|
||||
sha256: "41de1d39bcbb45b9c4d86fa8405b231188fcbf6a095edd294db22cdee2d5e095"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2+9"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -684,14 +692,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shimmer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shimmer
|
||||
sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ dependencies:
|
||||
flutter_dotenv: ^5.2.1
|
||||
home_widget: ^0.8.0
|
||||
permission_handler: ^12.0.1
|
||||
shimmer: ^3.0.0
|
||||
moon_phase: ^1.0.2+9
|
||||
|
||||
settings_tiles:
|
||||
path: ./settings_tiles_custom
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+22
@@ -565,3 +565,25 @@ create_cxx_tasks
|
||||
[gap of 20ms]
|
||||
create_cxx_tasks completed in 194ms
|
||||
|
||||
# C/C++ build system timings
|
||||
create_cxx_tasks
|
||||
create-initial-cxx-model
|
||||
create-module-model 40ms
|
||||
create-variant-model 16ms
|
||||
create-ARMEABI_V7A-model 44ms
|
||||
[gap of 101ms]
|
||||
create-initial-cxx-model completed in 207ms
|
||||
[gap of 22ms]
|
||||
create_cxx_tasks completed in 239ms
|
||||
|
||||
# C/C++ build system timings
|
||||
create_cxx_tasks
|
||||
create-initial-cxx-model
|
||||
create-module-model 45ms
|
||||
create-variant-model 15ms
|
||||
create-ARMEABI_V7A-model 45ms
|
||||
[gap of 87ms]
|
||||
create-initial-cxx-model completed in 197ms
|
||||
[gap of 23ms]
|
||||
create_cxx_tasks completed in 231ms
|
||||
|
||||
Reference in new issue
Block a user