From f0bf80bb67abdd2cf5eac817440cbb3dcc3147af Mon Sep 17 00:00:00 2001 From: Pranshul Date: Thu, 4 Sep 2025 22:35:39 +0530 Subject: [PATCH] view changelogs, fixed background updates, updated strings, expressive loader --- android/app/build.gradle.kts | 1 - assets/translations/en.json | 3 +- assets/translations/source.json | 3 +- lib/controllers/gradient_list.dart | 33 +- lib/main.dart | 6 + lib/screens/about_page.dart | 281 +++++++++++++++++- lib/screens/background_updates.dart | 5 +- lib/screens/daily_forecast.dart | 1 - lib/screens/extended_widgets.dart | 92 +++--- lib/screens/home.dart | 148 +++++++-- lib/screens/languages_page.dart | 15 +- lib/screens/locations.dart | 22 +- lib/screens/searchlocations.dart | 180 ++++++++--- lib/screens/settings.dart | 3 +- lib/services/fetch_data.dart | 205 +++++++------ lib/utils/bottom_provider.dart | 3 +- lib/utils/froggy_map.dart | 142 +++++---- lib/utils/is_online.dart | 45 +-- lib/widget_background.dart | 7 +- lib/widgets/top_weather_card.dart | 11 +- .../.gradle/8.9/fileHashes/fileHashes.bin | Bin 28497 -> 28497 bytes .../.gradle/8.9/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../8.9/fileHashes/resourceHashesCache.bin | Bin 22679 -> 22951 bytes .../cxx/create_cxx_tasks_352_timing.txt | 16 + .../cxx/create_cxx_tasks_38_timing.txt | 67 +++++ 25 files changed, 936 insertions(+), 353 deletions(-) create mode 100644 settings_tiles_custom/example/build/app/intermediates/cxx/create_cxx_tasks_352_timing.txt diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index c40f81e6b..2a3220e4f 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -79,7 +79,6 @@ flutter { dependencies { coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4") implementation("androidx.work:work-runtime-ktx:2.9.0") - implementation("androidx.glance:glance-appwidget:1.0.0-alpha05") implementation("com.google.android.material:material:1.12.0") } \ No newline at end of file diff --git a/assets/translations/en.json b/assets/translations/en.json index 3d861ddcb..f008e532d 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -571,5 +571,6 @@ "insights_sub_49": "Very cold weather expected — possibly record lows.", "insights_sub_50": "Temperatures are within the usual range — no records expected.", "background_updates_not_working": "Background updates not working?", - "background_updates_not_working_sub": "Some device vendors restrict apps in the background. Check dontkillmyapp.com for steps to fix this." + "background_updates_not_working_sub": "Some device vendors restrict apps in the background. Check dontkillmyapp.com for steps to fix this.", + "about_weathermaster_sub": "Changelog, Version, License, and More" } diff --git a/assets/translations/source.json b/assets/translations/source.json index 3d861ddcb..f008e532d 100644 --- a/assets/translations/source.json +++ b/assets/translations/source.json @@ -571,5 +571,6 @@ "insights_sub_49": "Very cold weather expected — possibly record lows.", "insights_sub_50": "Temperatures are within the usual range — no records expected.", "background_updates_not_working": "Background updates not working?", - "background_updates_not_working_sub": "Some device vendors restrict apps in the background. Check dontkillmyapp.com for steps to fix this." + "background_updates_not_working_sub": "Some device vendors restrict apps in the background. Check dontkillmyapp.com for steps to fix this.", + "about_weathermaster_sub": "Changelog, Version, License, and More" } diff --git a/lib/controllers/gradient_list.dart b/lib/controllers/gradient_list.dart index d12ca5c2f..1ad614b1d 100644 --- a/lib/controllers/gradient_list.dart +++ b/lib/controllers/gradient_list.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../utils/theme.dart'; +import 'package:material_color_utilities/material_color_utilities.dart'; List getGradients( bool isLight, bool isFroggyLayout, iscurrentDay) { @@ -16,8 +17,11 @@ List getGradients( ? iscurrentDay ? LinearGradient( colors: [ - Color(paletteWeather.secondary.get(30)), - Color(paletteWeather.secondary.get(15)) + Color(CorePalette.of( + const Color.fromARGB(255, 31, 25, 0).toARGB32()) + .secondary + .get(30)), + Color(paletteWeather.secondary.get(18)) ], begin: Alignment.topCenter, end: Alignment.bottomCenter, @@ -32,8 +36,11 @@ List getGradients( stops: [0, 0.5]) : LinearGradient( colors: [ - Color(paletteWeather.secondary.get(25)), - Color(paletteWeather.secondary.get(20)) + Color(CorePalette.of( + const Color.fromARGB(255, 31, 25, 0).toARGB32()) + .secondary + .get(30)), + Color(paletteWeather.secondary.get(18)) ], begin: Alignment.topCenter, end: Alignment.bottomCenter, @@ -74,7 +81,10 @@ List getGradients( stops: [0, 0.5], ) : LinearGradient( - colors: [const Color.fromARGB(255, 4, 36, 83), Color(0xFF004a76)], + colors: [ + const Color.fromARGB(255, 5, 47, 110), + Color.fromARGB(255, 0, 51, 92) + ], begin: Alignment.topCenter, end: Alignment.bottomCenter, stops: [0, 0.5]), @@ -180,8 +190,8 @@ List getGradientsScrolled( ? iscurrentDay ? LinearGradient( colors: [ - Color(paletteWeather.secondary.get(15)), - Color(paletteWeather.secondary.get(15)) + Color(paletteWeather.secondary.get(18)), + Color(paletteWeather.secondary.get(18)) ], begin: Alignment.topCenter, end: Alignment.bottomCenter, @@ -196,8 +206,8 @@ List getGradientsScrolled( stops: [0, 0.5]) : LinearGradient( colors: [ - Color(paletteWeather.secondary.get(20)), - Color(paletteWeather.secondary.get(20)) + Color(paletteWeather.secondary.get(18)), + Color(paletteWeather.secondary.get(18)) ], begin: Alignment.topCenter, end: Alignment.bottomCenter, @@ -239,7 +249,10 @@ List getGradientsScrolled( stops: [0, 0.5], ) : LinearGradient( - colors: [Color(0xFF004a76), Color(0xFF004a76)], + colors: [ + Color.fromARGB(255, 0, 51, 92), + Color.fromARGB(255, 0, 51, 92) + ], begin: Alignment.topCenter, end: Alignment.bottomCenter, stops: [0, 0.5]), diff --git a/lib/main.dart b/lib/main.dart index dd09ae012..f869109ef 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -24,6 +24,7 @@ import 'dart:ui' as ui; import 'services/widget_service.dart'; import 'widget_background.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; +import 'package:home_widget/home_widget.dart'; final CorePalette paletteStartScreen = CorePalette.of( const Color.fromARGB(255, 255, 196, 0).toARGB32(), @@ -32,6 +33,8 @@ final CorePalette paletteStartScreen = CorePalette.of( @pragma('vm:entry-point') Future workerUpdateWidget() async { WidgetsFlutterBinding.ensureInitialized(); + final dir = await getApplicationDocumentsDirectory(); + Hive.init(dir.path); await updateHomeWidget(null, updatedFromHome: false); } @@ -68,6 +71,7 @@ const easySupportedLocales = [ Locale('zh', 'CN'), Locale('zh', 'TW'), Locale('ca', 'ES'), + Locale('bg', 'BG') ]; final flutterSupportedLocales = @@ -94,6 +98,8 @@ void main() async { final dir = await getApplicationDocumentsDirectory(); Hive.init(dir.path); + await Hive.openBox('changelogs'); + // widget------ bool useBackgroundUpdates = prefs.getBool("useBackgroundUpdates") ?? false; diff --git a/lib/screens/about_page.dart b/lib/screens/about_page.dart index 2199b8fd3..111802590 100644 --- a/lib/screens/about_page.dart +++ b/lib/screens/about_page.dart @@ -5,13 +5,18 @@ import '../utils/open_links.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; +import 'package:hive/hive.dart'; +import 'package:expressive_loading_indicator/expressive_loading_indicator.dart'; class AboutPage extends StatelessWidget { const AboutPage({super.key}); @override Widget build(BuildContext context) { + final colorTheme = Theme.of(context).colorScheme; + return Scaffold( + backgroundColor: Colors.transparent, appBar: AppBar( automaticallyImplyLeading: false, backgroundColor: Theme.of(context).colorScheme.surfaceContainer, @@ -31,10 +36,93 @@ class AboutPage extends StatelessWidget { Text( "WeatherMaster", style: TextStyle( - color: Theme.of(context).colorScheme.secondary, + color: Theme.of(context).colorScheme.onSurface, fontSize: 24), ), - CheckUpdateButton() + Row( + spacing: 2, + children: [ + CheckUpdateButton(), + FilledButton.tonal( + onPressed: () { + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(28)), + ), + builder: (context) { + return DraggableScrollableSheet( + initialChildSize: 0.4, + minChildSize: 0.4, + maxChildSize: 0.9, + snap: true, + builder: (context, scrollController) { + return Scaffold( + appBar: AppBar( + toolbarHeight: 65, + elevation: 1, + automaticallyImplyLeading: false, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(28), + topRight: Radius.circular(28))), + title: Text("Changelog"), + actions: [ + IconButton.filledTonal( + onPressed: () { + Navigator.pop(context); + }, + icon: Icon(Icons.close)), + SizedBox( + width: 10, + ) + ], + ), + body: Container( + decoration: BoxDecoration( + color: colorTheme.surfaceContainerLow, + boxShadow: [ + BoxShadow( + blurRadius: 10, + color: Colors.black26, + offset: Offset(0, -2), + ), + ], + ), + child: ChangelogSheet( + scrollController: scrollController), + ), + ); + }, + ); + }, + ); + }, + style: ButtonStyle( + padding: WidgetStateProperty.all( + EdgeInsets.symmetric(horizontal: 12, vertical: 5), + ), + shape: WidgetStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(3), + topRight: Radius.circular(50), + bottomLeft: Radius.circular(3), + bottomRight: Radius.circular(50)), + ), + ), + minimumSize: WidgetStateProperty.all(Size(0, 30)), + iconAlignment: IconAlignment.end, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + child: Text("Whats new", + style: TextStyle(fontWeight: FontWeight.w700)), + ), + ], + ) ]), Container( clipBehavior: Clip.hardEdge, @@ -42,8 +130,8 @@ class AboutPage extends StatelessWidget { BoxDecoration(borderRadius: BorderRadius.circular(50)), child: Image.asset( "assets/weather-icons/new_icon.png", - width: 80, - height: 80, + width: 76, + height: 76, )) ], ), @@ -420,12 +508,21 @@ class _CheckUpdateButtonState extends State { Symbols.refresh, weight: 700, ), - label: Text(isChecking ? 'checking'.tr() : currentVersion, - style: TextStyle(fontWeight: FontWeight.w700)), + label: + Text(currentVersion, style: TextStyle(fontWeight: FontWeight.w700)), style: ButtonStyle( padding: WidgetStateProperty.all( EdgeInsets.symmetric(horizontal: 12, vertical: 5), ), + shape: WidgetStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(50), + topRight: Radius.circular(3), + bottomLeft: Radius.circular(50), + bottomRight: Radius.circular(3)), + ), + ), minimumSize: WidgetStateProperty.all(Size(0, 30)), iconAlignment: IconAlignment.end, tapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -433,3 +530,175 @@ class _CheckUpdateButtonState extends State { ); } } + +class ChangelogService { + final String githubRepo = "PranshulGG/WeatherMaster"; + final Box _box = Hive.box('changelogs'); + + Future>> getChangelogs() async { + final now = DateTime.now(); + final lastFetch = _box.get('lastFetch') as DateTime?; + + if (lastFetch != null && + now.difference(lastFetch) < const Duration(hours: 48)) { + final cachedData = + List>.from(_box.get('data', defaultValue: [])); + + await Future.delayed(const Duration(seconds: 2)); + return cachedData; + } + + final url = Uri.parse("https://api.github.com/repos/$githubRepo/releases"); + final response = await http.get(url); + + if (response.statusCode != 200) { + throw Exception("Failed to fetch releases"); + } + + final releases = jsonDecode(response.body) as List; + + final parsed = releases + .where((r) => r['prerelease'] == false) + .take(10) + .map((r) => { + "tag": r["tag_name"], + "name": r["name"] ?? "", + "body": r["body"] ?? "", + "published_at": r["published_at"], + }) + .toList(); + + await _box.put('data', parsed); + await _box.put('lastFetch', now); + + return parsed; + } +} + +class ChangelogSheet extends StatefulWidget { + final ScrollController scrollController; + const ChangelogSheet({super.key, required this.scrollController}); + + @override + State createState() => _ChangelogSheetState(); +} + +class _ChangelogSheetState extends State { + final service = ChangelogService(); + late Future>> _future; + + @override + void initState() { + super.initState(); + _future = service.getChangelogs(); + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: _future, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Center( + child: ExpressiveLoadingIndicator( + activeSize: 38, + color: Theme.of(context).colorScheme.primary, + )); + } + if (snapshot.hasError) { + return Center(child: Text("Error loading changelog")); + } + + final releases = snapshot.data as List>; + if (releases.isEmpty) { + return const Center(child: Text("No changelogs available")); + } + + final buffer = StringBuffer(""); + for (final release in releases) { + buffer.writeln("# ${release['tag']}"); + buffer.writeln(release['body']); + buffer.writeln("\n---\n"); + } + + final colorTheme = Theme.of(context).colorScheme; + + return ListView.builder( + controller: widget.scrollController, + itemCount: releases.length, + itemBuilder: (context, index) { + final release = releases[index]; + return Container( + margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + padding: EdgeInsets.all(12), + decoration: BoxDecoration( + color: colorTheme.surfaceContainerLowest, + borderRadius: BorderRadius.circular(16), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 6), + Row(spacing: 2.7, children: [ + Container( + padding: const EdgeInsets.only( + left: 10, right: 10, bottom: 3, top: 3), + decoration: BoxDecoration( + color: colorTheme.primaryContainer, + borderRadius: BorderRadius.circular(50)), + child: Text( + release['tag'], + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: + Theme.of(context).colorScheme.onPrimaryContainer, + ), + ), + ), + if (index == 0) + Container( + padding: const EdgeInsets.only( + left: 10, right: 10, bottom: 3, top: 3), + decoration: BoxDecoration( + color: colorTheme.tertiary, + borderRadius: BorderRadius.circular(8)), + child: Text( + "Latest", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.onTertiary, + ), + ), + ), + ]), + SizedBox(height: 12), + MarkdownBody( + data: release['body'], + styleSheet: MarkdownStyleSheet.fromTheme(Theme.of(context)) + .copyWith( + blockquote: TextStyle( + color: colorTheme.onSurfaceVariant, + fontStyle: FontStyle.italic, + ), + blockquoteDecoration: BoxDecoration( + color: Colors.transparent, + border: Border( + left: BorderSide( + color: colorTheme.outline, width: 4)), + ), + ), + onTapLink: (text, href, title) { + if (href != null) openLink(href); + }, + ), + ], + ), + ); + }, + ); + }, + ); + } +} diff --git a/lib/screens/background_updates.dart b/lib/screens/background_updates.dart index 02a24c626..7e4eed597 100644 --- a/lib/screens/background_updates.dart +++ b/lib/screens/background_updates.dart @@ -40,7 +40,7 @@ class _BackgroundUpdatesPageState extends State { } final optionsInterval = { - 30: "30 ${"minutes".tr()}", + 15: "30 ${"minutes".tr()}", 60: "1 ${"hours".tr()}", 90: "1.5 ${"hours".tr()}", 120: "2 ${"hours".tr()}", @@ -151,8 +151,7 @@ class _BackgroundUpdatesPageState extends State { title: BatteryOptWidget(), // 0% ), SettingSwitchTile( - title: Text( - "Show a snack message when a new version is released"), + title: Text("new_version_snack_message".tr()), toggled: showNewVerNotification, onChanged: (value) { PreferencesHelper.setBool( diff --git a/lib/screens/daily_forecast.dart b/lib/screens/daily_forecast.dart index 93eaf91ce..2f11fe0b5 100644 --- a/lib/screens/daily_forecast.dart +++ b/lib/screens/daily_forecast.dart @@ -958,7 +958,6 @@ class ConditionsWidgetsForecast extends StatelessWidget { crossAxisCount: 2, physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, - padding: EdgeInsets.only(top: 8.5), crossAxisSpacing: 12, mainAxisSpacing: 12, children: [ diff --git a/lib/screens/extended_widgets.dart b/lib/screens/extended_widgets.dart index 69e92afd0..67187db3c 100644 --- a/lib/screens/extended_widgets.dart +++ b/lib/screens/extended_widgets.dart @@ -95,47 +95,59 @@ class _ExtendWidgetState extends State { Widget build(BuildContext context) { final colorTheme = Theme.of(context).colorScheme; - if (_showLoader) { - return Scaffold( - body: Center( - child: ExpressiveLoadingIndicator( - color: colorTheme.primary, - activeSize: 48, - ), - )); - } + // if (_showLoader) { + // return Scaffold( + // body: Center( + // child: ExpressiveLoadingIndicator( + // color: colorTheme.primary, + // activeSize: 48, + // ), + // )); + // } return Scaffold( - body: CustomScrollView(slivers: [ - SliverAppBar.large( - titleSpacing: 0, - automaticallyImplyLeading: false, - flexibleSpace: FlexibleSpaceBar( - title: Row( - spacing: 5, - children: [Icon(iconData), Text(extendedTitle)], - ), - expandedTitleScale: 1.3, - titlePadding: EdgeInsets.all(16), - ), - backgroundColor: Theme.of(context).colorScheme.surface, - expandedHeight: 100, - scrolledUnderElevation: 1, - actions: [ - IconButton( - onPressed: () { - Navigator.pop(context); - }, - icon: Icon( - Symbols.close, - weight: 600, - )), - SizedBox(width: 5) - ], - ), - SliverToBoxAdapter( - child: child, - ) - ])); + body: AnimatedSwitcher( + duration: const Duration(milliseconds: 500), + switchInCurve: Curves.easeIn, + switchOutCurve: Curves.easeOut, + child: _showLoader + ? Center( + key: const ValueKey('loader'), + child: ExpressiveLoadingIndicator( + color: colorTheme.primary, + activeSize: 48, + ), + ) + : CustomScrollView(key: const ValueKey('content'), slivers: [ + SliverAppBar.large( + titleSpacing: 0, + automaticallyImplyLeading: false, + flexibleSpace: FlexibleSpaceBar( + title: Row( + spacing: 5, + children: [Icon(iconData), Text(extendedTitle)], + ), + expandedTitleScale: 1.3, + titlePadding: EdgeInsets.all(16), + ), + backgroundColor: Theme.of(context).colorScheme.surface, + expandedHeight: 100, + scrolledUnderElevation: 1, + actions: [ + IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: Icon( + Symbols.close, + weight: 600, + )), + SizedBox(width: 5) + ], + ), + SliverToBoxAdapter( + child: child, + ) + ]))); } Widget buildHumidityExtended() { diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 971cd6206..1e9bd9c2f 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -123,7 +123,7 @@ class _WeatherHomeState extends State { bool showAlertsPref = PreferencesHelper.getBool("showAlerts") ?? true; bool widgetsUpdated = false; bool? iscurrentDay = false; - + bool? _cachedIsShowFrog; bool? lastIsDay; final WeatherFroggyManager _weatherManager = WeatherFroggyManager(); @@ -132,6 +132,9 @@ class _WeatherHomeState extends State { bool _isLoadingFroggy = true; bool layoutCreated = false; + bool isFirstAppBuild = true; + bool onLoadForceCall = false; + double? lat; double? lon; @@ -251,20 +254,30 @@ class _WeatherHomeState extends State { isHomeLocation = false; } - final hasInternet = await hasRealInternet(); + final hasInternet = await hasNetworkConnection(); if (!hasInternet) { - _isAppFullyLoaded = true; - SnackUtil.showSnackBar( - context: context, message: "network_unavailable".tr()); + if (!_istriggeredFromLocations) { + _isAppFullyLoaded = true; + } else {} + + if (isFirstAppBuild) { + SnackUtil.showSnackBar( + context: context, message: "network_unavailable".tr()); + isFirstAppBuild = false; + } } else if (lastUpdated != null) { final lastUpdateTime = DateTime.tryParse(lastUpdated); final now = DateTime.now(); if (lastUpdateTime != null && now.difference(lastUpdateTime).inMinutes < 450) { - _isAppFullyLoaded = true; + if (!_istriggeredFromLocations) { + _isAppFullyLoaded = true; + } + isFirstAppBuild = false; } else { checkAndUpdateHomeLocation(); + isFirstAppBuild = false; } } return json.decode(cached); @@ -306,7 +319,7 @@ class _WeatherHomeState extends State { } Future _refreshWeatherData() async { - final hasInternet = await hasRealInternet(); + final hasInternet = await hasNetworkConnection(); if (isViewLocation) { if (!mounted) return; @@ -353,8 +366,24 @@ class _WeatherHomeState extends State { } final weatherService = WeatherService(); - final result = await weatherService.fetchWeather(lat!, lon!, - locationName: cacheKey, context: context); + Map? result; + try { + result = await weatherService.fetchWeather(lat!, lon!, + locationName: cacheKey, context: context); + } catch (e) { + setState(() { + _isAppFullyLoaded = true; + }); + + if (context != null) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('data_fetch_error'.tr()), + duration: Duration(seconds: 5), + ), + ); + } + } if (result == null) { return; @@ -460,9 +489,27 @@ class _WeatherHomeState extends State { await saveLocation(saved); final weatherService = WeatherService(); - await weatherService.fetchWeather(currentLat, currentLon, - locationName: currentCacheKey, context: context); + try { + await weatherService.fetchWeather( + currentLat, + currentLon, + locationName: currentCacheKey, + context: context, + ); + } catch (e) { + setState(() { + _isAppFullyLoaded = true; + }); + if (context != null) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('data_fetch_error'.tr()), + duration: Duration(seconds: 5), + ), + ); + } + } setState(() { _isAppFullyLoaded = false; _istriggeredFromLocations = true; @@ -657,14 +704,14 @@ class _WeatherHomeState extends State { opacity: val, child: RepaintBoundary( child: Container( - padding: const EdgeInsets.all(6), + padding: const EdgeInsets.all(2), decoration: BoxDecoration( color: colorTheme.primaryContainer, borderRadius: BorderRadius.circular(50), ), child: ExpressiveLoadingIndicator( color: colorTheme.primary, - activeSize: 48, + activeSize: 40, ), ), ), @@ -748,7 +795,13 @@ class _WeatherHomeState extends State { // cloudy isLight ? paletteWeather.secondary.get(98) - : paletteWeather.secondary.get(useDarkerBackground ? 2 : 8), + : paletteWeather.secondary.get(useDarkerBackground + ? 2 + : !isShowFrog + ? iscurrentDay! + ? 8 + : 3 + : 8), // overcast isLight @@ -845,10 +898,24 @@ class _WeatherHomeState extends State { daily['precipitation_probability_max']; final List dailyWeatherCodes = daily['weather_code']; - void maybeUpdateWeatherAnimation(Map current) { + void maybeUpdateWeatherAnimation(Map current, + {isForce = false}) { final int weatherCode = current['weather_code']; final int isDay = current['is_day']; + if (isForce) { + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + weatherAnimationWidget = + WeatherConditionAnimationMapper.build( + weatherCode: weatherCode, + isDay: isDay, + context: context, + setFullDisplay: !isShowFrog); + }); + }); + } + if (_cachedWeatherCode != weatherCode || _cachedIsDay != isDay) { weatherAnimationWidget = WeatherConditionAnimationMapper.build( weatherCode: weatherCode, @@ -858,9 +925,22 @@ class _WeatherHomeState extends State { _cachedWeatherCode = weatherCode; _cachedIsDay = isDay; + _cachedIsShowFrog = isShowFrog; + onLoadForceCall = false; } } + if (onLoadForceCall) { + if (_cachedIsShowFrog != isShowFrog) { + maybeUpdateWeatherAnimation(current, isForce: true); + print('called'); + + _cachedIsShowFrog = isShowFrog; + } + } else { + onLoadForceCall = true; + } + final Map daylightMap = { for (int i = 0; i < dailyDates.length; i++) dailyDates[i]: ( @@ -1340,18 +1420,32 @@ class _WeatherHomeState extends State { await Future.delayed(Duration(milliseconds: 300)); if (result != null) { if (result['viewLocaton'] == true) { + Map? result; + final weatherService = WeatherService(); - final result = - await weatherService.fetchWeather( - PreferencesHelper.getJson( - 'selectedViewLocation')?['lat'], - PreferencesHelper.getJson( - 'selectedViewLocation')?['lon'], - locationName: - "${PreferencesHelper.getJson('selectedViewLocation')?['city']}, ${PreferencesHelper.getJson('selectedViewLocation')?['country']}", - context: context, - isOnlyView: true, - ); + try { + result = await weatherService.fetchWeather( + lat!, lon!, + locationName: cacheKey, + context: context); + } catch (e) { + result = null; + setState(() { + _isAppFullyLoaded = true; + }); + + if (context != null) { + ScaffoldMessenger.of(context) + .showSnackBar( + SnackBar( + content: + Text('data_fetch_error'.tr()), + duration: Duration(seconds: 5), + ), + ); + } + } + if (result == null) { } else { setState(() { @@ -1429,7 +1523,7 @@ class _WeatherHomeState extends State { currentLastUpdated: formattedTime, ), WeatherFrogIconWidget(iconUrl: _iconUrlFroggy), - const SizedBox(height: 13.8), + const SizedBox(height: 14), SizedBox( width: isFoldableLayout(context) ? 500 : null, height: null, diff --git a/lib/screens/languages_page.dart b/lib/screens/languages_page.dart index 7dfb36495..8f2ab4e6c 100644 --- a/lib/screens/languages_page.dart +++ b/lib/screens/languages_page.dart @@ -161,7 +161,7 @@ class TranslationProgressService { final response = await http.get( Uri.parse( - 'https://api.crowdin.com/api/v2/projects/$projectId/languages/progress?limit=31&offset=0'), + 'https://api.crowdin.com/api/v2/projects/$projectId/languages/progress?limit=32&offset=0'), headers: { 'Authorization': 'Bearer $apiToken', 'Content-Type': 'application/json', @@ -293,6 +293,9 @@ class _LanguageTileState extends State { title: Text( widget.languageName['native']!, style: TextStyle( + fontFamily: widget.languageName['native'] == "English" + ? 'FlexFontEn' + : 'DefaultFont', color: _isSelected ? Theme.of(context).colorScheme.onPrimaryContainer : Theme.of(context).colorScheme.onSurface), @@ -419,6 +422,9 @@ Map getLanguageNames(Locale locale) { if (lang == 'ca' && country == 'ES') { return {'native': 'Català', 'english': 'Catalan'}; } + if (lang == 'bg' && country == 'BG') { + return {'native': 'Български', 'english': 'Bulgarian'}; + } if (lang == 'de' && country == 'DE') { return {'native': 'Deutsch', 'english': 'German'}; } @@ -482,10 +488,10 @@ Map getLanguageNames(Locale locale) { if (lang == 'sl' && country == 'SI') { return {'native': 'Slovenščina', 'english': 'Slovenian'}; } - if (lang == 'sr' && country == 'CS') { + if (lang == 'sr' && country == 'SP') { return {'native': 'Српски (Ћирилица)', 'english': 'Serbian (Cyrillic)'}; } - if (lang == 'sr' && country == 'SP') { + if (lang == 'sr' && country == 'CS') { return {'native': 'Српски', 'english': 'Serbian'}; } if (lang == 'sv' && country == 'SE') { @@ -554,7 +560,8 @@ String getLanguageCodeCrodwin(Locale locale) { 'tr', // Turkish 'uk', // Ukrainian 'vi', // Vietnamese - 'ca' + 'ca', + 'bg' ].contains(lang)) { return lang; } diff --git a/lib/screens/locations.dart b/lib/screens/locations.dart index 9b3104da7..520eaca50 100644 --- a/lib/screens/locations.dart +++ b/lib/screens/locations.dart @@ -14,6 +14,7 @@ import '../utils/condition_label_map.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart'; import 'package:animations/animations.dart'; import '../widgets/dialog.dart'; +import 'package:expressive_loading_indicator/expressive_loading_indicator.dart'; class LocationsScreen extends StatefulWidget { const LocationsScreen({super.key}); @@ -28,12 +29,21 @@ final GlobalKey _scaffoldMessengerKey = class _LocationsScreenState extends State { List savedLocations = []; bool _isFirstBuild = true; + bool _showLoader = true; @override void initState() { super.initState(); loadSavedLocations(); + + Future.delayed(const Duration(milliseconds: 300), () { + if (mounted) { + setState(() { + _showLoader = false; + }); + } + }); } Future loadSavedLocations() async { @@ -159,9 +169,13 @@ class _LocationsScreenState extends State { ), ); }, - child: isEditing - ? buildReorderableListView(key: ValueKey('reorderable')) - : buildDismissibleListView(key: ValueKey('dismissible')), + child: _showLoader + ? Center( + key: const ValueKey('loader'), + ) + : isEditing + ? buildReorderableListView(key: ValueKey('reorderable')) + : buildDismissibleListView(key: ValueKey('dismissible')), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, @@ -903,7 +917,7 @@ class _FadeInListItemState extends State { Widget build(BuildContext context) { return AnimatedOpacity( opacity: opacity, - duration: const Duration(milliseconds: 700), + duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, child: widget.child, ); diff --git a/lib/screens/searchlocations.dart b/lib/screens/searchlocations.dart index 8bb3ebb9a..9399cab7d 100644 --- a/lib/screens/searchlocations.dart +++ b/lib/screens/searchlocations.dart @@ -5,7 +5,6 @@ import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import '../models/saved_location.dart'; import '../services/fetch_data.dart'; -import '../utils/condition_label_map.dart'; import 'package:expressive_loading_indicator/expressive_loading_indicator.dart'; enum GeoProvider { nominatim, geonames, openMeteo } @@ -75,7 +74,7 @@ class _SearchLocationsScreenState extends State { Future loadSavedProvider() async { final prefs = await SharedPreferences.getInstance(); - final index = prefs.getInt('geo_provider_index') ?? 0; + final index = prefs.getInt('geo_provider_index') ?? 1; setState(() { selectedProvider = GeoProvider.values[index]; }); @@ -87,6 +86,7 @@ class _SearchLocationsScreenState extends State { } Future searchLocation(String input) async { + input = input.trim(); if (input.isEmpty) return; setState(() { @@ -172,51 +172,103 @@ class _SearchLocationsScreenState extends State { setState(() => isLoading = false); } - void openProviderDialog() async { + void openProviderSheet() async { GeoProvider tempProvider = selectedProvider; + final colorTheme = Theme.of(context).colorScheme; - final confirmed = await showDialog( + final confirmed = await showModalBottomSheet( context: context, + showDragHandle: true, + isScrollControlled: true, + backgroundColor: colorTheme.surfaceContainerLow, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(28)), + ), builder: (_) { - return AlertDialog( - title: Text("search_provider".tr()), - contentPadding: - EdgeInsets.only(left: 0, right: 0, top: 16, bottom: 5), - content: StatefulBuilder( + return Padding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).padding.bottom + 10), + child: StatefulBuilder( builder: (context, setState) { return Column( mainAxisSize: MainAxisSize.min, - children: GeoProvider.values.map((provider) { - return RadioListTile( - dense: true, - title: Text( - providerLabels[provider]!, - style: TextStyle(fontSize: 15), + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 18), + child: Text( + "search_provider".tr(), + style: TextStyle(fontSize: 22), ), - value: provider, - groupValue: tempProvider, - onChanged: (val) => setState(() => tempProvider = val!), - ); - }).toList(), + ), + + SizedBox(height: 15), + ...GeoProvider.values.asMap().entries.map((entry) { + final index = entry.key; + final provider = entry.value; + final isFirst = index == 0; + final isLast = index == GeoProvider.values.length - 1; + final isSelected = tempProvider == provider; + return Padding( + padding: + const EdgeInsets.only(left: 18, right: 18, bottom: 2), + child: ListTile( + shape: RoundedRectangleBorder( + borderRadius: isSelected + ? BorderRadiusGeometry.circular(50) + : BorderRadius.only( + topRight: + Radius.circular(isFirst ? 18 : 2.6), + topLeft: + Radius.circular(isFirst ? 18 : 2.6), + bottomLeft: + Radius.circular(isLast ? 18 : 2.6), + bottomRight: + Radius.circular(isLast ? 18 : 2.6))), + tileColor: colorTheme.surfaceContainerLowest, + dense: true, + selected: isSelected, + selectedTileColor: colorTheme.primaryContainer, + title: Text( + providerLabels[provider]!, + style: TextStyle( + fontSize: 15, + color: isSelected + ? colorTheme.onPrimaryContainer + : null, + ), + ), + onTap: () => setState(() => tempProvider = provider), + ), + ); + }).toList(), + SizedBox(height: 13), + // Divider(), + // SizedBox(height: 4), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 18), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + OutlinedButton( + onPressed: () => Navigator.pop(context, false), + child: Text( + 'cancel'.tr(), + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.w600), + )), + FilledButton( + onPressed: () => Navigator.pop(context, true), + child: Text( + 'save'.tr(), + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.w600), + )), + ], + )) + ], ); }, ), - actions: [ - TextButton( - child: Text( - "cancel".tr(), - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - onPressed: () => Navigator.pop(context, false), - ), - TextButton( - child: Text( - "save".tr(), - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - onPressed: () => Navigator.pop(context, true), - ), - ], ); }, ); @@ -251,7 +303,7 @@ class _SearchLocationsScreenState extends State { title: TextField( style: TextStyle(fontSize: 16, color: colorTheme.onSurface), onChanged: (value) => query = value, - onSubmitted: searchLocation, + onSubmitted: (value) => searchLocation(value.trim()), decoration: InputDecoration( border: InputBorder.none, focusedBorder: InputBorder.none, @@ -339,7 +391,6 @@ class _SearchLocationsScreenState extends State { color: colorTheme.primary, )), ); - final location = results[index]; final lat = double.tryParse( location['lat'] ?? '') ?? @@ -354,17 +405,33 @@ class _SearchLocationsScreenState extends State { city: location['city'] ?? '', country: location['country'] ?? '', ); - - saveLocation(saved); final cacheKey = "${saved.city}_${saved.country}" .toLowerCase() .replaceAll(' ', '_'); final weatherService = WeatherService(); - await weatherService.fetchWeather( - lat, lon, - locationName: cacheKey, - context: context); + try { + await weatherService.fetchWeather( + lat, lon, + locationName: cacheKey, + context: context); + } catch (e) { + Navigator.pop(context); + + if (context != null) { + ScaffoldMessenger.of(context) + .showSnackBar( + SnackBar( + content: + Text('data_fetch_error'.tr()), + duration: Duration(seconds: 5), + ), + ); + } + return; + } + + saveLocation(saved); final prefs = await SharedPreferences.getInstance(); @@ -455,13 +522,30 @@ class _SearchLocationsScreenState extends State { )), ); - saveLocation(saved); final cacheKey = "${saved.city}_${saved.country}" .toLowerCase() .replaceAll(' ', '_'); final weatherService = WeatherService(); - await weatherService.fetchWeather(lat, lon, - locationName: cacheKey, context: context); + try { + await weatherService.fetchWeather(lat, lon, + locationName: cacheKey, context: context); + } catch (e) { + if (context != null) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('data_fetch_error'.tr()), + duration: Duration(seconds: 5), + ), + ); + } + return; + } + + saveLocation(saved); + + // final weatherService = WeatherService(); + // await weatherService.fetchWeather(lat, lon, + // locationName: cacheKey, context: context); final prefs = await SharedPreferences.getInstance(); final jsonString = @@ -541,7 +625,7 @@ class _SearchLocationsScreenState extends State { ], ), FloatingActionButton( - onPressed: openProviderDialog, + onPressed: openProviderSheet, child: Icon(Icons.tune), ) ], diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index 14c276cc2..ac0ed2d8a 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -214,7 +214,8 @@ class _SettingsScreenState extends State { isLight ? Color(0xffe6deff) : Color(0xff493e76), isLight ? Color(0xff493e76) : Color(0xffe6deff)), title: Text('${"about".tr()} WeatherMaster'), - description: Text('learn_about_app'.tr()), + description: + Text('Changelog, Version, License, and More'), onTap: () { Navigator.of( context, diff --git a/lib/services/fetch_data.dart b/lib/services/fetch_data.dart index 0e55912f5..ce050eb47 100644 --- a/lib/services/fetch_data.dart +++ b/lib/services/fetch_data.dart @@ -59,117 +59,130 @@ class WeatherService { 'https://api.weatherapi.com/v1/astronomy.json?key=${dotenv.env['API_KEY_WEATHERAPI']!.toString()}&q=$lat,$lon'); // Prepare list of HTTP requests - final requests = >[ - http.get(uri), - http.get(airQualityUri), - http.get(astronomyUri), - ]; + try { + final requests = >[ + http.get(uri), + http.get(airQualityUri), + http.get(astronomyUri), + ]; - final responses = await Future.wait(requests); + final responses = await Future.wait(requests); - // Parse responses - final weatherData = json.decode(responses[0].body) as Map; - final airQualityData = - json.decode(responses[1].body) as Map; - final astronomyData = - json.decode(responses[2].body) as Map; + for (var response in responses) { + if (response.statusCode < 200 || response.statusCode >= 300) { + throw Exception( + 'HTTP request failed with status: ${response.statusCode}'); + } + } + // Parse responses + final weatherData = + json.decode(responses[0].body) as Map; + final airQualityData = + json.decode(responses[1].body) as Map; + final astronomyData = + json.decode(responses[2].body) as Map; - // Check if we need fallback data for missing fields - Map finalWeatherData = weatherData; - if (selectedModel != "best_match" && _hasIncompleteData(weatherData)) { - finalWeatherData = await _fetchWithFallback( - lat, lon, timezone, weatherData, selectedModel); - } - - finalWeatherData['current'] = sanitizeCurrent(finalWeatherData['current']); - finalWeatherData['hourly'] = sanitizeHourly(finalWeatherData['hourly']); - finalWeatherData['daily'] = sanitizeDaily(finalWeatherData['daily']); - - 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( - duration: Duration(seconds: 10), - content: Text("$reason. Please change your model"), - action: SnackBarAction( - label: 'Change model', - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const MeteoModelsPage()), - ); - }, - ), - ), - ); + // Check if we need fallback data for missing fields + Map finalWeatherData = weatherData; + if (selectedModel != "best_match" && _hasIncompleteData(weatherData)) { + finalWeatherData = await _fetchWithFallback( + lat, lon, timezone, weatherData, selectedModel); } - return null; - } + finalWeatherData['current'] = + sanitizeCurrent(finalWeatherData['current']); + finalWeatherData['hourly'] = sanitizeHourly(finalWeatherData['hourly']); + finalWeatherData['daily'] = sanitizeDaily(finalWeatherData['daily']); - final combinedDataForView = { - ...finalWeatherData, - 'air_quality': airQualityData, - 'astronomy': astronomyData, - }; + 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( + duration: Duration(seconds: 10), + content: Text("$reason. Please change your model"), + action: SnackBarAction( + label: 'Change model', + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const MeteoModelsPage()), + ); + }, + ), + ), + ); + } - final nowForView = DateTime.now().toIso8601String(); + return null; + } - if (isOnlyView) { - log("Only viewing data for $key. Not saving to cache."); - return { - 'data': combinedDataForView, - 'last_updated': nowForView, - 'from_cache': false, + final combinedDataForView = { + ...finalWeatherData, + 'air_quality': airQualityData, + 'astronomy': astronomyData, }; - } - final existingJson = box.get(key); - if (existingJson != null) { - final cachedMap = json.decode(existingJson); - final cachedData = cachedMap['data']; - final lastUpdated = cachedMap['last_updated']; + final nowForView = DateTime.now().toIso8601String(); - if (json.encode(cachedData['current']) == - json.encode(finalWeatherData['current']) && - json.encode(cachedData['air_quality'] ?? {}) == - json.encode(airQualityData) && - json.encode(cachedData['astronomy'] ?? {}) == - json.encode(astronomyData)) { - log("Hive: No update needed for $key"); + if (isOnlyView) { + log("Only viewing data for $key. Not saving to cache."); return { - 'data': cachedData, - 'last_updated': lastUpdated, - 'from_cache': true, + 'data': combinedDataForView, + 'last_updated': nowForView, + 'from_cache': false, }; } + + final existingJson = box.get(key); + if (existingJson != null) { + final cachedMap = json.decode(existingJson); + final cachedData = cachedMap['data']; + final lastUpdated = cachedMap['last_updated']; + + if (json.encode(cachedData['current']) == + json.encode(finalWeatherData['current']) && + json.encode(cachedData['air_quality'] ?? {}) == + json.encode(airQualityData) && + json.encode(cachedData['astronomy'] ?? {}) == + json.encode(astronomyData)) { + log("Hive: No update needed for $key"); + return { + 'data': cachedData, + 'last_updated': lastUpdated, + 'from_cache': true, + }; + } + } + + final now = DateTime.now().toIso8601String(); + final combinedData = { + ...finalWeatherData, + 'air_quality': airQualityData, + 'astronomy': astronomyData, + }; + + final wrappedData = { + 'data': combinedData, + 'last_updated': now, + }; + + await box.put(key, json.encode(wrappedData)); + log("Hive: Updated cache for $key at $now"); + + return { + 'data': combinedData, + 'last_updated': now, + 'from_cache': false, + }; + } catch (e) { + // This will propagate the error to the caller + throw Exception('WeatherService.fetchWeather failed: $e'); } - - final now = DateTime.now().toIso8601String(); - final combinedData = { - ...finalWeatherData, - 'air_quality': airQualityData, - 'astronomy': astronomyData, - }; - - final wrappedData = { - 'data': combinedData, - 'last_updated': now, - }; - - await box.put(key, json.encode(wrappedData)); - log("Hive: Updated cache for $key at $now"); - - return { - 'data': combinedData, - 'last_updated': now, - 'from_cache': false, - }; } /// Check if weather data has missing or incomplete fields diff --git a/lib/utils/bottom_provider.dart b/lib/utils/bottom_provider.dart index 18fb3f7fe..2c60cce35 100644 --- a/lib/utils/bottom_provider.dart +++ b/lib/utils/bottom_provider.dart @@ -1,3 +1,4 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'open_links.dart'; import '../utils/condition_label_map.dart'; @@ -8,7 +9,7 @@ Widget homeBottomBar(BuildContext context, bool isLight) { color: textColor, fontSize: 18, decoration: TextDecoration.underline, - decorationThickness: 3, + decorationThickness: context.locale.languageCode == "en" ? 2 : 3, ); return RepaintBoundary( diff --git a/lib/utils/froggy_map.dart b/lib/utils/froggy_map.dart index 10a0b3155..8126f25f9 100644 --- a/lib/utils/froggy_map.dart +++ b/lib/utils/froggy_map.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'is_online.dart'; +import 'dart:io'; class WeatherFroggyManager { List sunnyFrog = []; @@ -14,103 +15,100 @@ class WeatherFroggyManager { List clearNightFrog = []; List partlyCloudyNightFrog = []; - -Future initializeIcons() async { - final online = await hasRealInternet(); - if (online) { - _setOnlineIcons(); - - } else { - _setOfflineIcons(); - } - - Connectivity().onConnectivityChanged.listen((event) async { - if (await hasRealInternet()) { + Future initializeIcons() async { + const testUrl = + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/01-sunny/01-sunny-creek-swimming.png?ref_type=heads"; + final online = await urlIsReachable(testUrl); + if (online) { _setOnlineIcons(); } else { _setOfflineIcons(); } - }); -} + Connectivity().onConnectivityChanged.listen((event) async { + if (await hasNetworkConnection() && await urlIsReachable(testUrl)) { + _setOnlineIcons(); + } else { + _setOfflineIcons(); + } + }); + } void _setOnlineIcons() { sunnyFrog = [ - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/01-sunny/01-sunny-creek-swimming.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/01-sunny/01-sunny-home-laundry_c.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/01-sunny/01-sunny-orchard-picking.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/01-sunny/01-sunny-home-laundry_f.png?ref_type=heads" + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/01-sunny/01-sunny-creek-swimming.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/01-sunny/01-sunny-home-laundry_c.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/01-sunny/01-sunny-orchard-picking.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/01-sunny/01-sunny-home-laundry_f.png?ref_type=heads" ]; mostlySunnyFrog = [ - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/02-mostly-sunny/02-mostly-sunny-citypark-picnic.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/02-mostly-sunny/02-mostly-sunny-beach-sunscreen.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/02-mostly-sunny/02-mostly-sunny-home-laundry.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/02-mostly-sunny/02-mostly-sunny-beach-sandcastle.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/02-mostly-sunny/02-mostly-sunny-rooftop-pinacolada.png?ref_type=heads" + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/02-mostly-sunny/02-mostly-sunny-citypark-picnic.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/02-mostly-sunny/02-mostly-sunny-beach-sunscreen.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/02-mostly-sunny/02-mostly-sunny-home-laundry.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/02-mostly-sunny/02-mostly-sunny-beach-sandcastle.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/02-mostly-sunny/02-mostly-sunny-rooftop-pinacolada.png?ref_type=heads" ]; partlyCloudyFrog = [ - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/03-partly-cloudy-day/03-partly-cloudy-day-field-hiking_f.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/03-partly-cloudy-day/03-partly-cloudy-day-home-flowers.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/03-partly-cloudy-day/03-partly-cloudy-day-creek-feet.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/03-partly-cloudy-day/03-partly-cloudy-day-field-biking_c.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/03-partly-cloudy-day/03-partly-cloudy-day-citypark-ukelele.png?ref_type=heads" + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/03-partly-cloudy-day/03-partly-cloudy-day-field-hiking_f.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/03-partly-cloudy-day/03-partly-cloudy-day-home-flowers.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/03-partly-cloudy-day/03-partly-cloudy-day-creek-feet.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/03-partly-cloudy-day/03-partly-cloudy-day-field-biking_c.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/03-partly-cloudy-day/03-partly-cloudy-day-citypark-ukelele.png?ref_type=heads" ]; overcastFrog = [ - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/09-cloudy/09-cloudy-home-flowers.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/09-cloudy/09-cloudy-orchard-watching.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/04-mostly-cloudy-day/04-mostly-cloudy-day-home-flowers.png?ref_type=heads" + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/09-cloudy/09-cloudy-home-flowers.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/09-cloudy/09-cloudy-orchard-watching.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/04-mostly-cloudy-day/04-mostly-cloudy-day-home-flowers.png?ref_type=heads" ]; fogFrog = [ - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/26-haze-fog-dust-smoke/26-haze-fog-dust-smoke-bridge.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/26-haze-fog-dust-smoke/26-haze-fog-dust-smoke-fruit-stand.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/26-haze-fog-dust-smoke/26-haze-fog-dust-smoke-mountain.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/26-haze-fog-dust-smoke/26-haze-fog-dust-smoke-pier.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/26-haze-fog-dust-smoke/26-haze-fog-dust-smoke-field-lantern.png?ref_type=heads" + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/26-haze-fog-dust-smoke/26-haze-fog-dust-smoke-bridge.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/26-haze-fog-dust-smoke/26-haze-fog-dust-smoke-fruit-stand.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/26-haze-fog-dust-smoke/26-haze-fog-dust-smoke-mountain.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/26-haze-fog-dust-smoke/26-haze-fog-dust-smoke-pier.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/26-haze-fog-dust-smoke/26-haze-fog-dust-smoke-field-lantern.png?ref_type=heads" ]; rainFrog = [ - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/11-rain/11-rain-creek-leaf.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/11-rain/11-rain-home-inside.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/04-mostly-cloudy-day/04-mostly-cloudy-day-orchard-treeswing_f.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/12-heavy-rain/12-heavy-rain-busstop-umbrella.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/12-heavy-rain/12-heavy-rain-cafe-sitting-singing.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/11-rain/11-shower-rain-field-leaf.png?ref_type=heads" + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/11-rain/11-rain-creek-leaf.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/11-rain/11-rain-home-inside.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/04-mostly-cloudy-day/04-mostly-cloudy-day-orchard-treeswing_f.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/12-heavy-rain/12-heavy-rain-busstop-umbrella.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/12-heavy-rain/12-heavy-rain-cafe-sitting-singing.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/11-rain/11-shower-rain-field-leaf.png?ref_type=heads" ]; snowFrog = [ - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/15-snow-showers-snow/15-snow-showers-snow-citypark-snowman.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/15-snow-showers-snow/15-snow-showers-snow-home-shoveling.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/15-snow-showers-snow/15-snow-showers-snow-creek-iceskating.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/17-heavy-snow-blizzard/17-heavy-snow-blizzard-home-inside.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/16-blowing-snow/16-blowing-snow-field-snowman.png?ref_type=heads" + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/15-snow-showers-snow/15-snow-showers-snow-citypark-snowman.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/15-snow-showers-snow/15-snow-showers-snow-home-shoveling.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/15-snow-showers-snow/15-snow-showers-snow-creek-iceskating.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/17-heavy-snow-blizzard/17-heavy-snow-blizzard-home-inside.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/16-blowing-snow/16-blowing-snow-field-snowman.png?ref_type=heads" ]; thunderStormFrog = [ - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/22-iso-thunderstorms/22-iso-thunderstorms-home-inside.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/22-iso-thunderstorms/22-iso-thunderstorms-cafe-looking-outside.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/22-iso-thunderstorms/22-iso-thunderstorms-busstop-newspaper.png?ref_type=heads" + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/22-iso-thunderstorms/22-iso-thunderstorms-home-inside.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/22-iso-thunderstorms/22-iso-thunderstorms-cafe-looking-outside.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/22-iso-thunderstorms/22-iso-thunderstorms-busstop-newspaper.png?ref_type=heads" ]; clearNightFrog = [ - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/05-clear/05-clear-creek-stars.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/05-clear/05-clear-field-lanterns.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/05-clear/05-clear-orchard-fireflies.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/05-clear/05-clear-home-lounging.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/05-clear/05-clear-hills-telescope.png?ref_type=heads" + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/05-clear/05-clear-creek-stars.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/05-clear/05-clear-field-lanterns.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/05-clear/05-clear-orchard-fireflies.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/05-clear/05-clear-home-lounging.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/05-clear/05-clear-hills-telescope.png?ref_type=heads" ]; partlyCloudyNightFrog = [ - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/07-partly-cloudy-night/07-partly-cloudy-night-creek-fireflies.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/07-partly-cloudy-night/07-partly-cloudy-night-field-fireflies.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/07-partly-cloudy-night/07-partly-cloudy-night-hills-smores.png?ref_type=heads", - "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/07-partly-cloudy-night/07-partly-cloudy-night-orchard-eating.png?ref_type=heads" + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/07-partly-cloudy-night/07-partly-cloudy-night-creek-fireflies.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/07-partly-cloudy-night/07-partly-cloudy-night-field-fireflies.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/07-partly-cloudy-night/07-partly-cloudy-night-hills-smores.png?ref_type=heads", + "https://gitlab.com/bignutty/google-weather-icons/-/raw/main/froggie/v2/mobile/07-partly-cloudy-night/07-partly-cloudy-night-orchard-eating.png?ref_type=heads" ]; - - } void _setOfflineIcons() { @@ -126,7 +124,7 @@ Future initializeIcons() async { partlyCloudyNightFrog = ['assets/froggie/02n.png']; } - final Random _random = Random(); + final Random _random = Random(); String getFroggieIcon(int iconCode, bool isDay) { if (isDay) { @@ -140,7 +138,8 @@ Future initializeIcons() async { return _randomIcon(overcastFrog); } else if ([45, 48].contains(iconCode)) { return _randomIcon(fogFrog); - } else if ([51, 53, 55, 56, 57, 61, 63, 65, 80, 81, 82].contains(iconCode)) { + } else if ([51, 53, 55, 56, 57, 61, 63, 65, 80, 81, 82] + .contains(iconCode)) { return _randomIcon(rainFrog); } else if ([66, 67, 71, 73, 75, 77, 85, 86].contains(iconCode)) { return _randomIcon(snowFrog); @@ -152,11 +151,12 @@ Future initializeIcons() async { return _randomIcon(clearNightFrog); } else if ([1, 2].contains(iconCode)) { return _randomIcon(partlyCloudyNightFrog); - } else if (iconCode == 3){ + } else if (iconCode == 3) { return _randomIcon(overcastFrog); } else if ([45, 48].contains(iconCode)) { return _randomIcon(fogFrog); - } else if ([51, 53, 55, 56, 57, 61, 63, 65, 80, 81, 82].contains(iconCode)) { + } else if ([51, 53, 55, 56, 57, 61, 63, 65, 80, 81, 82] + .contains(iconCode)) { return _randomIcon(rainFrog); } else if ([66, 67, 71, 73, 75, 77, 85, 86].contains(iconCode)) { return _randomIcon(snowFrog); @@ -173,3 +173,15 @@ Future initializeIcons() async { return list[_random.nextInt(list.length)]; } } + +Future urlIsReachable(String url, + {Duration timeout = const Duration(seconds: 5)}) async { + try { + final uri = Uri.parse(url); + final request = await HttpClient().headUrl(uri).timeout(timeout); + final response = await request.close(); + return response.statusCode >= 200 && response.statusCode < 400; + } catch (_) { + return false; + } +} diff --git a/lib/utils/is_online.dart b/lib/utils/is_online.dart index 0cc8e13b9..4aa281ed0 100644 --- a/lib/utils/is_online.dart +++ b/lib/utils/is_online.dart @@ -1,39 +1,14 @@ -import 'dart:io'; -import 'package:http/http.dart' as http; +import 'package:connectivity_plus/connectivity_plus.dart'; -// Checks for actual internet access -Future hasRealInternet() async { - final testUrls = [ - 'http://connect.rom.miui.com/generate_204', // MIUI - 'http://captive.apple.com', // Apple - 'http://example.com', // Lightweight - 'http://baidu.com', // China - 'http://clients3.google.com/generate_204', // Android - 'http://www.msftconnecttest.com/connecttest.txt', // Windows - 'http://www.gstatic.com/generate_204', // Google lightweight - 'https://example.com', // HTTPS fallback - ]; +Future hasNetworkConnection() async { + final result = await Connectivity().checkConnectivity(); - try { - final dnsResult = await InternetAddress.lookup('example.com') - .timeout(const Duration(seconds: 3)); - if (dnsResult.isEmpty || dnsResult[0].rawAddress.isEmpty) return false; - - for (final url in testUrls) { - try { - final response = - await http.get(Uri.parse(url)).timeout(const Duration(seconds: 3)); - if (response.statusCode == 204 || - response.statusCode == 200 || - response.statusCode == 302) { - return true; - } - } catch (_) { - // try next - } - } - return false; - } catch (_) { - return false; + if (result is List) { + final first = result.isNotEmpty ? result.first : ConnectivityResult.none; + return first == ConnectivityResult.mobile || + first == ConnectivityResult.wifi; + } else { + return result == ConnectivityResult.mobile || + result == ConnectivityResult.wifi; } } diff --git a/lib/widget_background.dart b/lib/widget_background.dart index ade39d987..9cb5ca8d0 100644 --- a/lib/widget_background.dart +++ b/lib/widget_background.dart @@ -3,9 +3,9 @@ import 'services/fetch_data.dart'; import 'utils/preferences_helper.dart'; import 'package:flutter/material.dart'; import 'package:home_widget/home_widget.dart'; +import 'utils/unit_converter.dart'; import 'package:path_provider/path_provider.dart'; import 'package:hive/hive.dart'; -import 'utils/unit_converter.dart'; import 'utils/condition_label_map.dart'; import 'package:flutter/services.dart' show rootBundle; @@ -14,9 +14,6 @@ Future updateHomeWidget(weather, {bool updatedFromHome = false}) async { try { WidgetsFlutterBinding.ensureInitialized(); - final dir = await getApplicationDocumentsDirectory(); - Hive.init(dir.path); - await PreferencesHelper.init(); await HomeWidget.setAppGroupId('com.pranshulgg.weather_master_app'); @@ -289,6 +286,8 @@ Future updateHomeWidget(weather, {bool updatedFromHome = false}) async { name: 'clockDateWidgetProvider', iOSName: null); await HomeWidget.updateWidget( name: 'DateCurrentWidgetProvider', iOSName: null); + await HomeWidget.updateWidget( + name: 'ClockHourlyWidgetProvider', iOSName: null); print('[WidgetUpdate] Called updateWidget'); } catch (e, stack) { diff --git a/lib/widgets/top_weather_card.dart b/lib/widgets/top_weather_card.dart index 69fc113ee..acce8d265 100644 --- a/lib/widgets/top_weather_card.dart +++ b/lib/widgets/top_weather_card.dart @@ -295,7 +295,7 @@ class AnimatedTemperature extends StatelessWidget { color: Theme.of(context).brightness == Brightness.light ? Theme.of(context).colorScheme.inverseSurface : Theme.of(context).colorScheme.primary, - fontSize: isShowFrog ? 60 : 130, + fontSize: isShowFrog ? 65 : 136, fontWeight: isShowFrog ? null : FontWeight.bold, height: isShowFrog ? 1.3 : 1, ), @@ -370,7 +370,7 @@ class _WeatherTopCardStateVertical extends State { final colorTheme = Theme.of(context).colorScheme; return Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 14), + padding: const EdgeInsets.fromLTRB(16, 16, 16, 12), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -392,6 +392,7 @@ class _WeatherTopCardStateVertical extends State { height: 6, ), Row( + spacing: 3, mainAxisAlignment: MainAxisAlignment.center, children: [ PreferencesHelper.getBool("useTempAnimation") == false @@ -401,13 +402,13 @@ class _WeatherTopCardStateVertical extends State { Brightness.light ? Theme.of(context).colorScheme.inverseSurface : Theme.of(context).colorScheme.primary, - fontSize: 130, + fontSize: 136, fontWeight: isShowFrog ? null : FontWeight.bold, height: 1.3)) : AnimatedTemperature( targetTemp: convertedTemp.toDouble()), Padding( - padding: const EdgeInsets.only(bottom: 40), + padding: const EdgeInsets.only(bottom: 50), child: SvgPicture.asset( WeatherIconMapper.getIcon( widget.currentWeatherIconCode, widget.currentisDay), @@ -418,7 +419,7 @@ class _WeatherTopCardStateVertical extends State { ], ), SizedBox( - height: 16, + height: 10, ), Text( "${'feels_like'.tr()} ${widget.currentFeelsLike == 0000 ? '--' : '$convertedfeelsLikeTemp°'}", diff --git a/settings_tiles_custom/example/android/.gradle/8.9/fileHashes/fileHashes.bin b/settings_tiles_custom/example/android/.gradle/8.9/fileHashes/fileHashes.bin index 03a21d82b0d50956ca570d3f34b6bfaa4b67da00..e64d5fa9df372191b53931172628da9f7fbce694 100644 GIT binary patch delta 1929 zcmYk5Z%ov60LHl`IWybXk4?P|$@RwCgS1hwpax>hpY`=lgtr-#<4L zbPNR@J-w@ESl+P_B&Da=5JYCW6Y=SZwg{Qg@#v^+M|`Lvgm=Sl;I^O=bKkZz;Yy?l z_F<=>8s`LiF=8MgBjxF6xGIjnnU!cLw~(J<*$sP;n&w1(MxveAql7C7o(&ehQQ`oG zGq~7(%+4enzzRVPwh0>0CioE748*TtxE{*{K#AZZGz%IqXfpo^>aaA6v+7VNsD)2( z5Cdl9f#7{CUd!+yxCI}e-i!p+a?gjgqbL0cY_{-BwqQ9LYd$bvAdoNb5xA2*Z2X_XS73;tw!5J)hmkpnyK+uT>1D6D6F=a*; zZD4pGT!LyG5}d|Yf-Z~`B9E~!&kjc(VrePiF#=_Tf3UK^iJ?6ECL({~cjX>oqA5e#Z<}em;HHcmETm|G*vb@ak#+#dqsM5 zd@~j!Gyg^VGySGgvFA2&#mlT*Cow=#BQeUh&{oDqF|^UXl}P{eb6$crkA(#u`&J^~ znd;k|Q{~~D8*KAST*nU{?(7aDb2l+^mm*E#3Ot(_`Nh=99x=9kjtPaF_#?Ytm(Z&3 z#flDz@6o3l88nqze#K_C^s{A~#3hP0iQo8P*J4F{5$6PuRK&0R)>Mw7N+VyhVNkg~ z^Js3FM{|pvgKK+2<4feJJzqRP6Hp^gl4#1gQW3 delta 1929 zcmY+DU2KzO9K~B%8SVpIx@4@$T!>LF2qT0TK9WTVL7A)FCyv6p(v^MD4dR7D7~7~L zAZ}xf<4g!}(LiFjFcX$t5jEAANz6j(B!QSf7Fs&M2~!uD%AoH#d(3>Ve&_k0=RE)C z!7FVM2TY!v+$9yU2UjiiqDu ziC_}#f_wPFz#TyXIi8}dlsRGJm)?beRwwE_PAegfH66xYky%D~fMNst1%DzU_ygkx9OX3sj`e~kXc7E{vw|6n38wMPz}gDVdW@jpR}2as zV$_Vx3Z}5ClIGvw6Ffq{8HrYM&yTgE#lwj1abjte)7s`!4LUk8UF*b~RXm6})KoET z7AFLAxGMM?Qw9pF>3NC@!M`Z1cHw-rb%*g;jA--;l7ffG-_8khC?zCbK!?DNA;BU{ zn3D57%bajvt6(t>7`P-z!!LqG$gZK;jyD80yl>zFA^r?EG?I?=9c*I~8wrUe2njNA zUXX$72JBuYzle1P8obtNCen3qnIB>E4kxa7t%FNs;hJpO_(zb1)jOGx4ZmP11_aCS zoq-usTDgn8CE+#DLr69GmEa{jA|wZ~qSi7efwg-HgNTL*pJB7#g;=e16UhPGm+w;<&^SrcE`|7DjBhbt}o>{BvH7NWh7g z1J^t# literal 17 VcmZRMz56`-dT#I<1~BmE1OPq61t$Oi diff --git a/settings_tiles_custom/example/android/.gradle/8.9/fileHashes/resourceHashesCache.bin b/settings_tiles_custom/example/android/.gradle/8.9/fileHashes/resourceHashesCache.bin index 664c10108ba1caad0d8b7a8f3429a5ef25df94b5..0108fd5a30c653751db7df99cd9d4da8cf53f5ef 100644 GIT binary patch delta 205 zcmbQfk#YHE#tkMCjLn-(B{CQVChvdVdCzE}1p^pF%1@pu*&wh``&d%ss-TAu!HB<; zd8KCZb9GO3J!fVMRhYbau2cbw!0)!ohg!1d{GcjtPiB?R5MW-%``_TU{T`^`^vS96 z4FaP6TD$yKhW~-;Z=HNs-auu`qxPvq4B!5N~A~5&!@I diff --git a/settings_tiles_custom/example/build/app/intermediates/cxx/create_cxx_tasks_352_timing.txt b/settings_tiles_custom/example/build/app/intermediates/cxx/create_cxx_tasks_352_timing.txt new file mode 100644 index 000000000..d72bb2b05 --- /dev/null +++ b/settings_tiles_custom/example/build/app/intermediates/cxx/create_cxx_tasks_352_timing.txt @@ -0,0 +1,16 @@ +# C/C++ build system timings +create_cxx_tasks + create-initial-cxx-model + create-module-model 11ms + [gap of 87ms] + create-initial-cxx-model completed in 98ms +create_cxx_tasks completed in 102ms + +# C/C++ build system timings +create_cxx_tasks + create-initial-cxx-model + create-variant-model 19ms + [gap of 65ms] + create-initial-cxx-model completed in 88ms +create_cxx_tasks completed in 90ms + diff --git a/settings_tiles_custom/example/build/app/intermediates/cxx/create_cxx_tasks_38_timing.txt b/settings_tiles_custom/example/build/app/intermediates/cxx/create_cxx_tasks_38_timing.txt index ed7f9d524..0a3668e8c 100644 --- a/settings_tiles_custom/example/build/app/intermediates/cxx/create_cxx_tasks_38_timing.txt +++ b/settings_tiles_custom/example/build/app/intermediates/cxx/create_cxx_tasks_38_timing.txt @@ -675,3 +675,70 @@ create_cxx_tasks create-initial-cxx-model 83ms create_cxx_tasks completed in 86ms +# C/C++ build system timings +create_cxx_tasks + create-initial-cxx-model + create-module-model 32ms + create-variant-model 13ms + create-ARMEABI_V7A-model 36ms + [gap of 76ms] + create-ARM64_V8A-model 12ms + [gap of 13ms] + create-initial-cxx-model completed in 186ms + [gap of 22ms] +create_cxx_tasks completed in 215ms + +# C/C++ build system timings +create_cxx_tasks + create-initial-cxx-model 86ms +create_cxx_tasks completed in 91ms + +# C/C++ build system timings +create_cxx_tasks + create-initial-cxx-model + create-module-model 32ms + create-variant-model 15ms + create-ARMEABI_V7A-model 43ms + [gap of 15ms] + create-X86_64-model 10ms + [gap of 24ms] + create-X86-model 13ms + [gap of 29ms] + create-ARM64_V8A-model 15ms + [gap of 10ms] + create-X86_64-model 13ms + create-initial-cxx-model completed in 228ms + [gap of 28ms] +create_cxx_tasks completed in 263ms + +# C/C++ build system timings +create_cxx_tasks + create-initial-cxx-model 111ms +create_cxx_tasks completed in 116ms + +# C/C++ build system timings +create_cxx_tasks + create-initial-cxx-model + create-module-model 39ms + create-variant-model 16ms + create-ARMEABI_V7A-model 44ms + [gap of 110ms] + create-initial-cxx-model completed in 215ms + [gap of 26ms] +create_cxx_tasks completed in 251ms + +# C/C++ build system timings +create_cxx_tasks + create-initial-cxx-model + create-module-model 13ms + [gap of 18ms] + create-ARM64_V8A-model 10ms + create-X86_64-model 10ms + [gap of 33ms] + create-X86-model 11ms + create-module-model 15ms + create-ARMEABI_V7A-model 10ms + create-X86-model 13ms + create-initial-cxx-model completed in 175ms +create_cxx_tasks completed in 182ms +