From df6bef4ba21268c40ec0da587cc28562f51f42ac Mon Sep 17 00:00:00 2001 From: dimosthenis <76966291+dimostheenis@users.noreply.github.com> Date: Mon, 3 Jun 2024 23:55:36 +0300 Subject: [PATCH 001/129] Greek: fixed tiny mistake & couple improvements Signed-off-by: dimosthenis <76966291+dimostheenis@users.noreply.github.com> --- lib/languages.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/languages.dart b/lib/languages.dart index 541d1e9..17f6112 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -100,7 +100,7 @@ Map> mainTranslate = { '感觉像', '感じる', 'Odczuwalna', - 'Αισθάνεται' + 'Αισθητή' ], 'Donate': [ 'Donate', @@ -114,7 +114,7 @@ Map> mainTranslate = { '捐赠', '寄付', 'Wesprzyj', - 'Κάντε Δωρεά' + 'Κάντε δωρεά' ], 'About': [ 'About', @@ -170,7 +170,7 @@ Map> mainTranslate = { '明天', '明日', 'Jutro', - 'Άυριο' + 'Αύριο' ], 'Overmorrow': [ 'Overmorrow', From 1fd213357ead40bf13a0dbd0591cf744d25f8b5c Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 4 Jun 2024 17:12:11 +0200 Subject: [PATCH 002/129] started working on new settings page --- lib/settings_page.dart | 45 ++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 8918562..a260a86 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -231,6 +231,18 @@ Widget settingEntry(icon, text, settings, highlight, updatePage, textcolor, prim ); } +Widget NavButton(text, settings, textcolor, icon) { + return Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 8, right: 12, top: 13, bottom: 13), + child: Icon(icon, color: textcolor, size: 26,), + ), + comfortatext(text, 22, settings, color: textcolor), + ], + ); +} + Widget ColorCircle(name, primary, back, settings, updatePage, {w = 2, tap = 0}) { List colors = getColors(primary, back, settings, 0, force: name); @@ -300,7 +312,7 @@ class _SettingsPageState extends State { Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (context) { - return MyApp(); + return const MyApp(); }, ), ); @@ -332,6 +344,7 @@ Widget SettingsMain(Color primary, Map? settings, Function updat List colors = getColors(primary, back, settings, 0); return Scaffold( + backgroundColor: colors[5], appBar: AppBar( toolbarHeight: 65, shape: RoundedRectangleBorder( @@ -340,7 +353,6 @@ Widget SettingsMain(Color primary, Map? settings, Function updat elevation: 0, leadingWidth: 50, backgroundColor: colors[5], - title: comfortatext(translation('Settings', settings!["Language"]!), 25, settings, color: colors[2]), leading: IconButton( onPressed: (){ @@ -349,7 +361,7 @@ Widget SettingsMain(Color primary, Map? settings, Function updat icon: Icon(Icons.arrow_back, color: colors[2],), ) ), - body: settingsMain(colors[0], settings, updatePage, colors[2], colors[1], colors[5], colors[3], + body: settingsMain(colors[0], settings!, updatePage, colors[2], colors[1], colors[5], colors[3], image, primary, back), ); } @@ -363,16 +375,27 @@ Widget settingsMain(Color color, Map settings, Function updatePa padding: const EdgeInsets.only(left: 20, right: 15), color: highlight, child: SingleChildScrollView( - physics: BouncingScrollPhysics(), + physics: const BouncingScrollPhysics(), child: Center( child: Container( - constraints: BoxConstraints(maxWidth: 800), - padding: EdgeInsets.all(2), + constraints: const BoxConstraints(maxWidth: 800), + padding: const EdgeInsets.all(2), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(height: 15,), + const SizedBox(height: 15,), Padding( - padding: EdgeInsets.only(left: 10, right: 20), + padding: const EdgeInsets.only(top: 0, bottom: 30, left: 10), + child: comfortatext(translation('Settings', settings["Language"]!), 30, settings, color: textcolor), + ), + NavButton('Appearance', settings, textcolor, Icons.color_lens), + NavButton('Language', settings, textcolor, Icons.language), + NavButton('Units', settings, textcolor, Icons.cached), + NavButton('Advanced', settings, textcolor, Icons.code), + + /* + Padding( + padding: const EdgeInsets.only(left: 10, right: 20), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ @@ -391,7 +414,7 @@ Widget settingsMain(Color color, Map settings, Function updatePa ), ), Padding( - padding: EdgeInsets.only(top: 40, bottom: 30), + padding: const EdgeInsets.only(top: 40, bottom: 30), child: SizedBox( height: 300, child: Align( @@ -415,7 +438,7 @@ Widget settingsMain(Color color, Map settings, Function updatePa children: [ ParrallaxBackground(imagePath1: image, color: color), Padding( - padding: EdgeInsets.only(left: 10, bottom: 15), + padding: const EdgeInsets.only(left: 10, bottom: 15), child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.start, @@ -508,6 +531,8 @@ Widget settingsMain(Color color, Map settings, Function updatePa const SizedBox( height: 40, ) + + */ ] ), ), From fcdfb55bb5e1e02ca1b2b813ecaaeac927698c8a Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 4 Jun 2024 22:26:35 +0200 Subject: [PATCH 003/129] small change to new settings page ui --- lib/settings_page.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/settings_page.dart b/lib/settings_page.dart index a260a86..78fa968 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -235,10 +235,10 @@ Widget NavButton(text, settings, textcolor, icon) { return Row( children: [ Padding( - padding: const EdgeInsets.only(left: 8, right: 12, top: 13, bottom: 13), + padding: const EdgeInsets.only(left: 8, right: 12, top: 15, bottom: 15), child: Icon(icon, color: textcolor, size: 26,), ), - comfortatext(text, 22, settings, color: textcolor), + comfortatext(text, 21, settings, color: textcolor), ], ); } @@ -390,7 +390,7 @@ Widget settingsMain(Color color, Map settings, Function updatePa ), NavButton('Appearance', settings, textcolor, Icons.color_lens), NavButton('Language', settings, textcolor, Icons.language), - NavButton('Units', settings, textcolor, Icons.cached), + NavButton('Units', settings, textcolor, Icons.graphic_eq), NavButton('Advanced', settings, textcolor, Icons.code), /* From b859473ee04254ce1f4d9dbc3e18f74c5905d7e0 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 15 Jun 2024 15:33:38 -0400 Subject: [PATCH 004/129] fixed loading issue --- lib/main.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index e08610f..4e9789c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -224,15 +224,14 @@ class _MyAppState extends State { } } - late Widget w1; + Widget w1 = Container(); bool isLoading = false; @override void initState() { super.initState(); - w1 = Container(); //defaults to new york when no previous location was found - updateLocation('40.7128, 74.0060', "New York", time: 0); + updateLocation('40.7128, 74.0060', "New York", time: 500); } Future updateLocation(proposedLoc, backupName, {time = 500}) async { From 65d9b57f01a5c9f4a55763c49e613ee76f580d7e Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 15 Jun 2024 16:15:01 -0400 Subject: [PATCH 005/129] weather now loads separately from place name --- lib/main.dart | 39 ++------------------------------------ lib/search_screens.dart | 42 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 4e9789c..c1d321b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -23,7 +23,6 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; -import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; import 'package:overmorrow/search_screens.dart'; import 'package:overmorrow/ui_helper.dart'; @@ -72,7 +71,6 @@ class _MyAppState extends State { if (startup) { List n = await getLastPlace(); //loads the last place you visited - print(n); proposedLoc = n[1]; backupName = n[0]; startup = false; @@ -109,9 +107,9 @@ class _MyAppState extends State { } backupName = '${position.latitude},${position.longitude}'; - proposedLoc = 'search'; isItCurrentLocation = true; - print('True'); + absoluteProposed = backupName; + } else { return dumbySearch(errorMessage: translation(loc_status, settings["Language"]!), @@ -120,34 +118,6 @@ class _MyAppState extends State { place: backupName, settings: settings, provider: weather_provider, latlng: absoluteProposed,); } } - if (proposedLoc == 'search') { - - //List x = await getRecommend(backupName, "weatherapi", settings); - - List s_cord = backupName.split(","); - - try { - - List placemarks = await placemarkFromCoordinates( - double.parse(s_cord[0]), double.parse(s_cord[1])); - Placemark place = placemarks[0]; - - String city = '${place.locality}'; - - absoluteProposed = s_cord.join(', '); - backupName = city; - } on FormatException { - return dumbySearch( - errorMessage: '${translation('Place not found', settings["Language"]!)}: \n $backupName', - updateLocation: updateLocation, - icon: Icons.location_disabled, - place: backupName, settings: settings, provider: weather_provider, latlng: absoluteProposed,); - } on PlatformException { - absoluteProposed = backupName; - backupName = "${double.parse(s_cord[0]).toStringAsFixed(2)}, ${double.parse(s_cord[1]).toStringAsFixed(2)}"; - } - - } if (proposedLoc == 'query') { List x = await getRecommend(backupName, settings["Search provider"], settings); @@ -190,11 +160,6 @@ class _MyAppState extends State { updateLocation: updateLocation, icon: Icons.wifi_off, place: backupName, settings: settings, provider: weather_provider, latlng: absoluteProposed,); - } on Error catch (e, stacktrace) { - print(stacktrace); - return dumbySearch(errorMessage: "general error at place 2: $e", updateLocation: updateLocation, - icon: Icons.bug_report, - place: backupName, settings: settings, provider: weather_provider, latlng: absoluteProposed,); } print("temp:${weatherdata.current.temp}"); diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 9357696..f77fc50 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -22,6 +22,8 @@ import 'dart:ui'; import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:geocoding/geocoding.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/main_ui.dart'; import 'package:overmorrow/settings_page.dart'; @@ -42,7 +44,7 @@ Widget searchBar(Color color, List recommend, hint: translation('Search...', settings["Language"]!), title: Container( padding: const EdgeInsets.only(left: 5, top: 3), - child: comfortatext(place, 28 * getFontSize(settings["Font size"]!), settings, color: textColor) + child: getTitle(place, settings, textColor) ), hintStyle: GoogleFonts.comfortaa( color: textColor, @@ -312,6 +314,44 @@ Widget defaultSearchScreen(Color color, ); } +Widget getTitle(String place, settings, textColor) { + List split = place.split(','); + if (split.length > 1) { + return FutureBuilder( + future: getName(place), + builder: (BuildContext context, + AsyncSnapshot snapshot) { + if (snapshot.connectionState != ConnectionState.done) { + return comfortatext('Searching...', 18, settings, color: textColor); + } else if (snapshot.hasError) { + print(snapshot.error); + return comfortatext('Error', 18, settings, color: textColor); + } + return comfortatext(snapshot.data!, 23, settings, color: textColor); + }, + ); + + } + return comfortatext(place, 23, settings, color: textColor); +} + +Future getName(latlon) async { + List s_cord = latlon.split(","); + + try { + + List placemarks = await placemarkFromCoordinates( + double.parse(s_cord[0]), double.parse(s_cord[1])); + Placemark place = placemarks[0]; + + return '${place.locality}'; + } on FormatException { + return "${double.parse(s_cord[0]).toStringAsFixed(2)}, ${double.parse(s_cord[1]).toStringAsFixed(2)}"; + } on PlatformException { + return "${double.parse(s_cord[0]).toStringAsFixed(2)}, ${double.parse(s_cord[1]).toStringAsFixed(2)}"; + } +} + Widget recommendSearchScreen(Color color, List recommend, Function updateLocation, FloatingSearchBarController controller, List favorites, Function updateFav, var settings, textColor) { From d5853c20087a4c1f76aa1edcd21bc6ecffb73d2b Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 15 Jun 2024 16:30:35 -0400 Subject: [PATCH 006/129] fixed annoying bug where opening keyboard would trigger last updated --- lib/decoders/extra_info.dart | 5 +++++ lib/main_screens.dart | 2 +- lib/search_screens.dart | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 59f8ea7..dc2b524 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -51,6 +51,8 @@ class WeatherData { final double lat; final double lng; + final updatedTime; + final days; final current; final aqi; @@ -72,6 +74,7 @@ class WeatherData { required this.days, required this.current, required this.fetch_datetime, + required this.updatedTime, }); static Future getFullData(settings, placeName, real_loc, latlong, provider) async { @@ -128,6 +131,7 @@ class WeatherData { radar: await RainviewerRadar.getData(), fetch_datetime: fetch_datetime, + updatedTime: DateTime.now(), ); } else { @@ -169,6 +173,7 @@ class WeatherData { real_loc: real_loc, fetch_datetime: fetch_datetime, + updatedTime: DateTime.now(), ); } } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 5d15279..f8afa7d 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -64,7 +64,7 @@ Widget NewMain(data, updateLocation, context) { children: [ Stack( children: [ - UpdatedNotifier(data: data, time: DateTime.now(), key: Key(DateTime.now().toString()),), + UpdatedNotifier(data: data, time: data.updatedTime, key: Key(data.updatedTime.toString())), LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { if(constraints.maxWidth > 500.0) { diff --git a/lib/search_screens.dart b/lib/search_screens.dart index f77fc50..34c6c67 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -327,12 +327,12 @@ Widget getTitle(String place, settings, textColor) { print(snapshot.error); return comfortatext('Error', 18, settings, color: textColor); } - return comfortatext(snapshot.data!, 23, settings, color: textColor); + return comfortatext(snapshot.data!, 24, settings, color: textColor); }, ); } - return comfortatext(place, 23, settings, color: textColor); + return comfortatext(place, 24, settings, color: textColor); } Future getName(latlon) async { From 67a3a778f76d5e8434f19b374867193a3efc5a62 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 15 Jun 2024 16:44:21 -0400 Subject: [PATCH 007/129] searching texts now translated --- lib/languages.dart | 15 +++++++++++++++ lib/search_screens.dart | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/languages.dart b/lib/languages.dart index 17f6112..5aff0b2 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -1238,6 +1238,21 @@ Map> mainTranslate = { 'ανανεώθηκε, μόλις τώρα' ], + 'Finding place...': [ + 'Finding place...', + 'Hely keresése...', + 'Buscando lugar...', + 'Recherche de lieu...', + 'Ort finden...', + 'Ricerca del posto...', + 'Encontrando lugar...', + 'Поиск места...', + '寻找位置...', + '場所を見つけています...', + 'Szukanie miejsca...', + 'Εύρεση τοποθεσίας...' + ], + 'Search translation': [ //used for getting the codes used for translation of city names //If none are available then en (english) is the default // for more info visit https://open-meteo.com/en/docs/geocoding-api diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 34c6c67..e67a3f8 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -322,10 +322,10 @@ Widget getTitle(String place, settings, textColor) { builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState != ConnectionState.done) { - return comfortatext('Searching...', 18, settings, color: textColor); + return comfortatext(translation('Finding place...', settings["Language"]), 18, settings, color: textColor); } else if (snapshot.hasError) { print(snapshot.error); - return comfortatext('Error', 18, settings, color: textColor); + return comfortatext(translation('Place not found', settings["Language"]), 18, settings, color: textColor); } return comfortatext(snapshot.data!, 24, settings, color: textColor); }, From 5857ff1296b48d7e443eee84c96bfadd0253f6c7 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 18 Jun 2024 11:57:15 -0400 Subject: [PATCH 008/129] went back to old place finding, tried to improve loading inconsistencies --- lib/main.dart | 47 ++++++++++++++++++++++++++++++----------- lib/search_screens.dart | 41 +---------------------------------- 2 files changed, 36 insertions(+), 52 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index c1d321b..a2b7ef6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -23,6 +23,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; +import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; import 'package:overmorrow/search_screens.dart'; import 'package:overmorrow/ui_helper.dart'; @@ -59,9 +60,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { - bool startup = true; - - Future getDays(bool recall, proposedLoc, backupName) async { + Future getDays(bool recall, proposedLoc, backupName, startup) async { try { @@ -106,9 +105,22 @@ class _MyAppState extends State { place: backupName, settings: settings, provider: weather_provider, latlng: absoluteProposed,); } - backupName = '${position.latitude},${position.longitude}'; isItCurrentLocation = true; - absoluteProposed = backupName; + + try { + + List placemarks = await placemarkFromCoordinates( + position.latitude, position.longitude); + Placemark place = placemarks[0]; + + backupName = place.locality; + + + } on FormatException { + backupName = "${position.latitude.toStringAsFixed(2)}, ${position.longitude.toStringAsFixed(2)}"; + } on PlatformException { + backupName = "${position.latitude.toStringAsFixed(2)}, ${position.longitude.toStringAsFixed(2)}"; + } } else { @@ -184,33 +196,41 @@ class _MyAppState extends State { place: backupName, settings: settings, provider: weather_provider, latlng: 'search',); } else { - return getDays(true, proposedLoc, backupName); + return getDays(true, proposedLoc, backupName, startup); } } } Widget w1 = Container(); bool isLoading = false; + bool startup2 = false; @override void initState() { super.initState(); + //defaults to new york when no previous location was found - updateLocation('40.7128, 74.0060', "New York", time: 500); + updateLocation('40.7128, 74.0060', "New York", time: 300, startup: true); } - Future updateLocation(proposedLoc, backupName, {time = 500}) async { + Future updateLocation(proposedLoc, backupName, {time = 500, startup = false}) async { setState(() { + if (startup) { + startup2 = true; + } isLoading = true; }); await Future.delayed(Duration(milliseconds: time)); try { - Widget screen = await getDays(false, proposedLoc, backupName); + Widget screen = await getDays(false, proposedLoc, backupName, startup); setState(() { w1 = screen; + if (startup) { + startup2 = false; + } }); await Future.delayed(Duration(milliseconds: (800 - time).toInt())); @@ -225,6 +245,10 @@ class _MyAppState extends State { isLoading = false; }); } + + if (startup) { + startup2 = false; + } } @override @@ -232,7 +256,6 @@ class _MyAppState extends State { List colors = getStartBackColor(); final EdgeInsets systemGestureInsets = MediaQuery.of(context).systemGestureInsets; - print(('hihi', systemGestureInsets.left)); if (systemGestureInsets.left > 0) { SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( @@ -250,10 +273,10 @@ class _MyAppState extends State { children: [ w1, if (isLoading) Container( - color: startup ? colors[0] : const Color.fromRGBO(0, 0, 0, 0.7), + color: startup2 ? colors[0] : const Color.fromRGBO(0, 0, 0, 0.7), child: Center( child: LoadingAnimationWidget.staggeredDotsWave( - color: startup ? colors[1] : WHITE, + color: startup2 ? colors[1] : WHITE, size: 40, ), ), diff --git a/lib/search_screens.dart b/lib/search_screens.dart index e67a3f8..fe82e57 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -23,7 +23,6 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:geocoding/geocoding.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/main_ui.dart'; import 'package:overmorrow/settings_page.dart'; @@ -44,7 +43,7 @@ Widget searchBar(Color color, List recommend, hint: translation('Search...', settings["Language"]!), title: Container( padding: const EdgeInsets.only(left: 5, top: 3), - child: getTitle(place, settings, textColor) + child: comfortatext(place, 25, settings) ), hintStyle: GoogleFonts.comfortaa( color: textColor, @@ -314,44 +313,6 @@ Widget defaultSearchScreen(Color color, ); } -Widget getTitle(String place, settings, textColor) { - List split = place.split(','); - if (split.length > 1) { - return FutureBuilder( - future: getName(place), - builder: (BuildContext context, - AsyncSnapshot snapshot) { - if (snapshot.connectionState != ConnectionState.done) { - return comfortatext(translation('Finding place...', settings["Language"]), 18, settings, color: textColor); - } else if (snapshot.hasError) { - print(snapshot.error); - return comfortatext(translation('Place not found', settings["Language"]), 18, settings, color: textColor); - } - return comfortatext(snapshot.data!, 24, settings, color: textColor); - }, - ); - - } - return comfortatext(place, 24, settings, color: textColor); -} - -Future getName(latlon) async { - List s_cord = latlon.split(","); - - try { - - List placemarks = await placemarkFromCoordinates( - double.parse(s_cord[0]), double.parse(s_cord[1])); - Placemark place = placemarks[0]; - - return '${place.locality}'; - } on FormatException { - return "${double.parse(s_cord[0]).toStringAsFixed(2)}, ${double.parse(s_cord[1]).toStringAsFixed(2)}"; - } on PlatformException { - return "${double.parse(s_cord[0]).toStringAsFixed(2)}, ${double.parse(s_cord[1]).toStringAsFixed(2)}"; - } -} - Widget recommendSearchScreen(Color color, List recommend, Function updateLocation, FloatingSearchBarController controller, List favorites, Function updateFav, var settings, textColor) { From 1db4f916669dd143b3d000ceaf1aa96c0d73774f Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sun, 23 Jun 2024 14:39:41 -0400 Subject: [PATCH 009/129] started experimenting with network images --- lib/decoders/decode_OM.dart | 4 ++-- lib/decoders/extra_info.dart | 25 ++++++++++++++++++++++++- lib/main_screens.dart | 2 +- lib/main_ui.dart | 9 ++------- lib/search_screens.dart | 2 +- lib/settings_page.dart | 10 +++++----- 6 files changed, 35 insertions(+), 17 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index cfd8e44..0e02781 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -151,7 +151,7 @@ class OMCurrent { required this.wind_dir, }); - static OMCurrent fromJson(item, settings, sunstatus, timenow) { + static OMCurrent fromJson(item, settings, sunstatus, timenow, currentcolor) { Color back = BackColorCorrection( oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), @@ -177,7 +177,7 @@ class OMCurrent { item["current"]["apparent_temperature"], settings["Temperature"]) .round(), - backcolor: colors[0], + backcolor: currentcolor, primary: colors[1], textcolor: colors[2], colorpop: colors[3], diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index dc2b524..50858dd 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -19,6 +19,7 @@ along with this program. If not, see . import 'dart:convert'; import 'dart:ui'; +import 'package:flutter/cupertino.dart'; import 'package:overmorrow/decoders/decode_OM.dart'; import '../api_key.dart'; @@ -27,6 +28,7 @@ import '../caching.dart'; import '../ui_helper.dart'; import '../weather_refact.dart'; import 'decode_wapi.dart'; +import 'package:http/http.dart' as http; Color BackColorCorrection(String text) { @@ -61,6 +63,8 @@ class WeatherData { final fetch_datetime; + final image; + WeatherData({ required this.place, required this.settings, @@ -75,6 +79,7 @@ class WeatherData { required this.current, required this.fetch_datetime, required this.updatedTime, + required this.image, }); static Future getFullData(settings, placeName, real_loc, latlong, provider) async { @@ -107,6 +112,22 @@ class WeatherData { WapiSunstatus sunstatus = WapiSunstatus.fromJson(wapi_body, settings); + final params2 = { + 'client_id': access_key, + 'count' : '1' + + }; + final url2 = Uri.https('api.unsplash.com', 'photos/random', params2); + final response2 = await http.get(Uri.parse(url2.toString())); + + var wapi_body2 = jsonDecode(response2.body)[0]; + String image_path = wapi_body2["urls"]["regular"]; + Image hihi = Image.network(image_path, fit: BoxFit.cover); + + String color = wapi_body2["color"].replaceAll('#', '0xff'); + + Color otherColor = Color(int.parse(color)); + if (provider == 'weatherapi.com') { List days = []; @@ -132,6 +153,7 @@ class WeatherData { fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), + image: hihi ); } else { @@ -161,7 +183,7 @@ class WeatherData { aqi: WapiAqi.fromJson(wapi_body), sunstatus: WapiSunstatus.fromJson(wapi_body, settings), - current: OMCurrent.fromJson(oMBody, settings, sunstatus, real_time), + current: OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, otherColor), days: days, lat: lat, @@ -174,6 +196,7 @@ class WeatherData { fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), + image: hihi ); } } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index f8afa7d..7e361d5 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -27,7 +27,7 @@ Widget NewMain(data, updateLocation, context) { //backgroundColor: WHITE, blurContent: false, headerHeight: max(size.height * 0.57, 400), //we don't want it to be smaller than 400 - header: ParrallaxBackground(imagePath1: data.current.backdrop, key: Key(data.place), + header: ParrallaxBackground(imagePath1: data.image, key: Key(data.place), color: data.current.backcolor == BLACK ? BLACK : lightAccent(data.current.backcolor, 5000)), overlay: Stack( diff --git a/lib/main_ui.dart b/lib/main_ui.dart index d1ff959..3c6657a 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -65,7 +65,7 @@ class WeatherPage extends StatelessWidget { class ParrallaxBackground extends StatelessWidget { - final String imagePath1; + final Image imagePath1; final Color color; const ParrallaxBackground({Key? key, required this.imagePath1, required this.color}) : super(key: key); @@ -81,12 +81,7 @@ class ParrallaxBackground extends StatelessWidget { color: color, child: Opacity( opacity: value, - child: Image.asset( - 'assets/backdrops/$imagePath1', - fit: BoxFit.cover, - width: double.infinity, - height: double.infinity, - ), + child: imagePath1, ), ); }, diff --git a/lib/search_screens.dart b/lib/search_screens.dart index fe82e57..50ca54d 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -475,7 +475,7 @@ class dumbySearch extends StatelessWidget { headerData: HeaderData( blurContent: false, headerHeight: max(size.height * 0.6, 400), //we don't want it to be smaller than 400 - header: ParrallaxBackground(imagePath1: "grayscale_snow2.jpg", key: Key(place), + header: ParrallaxBackground(imagePath1: Image.asset("assets/backdrops/grayscale_snow2.jpg", fit: BoxFit.cover,), key: Key(place), color: darken(colors[0], 0.1),), overlay: Stack( children: [ diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 78fa968..28a9896 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -20,12 +20,12 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:overmorrow/decoders/decode_wapi.dart'; import 'package:overmorrow/donation_page.dart'; -import 'package:overmorrow/main_ui.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'decoders/decode_wapi.dart'; import 'languages.dart'; import 'main.dart'; +import 'main_ui.dart'; import 'ui_helper.dart'; Map> settingSwitches = { @@ -393,7 +393,7 @@ Widget settingsMain(Color color, Map settings, Function updatePa NavButton('Units', settings, textcolor, Icons.graphic_eq), NavButton('Advanced', settings, textcolor, Icons.code), - /* + Padding( padding: const EdgeInsets.only(left: 10, right: 20), child: Row( @@ -436,7 +436,7 @@ Widget settingsMain(Color color, Map settings, Function updatePa height: 220, child: Stack( children: [ - ParrallaxBackground(imagePath1: image, color: color), + ParrallaxBackground(imagePath1: Image.asset(image, fit: BoxFit.cover,), color: color), Padding( padding: const EdgeInsets.only(left: 10, bottom: 15), child: Column( @@ -532,7 +532,7 @@ Widget settingsMain(Color color, Map settings, Function updatePa height: 40, ) - */ + ] ), ), From 5eb33630c78b1a476d5a18355b2e942946ce697e Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 24 Jun 2024 20:07:17 +0200 Subject: [PATCH 010/129] dynamic themes from network images --- lib/decoders/decode_OM.dart | 14 +++++++++-- lib/decoders/extra_info.dart | 49 ++++++++++++++++++++++++++++-------- lib/search_screens.dart | 2 +- lib/settings_page.dart | 3 ++- pubspec.lock | 44 +++++++++++++++++++++++++++----- pubspec.yaml | 1 + 6 files changed, 93 insertions(+), 20 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 0e02781..0c062d8 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -19,6 +19,7 @@ along with this program. If not, see . import 'dart:ui'; +import 'package:flutter/material.dart'; import 'package:overmorrow/decoders/decode_wapi.dart'; import '../settings_page.dart'; @@ -151,7 +152,7 @@ class OMCurrent { required this.wind_dir, }); - static OMCurrent fromJson(item, settings, sunstatus, timenow, currentcolor) { + static OMCurrent fromJson(item, settings, sunstatus, timenow, ColorScheme palette) { Color back = BackColorCorrection( oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), @@ -177,12 +178,21 @@ class OMCurrent { item["current"]["apparent_temperature"], settings["Temperature"]) .round(), - backcolor: currentcolor, + /* + backcolor: colors[0], primary: colors[1], textcolor: colors[2], colorpop: colors[3], secondary: colors[4], highlight: colors[5], + */ + + backcolor: palette.secondaryContainer, + primary: palette.primary, + textcolor: palette.onSecondaryContainer, + colorpop: palette.secondaryContainer, + secondary: palette.onSecondaryContainer, + highlight: darken(palette.secondaryContainer, 0.07), backup_backcolor: back, backup_primary: primary, diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 50858dd..a54689b 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -19,7 +19,9 @@ along with this program. If not, see . import 'dart:convert'; import 'dart:ui'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:overmorrow/decoders/decode_OM.dart'; import '../api_key.dart'; @@ -28,7 +30,6 @@ import '../caching.dart'; import '../ui_helper.dart'; import '../weather_refact.dart'; import 'decode_wapi.dart'; -import 'package:http/http.dart' as http; Color BackColorCorrection(String text) { @@ -36,6 +37,17 @@ Color BackColorCorrection(String text) { return accentColors[text] ?? WHITE; } + +Future _materialPalette(Image imageWidget) async { + final ImageProvider imageProvider = imageWidget.image; + + return ColorScheme.fromImageProvider( + provider: imageProvider, + brightness: Brightness.dark, + + ); +} + Color PrimaryColorCorrection(String text) { return textBackColor[text] ?? BLACK; } @@ -112,21 +124,38 @@ class WeatherData { WapiSunstatus sunstatus = WapiSunstatus.fromJson(wapi_body, settings); + String text_query = textCorrection( + wapi_body["current"]["condition"]["code"], wapi_body["current"]["is_day"], + language: settings["Language"] + ); + + String addon = wapi_body["current"]["is_day"] == 1 ? 'daytime' : 'nighttime'; + print(addon); + final params2 = { 'client_id': access_key, - 'count' : '1' - + 'count' : '1', + 'query' : "$text_query $text_query $real_loc weather $addon", + 'content_filter' : 'high', }; + final url2 = Uri.https('api.unsplash.com', 'photos/random', params2); - final response2 = await http.get(Uri.parse(url2.toString())); - var wapi_body2 = jsonDecode(response2.body)[0]; - String image_path = wapi_body2["urls"]["regular"]; - Image hihi = Image.network(image_path, fit: BoxFit.cover); + var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query, unsplash") + .timeout(const Duration(seconds: 6)); + + var response2 = await file2.readAsString(); + + var wapi_body2 = jsonDecode(response2); + + String image_path = wapi_body2[0]["urls"]["regular"]; + + Image hihi = Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover,); + //Image hihi = Image.network(image_path, fit: BoxFit.cover); - String color = wapi_body2["color"].replaceAll('#', '0xff'); + //String color = wapi_body2["color"].replaceAll('#', '0xff'); - Color otherColor = Color(int.parse(color)); + //Color otherColor = Color(int.parse(color)); if (provider == 'weatherapi.com') { List days = []; @@ -183,7 +212,7 @@ class WeatherData { aqi: WapiAqi.fromJson(wapi_body), sunstatus: WapiSunstatus.fromJson(wapi_body, settings), - current: OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, otherColor), + current: OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, await _materialPalette(hihi)), days: days, lat: lat, diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 50ca54d..a2885a9 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -43,7 +43,7 @@ Widget searchBar(Color color, List recommend, hint: translation('Search...', settings["Language"]!), title: Container( padding: const EdgeInsets.only(left: 5, top: 3), - child: comfortatext(place, 25, settings) + child: comfortatext(place, 25, settings, color: textColor) ), hintStyle: GoogleFonts.comfortaa( color: textColor, diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 28a9896..f1fff7d 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -117,6 +117,7 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { return colors; } + Future> getSettingsUsed() async { Map settings = {}; for (var v in settingSwitches.entries) { @@ -436,7 +437,7 @@ Widget settingsMain(Color color, Map settings, Function updatePa height: 220, child: Stack( children: [ - ParrallaxBackground(imagePath1: Image.asset(image, fit: BoxFit.cover,), color: color), + ParrallaxBackground(imagePath1: Image.asset("assets/backdrops/$image", fit: BoxFit.cover,), color: color), Padding( padding: const EdgeInsets.only(left: 10, bottom: 15), child: Column( diff --git a/pubspec.lock b/pubspec.lock index a6b5dd7..b6bbe88 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: archive - sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265 + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d url: "https://pub.dev" source: hosted - version: "3.5.1" + version: "3.6.1" args: dependency: transitive description: @@ -33,6 +33,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "205d6a9f1862de34b93184f22b9d2d94586b2f05c581d546695e3d8f6a805cd7" + url: "https://pub.dev" + source: hosted + version: "1.2.0" characters: dependency: transitive description: @@ -220,10 +244,10 @@ packages: dependency: transitive description: name: geolocator_platform_interface - sha256: "009a21c4bc2761e58dccf07c24f219adaebe0ff707abdfd40b0a763d4003fab9" + sha256: "386ce3d9cce47838355000070b1d0b13efb5bc430f8ecda7e9238c8409ace012" url: "https://pub.dev" source: hosted - version: "4.2.2" + version: "4.2.4" geolocator_web: dependency: transitive description: @@ -276,10 +300,10 @@ packages: dependency: transitive description: name: image - sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" + sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" url: "https://pub.dev" source: hosted - version: "4.1.7" + version: "4.2.0" intl: dependency: transitive description: @@ -376,6 +400,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" + url: "https://pub.dev" + source: hosted + version: "2.0.0" path: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c26b31c..3f17a96 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,6 +45,7 @@ dependencies: loading_animation_widget: ^1.2.0+4 handy_window: ^0.3.1 stretchy_header: ^2.0.0 + cached_network_image: ^3.3.1 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. From 2c82ad04d6ba5402c778642e4508c7cdc5c8ff90 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 24 Jun 2024 21:06:34 +0200 Subject: [PATCH 011/129] new network images now support color themes --- lib/decoders/decode_OM.dart | 16 ++++----- lib/decoders/extra_info.dart | 10 +++--- lib/main_screens.dart | 2 +- lib/settings_page.dart | 55 +++++++++++++++++++++++++++++ lib/ui_helper.dart | 20 ++++++----- pubspec.lock | 68 ++++++++++++++++++++++++------------ 6 files changed, 125 insertions(+), 46 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 0c062d8..95a255a 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -163,12 +163,17 @@ class OMCurrent { item["current"]["weather_code"], sunstatus, timenow), ); + /* List colors = getColors(primary, back, settings, ColorPopCorrection( oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow),)[ settings["Color mode"] == "dark" ? 1 : 0 ]); + */ + + List colors = getNetworkColors(palette, settings); + return OMCurrent( text: translation(oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), @@ -178,21 +183,14 @@ class OMCurrent { item["current"]["apparent_temperature"], settings["Temperature"]) .round(), - /* + backcolor: colors[0], primary: colors[1], textcolor: colors[2], colorpop: colors[3], secondary: colors[4], highlight: colors[5], - */ - - backcolor: palette.secondaryContainer, - primary: palette.primary, - textcolor: palette.onSecondaryContainer, - colorpop: palette.secondaryContainer, - secondary: palette.onSecondaryContainer, - highlight: darken(palette.secondaryContainer, 0.07), + backup_backcolor: back, backup_primary: primary, diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index a54689b..21797ea 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -37,14 +37,13 @@ Color BackColorCorrection(String text) { return accentColors[text] ?? WHITE; } - -Future _materialPalette(Image imageWidget) async { +Future _materialPalette(Image imageWidget, theme) async { final ImageProvider imageProvider = imageWidget.image; return ColorScheme.fromImageProvider( provider: imageProvider, - brightness: Brightness.dark, - + brightness: theme == 'light' ? Brightness.light : Brightness.dark, + dynamicSchemeVariant: DynamicSchemeVariant.expressive, ); } @@ -212,7 +211,8 @@ class WeatherData { aqi: WapiAqi.fromJson(wapi_body), sunstatus: WapiSunstatus.fromJson(wapi_body, settings), - current: OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, await _materialPalette(hihi)), + current: OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, await _materialPalette(hihi, + settings["Color mode"])), days: days, lat: lat, diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 7e361d5..3cc97ff 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -41,7 +41,7 @@ Widget NewMain(data, updateLocation, context) { children: [ const Spacer(), Padding( - padding: const EdgeInsets.only(left: 0, bottom: 5), + padding: const EdgeInsets.only(left: 0, bottom: 0), child: comfortatext("${data.current.temp}°", 68, data.settings, color: data.current.colorpop, weight: FontWeight.w300), ), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index f1fff7d..b934757 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -117,6 +117,61 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { return colors; } +List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { + String x = force == "-1" ? settings["Color mode"] : force; + + List colors = [ + palette.primaryContainer, + palette.secondary, + palette.onPrimaryContainer, + palette.primaryContainer, + palette.onPrimaryContainer, + darken(palette.primaryContainer, 0.07) + ]; + + if (x == "monochrome") { + colors = [ + palette.secondaryContainer, + palette.secondary, + palette.onSecondaryContainer, + palette.secondaryContainer, + palette.onSecondaryContainer, + darken(palette.secondaryContainer, 0.07) + ]; + } + else if (x == "colorful") { + colors = [ + palette.secondaryContainer, + palette.primaryContainer, + palette.onSecondaryContainer, + palette.secondaryContainer, + palette.onSecondaryContainer, + darken(palette.secondaryContainer, 0.07) + ]; + } + else if (x == "light") { + colors = [ + palette.surface, + palette.primary, + palette.onSecondaryContainer, + palette.primary, + palette.onSurface, + darken(palette.surface, 0.07) + ]; + } + else if (x == "dark") { + colors = [ + darken(palette.surface, 0.02), + palette.primaryContainer, + palette.onSecondaryContainer, + palette.surface, + palette.onSecondaryContainer, + darken(palette.surface, 0.08) + ]; + } + return colors; +} + Future> getSettingsUsed() async { Map settings = {}; diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index e7b6f2a..a499177 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -55,15 +55,17 @@ Widget comfortatext(String text, double size, settings, double x = getFontSize(settings["Font size"]); return Text( - text, - style: GoogleFonts.comfortaa( - color: color, - fontSize: size * x, - fontWeight: weight, - ), - overflow: TextOverflow.ellipsis, - maxLines: 3, - textAlign: align, + text, + style: GoogleFonts.comfortaa( + color: color, + fontSize: size * x, + fontWeight: weight, + height: 1.1, + ), + overflow: TextOverflow.ellipsis, + maxLines: 3, + textAlign: align, + ); } diff --git a/pubspec.lock b/pubspec.lock index b6bbe88..5d10486 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -93,10 +93,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" crypto: dependency: transitive description: @@ -328,6 +328,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + url: "https://pub.dev" + source: hosted + version: "10.0.4" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" lints: dependency: transitive description: @@ -364,18 +388,18 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" material_floating_search_bar_2: dependency: "direct main" description: @@ -388,10 +412,10 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.12.0" mgrs_dart: dependency: transitive description: @@ -412,10 +436,10 @@ packages: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: transitive description: @@ -609,18 +633,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" stretchy_header: dependency: "direct main" description: @@ -657,10 +681,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.7.0" typed_data: dependency: transitive description: @@ -757,14 +781,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - web: + vm_service: dependency: transitive description: - name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + name: vm_service + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "14.2.1" win32: dependency: transitive description: @@ -806,5 +830,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.1.0 <4.0.0" - flutter: ">=3.13.0" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" From 6e3d246ae40c46f37a179d9d12f67313297f88f3 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 24 Jun 2024 21:13:37 +0200 Subject: [PATCH 012/129] small tweaks to colors --- lib/decoders/extra_info.dart | 3 ++- lib/settings_page.dart | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 21797ea..ae1a66a 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -43,7 +43,8 @@ Future _materialPalette(Image imageWidget, theme) async { return ColorScheme.fromImageProvider( provider: imageProvider, brightness: theme == 'light' ? Brightness.light : Brightness.dark, - dynamicSchemeVariant: DynamicSchemeVariant.expressive, + dynamicSchemeVariant: theme == 'original' ? DynamicSchemeVariant.tonalSpot : + DynamicSchemeVariant.tonalSpot, ); } diff --git a/lib/settings_page.dart b/lib/settings_page.dart index b934757..d9308da 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -142,7 +142,7 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { else if (x == "colorful") { colors = [ palette.secondaryContainer, - palette.primaryContainer, + palette.primary, palette.onSecondaryContainer, palette.secondaryContainer, palette.onSecondaryContainer, From cfe3ca708f9a2cea02320aa513f04b8bc74b6637 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 25 Jun 2024 12:18:35 +0200 Subject: [PATCH 013/129] still trying to tweak colors --- lib/decoders/extra_info.dart | 4 ++-- lib/main_screens.dart | 4 ++-- lib/settings_page.dart | 22 +++++++++++----------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index ae1a66a..49e8674 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -42,9 +42,9 @@ Future _materialPalette(Image imageWidget, theme) async { return ColorScheme.fromImageProvider( provider: imageProvider, - brightness: theme == 'light' ? Brightness.light : Brightness.dark, + brightness: theme == 'light' || theme == 'original' ? Brightness.light : Brightness.dark, dynamicSchemeVariant: theme == 'original' ? DynamicSchemeVariant.tonalSpot : - DynamicSchemeVariant.tonalSpot, + DynamicSchemeVariant.content, ); } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 3cc97ff..40ed301 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -34,14 +34,14 @@ Widget NewMain(data, updateLocation, context) { children: [ Padding( padding: EdgeInsets.only(left: 25, - top: MediaQuery.of(context).padding.top + 20, right: 25, bottom: 30 + top: MediaQuery.of(context).padding.top + 20, right: 25, bottom: 25 ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Spacer(), Padding( - padding: const EdgeInsets.only(left: 0, bottom: 0), + padding: const EdgeInsets.only(left: 0, bottom: 2), child: comfortatext("${data.current.temp}°", 68, data.settings, color: data.current.colorpop, weight: FontWeight.w300), ), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index d9308da..3ac75fc 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -121,12 +121,12 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { String x = force == "-1" ? settings["Color mode"] : force; List colors = [ - palette.primaryContainer, - palette.secondary, + palette.primary, + palette.secondaryContainer, + palette.onPrimary, + palette.primary, palette.onPrimaryContainer, - palette.primaryContainer, - palette.onPrimaryContainer, - darken(palette.primaryContainer, 0.07) + darken(palette.primary, 0.07) ]; if (x == "monochrome") { @@ -141,12 +141,12 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { } else if (x == "colorful") { colors = [ - palette.secondaryContainer, - palette.primary, - palette.onSecondaryContainer, - palette.secondaryContainer, - palette.onSecondaryContainer, - darken(palette.secondaryContainer, 0.07) + palette.primaryContainer, + palette.secondary, + palette.onPrimaryContainer, + palette.primaryContainer, + palette.onPrimaryContainer, + darken(palette.primaryContainer, 0.07) ]; } else if (x == "light") { From ec4649a7a906deee6e55bad0f220c7e45942423d Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 25 Jun 2024 21:27:02 +0200 Subject: [PATCH 014/129] still trying to figure out how to get palette from random image --- lib/decoders/decode_OM.dart | 4 ++ lib/decoders/extra_info.dart | 22 +++++-- lib/settings_page.dart | 18 +++--- pubspec.lock | 112 +++++++++++++++++++++-------------- pubspec.yaml | 1 + 5 files changed, 99 insertions(+), 58 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 95a255a..75281d3 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -28,6 +28,8 @@ import '../ui_helper.dart'; import '../weather_refact.dart'; import 'extra_info.dart'; + + String oMGetName(index, settings, item) { if (index < 3) { const names = ['Today', 'Tomorrow', 'Overmorrow']; @@ -174,6 +176,8 @@ class OMCurrent { List colors = getNetworkColors(palette, settings); + //List colors = palette.colors.toList(); + return OMCurrent( text: translation(oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 49e8674..812eea4 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -23,6 +23,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:overmorrow/decoders/decode_OM.dart'; +import 'package:palette_generator/palette_generator.dart'; import '../api_key.dart'; import '../caching.dart'; @@ -31,6 +32,16 @@ import '../ui_helper.dart'; import '../weather_refact.dart'; import 'decode_wapi.dart'; +Future _generatorPalette(Image imageWidget) async { + final ImageProvider imageProvider = imageWidget.image; + + PaletteGenerator _paletteGenerator = await PaletteGenerator.fromImageProvider( + imageProvider, + maximumColorCount: 6, + ); + return _paletteGenerator; +} + Color BackColorCorrection(String text) { //return Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0); @@ -42,9 +53,9 @@ Future _materialPalette(Image imageWidget, theme) async { return ColorScheme.fromImageProvider( provider: imageProvider, - brightness: theme == 'light' || theme == 'original' ? Brightness.light : Brightness.dark, - dynamicSchemeVariant: theme == 'original' ? DynamicSchemeVariant.tonalSpot : - DynamicSchemeVariant.content, + brightness: theme == 'light' ? Brightness.light : Brightness.dark, + dynamicSchemeVariant: theme == 'original' ? DynamicSchemeVariant.expressive : + DynamicSchemeVariant.expressive, ); } @@ -212,8 +223,9 @@ class WeatherData { aqi: WapiAqi.fromJson(wapi_body), sunstatus: WapiSunstatus.fromJson(wapi_body, settings), - current: OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, await _materialPalette(hihi, - settings["Color mode"])), + current: OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, + await _materialPalette(hihi, settings["Color mode"])), + //await _generatorPalette(hihi)), days: days, lat: lat, diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 3ac75fc..7c72790 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -121,20 +121,20 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { String x = force == "-1" ? settings["Color mode"] : force; List colors = [ - palette.primary, - palette.secondaryContainer, - palette.onPrimary, - palette.primary, - palette.onPrimaryContainer, - darken(palette.primary, 0.07) + palette.tertiary, + palette.primaryContainer, + palette.onTertiary, + palette.tertiary, + palette.onTertiary, + darken(palette.tertiary, 0.07) ]; if (x == "monochrome") { colors = [ palette.secondaryContainer, - palette.secondary, palette.onSecondaryContainer, - palette.secondaryContainer, + palette.onSecondaryContainer, + palette.onSecondaryContainer, palette.onSecondaryContainer, darken(palette.secondaryContainer, 0.07) ]; @@ -142,7 +142,7 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { else if (x == "colorful") { colors = [ palette.primaryContainer, - palette.secondary, + palette.tertiary, palette.onPrimaryContainer, palette.primaryContainer, palette.onPrimaryContainer, diff --git a/pubspec.lock b/pubspec.lock index 5d10486..e5b845c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file: dependency: transitive description: @@ -137,6 +137,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" flutter: dependency: "direct main" description: flutter @@ -146,10 +154,10 @@ packages: dependency: "direct main" description: name: flutter_cache_manager - sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + sha256: "395d6b7831f21f3b989ebedbb785545932adb9afe2622c1ffacf7f4b53a7e544" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.3.2" flutter_launcher_icons: dependency: "direct main" description: @@ -170,10 +178,10 @@ packages: dependency: "direct main" description: name: flutter_map - sha256: cda8d72135b697f519287258b5294a57ce2f2a5ebf234f0e406aad4dc14c9399 + sha256: "87cc8349b8fa5dccda5af50018c7374b6645334a0d680931c1fe11bce88fa5bb" url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.2.1" flutter_test: dependency: "direct dev" description: flutter @@ -228,10 +236,10 @@ packages: dependency: transitive description: name: geolocator_android - sha256: "06e37fa32392f69f133e166ef6b358a8b6afddbf4c418fc236988184cc115a49" + sha256: "00c7177a95823dd3ee35ef42fd8666cd27d219ae14cea472ac76a21dff43000b" url: "https://pub.dev" source: hosted - version: "4.4.1" + version: "4.6.0" geolocator_apple: dependency: transitive description: @@ -284,10 +292,10 @@ packages: dependency: "direct main" description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.1" http_parser: dependency: transitive description: @@ -432,6 +440,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + palette_generator: + dependency: "direct main" + description: + name: palette_generator + sha256: eb7082b4b97487ebc65b3ad3f6f0b7489b96e76840381ed0e06a46fe7ffd4068 + url: "https://pub.dev" + source: hosted + version: "0.3.3+3" path: dependency: transitive description: @@ -452,18 +468,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "51f0d2c554cfbc9d6a312ab35152fc77e2f0b758ce9f1a444a3a1e5b8f3c6b7f" + sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.2.6" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" path_provider_linux: dependency: transitive description: @@ -492,18 +508,18 @@ packages: dependency: transitive description: name: petitparser - sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "6.0.2" platform: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -548,18 +564,18 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.3" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.4.0" shared_preferences_linux: dependency: transitive description: @@ -580,10 +596,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf + sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" shared_preferences_windows: dependency: transitive description: @@ -617,18 +633,18 @@ packages: dependency: transitive description: name: sqflite - sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 + sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.3+1" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" + sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4" url: "https://pub.dev" source: hosted - version: "2.5.3" + version: "2.5.4" stack_trace: dependency: transitive description: @@ -705,26 +721,26 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c + sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.3.0" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 + sha256: ceb2625f0c24ade6ef6778d1de0b2e44f2db71fded235eb52295247feba8c5cf url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.3" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" + sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.3.0" url_launcher_linux: dependency: transitive description: @@ -753,10 +769,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2" + sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.1" url_launcher_windows: dependency: transitive description: @@ -769,10 +785,10 @@ packages: dependency: transitive description: name: uuid - sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f" + sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" url: "https://pub.dev" source: hosted - version: "4.2.2" + version: "4.4.0" vector_math: dependency: transitive description: @@ -789,14 +805,22 @@ packages: url: "https://pub.dev" source: hosted version: "14.2.1" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" win32: dependency: transitive description: name: win32 - sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574 + sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "5.5.1" wkt_parser: dependency: transitive description: @@ -817,10 +841,10 @@ packages: dependency: transitive description: name: xml - sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.5.0" yaml: dependency: transitive description: @@ -830,5 +854,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.22.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3f17a96..a6b9ad1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,7 @@ dependencies: handy_window: ^0.3.1 stretchy_header: ^2.0.0 cached_network_image: ^3.3.1 + palette_generator: ^0.3.3+3 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. From 41e2e9880dbbd2641d8fa43a8f13beece25cf162 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 29 Jun 2024 15:37:00 +0200 Subject: [PATCH 015/129] migrated code to new kotlin version + some tweaks to color --- android/app/build.gradle | 16 +++++++--------- android/build.gradle | 24 +++++++++++++----------- android/settings.gradle | 30 ++++++++++++++++++++++-------- lib/settings_page.dart | 18 +++++++++--------- lib/ui_helper.dart | 30 ++++++++++++++++-------------- 5 files changed, 67 insertions(+), 51 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 6185331..86571e8 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,3 +1,9 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { @@ -6,10 +12,6 @@ if (localPropertiesFile.exists()) { } } -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { @@ -21,10 +23,6 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - android { namespace "com.example.overmorrow" @@ -71,5 +69,5 @@ flutter { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + } diff --git a/android/build.gradle b/android/build.gradle index f7eb7f6..38c2e63 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,14 +1,20 @@ -buildscript { - ext.kotlin_version = '1.7.10' +allprojects { repositories { google() mavenCentral() } +} - dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir } allprojects { @@ -24,8 +30,4 @@ subprojects { } subprojects { project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} +} \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index 44e62bc..adce2b0 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,11 +1,25 @@ -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.3.0" apply false + id "org.jetbrains.kotlin.android" version "2.0.0" apply false +} + +include ":app" diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 7c72790..2eb4927 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -134,7 +134,7 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { palette.secondaryContainer, palette.onSecondaryContainer, palette.onSecondaryContainer, - palette.onSecondaryContainer, + palette.secondaryContainer, palette.onSecondaryContainer, darken(palette.secondaryContainer, 0.07) ]; @@ -152,21 +152,21 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { else if (x == "light") { colors = [ palette.surface, - palette.primary, - palette.onSecondaryContainer, - palette.primary, + palette.secondary, palette.onSurface, - darken(palette.surface, 0.07) + palette.secondary, + palette.onSecondaryFixed, + palette.surfaceContainer ]; } else if (x == "dark") { colors = [ - darken(palette.surface, 0.02), - palette.primaryContainer, - palette.onSecondaryContainer, palette.surface, + palette.secondary, palette.onSecondaryContainer, - darken(palette.surface, 0.08) + palette.secondary, + palette.onSurface, + palette.surfaceContainer ]; } return colors; diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index a499177..37b5f69 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -347,7 +347,7 @@ Widget WindWidget(data, day) { height: 150, decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), - border: Border.all(width: 1.2, color: WHITE) + border: Border.all(width: 1.2, color: data.current.secondary) ), child: ClipRRect( borderRadius: BorderRadius.circular(18), @@ -432,7 +432,7 @@ Widget RainWidget(data, day) { height: 150, decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), - border: Border.all(width: 1.2, color: WHITE) + border: Border.all(width: 1.2, color: data.current.secondary) ), child: ClipRRect( borderRadius: BorderRadius.circular(18), @@ -458,8 +458,9 @@ Widget RainWidget(data, day) { child: Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - comfortatext((index * 0.2).toStringAsFixed(1), 17, data.settings), - comfortatext('in', 12, data.settings), + comfortatext((index * 0.2).toStringAsFixed(1), 17, data.settings, + color: data.current.secondary), + comfortatext('in', 12, data.settings, color: data.current.secondary), ], ), ); @@ -470,8 +471,9 @@ Widget RainWidget(data, day) { child: Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - comfortatext((index * 5).toString(), 17, data.settings), - comfortatext('mm', 12, data.settings), + comfortatext((index * 5).toString(), 17, data.settings, + color: data.current.secondary), + comfortatext('mm', 12, data.settings, color: data.current.secondary), ], ), ); @@ -488,19 +490,19 @@ Widget RainWidget(data, day) { replacement: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - comfortatext("3am", 14,data. settings), - comfortatext("9am", 14, data.settings), - comfortatext("3pm", 14, data.settings), - comfortatext("9pm", 14, data.settings), + comfortatext("3am", 14,data. settings, color: data.current.secondary), + comfortatext("9am", 14, data.settings, color: data.current.secondary), + comfortatext("3pm", 14, data.settings, color: data.current.secondary), + comfortatext("9pm", 14, data.settings, color: data.current.secondary), ] ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - comfortatext("3:00", 14, data.settings), - comfortatext("9:00", 14, data.settings), - comfortatext("15:00", 14, data.settings), - comfortatext("21:00", 14, data.settings), + comfortatext("3:00", 14, data.settings, color: data.current.secondary), + comfortatext("9:00", 14, data.settings, color: data.current.secondary), + comfortatext("15:00", 14, data.settings, color: data.current.secondary), + comfortatext("21:00", 14, data.settings, color: data.current.secondary), ] ), ) From 103e36b935299035c510719d23c9f9d55ab0900f Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 1 Jul 2024 17:32:17 +0200 Subject: [PATCH 016/129] getting more comfortable with color themes --- lib/decoders/extra_info.dart | 4 ++-- lib/settings_page.dart | 25 ++++++++++++------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 812eea4..f3fd272 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -54,7 +54,7 @@ Future _materialPalette(Image imageWidget, theme) async { return ColorScheme.fromImageProvider( provider: imageProvider, brightness: theme == 'light' ? Brightness.light : Brightness.dark, - dynamicSchemeVariant: theme == 'original' ? DynamicSchemeVariant.expressive : + dynamicSchemeVariant: theme == 'original' || theme == 'monochrome' ? DynamicSchemeVariant.fruitSalad : DynamicSchemeVariant.expressive, ); } @@ -146,7 +146,7 @@ class WeatherData { final params2 = { 'client_id': access_key, 'count' : '1', - 'query' : "$text_query $text_query $real_loc weather $addon", + 'query' : "$text_query $real_loc", 'content_filter' : 'high', }; diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 2eb4927..ccd3d17 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -121,22 +121,21 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { String x = force == "-1" ? settings["Color mode"] : force; List colors = [ + palette.onPrimaryFixedVariant, palette.tertiary, - palette.primaryContainer, - palette.onTertiary, - palette.tertiary, - palette.onTertiary, - darken(palette.tertiary, 0.07) + WHITE, + palette.onPrimaryFixedVariant, + WHITE, + darken(palette.onPrimaryFixedVariant, 0.07) ]; - if (x == "monochrome") { colors = [ - palette.secondaryContainer, - palette.onSecondaryContainer, - palette.onSecondaryContainer, - palette.secondaryContainer, - palette.onSecondaryContainer, - darken(palette.secondaryContainer, 0.07) + palette.onPrimaryFixedVariant, + WHITE, + WHITE, + palette.onPrimaryFixedVariant, + WHITE, + darken(palette.onPrimaryFixedVariant, 0.07) ]; } else if (x == "colorful") { @@ -146,7 +145,7 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { palette.onPrimaryContainer, palette.primaryContainer, palette.onPrimaryContainer, - darken(palette.primaryContainer, 0.07) + darken(palette.primaryContainer, 0.1) ]; } else if (x == "light") { From 79e2342d3e2448fc7822e9e160b442eb7b81d275 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 2 Jul 2024 20:05:37 +0200 Subject: [PATCH 017/129] experimenting with material design --- lib/decoders/decode_OM.dart | 5 ++ lib/decoders/extra_info.dart | 2 +- lib/main_screens.dart | 30 +++++++++- lib/main_ui.dart | 6 +- lib/new_displays.dart | 113 +++++++++++++++++++++++++++++++++++ lib/search_screens.dart | 2 +- lib/settings_page.dart | 58 +++++++++--------- 7 files changed, 178 insertions(+), 38 deletions(-) create mode 100644 lib/new_displays.dart diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 75281d3..5dc0a3a 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -134,6 +134,8 @@ class OMCurrent { final Color backup_primary; final Color backup_backcolor; + final palette; + const OMCurrent({ required this.precip, required this.primary, @@ -152,6 +154,7 @@ class OMCurrent { required this.backup_backcolor, required this.backup_primary, required this.wind_dir, + required this.palette, }); static OMCurrent fromJson(item, settings, sunstatus, timenow, ColorScheme palette) { @@ -187,6 +190,8 @@ class OMCurrent { item["current"]["apparent_temperature"], settings["Temperature"]) .round(), + palette: palette, + backcolor: colors[0], primary: colors[1], diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index f3fd272..ae9e30c 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -55,7 +55,7 @@ Future _materialPalette(Image imageWidget, theme) async { provider: imageProvider, brightness: theme == 'light' ? Brightness.light : Brightness.dark, dynamicSchemeVariant: theme == 'original' || theme == 'monochrome' ? DynamicSchemeVariant.fruitSalad : - DynamicSchemeVariant.expressive, + DynamicSchemeVariant.tonalSpot, ); } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 40ed301..e8af7d1 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -1,7 +1,26 @@ +/* +Copyright (C) <2024> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:overmorrow/new_displays.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:material_floating_search_bar_2/material_floating_search_bar_2.dart'; import 'package:stretchy_header/stretchy_header.dart'; @@ -26,8 +45,8 @@ Widget NewMain(data, updateLocation, context) { headerData: HeaderData( //backgroundColor: WHITE, blurContent: false, - headerHeight: max(size.height * 0.57, 400), //we don't want it to be smaller than 400 - header: ParrallaxBackground(imagePath1: data.image, key: Key(data.place), + headerHeight: max(size.height * 0.56, 400), //we don't want it to be smaller than 400 + header: ParrallaxBackground(image: data.image, key: Key(data.place), color: data.current.backcolor == BLACK ? BLACK : lightAccent(data.current.backcolor, 5000)), overlay: Stack( @@ -76,12 +95,17 @@ Widget NewMain(data, updateLocation, context) { ), ], ), + + NewSunriseSunset(data, data.current.palette), + /* NewTimes(data, true), buildHihiDays(data), buildGlanceDay(data), providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), const Padding(padding: EdgeInsets.only(bottom: 20)) + + */ ], ), ); @@ -134,7 +158,7 @@ Widget TabletLayout(data, updateLocation, context) { padding: const EdgeInsets.only(top: 100), child: ClipRRect( borderRadius: BorderRadius.circular(20), - child: ParrallaxBackground(imagePath1: data.current.backdrop, key: Key(data.place), + child: ParrallaxBackground(image: data.current.backdrop, key: Key(data.place), color: darken(data.current.backcolor, 0.1),), ), ), diff --git a/lib/main_ui.dart b/lib/main_ui.dart index 3c6657a..2c0af85 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -65,10 +65,10 @@ class WeatherPage extends StatelessWidget { class ParrallaxBackground extends StatelessWidget { - final Image imagePath1; + final Image image; final Color color; - const ParrallaxBackground({Key? key, required this.imagePath1, required this.color}) : super(key: key); + const ParrallaxBackground({Key? key, required this.image, required this.color}) : super(key: key); @override Widget build(BuildContext context) { @@ -81,7 +81,7 @@ class ParrallaxBackground extends StatelessWidget { color: color, child: Opacity( opacity: value, - child: imagePath1, + child: image, ), ); }, diff --git a/lib/new_displays.dart b/lib/new_displays.dart new file mode 100644 index 0000000..6914141 --- /dev/null +++ b/lib/new_displays.dart @@ -0,0 +1,113 @@ +/* +Copyright (C) <2024> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +import 'dart:math'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class WavePainter extends CustomPainter { + final double waveValue; + final Color color; + + WavePainter(this.waveValue, this.color); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = color + ..strokeWidth = 2.5 + ..strokeCap = StrokeCap.round + ..style = PaintingStyle.stroke; + + + final path = Path(); + + final amplitude = 2.0; + final frequency = 20.0; + + for (double x = 0; x <= size.width; x++) { + final y = size.height / 2 + amplitude * sin((x / size.width * frequency * 2 * pi) + (waveValue * 2 * pi)); + if (x == 0) { + path.moveTo(x, y); + } else { + path.lineTo(x, y); + } + } + + canvas.drawPath(path, paint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; + } +} + +class WavySlider extends StatefulWidget { + final Color color; + + @override + WavySlider(this.color); + + @override + _WavySliderState createState() => _WavySliderState(); +} + +class _WavySliderState extends State with SingleTickerProviderStateMixin { + late AnimationController _controller; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, + duration: const Duration(seconds: 2), + )..repeat(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _controller, + builder: (context, child) { + return CustomPaint( + painter: WavePainter(_controller.value, widget.color), + child: Container( + width: double.infinity, + height: 8.0, + ), + ); + }, + ); + } +} + +Widget NewSunriseSunset(var data, ColorScheme palette) { + return Padding( + padding: const EdgeInsets.only(left: 20, right: 20, top: 5), + child: WavySlider(palette.secondary), + ); +} \ No newline at end of file diff --git a/lib/search_screens.dart b/lib/search_screens.dart index a2885a9..4fc1b91 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -475,7 +475,7 @@ class dumbySearch extends StatelessWidget { headerData: HeaderData( blurContent: false, headerHeight: max(size.height * 0.6, 400), //we don't want it to be smaller than 400 - header: ParrallaxBackground(imagePath1: Image.asset("assets/backdrops/grayscale_snow2.jpg", fit: BoxFit.cover,), key: Key(place), + header: ParrallaxBackground(image: Image.asset("assets/backdrops/grayscale_snow2.jpg", fit: BoxFit.cover,), key: Key(place), color: darken(colors[0], 0.1),), overlay: Stack( children: [ diff --git a/lib/settings_page.dart b/lib/settings_page.dart index ccd3d17..cc7daf0 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -151,10 +151,10 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { else if (x == "light") { colors = [ palette.surface, - palette.secondary, + palette.primary, palette.onSurface, - palette.secondary, - palette.onSecondaryFixed, + palette.primary, + palette.onPrimaryFixed, palette.surfaceContainer ]; } @@ -387,37 +387,39 @@ class _SettingsPageState extends State { child: ErrorWidget(snapshot.error as Object), ); } - return SettingsMain(primary, snapshot.data, updatePage, goBack, back, image); + return SettingsMain(primary, snapshot.data, updatePage, goBack, back, image, context); }, ); } } Widget SettingsMain(Color primary, Map? settings, Function updatePage, - Function goBack, Color back, String image) { + Function goBack, Color back, String image, context) { List colors = getColors(primary, back, settings, 0); - return Scaffold( - backgroundColor: colors[5], - appBar: AppBar( - toolbarHeight: 65, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(0) - ), - elevation: 0, - leadingWidth: 50, - backgroundColor: colors[5], + return Material( + color: colors[5], + child: CustomScrollView( + slivers: [ + SliverAppBar.large( leading: - IconButton( - onPressed: (){ - goBack(); - }, - icon: Icon(Icons.arrow_back, color: colors[2],), - ) - ), - body: settingsMain(colors[0], settings!, updatePage, colors[2], colors[1], colors[5], colors[3], - image, primary, back), + IconButton(icon: Icon(Icons.menu, color: colors[2],), onPressed: () {}), + title: comfortatext(translation('Settings', settings!["Language"]!), 30, settings, color: colors[2]), + actions: [ + IconButton(icon: Icon(Icons.more_vert, color: colors[2],), onPressed: () {}), + ], + backgroundColor: colors[5], + ), + // Just some content big enough to have something to scroll. + SliverToBoxAdapter( + child: Container( + color: colors[0], + child: settingsMain(colors[0], settings, updatePage, colors[2], colors[4], colors[5], colors[3], image, primary, back), + ), + ), + ], + ), ); } @@ -438,11 +440,6 @@ Widget settingsMain(Color color, Map settings, Function updatePa child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SizedBox(height: 15,), - Padding( - padding: const EdgeInsets.only(top: 0, bottom: 30, left: 10), - child: comfortatext(translation('Settings', settings["Language"]!), 30, settings, color: textcolor), - ), NavButton('Appearance', settings, textcolor, Icons.color_lens), NavButton('Language', settings, textcolor, Icons.language), NavButton('Units', settings, textcolor, Icons.graphic_eq), @@ -491,7 +488,8 @@ Widget settingsMain(Color color, Map settings, Function updatePa height: 220, child: Stack( children: [ - ParrallaxBackground(imagePath1: Image.asset("assets/backdrops/$image", fit: BoxFit.cover,), color: color), + ParrallaxBackground(image: Image.asset("assets/backdrops/$image", + fit: BoxFit.fill, width: double.infinity, height: double.infinity,), color: color), Padding( padding: const EdgeInsets.only(left: 10, bottom: 15), child: Column( From fb4dd7ad5ee7bbfee6400be80489010f04370d81 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 3 Jul 2024 14:56:17 +0200 Subject: [PATCH 018/129] experimenting with new sunrise sunset indicator --- lib/decoders/extra_info.dart | 14 ++++++++--- lib/main_screens.dart | 2 +- lib/new_displays.dart | 48 +++++++++++++++++++++++++++++------- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index ae9e30c..705f5b3 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -87,6 +87,7 @@ class WeatherData { final fetch_datetime; final image; + final localtime; WeatherData({ required this.place, @@ -103,6 +104,7 @@ class WeatherData { required this.fetch_datetime, required this.updatedTime, required this.image, + required this.localtime, }); static Future getFullData(settings, placeName, real_loc, latlong, provider) async { @@ -157,9 +159,9 @@ class WeatherData { var response2 = await file2.readAsString(); - var wapi_body2 = jsonDecode(response2); + var unsplash_body = jsonDecode(response2); - String image_path = wapi_body2[0]["urls"]["regular"]; + String image_path = unsplash_body[0]["urls"]["regular"]; Image hihi = Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover,); //Image hihi = Image.network(image_path, fit: BoxFit.cover); @@ -168,6 +170,8 @@ class WeatherData { //Color otherColor = Color(int.parse(color)); + final loctime = wapi_body["location"]["localtime"].split(" ")[1]; + if (provider == 'weatherapi.com') { List days = []; @@ -193,7 +197,8 @@ class WeatherData { fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), - image: hihi + image: hihi, + localtime: loctime ); } else { @@ -238,7 +243,8 @@ class WeatherData { fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), - image: hihi + image: hihi, + localtime: loctime ); } } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index e8af7d1..d2e314e 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -62,7 +62,7 @@ Widget NewMain(data, updateLocation, context) { Padding( padding: const EdgeInsets.only(left: 0, bottom: 2), child: comfortatext("${data.current.temp}°", 68, data.settings, - color: data.current.colorpop, weight: FontWeight.w300), + color: data.current.palette.primaryFixedDim, weight: FontWeight.w300), ), Padding( padding: const EdgeInsets.only(left: 0), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 6914141..975d075 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -25,25 +25,26 @@ import 'package:flutter/material.dart'; class WavePainter extends CustomPainter { final double waveValue; final Color color; + double hihi; - WavePainter(this.waveValue, this.color); + WavePainter(this.waveValue, this.color, this.hihi); @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = color - ..strokeWidth = 2.5 + ..strokeWidth = 2.3 ..strokeCap = StrokeCap.round ..style = PaintingStyle.stroke; final path = Path(); - final amplitude = 2.0; + final amplitude = 2.2; final frequency = 20.0; - for (double x = 0; x <= size.width; x++) { - final y = size.height / 2 + amplitude * sin((x / size.width * frequency * 2 * pi) + (waveValue * 2 * pi)); + for (double x = 0; x <= hihi * size.width; x++) { + final y = size.height / 2 + amplitude * sin((x / frequency * 2 * pi) + (waveValue * 2 * pi)); if (x == 0) { path.moveTo(x, y); } else { @@ -62,19 +63,42 @@ class WavePainter extends CustomPainter { class WavySlider extends StatefulWidget { final Color color; + final data; @override - WavySlider(this.color); + const WavySlider({super.key, required this.color, required this.data}); @override _WavySliderState createState() => _WavySliderState(); } class _WavySliderState extends State with SingleTickerProviderStateMixin { + + late DateTime riseDT; + late int offset; + late int total; + late AnimationController _controller; @override void initState() { + final List absoluteSunriseSunset = widget.data.sunstatus.absoluteSunriseSunset.split('/'); + + final List absoluteRise = absoluteSunriseSunset[0].split(':'); + final List absoluteSet = absoluteSunriseSunset[1].split(':'); + final List absoluteLocalTime = widget.data.localtime.split(':'); + + print(("riseSet", absoluteRise, absoluteSet, absoluteLocalTime)); + + final currentTime = DateTime.now(); + riseDT = currentTime.copyWith(hour: int.parse(absoluteRise[0]), minute: int.parse(absoluteRise[1])); + final setDT = currentTime.copyWith(hour: int.parse(absoluteSet[0]), minute: int.parse(absoluteSet[1])); + + final localtimeOld = currentTime.copyWith(hour: int.parse(absoluteLocalTime[0]), minute: int.parse(absoluteLocalTime[1])); + offset = currentTime.difference(localtimeOld).inSeconds; + + total = setDT.difference(riseDT).inSeconds; + super.initState(); _controller = AnimationController( vsync: this, @@ -93,8 +117,14 @@ class _WavySliderState extends State with SingleTickerProviderStateM return AnimatedBuilder( animation: _controller, builder: (context, child) { + + final thisdif = DateTime.now().difference(riseDT).inSeconds - offset; + final double progress = min(max(thisdif, 0) / total, 1); + + print(progress); + return CustomPaint( - painter: WavePainter(_controller.value, widget.color), + painter: WavePainter(_controller.value, widget.color, progress), child: Container( width: double.infinity, height: 8.0, @@ -107,7 +137,7 @@ class _WavySliderState extends State with SingleTickerProviderStateM Widget NewSunriseSunset(var data, ColorScheme palette) { return Padding( - padding: const EdgeInsets.only(left: 20, right: 20, top: 5), - child: WavySlider(palette.secondary), + padding: const EdgeInsets.only(left: 20, right: 20, top: 10), + child: WavySlider(color: palette.primaryFixedDim, data: data, key: Key(data.place),), ); } \ No newline at end of file From ce72d3fc1ae795c9c68a17b7bdc18fa9ab70845f Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 3 Jul 2024 17:00:00 +0200 Subject: [PATCH 019/129] major improvements to wavy sunrise sunset timeline --- lib/decoders/decode_OM.dart | 7 +-- lib/decoders/extra_info.dart | 13 ++-- lib/main_screens.dart | 8 +-- lib/main_ui.dart | 2 +- lib/new_displays.dart | 114 +++++++++++++++++++++++++---------- 5 files changed, 96 insertions(+), 48 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 5dc0a3a..6cb4e1b 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -134,8 +134,6 @@ class OMCurrent { final Color backup_primary; final Color backup_backcolor; - final palette; - const OMCurrent({ required this.precip, required this.primary, @@ -154,10 +152,9 @@ class OMCurrent { required this.backup_backcolor, required this.backup_primary, required this.wind_dir, - required this.palette, }); - static OMCurrent fromJson(item, settings, sunstatus, timenow, ColorScheme palette) { + static OMCurrent fromJson(item, settings, sunstatus, timenow, palette) { Color back = BackColorCorrection( oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), @@ -190,8 +187,6 @@ class OMCurrent { item["current"]["apparent_temperature"], settings["Temperature"]) .round(), - palette: palette, - backcolor: colors[0], primary: colors[1], diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 705f5b3..19d1e40 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -89,6 +89,8 @@ class WeatherData { final image; final localtime; + final palette; + WeatherData({ required this.place, required this.settings, @@ -105,6 +107,7 @@ class WeatherData { required this.updatedTime, required this.image, required this.localtime, + required this.palette, }); static Future getFullData(settings, placeName, real_loc, latlong, provider) async { @@ -171,6 +174,7 @@ class WeatherData { //Color otherColor = Color(int.parse(color)); final loctime = wapi_body["location"]["localtime"].split(" ")[1]; + final ColorScheme palette = await _materialPalette(hihi, settings["Color mode"]); if (provider == 'weatherapi.com') { List days = []; @@ -198,7 +202,8 @@ class WeatherData { fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), image: hihi, - localtime: loctime + localtime: loctime, + palette: palette, ); } else { @@ -228,8 +233,7 @@ class WeatherData { aqi: WapiAqi.fromJson(wapi_body), sunstatus: WapiSunstatus.fromJson(wapi_body, settings), - current: OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, - await _materialPalette(hihi, settings["Color mode"])), + current: OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, palette), //await _generatorPalette(hihi)), days: days, @@ -244,7 +248,8 @@ class WeatherData { fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), image: hihi, - localtime: loctime + localtime: loctime, + palette: palette, ); } } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index d2e314e..e4c9a17 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -45,7 +45,7 @@ Widget NewMain(data, updateLocation, context) { headerData: HeaderData( //backgroundColor: WHITE, blurContent: false, - headerHeight: max(size.height * 0.56, 400), //we don't want it to be smaller than 400 + headerHeight: max(size.height * 0.55, 400), //we don't want it to be smaller than 400 header: ParrallaxBackground(image: data.image, key: Key(data.place), color: data.current.backcolor == BLACK ? BLACK : lightAccent(data.current.backcolor, 5000)), @@ -62,12 +62,12 @@ Widget NewMain(data, updateLocation, context) { Padding( padding: const EdgeInsets.only(left: 0, bottom: 2), child: comfortatext("${data.current.temp}°", 68, data.settings, - color: data.current.palette.primaryFixedDim, weight: FontWeight.w300), + color: data.palette.primaryFixedDim, weight: FontWeight.w300), ), Padding( padding: const EdgeInsets.only(left: 0), child: comfortatext(data.current.text, 32, data.settings, - weight: FontWeight.w400), + weight: FontWeight.w400, color: data.palette.surface), ), ], ), @@ -96,7 +96,7 @@ Widget NewMain(data, updateLocation, context) { ], ), - NewSunriseSunset(data, data.current.palette), + NewSunriseSunset(data: data, key: Key(data.place), size: size,) /* NewTimes(data, true), buildHihiDays(data), diff --git a/lib/main_ui.dart b/lib/main_ui.dart index 2c0af85..b4518b4 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -96,7 +96,7 @@ Widget Circles(double width, var data, double bottom, color, {align = Alignment. child: SizedBox( width: width, child: Container( - padding: const EdgeInsets.only(top: 30, left: 4, right: 4), + padding: const EdgeInsets.only(top: 25, left: 4, right: 4), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 975d075..a9a8c28 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -21,29 +21,36 @@ import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:overmorrow/ui_helper.dart'; class WavePainter extends CustomPainter { final double waveValue; - final Color color; - double hihi; + final Color firstColor; + final Color secondColor; + final double hihi; - WavePainter(this.waveValue, this.color, this.hihi); + WavePainter(this.waveValue, this.firstColor, this.secondColor, this.hihi); @override void paint(Canvas canvas, Size size) { - final paint = Paint() - ..color = color - ..strokeWidth = 2.3 + final firstPaint = Paint() + ..color = firstColor + ..strokeWidth = 2.4 ..strokeCap = StrokeCap.round ..style = PaintingStyle.stroke; + final secondPaint = Paint() + ..color = secondColor + ..strokeWidth = 2.4 + ..strokeCap = StrokeCap.round + ..style = PaintingStyle.stroke; final path = Path(); + final amplitude = 2.45; + final frequency = 24.0; + final splitPoint = hihi * size.width; - final amplitude = 2.2; - final frequency = 20.0; - - for (double x = 0; x <= hihi * size.width; x++) { + for (double x = 0; x <= splitPoint; x++) { final y = size.height / 2 + amplitude * sin((x / frequency * 2 * pi) + (waveValue * 2 * pi)); if (x == 0) { path.moveTo(x, y); @@ -51,8 +58,18 @@ class WavePainter extends CustomPainter { path.lineTo(x, y); } } + canvas.drawPath(path, firstPaint); - canvas.drawPath(path, paint); + path.reset(); + for (double x = splitPoint; x <= size.width; x++) { + final y = size.height / 2 + amplitude * sin((x / frequency * 2 * pi) + (waveValue * 2 * pi)); + if (x == splitPoint) { + path.moveTo(x, y); + } else { + path.lineTo(x, y); + } + } + canvas.drawPath(path, secondPaint); } @override @@ -61,22 +78,22 @@ class WavePainter extends CustomPainter { } } -class WavySlider extends StatefulWidget { - final Color color; +class NewSunriseSunset extends StatefulWidget { final data; + final size; @override - const WavySlider({super.key, required this.color, required this.data}); + const NewSunriseSunset({super.key, required this.data, required this.size}); @override - _WavySliderState createState() => _WavySliderState(); + _NewSunriseSunsetState createState() => _NewSunriseSunsetState(); } -class _WavySliderState extends State with SingleTickerProviderStateMixin { +class _NewSunriseSunsetState extends State with SingleTickerProviderStateMixin { late DateTime riseDT; - late int offset; late int total; + late int hourdif; late AnimationController _controller; @@ -95,7 +112,8 @@ class _WavySliderState extends State with SingleTickerProviderStateM final setDT = currentTime.copyWith(hour: int.parse(absoluteSet[0]), minute: int.parse(absoluteSet[1])); final localtimeOld = currentTime.copyWith(hour: int.parse(absoluteLocalTime[0]), minute: int.parse(absoluteLocalTime[1])); - offset = currentTime.difference(localtimeOld).inSeconds; + + hourdif = localtimeOld.hour - currentTime.hour; total = setDT.difference(riseDT).inSeconds; @@ -118,26 +136,56 @@ class _WavySliderState extends State with SingleTickerProviderStateM animation: _controller, builder: (context, child) { - final thisdif = DateTime.now().difference(riseDT).inSeconds - offset; - final double progress = min(max(thisdif, 0) / total, 1); + DateTime now = DateTime.now(); + DateTime localTime = now.add(Duration(hours: hourdif)); - print(progress); + final thisdif = localTime.difference(riseDT).inSeconds; + final double progress = min(max(thisdif, 0) / total, 1); - return CustomPaint( - painter: WavePainter(_controller.value, widget.color, progress), - child: Container( - width: double.infinity, - height: 8.0, + return Padding( + padding: const EdgeInsets.only(left: 25, right: 25, top: 7), + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(left: max(progress * (widget.size.width - 50) - 30, 0)), + child: Align( + alignment: Alignment.centerLeft, + child: SizedBox( + width: 50, + child: Center( + child: comfortatext("${now.hour + hourdif}:${now.minute}", 15, widget.data.settings, + color: widget.data.palette.primary), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.all(5.0), + child: CustomPaint( + painter: WavePainter(_controller.value, widget.data.palette.primaryFixedDim, + widget.data.palette.surfaceContainerHigh, progress), + child: Container( + width: double.infinity, + height: 8.0, + ), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + comfortatext(widget.data.sunstatus.sunrise, 15, widget.data.settings, + color: widget.data.palette.onSurface), + Spacer(), + comfortatext(widget.data.sunstatus.sunset, 15, widget.data.settings, + color: widget.data.palette.onSurface), + ], + ), + ) + ], ), ); }, ); } -} - -Widget NewSunriseSunset(var data, ColorScheme palette) { - return Padding( - padding: const EdgeInsets.only(left: 20, right: 20, top: 10), - child: WavySlider(color: palette.primaryFixedDim, data: data, key: Key(data.place),), - ); } \ No newline at end of file From 09bd713ac8702479999373be9ff53ec390ba71b3 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 3 Jul 2024 17:56:25 +0200 Subject: [PATCH 020/129] improved time formating --- lib/new_displays.dart | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/new_displays.dart b/lib/new_displays.dart index a9a8c28..9f3bde7 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -23,6 +23,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:overmorrow/ui_helper.dart'; +import 'decoders/decode_wapi.dart'; + class WavePainter extends CustomPainter { final double waveValue; final Color firstColor; @@ -140,22 +142,25 @@ class _NewSunriseSunsetState extends State with SingleTickerPr DateTime localTime = now.add(Duration(hours: hourdif)); final thisdif = localTime.difference(riseDT).inSeconds; - final double progress = min(max(thisdif, 0) / total, 1); + final double progress = min(max(thisdif / total, 0), 1); + + print((progress, thisdif, total)); + + String write = widget.data.settings["Time mode"] == "24 hour" + ? convertTime("${localTime.hour}:${localTime.minute} j") //the j is just added so when splitting + : amPmTime("${localTime.hour}:${localTime.minute} j"); //it can grab the first item + return Padding( - padding: const EdgeInsets.only(left: 25, right: 25, top: 7), + padding: const EdgeInsets.only(left: 25, right: 25, top: 4), child: Column( children: [ Padding( - padding: EdgeInsets.only(left: max(progress * (widget.size.width - 50) - 30, 0)), + padding: EdgeInsets.only(left: max(progress * (widget.size.width - 50), 0)), //because the width is 70 child: Align( - alignment: Alignment.centerLeft, - child: SizedBox( - width: 50, - child: Center( - child: comfortatext("${now.hour + hourdif}:${now.minute}", 15, widget.data.settings, - color: widget.data.palette.primary), - ), + alignment: Alignment.center, + child: FractionallySizedBox( + child: comfortatext(write, 15, widget.data.settings, color: widget.data.palette.primary), ), ), ), From b7df7dddcd8754e7ebecf300d9be0fc252333f6b Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 4 Jul 2024 16:11:49 +0200 Subject: [PATCH 021/129] improved the new sunrise sunset indicator and alos improved colors --- lib/decoders/extra_info.dart | 2 +- lib/main_screens.dart | 4 ++-- lib/new_displays.dart | 38 ++++++++++++++++++++++++++---------- lib/search_screens.dart | 2 +- lib/settings_page.dart | 4 ++-- 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 19d1e40..b21ce70 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -151,7 +151,7 @@ class WeatherData { final params2 = { 'client_id': access_key, 'count' : '1', - 'query' : "$text_query $real_loc", + 'query' : "$text_query $real_loc day", 'content_filter' : 'high', }; diff --git a/lib/main_screens.dart b/lib/main_screens.dart index e4c9a17..683caa4 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -87,9 +87,9 @@ Widget NewMain(data, updateLocation, context) { LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { if(constraints.maxWidth > 500.0) { - return Circles(500, data, 0.5, data.current.primary); + return Circles(500, data, 0.5, data.palette.primary); } else { - return Circles(constraints.maxWidth * 0.97, data, 0.5, data.current.primary); + return Circles(constraints.maxWidth * 0.97, data, 0.5, data.palette.primary); } } ), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 9f3bde7..bcbbd56 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -21,6 +21,7 @@ import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/ui_helper.dart'; import 'decoders/decode_wapi.dart'; @@ -144,31 +145,40 @@ class _NewSunriseSunsetState extends State with SingleTickerPr final thisdif = localTime.difference(riseDT).inSeconds; final double progress = min(max(thisdif / total, 0), 1); - print((progress, thisdif, total)); - String write = widget.data.settings["Time mode"] == "24 hour" ? convertTime("${localTime.hour}:${localTime.minute} j") //the j is just added so when splitting : amPmTime("${localTime.hour}:${localTime.minute} j"); //it can grab the first item + + //this is all so that the text will be right above the progress + final textPainter = TextPainter( + text: TextSpan(text: write, style: GoogleFonts.comfortaa( + fontSize: 15.0 * getFontSize(widget.data.settings["Font size"]), + height: 1.1, + ),), + textDirection: TextDirection.ltr + ); + textPainter.layout(); + + final textWidth = textPainter.width; + return Padding( padding: const EdgeInsets.only(left: 25, right: 25, top: 4), child: Column( children: [ Padding( - padding: EdgeInsets.only(left: max(progress * (widget.size.width - 50), 0)), //because the width is 70 + padding: EdgeInsets.only(left: max((progress * (widget.size.width - 50)) - textWidth / 2, 0)), child: Align( - alignment: Alignment.center, - child: FractionallySizedBox( - child: comfortatext(write, 15, widget.data.settings, color: widget.data.palette.primary), - ), + alignment: Alignment.centerLeft, + child: comfortatext(write, 15, widget.data.settings, color: widget.data.palette.primary), ), ), Padding( padding: const EdgeInsets.all(5.0), child: CustomPaint( painter: WavePainter(_controller.value, widget.data.palette.primaryFixedDim, - widget.data.palette.surfaceContainerHigh, progress), + widget.data.palette.surfaceDim, progress), child: Container( width: double.infinity, height: 8.0, @@ -179,11 +189,19 @@ class _NewSunriseSunsetState extends State with SingleTickerPr padding: const EdgeInsets.all(8.0), child: Row( children: [ + Padding( + padding: const EdgeInsets.only(right: 4), + child: Icon(Icons.wb_sunny_outlined, color: widget.data.palette.primaryFixedDim, size: 14,), + ), comfortatext(widget.data.sunstatus.sunrise, 15, widget.data.settings, - color: widget.data.palette.onSurface), + color: widget.data.palette.primaryFixedDim), Spacer(), comfortatext(widget.data.sunstatus.sunset, 15, widget.data.settings, - color: widget.data.palette.onSurface), + color: widget.data.palette.outline), + Padding( + padding: const EdgeInsets.only(left: 4), + child: Icon(Icons.nightlight_outlined, color: widget.data.palette.outline, size: 14), + ), ], ), ) diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 4fc1b91..80289c5 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -43,7 +43,7 @@ Widget searchBar(Color color, List recommend, hint: translation('Search...', settings["Language"]!), title: Container( padding: const EdgeInsets.only(left: 5, top: 3), - child: comfortatext(place, 25, settings, color: textColor) + child: comfortatext(place, 25, settings, color: textColor, weight: FontWeight.w400) ), hintStyle: GoogleFonts.comfortaa( color: textColor, diff --git a/lib/settings_page.dart b/lib/settings_page.dart index cc7daf0..43d89ed 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -151,9 +151,9 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { else if (x == "light") { colors = [ palette.surface, + palette.primaryFixedDim, palette.primary, - palette.onSurface, - palette.primary, + palette.primaryFixedDim, palette.onPrimaryFixed, palette.surfaceContainer ]; From 1181162a766708a2899f25a6cf1026d24c444a61 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 5 Jul 2024 16:04:55 +0200 Subject: [PATCH 022/129] minor improvements to the overall design --- lib/decoders/decode_OM.dart | 1 - lib/decoders/extra_info.dart | 21 ++++---------------- lib/main_screens.dart | 2 +- lib/new_displays.dart | 37 +++++++++++++++++++++++++++--------- lib/search_screens.dart | 2 +- lib/settings_page.dart | 2 +- lib/ui_helper.dart | 2 +- pubspec.lock | 8 -------- pubspec.yaml | 2 +- 9 files changed, 37 insertions(+), 40 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 6cb4e1b..215282f 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -195,7 +195,6 @@ class OMCurrent { secondary: colors[4], highlight: colors[5], - backup_backcolor: back, backup_primary: primary, diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index b21ce70..a98a572 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -17,13 +17,10 @@ along with this program. If not, see . */ import 'dart:convert'; -import 'dart:ui'; import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:overmorrow/decoders/decode_OM.dart'; -import 'package:palette_generator/palette_generator.dart'; import '../api_key.dart'; import '../caching.dart'; @@ -32,16 +29,6 @@ import '../ui_helper.dart'; import '../weather_refact.dart'; import 'decode_wapi.dart'; -Future _generatorPalette(Image imageWidget) async { - final ImageProvider imageProvider = imageWidget.image; - - PaletteGenerator _paletteGenerator = await PaletteGenerator.fromImageProvider( - imageProvider, - maximumColorCount: 6, - ); - return _paletteGenerator; -} - Color BackColorCorrection(String text) { //return Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0); @@ -150,21 +137,21 @@ class WeatherData { final params2 = { 'client_id': access_key, - 'count' : '1', - 'query' : "$text_query $real_loc day", + 'query' : "$text_query, $real_loc", 'content_filter' : 'high', + //'collections' : '893395, 1319040, 583204, 11649432, 162468, 1492135', }; final url2 = Uri.https('api.unsplash.com', 'photos/random', params2); - var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query, unsplash") + var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query unsplash") .timeout(const Duration(seconds: 6)); var response2 = await file2.readAsString(); var unsplash_body = jsonDecode(response2); - String image_path = unsplash_body[0]["urls"]["regular"]; + String image_path = unsplash_body["urls"]["regular"]; Image hihi = Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover,); //Image hihi = Image.network(image_path, fit: BoxFit.cover); diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 683caa4..3821943 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -76,7 +76,7 @@ Widget NewMain(data, updateLocation, context) { color: data.current.backcolor, place: data.place, controller: controller, settings: data.settings, real_loc: data.real_loc, secondColor: data.current.primary, textColor: data.current.textcolor, - highlightColor: data.current.highlight, key: Key("${data.place}, ${data.current.backdrop}"),), + highlightColor: data.current.highlight, key: Key("${data.place}, ${data.image}"),), ], ) ), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index bcbbd56..57eb518 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -38,13 +38,13 @@ class WavePainter extends CustomPainter { void paint(Canvas canvas, Size size) { final firstPaint = Paint() ..color = firstColor - ..strokeWidth = 2.4 + ..strokeWidth = 2.5 ..strokeCap = StrokeCap.round ..style = PaintingStyle.stroke; final secondPaint = Paint() ..color = secondColor - ..strokeWidth = 2.4 + ..strokeWidth = 2.5 ..strokeCap = StrokeCap.round ..style = PaintingStyle.stroke; @@ -155,7 +155,7 @@ class _NewSunriseSunsetState extends State with SingleTickerPr final textPainter = TextPainter( text: TextSpan(text: write, style: GoogleFonts.comfortaa( fontSize: 15.0 * getFontSize(widget.data.settings["Font size"]), - height: 1.1, + fontWeight: FontWeight.w500 ),), textDirection: TextDirection.ltr ); @@ -164,18 +164,37 @@ class _NewSunriseSunsetState extends State with SingleTickerPr final textWidth = textPainter.width; return Padding( - padding: const EdgeInsets.only(left: 25, right: 25, top: 4), + padding: const EdgeInsets.only(left: 25, right: 25, top: 10), child: Column( children: [ Padding( - padding: EdgeInsets.only(left: max((progress * (widget.size.width - 50)) - textWidth / 2, 0)), + padding: EdgeInsets.only(left: + min(max((progress * (widget.size.width - 50)) - textWidth / 2 - 3, 0), + widget.size.width - 55 - textWidth)), child: Align( alignment: Alignment.centerLeft, - child: comfortatext(write, 15, widget.data.settings, color: widget.data.palette.primary), + child: comfortatext(write, 15, widget.data.settings, color: widget.data.palette.onPrimaryFixedVariant, + weight: FontWeight.w500), ), ), Padding( - padding: const EdgeInsets.all(5.0), + padding: EdgeInsets.only(top: 6, + left: min(max((progress * (widget.size.width - 50)) - 5, 2), widget.size.width - 52) + ), + child: Align( + alignment: Alignment.centerLeft, + child: Container( + height: 4, + width: 4, + decoration: BoxDecoration( + color: widget.data.palette.primaryFixedDim, + borderRadius: BorderRadius.circular(20), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5), child: CustomPaint( painter: WavePainter(_controller.value, widget.data.palette.primaryFixedDim, widget.data.palette.surfaceDim, progress), @@ -194,10 +213,10 @@ class _NewSunriseSunsetState extends State with SingleTickerPr child: Icon(Icons.wb_sunny_outlined, color: widget.data.palette.primaryFixedDim, size: 14,), ), comfortatext(widget.data.sunstatus.sunrise, 15, widget.data.settings, - color: widget.data.palette.primaryFixedDim), + color: widget.data.palette.primaryFixedDim, weight: FontWeight.w500), Spacer(), comfortatext(widget.data.sunstatus.sunset, 15, widget.data.settings, - color: widget.data.palette.outline), + color: widget.data.palette.outline, weight: FontWeight.w500), Padding( padding: const EdgeInsets.only(left: 4), child: Icon(Icons.nightlight_outlined, color: widget.data.palette.outline, size: 14), diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 80289c5..25924c4 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -418,7 +418,7 @@ Widget LocationButton(Function updateProg, Function updateLocation, Color color, elevation: 0, padding: const EdgeInsets.all(10), backgroundColor: color, - side: BorderSide(width: 1.5, color: textColor), + side: BorderSide(width: 1.7, color: textColor), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20) ) diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 43d89ed..7ce1fe1 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -155,7 +155,7 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { palette.primary, palette.primaryFixedDim, palette.onPrimaryFixed, - palette.surfaceContainer + palette.primaryContainer ]; } else if (x == "dark") { diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 37b5f69..219c163 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -238,7 +238,7 @@ class DescriptionCircle extends StatelessWidget { decoration: BoxDecoration( shape: BoxShape.circle, - border: Border.all(width: 2, color: color), + border: Border.all(width: 1.9, color: color), //color: WHITE, //borderRadius: BorderRadius.circular(size * 0.09) ), diff --git a/pubspec.lock b/pubspec.lock index e5b845c..94a265f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -440,14 +440,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" - palette_generator: - dependency: "direct main" - description: - name: palette_generator - sha256: eb7082b4b97487ebc65b3ad3f6f0b7489b96e76840381ed0e06a46fe7ffd4068 - url: "https://pub.dev" - source: hosted - version: "0.3.3+3" path: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a6b9ad1..733fc6c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,7 +46,7 @@ dependencies: handy_window: ^0.3.1 stretchy_header: ^2.0.0 cached_network_image: ^3.3.1 - palette_generator: ^0.3.3+3 + # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. From 08a299302a5f088ccc2eba7b403fdd2b853884a4 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sun, 7 Jul 2024 10:39:00 +0200 Subject: [PATCH 023/129] trying to improve the quality of network images --- lib/decoders/extra_info.dart | 8 +++++--- lib/main_screens.dart | 4 ++-- lib/new_displays.dart | 4 ++-- lib/weather_refact.dart | 19 +++++++++++++++++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index a98a572..b15f8b3 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -127,11 +127,13 @@ class WeatherData { WapiSunstatus sunstatus = WapiSunstatus.fromJson(wapi_body, settings); - String text_query = textCorrection( + String _text = textCorrection( wapi_body["current"]["condition"]["code"], wapi_body["current"]["is_day"], - language: settings["Language"] + language: 'english' ); + String text_query = textToUnsplashText[_text]!; + String addon = wapi_body["current"]["is_day"] == 1 ? 'daytime' : 'nighttime'; print(addon); @@ -144,7 +146,7 @@ class WeatherData { final url2 = Uri.https('api.unsplash.com', 'photos/random', params2); - var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query unsplash") + var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query") .timeout(const Duration(seconds: 6)); var response2 = await file2.readAsString(); diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 3821943..3c8edbb 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -67,7 +67,7 @@ Widget NewMain(data, updateLocation, context) { Padding( padding: const EdgeInsets.only(left: 0), child: comfortatext(data.current.text, 32, data.settings, - weight: FontWeight.w400, color: data.palette.surface), + weight: data.settings["Color mode"] == "dark" ? FontWeight.w600 : FontWeight.w400, color: data.palette.surface), ), ], ), @@ -76,7 +76,7 @@ Widget NewMain(data, updateLocation, context) { color: data.current.backcolor, place: data.place, controller: controller, settings: data.settings, real_loc: data.real_loc, secondColor: data.current.primary, textColor: data.current.textcolor, - highlightColor: data.current.highlight, key: Key("${data.place}, ${data.image}"),), + highlightColor: data.current.highlight, key: Key("${data.place}, ${data.image} ${data.settings}"),), ], ) ), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 57eb518..d0ef7ef 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -173,7 +173,7 @@ class _NewSunriseSunsetState extends State with SingleTickerPr widget.size.width - 55 - textWidth)), child: Align( alignment: Alignment.centerLeft, - child: comfortatext(write, 15, widget.data.settings, color: widget.data.palette.onPrimaryFixedVariant, + child: comfortatext(write, 15, widget.data.settings, color: widget.data.palette.secondary, weight: FontWeight.w500), ), ), @@ -197,7 +197,7 @@ class _NewSunriseSunsetState extends State with SingleTickerPr padding: const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5), child: CustomPaint( painter: WavePainter(_controller.value, widget.data.palette.primaryFixedDim, - widget.data.palette.surfaceDim, progress), + darken(widget.data.palette.surfaceVariant, 0.03), progress), child: Container( width: double.infinity, height: 8.0, diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 57aa63a..356378a 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -304,6 +304,25 @@ Map> conversionTable = { 'hPa': [0, 33.863886], }; +//I am trying to convert conditions to text that unsplash better understands +//for example: blue sky instead of clear sky tends to help a lot +Map textToUnsplashText = { + 'Clear Night': 'night', //somehow just 'night' always gives you clear skies: stars or moon + 'Partly Cloudy': 'cloudy', //this is also some simplification which improves a lot + 'Clear Sky': 'blue sky', //it doesn't understand clear as much so i use blue instead + 'Overcast': 'overcast', + 'Haze': 'haze', + 'Rain': 'rain', + 'Sleet': 'freezing rain',//this works much better + 'Drizzle': 'light rain', //somehow understands it more though still not perfect + 'Thunderstorm': 'thunderstorm', + 'Heavy Snow': 'heavy snow', + 'Fog': 'fog', + 'Snow': 'snow', + 'Heavy Rain': 'heavy rain', + 'Cloudy Night' : 'cloudy night' //if you specify cloudy then it gives cloudy results +}; + //if i have to get the average of two weather conditions then the condition // with the highest value will be chosen Map weatherConditionBiassTable = { From e1d876f11d65bb28b30b934ed70d30a9ca1f0fc9 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sun, 14 Jul 2024 18:05:30 +0200 Subject: [PATCH 024/129] temperature now computes background and changes color accordingly --- lib/decoders/extra_info.dart | 83 +++++++++++++++++++++++++++++++++++- lib/main.dart | 2 +- lib/main_screens.dart | 49 ++++++++++++++++++++- lib/ui_helper.dart | 2 +- pubspec.lock | 32 +++++++------- pubspec.yaml | 1 + 6 files changed, 148 insertions(+), 21 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index b15f8b3..8856414 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -16,11 +16,14 @@ along with this program. If not, see . */ +import 'dart:async'; import 'dart:convert'; +import 'dart:math'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:overmorrow/decoders/decode_OM.dart'; +import 'package:palette_generator/palette_generator.dart'; import '../api_key.dart'; import '../caching.dart'; @@ -29,12 +32,53 @@ import '../ui_helper.dart'; import '../weather_refact.dart'; import 'decode_wapi.dart'; +int difBetweenTwoColors(Color color1, Color color2) { + int r = (color1.red - color2.red).abs(); + int g = (color1.green - color2.green).abs(); + int b = (color1.blue - color2.blue).abs(); + return r + g + b; +} Color BackColorCorrection(String text) { //return Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0); return accentColors[text] ?? WHITE; } +Future _generatorPalette(Image imageWidget) async { + final ImageProvider imageProvider = imageWidget.image; + + final Completer completer = Completer(); + final ImageStreamListener listener = ImageStreamListener((ImageInfo info, bool _) { + if (!completer.isCompleted) { + completer.complete(info); + } + }); + + imageProvider.resolve(const ImageConfiguration()).addListener(listener); + + final ImageInfo imageInfo = await completer.future; + final int imageHeight = imageInfo.image.height; + + final double regionWidth = imageHeight / 4.5; + final double regionHeight = imageHeight / 4.5; + final Rect region = Rect.fromLTWH( + regionWidth * 0.3, + imageHeight - regionHeight * 2.2, + regionWidth, + regionHeight, + ); + + PaletteGenerator _paletteGenerator = await PaletteGenerator.fromImage( + imageInfo.image, + region: region, + ); + + imageProvider.resolve(const ImageConfiguration()).removeListener(listener); + + return _paletteGenerator; +} + + Future _materialPalette(Image imageWidget, theme) async { final ImageProvider imageProvider = imageWidget.image; @@ -77,6 +121,9 @@ class WeatherData { final localtime; final palette; + final colorpopdemo; + final colorlistdemo; + final backcolordemo; WeatherData({ required this.place, @@ -95,6 +142,10 @@ class WeatherData { required this.image, required this.localtime, required this.palette, + required this.colorpopdemo, + required this.colorlistdemo, + required this.backcolordemo, + }); static Future getFullData(settings, placeName, real_loc, latlong, provider) async { @@ -141,6 +192,7 @@ class WeatherData { 'client_id': access_key, 'query' : "$text_query, $real_loc", 'content_filter' : 'high', + 'count': '3', //'collections' : '893395, 1319040, 583204, 11649432, 162468, 1492135', }; @@ -152,8 +204,10 @@ class WeatherData { var response2 = await file2.readAsString(); var unsplash_body = jsonDecode(response2); + + var rng = Random(); - String image_path = unsplash_body["urls"]["regular"]; + String image_path = unsplash_body[rng.nextInt(3)]["urls"]["regular"]; Image hihi = Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover,); //Image hihi = Image.network(image_path, fit: BoxFit.cover); @@ -165,6 +219,25 @@ class WeatherData { final loctime = wapi_body["location"]["localtime"].split(" ")[1]; final ColorScheme palette = await _materialPalette(hihi, settings["Color mode"]); + final PaletteGenerator pali = await _generatorPalette(hihi); + + final Color dominant = pali.dominantColor!.color; + + Color bestcolor = palette.primaryFixedDim; + int bestDif = difBetweenTwoColors(bestcolor, dominant); + + print(("bestdif", bestDif)); + + if (bestDif < 250) { + for (int i = 0; i < pali.colors.length; i++) { + int newdif = difBetweenTwoColors(pali.colors.toList()[i], dominant); + if (newdif > bestDif) { + bestDif = newdif; + bestcolor = pali.colors.toList()[i]; + } + } + } + if (provider == 'weatherapi.com') { List days = []; @@ -193,6 +266,9 @@ class WeatherData { image: hihi, localtime: loctime, palette: palette, + colorpopdemo: bestcolor, + colorlistdemo: pali.colors.toList(), + backcolordemo: pali.dominantColor!.color, ); } else { @@ -222,7 +298,7 @@ class WeatherData { aqi: WapiAqi.fromJson(wapi_body), sunstatus: WapiSunstatus.fromJson(wapi_body, settings), - current: OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, palette), + current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, palette), //await _generatorPalette(hihi)), days: days, @@ -239,6 +315,9 @@ class WeatherData { image: hihi, localtime: loctime, palette: palette, + colorpopdemo: bestcolor, + colorlistdemo: pali.colors.toList(), + backcolordemo: pali.dominantColor!.color, ); } } diff --git a/lib/main.dart b/lib/main.dart index a2b7ef6..4e2e932 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -210,7 +210,7 @@ class _MyAppState extends State { super.initState(); //defaults to new york when no previous location was found - updateLocation('40.7128, 74.0060', "New York", time: 300, startup: true); + updateLocation('40.7128, 74.0060', "New York", time: 300, startup: true); //just for testing } Future updateLocation(proposedLoc, backupName, {time = 500, startup = false}) async { diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 3c8edbb..277bacc 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -62,7 +62,7 @@ Widget NewMain(data, updateLocation, context) { Padding( padding: const EdgeInsets.only(left: 0, bottom: 2), child: comfortatext("${data.current.temp}°", 68, data.settings, - color: data.palette.primaryFixedDim, weight: FontWeight.w300), + color: data.colorpopdemo, weight: FontWeight.w300), ), Padding( padding: const EdgeInsets.only(left: 0), @@ -96,6 +96,53 @@ Widget NewMain(data, updateLocation, context) { ], ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + height: 35, + width: 35, + decoration: BoxDecoration( + color: data.backcolordemo, + borderRadius: BorderRadius.circular(5) + ), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + height: 35, + width: 35, + decoration: BoxDecoration( + color: data.colorpopdemo, + borderRadius: BorderRadius.circular(5) + ), + ), + ), + + Container( + padding: EdgeInsets.all(6), + height: 47, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemExtent: 35, + itemBuilder: (BuildContext context, int index) { + if (index < data.colorlistdemo.length) { + return Padding( + padding: const EdgeInsets.all(2.0), + child: Container( + height: 35, + width: 35, + decoration: BoxDecoration( + color: data.colorlistdemo[index], + borderRadius: BorderRadius.circular(5) + ), + ), + ); + } + } + ), + ), + NewSunriseSunset(data: data, key: Key(data.place), size: size,) /* NewTimes(data, true), diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 219c163..5f81b61 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -63,7 +63,7 @@ Widget comfortatext(String text, double size, settings, height: 1.1, ), overflow: TextOverflow.ellipsis, - maxLines: 3, + maxLines: 40, textAlign: align, ); diff --git a/pubspec.lock b/pubspec.lock index 94a265f..5f90b2c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -440,6 +440,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + palette_generator: + dependency: "direct main" + description: + name: palette_generator + sha256: d50fbcd69abb80c5baec66d700033b1a320108b1aa17a5961866a12c0abb7c0c + url: "https://pub.dev" + source: hosted + version: "0.3.3+4" path: dependency: transitive description: @@ -460,10 +468,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a + sha256: "30c5aa827a6ae95ce2853cdc5fe3971daaac00f6f081c419c013f7f57bff2f5e" url: "https://pub.dev" source: hosted - version: "2.2.6" + version: "2.2.7" path_provider_foundation: dependency: transitive description: @@ -492,10 +500,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" petitparser: dependency: transitive description: @@ -729,10 +737,10 @@ packages: dependency: transitive description: name: url_launcher_ios - sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89" + sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.1" url_launcher_linux: dependency: transitive description: @@ -777,10 +785,10 @@ packages: dependency: transitive description: name: uuid - sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" + sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90" url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "4.4.2" vector_math: dependency: transitive description: @@ -805,14 +813,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.1" - win32: - dependency: transitive - description: - name: win32 - sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 - url: "https://pub.dev" - source: hosted - version: "5.5.1" wkt_parser: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 733fc6c..71d5d14 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,7 @@ dependencies: handy_window: ^0.3.1 stretchy_header: ^2.0.0 cached_network_image: ^3.3.1 + palette_generator: ^0.3.3+4 # The following adds the Cupertino Icons font to your application. From 1be4dea5fe248078ee6b694369f5d4ab5d11bc5f Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 15 Jul 2024 12:49:40 +0200 Subject: [PATCH 025/129] realized that image first needs to be cropped before getting background color --- lib/decoders/extra_info.dart | 49 +++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 8856414..16a1647 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -58,16 +58,35 @@ Future _generatorPalette(Image imageWidget) async { final ImageInfo imageInfo = await completer.future; final int imageHeight = imageInfo.image.height; + final int imageWidth = imageInfo.image.height; - final double regionWidth = imageHeight / 4.5; - final double regionHeight = imageHeight / 4.5; + final int desiredSquare = 400; //approximation because the top half image cropped is almost a square + + final double crop_x = desiredSquare / imageWidth; + final double crop_y = desiredSquare / imageHeight; + + final double crop_absolute = max(crop_y, crop_x); + + final double center_x = imageWidth / 2; + final double center_y = imageHeight / 2; + + final new_left = center_x - ((desiredSquare / 2) / crop_absolute); + final new_top = center_y - ((desiredSquare / 2) / crop_absolute); + + print((new_left, new_top, crop_absolute, (desiredSquare / 2) / crop_absolute)); + + final double regionWidth = 100; + final double regionHeight = 100; final Rect region = Rect.fromLTWH( - regionWidth * 0.3, - imageHeight - regionHeight * 2.2, - regionWidth, - regionHeight, + new_left + (30 / crop_absolute), + new_top + (280 / crop_absolute), + (regionWidth / crop_absolute), + (regionHeight / crop_absolute), ); + print(("original image", imageWidth, imageHeight)); + print(("cropped image",new_left + 30, new_top + 330, regionWidth, regionHeight,)); + PaletteGenerator _paletteGenerator = await PaletteGenerator.fromImage( imageInfo.image, region: region, @@ -124,6 +143,7 @@ class WeatherData { final colorpopdemo; final colorlistdemo; final backcolordemo; + final desc_color; WeatherData({ required this.place, @@ -145,7 +165,7 @@ class WeatherData { required this.colorpopdemo, required this.colorlistdemo, required this.backcolordemo, - + required this.desc_color, }); static Future getFullData(settings, placeName, real_loc, latlong, provider) async { @@ -209,6 +229,8 @@ class WeatherData { String image_path = unsplash_body[rng.nextInt(3)]["urls"]["regular"]; + print(image_path); + Image hihi = Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover,); //Image hihi = Image.network(image_path, fit: BoxFit.cover); @@ -228,16 +250,23 @@ class WeatherData { print(("bestdif", bestDif)); - if (bestDif < 250) { + if (bestDif < 280) { for (int i = 0; i < pali.colors.length; i++) { int newdif = difBetweenTwoColors(pali.colors.toList()[i], dominant); - if (newdif > bestDif) { + if (newdif > bestDif && newdif < 450) { bestDif = newdif; bestcolor = pali.colors.toList()[i]; } } } + Color desc_color = palette.surface; + int desc_dif = difBetweenTwoColors(desc_color, dominant); + + if (desc_dif < 220) { + desc_color = bestcolor; + } + if (provider == 'weatherapi.com') { List days = []; @@ -269,6 +298,7 @@ class WeatherData { colorpopdemo: bestcolor, colorlistdemo: pali.colors.toList(), backcolordemo: pali.dominantColor!.color, + desc_color: desc_color, ); } else { @@ -318,6 +348,7 @@ class WeatherData { colorpopdemo: bestcolor, colorlistdemo: pali.colors.toList(), backcolordemo: pali.dominantColor!.color, + desc_color: desc_color, ); } } From 98bf0c86a1461b9eeee482501dc4c89b53c6dbe2 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 15 Jul 2024 14:16:46 +0200 Subject: [PATCH 026/129] finished the temperature contrast modifier and cleaned up the code --- lib/decoders/decode_OM.dart | 20 ++- lib/decoders/decode_wapi.dart | 27 ++++ lib/decoders/extra_info.dart | 251 ++++++++++++++++++---------------- lib/main_screens.dart | 49 +------ 4 files changed, 177 insertions(+), 170 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 215282f..5c2eb1b 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -17,18 +17,36 @@ along with this program. If not, see . */ +import 'dart:convert'; import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:overmorrow/decoders/decode_wapi.dart'; +import '../caching.dart'; import '../settings_page.dart'; import '../ui_helper.dart'; import '../weather_refact.dart'; import 'extra_info.dart'; - +Future OMRequestData(double lat, double lng, String real_loc) async { + final oMParams = { + "latitude": lat.toString(), + "longitude": lng.toString(), + "current": ["temperature_2m", "relative_humidity_2m", "apparent_temperature", "weather_code", "wind_speed_10m", 'wind_direction_10m'], + "hourly": ["temperature_2m", "precipitation", "weather_code", "wind_speed_10m"], + "daily": ["weather_code", "temperature_2m_max", "temperature_2m_min", "uv_index_max", "precipitation_sum", "precipitation_probability_max", "wind_speed_10m_max", "wind_direction_10m_dominant"], + "timezone": "auto", + "forecast_days": "14" + }; + final oMUrl = Uri.https("api.open-meteo.com", 'v1/forecast', oMParams); + + var oMFile = await cacheManager2.getSingleFile(oMUrl.toString(), key: "$real_loc, open-meteo").timeout(const Duration(seconds: 6)); + var oMResponse = await oMFile.readAsString(); + final OMData = jsonDecode(oMResponse); + return OMData; +} String oMGetName(index, settings, item) { if (index < 3) { diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index 24f9732..24f016e 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -16,9 +16,13 @@ along with this program. If not, see . */ +import 'dart:async'; +import 'dart:convert'; import 'dart:math'; import 'dart:ui'; +import '../api_key.dart'; +import '../caching.dart'; import '../settings_page.dart'; import '../ui_helper.dart'; @@ -29,6 +33,29 @@ import 'extra_info.dart'; bool RandomSwitch = false; +Future> WapiMakeRequest(String latlong, String real_loc) async { + //gets the json response for weatherapi.com + final params = { + 'key': wapi_Key, + 'q': latlong, + 'days': '3', + 'aqi': 'yes', + 'alerts': 'no', + }; + final url = Uri.http('api.weatherapi.com', 'v1/forecast.json', params); + + var file = await cacheManager2.getSingleFile(url.toString(), key: "$real_loc, weatherapi.com") + .timeout(const Duration(seconds: 6)); + + DateTime fetch_datetime = await file.lastModified(); + + var response = await file.readAsString(); + + var wapi_body = jsonDecode(response); + + return [wapi_body, fetch_datetime]; +} + int wapiGetWindDir(var data) { int total = 0; for (var i = 0; i < data.length; i++) { diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 16a1647..1c28f74 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -32,6 +32,90 @@ import '../ui_helper.dart'; import '../weather_refact.dart'; import 'decode_wapi.dart'; +Future getUnsplashImage(var wapi_body, String real_loc) async { + String _text = textCorrection( + wapi_body["current"]["condition"]["code"], wapi_body["current"]["is_day"], + language: 'english' + ); + + String text_query = textToUnsplashText[_text]!; + + String addon = wapi_body["current"]["is_day"] == 1 ? 'daytime' : 'nighttime'; + print(addon); + + final params2 = { + 'client_id': access_key, + 'query' : "$text_query, $real_loc", + 'content_filter' : 'high', + 'count': '3', + //'collections' : '893395, 1319040, 583204, 11649432, 162468, 1492135', + }; + + final url2 = Uri.https('api.unsplash.com', 'photos/random', params2); + + var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query") + .timeout(const Duration(seconds: 6)); + + var response2 = await file2.readAsString(); + + var unsplash_body = jsonDecode(response2); + + var rng = Random(); + + String image_path = unsplash_body[rng.nextInt(3)]["urls"]["regular"]; + + print(image_path); + + return Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover,); +} + +Future getImageColors(Image Uimage, color_mode) async { + final ColorScheme palette = await _materialPalette(Uimage, color_mode); + final PaletteGenerator pali = await _generatorPalette(Uimage); + + final Color dominant = averageColor(pali.colors.toList()); + + Color startcolor = palette.primaryFixedDim; + + Color bestcolor = palette.primaryFixedDim; + int bestDif = difBetweenTwoColors(bestcolor, dominant); + + List colorsdemo = []; + + print(("bestdif", bestDif)); + + if (bestDif < 300) { + for (int i = 1; i < 4; i++) { + //LIGHT + Color newcolor = lighten(startcolor, i / 20); + int newdif = difBetweenTwoColors(newcolor, dominant); + if (newdif > bestDif && newdif < 500) { + bestDif = newdif; + bestcolor = newcolor; + } + colorsdemo.add(newcolor); + + //DARK + newcolor = darken(startcolor, i / 20); + newdif = difBetweenTwoColors(newcolor, dominant); + if (newdif > bestDif && newdif < 500) { + bestDif = newdif; + bestcolor = newcolor; + } + colorsdemo.add(newcolor); + } + } + + Color desc_color = palette.surface; + int desc_dif = difBetweenTwoColors(desc_color, dominant); + + if (desc_dif < 220) { + desc_color = bestcolor; + } + + return [palette, bestcolor, desc_color]; +} + int difBetweenTwoColors(Color color1, Color color2) { int r = (color1.red - color2.red).abs(); int g = (color1.green - color2.green).abs(); @@ -39,6 +123,22 @@ int difBetweenTwoColors(Color color1, Color color2) { return r + g + b; } +Color averageColor(List colors) { + if (colors.length > 0) { + int r = 0; + int g = 0; + int b = 0; + for (int i = 0; i < colors.length; i++) { + r += colors[i].red; g += colors[i].green; b += colors[i].blue; + } + r = r ~/ colors.length; + g = g ~/ colors.length; + b = b ~/ colors.length; + return Color.fromARGB(255, r, g, b); + } + return Colors.grey; +} + Color BackColorCorrection(String text) { //return Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0); return accentColors[text] ?? WHITE; @@ -75,11 +175,11 @@ Future _generatorPalette(Image imageWidget) async { print((new_left, new_top, crop_absolute, (desiredSquare / 2) / crop_absolute)); - final double regionWidth = 100; - final double regionHeight = 100; + final double regionWidth = 50; + final double regionHeight = 50; final Rect region = Rect.fromLTWH( - new_left + (30 / crop_absolute), - new_top + (280 / crop_absolute), + new_left + (40 / crop_absolute), + new_top + (300 / crop_absolute), (regionWidth / crop_absolute), (regionHeight / crop_absolute), ); @@ -90,6 +190,7 @@ Future _generatorPalette(Image imageWidget) async { PaletteGenerator _paletteGenerator = await PaletteGenerator.fromImage( imageInfo.image, region: region, + maximumColorCount: 3 ); imageProvider.resolve(const ImageConfiguration()).removeListener(listener); @@ -140,9 +241,7 @@ class WeatherData { final localtime; final palette; - final colorpopdemo; - final colorlistdemo; - final backcolordemo; + final colorpop; final desc_color; WeatherData({ @@ -161,10 +260,9 @@ class WeatherData { required this.updatedTime, required this.image, required this.localtime, + required this.palette, - required this.colorpopdemo, - required this.colorlistdemo, - required this.backcolordemo, + required this.colorpop, required this.desc_color, }); @@ -174,98 +272,25 @@ class WeatherData { double lat = double.parse(split[0]); double lng = double.parse(split[1]); - //gets the json response for weatherapi.com - final params = { - 'key': wapi_Key, - 'q': latlong, - 'days': '3', - 'aqi': 'yes', - 'alerts': 'no', - }; - final url = Uri.http('api.weatherapi.com', 'v1/forecast.json', params); - - var file = await cacheManager2.getSingleFile(url.toString(), key: "$real_loc, weatherapi.com") - .timeout(const Duration(seconds: 6)); - - DateTime fetch_datetime = await file.lastModified(); - - var response = await file.readAsString(); - - var wapi_body = jsonDecode(response); - - var timenow = wapi_body["location"]["localtime_epoch"]; - String real_time = wapi_body["location"]["localtime"]; - - WapiSunstatus sunstatus = WapiSunstatus.fromJson(wapi_body, settings); - - String _text = textCorrection( - wapi_body["current"]["condition"]["code"], wapi_body["current"]["is_day"], - language: 'english' - ); - - String text_query = textToUnsplashText[_text]!; - - String addon = wapi_body["current"]["is_day"] == 1 ? 'daytime' : 'nighttime'; - print(addon); - - final params2 = { - 'client_id': access_key, - 'query' : "$text_query, $real_loc", - 'content_filter' : 'high', - 'count': '3', - //'collections' : '893395, 1319040, 583204, 11649432, 162468, 1492135', - }; + //GET WEATHERAPI DATA + var wapi = await WapiMakeRequest(latlong, real_loc); - final url2 = Uri.https('api.unsplash.com', 'photos/random', params2); + var wapi_body = wapi[0]; + DateTime fetch_datetime = wapi[1]; - var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query") - .timeout(const Duration(seconds: 6)); - var response2 = await file2.readAsString(); - - var unsplash_body = jsonDecode(response2); - - var rng = Random(); - - String image_path = unsplash_body[rng.nextInt(3)]["urls"]["regular"]; - - print(image_path); - - Image hihi = Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover,); - //Image hihi = Image.network(image_path, fit: BoxFit.cover); - - //String color = wapi_body2["color"].replaceAll('#', '0xff'); - - //Color otherColor = Color(int.parse(color)); + //GET IMAGE + Image Uimage = await getUnsplashImage(wapi_body, real_loc); final loctime = wapi_body["location"]["localtime"].split(" ")[1]; - final ColorScheme palette = await _materialPalette(hihi, settings["Color mode"]); - - final PaletteGenerator pali = await _generatorPalette(hihi); - - final Color dominant = pali.dominantColor!.color; - Color bestcolor = palette.primaryFixedDim; - int bestDif = difBetweenTwoColors(bestcolor, dominant); + //GET COLORS + List imageColors = await getImageColors(Uimage, settings["Color mode"]); - print(("bestdif", bestDif)); - if (bestDif < 280) { - for (int i = 0; i < pali.colors.length; i++) { - int newdif = difBetweenTwoColors(pali.colors.toList()[i], dominant); - if (newdif > bestDif && newdif < 450) { - bestDif = newdif; - bestcolor = pali.colors.toList()[i]; - } - } - } - - Color desc_color = palette.surface; - int desc_dif = difBetweenTwoColors(desc_color, dominant); - - if (desc_dif < 220) { - desc_color = bestcolor; - } + var timenow = wapi_body["location"]["localtime_epoch"]; + String real_time = wapi_body["location"]["localtime"]; + WapiSunstatus sunstatus = WapiSunstatus.fromJson(wapi_body, settings); if (provider == 'weatherapi.com') { List days = []; @@ -292,30 +317,16 @@ class WeatherData { fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), - image: hihi, + image: Uimage, localtime: loctime, - palette: palette, - colorpopdemo: bestcolor, - colorlistdemo: pali.colors.toList(), - backcolordemo: pali.dominantColor!.color, - desc_color: desc_color, + palette: imageColors[0], + colorpop: imageColors[1], + desc_color: imageColors[2], ); } else { - final oMParams = { - "latitude": lat.toString(), - "longitude": lng.toString(), - "current": ["temperature_2m", "relative_humidity_2m", "apparent_temperature", "weather_code", "wind_speed_10m", 'wind_direction_10m'], - "hourly": ["temperature_2m", "precipitation", "weather_code", "wind_speed_10m"], - "daily": ["weather_code", "temperature_2m_max", "temperature_2m_min", "uv_index_max", "precipitation_sum", "precipitation_probability_max", "wind_speed_10m_max", "wind_direction_10m_dominant"], - "timezone": "auto", - "forecast_days": "14" - }; - final oMUrl = Uri.https("api.open-meteo.com", 'v1/forecast', oMParams); - - var oMFile = await cacheManager2.getSingleFile(oMUrl.toString(), key: "$real_loc, open-meteo").timeout(const Duration(seconds: 6)); - var oMResponse = await oMFile.readAsString(); - var oMBody = jsonDecode(oMResponse); + //GET OM data + var oMBody = await OMRequestData(lat, lng, real_loc); List days = []; for (int n = 0; n < 14; n++) { @@ -328,7 +339,7 @@ class WeatherData { aqi: WapiAqi.fromJson(wapi_body), sunstatus: WapiSunstatus.fromJson(wapi_body, settings), - current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, palette), + current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, imageColors[0]), //await _generatorPalette(hihi)), days: days, @@ -342,13 +353,11 @@ class WeatherData { fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), - image: hihi, + image: Uimage, localtime: loctime, - palette: palette, - colorpopdemo: bestcolor, - colorlistdemo: pali.colors.toList(), - backcolordemo: pali.dominantColor!.color, - desc_color: desc_color, + palette: imageColors[0], + colorpop: imageColors[1], + desc_color: imageColors[2], ); } } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 277bacc..55672a7 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -62,7 +62,7 @@ Widget NewMain(data, updateLocation, context) { Padding( padding: const EdgeInsets.only(left: 0, bottom: 2), child: comfortatext("${data.current.temp}°", 68, data.settings, - color: data.colorpopdemo, weight: FontWeight.w300), + color: data.colorpop, weight: FontWeight.w300), ), Padding( padding: const EdgeInsets.only(left: 0), @@ -96,53 +96,6 @@ Widget NewMain(data, updateLocation, context) { ], ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - height: 35, - width: 35, - decoration: BoxDecoration( - color: data.backcolordemo, - borderRadius: BorderRadius.circular(5) - ), - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - height: 35, - width: 35, - decoration: BoxDecoration( - color: data.colorpopdemo, - borderRadius: BorderRadius.circular(5) - ), - ), - ), - - Container( - padding: EdgeInsets.all(6), - height: 47, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemExtent: 35, - itemBuilder: (BuildContext context, int index) { - if (index < data.colorlistdemo.length) { - return Padding( - padding: const EdgeInsets.all(2.0), - child: Container( - height: 35, - width: 35, - decoration: BoxDecoration( - color: data.colorlistdemo[index], - borderRadius: BorderRadius.circular(5) - ), - ), - ); - } - } - ), - ), - NewSunriseSunset(data: data, key: Key(data.place), size: size,) /* NewTimes(data, true), From d0839da757cecd126e17813e18af4ae005e742f0 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 16 Jul 2024 18:14:54 +0200 Subject: [PATCH 027/129] started and mostly finsihed slight redisign of aqi --- lib/decoders/extra_info.dart | 32 +++++++++++++--- lib/main_screens.dart | 5 ++- lib/new_displays.dart | 74 ++++++++++++++++++++++++++++++++++++ lib/search_screens.dart | 1 - lib/ui_helper.dart | 65 ++++++++++++++++++++++++++++--- lib/weather_refact.dart | 2 +- 6 files changed, 165 insertions(+), 14 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 1c28f74..714e046 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -80,7 +80,7 @@ Future getImageColors(Image Uimage, color_mode) async { Color bestcolor = palette.primaryFixedDim; int bestDif = difBetweenTwoColors(bestcolor, dominant); - List colorsdemo = []; + print(dominant); print(("bestdif", bestDif)); @@ -93,7 +93,6 @@ Future getImageColors(Image Uimage, color_mode) async { bestDif = newdif; bestcolor = newcolor; } - colorsdemo.add(newcolor); //DARK newcolor = darken(startcolor, i / 20); @@ -102,18 +101,37 @@ Future getImageColors(Image Uimage, color_mode) async { bestDif = newdif; bestcolor = newcolor; } - colorsdemo.add(newcolor); } } Color desc_color = palette.surface; int desc_dif = difBetweenTwoColors(desc_color, dominant); - if (desc_dif < 220) { + print(("desc_dif", desc_dif)); + + if (desc_dif < 200) { desc_color = bestcolor; } - return [palette, bestcolor, desc_color]; + List gradientColors = getGradientColors(palette.primaryFixedDim, palette.error, 10); + + return [palette, bestcolor, desc_color, gradientColors, dominant]; +} + +List getGradientColors(Color color1, Color color2, int number) { + int r = color1.red; int g = color1.green; int b = color1.blue; + int dif_r = (color2.red - color1.red) ~/ number; + int dif_g = (color2.green - color1.green) ~/ number; + int dif_b = (color2.blue - color1.blue) ~/ number; + + List colors = []; + + for (int i = 0; i < number; i++) { + r += dif_r; b += dif_b; g += dif_g; + colors.add(Color.fromARGB(255, r, g, b)); + } + + return colors; } int difBetweenTwoColors(Color color1, Color color2) { @@ -243,6 +261,7 @@ class WeatherData { final palette; final colorpop; final desc_color; + final gradientColors; WeatherData({ required this.place, @@ -264,6 +283,7 @@ class WeatherData { required this.palette, required this.colorpop, required this.desc_color, + required this.gradientColors, }); static Future getFullData(settings, placeName, real_loc, latlong, provider) async { @@ -322,6 +342,7 @@ class WeatherData { palette: imageColors[0], colorpop: imageColors[1], desc_color: imageColors[2], + gradientColors: imageColors[3], ); } else { @@ -358,6 +379,7 @@ class WeatherData { palette: imageColors[0], colorpop: imageColors[1], desc_color: imageColors[2], + gradientColors: imageColors[3], ); } } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 55672a7..ad305d6 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -67,7 +67,7 @@ Widget NewMain(data, updateLocation, context) { Padding( padding: const EdgeInsets.only(left: 0), child: comfortatext(data.current.text, 32, data.settings, - weight: data.settings["Color mode"] == "dark" ? FontWeight.w600 : FontWeight.w400, color: data.palette.surface), + weight: data.settings["Color mode"] == "dark" ? FontWeight.w600 : FontWeight.w400, color: data.desc_color), ), ], ), @@ -96,7 +96,8 @@ Widget NewMain(data, updateLocation, context) { ], ), - NewSunriseSunset(data: data, key: Key(data.place), size: size,) + NewSunriseSunset(data: data, key: Key(data.place), size: size,), + NewAirQuality(data), /* NewTimes(data, true), buildHihiDays(data), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index d0ef7ef..419f176 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -22,6 +22,7 @@ import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:overmorrow/settings_page.dart'; import 'package:overmorrow/ui_helper.dart'; import 'decoders/decode_wapi.dart'; @@ -230,4 +231,77 @@ class _NewSunriseSunsetState extends State with SingleTickerPr }, ); } +} + +Widget NewAirQuality(var data) { + return Padding( + padding: const EdgeInsets.only(left: 22, right: 22, bottom: 19, top: 15), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 10, left: 5), + child: Align( + alignment: Alignment.centerLeft, + child: comfortatext(translation('air quality', data.settings["Language"]), 16, data.settings, + color: data.palette.primary), + ), + ), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + //border: Border.all(width: 1.2, color: data.current.textcolor) + color: data.palette.surfaceContainer + ), + padding: const EdgeInsets.all(11), + child: Row( + children: [ + Column( + children: [ + Container( + height: 85, + width: 85, + decoration: BoxDecoration( + color: data.current.primary, + borderRadius: BorderRadius.circular(20), + ), + child: Center( + child: Padding( + padding: const EdgeInsets.only(top: 5), + child: comfortatext(data.aqi.aqi_index.toString(), 38, data.settings, + color: data.current.backcolor), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 6), + child: Align( + alignment: Alignment.centerLeft, + child: SizedBox( + width: 120, + child: comfortatext( + translation(['good', 'moderate', 'slightly unhealthy', + 'unhealthy', 'very unhealthy', + 'hazardous'][data.aqi.aqi_index - 1], data.settings["Language"]), 15, data.settings, + color: data.current.textcolor, align: TextAlign.center) + ), + ), + ), + ], + ), + Expanded( + child: Column( + children: [ + NewAqiDataPoints("PM2.5", data.aqi.pm2_5, data), + NewAqiDataPoints("PM10", data.aqi.pm10, data), + NewAqiDataPoints("O3", data.aqi.o3, data), + NewAqiDataPoints("NO2", data.aqi.no2, data), + ], + ), + ) + ], + ), + ), + ], + ), + ); } \ No newline at end of file diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 25924c4..4d0585a 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -62,7 +62,6 @@ Widget searchBar(Color color, List recommend, borderRadius: BorderRadius.circular(23), backgroundColor: color, - //border: const BorderSide(width: 1.2, color: WHITE), accentColor: secondColor, elevation: 0, diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 5f81b61..a01429b 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -285,6 +285,61 @@ class DescriptionCircle extends StatelessWidget { } } +Widget NewAqiDataPoints(String name, double value, var data) { + return Padding( + padding: const EdgeInsets.only(left: 10, bottom: 4, top: 4), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 60, + child: comfortatext(name, 17, data.settings, color: data.palette.primary, + align: TextAlign.end) + ), + Container( + height: 12, + padding: EdgeInsets.only(left: 5), + child: ListView.builder( + itemExtent: 9.3, + scrollDirection: Axis.horizontal, + itemCount: 10, + shrinkWrap: true, + itemBuilder: (BuildContext context, int index) { + if (index < value / 13) { + return Center( + child: Container( + width: 3, + height: 11, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: data.gradientColors[index], + ), + ), + ); + } + return Center( + child: Container( + width: 4, + height: 4, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: data.palette.primaryFixedDim, + ), + ), + ); + } + ), + ), + SizedBox( + width: 40, + child: comfortatext(value.toString(), 18, data.settings, color: data.palette.primary, + align: TextAlign.end, weight: FontWeight.w600), + ), + ], + ), + ); +} + Widget aqiDataPoints(String name, double value, var data) { return Align( alignment: Alignment.centerRight, @@ -299,20 +354,20 @@ Widget aqiDataPoints(String name, double value, var data) { return SizedBox( width: width, child: Padding( - padding: const EdgeInsets.only(left: 10, bottom: 2, top: 2), + padding: const EdgeInsets.only(left: 10, bottom: 1.5, top: 1.5), child: Row( children: [ - comfortatext(name, 19, data.settings, color: data.current.textcolor, - weight: FontWeight.w500), + comfortatext(name, 18, data.settings, color: data.current.textcolor, + weight: FontWeight.w400), const Spacer(), Container( - padding: const EdgeInsets.only(top:5,bottom: 3, left: 4, right: 4), + padding: const EdgeInsets.only(top:4,bottom: 3, left: 4, right: 4), decoration: BoxDecoration( //border: Border.all(color: Colors.blueAccent) color: data.current.primary, borderRadius: BorderRadius.circular(10) ), - child: comfortatext(value.toString(), 18, data.settings, + child: comfortatext(value.toString(), 17, data.settings, color: data.current.highlight, weight: FontWeight.w600) ) ], diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 356378a..018d1b1 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -312,7 +312,7 @@ Map textToUnsplashText = { 'Clear Sky': 'blue sky', //it doesn't understand clear as much so i use blue instead 'Overcast': 'overcast', 'Haze': 'haze', - 'Rain': 'rain', + 'Rain': 'rain shower', 'Sleet': 'freezing rain',//this works much better 'Drizzle': 'light rain', //somehow understands it more though still not perfect 'Thunderstorm': 'thunderstorm', From f6258e2d2070db68846a4517a21f25750c237eb5 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 17 Jul 2024 17:43:52 +0200 Subject: [PATCH 028/129] i redesigned the aqi display (again). this i think looks better --- lib/decoders/extra_info.dart | 21 ++++++- lib/main_screens.dart | 2 +- lib/new_displays.dart | 114 +++++++++++++++++------------------ lib/settings_page.dart | 10 +-- lib/ui_helper.dart | 66 ++++++-------------- 5 files changed, 99 insertions(+), 114 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 714e046..d817b55 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -53,7 +53,7 @@ Future getUnsplashImage(var wapi_body, String real_loc) async { final url2 = Uri.https('api.unsplash.com', 'photos/random', params2); - var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query") + var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query ") .timeout(const Duration(seconds: 6)); var response2 = await file2.readAsString(); @@ -196,7 +196,7 @@ Future _generatorPalette(Image imageWidget) async { final double regionWidth = 50; final double regionHeight = 50; final Rect region = Rect.fromLTWH( - new_left + (40 / crop_absolute), + new_left + (50 / crop_absolute), new_top + (300 / crop_absolute), (regionWidth / crop_absolute), (regionHeight / crop_absolute), @@ -468,6 +468,8 @@ class WapiAqi { final double pm10; final double o3; final double no2; + final String aqi_title; + final String aqi_desc; const WapiAqi({ required this.no2, @@ -475,6 +477,8 @@ class WapiAqi { required this.pm2_5, required this.pm10, required this.aqi_index, + required this.aqi_desc, + required this.aqi_title, }); static WapiAqi fromJson(item) => WapiAqi( @@ -483,5 +487,18 @@ class WapiAqi { pm2_5: item["current"]["air_quality"]["pm2_5"], o3: item["current"]["air_quality"]["o3"], no2: item["current"]["air_quality"]["no2"], + + aqi_title: ['good', 'moderate', 'slightly unhealthy', + 'unhealthy', 'very unhealthy', + 'hazardous'][item["current"]["air_quality"]["us-epa-index"] - 1], + + aqi_desc: ['Air quality is excellent; no health risk.', + 'Acceptable air quality; minor risk for sensitive people.', + 'Sensitive individuals may experience mild effects.', + 'Health effects possible for everyone, serious for sensitive groups.', + 'Serious health effects for everyone.', + 'Emergency conditions; severe health effects for all.'] + [item["current"]["air_quality"]["us-epa-index"] - 1], + ); } \ No newline at end of file diff --git a/lib/main_screens.dart b/lib/main_screens.dart index ad305d6..7a45f94 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -45,7 +45,7 @@ Widget NewMain(data, updateLocation, context) { headerData: HeaderData( //backgroundColor: WHITE, blurContent: false, - headerHeight: max(size.height * 0.55, 400), //we don't want it to be smaller than 400 + headerHeight: max(size.height * 0.54, 400), //we don't want it to be smaller than 400 header: ParrallaxBackground(image: data.image, key: Key(data.place), color: data.current.backcolor == BLACK ? BLACK : lightAccent(data.current.backcolor, 5000)), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 419f176..6e977d0 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -165,7 +165,7 @@ class _NewSunriseSunsetState extends State with SingleTickerPr final textWidth = textPainter.width; return Padding( - padding: const EdgeInsets.only(left: 25, right: 25, top: 10), + padding: const EdgeInsets.only(left: 25, right: 25, top: 8), child: Column( children: [ Padding( @@ -235,72 +235,72 @@ class _NewSunriseSunsetState extends State with SingleTickerPr Widget NewAirQuality(var data) { return Padding( - padding: const EdgeInsets.only(left: 22, right: 22, bottom: 19, top: 15), + padding: const EdgeInsets.only(left: 22, right: 22, bottom: 19, top: 20), child: Column( children: [ Padding( - padding: const EdgeInsets.only(bottom: 10, left: 5), - child: Align( - alignment: Alignment.centerLeft, - child: comfortatext(translation('air quality', data.settings["Language"]), 16, data.settings, - color: data.palette.primary), - ), - ), - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - //border: Border.all(width: 1.2, color: data.current.textcolor) - color: data.palette.surfaceContainer - ), - padding: const EdgeInsets.all(11), + padding: const EdgeInsets.only(bottom: 6, left: 5), child: Row( children: [ - Column( - children: [ - Container( - height: 85, - width: 85, - decoration: BoxDecoration( - color: data.current.primary, - borderRadius: BorderRadius.circular(20), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.only(top: 5), - child: comfortatext(data.aqi.aqi_index.toString(), 38, data.settings, - color: data.current.backcolor), - ), - ), - ), - Padding( - padding: const EdgeInsets.only(top: 6), - child: Align( - alignment: Alignment.centerLeft, - child: SizedBox( - width: 120, - child: comfortatext( - translation(['good', 'moderate', 'slightly unhealthy', - 'unhealthy', 'very unhealthy', - 'hazardous'][data.aqi.aqi_index - 1], data.settings["Language"]), 15, data.settings, - color: data.current.textcolor, align: TextAlign.center) - ), - ), + comfortatext(translation('air quality', data.settings["Language"]), 16, data.settings, + color: data.palette.secondary), + Spacer(), + Padding( + padding: const EdgeInsets.only(right: 5), + child: Icon(Icons.arrow_forward, size: 16, color: data.palette.secondary,), + ) + ], + ), + ), + Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 5, top: 5, right: 14), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: data.palette.surfaceContainerLow + ), + width: 65, + height: 65, + child: Center( + child: comfortatext(data.aqi.aqi_index.toString(), 32, data.settings, color: data.palette.primaryFixedDim) + ), + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: Alignment.topLeft, + child: comfortatext( + translation(data.aqi.aqi_title, data.settings["Language"]), 20, data.settings, + color: data.palette.primaryFixedDim, align: TextAlign.left, weight: FontWeight.w600, ), + ), + Padding( + padding: const EdgeInsets.all(3.0), + child: comfortatext(data.aqi.aqi_desc, 14, data.settings, color: data.palette.secondary, + weight: FontWeight.w600), + ), ], ), - Expanded( - child: Column( - children: [ - NewAqiDataPoints("PM2.5", data.aqi.pm2_5, data), - NewAqiDataPoints("PM10", data.aqi.pm10, data), - NewAqiDataPoints("O3", data.aqi.o3, data), - NewAqiDataPoints("NO2", data.aqi.no2, data), - ], - ), - ) + ), + ], + ), + Padding( + padding: const EdgeInsets.only(top: 12, left: 13, right: 13), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + NewAqiDataPoints("PM2.5", data.aqi.pm2_5, data), + NewAqiDataPoints("PM10", data.aqi.pm10, data), + NewAqiDataPoints("O3", data.aqi.o3, data), + NewAqiDataPoints("NO2", data.aqi.no2, data), ], ), - ), + ) ], ), ); diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 7ce1fe1..045ab05 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -152,7 +152,7 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { colors = [ palette.surface, palette.primaryFixedDim, - palette.primary, + palette.secondary, palette.primaryFixedDim, palette.onPrimaryFixed, palette.primaryContainer @@ -161,11 +161,11 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { else if (x == "dark") { colors = [ palette.surface, + palette.primaryFixedDim, palette.secondary, - palette.onSecondaryContainer, - palette.secondary, - palette.onSurface, - palette.surfaceContainer + palette.primaryFixedDim, + palette.onPrimaryFixed, + palette.primaryContainer ]; } return colors; diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index a01429b..8d1ca2c 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -286,57 +286,25 @@ class DescriptionCircle extends StatelessWidget { } Widget NewAqiDataPoints(String name, double value, var data) { - return Padding( - padding: const EdgeInsets.only(left: 10, bottom: 4, top: 4), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox( - width: 60, - child: comfortatext(name, 17, data.settings, color: data.palette.primary, - align: TextAlign.end) - ), - Container( - height: 12, - padding: EdgeInsets.only(left: 5), - child: ListView.builder( - itemExtent: 9.3, - scrollDirection: Axis.horizontal, - itemCount: 10, - shrinkWrap: true, - itemBuilder: (BuildContext context, int index) { - if (index < value / 13) { - return Center( - child: Container( - width: 3, - height: 11, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: data.gradientColors[index], - ), - ), - ); - } - return Center( - child: Container( - width: 4, - height: 4, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: data.palette.primaryFixedDim, - ), - ), - ); - } + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + comfortatext(name, 15, data.settings, color: data.palette.secondary, + align: TextAlign.end), + Padding( + padding: const EdgeInsets.all(3.0), + child: Container( + width: 2.5, + height: 2.5, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: data.palette.primaryFixedDim, ), ), - SizedBox( - width: 40, - child: comfortatext(value.toString(), 18, data.settings, color: data.palette.primary, - align: TextAlign.end, weight: FontWeight.w600), - ), - ], - ), + ), + comfortatext(value.toString(), 15, data.settings, color: data.palette.primaryFixedDim, + align: TextAlign.end, weight: FontWeight.w600), + ], ); } From b980f5cee137bdfd2c1d4e573fa323d7f378b6c0 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 18 Jul 2024 16:31:23 +0200 Subject: [PATCH 029/129] added a totally new display, which shows the expected rain --- lib/caching.dart | 19 ++- lib/decoders/decode_OM.dart | 71 +++++++++- lib/decoders/extra_info.dart | 24 +++- lib/main_screens.dart | 5 +- lib/new_displays.dart | 252 ++++++++++++++++++++++++++--------- lib/settings_page.dart | 2 +- lib/ui_helper.dart | 2 +- 7 files changed, 303 insertions(+), 72 deletions(-) diff --git a/lib/caching.dart b/lib/caching.dart index 8cf56b3..7ce253b 100644 --- a/lib/caching.dart +++ b/lib/caching.dart @@ -37,14 +37,31 @@ class MyGetResponse implements FileServiceResponse { @override DateTime get validTill { - if (url.toString().contains("search.json")) { + if (url.toString().contains("search.json")) { //search results are stored for 20 days return DateTime.now().add(const Duration(days: 20)); } + + //snap to the next quarter hour because that's when the weather data updates + DateTime now = DateTime.now(); + int minutes = now.minute; + int nextQuarter = (minutes + 15 - minutes % 15) % 60; + int hoursToAdd = nextQuarter == 0 ? 1 : 0; + + return DateTime( + now.year, + now.month, + now.day, + now.hour + hoursToAdd, + nextQuarter, + ); + + /* return DateTime.now().add( Duration(minutes: 60 - DateTime.now().minute, seconds: 60 - DateTime.now().second) ); + */ } @override diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 5c2eb1b..e971bde 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -18,6 +18,7 @@ along with this program. If not, see . import 'dart:convert'; +import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart'; @@ -34,11 +35,13 @@ Future OMRequestData(double lat, double lng, String real_loc) async { final oMParams = { "latitude": lat.toString(), "longitude": lng.toString(), + "minutely_15" : ["precipitation"], "current": ["temperature_2m", "relative_humidity_2m", "apparent_temperature", "weather_code", "wind_speed_10m", 'wind_direction_10m'], "hourly": ["temperature_2m", "precipitation", "weather_code", "wind_speed_10m"], "daily": ["weather_code", "temperature_2m_max", "temperature_2m_min", "uv_index_max", "precipitation_sum", "precipitation_probability_max", "wind_speed_10m_max", "wind_direction_10m_dominant"], "timezone": "auto", - "forecast_days": "14" + "forecast_days": "14", + "forecast_minutely_15" : "24", }; final oMUrl = Uri.https("api.open-meteo.com", 'v1/forecast', oMParams); @@ -306,6 +309,72 @@ class OMDay { } } +class OM15MinutePrecip { + final String t_minus; + final int precip_sum; + final List precips; + + const OM15MinutePrecip({ + required this.t_minus, + required this.precip_sum, + required this.precips, + }); + + static OM15MinutePrecip fromJson(item, settings) { + + int closest = 100; + int end = 0; + double sum = 0; + + List precips = []; + + for (int i = 0; i < item["minutely_15"]["precipitation"].length; i++) { + double x = item["minutely_15"]["precipitation"][i]; + print(x); + if (x > 0.2) { + if (closest == 100) { + closest = i + 1; + } + if (i > end) { + end = i + 1; + } + } + sum += x; + + precips.add(x); + } + + String t_minus = ""; + if (closest != 100) { + if (closest <= 2) { + if (end == 2) { + t_minus = "the next half an hour"; + } + else if (end <= 4) { + t_minus = "the next ${[15, 30, 45][closest]} minutes"; + } + else { + t_minus = "the next ${closest ~/ 4} hours"; + } + } + else if (closest < 4) { + t_minus = "${[15, 30, 45][closest - 1]} minutes"; + } + else { + t_minus = "${closest ~/ 4} hours"; + } + } + + sum = max(sum, 1); // if there is rain then it shouldn't write 0 + + return OM15MinutePrecip( + t_minus: t_minus, + precip_sum: unit_coversion(sum, settings["Precipitation"]).toInt(), + precips: precips, + ); + } +} + class OMHour { final int temp; final String icon; diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index d817b55..b98034e 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -73,12 +73,12 @@ Future getImageColors(Image Uimage, color_mode) async { final ColorScheme palette = await _materialPalette(Uimage, color_mode); final PaletteGenerator pali = await _generatorPalette(Uimage); - final Color dominant = averageColor(pali.colors.toList()); + final List dominant = pali.colors.toList(); Color startcolor = palette.primaryFixedDim; Color bestcolor = palette.primaryFixedDim; - int bestDif = difBetweenTwoColors(bestcolor, dominant); + int bestDif = difFromBackColors(bestcolor, dominant); print(dominant); @@ -88,7 +88,7 @@ Future getImageColors(Image Uimage, color_mode) async { for (int i = 1; i < 4; i++) { //LIGHT Color newcolor = lighten(startcolor, i / 20); - int newdif = difBetweenTwoColors(newcolor, dominant); + int newdif = difFromBackColors(newcolor, dominant); if (newdif > bestDif && newdif < 500) { bestDif = newdif; bestcolor = newcolor; @@ -96,7 +96,7 @@ Future getImageColors(Image Uimage, color_mode) async { //DARK newcolor = darken(startcolor, i / 20); - newdif = difBetweenTwoColors(newcolor, dominant); + newdif = difFromBackColors(newcolor, dominant); if (newdif > bestDif && newdif < 500) { bestDif = newdif; bestcolor = newcolor; @@ -105,7 +105,7 @@ Future getImageColors(Image Uimage, color_mode) async { } Color desc_color = palette.surface; - int desc_dif = difBetweenTwoColors(desc_color, dominant); + int desc_dif = difFromBackColors(desc_color, dominant); print(("desc_dif", desc_dif)); @@ -134,6 +134,14 @@ List getGradientColors(Color color1, Color color2, int number) { return colors; } +int difFromBackColors(Color frontColor, List backcolors) { + int smallest = 2000; + for (int i = 0; i < backcolors.length; i++) { + smallest = min(smallest, difBetweenTwoColors(frontColor, backcolors[i])); + } + return smallest; +} + int difBetweenTwoColors(Color color1, Color color2) { int r = (color1.red - color2.red).abs(); int g = (color1.green - color2.green).abs(); @@ -252,6 +260,7 @@ class WeatherData { final aqi; final sunstatus; final radar; + final minutely_15_precip; final fetch_datetime; @@ -284,6 +293,7 @@ class WeatherData { required this.colorpop, required this.desc_color, required this.gradientColors, + required this.minutely_15_precip, }); static Future getFullData(settings, placeName, real_loc, latlong, provider) async { @@ -343,6 +353,9 @@ class WeatherData { colorpop: imageColors[1], desc_color: imageColors[2], gradientColors: imageColors[3], + minutely_15_precip: const OM15MinutePrecip(t_minus: "", precip_sum: 0, + precips: []), //because wapi doesn't have 15 minutely + ); } else { @@ -359,6 +372,7 @@ class WeatherData { radar: await RainviewerRadar.getData(), aqi: WapiAqi.fromJson(wapi_body), sunstatus: WapiSunstatus.fromJson(wapi_body, settings), + minutely_15_precip: OM15MinutePrecip.fromJson(oMBody, settings), current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, imageColors[0]), //await _generatorPalette(hihi)), diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 7a45f94..bc338f4 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -97,10 +97,13 @@ Widget NewMain(data, updateLocation, context) { ), NewSunriseSunset(data: data, key: Key(data.place), size: size,), + NewRain15MinuteIndicator(data), NewAirQuality(data), + + buildHihiDays(data), /* NewTimes(data, true), - buildHihiDays(data), + buildGlanceDay(data), providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 6e977d0..130e4fc 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -55,7 +55,8 @@ class WavePainter extends CustomPainter { final splitPoint = hihi * size.width; for (double x = 0; x <= splitPoint; x++) { - final y = size.height / 2 + amplitude * sin((x / frequency * 2 * pi) + (waveValue * 2 * pi)); + final y = size.height / 2 + + amplitude * sin((x / frequency * 2 * pi) + (waveValue * 2 * pi)); if (x == 0) { path.moveTo(x, y); } else { @@ -66,7 +67,8 @@ class WavePainter extends CustomPainter { path.reset(); for (double x = splitPoint; x <= size.width; x++) { - final y = size.height / 2 + amplitude * sin((x / frequency * 2 * pi) + (waveValue * 2 * pi)); + final y = size.height / 2 + + amplitude * sin((x / frequency * 2 * pi) + (waveValue * 2 * pi)); if (x == splitPoint) { path.moveTo(x, y); } else { @@ -93,8 +95,8 @@ class NewSunriseSunset extends StatefulWidget { _NewSunriseSunsetState createState() => _NewSunriseSunsetState(); } -class _NewSunriseSunsetState extends State with SingleTickerProviderStateMixin { - +class _NewSunriseSunsetState extends State + with SingleTickerProviderStateMixin { late DateTime riseDT; late int total; late int hourdif; @@ -103,7 +105,8 @@ class _NewSunriseSunsetState extends State with SingleTickerPr @override void initState() { - final List absoluteSunriseSunset = widget.data.sunstatus.absoluteSunriseSunset.split('/'); + final List absoluteSunriseSunset = + widget.data.sunstatus.absoluteSunriseSunset.split('/'); final List absoluteRise = absoluteSunriseSunset[0].split(':'); final List absoluteSet = absoluteSunriseSunset[1].split(':'); @@ -112,10 +115,14 @@ class _NewSunriseSunsetState extends State with SingleTickerPr print(("riseSet", absoluteRise, absoluteSet, absoluteLocalTime)); final currentTime = DateTime.now(); - riseDT = currentTime.copyWith(hour: int.parse(absoluteRise[0]), minute: int.parse(absoluteRise[1])); - final setDT = currentTime.copyWith(hour: int.parse(absoluteSet[0]), minute: int.parse(absoluteSet[1])); + riseDT = currentTime.copyWith( + hour: int.parse(absoluteRise[0]), minute: int.parse(absoluteRise[1])); + final setDT = currentTime.copyWith( + hour: int.parse(absoluteSet[0]), minute: int.parse(absoluteSet[1])); - final localtimeOld = currentTime.copyWith(hour: int.parse(absoluteLocalTime[0]), minute: int.parse(absoluteLocalTime[1])); + final localtimeOld = currentTime.copyWith( + hour: int.parse(absoluteLocalTime[0]), + minute: int.parse(absoluteLocalTime[1])); hourdif = localtimeOld.hour - currentTime.hour; @@ -139,7 +146,6 @@ class _NewSunriseSunsetState extends State with SingleTickerPr return AnimatedBuilder( animation: _controller, builder: (context, child) { - DateTime now = DateTime.now(); DateTime localTime = now.add(Duration(hours: hourdif)); @@ -147,19 +153,21 @@ class _NewSunriseSunsetState extends State with SingleTickerPr final double progress = min(max(thisdif / total, 0), 1); String write = widget.data.settings["Time mode"] == "24 hour" - ? convertTime("${localTime.hour}:${localTime.minute} j") //the j is just added so when splitting - : amPmTime("${localTime.hour}:${localTime.minute} j"); //it can grab the first item - - + ? convertTime( + "${localTime.hour}:${localTime.minute} j") //the j is just added so when splitting + : amPmTime( + "${localTime.hour}:${localTime.minute} j"); //it can grab the first item //this is all so that the text will be right above the progress final textPainter = TextPainter( - text: TextSpan(text: write, style: GoogleFonts.comfortaa( - fontSize: 15.0 * getFontSize(widget.data.settings["Font size"]), - fontWeight: FontWeight.w500 - ),), - textDirection: TextDirection.ltr - ); + text: TextSpan( + text: write, + style: GoogleFonts.comfortaa( + fontSize: + 15.0 * getFontSize(widget.data.settings["Font size"]), + fontWeight: FontWeight.w500), + ), + textDirection: TextDirection.ltr); textPainter.layout(); final textWidth = textPainter.width; @@ -169,19 +177,26 @@ class _NewSunriseSunsetState extends State with SingleTickerPr child: Column( children: [ Padding( - padding: EdgeInsets.only(left: - min(max((progress * (widget.size.width - 50)) - textWidth / 2 - 3, 0), - widget.size.width - 55 - textWidth)), + padding: EdgeInsets.only( + left: min( + max( + (progress * (widget.size.width - 50)) - + textWidth / 2 - + 3, + 0), + widget.size.width - 55 - textWidth)), child: Align( alignment: Alignment.centerLeft, - child: comfortatext(write, 15, widget.data.settings, color: widget.data.palette.secondary, - weight: FontWeight.w500), + child: comfortatext(write, 15, widget.data.settings, + color: widget.data.palette.secondary, + weight: FontWeight.w500), ), ), Padding( - padding: EdgeInsets.only(top: 6, - left: min(max((progress * (widget.size.width - 50)) - 5, 2), widget.size.width - 52) - ), + padding: EdgeInsets.only( + top: 6, + left: min(max((progress * (widget.size.width - 50)) - 5, 2), + widget.size.width - 52)), child: Align( alignment: Alignment.centerLeft, child: Container( @@ -195,10 +210,14 @@ class _NewSunriseSunsetState extends State with SingleTickerPr ), ), Padding( - padding: const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5), + padding: + const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5), child: CustomPaint( - painter: WavePainter(_controller.value, widget.data.palette.primaryFixedDim, - darken(widget.data.palette.surfaceVariant, 0.03), progress), + painter: WavePainter( + _controller.value, + widget.data.palette.primaryFixedDim, + darken(widget.data.palette.surfaceVariant, 0.03), + progress), child: Container( width: double.infinity, height: 8.0, @@ -211,16 +230,25 @@ class _NewSunriseSunsetState extends State with SingleTickerPr children: [ Padding( padding: const EdgeInsets.only(right: 4), - child: Icon(Icons.wb_sunny_outlined, color: widget.data.palette.primaryFixedDim, size: 14,), + child: Icon( + Icons.wb_sunny_outlined, + color: widget.data.palette.primaryFixedDim, + size: 14, + ), ), - comfortatext(widget.data.sunstatus.sunrise, 15, widget.data.settings, - color: widget.data.palette.primaryFixedDim, weight: FontWeight.w500), - Spacer(), - comfortatext(widget.data.sunstatus.sunset, 15, widget.data.settings, - color: widget.data.palette.outline, weight: FontWeight.w500), + comfortatext( + widget.data.sunstatus.sunrise, 15, widget.data.settings, + color: widget.data.palette.primaryFixedDim, + weight: FontWeight.w500), + const Spacer(), + comfortatext( + widget.data.sunstatus.sunset, 15, widget.data.settings, + color: widget.data.palette.outline, + weight: FontWeight.w500), Padding( padding: const EdgeInsets.only(left: 4), - child: Icon(Icons.nightlight_outlined, color: widget.data.palette.outline, size: 14), + child: Icon(Icons.nightlight_outlined, + color: widget.data.palette.outline, size: 14), ), ], ), @@ -242,12 +270,19 @@ Widget NewAirQuality(var data) { padding: const EdgeInsets.only(bottom: 6, left: 5), child: Row( children: [ - comfortatext(translation('air quality', data.settings["Language"]), 16, data.settings, - color: data.palette.secondary), - Spacer(), + comfortatext( + translation('air quality', data.settings["Language"]), + 16, + data.settings, + color: data.palette.primary), + const Spacer(), Padding( padding: const EdgeInsets.only(right: 5), - child: Icon(Icons.arrow_forward, size: 16, color: data.palette.secondary,), + child: Icon( + Icons.arrow_forward, + size: 16, + color: data.palette.primary, + ), ) ], ), @@ -258,32 +293,37 @@ Widget NewAirQuality(var data) { padding: const EdgeInsets.only(left: 5, top: 5, right: 14), child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: data.palette.surfaceContainerLow - ), + borderRadius: BorderRadius.circular(15), + color: data.palette.surfaceContainerLow), width: 65, height: 65, child: Center( - child: comfortatext(data.aqi.aqi_index.toString(), 32, data.settings, color: data.palette.primaryFixedDim) - ), + child: comfortatext( + data.aqi.aqi_index.toString(), 32, data.settings, + color: data.palette.primaryFixedDim)), ), ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Align( - alignment: Alignment.topLeft, - child: comfortatext( - translation(data.aqi.aqi_title, data.settings["Language"]), 20, data.settings, - color: data.palette.primaryFixedDim, align: TextAlign.left, weight: FontWeight.w600, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: Alignment.topLeft, + child: comfortatext( + translation( + data.aqi.aqi_title, data.settings["Language"]), + 20, + data.settings, + color: data.palette.primaryFixedDim, + align: TextAlign.left, + weight: FontWeight.w600, + ), + ), + Padding( + padding: const EdgeInsets.all(3.0), + child: comfortatext(data.aqi.aqi_desc, 14, data.settings, + color: data.palette.primary, weight: FontWeight.w600), ), - ), - Padding( - padding: const EdgeInsets.all(3.0), - child: comfortatext(data.aqi.aqi_desc, 14, data.settings, color: data.palette.secondary, - weight: FontWeight.w600), - ), ], ), ), @@ -304,4 +344,92 @@ Widget NewAirQuality(var data) { ], ), ); -} \ No newline at end of file +} + +Widget NewRain15MinuteIndicator(var data) { + return Visibility( + visible: data.minutely_15_precip.t_minus != "", + child: Padding( + padding: const EdgeInsets.only(left: 21, right: 21, top: 18, bottom: 10), + child: Container( + decoration: BoxDecoration( + color: data.palette.surfaceContainerLow, + borderRadius: BorderRadius.circular(18), + ), + padding: const EdgeInsets.all(18), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Padding( + padding: + const EdgeInsets.only(left: 5, bottom: 2, right: 5), + child: Icon( + Icons.water_drop_outlined, + color: data.palette.primary, + size: 20, + ), + ), + comfortatext(data.minutely_15_precip.precip_sum.toString(), + 20, data.settings, + color: data.palette.primary), + comfortatext( + data.settings["Precipitation"], 20, data.settings, + color: data.palette.primary), + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 8), + child: comfortatext( + "rain expected in ${data.minutely_15_precip.t_minus}", + 14, + data.settings, + color: data.palette.onPrimaryContainer), + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.only(top: 14, bottom: 10), + child: SizedBox( + height: 30, + child: ListView.builder( + itemExtent: 11, + scrollDirection: Axis.horizontal, + itemCount: data.minutely_15_precip.precips.length, + shrinkWrap: true, + itemBuilder: (BuildContext context, int index) { + return Center( + child: Container( + width: 3.5, + height: 3.5 + data.minutely_15_precip.precips[index] * 40, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: data.minutely_15_precip.precips[index] == 0 + ? data.palette.primaryFixedDim : data.palette.primary, + ), + ), + ); + } + ) + ), + ), + SizedBox( + height: 10, + width: 11.0 * data.minutely_15_precip.precips.length + 11, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + comfortatext('now', 13, data.settings, color: data.palette.onPrimaryContainer), + comfortatext('3hr', 13, data.settings, color: data.palette.onPrimaryContainer), + comfortatext('6hr', 13, data.settings, color: data.palette.onPrimaryContainer) + ], + ), + ) + ], + ), + ), + ) + ); +} diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 045ab05..3001b6b 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -152,7 +152,7 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { colors = [ palette.surface, palette.primaryFixedDim, - palette.secondary, + palette.primary, palette.primaryFixedDim, palette.onPrimaryFixed, palette.primaryContainer diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 8d1ca2c..949ee91 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -289,7 +289,7 @@ Widget NewAqiDataPoints(String name, double value, var data) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - comfortatext(name, 15, data.settings, color: data.palette.secondary, + comfortatext(name, 15, data.settings, color: data.palette.primary, align: TextAlign.end), Padding( padding: const EdgeInsets.all(3.0), From 36c4549f27b9db4080965554977d77c85a001d4b Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 18 Jul 2024 16:41:15 +0200 Subject: [PATCH 030/129] removed all unused prints --- lib/decoders/decode_OM.dart | 1 - lib/decoders/decode_mn.dart | 2 -- lib/decoders/decode_wapi.dart | 1 - lib/decoders/extra_info.dart | 14 +------------- lib/main.dart | 7 ------- lib/main_ui.dart | 2 -- lib/new_displays.dart | 2 -- lib/ui_helper.dart | 4 ---- 8 files changed, 1 insertion(+), 32 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index e971bde..0cd8808 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -330,7 +330,6 @@ class OM15MinutePrecip { for (int i = 0; i < item["minutely_15"]["precipitation"].length; i++) { double x = item["minutely_15"]["precipitation"][i]; - print(x); if (x > 0.2) { if (closest == 100) { closest = i + 1; diff --git a/lib/decoders/decode_mn.dart b/lib/decoders/decode_mn.dart index 5e6d6a0..78e165b 100644 --- a/lib/decoders/decode_mn.dart +++ b/lib/decoders/decode_mn.dart @@ -180,8 +180,6 @@ class MetNDay { index += 1; } - print(("hihihihihih", begin, end)); - //now we know the timestamps for the beginning and the end of the day List temperatures = []; diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index 24f016e..f0d629a 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -197,7 +197,6 @@ String getName(index, settings) { String backdropCorrection(name, isday) { String text = textCorrection(name, isday); - print((name, text)); String backdrop = weather_refactor.textBackground[text] ?? "haze.jpg"; return backdrop; } diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index b98034e..177827c 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -40,8 +40,7 @@ Future getUnsplashImage(var wapi_body, String real_loc) async { String text_query = textToUnsplashText[_text]!; - String addon = wapi_body["current"]["is_day"] == 1 ? 'daytime' : 'nighttime'; - print(addon); + //String addon = wapi_body["current"]["is_day"] == 1 ? 'daytime' : 'nighttime'; final params2 = { 'client_id': access_key, @@ -80,10 +79,6 @@ Future getImageColors(Image Uimage, color_mode) async { Color bestcolor = palette.primaryFixedDim; int bestDif = difFromBackColors(bestcolor, dominant); - print(dominant); - - print(("bestdif", bestDif)); - if (bestDif < 300) { for (int i = 1; i < 4; i++) { //LIGHT @@ -199,8 +194,6 @@ Future _generatorPalette(Image imageWidget) async { final new_left = center_x - ((desiredSquare / 2) / crop_absolute); final new_top = center_y - ((desiredSquare / 2) / crop_absolute); - print((new_left, new_top, crop_absolute, (desiredSquare / 2) / crop_absolute)); - final double regionWidth = 50; final double regionHeight = 50; final Rect region = Rect.fromLTWH( @@ -210,9 +203,6 @@ Future _generatorPalette(Image imageWidget) async { (regionHeight / crop_absolute), ); - print(("original image", imageWidth, imageHeight)); - print(("cropped image",new_left + 30, new_top + 330, regionWidth, regionHeight,)); - PaletteGenerator _paletteGenerator = await PaletteGenerator.fromImage( imageInfo.image, region: region, @@ -432,8 +422,6 @@ class RainviewerRadar { for (var x in past) { DateTime time = DateTime.fromMillisecondsSinceEpoch(x["time"]); - //print("${time.hour}h ${time.minute}m"); - //print(host + x["path"]); images.add(host + x["path"]); times.add("${time.hour}h ${time.minute}m"); } diff --git a/lib/main.dart b/lib/main.dart index 4e2e932..116f90e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -66,7 +66,6 @@ class _MyAppState extends State { Map settings = await getSettingsUsed(); String weather_provider = await getWeatherProvider(); - //print(weather_provider); if (startup) { List n = await getLastPlace(); //loads the last place you visited @@ -79,9 +78,7 @@ class _MyAppState extends State { bool isItCurrentLocation = false; if (backupName == 'CurrentLocation') { - print("almost therre"); String loc_status = await isLocationSafe(); - print("got past"); if (loc_status == "enabled") { Position position; try { @@ -163,7 +160,6 @@ class _MyAppState extends State { icon: Icons.wifi_off, place: backupName, settings: settings, provider: weather_provider, latlng: absoluteProposed,); } on HttpExceptionWithStatus catch (hihi){ - print(hihi.toString()); return dumbySearch(errorMessage: "general error at place 1: ${hihi.toString()}", updateLocation: updateLocation, icon: Icons.bug_report, place: backupName, settings: settings, provider: weather_provider, latlng: absoluteProposed,); @@ -174,8 +170,6 @@ class _MyAppState extends State { place: backupName, settings: settings, provider: weather_provider, latlng: absoluteProposed,); } - print("temp:${weatherdata.current.temp}"); - await setLastPlace(backupName, absoluteProposed); // if the code didn't fail // then this will be the new startup @@ -290,7 +284,6 @@ class _MyAppState extends State { List getStartBackColor() { var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; - print(brightness); bool isDarkMode = brightness == Brightness.dark; Color back = isDarkMode ? BLACK : WHITE; Color front = isDarkMode ? const Color.fromRGBO(250, 250, 250, 0.7) : const Color.fromRGBO(0, 0, 0, 0.3); diff --git a/lib/main_ui.dart b/lib/main_ui.dart index b4518b4..4c9d243 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -56,8 +56,6 @@ class WeatherPage extends StatelessWidget { //return PhoneLayout(data, updateLocation, context); - print("temphehe:${data.current.temp}"); - return NewMain(data, updateLocation, context,); } diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 130e4fc..0487714 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -112,8 +112,6 @@ class _NewSunriseSunsetState extends State final List absoluteSet = absoluteSunriseSunset[1].split(':'); final List absoluteLocalTime = widget.data.localtime.split(':'); - print(("riseSet", absoluteRise, absoluteSet, absoluteLocalTime)); - final currentTime = DateTime.now(); riseDT = currentTime.copyWith( hour: int.parse(absoluteRise[0]), minute: int.parse(absoluteRise[1])); diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 949ee91..c9009c2 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -89,7 +89,6 @@ Color darken(Color color, [double amount = .1]) { Color lightAccent(Color color, int intensity) { double x = intensity / (color.red + color.green + color.blue); - print((x, (color.red * x).toInt(), (color.green * x).toInt(), (color.blue * x).toInt())); return Color.fromRGBO(sqrt(color.red * x).toInt(), sqrt(color.green * x).toInt(), sqrt(color.blue * x).toInt(), 1); } @@ -354,7 +353,6 @@ Widget WindWidget(data, day) { for (var i = 0; i < hours.length; i+= 2) { double x = min(round((hours[i].wind + hours[i + 1].wind) * 0.5, decimals: 0) / 2, 10); - print((hours[i].wind, x)); wind.add(x); } @@ -683,8 +681,6 @@ Future> getOMReccomend(String query, settings) async { x = x.replaceAll('latitude', "lat"); x = x.replaceAll('longitude', "lon"); - print(('got here', x)); - recomendations.add(x); } return recomendations; From 35c9004ed6cc4da4018e1d0e05b6f957af081128 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 18 Jul 2024 17:18:46 +0200 Subject: [PATCH 031/129] slight improvements to the next rain indicator --- lib/decoders/decode_OM.dart | 23 ++++++++++++++--------- lib/decoders/extra_info.dart | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 0cd8808..11389e0 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -18,7 +18,6 @@ along with this program. If not, see . import 'dart:convert'; -import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart'; @@ -311,7 +310,7 @@ class OMDay { class OM15MinutePrecip { final String t_minus; - final int precip_sum; + final double precip_sum; final List precips; const OM15MinutePrecip({ @@ -330,7 +329,7 @@ class OM15MinutePrecip { for (int i = 0; i < item["minutely_15"]["precipitation"].length; i++) { double x = item["minutely_15"]["precipitation"][i]; - if (x > 0.2) { + if (x > 0.0) { if (closest == 100) { closest = i + 1; } @@ -343,32 +342,38 @@ class OM15MinutePrecip { precips.add(x); } + print(("closest", closest)); + String t_minus = ""; if (closest != 100) { if (closest <= 2) { if (end == 2) { t_minus = "the next half an hour"; } - else if (end <= 4) { - t_minus = "the next ${[15, 30, 45][closest]} minutes"; + else if (end < 4) { + t_minus = "the next ${[15, 30, 45][end - 1]} minutes"; + } + else if (end ~/ 4 == 1) { + t_minus = "the next 1 hour"; } else { - t_minus = "the next ${closest ~/ 4} hours"; + t_minus = "the next ${end ~/ 4} hours"; } } else if (closest < 4) { t_minus = "${[15, 30, 45][closest - 1]} minutes"; } + else if (closest ~/ 4 == 1) { + t_minus = "1 hour"; + } else { t_minus = "${closest ~/ 4} hours"; } } - sum = max(sum, 1); // if there is rain then it shouldn't write 0 - return OM15MinutePrecip( t_minus: t_minus, - precip_sum: unit_coversion(sum, settings["Precipitation"]).toInt(), + precip_sum: unit_coversion(sum, settings["Precipitation"]), precips: precips, ); } diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 177827c..b5c21b7 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -52,7 +52,7 @@ Future getUnsplashImage(var wapi_body, String real_loc) async { final url2 = Uri.https('api.unsplash.com', 'photos/random', params2); - var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query ") + var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query") .timeout(const Duration(seconds: 6)); var response2 = await file2.readAsString(); From d62bfc794dd35383d797c12879336b99ca9c2944 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 18 Jul 2024 17:32:58 +0200 Subject: [PATCH 032/129] some extra small improvements to the overall design --- lib/new_displays.dart | 4 ++-- lib/search_screens.dart | 2 +- lib/weather_refact.dart | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 0487714..e9c0ff6 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -363,7 +363,7 @@ Widget NewRain15MinuteIndicator(var data) { children: [ Padding( padding: - const EdgeInsets.only(left: 5, bottom: 2, right: 5), + const EdgeInsets.only(left: 5, bottom: 2, right: 3), child: Icon( Icons.water_drop_outlined, color: data.palette.primary, @@ -372,7 +372,7 @@ Widget NewRain15MinuteIndicator(var data) { ), comfortatext(data.minutely_15_precip.precip_sum.toString(), 20, data.settings, - color: data.palette.primary), + color: data.palette.primary, weight: FontWeight.w500), comfortatext( data.settings["Precipitation"], 20, data.settings, color: data.palette.primary), diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 4d0585a..ddafd67 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -43,7 +43,7 @@ Widget searchBar(Color color, List recommend, hint: translation('Search...', settings["Language"]!), title: Container( padding: const EdgeInsets.only(left: 5, top: 3), - child: comfortatext(place, 25, settings, color: textColor, weight: FontWeight.w400) + child: comfortatext(place, 24, settings, color: textColor, weight: FontWeight.w400) ), hintStyle: GoogleFonts.comfortaa( color: textColor, diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 018d1b1..f223e60 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -310,7 +310,7 @@ Map textToUnsplashText = { 'Clear Night': 'night', //somehow just 'night' always gives you clear skies: stars or moon 'Partly Cloudy': 'cloudy', //this is also some simplification which improves a lot 'Clear Sky': 'blue sky', //it doesn't understand clear as much so i use blue instead - 'Overcast': 'overcast', + 'Overcast': 'dark clouds', //kinda works 'Haze': 'haze', 'Rain': 'rain shower', 'Sleet': 'freezing rain',//this works much better From d5cdd865438b0bbd3656b4fd00d76e08d9375775 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 19 Jul 2024 18:52:35 +0200 Subject: [PATCH 033/129] fixed 2 bugs --- lib/decoders/decode_OM.dart | 6 +++++- lib/new_displays.dart | 2 +- lib/weather_refact.dart | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 11389e0..8bc716b 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -18,6 +18,7 @@ along with this program. If not, see . import 'dart:convert'; +import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart'; @@ -271,6 +272,7 @@ class OMDay { }); static OMDay build(item, settings, index, sunstatus) { + return OMDay( uv: item["daily"]["uv_index_max"][0].round(), icon: oMIconCorrection(oMTextCorrection(item["daily"]["weather_code"][index])), @@ -322,7 +324,7 @@ class OM15MinutePrecip { static OM15MinutePrecip fromJson(item, settings) { int closest = 100; - int end = 0; + int end = -1; double sum = 0; List precips = []; @@ -344,6 +346,8 @@ class OM15MinutePrecip { print(("closest", closest)); + sum = max(sum, 0.1); //if there is rain then it shouldn't write 0 + String t_minus = ""; if (closest != 100) { if (closest <= 2) { diff --git a/lib/new_displays.dart b/lib/new_displays.dart index e9c0ff6..a7f5849 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -370,7 +370,7 @@ Widget NewRain15MinuteIndicator(var data) { size: 20, ), ), - comfortatext(data.minutely_15_precip.precip_sum.toString(), + comfortatext(data.minutely_15_precip.precip_sum.toStringAsFixed(1), 20, data.settings, color: data.palette.primary, weight: FontWeight.w500), comfortatext( diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index f223e60..630b7f3 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -201,7 +201,7 @@ Map OMCodes = { 86: 'Heavy Snow', 95: 'Thunderstorm', 96: 'Thunderstorm', - 99: 'thunderstorm', + 99: 'Thunderstorm', }; Map textBackground = { From e49b05a80bda3f432e52c24f77a9d608ddb835b2 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 22 Jul 2024 13:07:14 +0200 Subject: [PATCH 034/129] totally restructured the data fetching so that they work independently of each other. --- lib/decoders/decode_OM.dart | 201 +++++++++++++++++++++++++++++++++- lib/decoders/decode_wapi.dart | 145 +++++++++++++++++++++++- lib/decoders/extra_info.dart | 172 +---------------------------- lib/main_screens.dart | 3 +- lib/new_displays.dart | 9 +- lib/radar.dart | 179 ++++++++---------------------- lib/ui_helper.dart | 32 +++--- lib/weather_refact.dart | 2 +- 8 files changed, 416 insertions(+), 327 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 8bc716b..247301f 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -31,14 +31,74 @@ import '../ui_helper.dart'; import '../weather_refact.dart'; import 'extra_info.dart'; -Future OMRequestData(double lat, double lng, String real_loc) async { +String OMConvertTime(String time) { + print(("time", time)); + return time.split("T")[1]; +} + +String OMamPmTime(String time) { + print(("time", time)); + String a = time.split("T")[1]; + List num = a.split(":"); + int hour = int.parse(num[0]); + + if (hour > 12) { + int x = hour - 12; + if (x < 10) { + return "0${hour - 12}:${num[1]}"; + } + return "${hour - 12}:${num[1]}"; + } + + return "${num[0]}:${num[1]}"; +} + +int AqiIndexCorrection(int aqi) { + if (aqi <= 20) { + return 1; + } + if (aqi <= 40) { + return 2; + } + if (aqi <= 60) { + return 3; + } + if (aqi <= 80) { + return 4; + } + if (aqi <= 100) { + return 5; + } + return 6; +} + +DateTime OMGetLocalTime(item) { + return DateTime.now().toUtc().add(Duration(seconds: item["utc_offset_seconds"])); +} + +double OMGetSunStatus(item) { + DateTime localtime = OMGetLocalTime(item); + + List splitted1 = item["daily"]["sunrise"][0].split("T")[1].split(":"); + DateTime sunrise = localtime.copyWith(hour: int.parse(splitted1[0]), minute: int.parse(splitted1[1])); + + List splitted2 = item["daily"]["sunset"][0].split("T")[1].split(":"); + DateTime sunset = localtime.copyWith(hour: int.parse(splitted2[0]), minute: int.parse(splitted1[1])); + + int total = sunset.difference(sunrise).inMinutes; + int passed = localtime.difference(sunrise).inMinutes; + + return passed / total; +} + +Future> OMRequestData(double lat, double lng, String real_loc) async { final oMParams = { "latitude": lat.toString(), "longitude": lng.toString(), "minutely_15" : ["precipitation"], "current": ["temperature_2m", "relative_humidity_2m", "apparent_temperature", "weather_code", "wind_speed_10m", 'wind_direction_10m'], "hourly": ["temperature_2m", "precipitation", "weather_code", "wind_speed_10m"], - "daily": ["weather_code", "temperature_2m_max", "temperature_2m_min", "uv_index_max", "precipitation_sum", "precipitation_probability_max", "wind_speed_10m_max", "wind_direction_10m_dominant"], + "daily": ["weather_code", "temperature_2m_max", "temperature_2m_min", "uv_index_max", "precipitation_sum", "precipitation_probability_max", "wind_speed_10m_max", "wind_direction_10m_dominant", "sunrise", "sunset"], "timezone": "auto", "forecast_days": "14", "forecast_minutely_15" : "24", @@ -48,7 +108,10 @@ Future OMRequestData(double lat, double lng, String real_loc) async { var oMFile = await cacheManager2.getSingleFile(oMUrl.toString(), key: "$real_loc, open-meteo").timeout(const Duration(seconds: 6)); var oMResponse = await oMFile.readAsString(); final OMData = jsonDecode(oMResponse); - return OMData; + + DateTime fetch_datetime = await oMFile.lastModified(); + + return [OMData, fetch_datetime]; } String oMGetName(index, settings, item) { @@ -410,4 +473,136 @@ class OMHour { precip: unit_coversion(item["hourly"]["precipitation"][index], settings["Precipitation"]), wind: unit_coversion(item["hourly"]["wind_speed_10m"][index], settings["Wind"]), ); +} + +class OMSunstatus { + final String sunrise; + final String sunset; + final double sunstatus; + final String absoluteSunriseSunset; + + const OMSunstatus({ + required this.sunrise, + required this.sunstatus, + required this.sunset, + required this.absoluteSunriseSunset, + }); + + static OMSunstatus fromJson(item, settings) => OMSunstatus( + sunrise: settings["Time mode"] == "24 hour" + ? OMConvertTime(item["daily"]["sunrise"][0]) + : OMamPmTime(item["daily"]["sunrise"][0]), + sunset: settings["Time mode"] == "24 hour" + ? OMConvertTime(item["daily"]["sunrise"][0]) + : OMamPmTime(item["daily"]["sunset"][0]), + absoluteSunriseSunset: "${OMConvertTime(item["daily"]["sunrise"][0])}/" + "${OMConvertTime(item["daily"]["sunrise"][0])}", + sunstatus: OMGetSunStatus(item) + ); +} + +class OMAqi{ + final int aqi_index; + final double pm2_5; + final double pm10; + final double o3; + final double no2; + final String aqi_title; + final String aqi_desc; + + const OMAqi({ + required this.no2, + required this.o3, + required this.pm2_5, + required this.pm10, + required this.aqi_index, + required this.aqi_desc, + required this.aqi_title, + }); + + static Future fromJson(item, lat, lng) async { + final params = { + "latitude": lat.toString(), + "longitude": lng.toString(), + "current": ["european_aqi", "pm10", "pm2_5", "nitrogen_dioxide", 'ozone'], + }; + final url = Uri.https("air-quality-api.open-meteo.com", 'v1/air-quality', params); + print(url); + var file = await cacheManager2.getSingleFile(url.toString(), key: "$lat, $lng, aqi open-meteo").timeout(const Duration(seconds: 6)); + var response = await file.readAsString(); + final item = jsonDecode(response)["current"]; + + int index = AqiIndexCorrection(item["european_aqi"]); + + return OMAqi( + aqi_index: index, + pm10: item["pm10"], + pm2_5: item["pm2_5"], + no2: item["nitrogen_dioxide"], + o3: item["ozone"], + + aqi_title: ['good', 'fair', 'moderate', 'poor', 'very poor', 'unhealthy'] + [index - 1], + + aqi_desc: ['Air quality is excellent; no health risk.', + 'Acceptable air quality; minor risk for sensitive people.', + 'Sensitive individuals may experience mild effects.', + 'Health effects possible for everyone, serious for sensitive groups.', + 'Serious health effects for everyone.', + 'Emergency conditions; severe health effects for all.'] + [index - 1], + ); + } +} + +Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) async { + var OM = await OMRequestData(lat, lng, real_loc); + var oMBody = OM[0]; + + DateTime fetch_datetime = OM[1]; + + OMSunstatus sunstatus = OMSunstatus.fromJson(oMBody, settings); + + List days = []; + for (int n = 0; n < 14; n++) { + OMDay x = OMDay.build(oMBody, settings, n, sunstatus); + days.add(x); + } + + DateTime localtime = OMGetLocalTime(oMBody); + String real_time = "jT${localtime.hour}:${localtime.minute}"; + + //GET IMAGE + Image Uimage = await getUnsplashImage(oMCurrentTextCorrection( + oMBody["current"]["weather_code"], sunstatus, real_time), real_loc); + + //GET COLORS + List imageColors = await getImageColors(Uimage, settings["Color mode"]); + + return WeatherData( + radar: await RainviewerRadar.getData(), + aqi: await OMAqi.fromJson(oMBody, lat, lng), + sunstatus: sunstatus, + minutely_15_precip: OM15MinutePrecip.fromJson(oMBody, settings), + + current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, imageColors[0]), + days: days, + + lat: lat, + lng: lng, + + place: placeName, + settings: settings, + provider: "open-meteo", + real_loc: real_loc, + + fetch_datetime: fetch_datetime, + updatedTime: DateTime.now(), + image: Uimage, + localtime: real_time.split("T")[1], + palette: imageColors[0], + colorpop: imageColors[1], + desc_color: imageColors[2], + gradientColors: imageColors[3], + ); } \ No newline at end of file diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index f0d629a..6cafbec 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -27,12 +27,21 @@ import '../settings_page.dart'; import '../ui_helper.dart'; import '../weather_refact.dart' as weather_refactor; +import 'decode_OM.dart'; import 'extra_info.dart'; +import 'package:flutter/material.dart'; + //decodes the whole response from the weatherapi.com api_call bool RandomSwitch = false; +DateTime WapiGetLocalTime(item) { + DateTime now = DateTime.now(); + List loctime = item["location"]["localtime"].split(" ")[1].split(); + return now.copyWith(hour: int.parse(loctime[0]), minute: int.parse(loctime[1])); +} + Future> WapiMakeRequest(String latlong, String real_loc) async { //gets the json response for weatherapi.com final params = { @@ -44,7 +53,9 @@ Future> WapiMakeRequest(String latlong, String real_loc) async { }; final url = Uri.http('api.weatherapi.com', 'v1/forecast.json', params); - var file = await cacheManager2.getSingleFile(url.toString(), key: "$real_loc, weatherapi.com") + print(url); + + var file = await cacheManager2.getSingleFile(url.toString(), key: "$real_loc, weatherapi.com ") .timeout(const Duration(seconds: 6)); DateTime fetch_datetime = await file.lastModified(); @@ -53,6 +64,8 @@ Future> WapiMakeRequest(String latlong, String real_loc) async { var wapi_body = jsonDecode(response); + print(wapi_body["current"]["air_quality"]); + return [wapi_body, fetch_datetime]; } @@ -81,8 +94,8 @@ String amPmTime(String time) { return "$hour:$minute$atEnd"; } -String convertTime(String input) { - List splited = input.split(" "); +String convertTime(String input, {by = " "}) { + List splited = input.split(by); List num = splited[0].split(":"); int hour = int.parse(num[0]); int minute = int.parse(num[1]); @@ -101,8 +114,8 @@ String convertTime(String input) { return "$hour:$minute"; } -double getSunStatus(String sunrise, String sunset, String time) { - List splited1 = sunrise.split(" "); +double getSunStatus(String sunrise, String sunset, String time, {by = " "}) { + List splited1 = sunrise.split(by); List num1 = splited1[0].split(":"); int hour1 = int.parse(num1[0]); int minute1 = int.parse(num1[1]); @@ -428,3 +441,125 @@ class WapiHour { precip: item["precip_mm"] + (item["snow_cm"] / 10), ); } + +class WapiSunstatus { + final String sunrise; + final String sunset; + final double sunstatus; + final String absoluteSunriseSunset; + + const WapiSunstatus({ + required this.sunrise, + required this.sunstatus, + required this.sunset, + required this.absoluteSunriseSunset, + }); + + static WapiSunstatus fromJson(item, settings) => WapiSunstatus( + sunrise: settings["Time mode"] == "24 hour" + ? convertTime(item["forecast"]["forecastday"][0]["astro"]["sunrise"]) + : amPmTime(item["forecast"]["forecastday"][0]["astro"]["sunrise"]), + sunset: settings["Time mode"] == "24 hour" + ? convertTime(item["forecast"]["forecastday"][0]["astro"]["sunset"]) + : amPmTime(item["forecast"]["forecastday"][0]["astro"]["sunset"]), + absoluteSunriseSunset: "${convertTime(item["forecast"]["forecastday"][0]["astro"]["sunrise"])}/" + "${convertTime(item["forecast"]["forecastday"][0]["astro"]["sunset"])}", + sunstatus: getSunStatus(item["forecast"]["forecastday"][0]["astro"]["sunrise"], + item["forecast"]["forecastday"][0]["astro"]["sunset"], item["current"]["last_updated"]), + ); +} + +class WapiAqi { + final int aqi_index; + final double pm2_5; + final double pm10; + final double o3; + final double no2; + final String aqi_title; + final String aqi_desc; + + const WapiAqi({ + required this.no2, + required this.o3, + required this.pm2_5, + required this.pm10, + required this.aqi_index, + required this.aqi_desc, + required this.aqi_title, + }); + + static WapiAqi fromJson(item) => WapiAqi( + aqi_index: item["current"]["air_quality"]["us-epa-index"], + pm10: item["current"]["air_quality"]["pm10"], + pm2_5: item["current"]["air_quality"]["pm2_5"], + o3: item["current"]["air_quality"]["o3"], + no2: item["current"]["air_quality"]["no2"], + + aqi_title: ['good', 'fair', 'moderate', 'poor', 'very poor', 'unhealthy'] + [item["current"]["air_quality"]["us-epa-index"] - 1], + + aqi_desc: ['Air quality is excellent; no health risk.', + 'Acceptable air quality; minor risk for sensitive people.', + 'Sensitive individuals may experience mild effects.', + 'Health effects possible for everyone, serious for sensitive groups.', + 'Serious health effects for everyone.', + 'Emergency conditions; severe health effects for all.'] + [item["current"]["air_quality"]["us-epa-index"] - 1], + + ); +} + +Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) async { + + var wapi = await WapiMakeRequest("$lat,$lng", real_loc); + + var wapi_body = wapi[0]; + DateTime fetch_datetime = wapi[1]; + + final text = textCorrection( + wapi_body["current"]["condition"]["code"], wapi_body["current"]["is_day"], + language: "English"); + + //GET IMAGE + + Image Uimage = await getUnsplashImage(text, real_loc); + + //GET COLORS + List imageColors = await getImageColors(Uimage, settings["Color mode"]); + + String real_time = wapi_body["location"]["localtime"]; + WapiSunstatus sunstatus = WapiSunstatus.fromJson(wapi_body, settings); + + List days = []; + + for (int n = 0; n < wapi_body["forecast"]["forecastday"].length; n++) { + days.add(WapiDay.fromJson( + wapi_body["forecast"]["forecastday"][n], n, settings, real_time)); + } + + return WeatherData( + place: placeName, + settings: settings, + provider: "weatherapi.com", + real_loc: real_loc, + + lat: lat, + lng: lng, + + current: WapiCurrent.fromJson(wapi_body, settings,), + days: days, + sunstatus: sunstatus, + aqi: WapiAqi.fromJson(wapi_body), + radar: await RainviewerRadar.getData(), + + fetch_datetime: fetch_datetime, + updatedTime: DateTime.now(), + image: Uimage, + localtime: WapiGetLocalTime(wapi_body), + palette: imageColors[0], + colorpop: imageColors[1], + desc_color: imageColors[2], + gradientColors: imageColors[3], + minutely_15_precip: const OM15MinutePrecip(t_minus: "", precip_sum: 0, precips: []), //because wapi doesn't have 15 minutely + ); +} diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index b5c21b7..3865630 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -32,11 +32,7 @@ import '../ui_helper.dart'; import '../weather_refact.dart'; import 'decode_wapi.dart'; -Future getUnsplashImage(var wapi_body, String real_loc) async { - String _text = textCorrection( - wapi_body["current"]["condition"]["code"], wapi_body["current"]["is_day"], - language: 'english' - ); +Future getUnsplashImage(String _text, String real_loc) async { String text_query = textToUnsplashText[_text]!; @@ -52,7 +48,7 @@ Future getUnsplashImage(var wapi_body, String real_loc) async { final url2 = Uri.https('api.unsplash.com', 'photos/random', params2); - var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query") + var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query ") .timeout(const Duration(seconds: 6)); var response2 = await file2.readAsString(); @@ -84,7 +80,7 @@ Future getImageColors(Image Uimage, color_mode) async { //LIGHT Color newcolor = lighten(startcolor, i / 20); int newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < 500) { + if (newdif > bestDif && newdif < 400) { bestDif = newdif; bestcolor = newcolor; } @@ -92,7 +88,7 @@ Future getImageColors(Image Uimage, color_mode) async { //DARK newcolor = darken(startcolor, i / 20); newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < 500) { + if (newdif > bestDif && newdif < 400) { bestDif = newdif; bestcolor = newcolor; } @@ -292,99 +288,11 @@ class WeatherData { double lat = double.parse(split[0]); double lng = double.parse(split[1]); - //GET WEATHERAPI DATA - var wapi = await WapiMakeRequest(latlong, real_loc); - - var wapi_body = wapi[0]; - DateTime fetch_datetime = wapi[1]; - - - //GET IMAGE - Image Uimage = await getUnsplashImage(wapi_body, real_loc); - - final loctime = wapi_body["location"]["localtime"].split(" ")[1]; - - //GET COLORS - List imageColors = await getImageColors(Uimage, settings["Color mode"]); - - - var timenow = wapi_body["location"]["localtime_epoch"]; - String real_time = wapi_body["location"]["localtime"]; - WapiSunstatus sunstatus = WapiSunstatus.fromJson(wapi_body, settings); - if (provider == 'weatherapi.com') { - List days = []; - - for (int n = 0; n < wapi_body["forecast"]["forecastday"].length; n++) { - days.add(WapiDay.fromJson( - wapi_body["forecast"]["forecastday"][n], n, settings, timenow)); - } - - return WeatherData( - place: placeName, - settings: settings, - provider: "weatherapi.com", - real_loc: real_loc, - - lat: lat, - lng: lng, - - current: WapiCurrent.fromJson(wapi_body, settings,), - days: days, - sunstatus: sunstatus, - aqi: WapiAqi.fromJson(wapi_body), - radar: await RainviewerRadar.getData(), - - fetch_datetime: fetch_datetime, - updatedTime: DateTime.now(), - image: Uimage, - localtime: loctime, - palette: imageColors[0], - colorpop: imageColors[1], - desc_color: imageColors[2], - gradientColors: imageColors[3], - minutely_15_precip: const OM15MinutePrecip(t_minus: "", precip_sum: 0, - precips: []), //because wapi doesn't have 15 minutely - - ); + return WapiGetWeatherData(lat, lng, real_loc, settings, placeName); } else { - //GET OM data - var oMBody = await OMRequestData(lat, lng, real_loc); - - List days = []; - for (int n = 0; n < 14; n++) { - OMDay x = OMDay.build(oMBody, settings, n, sunstatus); - days.add(x); - } - - return WeatherData( - radar: await RainviewerRadar.getData(), - aqi: WapiAqi.fromJson(wapi_body), - sunstatus: WapiSunstatus.fromJson(wapi_body, settings), - minutely_15_precip: OM15MinutePrecip.fromJson(oMBody, settings), - - current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, imageColors[0]), - //await _generatorPalette(hihi)), - days: days, - - lat: lat, - lng: lng, - - place: placeName, - settings: settings, - provider: "open-meteo", - real_loc: real_loc, - - fetch_datetime: fetch_datetime, - updatedTime: DateTime.now(), - image: Uimage, - localtime: loctime, - palette: imageColors[0], - colorpop: imageColors[1], - desc_color: imageColors[2], - gradientColors: imageColors[3], - ); + return OMGetWeatherData(lat, lng, real_loc, settings, placeName); } } } @@ -435,72 +343,4 @@ class RainviewerRadar { return RainviewerRadar.fromJson(images, times); } -} - -class WapiSunstatus { - final String sunrise; - final String sunset; - final double sunstatus; - final String absoluteSunriseSunset; - - const WapiSunstatus({ - required this.sunrise, - required this.sunstatus, - required this.sunset, - required this.absoluteSunriseSunset, - }); - - static WapiSunstatus fromJson(item, settings) => WapiSunstatus( - sunrise: settings["Time mode"] == "24 hour" - ? convertTime(item["forecast"]["forecastday"][0]["astro"]["sunrise"]) - : amPmTime(item["forecast"]["forecastday"][0]["astro"]["sunrise"]), - sunset: settings["Time mode"] == "24 hour" - ? convertTime(item["forecast"]["forecastday"][0]["astro"]["sunset"]) - : amPmTime(item["forecast"]["forecastday"][0]["astro"]["sunset"]), - absoluteSunriseSunset: "${convertTime(item["forecast"]["forecastday"][0]["astro"]["sunrise"])}/" - "${convertTime(item["forecast"]["forecastday"][0]["astro"]["sunset"])}", - sunstatus: getSunStatus(item["forecast"]["forecastday"][0]["astro"]["sunrise"], - item["forecast"]["forecastday"][0]["astro"]["sunset"], item["current"]["last_updated"]), - ); -} - -class WapiAqi { - final int aqi_index; - final double pm2_5; - final double pm10; - final double o3; - final double no2; - final String aqi_title; - final String aqi_desc; - - const WapiAqi({ - required this.no2, - required this.o3, - required this.pm2_5, - required this.pm10, - required this.aqi_index, - required this.aqi_desc, - required this.aqi_title, - }); - - static WapiAqi fromJson(item) => WapiAqi( - aqi_index: item["current"]["air_quality"]["us-epa-index"], - pm10: item["current"]["air_quality"]["pm10"], - pm2_5: item["current"]["air_quality"]["pm2_5"], - o3: item["current"]["air_quality"]["o3"], - no2: item["current"]["air_quality"]["no2"], - - aqi_title: ['good', 'moderate', 'slightly unhealthy', - 'unhealthy', 'very unhealthy', - 'hazardous'][item["current"]["air_quality"]["us-epa-index"] - 1], - - aqi_desc: ['Air quality is excellent; no health risk.', - 'Acceptable air quality; minor risk for sensitive people.', - 'Sensitive individuals may experience mild effects.', - 'Health effects possible for everyone, serious for sensitive groups.', - 'Serious health effects for everyone.', - 'Emergency conditions; severe health effects for all.'] - [item["current"]["air_quality"]["us-epa-index"] - 1], - - ); } \ No newline at end of file diff --git a/lib/main_screens.dart b/lib/main_screens.dart index bc338f4..65a5701 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -21,6 +21,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:overmorrow/new_displays.dart'; +import 'package:overmorrow/radar.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:material_floating_search_bar_2/material_floating_search_bar_2.dart'; import 'package:stretchy_header/stretchy_header.dart'; @@ -99,8 +100,8 @@ Widget NewMain(data, updateLocation, context) { NewSunriseSunset(data: data, key: Key(data.place), size: size,), NewRain15MinuteIndicator(data), NewAirQuality(data), + RadarMap(data: data, key: Key(data.place),), - buildHihiDays(data), /* NewTimes(data, true), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index a7f5849..8d5d306 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -261,7 +261,7 @@ class _NewSunriseSunsetState extends State Widget NewAirQuality(var data) { return Padding( - padding: const EdgeInsets.only(left: 22, right: 22, bottom: 19, top: 20), + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 19, top: 20), child: Column( children: [ Padding( @@ -431,3 +431,10 @@ Widget NewRain15MinuteIndicator(var data) { ) ); } + +Widget newRadar(var data) { + return Padding( + padding: EdgeInsets.only(left: 20, right: 20, top: 10), + child: Container(), + ); +} diff --git a/lib/radar.dart b/lib/radar.dart index 3fcb64d..c7abc80 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -18,12 +18,14 @@ along with this program. If not, see . import 'dart:async'; import 'dart:math'; +import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:overmorrow/ui_helper.dart'; import 'package:latlong2/latlong.dart'; +import 'package:http/http.dart' as http; class RadarMap extends StatefulWidget { @@ -247,6 +249,23 @@ class _RadarMapState extends State { } } +Future> preloadImages(List urls) async { + List images = []; + for (String url in urls) { + try { + final response = await http.get(Uri.parse(url + "/256/8/1.png")); + if (response.statusCode == 200) { + images.add(response.bodyBytes); + } else { + print('Failed to load image: $url'); + } + } catch (e) { + print('Error loading image: $e'); + } + } + return images; +} + class RadarPage extends StatefulWidget { final data; @@ -264,16 +283,25 @@ class _RadarPageState extends State { int currentFrameIndex = 0; late Timer timer; bool isPlaying = false; + List preloadedFrames = []; // Store image data @override void initState() { super.initState(); - timer = Timer.periodic(const Duration(milliseconds: 1500), (Timer t) { + // Preload images asynchronously + preloadImages(data.radar.images).then((images) { + setState(() { + preloadedFrames = images; + }); + }); + + timer = Timer.periodic(const Duration(milliseconds: 500), (Timer t) { if (isPlaying) { setState(() { - currentFrameIndex = - ((currentFrameIndex + 1) % data.radar.images.length).toInt(); + if (preloadedFrames.isNotEmpty) { + currentFrameIndex = (currentFrameIndex + 1) % preloadedFrames.length; + } }); } }); @@ -300,6 +328,12 @@ class _RadarPageState extends State { double x = MediaQuery.of(context).padding.top; Color main = data.current.textcolor; Color top = lighten(data.current.highlight, 0.1); + + // Check if preloadedFrames is initialized + if (preloadedFrames.isEmpty) { + return Center(child: CircularProgressIndicator()); // or any loading indicator + } + return Stack( children: [ FlutterMap( @@ -308,153 +342,28 @@ class _RadarPageState extends State { initialZoom: 5, minZoom: 2, maxZoom: 8, - backgroundColor: WHITE, - interactionOptions: const InteractionOptions(flags: InteractiveFlag.all & ~InteractiveFlag.rotate,), + interactionOptions: const InteractionOptions( + flags: InteractiveFlag.all & ~InteractiveFlag.rotate, + ), ), children: [ - Container( - color: data.settings["Color theme"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), - ), TileLayer( urlTemplate: data.settings["Color theme"] == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', ), - TileLayer( - urlTemplate: data.radar.images[currentFrameIndex] + "/256/{z}/{x}/{y}/8/1_1.png", - ), TileLayer( urlTemplate: data.settings["Color theme"] == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_only_labels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', ), + // Handle radar image layer manually if needed + if (preloadedFrames.isNotEmpty) ...[ + // For custom tile handling, you might need to implement a custom TileLayer + ], ], ), - Align( - alignment: Alignment.bottomCenter, - child: Container( - constraints: const BoxConstraints(maxWidth: 500), - child: Padding( - padding: const EdgeInsets.only(left: 20, bottom: 20, right: 20), - child: Material( - borderRadius: BorderRadius.circular(20), - elevation: 10, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(18), - color: top, - ), - padding: EdgeInsets.all(6), - child: Row( - children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 200), - transitionBuilder: (Widget child, Animation animation) { - return ScaleTransition(scale: animation, child: child,); - }, - child: Hero( - key: ValueKey (isPlaying), - tag: 'playpause', - child: SizedBox( - height: 48, - width: 48, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 8, - padding: const EdgeInsets.all(10), - backgroundColor: top, - //side: const BorderSide(width: 5, color: WHITE), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16) - ), - ), - onPressed: () async { - togglePlayPause(); - }, - child: Icon(isPlaying? Icons.pause : Icons.play_arrow, color: main, size: 18,), - ), - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 6), - child: Hero( - tag: 'progress', - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Material( - borderRadius: BorderRadius.circular(13), - elevation: 8, - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: Container( - height: 48, - color: top, - child: Stack( - children: [ - Container( - color: main, - width: constraints.maxWidth * - (max(currentFrameIndex - 1, 0) / data.radar.images.length), - ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - transitionBuilder: (Widget child, Animation animation) => - SizeTransition(sizeFactor: animation, axis: Axis.horizontal, child: child), - child: Container( - key: ValueKey(currentFrameIndex), - color: main, - width: constraints.maxWidth * - (currentFrameIndex / data.radar.images.length), - ), - ), - ], - ), - ), - ), - ); - } - ), - ), - ), - ) - ], - ), - ), - ), - ), - ), - ), - Padding( - padding: EdgeInsets.only(right: 20, top: x + 20), - child: Align( - alignment: Alignment.topRight, - child: Hero( - tag: 'switch', - child: SizedBox( - height: 52, - width: 52, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 10, - padding: const EdgeInsets.all(10), - backgroundColor: top, - //side: BorderSide(width: 3, color: main), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20) - ), - ), - onPressed: () { - Navigator.of(context).pop(); - }, - child: Icon(Icons.close_fullscreen, color: main, size: 26,), - ), - ), - ), - ), - ) ], ); } diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index c9009c2..770fdcf 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -69,24 +69,26 @@ Widget comfortatext(String text, double size, settings, ); } -Color lighten(Color color, [double amount = .1]) { - assert(amount >= 0 && amount <= 1); - - final hsl = HSLColor.fromColor(color); - final hslLight = hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0)); - - return hslLight.toColor(); +Color darken(Color c, [double amount = 0.1]) { + assert(0 <= amount && amount <= 1); + var f = 1 - amount; + return Color.fromARGB( + c.alpha, + (c.red * f).round(), + (c.green * f).round(), + (c.blue * f).round() + ); } -Color darken(Color color, [double amount = .1]) { - assert(amount >= 0 && amount <= 1); - - final hsl = HSLColor.fromColor(color); - final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0)); - - return hslDark.toColor(); +Color lighten(Color c, [double amount = 0.1]) { + assert(0 <= amount && amount <= 1); + return Color.fromARGB( + c.alpha, + c.red + ((255 - c.red) * amount).round(), + c.green + ((255 - c.green) * amount).round(), + c.blue + ((255 - c.blue) * amount).round() + ); } - Color lightAccent(Color color, int intensity) { double x = intensity / (color.red + color.green + color.blue); return Color.fromRGBO(sqrt(color.red * x).toInt(), sqrt(color.green * x).toInt(), sqrt(color.blue * x).toInt(), 1); diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 630b7f3..046ec24 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -312,7 +312,7 @@ Map textToUnsplashText = { 'Clear Sky': 'blue sky', //it doesn't understand clear as much so i use blue instead 'Overcast': 'dark clouds', //kinda works 'Haze': 'haze', - 'Rain': 'rain shower', + 'Rain': 'rain', 'Sleet': 'freezing rain',//this works much better 'Drizzle': 'light rain', //somehow understands it more though still not perfect 'Thunderstorm': 'thunderstorm', From 8273a45f1083dc956d935d48512f5876bf1f6d04 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 22 Jul 2024 13:40:14 +0200 Subject: [PATCH 035/129] fixed one tiny bug --- lib/main.dart | 2 +- lib/main_screens.dart | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index 116f90e..811970b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -187,7 +187,7 @@ class _MyAppState extends State { if (recall) { return dumbySearch(errorMessage: "general error at place X: $e", updateLocation: updateLocation, icon: Icons.bug_report, - place: backupName, settings: settings, provider: weather_provider, latlng: 'search',); + place: backupName, settings: settings, provider: weather_provider, latlng: 'query',); } else { return getDays(true, proposedLoc, backupName, startup); diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 65a5701..4e3a510 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -101,6 +101,8 @@ Widget NewMain(data, updateLocation, context) { NewRain15MinuteIndicator(data), NewAirQuality(data), RadarMap(data: data, key: Key(data.place),), + providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, + data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), /* NewTimes(data, true), From 3677948b3e79138ebe3c7de8d9f324c58f20eb8b Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 22 Jul 2024 14:17:39 +0200 Subject: [PATCH 036/129] fixed up all the bugs with the separation --- lib/decoders/decode_OM.dart | 60 ++++++----- lib/decoders/decode_wapi.dart | 3 +- lib/main_screens.dart | 12 ++- lib/new_displays.dart | 5 +- lib/radar.dart | 183 +++++++++++++++++++++++++--------- lib/search_screens.dart | 2 +- 6 files changed, 178 insertions(+), 87 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 247301f..76280e2 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -43,14 +43,10 @@ String OMamPmTime(String time) { int hour = int.parse(num[0]); if (hour > 12) { - int x = hour - 12; - if (x < 10) { - return "0${hour - 12}:${num[1]}"; - } - return "${hour - 12}:${num[1]}"; + return "${hour - 12}:${num[1]}pm"; } - return "${num[0]}:${num[1]}"; + return "$hour:${num[1]}am"; } int AqiIndexCorrection(int aqi) { @@ -496,7 +492,7 @@ class OMSunstatus { ? OMConvertTime(item["daily"]["sunrise"][0]) : OMamPmTime(item["daily"]["sunset"][0]), absoluteSunriseSunset: "${OMConvertTime(item["daily"]["sunrise"][0])}/" - "${OMConvertTime(item["daily"]["sunrise"][0])}", + "${OMConvertTime(item["daily"]["sunset"][0])}", sunstatus: OMGetSunStatus(item) ); } @@ -580,29 +576,29 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as List imageColors = await getImageColors(Uimage, settings["Color mode"]); return WeatherData( - radar: await RainviewerRadar.getData(), - aqi: await OMAqi.fromJson(oMBody, lat, lng), - sunstatus: sunstatus, - minutely_15_precip: OM15MinutePrecip.fromJson(oMBody, settings), - - current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, imageColors[0]), - days: days, - - lat: lat, - lng: lng, - - place: placeName, - settings: settings, - provider: "open-meteo", - real_loc: real_loc, - - fetch_datetime: fetch_datetime, - updatedTime: DateTime.now(), - image: Uimage, - localtime: real_time.split("T")[1], - palette: imageColors[0], - colorpop: imageColors[1], - desc_color: imageColors[2], - gradientColors: imageColors[3], - ); + radar: await RainviewerRadar.getData(), + aqi: await OMAqi.fromJson(oMBody, lat, lng), + sunstatus: sunstatus, + minutely_15_precip: OM15MinutePrecip.fromJson(oMBody, settings), + + current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, imageColors[0]), + days: days, + + lat: lat, + lng: lng, + + place: placeName, + settings: settings, + provider: "open-meteo", + real_loc: real_loc, + + fetch_datetime: fetch_datetime, + updatedTime: DateTime.now(), + image: Uimage, + localtime: real_time.split("T")[1], + palette: imageColors[0], + colorpop: imageColors[1], + desc_color: imageColors[2], + gradientColors: imageColors[3], + ); } \ No newline at end of file diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index 6cafbec..15090f1 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -528,13 +528,14 @@ Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) List imageColors = await getImageColors(Uimage, settings["Color mode"]); String real_time = wapi_body["location"]["localtime"]; + int epoch = wapi_body["location"]["localtime_epoch"]; WapiSunstatus sunstatus = WapiSunstatus.fromJson(wapi_body, settings); List days = []; for (int n = 0; n < wapi_body["forecast"]["forecastday"].length; n++) { days.add(WapiDay.fromJson( - wapi_body["forecast"]["forecastday"][n], n, settings, real_time)); + wapi_body["forecast"]["forecastday"][n], n, settings, epoch)); } return WeatherData( diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 4e3a510..a605558 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -21,7 +21,6 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:overmorrow/new_displays.dart'; -import 'package:overmorrow/radar.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:material_floating_search_bar_2/material_floating_search_bar_2.dart'; import 'package:stretchy_header/stretchy_header.dart'; @@ -100,13 +99,16 @@ Widget NewMain(data, updateLocation, context) { NewSunriseSunset(data: data, key: Key(data.place), size: size,), NewRain15MinuteIndicator(data), NewAirQuality(data), - RadarMap(data: data, key: Key(data.place),), - providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, - data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), + + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 30), + child: providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, + data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), + ), /* NewTimes(data, true), - + RadarMap(data: data, key: Key(data.place),), buildGlanceDay(data), providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 8d5d306..6c90d02 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -110,6 +110,7 @@ class _NewSunriseSunsetState extends State final List absoluteRise = absoluteSunriseSunset[0].split(':'); final List absoluteSet = absoluteSunriseSunset[1].split(':'); + final List absoluteLocalTime = widget.data.localtime.split(':'); final currentTime = DateTime.now(); @@ -148,6 +149,7 @@ class _NewSunriseSunsetState extends State DateTime localTime = now.add(Duration(hours: hourdif)); final thisdif = localTime.difference(riseDT).inSeconds; + final double progress = min(max(thisdif / total, 0), 1); String write = widget.data.settings["Time mode"] == "24 hour" @@ -308,8 +310,7 @@ Widget NewAirQuality(var data) { Align( alignment: Alignment.topLeft, child: comfortatext( - translation( - data.aqi.aqi_title, data.settings["Language"]), + data.aqi.aqi_title, 20, data.settings, color: data.palette.primaryFixedDim, diff --git a/lib/radar.dart b/lib/radar.dart index c7abc80..cced279 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -18,14 +18,12 @@ along with this program. If not, see . import 'dart:async'; import 'dart:math'; -import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:overmorrow/ui_helper.dart'; import 'package:latlong2/latlong.dart'; -import 'package:http/http.dart' as http; class RadarMap extends StatefulWidget { @@ -80,7 +78,7 @@ class _RadarMapState extends State { child: Align( alignment: Alignment.centerLeft, child: comfortatext(translation('radar', data.settings["Language"]), 19, data.settings, - color: data.current.textcolor), + color: data.current.textcolor), ), ), Padding( @@ -249,23 +247,6 @@ class _RadarMapState extends State { } } -Future> preloadImages(List urls) async { - List images = []; - for (String url in urls) { - try { - final response = await http.get(Uri.parse(url + "/256/8/1.png")); - if (response.statusCode == 200) { - images.add(response.bodyBytes); - } else { - print('Failed to load image: $url'); - } - } catch (e) { - print('Error loading image: $e'); - } - } - return images; -} - class RadarPage extends StatefulWidget { final data; @@ -283,25 +264,16 @@ class _RadarPageState extends State { int currentFrameIndex = 0; late Timer timer; bool isPlaying = false; - List preloadedFrames = []; // Store image data @override void initState() { super.initState(); - // Preload images asynchronously - preloadImages(data.radar.images).then((images) { - setState(() { - preloadedFrames = images; - }); - }); - - timer = Timer.periodic(const Duration(milliseconds: 500), (Timer t) { + timer = Timer.periodic(const Duration(milliseconds: 1500), (Timer t) { if (isPlaying) { setState(() { - if (preloadedFrames.isNotEmpty) { - currentFrameIndex = (currentFrameIndex + 1) % preloadedFrames.length; - } + currentFrameIndex = + ((currentFrameIndex + 1) % data.radar.images.length).toInt(); }); } }); @@ -328,12 +300,6 @@ class _RadarPageState extends State { double x = MediaQuery.of(context).padding.top; Color main = data.current.textcolor; Color top = lighten(data.current.highlight, 0.1); - - // Check if preloadedFrames is initialized - if (preloadedFrames.isEmpty) { - return Center(child: CircularProgressIndicator()); // or any loading indicator - } - return Stack( children: [ FlutterMap( @@ -342,29 +308,154 @@ class _RadarPageState extends State { initialZoom: 5, minZoom: 2, maxZoom: 8, + backgroundColor: WHITE, - interactionOptions: const InteractionOptions( - flags: InteractiveFlag.all & ~InteractiveFlag.rotate, - ), + interactionOptions: const InteractionOptions(flags: InteractiveFlag.all & ~InteractiveFlag.rotate,), ), children: [ + Container( + color: data.settings["Color theme"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), + ), TileLayer( urlTemplate: data.settings["Color theme"] == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', ), + TileLayer( + urlTemplate: data.radar.images[currentFrameIndex] + "/256/{z}/{x}/{y}/8/1_1.png", + ), TileLayer( urlTemplate: data.settings["Color theme"] == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_only_labels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', ), - // Handle radar image layer manually if needed - if (preloadedFrames.isNotEmpty) ...[ - // For custom tile handling, you might need to implement a custom TileLayer - ], ], ), + Align( + alignment: Alignment.bottomCenter, + child: Container( + constraints: const BoxConstraints(maxWidth: 500), + child: Padding( + padding: const EdgeInsets.only(left: 20, bottom: 20, right: 20), + child: Material( + borderRadius: BorderRadius.circular(20), + elevation: 10, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + color: top, + ), + padding: EdgeInsets.all(6), + child: Row( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + transitionBuilder: (Widget child, Animation animation) { + return ScaleTransition(scale: animation, child: child,); + }, + child: Hero( + key: ValueKey (isPlaying), + tag: 'playpause', + child: SizedBox( + height: 48, + width: 48, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 8, + padding: const EdgeInsets.all(10), + backgroundColor: top, + //side: const BorderSide(width: 5, color: WHITE), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16) + ), + ), + onPressed: () async { + togglePlayPause(); + }, + child: Icon(isPlaying? Icons.pause : Icons.play_arrow, color: main, size: 18,), + ), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 6), + child: Hero( + tag: 'progress', + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return Material( + borderRadius: BorderRadius.circular(13), + elevation: 8, + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: Container( + height: 48, + color: top, + child: Stack( + children: [ + Container( + color: main, + width: constraints.maxWidth * + (max(currentFrameIndex - 1, 0) / data.radar.images.length), + ), + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + transitionBuilder: (Widget child, Animation animation) => + SizeTransition(sizeFactor: animation, axis: Axis.horizontal, child: child), + child: Container( + key: ValueKey(currentFrameIndex), + color: main, + width: constraints.maxWidth * + (currentFrameIndex / data.radar.images.length), + ), + ), + ], + ), + ), + ), + ); + } + ), + ), + ), + ) + ], + ), + ), + ), + ), + ), + ), + Padding( + padding: EdgeInsets.only(right: 20, top: x + 20), + child: Align( + alignment: Alignment.topRight, + child: Hero( + tag: 'switch', + child: SizedBox( + height: 52, + width: 52, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 10, + padding: const EdgeInsets.all(10), + backgroundColor: top, + //side: BorderSide(width: 3, color: main), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20) + ), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + child: Icon(Icons.close_fullscreen, color: main, size: 26,), + ), + ), + ), + ), + ) ], ); } -} +} \ No newline at end of file diff --git a/lib/search_screens.dart b/lib/search_screens.dart index ddafd67..964cbf2 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -473,7 +473,7 @@ class dumbySearch extends StatelessWidget { }, headerData: HeaderData( blurContent: false, - headerHeight: max(size.height * 0.6, 400), //we don't want it to be smaller than 400 + headerHeight: max(size.height * 0.54, 400), //we don't want it to be smaller than 400 header: ParrallaxBackground(image: Image.asset("assets/backdrops/grayscale_snow2.jpg", fit: BoxFit.cover,), key: Key(place), color: darken(colors[0], 0.1),), overlay: Stack( From 4a9869430051f9fa559d959359f3e41cd9f63005 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 22 Jul 2024 19:18:34 +0200 Subject: [PATCH 037/129] had to revert to old because of stupid weatherapi aqi --- lib/decoders/decode_OM.dart | 22 ++++++++-------------- lib/decoders/decode_wapi.dart | 17 ++++++----------- lib/decoders/extra_info.dart | 20 ++++++++++---------- lib/main.dart | 6 ++++-- lib/main_screens.dart | 24 +++++++++++++----------- lib/new_displays.dart | 19 +++++++++++-------- lib/search_screens.dart | 8 +++++++- lib/settings_page.dart | 12 ++++++++---- 8 files changed, 67 insertions(+), 61 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 76280e2..51e7ef5 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -234,7 +234,7 @@ class OMCurrent { required this.wind_dir, }); - static OMCurrent fromJson(item, settings, sunstatus, timenow, palette) { + static OMCurrent fromJson(item, settings, sunstatus, timenow) { Color back = BackColorCorrection( oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), @@ -245,16 +245,16 @@ class OMCurrent { item["current"]["weather_code"], sunstatus, timenow), ); - /* + List colors = getColors(primary, back, settings, ColorPopCorrection( oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow),)[ settings["Color mode"] == "dark" ? 1 : 0 ]); - */ - List colors = getNetworkColors(palette, settings); + + //List colors = getNetworkColors(palette, settings); //List colors = palette.colors.toList(); @@ -523,7 +523,6 @@ class OMAqi{ "current": ["european_aqi", "pm10", "pm2_5", "nitrogen_dioxide", 'ozone'], }; final url = Uri.https("air-quality-api.open-meteo.com", 'v1/air-quality', params); - print(url); var file = await cacheManager2.getSingleFile(url.toString(), key: "$lat, $lng, aqi open-meteo").timeout(const Duration(seconds: 6)); var response = await file.readAsString(); final item = jsonDecode(response)["current"]; @@ -569,11 +568,11 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as String real_time = "jT${localtime.hour}:${localtime.minute}"; //GET IMAGE - Image Uimage = await getUnsplashImage(oMCurrentTextCorrection( - oMBody["current"]["weather_code"], sunstatus, real_time), real_loc); + //Image Uimage = await getUnsplashImage(oMCurrentTextCorrection( + // oMBody["current"]["weather_code"], sunstatus, real_time), real_loc); //GET COLORS - List imageColors = await getImageColors(Uimage, settings["Color mode"]); + //List imageColors = await getImageColors(Uimage, settings["Color mode"]); return WeatherData( radar: await RainviewerRadar.getData(), @@ -581,7 +580,7 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as sunstatus: sunstatus, minutely_15_precip: OM15MinutePrecip.fromJson(oMBody, settings), - current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, imageColors[0]), + current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time), days: days, lat: lat, @@ -594,11 +593,6 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), - image: Uimage, localtime: real_time.split("T")[1], - palette: imageColors[0], - colorpop: imageColors[1], - desc_color: imageColors[2], - gradientColors: imageColors[3], ); } \ No newline at end of file diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index 15090f1..b39ccda 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -516,18 +516,18 @@ Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) var wapi_body = wapi[0]; DateTime fetch_datetime = wapi[1]; - final text = textCorrection( - wapi_body["current"]["condition"]["code"], wapi_body["current"]["is_day"], - language: "English"); + //final text = textCorrection( + // wapi_body["current"]["condition"]["code"], wapi_body["current"]["is_day"], + // language: "English"); //GET IMAGE - Image Uimage = await getUnsplashImage(text, real_loc); + //Image Uimage = await getUnsplashImage(text, real_loc); //GET COLORS - List imageColors = await getImageColors(Uimage, settings["Color mode"]); + //List imageColors = await getImageColors(Uimage, settings["Color mode"]); - String real_time = wapi_body["location"]["localtime"]; + //String real_time = wapi_body["location"]["localtime"]; int epoch = wapi_body["location"]["localtime_epoch"]; WapiSunstatus sunstatus = WapiSunstatus.fromJson(wapi_body, settings); @@ -555,12 +555,7 @@ Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), - image: Uimage, localtime: WapiGetLocalTime(wapi_body), - palette: imageColors[0], - colorpop: imageColors[1], - desc_color: imageColors[2], - gradientColors: imageColors[3], minutely_15_precip: const OM15MinutePrecip(t_minus: "", precip_sum: 0, precips: []), //because wapi doesn't have 15 minutely ); } diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 3865630..e3e085e 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -250,13 +250,13 @@ class WeatherData { final fetch_datetime; - final image; + //final image; final localtime; - final palette; - final colorpop; - final desc_color; - final gradientColors; + //final palette; + //final colorpop; + //final desc_color; + //final gradientColors; WeatherData({ required this.place, @@ -272,13 +272,13 @@ class WeatherData { required this.current, required this.fetch_datetime, required this.updatedTime, - required this.image, + //required this.image, required this.localtime, - required this.palette, - required this.colorpop, - required this.desc_color, - required this.gradientColors, + //required this.palette, + //required this.colorpop, + //required this.desc_color, + //required this.gradientColors, required this.minutely_15_precip, }); diff --git a/lib/main.dart b/lib/main.dart index 811970b..06e2729 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -162,7 +162,8 @@ class _MyAppState extends State { } on HttpExceptionWithStatus catch (hihi){ return dumbySearch(errorMessage: "general error at place 1: ${hihi.toString()}", updateLocation: updateLocation, icon: Icons.bug_report, - place: backupName, settings: settings, provider: weather_provider, latlng: absoluteProposed,); + place: backupName, settings: settings, provider: weather_provider, latlng: absoluteProposed, + shouldAdd: "Please try another weather provider",); } on SocketException { return dumbySearch(errorMessage: translation("Not connected to the internet", settings["Language"]!), updateLocation: updateLocation, @@ -187,7 +188,8 @@ class _MyAppState extends State { if (recall) { return dumbySearch(errorMessage: "general error at place X: $e", updateLocation: updateLocation, icon: Icons.bug_report, - place: backupName, settings: settings, provider: weather_provider, latlng: 'query',); + place: backupName, settings: settings, provider: weather_provider, latlng: 'query', + shouldAdd: "Please try another weather provider",); } else { return getDays(true, proposedLoc, backupName, startup); diff --git a/lib/main_screens.dart b/lib/main_screens.dart index a605558..793941c 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -20,7 +20,6 @@ import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:overmorrow/new_displays.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:material_floating_search_bar_2/material_floating_search_bar_2.dart'; import 'package:stretchy_header/stretchy_header.dart'; @@ -46,7 +45,7 @@ Widget NewMain(data, updateLocation, context) { //backgroundColor: WHITE, blurContent: false, headerHeight: max(size.height * 0.54, 400), //we don't want it to be smaller than 400 - header: ParrallaxBackground(image: data.image, key: Key(data.place), + header: ParrallaxBackground(image: Image.asset("assets/backdrops/${data.current.backdrop}", fit: BoxFit.cover,), key: Key(data.place), color: data.current.backcolor == BLACK ? BLACK : lightAccent(data.current.backcolor, 5000)), overlay: Stack( @@ -62,13 +61,13 @@ Widget NewMain(data, updateLocation, context) { Padding( padding: const EdgeInsets.only(left: 0, bottom: 2), child: comfortatext("${data.current.temp}°", 68, data.settings, - color: data.colorpop, weight: FontWeight.w300), + color: data.current.colorpop, weight: FontWeight.w300), ), Padding( padding: const EdgeInsets.only(left: 0), child: comfortatext(data.current.text, 32, data.settings, - weight: data.settings["Color mode"] == "dark" ? FontWeight.w600 : FontWeight.w400, color: data.desc_color), - ), + weight: data.settings["Color mode"] == "dark" ? FontWeight.w600 : FontWeight.w400, color: WHITE), + ) ], ), ), @@ -76,7 +75,7 @@ Widget NewMain(data, updateLocation, context) { color: data.current.backcolor, place: data.place, controller: controller, settings: data.settings, real_loc: data.real_loc, secondColor: data.current.primary, textColor: data.current.textcolor, - highlightColor: data.current.highlight, key: Key("${data.place}, ${data.image} ${data.settings}"),), + highlightColor: data.current.highlight, key: Key("${data.place}, ${data.settings}"),), ], ) ), @@ -87,15 +86,16 @@ Widget NewMain(data, updateLocation, context) { LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { if(constraints.maxWidth > 500.0) { - return Circles(500, data, 0.5, data.palette.primary); + return Circles(500, data, 0.5, data.current.primary); } else { - return Circles(constraints.maxWidth * 0.97, data, 0.5, data.palette.primary); + return Circles(constraints.maxWidth * 0.97, data, 0.5, data.current.primary); } } ), ], ), + /* NewSunriseSunset(data: data, key: Key(data.place), size: size,), NewRain15MinuteIndicator(data), NewAirQuality(data), @@ -106,15 +106,17 @@ Widget NewMain(data, updateLocation, context) { data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), ), - /* + */ + NewTimes(data, true), - RadarMap(data: data, key: Key(data.place),), + //RadarMap(data: data, key: Key(data.place),), + buildHihiDays(data), buildGlanceDay(data), providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), const Padding(padding: EdgeInsets.only(bottom: 20)) - */ + ], ), ); diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 6c90d02..739afaa 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -49,7 +49,8 @@ class WavePainter extends CustomPainter { ..strokeCap = StrokeCap.round ..style = PaintingStyle.stroke; - final path = Path(); + final path1 = Path(); + final amplitude = 2.45; final frequency = 24.0; final splitPoint = hihi * size.width; @@ -58,24 +59,26 @@ class WavePainter extends CustomPainter { final y = size.height / 2 + amplitude * sin((x / frequency * 2 * pi) + (waveValue * 2 * pi)); if (x == 0) { - path.moveTo(x, y); + path1.moveTo(x, y); } else { - path.lineTo(x, y); + path1.lineTo(x, y); } } - canvas.drawPath(path, firstPaint); - path.reset(); + final path2 = Path(); + for (double x = splitPoint; x <= size.width; x++) { final y = size.height / 2 + amplitude * sin((x / frequency * 2 * pi) + (waveValue * 2 * pi)); if (x == splitPoint) { - path.moveTo(x, y); + path2.moveTo(x, y); } else { - path.lineTo(x, y); + path2.lineTo(x, y); } } - canvas.drawPath(path, secondPaint); + + canvas.drawPath(path2, secondPaint); + canvas.drawPath(path1, firstPaint); } @override diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 964cbf2..53759e0 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -440,10 +440,11 @@ class dumbySearch extends StatelessWidget { final settings; final provider; final latlng; + final shouldAdd; dumbySearch({super.key, required this.errorMessage, required this.updateLocation, required this.icon, required this.place, - required this.settings, required this.provider, required this.latlng}); + required this.settings, required this.provider, required this.latlng, this.shouldAdd}); final FloatingSearchBarController controller = FloatingSearchBarController(); @@ -491,6 +492,11 @@ class dumbySearch extends StatelessWidget { ), comfortatext(newStr, 20, settings, color: Colors.black54, weight: FontWeight.w300, align: TextAlign.center), + Padding( + padding: const EdgeInsets.only(top: 20), + child: comfortatext(shouldAdd, 20, settings, color: Colors.black54, weight: FontWeight.w500, + align: TextAlign.center), + ), ], ), ), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 3001b6b..f281826 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -404,12 +404,12 @@ Widget SettingsMain(Color primary, Map? settings, Function updat slivers: [ SliverAppBar.large( leading: - IconButton(icon: Icon(Icons.menu, color: colors[2],), onPressed: () {}), + IconButton(icon: Icon(Icons.arrow_back, color: colors[2],), onPressed: () { + goBack(); + }), title: comfortatext(translation('Settings', settings!["Language"]!), 30, settings, color: colors[2]), - actions: [ - IconButton(icon: Icon(Icons.more_vert, color: colors[2],), onPressed: () {}), - ], backgroundColor: colors[5], + pinned: false, ), // Just some content big enough to have something to scroll. SliverToBoxAdapter( @@ -440,11 +440,15 @@ Widget settingsMain(Color color, Map settings, Function updatePa child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + + /* NavButton('Appearance', settings, textcolor, Icons.color_lens), NavButton('Language', settings, textcolor, Icons.language), NavButton('Units', settings, textcolor, Icons.graphic_eq), NavButton('Advanced', settings, textcolor, Icons.code), + */ + Padding( padding: const EdgeInsets.only(left: 10, right: 20), From a56608dc4c69eed979d68a889f3a9b20cab17c6e Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 22 Jul 2024 20:23:31 +0200 Subject: [PATCH 038/129] went back to old darken/lighten --- lib/decoders/extra_info.dart | 4 ++-- lib/main_screens.dart | 4 ++-- lib/ui_helper.dart | 23 +++++++++++++++++++++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index e3e085e..9a68966 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -78,7 +78,7 @@ Future getImageColors(Image Uimage, color_mode) async { if (bestDif < 300) { for (int i = 1; i < 4; i++) { //LIGHT - Color newcolor = lighten(startcolor, i / 20); + Color newcolor = lighten2(startcolor, i / 20); int newdif = difFromBackColors(newcolor, dominant); if (newdif > bestDif && newdif < 400) { bestDif = newdif; @@ -86,7 +86,7 @@ Future getImageColors(Image Uimage, color_mode) async { } //DARK - newcolor = darken(startcolor, i / 20); + newcolor = darken2(startcolor, i / 20); newdif = difFromBackColors(newcolor, dominant); if (newdif > bestDif && newdif < 400) { bestDif = newdif; diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 793941c..92e4ff0 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -75,7 +75,7 @@ Widget NewMain(data, updateLocation, context) { color: data.current.backcolor, place: data.place, controller: controller, settings: data.settings, real_loc: data.real_loc, secondColor: data.current.primary, textColor: data.current.textcolor, - highlightColor: data.current.highlight, key: Key("${data.place}, ${data.settings}"),), + highlightColor: data.current.highlight, key: Key("${data.place}, ${data.current.backcolor}"),), ], ) ), @@ -210,7 +210,7 @@ Widget TabletLayout(data, updateLocation, context) { color: data.current.highlight, place: data.place, controller: controller, settings: data.settings, real_loc: data.real_loc, secondColor: data.current.primary, textColor: data.current.textcolor, - highlightColor: data.current.primary, key: Key(data.place),), + highlightColor: data.current.primary, key: Key("${data.place}, ${data.current.backcolor}"),), ], ), ), diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 770fdcf..9a490d8 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -69,7 +69,25 @@ Widget comfortatext(String text, double size, settings, ); } -Color darken(Color c, [double amount = 0.1]) { +Color darken(Color color, [double amount = .1]) { + assert(amount >= 0 && amount <= 1); + + final hsl = HSLColor.fromColor(color); + final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0)); + + return hslDark.toColor(); +} + +Color lighten(Color color, [double amount = .1]) { + assert(amount >= 0 && amount <= 1); + + final hsl = HSLColor.fromColor(color); + final hslLight = hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0)); + + return hslLight.toColor(); +} + +Color darken2(Color c, [double amount = 0.1]) { assert(0 <= amount && amount <= 1); var f = 1 - amount; return Color.fromARGB( @@ -80,7 +98,7 @@ Color darken(Color c, [double amount = 0.1]) { ); } -Color lighten(Color c, [double amount = 0.1]) { +Color lighten2(Color c, [double amount = 0.1]) { assert(0 <= amount && amount <= 1); return Color.fromARGB( c.alpha, @@ -169,6 +187,7 @@ class _FadingWidgetState extends State { String text = translation('updated, just now', widget.data.settings["Language"]); + print(dif); if (dif > 0) { From 6cfc8ff71e25e829e1fc4281cae7d85a6c91187c Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 22 Jul 2024 21:02:52 +0200 Subject: [PATCH 039/129] bumped gradle version before release --- android/app/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 86571e8..74b9bc7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ if (flutterVersionName == null) { android { namespace "com.example.overmorrow" - compileSdkVersion 34 + compileSdk 34 // compileSdkVersion flutter.compileSdkVersion <- this vas the original one but // geolocator insisted on it being 33 ndkVersion flutter.ndkVersion @@ -51,8 +51,8 @@ android { // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdkVersion flutter.minSdkVersion targetSdkVersion flutter.targetSdkVersion - versionCode 37 - versionName "2.3.10" + versionCode 39 + versionName "2.3.11" } buildTypes { From 907c5e0e74ef914fa106b155422114dacca5000a Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 23 Jul 2024 17:58:05 +0200 Subject: [PATCH 040/129] started working on new radar timelines which now display times --- lib/decoders/decode_OM.dart | 30 +++-- lib/decoders/decode_wapi.dart | 59 +++++---- lib/decoders/extra_info.dart | 27 ++-- lib/main_screens.dart | 23 ++-- lib/radar.dart | 240 +++++++++++++++++++++++++++++++++- 5 files changed, 314 insertions(+), 65 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 51e7ef5..ce9442b 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -234,7 +234,7 @@ class OMCurrent { required this.wind_dir, }); - static OMCurrent fromJson(item, settings, sunstatus, timenow) { + static OMCurrent fromJson(item, settings, sunstatus, timenow, palette) { Color back = BackColorCorrection( oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), @@ -246,15 +246,15 @@ class OMCurrent { ); - List colors = getColors(primary, back, settings, - ColorPopCorrection( oMCurrentTextCorrection( - item["current"]["weather_code"], sunstatus, timenow),)[ - settings["Color mode"] == "dark" ? 1 : 0 - ]); + //List colors = getColors(primary, back, settings, + // ColorPopCorrection( oMCurrentTextCorrection( + // item["current"]["weather_code"], sunstatus, timenow),)[ + // settings["Color mode"] == "dark" ? 1 : 0 + // ]); - //List colors = getNetworkColors(palette, settings); + List colors = getNetworkColors(palette, settings); //List colors = palette.colors.toList(); @@ -567,12 +567,12 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as DateTime localtime = OMGetLocalTime(oMBody); String real_time = "jT${localtime.hour}:${localtime.minute}"; - //GET IMAGE - //Image Uimage = await getUnsplashImage(oMCurrentTextCorrection( - // oMBody["current"]["weather_code"], sunstatus, real_time), real_loc); + // GET IMAGE + Image Uimage = await getUnsplashImage(oMCurrentTextCorrection( + oMBody["current"]["weather_code"], sunstatus, real_time), real_loc); //GET COLORS - //List imageColors = await getImageColors(Uimage, settings["Color mode"]); + List imageColors = await getImageColors(Uimage, settings["Color mode"]); return WeatherData( radar: await RainviewerRadar.getData(), @@ -580,7 +580,7 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as sunstatus: sunstatus, minutely_15_precip: OM15MinutePrecip.fromJson(oMBody, settings), - current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time), + current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, imageColors[0]), days: days, lat: lat, @@ -594,5 +594,11 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), localtime: real_time.split("T")[1], + + image: Uimage, + + palette: imageColors[0], + colorpop: imageColors[1], + desc_color: imageColors[2], ); } \ No newline at end of file diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index b39ccda..76d2d9f 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -36,10 +36,8 @@ import 'package:flutter/material.dart'; bool RandomSwitch = false; -DateTime WapiGetLocalTime(item) { - DateTime now = DateTime.now(); - List loctime = item["location"]["localtime"].split(" ")[1].split(); - return now.copyWith(hour: int.parse(loctime[0]), minute: int.parse(loctime[1])); +String WapiGetLocalTime(item) { + return item["location"]["localtime"].split(" ")[1]; } Future> WapiMakeRequest(String latlong, String real_loc) async { @@ -516,16 +514,15 @@ Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) var wapi_body = wapi[0]; DateTime fetch_datetime = wapi[1]; - //final text = textCorrection( - // wapi_body["current"]["condition"]["code"], wapi_body["current"]["is_day"], - // language: "English"); + final text = textCorrection( + wapi_body["current"]["condition"]["code"], wapi_body["current"]["is_day"], + language: "English"); //GET IMAGE - - //Image Uimage = await getUnsplashImage(text, real_loc); + Image Uimage = await getUnsplashImage(text, real_loc); //GET COLORS - //List imageColors = await getImageColors(Uimage, settings["Color mode"]); + List imageColors = await getImageColors(Uimage, settings["Color mode"]); //String real_time = wapi_body["location"]["localtime"]; int epoch = wapi_body["location"]["localtime_epoch"]; @@ -539,23 +536,29 @@ Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) } return WeatherData( - place: placeName, - settings: settings, - provider: "weatherapi.com", - real_loc: real_loc, - - lat: lat, - lng: lng, - - current: WapiCurrent.fromJson(wapi_body, settings,), - days: days, - sunstatus: sunstatus, - aqi: WapiAqi.fromJson(wapi_body), - radar: await RainviewerRadar.getData(), - - fetch_datetime: fetch_datetime, - updatedTime: DateTime.now(), - localtime: WapiGetLocalTime(wapi_body), - minutely_15_precip: const OM15MinutePrecip(t_minus: "", precip_sum: 0, precips: []), //because wapi doesn't have 15 minutely + place: placeName, + settings: settings, + provider: "weatherapi.com", + real_loc: real_loc, + + lat: lat, + lng: lng, + + current: WapiCurrent.fromJson(wapi_body, settings,), + days: days, + sunstatus: sunstatus, + aqi: WapiAqi.fromJson(wapi_body), + radar: await RainviewerRadar.getData(), + + fetch_datetime: fetch_datetime, + updatedTime: DateTime.now(), + localtime: WapiGetLocalTime(wapi_body), + minutely_15_precip: const OM15MinutePrecip(t_minus: "", precip_sum: 0, precips: []), //because wapi doesn't have 15 minutely + + image: Uimage, + + palette: imageColors[0], + colorpop: imageColors[1], + desc_color: imageColors[2], ); } diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 9a68966..4909740 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -250,13 +250,12 @@ class WeatherData { final fetch_datetime; - //final image; + final image; final localtime; - //final palette; - //final colorpop; - //final desc_color; - //final gradientColors; + final palette; + final colorpop; + final desc_color; WeatherData({ required this.place, @@ -272,14 +271,14 @@ class WeatherData { required this.current, required this.fetch_datetime, required this.updatedTime, - //required this.image, + required this.image, required this.localtime, - //required this.palette, - //required this.colorpop, - //required this.desc_color, - //required this.gradientColors, required this.minutely_15_precip, + + required this.palette, + required this.colorpop, + required this.desc_color, }); static Future getFullData(settings, placeName, real_loc, latlong, provider) async { @@ -320,7 +319,7 @@ class RainviewerRadar { final String host = data["host"]; - int timenow = DateTime.now().toUtc().microsecond; + //int timenow = DateTime.now().toUtc().microsecond; List images = []; List times = []; @@ -329,14 +328,14 @@ class RainviewerRadar { final future = data["radar"]["nowcast"]; for (var x in past) { - DateTime time = DateTime.fromMillisecondsSinceEpoch(x["time"]); + DateTime time = DateTime.fromMillisecondsSinceEpoch(x["time"] * 1000); images.add(host + x["path"]); times.add("${time.hour}h ${time.minute}m"); } for (var x in future) { - int dif = x["time"] * 1000 - timenow; - DateTime time = DateTime.fromMicrosecondsSinceEpoch(dif); + //int dif = x["time"] * 1000 - timenow; + DateTime time = DateTime.fromMillisecondsSinceEpoch(x["time"] * 1000); images.add(host + x["path"]); times.add("${time.hour}h ${time.minute}m"); } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 92e4ff0..4e7ad12 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -20,10 +20,12 @@ import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:overmorrow/radar.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:material_floating_search_bar_2/material_floating_search_bar_2.dart'; import 'package:stretchy_header/stretchy_header.dart'; import 'main_ui.dart'; +import 'new_displays.dart'; import 'ui_helper.dart'; Widget NewMain(data, updateLocation, context) { @@ -44,8 +46,8 @@ Widget NewMain(data, updateLocation, context) { headerData: HeaderData( //backgroundColor: WHITE, blurContent: false, - headerHeight: max(size.height * 0.54, 400), //we don't want it to be smaller than 400 - header: ParrallaxBackground(image: Image.asset("assets/backdrops/${data.current.backdrop}", fit: BoxFit.cover,), key: Key(data.place), + headerHeight: max(size.height * 0.53, 400), //we don't want it to be smaller than 400 + header: ParrallaxBackground(image: data.image, key: Key(data.place), color: data.current.backcolor == BLACK ? BLACK : lightAccent(data.current.backcolor, 5000)), overlay: Stack( @@ -61,12 +63,13 @@ Widget NewMain(data, updateLocation, context) { Padding( padding: const EdgeInsets.only(left: 0, bottom: 2), child: comfortatext("${data.current.temp}°", 68, data.settings, - color: data.current.colorpop, weight: FontWeight.w300), + color: data.colorpop, weight: FontWeight.w300), ), Padding( padding: const EdgeInsets.only(left: 0), child: comfortatext(data.current.text, 32, data.settings, - weight: data.settings["Color mode"] == "dark" ? FontWeight.w600 : FontWeight.w400, color: WHITE), + weight: data.settings["Color mode"] == "dark" ? FontWeight.w600 : FontWeight.w400, + color: data.desc_color), ) ], ), @@ -86,19 +89,20 @@ Widget NewMain(data, updateLocation, context) { LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { if(constraints.maxWidth > 500.0) { - return Circles(500, data, 0.5, data.current.primary); + return Circles(500, data, 0.5, data.palette.primary); } else { - return Circles(constraints.maxWidth * 0.97, data, 0.5, data.current.primary); + return Circles(constraints.maxWidth * 0.97, data, 0.5, data.palette.primary); } } ), ], ), - /* + NewSunriseSunset(data: data, key: Key(data.place), size: size,), NewRain15MinuteIndicator(data), NewAirQuality(data), + RadarSmall(data: data, key: Key("${data.place}, ${data.current.backcolor}")), Padding( padding: const EdgeInsets.only(top: 10, bottom: 30), @@ -106,14 +110,15 @@ Widget NewMain(data, updateLocation, context) { data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), ), - */ + /* NewTimes(data, true), - //RadarMap(data: data, key: Key(data.place),), buildHihiDays(data), buildGlanceDay(data), providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), + + */ const Padding(padding: EdgeInsets.only(bottom: 20)) diff --git a/lib/radar.dart b/lib/radar.dart index cced279..523f392 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -19,8 +19,10 @@ along with this program. If not, see . import 'dart:async'; import 'dart:math'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:overmorrow/ui_helper.dart'; import 'package:latlong2/latlong.dart'; @@ -74,7 +76,7 @@ class _RadarMapState extends State { return Column( children: [ Padding( - padding: EdgeInsets.only(left: 20, bottom: 0), + padding: const EdgeInsets.only(left: 20, bottom: 0), child: Align( alignment: Alignment.centerLeft, child: comfortatext(translation('radar', data.settings["Language"]), 19, data.settings, @@ -345,7 +347,7 @@ class _RadarPageState extends State { borderRadius: BorderRadius.circular(18), color: top, ), - padding: EdgeInsets.all(6), + padding: const EdgeInsets.all(6), child: Row( children: [ AnimatedSwitcher( @@ -458,4 +460,238 @@ class _RadarPageState extends State { ], ); } +} + + +class RadarSmall extends StatefulWidget { + + final data; + + const RadarSmall({Key? key, required this.data}) : super(key: key); + + @override + _RadarSmallState createState() => _RadarSmallState(data); +} + +class _RadarSmallState extends State { + double currentFrameIndex = 12; + late Timer timer; + + final data; + + _RadarSmallState(this.data); + + bool isPlaying = false; + + @override + void initState() { + super.initState(); + + timer = Timer.periodic(const Duration(milliseconds: 1500), (Timer t) { + if (isPlaying) { + setState(() { + currentFrameIndex = + ((currentFrameIndex + 1) % (data.radar.images.length - 1)); + }); + } + }); + } + + @override + void dispose() { + timer.cancel(); + super.dispose(); + } + + void togglePlayPause() { + setState(() { + isPlaying = !isPlaying; + }); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.only(left: 25, top: 20), + child: Align( + alignment: Alignment.centerLeft, + child: comfortatext( + translation('radar', data.settings["Language"]), 16, + data.settings, + color: data.palette.primary), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 25, right: 25, top: 12, bottom: 10), + child: AspectRatio( + aspectRatio: 1.57, + child: Container( + decoration: BoxDecoration( + color: data.palette.surfaceContainerHigh, + borderRadius: BorderRadius.circular(18), + border: Border.all( + width: 2.2, color: data.palette.surfaceContainerHigh) + ), + child: Stack( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(17), + child: FlutterMap( + options: MapOptions( + onTap: (tapPosition, point) => + { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => RadarPage(data: data,)), + ) + }, + initialCenter: LatLng(data.lat, data.lng), + initialZoom: 6, + backgroundColor: WHITE, + keepAlive: true, + maxZoom: 6, + minZoom: 6, + interactionOptions: const InteractionOptions( + flags: InteractiveFlag.drag | InteractiveFlag + .flingAnimation), + cameraConstraint: CameraConstraint.containCenter( + bounds: LatLngBounds( + LatLng(data.lat - 3, data.lng - 3), + LatLng(data.lat + 3, data.lng + 3), + ), + ), + ), + children: [ + TileLayer( + urlTemplate: data.settings["Color theme"] == "dark" + ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' + : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', + ), + TileLayer( + urlTemplate: data.radar.images[currentFrameIndex + .toInt()] + "/256/{z}/{x}/{y}/8/1_1.png", + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.only(right: 8, top: 8), + child: Align( + alignment: Alignment.topRight, + child: Hero( + tag: 'switch', + child: SizedBox( + height: 45, + width: 45, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.all(10), + elevation: 0.0, + backgroundColor: data.palette.surfaceContainer, + //side: BorderSide(width: 3, color: main), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15) + ), + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => + RadarPage(data: data,)), + ); + }, + child: Icon(CupertinoIcons.fullscreen, + color: data.palette.primaryFixedDim, size: 20,), + ), + ), + ), + ), + ), + ], + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 40, right: 25, bottom: 20, top: 10), + child: Row( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + transitionBuilder: (Widget child, Animation animation) { + return ScaleTransition(scale: animation, child: child,); + }, + child: Hero( + tag: 'playpause', + key: ValueKey(isPlaying), + child: SizedBox( + height: 46, + width: 46, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 0.0, + padding: const EdgeInsets.all(10), + backgroundColor: data.palette.primaryFixedDim, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18) + ) + ), + onPressed: () async { + togglePlayPause(); + }, + child: Icon(isPlaying ? Icons.pause : Icons.play_arrow, + color: data.palette.surface, size: 18,), + + ), + ), + ), + ), + + Expanded( + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + trackHeight: 18, + valueIndicatorTextStyle: GoogleFonts.comfortaa( + color: WHITE, + fontSize: 12, + ), + + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 10, elevation: 0.0, + pressedElevation: 0), + + tickMarkShape: RoundSliderTickMarkShape(tickMarkRadius: 2), + + ), + child: Slider( + value: currentFrameIndex, + min: 0, + max: data.radar.times.length - 1.0, + divisions: data.radar.times.length, + label: data.radar.times[currentFrameIndex.toInt()] + .toString(), + + activeColor: data.palette.primaryFixedDim, + inactiveColor: data.palette.surface, + //thumbColor: data.palette.primary, + + onChanged: (double value) { + setState(() { + currentFrameIndex = value; + }); + }, + ), + ), + ), + ], + ), + ), + + ], + ); + } } \ No newline at end of file From 3c8e371b52fed8e464668ba29781821ccd33467f Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 24 Jul 2024 16:52:14 +0200 Subject: [PATCH 041/129] improved new radar --- lib/new_displays.dart | 10 +- lib/radar.dart | 397 +++++++++++++++++++++++++++++++++++----- lib/search_screens.dart | 2 +- 3 files changed, 361 insertions(+), 48 deletions(-) diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 739afaa..1253a4f 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -176,7 +176,7 @@ class _NewSunriseSunsetState extends State final textWidth = textPainter.width; return Padding( - padding: const EdgeInsets.only(left: 25, right: 25, top: 8), + padding: const EdgeInsets.only(left: 25, right: 25, top: 10), child: Column( children: [ Padding( @@ -266,7 +266,7 @@ class _NewSunriseSunsetState extends State Widget NewAirQuality(var data) { return Padding( - padding: const EdgeInsets.only(left: 20, right: 20, bottom: 19, top: 20), + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 19, top: 24), child: Column( children: [ Padding( @@ -324,7 +324,7 @@ Widget NewAirQuality(var data) { Padding( padding: const EdgeInsets.all(3.0), child: comfortatext(data.aqi.aqi_desc, 14, data.settings, - color: data.palette.primary, weight: FontWeight.w600), + color: data.palette.primary, weight: FontWeight.w500), ), ], ), @@ -352,7 +352,7 @@ Widget NewRain15MinuteIndicator(var data) { return Visibility( visible: data.minutely_15_precip.t_minus != "", child: Padding( - padding: const EdgeInsets.only(left: 21, right: 21, top: 18, bottom: 10), + padding: const EdgeInsets.only(left: 21, right: 21, top: 20, bottom: 10), child: Container( decoration: BoxDecoration( color: data.palette.surfaceContainerLow, @@ -387,7 +387,7 @@ Widget NewRain15MinuteIndicator(var data) { "rain expected in ${data.minutely_15_precip.t_minus}", 14, data.settings, - color: data.palette.onPrimaryContainer), + color: data.palette.onPrimaryContainer, weight: FontWeight.w500), ), ), ], diff --git a/lib/radar.dart b/lib/radar.dart index 523f392..048aa00 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -479,6 +479,8 @@ class _RadarSmallState extends State { final data; + List times = []; + _RadarSmallState(this.data); bool isPlaying = false; @@ -487,7 +489,20 @@ class _RadarSmallState extends State { void initState() { super.initState(); - timer = Timer.periodic(const Duration(milliseconds: 1500), (Timer t) { + int precived_hour = int.parse(data.localtime.split(":")[0]); + int real = int.parse(data.radar.times[11].split("h")[0]); + + int offset = precived_hour - real; + + String x; + + for (int i = 0; i < data.radar.times.length; i++) { + List split = data.radar.times[i].split("h"); + String minute = split[1].replaceAll(RegExp(r"\D"), ""); + times.add("${int.parse(split[0]) + offset}:${minute == "0" ? "00" : minute}"); + } + + timer = Timer.periodic(const Duration(milliseconds: 1000), (Timer t) { if (isPlaying) { setState(() { currentFrameIndex = @@ -573,7 +588,7 @@ class _RadarSmallState extends State { ), TileLayer( urlTemplate: data.radar.images[currentFrameIndex - .toInt()] + "/256/{z}/{x}/{y}/8/1_1.png", + .toInt()] + "/256/{z}/{x}/{y}/8/0_1.png", ), ], ), @@ -585,8 +600,8 @@ class _RadarSmallState extends State { child: Hero( tag: 'switch', child: SizedBox( - height: 45, - width: 45, + height: 48, + width: 48, child: ElevatedButton( style: ElevatedButton.styleFrom( padding: const EdgeInsets.all(10), @@ -601,7 +616,7 @@ class _RadarSmallState extends State { Navigator.push( context, MaterialPageRoute(builder: (context) => - RadarPage(data: data,)), + RadarBig(data: data,)), ); }, child: Icon(CupertinoIcons.fullscreen, @@ -617,7 +632,7 @@ class _RadarSmallState extends State { ), ), Padding( - padding: const EdgeInsets.only(left: 40, right: 25, bottom: 20, top: 10), + padding: const EdgeInsets.only(left: 38, right: 25, bottom: 20, top: 10), child: Row( children: [ AnimatedSwitcher( @@ -629,22 +644,23 @@ class _RadarSmallState extends State { tag: 'playpause', key: ValueKey(isPlaying), child: SizedBox( - height: 46, - width: 46, + height: 48, + width: 48, child: ElevatedButton( style: ElevatedButton.styleFrom( elevation: 0.0, padding: const EdgeInsets.all(10), - backgroundColor: data.palette.primaryFixedDim, + backgroundColor: data.palette.surfaceContainer, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(18) + borderRadius: BorderRadius.circular(16), + //side: BorderSide(width: 2, color: data.palette.primaryFixed) ) ), onPressed: () async { togglePlayPause(); }, - child: Icon(isPlaying ? Icons.pause : Icons.play_arrow, - color: data.palette.surface, size: 18,), + child: Icon(isPlaying ? Icons.pause_outlined : Icons.play_arrow, + color: data.palette.primaryFixedDim, size: 18,), ), ), @@ -652,46 +668,343 @@ class _RadarSmallState extends State { ), Expanded( - child: SliderTheme( - data: SliderTheme.of(context).copyWith( - trackHeight: 18, - valueIndicatorTextStyle: GoogleFonts.comfortaa( - color: WHITE, - fontSize: 12, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(left: 8, right: 8), + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + trackHeight: 18, + valueIndicatorTextStyle: GoogleFonts.comfortaa( + color: WHITE, + fontSize: 12, + ), + + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 10, elevation: 0.0, + pressedElevation: 0), + + tickMarkShape: RoundSliderTickMarkShape(tickMarkRadius: 2), + overlayShape: SliderComponentShape.noOverlay + + ), + child: Slider( + value: currentFrameIndex, + min: 0, + max: data.radar.times.length - 1.0, + divisions: data.radar.times.length, + label: times[currentFrameIndex.toInt()] + .toString(), + + activeColor: data.palette.primaryFixed, + inactiveColor: data.palette.surface, + //thumbColor: data.palette.primary, + + onChanged: (double value) { + setState(() { + currentFrameIndex = value; + }); + }, + ), + ), ), + Padding( + padding: const EdgeInsets.only(left: 16, right: 16, top: 9), + child: Row( + children: [ + comfortatext('-2hr', 13, data.settings, color: data.palette.onPrimaryContainer), + Expanded( + flex: 6, + child: Align( + alignment: Alignment.centerRight, + child: comfortatext('-1hr', 13, data.settings, color: data.palette.onPrimaryContainer) + ), + ), + Expanded( + flex: 6, + child: Align( + alignment: Alignment.centerRight, + child: comfortatext('now', 13, data.settings, color: data.palette.onPrimaryContainer) + ), + ), + Expanded( + flex: 3, + child: Align( + alignment: Alignment.centerRight, + child: comfortatext('30m', 13, data.settings, color: data.palette.onPrimaryContainer) + ), + ), + ], + ), + ) + ], + ), + ), + ], + ), + ), + ], + ); + } +} - thumbShape: const RoundSliderThumbShape( - enabledThumbRadius: 10, elevation: 0.0, - pressedElevation: 0), - tickMarkShape: RoundSliderTickMarkShape(tickMarkRadius: 2), +class RadarBig extends StatefulWidget { + final data; + + const RadarBig({Key? key, this.data}) : super(key: key); + + @override + _RadarBigState createState() => _RadarBigState(data: data); +} +class _RadarBigState extends State { + double currentFrameIndex = 12; + late Timer timer; + + List times = []; + + final data; + + _RadarBigState({this.data}); + + bool isPlaying = false; + + @override + void initState() { + super.initState(); + + int precived_hour = int.parse(data.localtime.split(":")[0]); + int real = int.parse(data.radar.times[11].split("h")[0]); + + int offset = precived_hour - real; + + String x; + + for (int i = 0; i < data.radar.times.length; i++) { + List split = data.radar.times[i].split("h"); + String minute = split[1].replaceAll(RegExp(r"\D"), ""); + times.add("${int.parse(split[0]) + offset}:${minute == "0" ? "00" : minute}"); + } + + + timer = Timer.periodic(const Duration(milliseconds: 1600), (Timer t) { + if (isPlaying) { + setState(() { + currentFrameIndex = + ((currentFrameIndex + 1) % (data.radar.images.length - 1)); + }); + } + }); + } + + @override + void dispose() { + timer.cancel(); + super.dispose(); + } + + void togglePlayPause() { + setState(() { + isPlaying = !isPlaying; + }); + } + + @override + Widget build(BuildContext context) { + double x = MediaQuery.of(context).padding.top; + Color main = data.current.textcolor; + Color top = lighten(data.current.highlight, 0.1); + return Scaffold( + body: Stack( + children: [ + FlutterMap( + options: MapOptions( + initialCenter: LatLng(data.lat, data.lng), + initialZoom: 5, + minZoom: 2, + maxZoom: 8, + + backgroundColor: WHITE, + interactionOptions: const InteractionOptions(flags: InteractiveFlag.all & ~InteractiveFlag.rotate,), + ), + children: [ + Container( + color: data.settings["Color theme"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), + ), + TileLayer( + urlTemplate: data.settings["Color theme"] == "dark" + ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' + : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', + ), + TileLayer( + urlTemplate: data.radar.images[currentFrameIndex.toInt()] + "/256/{z}/{x}/{y}/8/1_1.png", + ), + TileLayer( + urlTemplate: data.settings["Color theme"] == "dark" + ? 'https://{s}.basemaps.cartocdn.com/dark_only_labels/{z}/{x}/{y}.png' + : 'https://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', + ), + ], + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.only(left: 15, right: 15, bottom: 25), + child: Container( + height: 100, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + color: data.palette.surface, + ), + child: Padding( + padding: const EdgeInsets.only(left: 24, right: 12), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + transitionBuilder: (Widget child, Animation animation) { + return ScaleTransition(scale: animation, child: child,); + }, + child: Hero( + tag: 'playpause', + key: ValueKey(isPlaying), + child: SizedBox( + height: 48, + width: 48, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 0.0, + padding: const EdgeInsets.all(10), + backgroundColor: data.palette.surfaceContainer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + //side: BorderSide(width: 2, color: data.palette.primaryFixed) + ) + ), + onPressed: () async { + togglePlayPause(); + }, + child: Icon(isPlaying ? Icons.pause_outlined : Icons.play_arrow, + color: data.palette.primaryFixedDim, size: 18,), + + ), + ), + ), + ), + + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only(left: 8, right: 8), + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + trackHeight: 18, + valueIndicatorTextStyle: GoogleFonts.comfortaa( + color: WHITE, + fontSize: 12, + ), + + thumbShape: const RoundSliderThumbShape( + enabledThumbRadius: 10, elevation: 0.0, + pressedElevation: 0), + + tickMarkShape: RoundSliderTickMarkShape(tickMarkRadius: 2), + overlayShape: SliderComponentShape.noOverlay + + ), + child: Slider( + value: currentFrameIndex, + min: 0, + max: data.radar.times.length - 1.0, + divisions: data.radar.times.length, + label: times[currentFrameIndex.toInt()] + .toString(), + + activeColor: data.palette.primaryFixed, + inactiveColor: data.palette.surface, + //thumbColor: data.palette.primary, + + onChanged: (double value) { + setState(() { + currentFrameIndex = value; + }); + }, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 16, right: 16, top: 9), + child: Row( + children: [ + comfortatext('-2hr', 13, data.settings, color: data.palette.onPrimaryContainer), + Expanded( + flex: 6, + child: Align( + alignment: Alignment.centerRight, + child: comfortatext('-1hr', 13, data.settings, color: data.palette.onPrimaryContainer) + ), + ), + Expanded( + flex: 6, + child: Align( + alignment: Alignment.centerRight, + child: comfortatext('now', 13, data.settings, color: data.palette.onPrimaryContainer) + ), + ), + Expanded( + flex: 3, + child: Align( + alignment: Alignment.centerRight, + child: comfortatext('30m', 13, data.settings, color: data.palette.onPrimaryContainer) + ), + ), + ], + ), + ) + ], + ), + ), + ], ), - child: Slider( - value: currentFrameIndex, - min: 0, - max: data.radar.times.length - 1.0, - divisions: data.radar.times.length, - label: data.radar.times[currentFrameIndex.toInt()] - .toString(), - - activeColor: data.palette.primaryFixedDim, - inactiveColor: data.palette.surface, - //thumbColor: data.palette.primary, - - onChanged: (double value) { - setState(() { - currentFrameIndex = value; - }); + ), + ), + ), + ), + Padding( + padding: EdgeInsets.only(right: 15, top: x + 15), + child: Align( + alignment: Alignment.topRight, + child: Hero( + tag: 'switch', + child: SizedBox( + height: 52, //the big space looks ugly with a small button + width: 52, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.all(10), + elevation: 0.0, + backgroundColor: data.palette.surface, + //side: BorderSide(width: 3, color: main), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15) + ), + ), + onPressed: () { + Navigator.of(context).pop(); }, + child: Icon(CupertinoIcons.fullscreen_exit, + color: data.palette.primaryFixedDim, size: 21,), ), ), ), - ], + ), ), - ), - - ], + ], + ), ); } } \ No newline at end of file diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 53759e0..2786dbe 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -494,7 +494,7 @@ class dumbySearch extends StatelessWidget { align: TextAlign.center), Padding( padding: const EdgeInsets.only(top: 20), - child: comfortatext(shouldAdd, 20, settings, color: Colors.black54, weight: FontWeight.w500, + child: comfortatext(shouldAdd ?? "", 20, settings, color: Colors.black54, weight: FontWeight.w500, align: TextAlign.center), ), ], From 88c698a3d3bf9e82861094cb43b99df3fc4d8a9e Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 25 Jul 2024 19:14:37 +0200 Subject: [PATCH 042/129] Weather Icons are now icons and not images --- fonts/OvermorrowWeatherIcons.ttf | Bin 0 -> 7840 bytes lib/Icons/overmorrow_weather_icons_icons.dart | 38 +++++++++++++++++ pubspec.lock | 40 +++++++++--------- pubspec.yaml | 6 +++ 4 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 fonts/OvermorrowWeatherIcons.ttf create mode 100644 lib/Icons/overmorrow_weather_icons_icons.dart diff --git a/fonts/OvermorrowWeatherIcons.ttf b/fonts/OvermorrowWeatherIcons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..07078e021d74d025deb544c4b3dc819791d1d0ac GIT binary patch literal 7840 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 Date: Fri, 26 Jul 2024 16:04:39 +0200 Subject: [PATCH 043/129] started working on new days view --- lib/decoders/decode_OM.dart | 23 ++- lib/main_screens.dart | 2 + lib/new_displays.dart | 2 +- lib/new_forecast.dart | 275 ++++++++++++++++++++++++++++++++++++ lib/radar.dart | 10 +- lib/weather_refact.dart | 38 +++++ 6 files changed, 337 insertions(+), 13 deletions(-) create mode 100644 lib/new_forecast.dart diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index ce9442b..6cfb131 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -22,6 +22,7 @@ import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:overmorrow/Icons/overmorrow_weather_icons_icons.dart'; import 'package:overmorrow/decoders/decode_wapi.dart'; import '../caching.dart'; @@ -187,8 +188,15 @@ List oMtextcolorCorrection(String text) { return textFontColor[text] ?? [WHITE, WHITE]; } -String oMIconCorrection(String text) { - return textIconMap[text] ?? 'sun.png'; +IconData oMIconCorrection(String text) { + //return textIconMap[text] ?? 'sun.png'; + return textMaterialIcon[text] ?? OvermorrowWeatherIcons.sun; +} + + +double oMIconSizeCorrection(String text) { + //return textIconMap[text] ?? 'sun.png'; + return textIconSizeNormalize[text] ?? 1; } @@ -299,7 +307,10 @@ class OMCurrent { class OMDay { final String text; - final String icon; + + final IconData icon; + final double iconSize; + final String name; final String minmaxtemp; final List hourly; @@ -316,7 +327,10 @@ class OMDay { const OMDay({ required this.text, + required this.icon, + required this.iconSize, + required this.name, required this.minmaxtemp, required this.hourly, @@ -335,6 +349,7 @@ class OMDay { return OMDay( uv: item["daily"]["uv_index_max"][0].round(), icon: oMIconCorrection(oMTextCorrection(item["daily"]["weather_code"][index])), + iconSize: oMIconSizeCorrection(oMTextCorrection(item["daily"]["weather_code"][index])), text: translation(oMTextCorrection(item["daily"]["weather_code"][index]), settings["Language"]), name: oMGetName(index, settings, item), windspeed: unit_coversion(item["daily"]["wind_speed_10m_max"][index], settings["Wind"]).round(), @@ -444,7 +459,7 @@ class OM15MinutePrecip { class OMHour { final int temp; - final String icon; + final IconData icon; final String time; final String text; final double precip; diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 4e7ad12..5b354b8 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -20,6 +20,7 @@ import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:overmorrow/new_forecast.dart'; import 'package:overmorrow/radar.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:material_floating_search_bar_2/material_floating_search_bar_2.dart'; @@ -103,6 +104,7 @@ Widget NewMain(data, updateLocation, context) { NewRain15MinuteIndicator(data), NewAirQuality(data), RadarSmall(data: data, key: Key("${data.place}, ${data.current.backcolor}")), + buildNewDays(data), Padding( padding: const EdgeInsets.only(top: 10, bottom: 30), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 1253a4f..446ffc3 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -332,7 +332,7 @@ Widget NewAirQuality(var data) { ], ), Padding( - padding: const EdgeInsets.only(top: 12, left: 13, right: 13), + padding: const EdgeInsets.only(top: 15, left: 14, right: 14), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart new file mode 100644 index 0000000..bf00342 --- /dev/null +++ b/lib/new_forecast.dart @@ -0,0 +1,275 @@ +/* +Copyright (C) <2024> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:overmorrow/settings_page.dart'; +import 'decoders/decode_wapi.dart'; +import 'ui_helper.dart'; + + +class NewDay extends StatefulWidget { + final data; + final index; + + NewDay({Key? key, required this.data, required this.index}) : super(key: key); + + @override + _NewDayState createState() => _NewDayState(data); +} + +class _NewDayState extends State { + final data; + + int _value = 0; + + _NewDayState(this.data); + + @override + Widget build(BuildContext context) { + final day = data.days[widget.index]; + + return Padding( + padding: const EdgeInsets.only(left: 20, right: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 5, top: 0), + child: Align( + alignment: Alignment.centerLeft, + child: comfortatext( + translation(day.name, data.settings["Language"]), 16, + data.settings, + color: data.palette.primary), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 20, left: 15, right: 20), + child: Row( + children: [ + Icon(day.icon, size: 37.0 * day.iconSize, color: data.palette.primary,), + Padding( + padding: EdgeInsets.only(left: 12.0 / day.iconSize, top: 3), + child: comfortatext(day.text, 22, data.settings, color: data.palette.primaryFixedDim, + weight: FontWeight.w400), + ), + Spacer(), + Padding( + padding: const EdgeInsets.only(top: 5), + child: comfortatext(day.minmaxtemp, 20, data.settings, color: data.palette.primary), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8, right: 8, top: 20, bottom: 10), + child: Container( + height: 85, + padding: const EdgeInsets.only(top: 8, bottom: 8, left: 10, right: 10), + decoration: BoxDecoration( + //border: Border.all(width: 1.2, color: data.palette.primary), + color: data.palette.surfaceContainerLow, + borderRadius: BorderRadius.circular(18), + ), + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return GridView.count( + padding: const EdgeInsets.all(0), + physics: const NeverScrollableScrollPhysics(), + crossAxisSpacing: 1, + mainAxisSpacing: 1, + crossAxisCount: 2, + childAspectRatio: constraints.maxWidth / constraints.maxHeight, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 8, right: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.water_drop_outlined, + color: data.palette.primaryFixedDim, size: 21), + Padding( + padding: const EdgeInsets.only(left: 10, top: 3), + child: comfortatext('${day.precip_prob}%', 18, data.settings, + color: data.palette.primary), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 8, right: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.water_drop, color: data.palette.primaryFixedDim, size: 21), + Padding( + padding: const EdgeInsets.only(top: 3, left: 10), + child: comfortatext(day.total_precip.toString() + + data.settings["Precipitation"], 18, data.settings, + color: data.palette.primary), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 8, right: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + CupertinoIcons.wind, color: data.palette.primaryFixedDim, size: 21,), + Padding( + padding: const EdgeInsets.only(top: 3, left: 10), + child: comfortatext('${day.windspeed} ${data + .settings["Wind"]}', 18, data.settings, + color: data.palette.primary), + ), + Padding( + padding: const EdgeInsets.only(left: 5, right: 3), + child: RotationTransition( + turns: AlwaysStoppedAnimation(day.wind_dir / 360), + child: Icon(CupertinoIcons.arrow_up_circle, + color: data.palette.primaryFixedDim, size: 18,) + ) + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 8, right: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(CupertinoIcons.sun_max, + color: data.palette.primaryFixedDim, size: 21), + Padding( + padding: const EdgeInsets.only(top: 3, left: 10), + child: comfortatext('${day.uv} UV', 18, data.settings, + color: data.palette.primary), + ), + ], + ), + ), + ] + ); + } + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 10, right: 10), + child: Wrap( + spacing: 5.0, + children: List.generate( + 4, + (int index) { + return ChoiceChip( + checkmarkColor: data.palette.onPrimaryContainer, + selectedColor: data.palette.primaryFixedDim, + backgroundColor: data.palette.surfaceContainerLow, + side: BorderSide.none, + label: comfortatext(['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, + color: data.palette.onPrimaryContainer), + selected: _value == index, + onSelected: (bool selected) { + setState(() { + _value = (selected ? index : null)!; + }); + }, + ); + }, + ).toList(), + ), + ), + SizedBox(height: 200,), + ], + ), + ); + } +} + +Widget buildNewDays(data) { + return ListView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: 3, + itemBuilder: (BuildContext context, int index) { + return NewDay(data: data, index: index); + }, + ); +} + + +Widget buildNewHours(List hours, data) => SizedBox( + height: 285, + child: ListView( + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: hours.map((hour) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 10), + child: comfortatext('${hour.temp}°', 22, data.settings, color: data.current.primary), + ), + Stack( + alignment: Alignment.bottomCenter, + children: [ + Container( + width: 15, + height: 100, + decoration: BoxDecoration( + border: Border.all( + color: data.current.secondary, + ), + borderRadius: const BorderRadius.all(Radius.circular(20)) + ), + ), + Container( + width: 15, + height: temp_multiply_for_scale(hour.temp, data.settings['Temperature']!), + decoration: BoxDecoration( + color: data.current.secondary, + borderRadius: const BorderRadius.all(Radius.circular(20)) + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.only(top: 20, left: 3, right: 3), + child: Icon( + hour.icon + ) + ), + Padding( + padding: const EdgeInsets.only(top:20, left: 9, right: 9), + child: comfortatext(hour.time, 17, data.settings, color: data.current.primary) + ) + ], + ); + }).toList(), + ), +); \ No newline at end of file diff --git a/lib/radar.dart b/lib/radar.dart index 048aa00..408394b 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -494,8 +494,6 @@ class _RadarSmallState extends State { int offset = precived_hour - real; - String x; - for (int i = 0; i < data.radar.times.length; i++) { List split = data.radar.times[i].split("h"); String minute = split[1].replaceAll(RegExp(r"\D"), ""); @@ -632,7 +630,7 @@ class _RadarSmallState extends State { ), ), Padding( - padding: const EdgeInsets.only(left: 38, right: 25, bottom: 20, top: 10), + padding: const EdgeInsets.only(left: 38, right: 25, bottom: 0, top: 10), child: Row( children: [ AnimatedSwitcher( @@ -684,8 +682,8 @@ class _RadarSmallState extends State { enabledThumbRadius: 10, elevation: 0.0, pressedElevation: 0), + overlayColor: BLACK, tickMarkShape: RoundSliderTickMarkShape(tickMarkRadius: 2), - overlayShape: SliderComponentShape.noOverlay ), child: Slider( @@ -779,8 +777,6 @@ class _RadarBigState extends State { int offset = precived_hour - real; - String x; - for (int i = 0; i < data.radar.times.length; i++) { List split = data.radar.times[i].split("h"); String minute = split[1].replaceAll(RegExp(r"\D"), ""); @@ -813,8 +809,6 @@ class _RadarBigState extends State { @override Widget build(BuildContext context) { double x = MediaQuery.of(context).padding.top; - Color main = data.current.textcolor; - Color top = lighten(data.current.highlight, 0.1); return Scaffold( body: Stack( children: [ diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 046ec24..5452795 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -17,6 +17,9 @@ along with this program. If not, see . */ import 'dart:ui'; +import 'package:overmorrow/Icons/overmorrow_weather_icons_icons.dart'; +import 'package:flutter/material.dart'; + import 'ui_helper.dart'; Map textIconMap = { @@ -36,6 +39,41 @@ Map textIconMap = { 'Cloudy Night' : 'cloudy_night.png', }; +Map textMaterialIcon = { + 'Clear Night': OvermorrowWeatherIcons.moon2, + 'Partly Cloudy': OvermorrowWeatherIcons.partly_cloudy, + 'Clear Sky': OvermorrowWeatherIcons.sun, + 'Overcast': OvermorrowWeatherIcons.cloudy2, + 'Haze': OvermorrowWeatherIcons.haze2, + 'Rain': OvermorrowWeatherIcons.rain2, + 'Sleet': OvermorrowWeatherIcons.sleet2, + 'Drizzle': OvermorrowWeatherIcons.drizzle2, + 'Thunderstorm': OvermorrowWeatherIcons.lightning2, + 'Heavy Snow': OvermorrowWeatherIcons.heavy_snow2, + 'Fog': OvermorrowWeatherIcons.fog2, + 'Snow': OvermorrowWeatherIcons.snow2, + 'Heavy Rain': OvermorrowWeatherIcons.heavy_rain2, + 'Cloudy Night' : OvermorrowWeatherIcons.cloudy_night2, +}; + + +Map textIconSizeNormalize = { + 'Clear Night': 1, + 'Partly Cloudy': 1, + 'Clear Sky': 1, + 'Overcast': 0.72, + 'Haze': 1, + 'Rain': 1, + 'Sleet': 1, + 'Drizzle': 1, + 'Thunderstorm': 1, + 'Heavy Snow': 1, + 'Fog': 1, + 'Snow': 1, + 'Heavy Rain': 1, + 'Cloudy Night' : 1, +}; + Map weatherTextMap = { 1000: 'Clear Sky', 1003: 'Partly Cloudy', From 0ebe73343c59fa4d4b7b16885ef786631010f258 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 27 Jul 2024 18:21:52 +0200 Subject: [PATCH 044/129] did a small ui tweak --- lib/new_forecast.dart | 2 +- lib/radar.dart | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index bf00342..51e000a 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -61,7 +61,7 @@ class _NewDayState extends State { ), ), Padding( - padding: const EdgeInsets.only(top: 20, left: 15, right: 20), + padding: const EdgeInsets.only(top: 20, left: 25, right: 25), child: Row( children: [ Icon(day.icon, size: 37.0 * day.iconSize, color: data.palette.primary,), diff --git a/lib/radar.dart b/lib/radar.dart index 408394b..911421e 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -684,6 +684,7 @@ class _RadarSmallState extends State { overlayColor: BLACK, tickMarkShape: RoundSliderTickMarkShape(tickMarkRadius: 2), + overlayShape: SliderComponentShape.noOverlay ), child: Slider( From b6fbbfc6d4d2acab98d80321ce11db34dbce69ca Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 29 Jul 2024 15:38:42 +0200 Subject: [PATCH 045/129] cleaned up icons, and changed some colors --- fonts/OvermorrowWeatherIcons.ttf | Bin 7840 -> 7500 bytes lib/Icons/overmorrow_weather_icons_icons.dart | 4 ++-- lib/decoders/decode_OM.dart | 2 +- lib/new_displays.dart | 8 ++++---- lib/new_forecast.dart | 12 ++++++------ lib/radar.dart | 10 +++++----- lib/weather_refact.dart | 6 +++--- pubspec.lock | 16 ++++++++-------- 8 files changed, 29 insertions(+), 29 deletions(-) diff --git a/fonts/OvermorrowWeatherIcons.ttf b/fonts/OvermorrowWeatherIcons.ttf index 07078e021d74d025deb544c4b3dc819791d1d0ac..d9f1aed792c8674bf3200fc7adcb820ae207be5f 100644 GIT binary patch delta 3987 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 oMtextcolorCorrection(String text) { IconData oMIconCorrection(String text) { //return textIconMap[text] ?? 'sun.png'; - return textMaterialIcon[text] ?? OvermorrowWeatherIcons.sun; + return textMaterialIcon[text] ?? OvermorrowWeatherIcons.sun2; } diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 446ffc3..2e113d2 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -191,7 +191,7 @@ class _NewSunriseSunsetState extends State child: Align( alignment: Alignment.centerLeft, child: comfortatext(write, 15, widget.data.settings, - color: widget.data.palette.secondary, + color: widget.data.palette.onSurface, weight: FontWeight.w500), ), ), @@ -277,14 +277,14 @@ Widget NewAirQuality(var data) { translation('air quality', data.settings["Language"]), 16, data.settings, - color: data.palette.primary), + color: data.palette.onSurface), const Spacer(), Padding( padding: const EdgeInsets.only(right: 5), child: Icon( Icons.arrow_forward, size: 16, - color: data.palette.primary, + color: data.palette.onSurface, ), ) ], @@ -324,7 +324,7 @@ Widget NewAirQuality(var data) { Padding( padding: const EdgeInsets.all(3.0), child: comfortatext(data.aqi.aqi_desc, 14, data.settings, - color: data.palette.primary, weight: FontWeight.w500), + color: data.palette.onSurface, weight: FontWeight.w500), ), ], ), diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 51e000a..044cc42 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -57,7 +57,7 @@ class _NewDayState extends State { child: comfortatext( translation(day.name, data.settings["Language"]), 16, data.settings, - color: data.palette.primary), + color: data.palette.onSurface), ), ), Padding( @@ -67,13 +67,13 @@ class _NewDayState extends State { Icon(day.icon, size: 37.0 * day.iconSize, color: data.palette.primary,), Padding( padding: EdgeInsets.only(left: 12.0 / day.iconSize, top: 3), - child: comfortatext(day.text, 22, data.settings, color: data.palette.primaryFixedDim, + child: comfortatext(day.text, 20, data.settings, color: data.palette.onSurface, weight: FontWeight.w400), ), Spacer(), Padding( padding: const EdgeInsets.only(top: 5), - child: comfortatext(day.minmaxtemp, 20, data.settings, color: data.palette.primary), + child: comfortatext(day.minmaxtemp, 19, data.settings, color: data.palette.primary), ), ], ), @@ -84,7 +84,7 @@ class _NewDayState extends State { height: 85, padding: const EdgeInsets.only(top: 8, bottom: 8, left: 10, right: 10), decoration: BoxDecoration( - //border: Border.all(width: 1.2, color: data.palette.primary), + //border: Border.all(width: 1, color: data.palette.outline), color: data.palette.surfaceContainerLow, borderRadius: BorderRadius.circular(18), ), @@ -189,9 +189,9 @@ class _NewDayState extends State { checkmarkColor: data.palette.onPrimaryContainer, selectedColor: data.palette.primaryFixedDim, backgroundColor: data.palette.surfaceContainerLow, - side: BorderSide.none, + side: BorderSide(color: data.palette.surfaceContainerLow), label: comfortatext(['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, - color: data.palette.onPrimaryContainer), + color: data.palette.onSurface), selected: _value == index, onSelected: (bool selected) { setState(() { diff --git a/lib/radar.dart b/lib/radar.dart index 911421e..119a9a9 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -533,7 +533,7 @@ class _RadarSmallState extends State { child: comfortatext( translation('radar', data.settings["Language"]), 16, data.settings, - color: data.palette.primary), + color: data.palette.onSurface), ), ), Padding( @@ -711,26 +711,26 @@ class _RadarSmallState extends State { padding: const EdgeInsets.only(left: 16, right: 16, top: 9), child: Row( children: [ - comfortatext('-2hr', 13, data.settings, color: data.palette.onPrimaryContainer), + comfortatext('-2hr', 13, data.settings, color: data.palette.onSurface), Expanded( flex: 6, child: Align( alignment: Alignment.centerRight, - child: comfortatext('-1hr', 13, data.settings, color: data.palette.onPrimaryContainer) + child: comfortatext('-1hr', 13, data.settings, color: data.palette.onSurface) ), ), Expanded( flex: 6, child: Align( alignment: Alignment.centerRight, - child: comfortatext('now', 13, data.settings, color: data.palette.onPrimaryContainer) + child: comfortatext('now', 13, data.settings, color: data.palette.onSurface) ), ), Expanded( flex: 3, child: Align( alignment: Alignment.centerRight, - child: comfortatext('30m', 13, data.settings, color: data.palette.onPrimaryContainer) + child: comfortatext('30m', 13, data.settings, color: data.palette.onSurface) ), ), ], diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 5452795..543efde 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -41,8 +41,8 @@ Map textIconMap = { Map textMaterialIcon = { 'Clear Night': OvermorrowWeatherIcons.moon2, - 'Partly Cloudy': OvermorrowWeatherIcons.partly_cloudy, - 'Clear Sky': OvermorrowWeatherIcons.sun, + 'Partly Cloudy': OvermorrowWeatherIcons.partly_cloudy2, + 'Clear Sky': OvermorrowWeatherIcons.sun2, 'Overcast': OvermorrowWeatherIcons.cloudy2, 'Haze': OvermorrowWeatherIcons.haze2, 'Rain': OvermorrowWeatherIcons.rain2, @@ -60,7 +60,7 @@ Map textMaterialIcon = { Map textIconSizeNormalize = { 'Clear Night': 1, 'Partly Cloudy': 1, - 'Clear Sky': 1, + 'Clear Sky': 0.8, 'Overcast': 0.72, 'Haze': 1, 'Rain': 1, diff --git a/pubspec.lock b/pubspec.lock index d76d617..d15e55e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -236,10 +236,10 @@ packages: dependency: transitive description: name: geolocator_android - sha256: "00c7177a95823dd3ee35ef42fd8666cd27d219ae14cea472ac76a21dff43000b" + sha256: "7aefc530db47d90d0580b552df3242440a10fe60814496a979aa67aa98b1fd47" url: "https://pub.dev" source: hosted - version: "4.6.0" + version: "4.6.1" geolocator_apple: dependency: transitive description: @@ -468,10 +468,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "30c5aa827a6ae95ce2853cdc5fe3971daaac00f6f081c419c013f7f57bff2f5e" + sha256: e84c8a53fe1510ef4582f118c7b4bdf15b03002b51d7c2b66983c65843d61193 url: "https://pub.dev" source: hosted - version: "2.2.7" + version: "2.2.8" path_provider_foundation: dependency: transitive description: @@ -564,10 +564,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577" + sha256: "3d4571b3c5eb58ce52a419d86e655493d0bc3020672da79f72fa0c16ca3a8ec1" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.2.4" shared_preferences_foundation: dependency: transitive description: @@ -729,10 +729,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "95d8027db36a0e52caf55680f91e33ea6aa12a3ce608c90b06f4e429a21067ac" + sha256: c24484594a8dea685610569ab0f2547de9c7a1907500a9bc5e37e4c9a3cbfb23 url: "https://pub.dev" source: hosted - version: "6.3.5" + version: "6.3.6" url_launcher_ios: dependency: transitive description: From da281d9b12f66d680d02a094d5a952eddcc0fe9d Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 29 Jul 2024 16:44:20 +0200 Subject: [PATCH 046/129] tweaked icons sizes and updated hourly --- lib/decoders/decode_OM.dart | 6 ++ lib/decoders/decode_wapi.dart | 4 +- lib/new_forecast.dart | 129 +++++++++++++++++++--------------- lib/radar.dart | 25 ++++--- lib/weather_refact.dart | 11 ++- 5 files changed, 101 insertions(+), 74 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 015ecea..c40611a 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -459,7 +459,10 @@ class OM15MinutePrecip { class OMHour { final int temp; + final IconData icon; + final double iconSize; + final String time; final String text; final double precip; @@ -472,6 +475,7 @@ class OMHour { required this.text, required this.precip, required this.wind, + required this.iconSize, }); static OMHour fromJson(item, index, settings, sunstatus) => OMHour( @@ -480,6 +484,8 @@ class OMHour { sunstatus, item["hourly"]["time"][index]), settings["Language"]), icon: oMIconCorrection(oMCurrentTextCorrection(item["hourly"]["weather_code"][index], sunstatus, item["hourly"]["time"][index])), + iconSize: oMIconSizeCorrection(oMCurrentTextCorrection(item["hourly"]["weather_code"][index], + sunstatus, item["hourly"]["time"][index])), time: settings["Time mode"] == '12 hour'? oMamPmTime(item["hourly"]["time"][index]) : oM24hour(item["hourly"]["time"][index]), precip: unit_coversion(item["hourly"]["precipitation"][index], settings["Precipitation"]), wind: unit_coversion(item["hourly"]["wind_speed_10m"][index], settings["Wind"]), diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index 76d2d9f..b064daf 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -149,10 +149,10 @@ double unit_coversion(double value, String unit) { double temp_multiply_for_scale(int temp, String unit) { if (unit == '˚C') { - return max(0, min(100, 17 + temp * 2.4)); + return max(0, min(105, 17 + temp * 2.4)); } else{ - return max(0, min(100, (0 + temp).toDouble())); + return max(0, min(105, (0 + temp).toDouble())); } } diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 044cc42..e7ffe1f 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -64,7 +64,9 @@ class _NewDayState extends State { padding: const EdgeInsets.only(top: 20, left: 25, right: 25), child: Row( children: [ - Icon(day.icon, size: 37.0 * day.iconSize, color: data.palette.primary,), + SizedBox( + width: 35, + child: Icon(day.icon, size: 37.0 * day.iconSize, color: data.palette.primary,)), Padding( padding: EdgeInsets.only(left: 12.0 / day.iconSize, top: 3), child: comfortatext(day.text, 20, data.settings, color: data.palette.onSurface, @@ -72,9 +74,18 @@ class _NewDayState extends State { ), Spacer(), Padding( - padding: const EdgeInsets.only(top: 5), - child: comfortatext(day.minmaxtemp, 19, data.settings, color: data.palette.primary), - ), + padding: const EdgeInsets.only(top: 4), + child: Row( + children: [ + comfortatext(day.minmaxtemp.split("/")[0], 19, data.settings, color: data.palette.primary), + Padding( + padding: const EdgeInsets.only(left: 5, right: 4), + child: comfortatext("/", 19, data.settings, color: data.palette.onSurface), + ), + comfortatext(day.minmaxtemp.split("/")[1], 19, data.settings, color: data.palette.primary), + ], + ), + ) ], ), ), @@ -179,19 +190,20 @@ class _NewDayState extends State { ), ), Padding( - padding: const EdgeInsets.only(left: 10, right: 10), + padding: const EdgeInsets.only(left: 10, right: 10, top: 10), child: Wrap( spacing: 5.0, children: List.generate( 4, (int index) { return ChoiceChip( - checkmarkColor: data.palette.onPrimaryContainer, + elevation: 0.0, + checkmarkColor: data.palette.onPrimaryFixed, selectedColor: data.palette.primaryFixedDim, backgroundColor: data.palette.surfaceContainerLow, - side: BorderSide(color: data.palette.surfaceContainerLow), + side: BorderSide(color: data.palette.surfaceContainerLow, width: 0), label: comfortatext(['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, - color: data.palette.onSurface), + color: _value == index ? data.palette.onPrimaryFixed : data.palette.onSurface), selected: _value == index, onSelected: (bool selected) { setState(() { @@ -203,7 +215,7 @@ class _NewDayState extends State { ).toList(), ), ), - SizedBox(height: 200,), + buildNewHours(day.hourly, data), ], ), ); @@ -222,54 +234,61 @@ Widget buildNewDays(data) { } -Widget buildNewHours(List hours, data) => SizedBox( - height: 285, - child: ListView( - physics: const BouncingScrollPhysics(), - scrollDirection: Axis.horizontal, - shrinkWrap: true, - children: hours.map((hour) { - return Column( - children: [ - Padding( - padding: const EdgeInsets.only(top: 10, bottom: 10), - child: comfortatext('${hour.temp}°', 22, data.settings, color: data.current.primary), - ), - Stack( - alignment: Alignment.bottomCenter, - children: [ - Container( - width: 15, - height: 100, - decoration: BoxDecoration( - border: Border.all( - color: data.current.secondary, - ), - borderRadius: const BorderRadius.all(Radius.circular(20)) +Widget buildNewHours(List hours, data) => Padding( + padding: const EdgeInsets.only(top: 15), + child: SizedBox( + height: 270, + child: ListView( + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: hours.map((hour) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 10), + child: comfortatext('${hour.temp}°', 19, data.settings, color: data.palette.primary), + ), + Stack( + alignment: Alignment.bottomCenter, + children: [ + Container( + width: 15, + height: 105, + decoration: BoxDecoration( + color: data.palette.surfaceContainer, + //border: Border.all(color: data.palette.outline,), + borderRadius: const BorderRadius.all(Radius.circular(20)) + ), ), - ), - Container( - width: 15, - height: temp_multiply_for_scale(hour.temp, data.settings['Temperature']!), - decoration: BoxDecoration( - color: data.current.secondary, - borderRadius: const BorderRadius.all(Radius.circular(20)) + Container( + width: 15, + height: temp_multiply_for_scale(hour.temp, data.settings['Temperature']!), + decoration: BoxDecoration( + color: data.palette.primaryFixedDim, + borderRadius: const BorderRadius.all(Radius.circular(20)) + ), ), - ), - ], - ), - Padding( - padding: const EdgeInsets.only(top: 20, left: 3, right: 3), - child: Icon( - hour.icon + ], + ), + Padding( + padding: const EdgeInsets.only(top: 15, left: 3, right: 3), + child: SizedBox( + height: 30, + child: Icon( + hour.icon, + color: data.palette.primary, + size: 30.0 * hour.iconSize, + ), + ) + ), + Padding( + padding: const EdgeInsets.only(top:15, left: 9, right: 9), + child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) ) - ), - Padding( - padding: const EdgeInsets.only(top:20, left: 9, right: 9), - child: comfortatext(hour.time, 17, data.settings, color: data.current.primary) - ) - ], - ); - }).toList(), + ], + ); + }).toList(), + ), ), ); \ No newline at end of file diff --git a/lib/radar.dart b/lib/radar.dart index 119a9a9..c9c0ff7 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -121,7 +121,7 @@ class _RadarMapState extends State { ), children: [ TileLayer( - urlTemplate: data.settings["Color theme"] == "dark" + urlTemplate: data.settings["Color mode"] == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', ), @@ -316,10 +316,10 @@ class _RadarPageState extends State { ), children: [ Container( - color: data.settings["Color theme"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), + color: data.settings["Color mode"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), ), TileLayer( - urlTemplate: data.settings["Color theme"] == "dark" + urlTemplate: data.settings["Color mode"] == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', ), @@ -327,7 +327,7 @@ class _RadarPageState extends State { urlTemplate: data.radar.images[currentFrameIndex] + "/256/{z}/{x}/{y}/8/1_1.png", ), TileLayer( - urlTemplate: data.settings["Color theme"] == "dark" + urlTemplate: data.settings["Color mode"] == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_only_labels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', ), @@ -580,7 +580,7 @@ class _RadarSmallState extends State { ), children: [ TileLayer( - urlTemplate: data.settings["Color theme"] == "dark" + urlTemplate: data.settings["Color mode"] == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', ), @@ -674,8 +674,9 @@ class _RadarSmallState extends State { data: SliderTheme.of(context).copyWith( trackHeight: 18, valueIndicatorTextStyle: GoogleFonts.comfortaa( - color: WHITE, + color: data.palette.surface, fontSize: 12, + fontWeight: FontWeight.w500, ), thumbShape: const RoundSliderThumbShape( @@ -810,6 +811,7 @@ class _RadarBigState extends State { @override Widget build(BuildContext context) { double x = MediaQuery.of(context).padding.top; + return Scaffold( body: Stack( children: [ @@ -825,10 +827,10 @@ class _RadarBigState extends State { ), children: [ Container( - color: data.settings["Color theme"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), + color: data.settings["Color mode"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), ), TileLayer( - urlTemplate: data.settings["Color theme"] == "dark" + urlTemplate: data.settings["Color mode"] == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', ), @@ -836,7 +838,7 @@ class _RadarBigState extends State { urlTemplate: data.radar.images[currentFrameIndex.toInt()] + "/256/{z}/{x}/{y}/8/1_1.png", ), TileLayer( - urlTemplate: data.settings["Color theme"] == "dark" + urlTemplate: data.settings["Color mode"] == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_only_labels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', ), @@ -899,8 +901,9 @@ class _RadarBigState extends State { data: SliderTheme.of(context).copyWith( trackHeight: 18, valueIndicatorTextStyle: GoogleFonts.comfortaa( - color: WHITE, + color: data.palette.surface, fontSize: 12, + fontWeight: FontWeight.w500, ), thumbShape: const RoundSliderThumbShape( @@ -908,7 +911,7 @@ class _RadarBigState extends State { pressedElevation: 0), tickMarkShape: RoundSliderTickMarkShape(tickMarkRadius: 2), - overlayShape: SliderComponentShape.noOverlay + overlayShape: SliderComponentShape.noOverlay, ), child: Slider( diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 543efde..c225ef9 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -56,14 +56,13 @@ Map textMaterialIcon = { 'Cloudy Night' : OvermorrowWeatherIcons.cloudy_night2, }; - Map textIconSizeNormalize = { - 'Clear Night': 1, - 'Partly Cloudy': 1, + 'Clear Night': 0.8, + 'Partly Cloudy': 0.8, 'Clear Sky': 0.8, - 'Overcast': 0.72, + 'Overcast': 0.74, 'Haze': 1, - 'Rain': 1, + 'Rain': 0.95, 'Sleet': 1, 'Drizzle': 1, 'Thunderstorm': 1, @@ -71,7 +70,7 @@ Map textIconSizeNormalize = { 'Fog': 1, 'Snow': 1, 'Heavy Rain': 1, - 'Cloudy Night' : 1, + 'Cloudy Night' : 0.8, }; Map weatherTextMap = { From 7ff9a553891a3a1c9a13290b91b5849f50e6a06d Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 29 Jul 2024 20:12:21 +0200 Subject: [PATCH 047/129] fixed a small sunstatus time bug --- lib/decoders/decode_OM.dart | 1 - lib/new_displays.dart | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index c40611a..0c46775 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -33,7 +33,6 @@ import '../weather_refact.dart'; import 'extra_info.dart'; String OMConvertTime(String time) { - print(("time", time)); return time.split("T")[1]; } diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 2e113d2..87fe708 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -25,7 +25,7 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:overmorrow/ui_helper.dart'; -import 'decoders/decode_wapi.dart'; +import 'decoders/decode_OM.dart'; class WavePainter extends CustomPainter { final double waveValue; @@ -156,10 +156,10 @@ class _NewSunriseSunsetState extends State final double progress = min(max(thisdif / total, 0), 1); String write = widget.data.settings["Time mode"] == "24 hour" - ? convertTime( - "${localTime.hour}:${localTime.minute} j") //the j is just added so when splitting - : amPmTime( - "${localTime.hour}:${localTime.minute} j"); //it can grab the first item + ? OMConvertTime( + "j T${localTime.hour}:${localTime.minute}") //the j is just added so when splitting + : OMamPmTime( + "j T${localTime.hour}:${localTime.minute}"); //it can grab the second item //this is all so that the text will be right above the progress final textPainter = TextPainter( From e5e757cdc9986a24a1f065e0ddd0ff1be2d79574 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 30 Jul 2024 16:48:08 +0200 Subject: [PATCH 048/129] now there is wind in hourly --- lib/decoders/decode_OM.dart | 22 +++- lib/main_screens.dart | 1 - lib/new_forecast.dart | 196 +++++++++++++++++++++++++++++++----- lib/radar.dart | 6 +- lib/weather_refact.dart | 6 +- 5 files changed, 194 insertions(+), 37 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 0c46775..380dae4 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -37,7 +37,6 @@ String OMConvertTime(String time) { } String OMamPmTime(String time) { - print(("time", time)); String a = time.split("T")[1]; List num = a.split(":"); int hour = int.parse(num[0]); @@ -93,7 +92,7 @@ Future> OMRequestData(double lat, double lng, String real_loc) asy "longitude": lng.toString(), "minutely_15" : ["precipitation"], "current": ["temperature_2m", "relative_humidity_2m", "apparent_temperature", "weather_code", "wind_speed_10m", 'wind_direction_10m'], - "hourly": ["temperature_2m", "precipitation", "weather_code", "wind_speed_10m"], + "hourly": ["temperature_2m", "precipitation", "weather_code", "wind_speed_10m", "wind_direction_10m"], "daily": ["weather_code", "temperature_2m_max", "temperature_2m_min", "uv_index_max", "precipitation_sum", "precipitation_probability_max", "wind_speed_10m_max", "wind_direction_10m_dominant", "sunrise", "sunset"], "timezone": "auto", "forecast_days": "14", @@ -260,7 +259,6 @@ class OMCurrent { // ]); - List colors = getNetworkColors(palette, settings); //List colors = palette.colors.toList(); @@ -466,6 +464,11 @@ class OMHour { final String text; final double precip; final double wind; + final int wind_dir; + + final double raw_temp; + final double raw_precip; + final double raw_wind; const OMHour({ required this.temp, @@ -475,6 +478,10 @@ class OMHour { required this.precip, required this.wind, required this.iconSize, + required this.raw_precip, + required this.raw_temp, + required this.raw_wind, + required this.wind_dir, }); static OMHour fromJson(item, index, settings, sunstatus) => OMHour( @@ -486,8 +493,15 @@ class OMHour { iconSize: oMIconSizeCorrection(oMCurrentTextCorrection(item["hourly"]["weather_code"][index], sunstatus, item["hourly"]["time"][index])), time: settings["Time mode"] == '12 hour'? oMamPmTime(item["hourly"]["time"][index]) : oM24hour(item["hourly"]["time"][index]), + precip: unit_coversion(item["hourly"]["precipitation"][index], settings["Precipitation"]), - wind: unit_coversion(item["hourly"]["wind_speed_10m"][index], settings["Wind"]), + wind: double.parse( + unit_coversion(item["hourly"]["wind_speed_10m"][index], settings["Wind"]).toStringAsFixed(1)), + wind_dir: item["hourly"]["wind_direction_10m"][index], + + raw_precip: item["hourly"]["precipitation"][index], + raw_temp: item["hourly"]["temperature_2m"][index], + raw_wind: item["hourly"]["wind_speed_10m"][index], ); } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 5b354b8..8dddabc 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -99,7 +99,6 @@ Widget NewMain(data, updateLocation, context) { ], ), - NewSunriseSunset(data: data, key: Key(data.place), size: size,), NewRain15MinuteIndicator(data), NewAirQuality(data), diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index e7ffe1f..0a79bad 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -17,10 +17,11 @@ along with this program. If not, see . */ +import 'dart:math'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:overmorrow/settings_page.dart'; -import 'decoders/decode_wapi.dart'; import 'ui_helper.dart'; @@ -61,18 +62,18 @@ class _NewDayState extends State { ), ), Padding( - padding: const EdgeInsets.only(top: 20, left: 25, right: 25), + padding: const EdgeInsets.only(top: 20, left: 23, right: 25), child: Row( children: [ SizedBox( width: 35, child: Icon(day.icon, size: 37.0 * day.iconSize, color: data.palette.primary,)), Padding( - padding: EdgeInsets.only(left: 12.0 / day.iconSize, top: 3), + padding: const EdgeInsets.only(left: 12.0, top: 3), child: comfortatext(day.text, 20, data.settings, color: data.palette.onSurface, weight: FontWeight.w400), ), - Spacer(), + const Spacer(), Padding( padding: const EdgeInsets.only(top: 4), child: Row( @@ -190,7 +191,7 @@ class _NewDayState extends State { ), ), Padding( - padding: const EdgeInsets.only(left: 10, right: 10, top: 10), + padding: const EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 15), child: Wrap( spacing: 5.0, children: List.generate( @@ -215,7 +216,8 @@ class _NewDayState extends State { ).toList(), ), ), - buildNewHours(day.hourly, data), + if (_value == 0)(buildNewHours(day.hourly, data)), + if (_value == 2)(WindReport(hours: day.hourly, data: data,)) ], ), ); @@ -228,22 +230,21 @@ Widget buildNewDays(data) { shrinkWrap: true, itemCount: 3, itemBuilder: (BuildContext context, int index) { - return NewDay(data: data, index: index); + return NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.backcolor}"),); }, ); } - -Widget buildNewHours(List hours, data) => Padding( - padding: const EdgeInsets.only(top: 15), - child: SizedBox( - height: 270, - child: ListView( - physics: const BouncingScrollPhysics(), - scrollDirection: Axis.horizontal, - shrinkWrap: true, - children: hours.map((hour) { - return Column( +Widget buildNewHours(List hours, data) => SizedBox( + height: 270, + child: ListView( + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: hours.map((hour) { + return SizedBox( + width: 55, //this is all to ensure that nothing shifts when you switch categories + child: Column( children: [ Padding( padding: const EdgeInsets.only(top: 10, bottom: 10), @@ -253,7 +254,7 @@ Widget buildNewHours(List hours, data) => Padding( alignment: Alignment.bottomCenter, children: [ Container( - width: 15, + width: 14, height: 105, decoration: BoxDecoration( color: data.palette.surfaceContainer, @@ -262,8 +263,8 @@ Widget buildNewHours(List hours, data) => Padding( ), ), Container( - width: 15, - height: temp_multiply_for_scale(hour.temp, data.settings['Temperature']!), + width: 14, + height: hour.raw_temp * 1.8 + 30, decoration: BoxDecoration( color: data.palette.primaryFixedDim, borderRadius: const BorderRadius.all(Radius.circular(20)) @@ -283,12 +284,155 @@ Widget buildNewHours(List hours, data) => Padding( ) ), Padding( - padding: const EdgeInsets.only(top:15, left: 9, right: 9), + padding: const EdgeInsets.only(top:15), child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) ) ], - ); - }).toList(), - ), + ), + ); + }).toList(), ), -); \ No newline at end of file +); + +class WindChartPainter extends CustomPainter { + final List hours; + final data; + final double dotRadius; + final double smallDotRadius; + final double spacing; + final double maxHeight; + + WindChartPainter({ + required this.hours, + required this.data, + this.dotRadius = 7.0, + this.smallDotRadius = 1.8, + this.spacing = 55.0, + this.maxHeight = 140.0, + }); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = data.palette.primaryFixedDim + ..strokeWidth = 2.0; + + final smallDotPaint = Paint() + ..color = data.palette.primaryContainer + ..strokeWidth = 1.0; + + final textPainter = TextPainter( + textAlign: TextAlign.center, + textDirection: TextDirection.ltr, + ); + + for (int i = 0; i < hours.length; i++) { + final x = 27.5 + i * spacing; + final y = maxHeight - max(min(hours[i].raw_wind * 1.5, maxHeight), 0); + + canvas.drawCircle(Offset(x, y), dotRadius, paint); + + textPainter.text = TextSpan( + text: String.fromCharCode(Icons.arrow_forward.codePoint), + style: TextStyle( + fontSize: dotRadius * 2, + fontFamily: Icons.arrow_forward.fontFamily, + color: data.palette.primary, + ), + ); + textPainter.layout(); + + //this is all so it can be rotated + canvas.save(); + canvas.translate(x, (y < 30) ? y + dotRadius * 2.4 : y - dotRadius * 2.4); + canvas.rotate(pi / 180 * hours[i].wind_dir); + textPainter.paint(canvas, Offset(-dotRadius, -dotRadius)); + canvas.restore(); + + if (i < hours.length - 1) { + final nextX = 27.5 + (i + 1) * spacing; + final nextY = maxHeight - max(min(hours[i + 1].raw_wind * 1.5, maxHeight), 0); + + int numDots = 4; + double dx = (nextX - x) / numDots; + double dy = (nextY - y) / numDots; + + for (int j = 1; j < numDots; j++) { + double startX = x + dx * j; + double startY = y + dy * j; + canvas.drawCircle(Offset(startX, startY), smallDotRadius, smallDotPaint); + } + } + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return false; + } +} + +class WindReport extends StatelessWidget { + final hours; + final data; + + WindReport({required this.hours, required this.data}); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 270, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.only(top: 45, bottom: 20), + child: CustomPaint( + size: Size(hours.length * 55.0, 145.0), + painter: WindChartPainter(hours: hours, data: data), + ), + ), + SizedBox( + height: 250, + child: ListView( + physics: const NeverScrollableScrollPhysics(), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: hours.map((hour) { + return SizedBox( + width: 55, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + comfortatext('${hour.wind}', 18, data.settings, color: data.palette.primary, + weight: FontWeight.w500), + comfortatext('${data.settings["Wind"]}', 9, data.settings, color: data.palette.primary), + ], + ), + ), + const SizedBox( + height: 152, + ), + Padding( + padding: const EdgeInsets.only(top:15), + child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) + ) + ], + ), + ); + }).toList(), + ), + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/radar.dart b/lib/radar.dart index c9c0ff7..57617e6 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -543,7 +543,7 @@ class _RadarSmallState extends State { aspectRatio: 1.57, child: Container( decoration: BoxDecoration( - color: data.palette.surfaceContainerHigh, + color: data.palette.surface, borderRadius: BorderRadius.circular(18), border: Border.all( width: 2.2, color: data.palette.surfaceContainerHigh) @@ -564,7 +564,7 @@ class _RadarSmallState extends State { }, initialCenter: LatLng(data.lat, data.lng), initialZoom: 6, - backgroundColor: WHITE, + backgroundColor: data.settings["Color mode"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), keepAlive: true, maxZoom: 6, minZoom: 6, @@ -822,7 +822,7 @@ class _RadarBigState extends State { minZoom: 2, maxZoom: 8, - backgroundColor: WHITE, + backgroundColor: data.settings["Color mode"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), interactionOptions: const InteractionOptions(flags: InteractiveFlag.all & ~InteractiveFlag.rotate,), ), children: [ diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index c225ef9..302e4c1 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -67,9 +67,9 @@ Map textIconSizeNormalize = { 'Drizzle': 1, 'Thunderstorm': 1, 'Heavy Snow': 1, - 'Fog': 1, - 'Snow': 1, - 'Heavy Rain': 1, + 'Fog': 0.8, + 'Snow': 0.8, + 'Heavy Rain': 0.95, 'Cloudy Night' : 0.8, }; From 94fd2c54041b51016901acd8ac8b9bdc04308db4 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 30 Jul 2024 17:18:47 +0200 Subject: [PATCH 049/129] small tweaks and trying to animate switching --- lib/new_forecast.dart | 39 ++++++++++++++++++++++++++++++--------- lib/settings_page.dart | 1 + 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 0a79bad..335781a 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -21,7 +21,6 @@ import 'dart:math'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:overmorrow/settings_page.dart'; import 'ui_helper.dart'; @@ -56,7 +55,7 @@ class _NewDayState extends State { child: Align( alignment: Alignment.centerLeft, child: comfortatext( - translation(day.name, data.settings["Language"]), 16, + day.name, 16, data.settings, color: data.palette.onSurface), ), @@ -216,8 +215,17 @@ class _NewDayState extends State { ).toList(), ), ), - if (_value == 0)(buildNewHours(day.hourly, data)), - if (_value == 2)(WindReport(hours: day.hourly, data: data,)) + AnimatedSwitcher( + duration: const Duration(milliseconds: 500), + transitionBuilder: (child, animation) { + return ScaleTransition( + scale: animation, + child: child, + ); + }, + child: _value == 0 ? buildNewHours(day.hourly, data) + : WindReport(hours: day.hourly, data: data,) + ), ], ), ); @@ -235,7 +243,8 @@ Widget buildNewDays(data) { ); } -Widget buildNewHours(List hours, data) => SizedBox( +Widget buildNewHours(List hours, data) => Container( + color: data.palette.surface, height: 270, child: ListView( physics: const BouncingScrollPhysics(), @@ -308,7 +317,7 @@ class WindChartPainter extends CustomPainter { this.dotRadius = 7.0, this.smallDotRadius = 1.8, this.spacing = 55.0, - this.maxHeight = 140.0, + this.maxHeight = 110.0, }); @override @@ -380,8 +389,9 @@ class WindReport extends StatelessWidget { @override Widget build(BuildContext context) { - return SizedBox( + return Container( height: 270, + color: data.palette.surface, child: SingleChildScrollView( scrollDirection: Axis.horizontal, physics: const BouncingScrollPhysics(), @@ -390,7 +400,7 @@ class WindReport extends StatelessWidget { Padding( padding: const EdgeInsets.only(top: 45, bottom: 20), child: CustomPaint( - size: Size(hours.length * 55.0, 145.0), + size: Size(hours.length * 55.0, 110.0), painter: WindChartPainter(hours: hours, data: data), ), ), @@ -418,7 +428,18 @@ class WindReport extends StatelessWidget { ), ), const SizedBox( - height: 152, + height: 112, + ), + Padding( + padding: const EdgeInsets.only(left: 3, right: 3), + child: SizedBox( + height: 30, + child: Icon( + hour.icon, + color: data.palette.primary, + size: 30.0 * hour.iconSize, + ), + ) ), Padding( padding: const EdgeInsets.only(top:15), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index f281826..521ff01 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -47,6 +47,7 @@ Map> settingSwitches = { String translation(String text, String language) { int index = languageIndex[language] ?? 0; + print((text, language)); String translated = mainTranslate[text]![index]; return translated; } From ec887e25d61cdb1542f9611073ae67ea452d601b Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 31 Jul 2024 15:31:06 +0200 Subject: [PATCH 050/129] icons finally totally outlined --- fonts/OvermorrowWeatherIcons.ttf | Bin 7500 -> 8056 bytes lib/new_forecast.dart | 6 ++-- pubspec.lock | 48 +++++++++++++++---------------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/fonts/OvermorrowWeatherIcons.ttf b/fonts/OvermorrowWeatherIcons.ttf index d9f1aed792c8674bf3200fc7adcb820ae207be5f..bf72c1a4864d88596a381f211d037adf175afcc8 100644 GIT binary patch delta 2200 zcmaJ?YiuId6~32&8H{cG;$>r49%csf7+{zIi~(b?V`H$*%Ph-cuf5q={66?i&_6*t@gUIUWbcDw2vsG3>!$^K=zwR9wPZU60}?V^hhom7xkw_*9lHM zAsLW7BA3X|sUJyy-S(C2^Y;AFhPVf2NrYaLY!X@E0ArvG_Q7570KJDv4i$RHMW8T3 z@eB)1BqfJt6AJ|o@AF3>PcvrPOp(aR%lS!)Y(3-sK1t&jioV7-WFMhYlZ|)8bX~j~ zzZH+)`r)m(NYvHWC6cBECPq&RvW^ZJ(bsmRbFKejo9 zA@j@gC~s4;q~z7YN&TJH4mQ+n9YLOeEh|1 zJXY@E^KNTq=}KzG?sVE`Qt&aGa=5c@V@MM=nceV`&Uc9(Kdv`qauKDO(OZ=UgD$Ca z4-H$>RU$Dq%2GtPf?T+BJ>Ds|T8x}7s5fYoMzzJPq=@WUmMB#hJJ-q*sqk5rC{+fh z_$kiSpw}D18+X<~%UItgAT)wH*xXC&1| z^>kj+sia5Ijw9Ijuyw`)7zY_p0u`_Y4jOMORG9sZKS;V78mdz+Qli5&n;4(pC-AVb zObs-4$%SHa+U{`Jr<3p} zB9kF#b0n`?qZU`%EwE!|OY=o7!}u8nc4@8n-XsQ3e`{OoRw9c59$_TEx*tIVmLp{5 z`xcr_8T8welE}&kGp)1Z`0rq#<`YdvDn9PyqU@Yo>Pgt#8P_FmB9(7%-nROzOn^}$ z7^{!bAQLT2F=)}x98GjNVO@k7PJBt^fE&zVP9tuT-I$REKYsZU;(U&XP&p7aF>g;N z2_7UAsZ?NRG);VdIm83y)Csx3ukY>e#wRA?yZf*kTVhdMP6X-sl~>yJru009af8lmr!p@ac_&CUbL|bwec$0MMIPOe_ebr zO8YwBvNo#I7Rt-HjLYM3WpeOik!5I%b!XQcQ^RNg zhCGv2#Fglc?fP~!ik0^a3?ar1z7|;2XYkTNh6&Q$80pU#GTc8H+l_}`oS;e%hHYN6 z=}wBA*oxTGMi<8U6$Wg6(y7fQr#WB3TM(rF42y=maU_#p>^$o3eU+?>FKD9x!yp23 z|4p54OazL4yZ*DL$%m&pwZR_T6Xg zz4m?>`7Ct9R(=lvcntuMUpiafNca763;@E6#JRk>b^6*%4@dw+6#z8bl~d)D?vZak zLbg93;VMWW{fVN`{(U6&%Gu3lhTcXy0PmtHyt=+rw(s=CZ$58z>5+zfYh(TVru^wI zF9Bf0FMa?Z(q{Kp0HCe|u-~M1Z+>yeT6lFly`T#J4iw})WCecwJgxqB-Cw451v$I| zO~MU0Z{d-LIfPI^vWND!k!&G(6AAj8y53L{M+k$92$6E~XVD#MO)L_}#a~HVWC6KW z9%)oWZLlB3u)jj_WELC(9LRtZ;4F&5s)U+uNJk*c^ePFP)l0BU1oBQwsOcTT_ezzJ zQMA=NbsC9S;>1^?BZ*o(UVEVyC&b*O*O_FE?vz)xmpfNp2n2(Hh4Q(JE7n@e@glefYwQ=a0hDE1tuw!|~jtVss_ko9+%`x1Ubsd~~xx z1_}&cM%*ap7BxroGKncsZL4A z)|C`5ml;|W5|WT33#FyUAVqcFxZl!%LQby{*7eiEyOMU{HHl213<=9v^M1G6J?M7B zE|bTD*1g~G+2etlgR^kOkkQllX3!(UhJ)_$g9ZD2sCoj{QOE7CkoOR`4$LSfQH@D7 z^Bm8iI!9-T*k;8Pu?*JnPWa&JW-T#{N_G>f@lMprvy-_}r7-PhJnr<^d=Ht$x6S*1 z+gIWgH`FL0LUw>tqV2?O=S98AiQb4+W6{-}YBaj~$9G$2PKAet!l%w`9p4Sv zr~6aeDKt8am-4eq`SD|GhCqStG5H50@oI5~VOeITNO { children: [ SizedBox( width: 35, - child: Icon(day.icon, size: 37.0 * day.iconSize, color: data.palette.primary,)), + child: Icon(day.icon, size: 38.0 * day.iconSize, color: data.palette.primary,)), Padding( padding: const EdgeInsets.only(left: 12.0, top: 3), child: comfortatext(day.text, 20, data.settings, color: data.palette.onSurface, @@ -288,7 +288,7 @@ Widget buildNewHours(List hours, data) => Container( child: Icon( hour.icon, color: data.palette.primary, - size: 30.0 * hour.iconSize, + size: 31.0 * hour.iconSize, ), ) ), @@ -437,7 +437,7 @@ class WindReport extends StatelessWidget { child: Icon( hour.icon, color: data.palette.primary, - size: 30.0 * hour.iconSize, + size: 31.0 * hour.iconSize, ), ) ), diff --git a/pubspec.lock b/pubspec.lock index d15e55e..ac161d0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -460,18 +460,18 @@ packages: dependency: transitive description: name: path_provider - sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: e84c8a53fe1510ef4582f118c7b4bdf15b03002b51d7c2b66983c65843d61193 + sha256: "490539678396d4c3c0b06efdaab75ae60675c3e0c66f72bc04c2e2c1e0e2abeb" url: "https://pub.dev" source: hosted - version: "2.2.8" + version: "2.2.9" path_provider_foundation: dependency: transitive description: @@ -556,58 +556,58 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 + sha256: c3f888ba2d659f3e75f4686112cc1e71f46177f74452d40d8307edc332296ead url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.0" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "3d4571b3c5eb58ce52a419d86e655493d0bc3020672da79f72fa0c16ca3a8ec1" + sha256: "041be4d9d2dc6079cf342bc8b761b03787e3b71192d658220a56cac9c04a0294" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.3.0" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" + sha256: "671e7a931f55a08aa45be2a13fe7247f2a41237897df434b30d2012388191833" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.5.0" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + sha256: "2ba0510d3017f91655b7543e9ee46d48619de2a2af38e5c790423f7007c7ccc1" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "034650b71e73629ca08a0bd789fd1d83cc63c2d1e405946f7cef7bc37432f93a" + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf + sha256: "3a293170d4d9403c3254ee05b84e62e8a9b3c5808ebd17de6a33fe9ea6457936" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.4.0" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + sha256: "398084b47b7f92110683cac45c6dc4aae853db47e470e5ddcd52cab7f7196ab2" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" sky_engine: dependency: transitive description: flutter @@ -729,10 +729,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: c24484594a8dea685610569ab0f2547de9c7a1907500a9bc5e37e4c9a3cbfb23 + sha256: "94d8ad05f44c6d4e2ffe5567ab4d741b82d62e3c8e288cc1fcea45965edf47c9" url: "https://pub.dev" source: hosted - version: "6.3.6" + version: "6.3.8" url_launcher_ios: dependency: transitive description: @@ -769,10 +769,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "7fd2f55fe86cea2897b963e864dc01a7eb0719ecc65fcef4c1cc3d686d718bb2" + sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.1" url_launcher_windows: dependency: transitive description: @@ -809,10 +809,10 @@ packages: dependency: transitive description: name: web - sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "0.5.1" wkt_parser: dependency: transitive description: From ab74b779a96f60af9d77ed3755fb62d2e126701a Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 31 Jul 2024 16:18:00 +0200 Subject: [PATCH 051/129] finally got a normal animation for hourly switching --- lib/new_forecast.dart | 258 +++++++++++++++++++++-------------------- lib/settings_page.dart | 1 - 2 files changed, 131 insertions(+), 128 deletions(-) diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 203b597..2363db1 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -38,6 +38,16 @@ class _NewDayState extends State { final data; int _value = 0; + + PageController _pageController = PageController(); + + void _onItemTapped(int index) { + _pageController.animateToPage( + index, + duration: Duration(milliseconds: 400), + curve: Curves.fastEaseInToSlowEaseOut, + ); + } _NewDayState(this.data); @@ -208,6 +218,7 @@ class _NewDayState extends State { onSelected: (bool selected) { setState(() { _value = (selected ? index : null)!; + _onItemTapped(index); }); }, ); @@ -215,16 +226,16 @@ class _NewDayState extends State { ).toList(), ), ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 500), - transitionBuilder: (child, animation) { - return ScaleTransition( - scale: animation, - child: child, - ); - }, - child: _value == 0 ? buildNewHours(day.hourly, data) - : WindReport(hours: day.hourly, data: data,) + SizedBox( + height: 260, + child: PageView( + controller: _pageController, + children: [ + buildNewHours(day.hourly, data), + WindReport(hours: day.hourly, data: data,), + WindReport(hours: day.hourly, data: data,), + ], + ), ), ], ), @@ -243,64 +254,61 @@ Widget buildNewDays(data) { ); } -Widget buildNewHours(List hours, data) => Container( - color: data.palette.surface, - height: 270, - child: ListView( - physics: const BouncingScrollPhysics(), - scrollDirection: Axis.horizontal, - shrinkWrap: true, - children: hours.map((hour) { - return SizedBox( - width: 55, //this is all to ensure that nothing shifts when you switch categories - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(top: 10, bottom: 10), - child: comfortatext('${hour.temp}°', 19, data.settings, color: data.palette.primary), - ), - Stack( - alignment: Alignment.bottomCenter, - children: [ - Container( - width: 14, - height: 105, - decoration: BoxDecoration( - color: data.palette.surfaceContainer, - //border: Border.all(color: data.palette.outline,), - borderRadius: const BorderRadius.all(Radius.circular(20)) - ), - ), - Container( - width: 14, - height: hour.raw_temp * 1.8 + 30, - decoration: BoxDecoration( - color: data.palette.primaryFixedDim, - borderRadius: const BorderRadius.all(Radius.circular(20)) - ), +Widget buildNewHours(List hours, data) => ListView( + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: hours.map((hour) { + return SizedBox( + width: 55, //this is all to ensure that nothing shifts when you switch categories + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 10), + child: comfortatext('${hour.temp}°', 19, data.settings, color: data.palette.primary), + ), + Stack( + alignment: Alignment.bottomCenter, + children: [ + Container( + width: 14, + height: 105, + decoration: BoxDecoration( + color: data.palette.surfaceContainer, + //border: Border.all(color: data.palette.outline,), + borderRadius: const BorderRadius.all(Radius.circular(20)) ), - ], - ), - Padding( - padding: const EdgeInsets.only(top: 15, left: 3, right: 3), - child: SizedBox( - height: 30, - child: Icon( - hour.icon, - color: data.palette.primary, - size: 31.0 * hour.iconSize, + ), + Container( + width: 13, + height: hour.raw_temp * 1.8 + 30, + decoration: BoxDecoration( + color: data.palette.primaryFixedDim, + //border: Border.all(color: data.palette.primaryFixedDim, width: 2), + borderRadius: const BorderRadius.all(Radius.circular(20)) ), - ) - ), - Padding( - padding: const EdgeInsets.only(top:15), - child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) + ), + ], + ), + Padding( + padding: const EdgeInsets.only(top: 17, left: 3, right: 3), + child: SizedBox( + height: 30, + child: Icon( + hour.icon, + color: data.palette.primary, + size: 31.0 * hour.iconSize, + ), ) - ], - ), - ); - }).toList(), - ), + ), + Padding( + padding: const EdgeInsets.only(top:13), + child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) + ) + ], + ), + ); + }).toList(), ); class WindChartPainter extends CustomPainter { @@ -317,7 +325,7 @@ class WindChartPainter extends CustomPainter { this.dotRadius = 7.0, this.smallDotRadius = 1.8, this.spacing = 55.0, - this.maxHeight = 110.0, + this.maxHeight = 105.0, }); @override @@ -389,70 +397,66 @@ class WindReport extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - height: 270, - color: data.palette.surface, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), - child: Stack( - children: [ - Padding( - padding: const EdgeInsets.only(top: 45, bottom: 20), - child: CustomPaint( - size: Size(hours.length * 55.0, 110.0), - painter: WindChartPainter(hours: hours, data: data), - ), + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.only(top: 45, bottom: 20), + child: CustomPaint( + size: Size(hours.length * 55.0, 105.0), + painter: WindChartPainter(hours: hours, data: data), ), - SizedBox( - height: 250, - child: ListView( - physics: const NeverScrollableScrollPhysics(), - scrollDirection: Axis.horizontal, - shrinkWrap: true, - children: hours.map((hour) { - return SizedBox( - width: 55, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.only(top: 10, bottom: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - comfortatext('${hour.wind}', 18, data.settings, color: data.palette.primary, - weight: FontWeight.w500), - comfortatext('${data.settings["Wind"]}', 9, data.settings, color: data.palette.primary), - ], - ), - ), - const SizedBox( - height: 112, - ), - Padding( - padding: const EdgeInsets.only(left: 3, right: 3), - child: SizedBox( - height: 30, - child: Icon( - hour.icon, - color: data.palette.primary, - size: 31.0 * hour.iconSize, - ), - ) + ), + SizedBox( + height: 250, + child: ListView( + physics: const NeverScrollableScrollPhysics(), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: hours.map((hour) { + return SizedBox( + width: 55, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + comfortatext('${hour.wind}', 18, data.settings, color: data.palette.primary, + weight: FontWeight.w500), + comfortatext('${data.settings["Wind"]}', 9, data.settings, color: data.palette.primary), + ], ), - Padding( - padding: const EdgeInsets.only(top:15), - child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) - ) - ], - ), - ); - }).toList(), - ), + ), + const SizedBox( + height: 114, + ), + Padding( + padding: const EdgeInsets.only(left: 3, right: 3), + child: SizedBox( + height: 30, + child: Icon( + hour.icon, + color: data.palette.primary, + size: 31.0 * hour.iconSize, + ), + ) + ), + Padding( + padding: const EdgeInsets.only(top:13), + child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) + ) + ], + ), + ); + }).toList(), ), - ], - ), + ), + ], ), ); } diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 521ff01..f281826 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -47,7 +47,6 @@ Map> settingSwitches = { String translation(String text, String language) { int index = languageIndex[language] ?? 0; - print((text, language)); String translated = mainTranslate[text]![index]; return translated; } From 2bdb0fae55a5808bee499e89591e50a6260c494a Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 31 Jul 2024 16:38:25 +0200 Subject: [PATCH 052/129] now there is hourly uv --- lib/decoders/decode_OM.dart | 5 ++- lib/new_forecast.dart | 76 +++++++++++++++++++++++++++++++++++-- lib/weather_refact.dart | 2 +- 3 files changed, 78 insertions(+), 5 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 380dae4..2fbb12b 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -92,7 +92,7 @@ Future> OMRequestData(double lat, double lng, String real_loc) asy "longitude": lng.toString(), "minutely_15" : ["precipitation"], "current": ["temperature_2m", "relative_humidity_2m", "apparent_temperature", "weather_code", "wind_speed_10m", 'wind_direction_10m'], - "hourly": ["temperature_2m", "precipitation", "weather_code", "wind_speed_10m", "wind_direction_10m"], + "hourly": ["temperature_2m", "precipitation", "weather_code", "wind_speed_10m", "wind_direction_10m", "uv_index"], "daily": ["weather_code", "temperature_2m_max", "temperature_2m_min", "uv_index_max", "precipitation_sum", "precipitation_probability_max", "wind_speed_10m_max", "wind_direction_10m_dominant", "sunrise", "sunset"], "timezone": "auto", "forecast_days": "14", @@ -465,6 +465,7 @@ class OMHour { final double precip; final double wind; final int wind_dir; + final int uv; final double raw_temp; final double raw_precip; @@ -482,6 +483,7 @@ class OMHour { required this.raw_temp, required this.raw_wind, required this.wind_dir, + required this.uv, }); static OMHour fromJson(item, index, settings, sunstatus) => OMHour( @@ -498,6 +500,7 @@ class OMHour { wind: double.parse( unit_coversion(item["hourly"]["wind_speed_10m"][index], settings["Wind"]).toStringAsFixed(1)), wind_dir: item["hourly"]["wind_direction_10m"][index], + uv: item["hourly"]["uv_index"][index].round(), raw_precip: item["hourly"]["precipitation"][index], raw_temp: item["hourly"]["temperature_2m"][index], diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 2363db1..78c5d73 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -231,9 +231,10 @@ class _NewDayState extends State { child: PageView( controller: _pageController, children: [ - buildNewHours(day.hourly, data), + buildTemp(day.hourly, data), WindReport(hours: day.hourly, data: data,), WindReport(hours: day.hourly, data: data,), + buildUV(day.hourly, data), ], ), ), @@ -254,7 +255,7 @@ Widget buildNewDays(data) { ); } -Widget buildNewHours(List hours, data) => ListView( +Widget buildTemp(List hours, data) => ListView( physics: const BouncingScrollPhysics(), scrollDirection: Axis.horizontal, shrinkWrap: true, @@ -460,4 +461,73 @@ class WindReport extends StatelessWidget { ), ); } -} \ No newline at end of file +} + + +Widget buildUV(List hours, data) => ListView( + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: hours.map((hour) { + return SizedBox( + width: 55, //this is all to ensure that nothing shifts when you switch categories + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 15), + child: comfortatext('${hour.uv}', 19, data.settings, color: data.palette.primary), + ), + SizedBox( + height: 105, + child: ListView.builder( + physics: NeverScrollableScrollPhysics(), + itemCount: 10, + itemExtent: 10, + itemBuilder: (BuildContext context, int index) { + if (index < min(max(10 - hour.uv, 0), 10)) { + return Center( + child: Container( + width: 5, + height: 5, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: data.palette.primaryFixedDim, + ), + ), + ); + } + else { + return Center( + child: Container( + width: 8, + height: 8, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: data.palette.primary, + ), + ), + ); + } + } + ), + ), + Padding( + padding: const EdgeInsets.only(top: 12, left: 3, right: 3), + child: SizedBox( + height: 30, + child: Icon( + hour.icon, + color: data.palette.primary, + size: 31.0 * hour.iconSize, + ), + ) + ), + Padding( + padding: const EdgeInsets.only(top:13), + child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) + ) + ], + ), + ); + }).toList(), +); \ No newline at end of file diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 302e4c1..6998e70 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -57,7 +57,7 @@ Map textMaterialIcon = { }; Map textIconSizeNormalize = { - 'Clear Night': 0.8, + 'Clear Night': 0.77, 'Partly Cloudy': 0.8, 'Clear Sky': 0.8, 'Overcast': 0.74, From d90495827ddb71b5c61d08323b7aff46700dbb56 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 1 Aug 2024 15:34:07 +0200 Subject: [PATCH 053/129] finally got rid of splash color for choiceChip --- lib/decoders/decode_OM.dart | 12 +++- lib/new_forecast.dart | 106 ++++++++++++++++++++++++++++++++---- 2 files changed, 104 insertions(+), 14 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 2fbb12b..6b76341 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -40,12 +40,18 @@ String OMamPmTime(String time) { String a = time.split("T")[1]; List num = a.split(":"); int hour = int.parse(num[0]); + int minute = int.parse(num[1]); if (hour > 12) { - return "${hour - 12}:${num[1]}pm"; + if (minute < 10) { + return "${hour - 12}:0${minute}pm"; + } + return "${hour - 12}:${minute}pm"; } - - return "$hour:${num[1]}am"; + if (minute < 10) { + return "$hour:0${minute}am"; + } + return "$hour:${minute}am"; } int AqiIndexCorrection(int aqi) { diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 78c5d73..d584f0f 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -206,12 +206,17 @@ class _NewDayState extends State { children: List.generate( 4, (int index) { + return ChoiceChip( elevation: 0.0, checkmarkColor: data.palette.onPrimaryFixed, - selectedColor: data.palette.primaryFixedDim, - backgroundColor: data.palette.surfaceContainerLow, - side: BorderSide(color: data.palette.surfaceContainerLow, width: 0), + color: WidgetStateProperty.resolveWith((states) { + if (index == _value) { + return data.palette.primaryFixedDim; + } + return data.palette.surface; + }), + side: BorderSide(color: data.palette.primaryFixedDim, width: 1.0), label: comfortatext(['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, color: _value == index ? data.palette.onPrimaryFixed : data.palette.onSurface), selected: _value == index, @@ -232,7 +237,7 @@ class _NewDayState extends State { controller: _pageController, children: [ buildTemp(day.hourly, data), - WindReport(hours: day.hourly, data: data,), + buildPrecip(day.hourly, data), WindReport(hours: day.hourly, data: data,), buildUV(day.hourly, data), ], @@ -463,7 +468,6 @@ class WindReport extends StatelessWidget { } } - Widget buildUV(List hours, data) => ListView( physics: const BouncingScrollPhysics(), scrollDirection: Axis.horizontal, @@ -487,11 +491,11 @@ Widget buildUV(List hours, data) => ListView( if (index < min(max(10 - hour.uv, 0), 10)) { return Center( child: Container( - width: 5, - height: 5, + width: 10, + height: 4, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: data.palette.primaryFixedDim, + color: data.palette.surfaceContainerHigh, ), ), ); @@ -499,11 +503,91 @@ Widget buildUV(List hours, data) => ListView( else { return Center( child: Container( - width: 8, - height: 8, + width: 10, + height: 4, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: data.palette.primary, + color: data.palette.primaryFixedDim, + ), + ), + ); + } + } + ), + ), + Padding( + padding: const EdgeInsets.only(top: 12, left: 3, right: 3), + child: SizedBox( + height: 30, + child: Icon( + hour.icon, + color: data.palette.primary, + size: 31.0 * hour.iconSize, + ), + ) + ), + Padding( + padding: const EdgeInsets.only(top:13), + child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) + ) + ], + ), + ); + }).toList(), +); + + +Widget buildPrecip(List hours, data) => ListView( + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: hours.map((hour) { + return SizedBox( + width: 55, //this is all to ensure that nothing shifts when you switch categories + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + comfortatext('${hour.precip}', 18, data.settings, color: data.palette.primary, + weight: FontWeight.w500), + comfortatext('${data.settings["Precipitation"]}', 9, data.settings, color: data.palette.primary), + ], + ), + ), + SizedBox( + height: 101, + width: 15.5, + child: GridView.builder( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + ), + physics: NeverScrollableScrollPhysics(), + itemCount: 26, + reverse: true, + itemBuilder: (BuildContext context, int index) { + double prec = hour.precip > 0 ? 1 : 0; + prec += hour.precip * 2.0; + if (index >= prec) { + return Padding( + padding: const EdgeInsets.all(1.5), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: data.palette.surfaceContainerHigh, + ), + ), + ); + } + else { + return Padding( + padding: const EdgeInsets.all(1.5), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: data.palette.primaryFixedDim, ), ), ); From 3ce80c37ad5dee4a789e63866fdcd7dea8b2ef3a Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 1 Aug 2024 17:49:38 +0200 Subject: [PATCH 054/129] trying to keep the values of choiceChips --- lib/main_screens.dart | 226 ++++++++++++++++++++++++++---------------- lib/main_ui.dart | 3 +- lib/new_displays.dart | 17 +--- lib/new_forecast.dart | 72 +++++++++++--- lib/ui_helper.dart | 4 +- 5 files changed, 205 insertions(+), 117 deletions(-) diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 8dddabc..e419461 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -29,103 +29,159 @@ import 'main_ui.dart'; import 'new_displays.dart'; import 'ui_helper.dart'; -Widget NewMain(data, updateLocation, context) { - FlutterView view = WidgetsBinding.instance.platformDispatcher.views.first; - Size size = view.physicalSize / view.devicePixelRatio; - final FloatingSearchBarController controller = FloatingSearchBarController(); +class NewMain extends StatefulWidget { + final data; + final updateLocation; + final context; - return Scaffold( - backgroundColor: data.current.backcolor, - drawer: MyDrawer(primary: data.current.backup_primary, back: data.current.backup_backcolor, - settings: data.settings, image: data.current.backdrop,), - body: StretchyHeader.listView( - displacement: 130, - onRefresh: () async { - await updateLocation("${data.lat}, ${data.lng}", data.real_loc); - }, - headerData: HeaderData( - //backgroundColor: WHITE, - blurContent: false, - headerHeight: max(size.height * 0.53, 400), //we don't want it to be smaller than 400 - header: ParrallaxBackground(image: data.image, key: Key(data.place), - color: data.current.backcolor == BLACK ? BLACK - : lightAccent(data.current.backcolor, 5000)), - overlay: Stack( - children: [ - Padding( - padding: EdgeInsets.only(left: 25, - top: MediaQuery.of(context).padding.top + 20, right: 25, bottom: 25 - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Spacer(), - Padding( - padding: const EdgeInsets.only(left: 0, bottom: 2), - child: comfortatext("${data.current.temp}°", 68, data.settings, - color: data.colorpop, weight: FontWeight.w300), - ), - Padding( - padding: const EdgeInsets.only(left: 0), - child: comfortatext(data.current.text, 32, data.settings, - weight: data.settings["Color mode"] == "dark" ? FontWeight.w600 : FontWeight.w400, - color: data.desc_color), - ) - ], + NewMain({Key? key, required this.data, required this.updateLocation, required this.context}) : super(key: key); + + @override + _NewMainState createState() => _NewMainState(data, updateLocation, context); +} + +class _NewMainState extends State { + final data; + final updateLocation; + final context; + + List chips = [0, 0, 0]; + + void updateChip(int index, int to) { + setState(() { + chips[index] = to; + }); + } + + _NewMainState(this.data, this.updateLocation, this.context); + + @override + Widget build(BuildContext context) { + final FlutterView view = WidgetsBinding.instance.platformDispatcher.views.first; + final Size size = view.physicalSize / view.devicePixelRatio; + + final FloatingSearchBarController controller = FloatingSearchBarController(); + + return Scaffold( + backgroundColor: data.current.backcolor, + drawer: MyDrawer(primary: data.current.backup_primary, + back: data.current.backup_backcolor, + settings: data.settings, + image: data.current.backdrop,), + body: StretchyHeader.listView( + displacement: 130, + onRefresh: () async { + await updateLocation("${data.lat}, ${data.lng}", data.real_loc); + }, + headerData: HeaderData( + //backgroundColor: WHITE, + blurContent: false, + headerHeight: max(size.height * 0.525, 400), + //we don't want it to be smaller than 400 + header: ParrallaxBackground(image: data.image, key: Key(data.place), + color: data.current.backcolor == BLACK ? BLACK + : lightAccent(data.current.backcolor, 5000)), + overlay: Stack( + children: [ + Padding( + padding: EdgeInsets.only(left: 25, + top: MediaQuery + .of(context) + .padding + .top + 20, right: 25, bottom: 25 + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Spacer(), + Padding( + padding: const EdgeInsets.only(left: 0, bottom: 2), + child: comfortatext( + "${data.current.temp}°", 68, data.settings, + color: data.colorpop, weight: FontWeight.w300), + ), + Padding( + padding: const EdgeInsets.only(left: 0), + child: comfortatext( + data.current.text, 32, data.settings, + weight: data.settings["Color mode"] == "dark" + ? FontWeight.w600 + : FontWeight.w400, + color: data.desc_color), + ) + ], + ), ), + MySearchParent(updateLocation: updateLocation, + color: data.current.backcolor, + place: data.place, + controller: controller, + settings: data.settings, + real_loc: data.real_loc, + secondColor: data.current.primary, + textColor: data.current.textcolor, + highlightColor: data.current.highlight, + key: Key("${data.place}, ${data.current.backcolor}"),), + ], + ) + ), + children: [ + Stack( + children: [ + UpdatedNotifier(data: data, + time: data.updatedTime, + key: Key(data.updatedTime.toString())), + LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + if (constraints.maxWidth > 500.0) { + return Circles(500, data, 0.5, data.palette.primary); + } else { + return Circles(constraints.maxWidth * 0.97, data, 0.5, + data.palette.primary); + } + } ), - MySearchParent(updateLocation: updateLocation, - color: data.current.backcolor, place: data.place, - controller: controller, settings: data.settings, real_loc: data.real_loc, - secondColor: data.current.primary, textColor: data.current.textcolor, - highlightColor: data.current.highlight, key: Key("${data.place}, ${data.current.backcolor}"),), ], - ) - ), - children: [ - Stack( - children: [ - UpdatedNotifier(data: data, time: data.updatedTime, key: Key(data.updatedTime.toString())), - LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - if(constraints.maxWidth > 500.0) { - return Circles(500, data, 0.5, data.palette.primary); - } else { - return Circles(constraints.maxWidth * 0.97, data, 0.5, data.palette.primary); - } - } - ), - ], - ), + ), - NewSunriseSunset(data: data, key: Key(data.place), size: size,), - NewRain15MinuteIndicator(data), - NewAirQuality(data), - RadarSmall(data: data, key: Key("${data.place}, ${data.current.backcolor}")), - buildNewDays(data), + NewSunriseSunset(data: data, key: Key(data.place), size: size,), + NewRain15MinuteIndicator(data), + NewAirQuality(data), + RadarSmall( + data: data, key: Key("${data.place}, ${data.current.backcolor}")), + buildNewDays(data, chips, updateChip), + buildNewGlanceDay(data), - Padding( - padding: const EdgeInsets.only(top: 10, bottom: 30), - child: providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, - data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), - ), + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 30), + child: providerSelector( + data.settings, + updateLocation, + data.current.textcolor, + data.current.highlight, + data.current.primary, + data.provider, + "${data.lat}, ${data.lng}", + data.real_loc), + ), - /* - NewTimes(data, true), - buildHihiDays(data), - buildGlanceDay(data), - providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, - data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), + /* + NewTimes(data, true), + buildHihiDays(data), + buildGlanceDay(data), + providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, + data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), - */ - const Padding(padding: EdgeInsets.only(bottom: 20)) + */ + const Padding(padding: EdgeInsets.only(bottom: 20)) - ], - ), - ); + ], + ), + ); + } } Widget TabletLayout(data, updateLocation, context) { diff --git a/lib/main_ui.dart b/lib/main_ui.dart index 4c9d243..985d718 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -56,7 +56,8 @@ class WeatherPage extends StatelessWidget { //return PhoneLayout(data, updateLocation, context); - return NewMain(data, updateLocation, context,); + return NewMain(data: data, updateLocation: updateLocation, context: context, + key: Key("${data.place}, ${data.current.backcolor}"),); } } diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 87fe708..e020d53 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -182,11 +182,7 @@ class _NewSunriseSunsetState extends State Padding( padding: EdgeInsets.only( left: min( - max( - (progress * (widget.size.width - 50)) - - textWidth / 2 - - 3, - 0), + max((progress * (widget.size.width - 50)) - textWidth / 2 + 2, 0), widget.size.width - 55 - textWidth)), child: Align( alignment: Alignment.centerLeft, @@ -198,7 +194,7 @@ class _NewSunriseSunsetState extends State Padding( padding: EdgeInsets.only( top: 6, - left: min(max((progress * (widget.size.width - 50)) - 5, 2), + left: min(max((progress * (widget.size.width - 50)), 2), widget.size.width - 52)), child: Align( alignment: Alignment.centerLeft, @@ -434,11 +430,4 @@ Widget NewRain15MinuteIndicator(var data) { ), ) ); -} - -Widget newRadar(var data) { - return Padding( - padding: EdgeInsets.only(left: 20, right: 20, top: 10), - child: Container(), - ); -} +} \ No newline at end of file diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index d584f0f..3d4d1f6 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -27,17 +27,21 @@ import 'ui_helper.dart'; class NewDay extends StatefulWidget { final data; final index; + final value; + final updateChip; - NewDay({Key? key, required this.data, required this.index}) : super(key: key); + NewDay({Key? key, required this.data, required this.index, required this.value, + required this.updateChip}) : super(key: key); @override - _NewDayState createState() => _NewDayState(data); + _NewDayState createState() => _NewDayState(data, value, updateChip, index); } class _NewDayState extends State { final data; - - int _value = 0; + final _value; + final Function updateChip; + final myIndex; PageController _pageController = PageController(); @@ -48,8 +52,8 @@ class _NewDayState extends State { curve: Curves.fastEaseInToSlowEaseOut, ); } - - _NewDayState(this.data); + + _NewDayState(this.data, this._value, this.updateChip, this.myIndex); @override Widget build(BuildContext context) { @@ -217,12 +221,13 @@ class _NewDayState extends State { return data.palette.surface; }), side: BorderSide(color: data.palette.primaryFixedDim, width: 1.0), - label: comfortatext(['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, + label: comfortatext( + ['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, color: _value == index ? data.palette.onPrimaryFixed : data.palette.onSurface), selected: _value == index, onSelected: (bool selected) { + updateChip(myIndex, selected); setState(() { - _value = (selected ? index : null)!; _onItemTapped(index); }); }, @@ -249,13 +254,14 @@ class _NewDayState extends State { } } -Widget buildNewDays(data) { +Widget buildNewDays(data, chips, updateChip) { return ListView.builder( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: 3, itemBuilder: (BuildContext context, int index) { - return NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.backcolor}"),); + return NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.backcolor} $chips"), + value: chips[index], updateChip: updateChip,); }, ); } @@ -341,7 +347,7 @@ class WindChartPainter extends CustomPainter { ..strokeWidth = 2.0; final smallDotPaint = Paint() - ..color = data.palette.primaryContainer + ..color = data.palette.surfaceContainerHigh ..strokeWidth = 1.0; final textPainter = TextPainter( @@ -351,7 +357,7 @@ class WindChartPainter extends CustomPainter { for (int i = 0; i < hours.length; i++) { final x = 27.5 + i * spacing; - final y = maxHeight - max(min(hours[i].raw_wind * 1.5, maxHeight), 0); + final y = maxHeight - max(min(hours[i].raw_wind * 1.8, maxHeight), 0); canvas.drawCircle(Offset(x, y), dotRadius, paint); @@ -374,7 +380,7 @@ class WindChartPainter extends CustomPainter { if (i < hours.length - 1) { final nextX = 27.5 + (i + 1) * spacing; - final nextY = maxHeight - max(min(hours[i + 1].raw_wind * 1.5, maxHeight), 0); + final nextY = maxHeight - max(min(hours[i + 1].raw_wind * 1.8, maxHeight), 0); int numDots = 4; double dx = (nextX - x) / numDots; @@ -492,7 +498,7 @@ Widget buildUV(List hours, data) => ListView( return Center( child: Container( width: 10, - height: 4, + height: 5, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: data.palette.surfaceContainerHigh, @@ -504,7 +510,7 @@ Widget buildUV(List hours, data) => ListView( return Center( child: Container( width: 10, - height: 4, + height: 5, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: data.palette.primaryFixedDim, @@ -614,4 +620,40 @@ Widget buildPrecip(List hours, data) => ListView( ), ); }).toList(), +); + + +Widget buildNewGlanceDay(var data) => Padding( + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 10), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(left: 5, top: 0), + child: Align( + alignment: Alignment.centerLeft, + child: comfortatext( + "daily", 16, + data.settings, + color: data.palette.onSurface), + ), + ), + ListView.builder( + shrinkWrap: true, + padding: const EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 5), + physics: const NeverScrollableScrollPhysics(), + itemCount: data.days.length - 3, + itemBuilder: (context, index) { + final day = data.days[index + 3]; + return Padding( + padding: const EdgeInsets.only(top: 5, bottom: 5), + child: Column( + children: [ + + ] + ) + ); + } + ), + ], + ), ); \ No newline at end of file diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 9a490d8..d2d2b26 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -268,9 +268,9 @@ class DescriptionCircle extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic, children: [ - comfortatext(text, fontsize, settings, color: color, weight: FontWeight.w500), + comfortatext(text, fontsize, settings, color: color, weight: FontWeight.w400), Flexible( - child: comfortatext(extra, small_font, settings, color: color, weight: FontWeight.w500) + child: comfortatext(extra, small_font, settings, color: color, weight: FontWeight.w400) ), ], ), From 2f226d10494301cb718a5e5e2627f8f4d63db31d Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 3 Aug 2024 17:00:23 +0200 Subject: [PATCH 055/129] trying to improve the relevancy of unsplash images --- lib/decoders/decode_OM.dart | 2 +- lib/decoders/decode_wapi.dart | 2 +- lib/decoders/extra_info.dart | 93 ++++++++++++++++++++++++++++++----- lib/main_screens.dart | 2 +- lib/main_ui.dart | 2 +- lib/ui_helper.dart | 1 + lib/weather_refact.dart | 56 +++++++++++++++------ 7 files changed, 126 insertions(+), 32 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 6b76341..c6948e2 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -612,7 +612,7 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as // GET IMAGE Image Uimage = await getUnsplashImage(oMCurrentTextCorrection( - oMBody["current"]["weather_code"], sunstatus, real_time), real_loc); + oMBody["current"]["weather_code"], sunstatus, real_time), real_loc, lat, lng); //GET COLORS List imageColors = await getImageColors(Uimage, settings["Color mode"]); diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index b064daf..f19b7ad 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -519,7 +519,7 @@ Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) language: "English"); //GET IMAGE - Image Uimage = await getUnsplashImage(text, real_loc); + Image Uimage = await getUnsplashImage(text, real_loc, lat, lng); //GET COLORS List imageColors = await getImageColors(Uimage, settings["Color mode"]); diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 4909740..c0ba1b4 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -32,9 +32,9 @@ import '../ui_helper.dart'; import '../weather_refact.dart'; import 'decode_wapi.dart'; -Future getUnsplashImage(String _text, String real_loc) async { +Future getUnsplashImage(String _text, String real_loc, double lat, double lng) async { - String text_query = textToUnsplashText[_text]!; + String text_query = textToUnsplashText[_text]![0]; //String addon = wapi_body["current"]["is_day"] == 1 ? 'daytime' : 'nighttime'; @@ -42,24 +42,77 @@ Future getUnsplashImage(String _text, String real_loc) async { 'client_id': access_key, 'query' : "$text_query, $real_loc", 'content_filter' : 'high', - 'count': '3', - //'collections' : '893395, 1319040, 583204, 11649432, 162468, 1492135', + 'count': '6', + //'collections' : '893395, 583204, 11649432, 162468, 1492135, 42478673, 8253647, 461360' + //'collections' : '893395, 162468, 461360' }; final url2 = Uri.https('api.unsplash.com', 'photos/random', params2); - var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query ") + var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query") .timeout(const Duration(seconds: 6)); var response2 = await file2.readAsString(); var unsplash_body = jsonDecode(response2); - var rng = Random(); + //var rng = Random(); + //int index = rng.nextInt(3); + int index = 0; + double best = 99999999999; - String image_path = unsplash_body[rng.nextInt(3)]["urls"]["regular"]; + for (int i = 0; i < unsplash_body.length; i++) { + double lat_dif = pow((lat - (unsplash_body[i]["location"]["position"]["latitude"] ?? 9999)).abs(), 2) * 1.0; + double lng_dif = pow((lng - (unsplash_body[i]["location"]["position"]["longitude"] ?? 9999)).abs(), 2) * 1.0; + double unaccuracy = min(lat_dif + lng_dif, 50); - print(image_path); + if (unsplash_body[i]["location"]["position"]["city"] == real_loc) { + unaccuracy -= 10000; + } + + var desc = unsplash_body[i]["description"]; + + if (desc != null) { + desc = desc.toLowerCase(); + List keys = textToUnsplashText.keys.toList(); + for (int x = 0; x < textToUnsplashText.length; x ++) { + for (int y = 0; y < textToUnsplashText[keys[x]]!.length; y ++) { + int reward = keys[x] == _text ? -3000 : 10000; + if (desc.contains(textToUnsplashText[keys[x]]![y])) { + unaccuracy += reward; // i had to reverse it + } + } + } + + keys = textFilter.keys.toList(); + for (int x = 0; x < textFilter.length; x ++) { + if (desc.contains(keys[x])) { + unaccuracy -= textFilter[keys[x]]!; // i had to reverse it + } + } + + if (desc.contains(real_loc.toLowerCase())) { + unaccuracy -= 3000; + } + } + else { + unaccuracy += 100; //if there is a description then there is a chance that we determine the value more. + //therefore not having one must be punished + } + + unaccuracy -= unsplash_body[i]["likes"] * 0.02 ?? 0; + unaccuracy -= unsplash_body[i]["downloads"] * 0.01 ?? 0; + + print((unaccuracy.toStringAsFixed(6), (desc ?? "null").trim(), unsplash_body[i]["likes"], unsplash_body[i]["downloads"])); + if (unaccuracy < best) { + index = i; + best = unaccuracy; + } + } + + String image_path = unsplash_body[index]["urls"]["regular"]; + print(index); + print(unsplash_body[index]["links"]["html"]); return Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover,); } @@ -75,20 +128,32 @@ Future getImageColors(Image Uimage, color_mode) async { Color bestcolor = palette.primaryFixedDim; int bestDif = difFromBackColors(bestcolor, dominant); - if (bestDif < 300) { + if (bestDif <= 330) { for (int i = 1; i < 4; i++) { //LIGHT - Color newcolor = lighten2(startcolor, i / 20); + Color newcolor = lighten(startcolor, i / 25); int newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < 400) { + if (newdif > bestDif && newdif < 440) { bestDif = newdif; bestcolor = newcolor; } //DARK - newcolor = darken2(startcolor, i / 20); + newcolor = darken(startcolor, i / 25); newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < 400) { + if (newdif > bestDif && newdif < 440) { + bestDif = newdif; + bestcolor = newcolor; + } + } + } + + //if the contrast is still low then we need to choose another color + if (bestDif <= 330) { + for (int i = 0; i < dominant.length; i++) { + Color newcolor = dominant[i]; + int newdif = difFromBackColors(newcolor, dominant); + if (newdif > bestDif && newdif < 440) { bestDif = newdif; bestcolor = newcolor; } @@ -98,6 +163,8 @@ Future getImageColors(Image Uimage, color_mode) async { Color desc_color = palette.surface; int desc_dif = difFromBackColors(desc_color, dominant); + print(("diffs", bestDif, desc_dif)); + print(("desc_dif", desc_dif)); if (desc_dif < 200) { diff --git a/lib/main_screens.dart b/lib/main_screens.dart index e419461..38ee849 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -77,7 +77,7 @@ class _NewMainState extends State { headerData: HeaderData( //backgroundColor: WHITE, blurContent: false, - headerHeight: max(size.height * 0.525, 400), + headerHeight: max(size.height * 0.53, 400), //we don't want it to be smaller than 400 header: ParrallaxBackground(image: data.image, key: Key(data.place), color: data.current.backcolor == BLACK ? BLACK diff --git a/lib/main_ui.dart b/lib/main_ui.dart index 985d718..cfa4951 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -57,7 +57,7 @@ class WeatherPage extends StatelessWidget { //return PhoneLayout(data, updateLocation, context); return NewMain(data: data, updateLocation: updateLocation, context: context, - key: Key("${data.place}, ${data.current.backcolor}"),); + key: Key("${data.place}, ${data.current.primary} ${data.image}"),); } } diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index d2d2b26..c196dd6 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -107,6 +107,7 @@ Color lighten2(Color c, [double amount = 0.1]) { c.blue + ((255 - c.blue) * amount).round() ); } + Color lightAccent(Color color, int intensity) { double x = intensity / (color.red + color.green + color.blue); return Color.fromRGBO(sqrt(color.red * x).toInt(), sqrt(color.green * x).toInt(), sqrt(color.blue * x).toInt(), 1); diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 6998e70..1531fb3 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -343,21 +343,47 @@ Map> conversionTable = { //I am trying to convert conditions to text that unsplash better understands //for example: blue sky instead of clear sky tends to help a lot -Map textToUnsplashText = { - 'Clear Night': 'night', //somehow just 'night' always gives you clear skies: stars or moon - 'Partly Cloudy': 'cloudy', //this is also some simplification which improves a lot - 'Clear Sky': 'blue sky', //it doesn't understand clear as much so i use blue instead - 'Overcast': 'dark clouds', //kinda works - 'Haze': 'haze', - 'Rain': 'rain', - 'Sleet': 'freezing rain',//this works much better - 'Drizzle': 'light rain', //somehow understands it more though still not perfect - 'Thunderstorm': 'thunderstorm', - 'Heavy Snow': 'heavy snow', - 'Fog': 'fog', - 'Snow': 'snow', - 'Heavy Rain': 'heavy rain', - 'Cloudy Night' : 'cloudy night' //if you specify cloudy then it gives cloudy results +Map> textToUnsplashText = { + 'Clear Night': ['night', 'clear', 'night'], //somehow just 'night' always gives you clear skies: stars or moon + 'Partly Cloudy': ['cloudy', 'cloud', 'clouds', 'day'], //this is also some simplification which improves a lot + 'Clear Sky': ['blue sky', 'sunny', 'sun', 'clear', 'day'], //it doesn't understand clear as much so i use blue instead + 'Overcast': ['overcast', 'clouds', 'day'], + 'Haze': ['haze', 'fog', 'mist'], + 'Rain': ['rain', 'drop', 'rainy', 'raining', 'drops'], + 'Sleet': ['freezing rain', 'sleet', 'ice'],//this works much better + 'Drizzle': ['light rain', 'rain', 'rainy', 'raining', 'drop', 'drops'], //somehow understands it more though still not perfect + 'Thunderstorm': ['thunderstorm', 'lighting', 'storm'], + 'Heavy Snow': ['heavy snow', 'snow', 'snowing', 'snows', 'day'], + 'Fog': ['fog', 'mist', 'haze'], + 'Snow': ['snow', 'snowing', 'snows'], + 'Heavy Rain': ['heavy rain', 'rain', 'drop', 'rainy', 'raining'], + 'Cloudy Night' : ['cloudy night', 'night'] //if you specify cloudy then it gives cloudy results +}; + +//trying to assign values for words (for example sky will be rewarded) +Map textFilter = { + 'sky' : 3300, + 'weather': 5000, + 'tree': 1000, + 'plant': 1000, + 'flower': 1000, + 'cliff': 1000, + 'mountain': 10000, + 'bubble': -10000, + 'ring': -10000, + 'man': -10000000, //trying to not have people in images + 'male': -1000000, + 'female': -1000000, + 'human': -1000000, + 'girl': -1000000, + 'boy': -1000000, + 'woman': -10000000, + 'person': -10000000, + 'child': -10000000, + 'crowd': -10000, + 'people': 100000, + 'hand': -100000, + 'feet': -100000, }; //if i have to get the average of two weather conditions then the condition From e406bae21e4a68572bfae592a3c0afa069c2c130 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 3 Aug 2024 17:53:17 +0200 Subject: [PATCH 056/129] tweaking the image selection process --- lib/decoders/extra_info.dart | 14 ++++++++------ lib/weather_refact.dart | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index c0ba1b4..d2469c7 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -64,10 +64,10 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double for (int i = 0; i < unsplash_body.length; i++) { double lat_dif = pow((lat - (unsplash_body[i]["location"]["position"]["latitude"] ?? 9999)).abs(), 2) * 1.0; double lng_dif = pow((lng - (unsplash_body[i]["location"]["position"]["longitude"] ?? 9999)).abs(), 2) * 1.0; - double unaccuracy = min(lat_dif + lng_dif, 50); + double unaccuracy = min(lat_dif + lng_dif, 100) * 10; if (unsplash_body[i]["location"]["position"]["city"] == real_loc) { - unaccuracy -= 10000; + unaccuracy -= 1000; } var desc = unsplash_body[i]["description"]; @@ -77,8 +77,9 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double List keys = textToUnsplashText.keys.toList(); for (int x = 0; x < textToUnsplashText.length; x ++) { for (int y = 0; y < textToUnsplashText[keys[x]]!.length; y ++) { - int reward = keys[x] == _text ? -3000 : 10000; + int reward = keys[x] == _text ? -3000 : 1000; if (desc.contains(textToUnsplashText[keys[x]]![y])) { + print(("punished", textToUnsplashText[keys[x]]![y], reward)); unaccuracy += reward; // i had to reverse it } } @@ -87,6 +88,7 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double keys = textFilter.keys.toList(); for (int x = 0; x < textFilter.length; x ++) { if (desc.contains(keys[x])) { + print(("punished", keys[x])); unaccuracy -= textFilter[keys[x]]!; // i had to reverse it } } @@ -100,10 +102,10 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double //therefore not having one must be punished } - unaccuracy -= unsplash_body[i]["likes"] * 0.02 ?? 0; - unaccuracy -= unsplash_body[i]["downloads"] * 0.01 ?? 0; + unaccuracy -= unsplash_body[i]["likes"] * 0.01 ?? 0; + unaccuracy -= unsplash_body[i]["downloads"] * 0.005 ?? 0; - print((unaccuracy.toStringAsFixed(6), (desc ?? "null").trim(), unsplash_body[i]["likes"], unsplash_body[i]["downloads"])); + print((i, unaccuracy.toStringAsFixed(6), (desc ?? "null").trim(), unsplash_body[i]["likes"], unsplash_body[i]["downloads"])); if (unaccuracy < best) { index = i; best = unaccuracy; diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 1531fb3..c0390b9 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -345,15 +345,15 @@ Map> conversionTable = { //for example: blue sky instead of clear sky tends to help a lot Map> textToUnsplashText = { 'Clear Night': ['night', 'clear', 'night'], //somehow just 'night' always gives you clear skies: stars or moon - 'Partly Cloudy': ['cloudy', 'cloud', 'clouds', 'day'], //this is also some simplification which improves a lot - 'Clear Sky': ['blue sky', 'sunny', 'sun', 'clear', 'day'], //it doesn't understand clear as much so i use blue instead - 'Overcast': ['overcast', 'clouds', 'day'], + 'Partly Cloudy': ['cloudy', 'cloud', 'clouds',], //this is also some simplification which improves a lot + 'Clear Sky': ['blue sky', 'sunny', 'sun', 'clear',], //it doesn't understand clear as much so i use blue instead + 'Overcast': ['overcast', 'clouds'], 'Haze': ['haze', 'fog', 'mist'], 'Rain': ['rain', 'drop', 'rainy', 'raining', 'drops'], 'Sleet': ['freezing rain', 'sleet', 'ice'],//this works much better 'Drizzle': ['light rain', 'rain', 'rainy', 'raining', 'drop', 'drops'], //somehow understands it more though still not perfect - 'Thunderstorm': ['thunderstorm', 'lighting', 'storm'], - 'Heavy Snow': ['heavy snow', 'snow', 'snowing', 'snows', 'day'], + 'Thunderstorm': ['thunderstorm', 'lightning', 'storm'], + 'Heavy Snow': ['heavy snow', 'snow', 'snowing', 'snows'], 'Fog': ['fog', 'mist', 'haze'], 'Snow': ['snow', 'snowing', 'snows'], 'Heavy Rain': ['heavy rain', 'rain', 'drop', 'rainy', 'raining'], @@ -369,10 +369,17 @@ Map textFilter = { 'flower': 1000, 'cliff': 1000, 'mountain': 10000, + 'ice': -10000, + 'icy': -10000, 'bubble': -10000, + 'instagram': -10000, 'ring': -10000, + 'fabric': -10000, + 'texture': -10000, + 'pattern': -10000, 'man': -10000000, //trying to not have people in images 'male': -1000000, + 'couple': -1000000, 'female': -1000000, 'human': -1000000, 'girl': -1000000, From 74bba3ef0db992f6f19443f1795a9d9eabd613a8 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 3 Aug 2024 18:20:35 +0200 Subject: [PATCH 057/129] filtering now uses the link too --- lib/decoders/extra_info.dart | 47 ++++++++++++++++-------------------- lib/new_displays.dart | 6 ++--- lib/weather_refact.dart | 3 ++- 3 files changed, 26 insertions(+), 30 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index d2469c7..4c15982 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -70,42 +70,37 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double unaccuracy -= 1000; } - var desc = unsplash_body[i]["description"]; - - if (desc != null) { - desc = desc.toLowerCase(); - List keys = textToUnsplashText.keys.toList(); - for (int x = 0; x < textToUnsplashText.length; x ++) { - for (int y = 0; y < textToUnsplashText[keys[x]]!.length; y ++) { - int reward = keys[x] == _text ? -3000 : 1000; - if (desc.contains(textToUnsplashText[keys[x]]![y])) { - print(("punished", textToUnsplashText[keys[x]]![y], reward)); - unaccuracy += reward; // i had to reverse it - } - } - } - - keys = textFilter.keys.toList(); - for (int x = 0; x < textFilter.length; x ++) { - if (desc.contains(keys[x])) { - print(("punished", keys[x])); - unaccuracy -= textFilter[keys[x]]!; // i had to reverse it + var desc1 = unsplash_body[i]["description"] ?? " "; + var desc2 = unsplash_body[i]["links"]["html"]; + + var desc = desc1.toLowerCase() + " " + desc2.toLowerCase(); + List keys = textToUnsplashText.keys.toList(); + for (int x = 0; x < textToUnsplashText.length; x ++) { + for (int y = 0; y < textToUnsplashText[keys[x]]!.length; y ++) { + int reward = keys[x] == _text ? -3000 : 1000; + if (desc.contains(textToUnsplashText[keys[x]]![y])) { + print(("punished", textToUnsplashText[keys[x]]![y], reward)); + unaccuracy += reward; // i had to reverse it } } + } - if (desc.contains(real_loc.toLowerCase())) { - unaccuracy -= 3000; + keys = textFilter.keys.toList(); + for (int x = 0; x < textFilter.length; x ++) { + if (desc.contains(keys[x])) { + print(("punished", keys[x])); + unaccuracy -= textFilter[keys[x]]!; // i had to reverse it } } - else { - unaccuracy += 100; //if there is a description then there is a chance that we determine the value more. - //therefore not having one must be punished + + if (desc.contains(real_loc.toLowerCase())) { + unaccuracy -= 3000; } unaccuracy -= unsplash_body[i]["likes"] * 0.01 ?? 0; unaccuracy -= unsplash_body[i]["downloads"] * 0.005 ?? 0; - print((i, unaccuracy.toStringAsFixed(6), (desc ?? "null").trim(), unsplash_body[i]["likes"], unsplash_body[i]["downloads"])); + print((i, unaccuracy.toStringAsFixed(6), (desc1 ?? "null").trim() + ", " + desc2, unsplash_body[i]["likes"], unsplash_body[i]["downloads"])); if (unaccuracy < best) { index = i; best = unaccuracy; diff --git a/lib/new_displays.dart b/lib/new_displays.dart index e020d53..985dfc4 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -176,7 +176,7 @@ class _NewSunriseSunsetState extends State final textWidth = textPainter.width; return Padding( - padding: const EdgeInsets.only(left: 25, right: 25, top: 10), + padding: const EdgeInsets.only(left: 25, right: 25, top: 13), child: Column( children: [ Padding( @@ -262,7 +262,7 @@ class _NewSunriseSunsetState extends State Widget NewAirQuality(var data) { return Padding( - padding: const EdgeInsets.only(left: 20, right: 20, bottom: 19, top: 24), + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 19, top: 26), child: Column( children: [ Padding( @@ -348,7 +348,7 @@ Widget NewRain15MinuteIndicator(var data) { return Visibility( visible: data.minutely_15_precip.t_minus != "", child: Padding( - padding: const EdgeInsets.only(left: 21, right: 21, top: 20, bottom: 10), + padding: const EdgeInsets.only(left: 21, right: 21, top: 23, bottom: 15), child: Container( decoration: BoxDecoration( color: data.palette.surfaceContainerLow, diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index c0390b9..49bb61a 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -374,6 +374,7 @@ Map textFilter = { 'bubble': -10000, 'instagram': -10000, 'ring': -10000, + 'during': 10000, 'fabric': -10000, 'texture': -10000, 'pattern': -10000, @@ -388,7 +389,7 @@ Map textFilter = { 'person': -10000000, 'child': -10000000, 'crowd': -10000, - 'people': 100000, + 'people': -100000, 'hand': -100000, 'feet': -100000, }; From 74b85785b0d19a6842933d0ca7c74a100c182f63 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 3 Aug 2024 18:36:56 +0200 Subject: [PATCH 058/129] still trying to filter images --- lib/decoders/extra_info.dart | 29 +++++++++++++++++++---------- lib/weather_refact.dart | 2 ++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 4c15982..768cf8e 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -34,13 +34,23 @@ import 'decode_wapi.dart'; Future getUnsplashImage(String _text, String real_loc, double lat, double lng) async { + List keys1 = textFilter.keys.toList(); + //this is all to make sure that none + // of the banned words get somehow into the search query + String loc = real_loc; + for (int i = 0; i < keys1.length; i++) { + if (loc.contains(keys1[i])) { + loc = ""; + } + } + String text_query = textToUnsplashText[_text]![0]; //String addon = wapi_body["current"]["is_day"] == 1 ? 'daytime' : 'nighttime'; final params2 = { 'client_id': access_key, - 'query' : "$text_query, $real_loc", + 'query' : "$text_query, $loc", 'content_filter' : 'high', 'count': '6', //'collections' : '893395, 583204, 11649432, 162468, 1492135, 42478673, 8253647, 461360' @@ -74,22 +84,21 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double var desc2 = unsplash_body[i]["links"]["html"]; var desc = desc1.toLowerCase() + " " + desc2.toLowerCase(); - List keys = textToUnsplashText.keys.toList(); + List keys2 = textToUnsplashText.keys.toList(); for (int x = 0; x < textToUnsplashText.length; x ++) { - for (int y = 0; y < textToUnsplashText[keys[x]]!.length; y ++) { - int reward = keys[x] == _text ? -3000 : 1000; - if (desc.contains(textToUnsplashText[keys[x]]![y])) { - print(("punished", textToUnsplashText[keys[x]]![y], reward)); + for (int y = 0; y < textToUnsplashText[keys2[x]]!.length; y ++) { + int reward = keys2[x] == _text ? -3000 : 1000; + if (desc.contains(textToUnsplashText[keys2[x]]![y])) { + print(("punished", textToUnsplashText[keys2[x]]![y], reward)); unaccuracy += reward; // i had to reverse it } } } - keys = textFilter.keys.toList(); for (int x = 0; x < textFilter.length; x ++) { - if (desc.contains(keys[x])) { - print(("punished", keys[x])); - unaccuracy -= textFilter[keys[x]]!; // i had to reverse it + if (desc.contains(keys1[x])) { + print(("punished", keys1[x])); + unaccuracy -= textFilter[keys1[x]]!; // i had to reverse it } } diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 49bb61a..40e9a49 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -392,6 +392,8 @@ Map textFilter = { 'people': -100000, 'hand': -100000, 'feet': -100000, + 'bikini': -1000000, + 'swimsuit': -1000000, }; //if i have to get the average of two weather conditions then the condition From 92bc342cf5be966831e5f1656f2940786a03ff2d Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 3 Aug 2024 19:17:14 +0200 Subject: [PATCH 059/129] removed all old icons --- assets/icons/Overmorrow_white_circle.png | Bin 16003 -> 0 bytes assets/icons/Overmorrow_white_classic.png | Bin 13429 -> 0 bytes assets/icons/Overmorrow_white_rect.png | Bin 10255 -> 0 bytes assets/icons/cloudy.png | Bin 14274 -> 0 bytes assets/icons/cloudy_night.png | Bin 16790 -> 0 bytes assets/icons/drizzle.png | Bin 14833 -> 0 bytes assets/icons/fog.png | Bin 16999 -> 0 bytes assets/icons/haze.png | Bin 18316 -> 0 bytes assets/icons/heavy_rain.png | Bin 15809 -> 0 bytes assets/icons/heavy_snow.png | Bin 14438 -> 0 bytes assets/icons/lightning.png | Bin 14039 -> 0 bytes assets/icons/moon.png | Bin 9335 -> 0 bytes assets/icons/partly_cloudy.png | Bin 16203 -> 0 bytes assets/icons/rainy.png | Bin 15875 -> 0 bytes assets/icons/sleet.png | Bin 15791 -> 0 bytes assets/icons/snow.png | Bin 15611 -> 0 bytes assets/icons/sun.png | Bin 6810 -> 0 bytes lib/decoders/decode_mn.dart | 10 +++--- lib/decoders/decode_wapi.dart | 12 +++++--- lib/weather_refact.dart | 19 +----------- pubspec.lock | 36 +++++++++++----------- pubspec.yaml | 1 - 22 files changed, 32 insertions(+), 46 deletions(-) delete mode 100644 assets/icons/Overmorrow_white_circle.png delete mode 100644 assets/icons/Overmorrow_white_classic.png delete mode 100644 assets/icons/Overmorrow_white_rect.png delete mode 100644 assets/icons/cloudy.png delete mode 100644 assets/icons/cloudy_night.png delete mode 100644 assets/icons/drizzle.png delete mode 100644 assets/icons/fog.png delete mode 100644 assets/icons/haze.png delete mode 100644 assets/icons/heavy_rain.png delete mode 100644 assets/icons/heavy_snow.png delete mode 100644 assets/icons/lightning.png delete mode 100644 assets/icons/moon.png delete mode 100644 assets/icons/partly_cloudy.png delete mode 100644 assets/icons/rainy.png delete mode 100644 assets/icons/sleet.png delete mode 100644 assets/icons/snow.png delete mode 100644 assets/icons/sun.png diff --git a/assets/icons/Overmorrow_white_circle.png b/assets/icons/Overmorrow_white_circle.png deleted file mode 100644 index fdc6f133d51e27bd561caf78a79b6771f4d2bc88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16003 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 diff --git a/assets/icons/Overmorrow_white_classic.png b/assets/icons/Overmorrow_white_classic.png deleted file mode 100644 index 12d48ebed2a9fa3662d9e8dcc1c40b6078f24ebe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13429 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 diff --git a/assets/icons/Overmorrow_white_rect.png b/assets/icons/Overmorrow_white_rect.png deleted file mode 100644 index 7ef1d647bf1a59ee8e47a1e40ffc029cfb36585e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10255 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 diff --git a/assets/icons/drizzle.png b/assets/icons/drizzle.png deleted file mode 100644 index 3db9a5902f5e4e72699e22678d5bf847e0eab18c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14833 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 N(^S<}X;iX{{U1gx+X4Up diff --git a/assets/icons/fog.png b/assets/icons/fog.png deleted file mode 100644 index a827f4d29630fb57704dfac12abad2c1f56a1661..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16999 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 diff --git a/assets/icons/haze.png b/assets/icons/haze.png deleted file mode 100644 index 44fca8024cdbc26dfcfbec54e9f18ed6acc15f13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18316 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 DOFcN4 diff --git a/assets/icons/heavy_snow.png b/assets/icons/heavy_snow.png deleted file mode 100644 index 94caf1d80e067c2f2525399e02c99eda7f83a389..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14438 zcmb_@?ogcK?i4Q+DBj}kE~U6r+@ZJ?D-viaR;G>V#Ut$ z{?3Q<51bFVlIzK4cXoEUOdNgZ)_y{3A*a#E+thJO@_@;w|%B2h&)_rmk1?;BlMo8F&$n z&jt_N{urkn!Blrc#EXwrz-oFW2 zA;QnWH&Sj?$c6h4)*~WH;QX=A@P3ee>DA%T4}2uC8pTScy$QBIoDDRT7mf$n1MT={ zJ+t_xdlk7H?poH47sFVUK?3JOsIxJ>HeCOE=6A1Hq`)XENvo_DmqEB3a%R@bg~fm> zhfzAimZ}ovAoQMHfXRhS8}ad8DiMMtKm@tK&I zu<`H&1q9?6Q!zZ)xW-FMOC!$DJvcZxs_W{?Yid5!)NnASzV}6cT*L{2-ULk3P@QXk zVhdA4V8JhCG%E{!w`+!mN(ToA|GmBz1STCBQTZ;1ChPAnW?*12J3FiM>Xo{tCQgW(>Ewq%L*Z(Ht3bkbVBz9LdmQdP&l zut>&Rsv8@t`uYkniCApjXg7tUhxtN=Aw<(DFF$C4XCdn-hG)Jaubk7;`)X_B*Vfh| z{Ku=}@gtU&OmlN{9h{srj3^f2z14pVw2L8>En58SVN)n{kg@x<#nn|!Wo7i$)m265 zg93cH>FH@1Pfx+i%gX~NBBk)g5+~FcNC`PHoMZMy|LBxvSy`Evm)G>n3;`v|YhyNE zUi-~&aT>WoaV-Mt|Jtx@>5R#GY+{PpZJ>NOH#lxFMR{oG=wd-Pe8WjJoWDDIdE_tv ziE;#NVSqM6Ttm_PP&i~p@%3N^;1$#$YP!4ozP=Yr%gYA`{L8amz^?5NXFtu(&E0l! zhcD#@3rOfu2vkfH!}SmgaK~;D;EX(x2wA~1l+uQVq=R2oFJHYn+G`JnQ-#~NGG#KD z!&JdRl$R_s;`3D0)Z6fI6fa+2dxL7d3P70@f_6IQ=JkQ`iKaL~jDdO-_j(wxVglpj zv4$;GN!qI3-hwja=DwDE< zt1I5h^%_Epna~Q5SmUFB;`NOisvnh`w$C#`KLR@_5(n`hj)RVdw%BTqhk}A)LOP02 zQdESt+D)8Wv)vOQla5twkcL0`pJU ztVAqOH-f|WQ**h@72DG#@@*X*c^x5OKL2wYyUF}d)>JAW*MUW-hng`l96kKinM${q zq~wnV^Dq0Sr&EdgF*4N+4ZuJ#eZv5j*J;(p5xn*m94Jxp;2p7t}_2*FNk6H?FJA2a;8xqoCxF_ti+CiSkKp)2#JV%d7cV?tFbwgFj@&Qey;}J*N=DirCFR24<#X_zGr@WN^5J!>qiL@oMMDkY#48_ zka`Gq>Won!{!d9i^^9&?V??Pi4{i>{ul|fzwG>0zoRo8zMHqwcmp;+4SEz2;Vq_>V zZjcBv>gZOX;RqOjiqP!D%_aSi#i|HLjC>$u^9I7P5m>+Q}&OYcU+X_wWpT1k-1=FsU6=Ww;r za1?ZM3JTTMcagHmsi_2w^+5cp2PUUi^~IWw=2#AfJv=-(t#;4#Jm82~&y*^<_(KDA zr)timv}MIP!+1CNZqrq1er$_ur%44~bq;0CT5;frZTdoW@VpTCTcI~dtEx+pWW zNM5@iIRmqwUKa2ShpWQRR#f%LZ_L5>__3pO$-_WEnKEOHWWWI;>}tf1(rWt!H^LBN z878D%RXjQ_H6N~YOpn!ayU}guco;h%pe3>lbn&WCQq-j_Ny{efBWkvbyT3>E&g0S6A02LJDk(&1Q~7P{*!L zz7Fu4wF9pK=3Blfl4Sb}=k0bLJBPD>gfBq)Ro#4|q7GM&G1EVnmydiHb>i50(fl~W z@WjnUgKpg5rR3NHn`a4+o(%mdEjPIw3&3S5Q;IY0JB&G)Bp!59! zC4{aO$h*raazK%2VuFZ+&kunVh_cP3(|nIc62g&()B^v z;?Lb?ve4vZH_tRAD&f3JX|4}OV$b>RLgkz3qly8{*V2;F?4tSt_g-Qe=PydI_0u0n zK=>ax7W~5cNjhKiW2>efm`l@}pEfyfn=U4zqNOFRyIcJ5@UXh32EdFE2E9VB|g*fC!3mCA&Kg$r~3(z^b0 zawqm9_9O44!|>ktQ4VQR-9Yu)9w7iCU^Xxo%{&Sp82WQ|RzY4qa+2yrHgniIiZ57N z-uaoFB5~%U#7>8>q}lW`l{~>qb8}4qjcICXDloFw&c}vhAeWl8>D+jc=7{DX*z-a* zTwEDT;xL9F08(5Ql4{vuz0KcyL~N54`hK#OFwlL!N#*!_#Nbcfd#-ijXdGR zrKNo0t5poiq?Y(Oa3Y`&A_E=fU%}t~+3w&<2v0b#&N4EeNKp)2@vRPoeOn2j=3iP8 z++}e^36SH{Q+o%8_a!9^fRT%BB?#ub9DEZK^m*Qd@!XXZ!l_g8?SMxnU*dT{cCl704G%>g;FcMU17fqI{rUy}7m1q3Dyewd|INhFnAufLCrN=i^aR;`% zSlo;1tkzf}D;2;p59^=a6x3agpaVT&ZgXAtrRce!>=p%C0V4E2{Bi9{`)VmFD=&{y zRp3Lpv$NB8LPbeg+S>YGn(nv{Wi{^hVh4ccC!RlOyEl~gLqZ@|v^AJnR6n;onHv!j zXO>;gFs}4UvH&To9AZQ)U^A zesm|C@ytYFjU_7=jVQRbZ1J3=Z?!#PN?>viRd4U->RDVfh4(;Kyt?u!^xvhxr4~g5 zp0nP$(eJd-Yx@SUb{P;;o*y)DI z_yNq*7kuZp`_W$14{511^=Z6!E#k%=^)sU=jUSmBzaKxQAAW^Q%jU7An70#P4a>$^ zLp}Z%IRId+D$!OO-S`^ofA!m5%wt=H9_?+my<}d+ppwq_zF*-~;Kqu0Xb|j%`%qLs zhl?7Uco!9(q6sJgihNl{q6&h((l&T`d1xx&$w21D5h*>2DA`_`f_>;|7_W8&y>xA zeDB`?a#rc<>o+;fFjj4K5MkrsoZVkc*?*=E9w|KYzF(z-C;n!OE%A&XpLK5}YT+H$ zLDe@jd`oc$fUCt8TlM+$89yghy}~5hkHKuprMz3TOw*{63LsSt^>&_ahK`KP%x230 zNa;+*Csy#~&))z(4!k9@}j?dWgO9`SapQ%Fg1)p5!|*s_);q!)WrzN;6k zgqQ#@&ANcJL6Hg4;C#GeZ%09*&x8(Y_8?%Oi7f!08|EK@>|YrAc-vE6O!cT_3=+6Wg=X7Wzz0Ah4|G~ImacI!-Zx!qZPJW&M0tniGF9i;PpU;z|p zwp54u;!lS)7P__a`(IoXu&~3!w|0|WS0<__w-?WE2QDe_%BYUPh&PD$>UqfTgfg&vc1LO4{Ri|#m!^MrMnT#42 zEPUFD6Dg8`qKlo03DwZNk_oKAN>%wr4#DZm5q8eCeonjG{vTE+m%ImgLlC7Py~(%~ z0`!J~-@4VbnE@*#SlJhf1*kY^DAmWk>8#p5J$r!Y$ot%r+g+aF6>A8H_d#JUY3c!5>=^W)TUU0(-zk#$Zcsu zEr$KDlc*D+F)MV&JRT`wlWiiqsT;r4M&RFM-&?5-LmJC*(Bz$+xxKyF1;+)&#nl1> zMgKU?%_VI-T3vzNwhS$6zkYsJEe@>$G9mkvT>^y9Z{zAp+G}6OA${D?P@MEcEJa-m zVuN~<0L+`lcxR*smdra$Qel464n|Y1sja1{{ri3EY?|UREh9Vo3k{gmL#(a{kl2!f zBMYI(OaiCN4-l#aMG{R+Oe8Jf(!HS06?{rR^Q(Ny=M-y^fn2vf`4-(rmP7pD2T4Hb zj%_PI%p`}wqLGtwZrWmIWDE@T*7J(}NVh>P97MtAevg+1v&6$?Pw~)CUe&P_5)u;S zDU%Qvm-}*!zF;qoE14~?+cLmb)8xQ0rh71~&G+a)Uol_(=@b8`EOr&2`=-M1J1fj9 z)oA=dXDI%Q*yz8VSbOD_3yDv|Hy;Z;PMM~=w}>eXKqCJ`0&R(pP1+7=3IE& zyKe&Q-kE!J8DVPZdK!-$J3t# zUxV+_Vwq92mezD~MKu}OpP8GRi)DSM15R5jo0)^ew;3sz|25a5;J)Y#23JxfE0ELF zOdQ3t6b(;@0M)U*mzU7+&wZjeg%!hA^brgG6em86`^k-^Tee69`{O{r>YORY#%C{q z42;ao%%oJW-rfzZ@|Q+Nds(m*#};CNWYPN`NaSnv@~Zb+ zXV?-i?w|?j5Rie(Juwu?g*$+sn3z~;{C+?eya+H={Vx^XJ`%`v?r>0ld&a8-ZiR~O zyZxC<5m#`NubBrNXd>(l8$tex17P5C=DOVt4U-c|1_|lXalbea*edlP7x%+YpV;fq ztz#HvF*eAlh57JL*i4h{uipV~fam0O<4?rLp9%59j~&DSxU27+O;PN;yuK@FG3@K> zqkddZ%3;R1L!-~N#2_G2iHY5e*Wtjb&-cERbh^it;C+Sw?335H+e5b5SQ`2YF`N;= z!nRcsD{?Y8Ly371a$4MX&$*}UuWEtiw2#s9+gi*1TZ}o<+uOSVFQUZHed%d<%YF0A z?cX$zE;=b1(cLGjUvVvpvSNNbZ7=CxIEXNTX0T|D@293_q;8kMx!)3G>U|-08^fF4 zuLQk_kZ(uC5wTKQTVigOg9a(@c%zU3CJ*)vHlu=Cb5Tbtc4tQfDbf+lZ=a)c*Z|237ocQZYU zo`EjbzXl^G0QgRrzamuYO$<*I^+Pi>GNKwTCLDAujh&!hnVv>uUAqz+aMWhFjU9*- zUu3tsyJzOV2o5kMq=4a7RfH@OhYbt*^Wsu8#gkW&pU|%MuiUwfWa$|g?Bvj`>6nSK zgUCdd^98L2Q9GF1F%b`9#H?JR>|w8g>J)wDkC*%R1d3gSVpO-5t5{noJ)oVtMrhKG zNTX;!fbih2%G?VnmTyn>DkK8sQ0aN=zgy?Aqa4~?5U>-(b#XK5}u%{ z;F)=^IuVN@u^D=RL4zggj^J~-!00U)Hsvt1B>o7AFnLKJZ>c{J3zK%4sjGuQW=CEn zEiFICvBq_Z6A}_c#Zh+D!5RhPbG1G@%bw5FRZR9h{zQ9`z{}u8`8-;{7yN;BC2pyD z;!9vN$Y&hpT(C=!g;|)S~ziYRezCA-ey9o;JOjYih>wVSuge^mC1m9dK9zNAP;< zL0awCfxVHB21_5Kp$Ywm&`!4%e$f{DSA9?AZBPPr(TW zAS^jBHQbg{$I$TmN|&c*oeaT78?3s%exjyDdnrru`wd@3`r&vYCE`u&yHLv?_0nv$ z6CLhiB)|~c-5(#pIJP4qF3Vv~S;=_-#$4do;{PB$)z4!D(R%IAdI&{xZ0{u}vp51Q zC2uK0aqw(wnC1c8lF8Nn>C-4DqK@t}&2zT3U8E=GO7^{S3d|D2j|lhEH`(7P3AJt; z=_<^kA(FN=Dm67VkZbU#PoJy+Cd@^X`OsK=g+$GB*en0~DHP(v@Jt1^VM^U^m`Jy9sxiI zN{5E5l?`KmoLOD{V~ktZ)g_if4IZ^0`nrFOp#~-=CK09Di4|q1)Lr|J&p#fZ5Vwn#3*V@{NpEFQY^tJn|D%0UzyT=7gKb5Y!JL+Htt?c}> zfBC>ic63Tk8%+*`EN`yf7<_;|J>4e<@OC8)e%8vxyYifVf^6)$XFrtPv>q;rkuo({ zUAgW>D1C_e;*yeZC>AOCS4;3_J1j@YG0kW&i74HI$?f$PV;*-hN5$lP2?Qr_22`O&b1-oR_|ZuEuO*>WKaL!grIJ9|?g2{{V$wdJyL z_aGU=5+EVW#QEJE68J)Rb-_JNpDm zYSGG~zu_s4RE9hH+m@X(yj_sPNIzOlhf7-a8-4w6(>9}o+UP{`kN9$;hD2HevX;Vj z=U@1VZk|u3)9K?VSVZd#wn50J%&WKLwEwHwI$VoPaH3EF#ff`!ysXliOFSi)RlJnS zG#`cK{)W4TLwTG-(0jnyh%fq42H-HYx5(#0hU`F7<9PK;c41-RvAV6>e=cFtYFE*E zEsbjyW4cE9`o{s>RfiMAS_q!pD>n|M8LR_=CgmLalnTBBNbY#Oe?6agJLkWa$YlP< zxE(tEpeJu~6oem-jF?=P)RTm+)phJo3ZS0@nuS@?Hy7X{?>$td z#BSbkAnC`fh7uX{KQ+3RZp;}XdPr{25F}*1G=4N&9(VR~B^)4~z%p+*)tMU;?bQB0 zn{qPk&i+hUl4Cv22Y_M+h@2cr|CaUKP(p9JV3N0lRi&hzWW9BLc{=KwZ!}QaLC?>; z`(lM>FG85B2e3@Q%wj~w@z-hRii_1W20^g3Rh|7CObD zi$DTp3hn;)>K?0J>@0xJn5w^}_B}*ZWB}d8UvqN?gk$uCanp;7BT<+{Ku1zrMDW5% z?ad_!M7H!qf$&Yk4?b;R}Oh*eEe)pkQpt{Ho^~DxYA_6irzkYHX9z9mBPom~@ zwO8W@^x21Ep-{knCt$>yst1t1^8dHb3v{i~IV}4C_*e{dzhYuyG+3liMb3s_#+vS0 z9Bmc8*6)MU5ri2?VsXjVYq`S3{FOOEpgkyV4Sj^5p&C${f^HYuT4X@yPdh)qoRbq5 zfWJLBI^xWklNF+@0KDcucJt^ca^&-3teX5~kxe7VR0aI0I0*631pWNshMIpEwzv(%TH>b!A;vR+FOqp$5?R3tGg>>Yt+&f|8ON78Y~>MT?D%%_k(3;X5Ti z-lCPU*HB+yQCZ0{vRxCaLy_M{p&v`DUj{S3N6($K*lN;EjZQ9x%{@|N3wVQdlElCC zyB&M-&~|a_rN{(#6e)<^Zb#|qfmC^9>S2>C2)BIz!2pe83R>F#c9WW#O7w)oVLH>o zH8wsDlpj^4rJLWX01(yanS?8hL>)5?Rx|lT-Hc(o60C_9j15jM3&|!6tG6!l%32@_ zi?;UQhM0yKm8K34MoXhSY0$RwRaAr0^h*<>pD=6;#|%-H+vA3}SYN~`K-hOMhf?l+ z1#~O%A>%FY6&MxDW{8TY4Yb8SEE%n1V{gBa!Fe5RO3=dte<2axTg}$p*R0KZh_e!Q zZlDrEsbhFYUz90bs^%j_Y+2ODW((yj^soLEDT4CyoJ+lLU$%G0m1X6mgIB(wzygc- zEybr{9i>By-BzgN8hA)*WGK7<-hTff-J4R!wuMKb9i@ve^hql&tAhe7emFfgU{A`JoJN{4 zBox1)D^v@+F7*xP z1S}LBQ76~tum+g&WImeNmgv`=iLzF{=)s406X=(Xwq5r_yBearJtjg{v+?6q6wv+Z$HBXi$GGj z5@)iSx)}3bdtW=-84m7>6^kb>cQE?v8#|@)fx>Li(rhtaYf`>IAv`f#9bEpEGGr+l zUB?!NzEn*cL8oR+?Z{o~Gj>4fFR-TUC%c+Y>Ytb!&4p0Zoyo;94hx{41;bM^0H6;^$B-Xj$EjTJ{ zdBJ77hh9A1*^V%6Tqy7K+vcW*6G1)aO&{@n`V|hrTIPu{ntU4E5Y(Kw5`p*{?v+Jx zx7Bo#<}}fA@6{w9fyxWO(nYBTVt;me6Z;v%9_cM(+YY{! z!bY)+72#B26ff@bDZ*bd2_Exc{N8>k6mkp>CV4Q_h$Xww|tb^Ag0m#ID^7Tst5 z`ykMemL>w>jQg2TpA|96#}Vft9>;9yNF~KTS|*3g(>2aJP%kAP@q@Y%8LKZZhDn#L zheb7JWS)6`Pc`hRF(<_TIK^`x{5>7Y3A_+atR!mX4;jIKw|s+*RJYV49sZOaL09j*_2p+O!#BtmNe}C|u%&?3>(a_n& zq^2eCV;^u4{R2qA0;BWMfkyg^wNz#oIq$knISAFP?)OR7JZYlTXBOQXKECRiwm7l2 z8(R2JY_awh(k)N`tB?s^)EH}3$C&|mVb5w`WNx;lo!AiK$QkyfuoA6}WkE-%)Vr`@ zB9prf>!#VzIv(r(ig#K|PGHV;{Y6gY42#gHUIa^f9G?1(%o-}bSwLG7@1FBLb!t1L zn%0UT!1a@bJ(G_GETm>3rNZ&=YQt||!=K(mg=M5URs4?wP6^Ueq}=AwxXYB>75 z^O)mRRet&vA*)rhj6*&>Y=G`3&DX@G0NSG?J7TsAhZ@_NPy%_Uij^-Pb$*9`?ee>|L$pjX{%B-y_wrlZbhMBpFsf&Do6KSuGuXkSm z6da@6@POX^GllhUc|C|L4^wZiw(WQB3Asy;)r+sq!dIXRsa)aPKVL4XlZKWSvGR9k zyw;Y44I5lAZ$x#@lLIC`OodnU=Y^t^-gc|H@nSyKUUC(BIeJ?=5nVuoG}P9@9}j&! zyrP~UYp3d!5Qbo;;%N;#h6AlYY*z}eww6N0Cw&Jihy%jr!@PHoR+~9@bB}of3sOl07KJPV>dceK&H^nqK zxqR;PHdvE_$9REM!)A@<=#v7H<}dNs$vkNx&YP7cKK+5q{l-OHQ{NEeGcf zZOnKh(3Inv9?vtnzY$-U^Gr=vCig-O1FttfqPA`5AO?iPD!>#^yZxopVBO#Jfcw@hW(QFcUeNE8gDd zyjAvJUaV09!jyT($M|`dO_%XXoB*ht(V{B z7>SIOeP9g>uJc6zr6}4AQ1>2A|)IuSm$l$q0ol-hXb! zT4aPu$q~v5q>Dd-^On4laG6&!CWQ9=6^5NE2oG9Jn> zU~6qs8+b7N!%SAUJc2`!_*}_JFdhHC!|tO0wP$-_>TsOMXFkhiGtJy8OgJ?nQO@J} zw74Ptkgrr2KP`d8?c3bzn5^codNE2(5nDpd!*7X}SZzP+jJTH&67mMsqbgwifvK6c z7WILJdFLNonU{dAF%O7OOPJuh8L@0VGw~#)V!nTeA8ZS6@XLR9Za~GKm%&|(OEab1 zvZaq^S!T~ksQZ*;YsJC@MOKocmCv?k7^w}Qyc2PE6t`Xla)~Mi9CVe?QfkD7>ZJl^# z3DE<%-Q3J1N6-*tR5%e5)!3xUfUr;^IyPPYo_+coZt^M3=bJF!^Y&EVA>p&Aup+Qv za6)qthtzn3h3TssSB5UqztklHHd4ZSZ4D!9KSi*=-97JDKRBX5#sXKfUX^yrHKBaM z!Vk>n81tt*g;TTs3p1BtK_Q>?e8sViY1VaLs^Z(h8GhF0v)F zVEZl=$^j(WAqkS@@cFD`ws2#rv_TbsTk~A`ldnpYo}e?tO*PH{!ba@ z2#MP4i#2K-R=_&B<<1?wHm`e|D=eL7ceg@_st(;2e$DD9H}Qdqph7UL<@N)Dh_9b< zdQzqsnVK~vV`fL1oLV(lk;8btPnqm9Yl^osC$n#y^u)r&bl^5k_*~jI6E$HJ*w&%k>Zr$zy^w^ny&tch;3ne zV!PaxThg+%dWJlN1L?Cmj2Ct36YZ41AhdqZ=DBVat8`%QXc?244d!Ha#4{Dr62_G@ zrApdjnngw{qO{l{o=3uMy{9T|0SU@I>2id4F~fvQ5=i=e)|o-aCbw*}3zKVBMA17T znwE`YA5w_>8d&cqy)Okfz}e~w}kcs?xbzTptDH>~yn z>ThPqy^)@Aq2VO&<3SH;$&ea2<<<% ze`yNEg&FsDNBi1eOz2~LTk@kzTL-;t5&a>__1NaaWMu1%x~zQVFe*JPd|t5V8L)S~ z)rDE-?YweqU(4}l)AS$f=ol%&X5M8x5#n-Aak;A?65*PV;GsU9^dkEEze|PW`7>$w zorfrJvto5AjizzLn5utBd$HbziS*RjTr1D;iOM7jk%!>){kmTGZX@9h45F4s1WmD7 zwc}wNkSIsM{$2%yD!1suPB@a??1g_OkkK>FfA?j`@v`YdkDaP}yYW)?I`EWbvgw)g zjYLTrJW}O^E&e=|RhsUoP1lfsM` zOg>n?-~$^Z1%h^LJG2K48Gg%9;AOwrF%)^@yn;HQEhDWm`o*wuIte;sXHI2t{*l^C zQn-oC`-4?ke!N}!ZfZx^7o*Q^&bcj7g*|K_dAmC2tvN_YY-ng?F~#6+eld-wi))!v z#P&?{^g&QdEJ4=Zor72&IaJ3ofhOCTLCWahj~+5m{al1uxdNV+#txUp7#MQA>iSra zPtrDi9-Q|vv*}haw`ARpSM7) zR~PXhh|mT%{++oK*hRhoz~7d@)ykJRk;OD+m9kFt7;MJQ(nVJ391{@vC-EE2v7 zdESVQ4xT;x7cm6ymi>~$o|FU?NJYP4c(%Gz2TrkM8K=e4+rPLOjz+W?jDHqDC6Vkp zpA|%vF^R$}mcG4SO7jfX3IT~_-ET8auia@?m`T?*)6H|)s}F9HV9-t|J+YpZ7a)%H zKHggr%M9Sh6Hs6Y|125Tay!c;U zsJQLnxf9B@mAmzkz#joC#b^^SF-H6L=UmMN^yjx=mP@3;-*k7oUbpX=|^tix^eRtOt8fHg_{e+2Emb>!} zWRvRUotWZL>lEB7qoU#Z`UVbI`-&bmb#k+U5Lyb(nzyt;Klm+6=%+dJXBd3Wbm$4l zw%A&YC2|qMJ%wbW2LnlU!;9@@)fX&wSilBBC+{TAlrA=te~&Qu-F~E2ZZau5=+Vb~ zjk7Vt76!4@53sKVH7_s-?n==(^Z34RY{|5Kue6Y)aD1nJV*#*kH9GRVD_QSMzFFZ~PHMwM;%^^$6 zR~+KOz)G>2l+I&{P*8 zM#%dK^Qn5vtx*z}`9{`&wwQ}1KXfR{Y3>hvdKNkvFd_F=!I`db`s>O2?_?w^_!M#Ha<}+& zqt)p0ulbeWknInGqKv3UDDwWqTRBiy+6z4)Vm3hSY_(Yz!_7-q0jUuK0`yKiy)}xQ z%3%!O0D0kcE*pDt2BworHBPME<=dZK3}UdOBXvR0$(kKW%jG&$pB>9i)_M$kfOWDK zBOgye0R)E3=MTlSV2p=LjA*qlcSgOs3ly{e!8D`8oMR1VwEm+sNrV(b-9w))P&fxg zBzFKn8}vXS7o!VO99v4vx5r%L-cb81086fVsS?7$<-$B#A*tr)a-X0Q^S~q^hW;&>&|S G@qYka=M0ws diff --git a/assets/icons/lightning.png b/assets/icons/lightning.png deleted file mode 100644 index f3302fd91e5b3cedd297af1164fa239965e6628a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14039 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 diff --git a/assets/icons/moon.png b/assets/icons/moon.png deleted file mode 100644 index aa7c41f0a437d4ac242da8608eb4cc0b2f2b5de7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9335 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 I_AK)M0lcO4)6co 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 diff --git a/assets/icons/sleet.png b/assets/icons/sleet.png deleted file mode 100644 index 9b11aebbb725459b5eff812edc4e8a32f8acfa35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15791 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 diff --git a/assets/icons/sun.png b/assets/icons/sun.png deleted file mode 100644 index ed098a7f34b5e88333144ecbf95e1394c0b6cee2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6810 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 diff --git a/lib/decoders/decode_mn.dart b/lib/decoders/decode_mn.dart index 78e165b..3c7e713 100644 --- a/lib/decoders/decode_mn.dart +++ b/lib/decoders/decode_mn.dart @@ -18,6 +18,8 @@ along with this program. If not, see . import 'dart:math'; import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'package:overmorrow/Icons/overmorrow_weather_icons_icons.dart'; import 'package:overmorrow/decoders/decode_wapi.dart'; @@ -48,8 +50,8 @@ List metNContentColorCorrection(String text) { return textFontColor[text] ?? [WHITE, WHITE]; } -String metNIconCorrection(String text) { - return textIconMap[text] ?? 'sun.png'; +IconData metNIconCorrection(String text) { + return textMaterialIcon[text] ?? OvermorrowWeatherIcons.sun2; } String metNTimeCorrect(String date) { @@ -123,7 +125,7 @@ class MetNCurrent { class MetNDay { final String text; - final String icon; + final IconData icon; final String name; final String minmaxtemp; final List hourly; @@ -232,7 +234,7 @@ class MetNDay { class MetNHour { final int temp; - final String icon; + final IconData icon; final String time; final String text; final double precip; diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index f19b7ad..7b69ef9 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -21,12 +21,14 @@ import 'dart:convert'; import 'dart:math'; import 'dart:ui'; +import '../Icons/overmorrow_weather_icons_icons.dart'; import '../api_key.dart'; import '../caching.dart'; import '../settings_page.dart'; import '../ui_helper.dart'; import '../weather_refact.dart' as weather_refactor; +import '../weather_refact.dart'; import 'decode_OM.dart'; import 'extra_info.dart'; @@ -156,10 +158,10 @@ double temp_multiply_for_scale(int temp, String unit) { } } -String iconCorrection(name, isday) { +IconData iconCorrection(name, isday) { String text = textCorrection(name, isday); - String p = weather_refactor.textIconMap[text] ?? 'clear_night.png'; - return p; + //String p = weather_refactor.textIconMap[text] ?? 'clear_night.png'; + return textMaterialIcon[text] ?? OvermorrowWeatherIcons.sun2; } String getTime(date, bool ampm) { @@ -340,7 +342,7 @@ class WapiCurrent { class WapiDay { final String text; - final String icon; + final IconData icon; final String name; final String minmaxtemp; final List hourly; @@ -412,7 +414,7 @@ class WapiDay { class WapiHour { final int temp; - final String icon; + final IconData icon; final String time; final String text; final double precip; diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 40e9a49..d5ada1a 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -22,23 +22,6 @@ import 'package:flutter/material.dart'; import 'ui_helper.dart'; -Map textIconMap = { - 'Clear Night': 'moon.png', - 'Partly Cloudy': 'partly_cloudy.png', - 'Clear Sky': 'sun.png', - 'Overcast': 'cloudy.png', - 'Haze': 'haze.png', - 'Rain': 'rainy.png', - 'Sleet': 'sleet.png', - 'Drizzle': 'drizzle.png', - 'Thunderstorm': 'lightning.png', - 'Heavy Snow': 'heavy_snow.png', - 'Fog': 'fog.png', - 'Snow': 'snow.png', - 'Heavy Rain': 'heavy_rain.png', - 'Cloudy Night' : 'cloudy_night.png', -}; - Map textMaterialIcon = { 'Clear Night': OvermorrowWeatherIcons.moon2, 'Partly Cloudy': OvermorrowWeatherIcons.partly_cloudy2, @@ -61,7 +44,7 @@ Map textIconSizeNormalize = { 'Partly Cloudy': 0.8, 'Clear Sky': 0.8, 'Overcast': 0.74, - 'Haze': 1, + 'Haze': 0.8, 'Rain': 0.95, 'Sleet': 1, 'Drizzle': 1, diff --git a/pubspec.lock b/pubspec.lock index ac161d0..e2aad3b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -37,26 +37,26 @@ packages: dependency: "direct main" description: name: cached_network_image - sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + sha256: "4a5d8d2c728b0f3d0245f69f921d7be90cae4c2fd5288f773088672c0893f819" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.4.0" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + sha256: ff0c949e323d2a1b52be73acce5b4a7b04063e61414c8ca542dbba47281630a7 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: "205d6a9f1862de34b93184f22b9d2d94586b2f05c581d546695e3d8f6a805cd7" + sha256: "6322dde7a5ad92202e64df659241104a43db20ed594c41ca18de1014598d7996" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" characters: dependency: transitive description: @@ -154,10 +154,10 @@ packages: dependency: "direct main" description: name: flutter_cache_manager - sha256: ceff65d74d907b1b772e22cf04daad60fb472461638977d9fae8b00a63e01e3d + sha256: a77f77806a790eb9ba0118a5a3a936e81c4fea2b61533033b2b0c3d50bbde5ea url: "https://pub.dev" source: hosted - version: "3.3.3" + version: "3.4.0" flutter_launcher_icons: dependency: "direct main" description: @@ -436,10 +436,10 @@ packages: dependency: transitive description: name: octo_image - sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.0" palette_generator: dependency: "direct main" description: @@ -556,10 +556,10 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: c3f888ba2d659f3e75f4686112cc1e71f46177f74452d40d8307edc332296ead + sha256: c272f9cabca5a81adc9b0894381e9c1def363e980f960fa903c604c471b22f68 url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.1" shared_preferences_android: dependency: transitive description: @@ -596,10 +596,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "3a293170d4d9403c3254ee05b84e62e8a9b3c5808ebd17de6a33fe9ea6457936" + sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" shared_preferences_windows: dependency: transitive description: @@ -769,10 +769,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" + sha256: a36e2d7981122fa185006b216eb6b5b97ede3f9a54b7a511bc966971ab98d049 url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" url_launcher_windows: dependency: transitive description: @@ -809,10 +809,10 @@ packages: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "1.0.0" wkt_parser: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 592ed80..398fbce 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -104,7 +104,6 @@ flutter: assets: - assets/backdrops/ - - assets/icons/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware From f59ca5b2651474fd676c3e5c33d4a0938514afda Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sun, 4 Aug 2024 20:32:22 +0200 Subject: [PATCH 060/129] finally chips don't get reset when scrolling --- lib/decoders/extra_info.dart | 11 +++++++---- lib/main_screens.dart | 14 +++----------- lib/new_displays.dart | 4 ++-- lib/new_forecast.dart | 36 ++++++++++++++++++++++-------------- lib/weather_refact.dart | 6 +++--- 5 files changed, 37 insertions(+), 34 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 768cf8e..186b590 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -74,7 +74,7 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double for (int i = 0; i < unsplash_body.length; i++) { double lat_dif = pow((lat - (unsplash_body[i]["location"]["position"]["latitude"] ?? 9999)).abs(), 2) * 1.0; double lng_dif = pow((lng - (unsplash_body[i]["location"]["position"]["longitude"] ?? 9999)).abs(), 2) * 1.0; - double unaccuracy = min(lat_dif + lng_dif, 100) * 10; + double unaccuracy = min(lat_dif + lng_dif, 100) * 20; if (unsplash_body[i]["location"]["position"]["city"] == real_loc) { unaccuracy -= 1000; @@ -97,7 +97,7 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double for (int x = 0; x < textFilter.length; x ++) { if (desc.contains(keys1[x])) { - print(("punished", keys1[x])); + print(("punished", keys1[x], -textFilter[keys1[x]]!)); unaccuracy -= textFilter[keys1[x]]!; // i had to reverse it } } @@ -106,8 +106,11 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double unaccuracy -= 3000; } - unaccuracy -= unsplash_body[i]["likes"] * 0.01 ?? 0; - unaccuracy -= unsplash_body[i]["downloads"] * 0.005 ?? 0; + double ratings = unsplash_body[i]["likes"] * 0.02 ?? 0; + ratings += unsplash_body[i]["downloads"] * 0.01 ?? 0; + print(("ratings", ratings)); + + unaccuracy -= min(ratings, 4000); print((i, unaccuracy.toStringAsFixed(6), (desc1 ?? "null").trim() + ", " + desc2, unsplash_body[i]["likes"], unsplash_body[i]["downloads"])); if (unaccuracy < best) { diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 38ee849..ba896e7 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -46,14 +46,6 @@ class _NewMainState extends State { final updateLocation; final context; - List chips = [0, 0, 0]; - - void updateChip(int index, int to) { - setState(() { - chips[index] = to; - }); - } - _NewMainState(this.data, this.updateLocation, this.context); @override @@ -98,7 +90,7 @@ class _NewMainState extends State { Padding( padding: const EdgeInsets.only(left: 0, bottom: 2), child: comfortatext( - "${data.current.temp}°", 68, data.settings, + "${data.current.temp}°", 69, data.settings, color: data.colorpop, weight: FontWeight.w300), ), Padding( @@ -107,7 +99,7 @@ class _NewMainState extends State { data.current.text, 32, data.settings, weight: data.settings["Color mode"] == "dark" ? FontWeight.w600 - : FontWeight.w400, + : FontWeight.w500, color: data.desc_color), ) ], @@ -150,7 +142,7 @@ class _NewMainState extends State { NewAirQuality(data), RadarSmall( data: data, key: Key("${data.place}, ${data.current.backcolor}")), - buildNewDays(data, chips, updateChip), + buildNewDays(data), buildNewGlanceDay(data), Padding( diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 985dfc4..667d81d 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -182,7 +182,7 @@ class _NewSunriseSunsetState extends State Padding( padding: EdgeInsets.only( left: min( - max((progress * (widget.size.width - 50)) - textWidth / 2 + 2, 0), + max((progress * (widget.size.width - 53)) - textWidth / 2 + 2, 0), widget.size.width - 55 - textWidth)), child: Align( alignment: Alignment.centerLeft, @@ -194,7 +194,7 @@ class _NewSunriseSunsetState extends State Padding( padding: EdgeInsets.only( top: 6, - left: min(max((progress * (widget.size.width - 50)), 2), + left: min(max((progress * (widget.size.width - 53)), 2), widget.size.width - 52)), child: Align( alignment: Alignment.centerLeft, diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 3d4d1f6..be25ca7 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -27,21 +27,16 @@ import 'ui_helper.dart'; class NewDay extends StatefulWidget { final data; final index; - final value; - final updateChip; - NewDay({Key? key, required this.data, required this.index, required this.value, - required this.updateChip}) : super(key: key); + NewDay({Key? key, required this.data, required this.index}) : super(key: key); @override - _NewDayState createState() => _NewDayState(data, value, updateChip, index); + _NewDayState createState() => _NewDayState(data); } -class _NewDayState extends State { +class _NewDayState extends State with AutomaticKeepAliveClientMixin { final data; - final _value; - final Function updateChip; - final myIndex; + int _value = 0; PageController _pageController = PageController(); @@ -53,10 +48,15 @@ class _NewDayState extends State { ); } - _NewDayState(this.data, this._value, this.updateChip, this.myIndex); + @override + bool get wantKeepAlive => true; + + _NewDayState(this.data); @override Widget build(BuildContext context) { + super.build(context); + print(("here", _value)); final day = data.days[widget.index]; return Padding( @@ -210,6 +210,7 @@ class _NewDayState extends State { children: List.generate( 4, (int index) { + print((_value, index)); return ChoiceChip( elevation: 0.0, @@ -226,10 +227,18 @@ class _NewDayState extends State { color: _value == index ? data.palette.onPrimaryFixed : data.palette.onSurface), selected: _value == index, onSelected: (bool selected) { - updateChip(myIndex, selected); + //setState(() { + // updateChip(index); + //}); + _value = index; + setState(() { + _onItemTapped(index); + }); + /* setState(() { _onItemTapped(index); }); + */ }, ); }, @@ -254,14 +263,13 @@ class _NewDayState extends State { } } -Widget buildNewDays(data, chips, updateChip) { +Widget buildNewDays(data) { return ListView.builder( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: 3, itemBuilder: (BuildContext context, int index) { - return NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.backcolor} $chips"), - value: chips[index], updateChip: updateChip,); + return NewDay(data: data, index: index); }, ); } diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index d5ada1a..65fd950 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -345,13 +345,13 @@ Map> textToUnsplashText = { //trying to assign values for words (for example sky will be rewarded) Map textFilter = { - 'sky' : 3300, - 'weather': 5000, + 'sky' : 2000, + 'weather': 2000, 'tree': 1000, 'plant': 1000, 'flower': 1000, 'cliff': 1000, - 'mountain': 10000, + 'mountain': 1000, 'ice': -10000, 'icy': -10000, 'bubble': -10000, From 8bea43a8ab8bea2126e9d64a80f652ce50929999 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 5 Aug 2024 15:50:46 +0200 Subject: [PATCH 061/129] started working on new daily --- lib/decoders/decode_OM.dart | 3 +- lib/new_forecast.dart | 130 +++++++++++++++++++++++++++++++++--- lib/weather_refact.dart | 1 - 3 files changed, 123 insertions(+), 11 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index c6948e2..c468fa8 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -124,7 +124,8 @@ String oMGetName(index, settings, item) { List z = x.split("-"); DateTime time = DateTime(int.parse(z[0]), int.parse(z[1]), int.parse(z[2])); const weeks = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; - return translation(weeks[time.weekday - 1], settings["Language"]); + String weekname = translation(weeks[time.weekday - 1], settings["Language"]); + return "$weekname, ${time.month}/${time.day}"; } String oMamPmTime(String time) { diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index be25ca7..fcb3eee 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -269,7 +269,7 @@ Widget buildNewDays(data) { shrinkWrap: true, itemCount: 3, itemBuilder: (BuildContext context, int index) { - return NewDay(data: data, index: index); + return NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.backcolor}"),); }, ); } @@ -632,11 +632,11 @@ Widget buildPrecip(List hours, data) => ListView( Widget buildNewGlanceDay(var data) => Padding( - padding: const EdgeInsets.only(left: 20, right: 20, bottom: 10), + padding: const EdgeInsets.only(left: 24, right: 24, bottom: 10), child: Column( children: [ Padding( - padding: const EdgeInsets.only(left: 5, top: 0), + padding: const EdgeInsets.only(left: 1, top: 0, bottom: 6), child: Align( alignment: Alignment.centerLeft, child: comfortatext( @@ -647,18 +647,130 @@ Widget buildNewGlanceDay(var data) => Padding( ), ListView.builder( shrinkWrap: true, - padding: const EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 5), + padding: const EdgeInsets.only(top: 5, bottom: 5, left: 0, right: 0), physics: const NeverScrollableScrollPhysics(), itemCount: data.days.length - 3, itemBuilder: (context, index) { final day = data.days[index + 3]; return Padding( padding: const EdgeInsets.only(top: 5, bottom: 5), - child: Column( - children: [ - - ] - ) + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: data.palette.surfaceContainerLow), + child: Column( + children: [ + Row( + children: [ + SizedBox( + width: 65, + height: 73, + child: Padding( + padding: const EdgeInsets.only(left: 18), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + comfortatext(day.name.split(", ")[0], 18, data.settings, color: data.palette.primary), + comfortatext(day.name.split(", ")[1], 14, data.settings, color: data.palette.primaryFixedDim), + ], + ), + ), + ), + SizedBox( + height: 30, + width: 40, + child: Icon( + day.icon, + color: data.palette.primary, + size: 31.0 * day.iconSize, + ), + ), + Padding( + padding: const EdgeInsets.only(left: 10, top: 4, bottom: 4), + child: Container( + height: 58, + width: 43, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(14), + color: data.palette.primaryFixedDim), + child: Row( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.arrow_drop_up, color: data.palette.primary, size: 14,), + Icon(Icons.arrow_drop_down, color: data.palette.primary, size: 14,), + ], + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + comfortatext(day.minmaxtemp.split("/")[1], 14, data.settings, color: data.palette.primary), + comfortatext(day.minmaxtemp.split("/")[0], 14, data.settings,color: data.palette.primary), + ], + ), + ), + ], + ), + ), + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.water_drop_outlined, + color: data.current.secondary, size: 18,), + Padding( + padding: const EdgeInsets.only(left: 2, right: 5), + child: comfortatext('${day.precip_prob}%', 17, data.settings, + color: data.current.secondary), + ), + Icon( + Icons.water_drop, color: data.current.secondary, size: 18,), + Padding( + padding: const EdgeInsets.only(left: 2, right: 2), + child: comfortatext(day.total_precip.toString() + + data.settings["Precipitation"], 17, data.settings, color: data.current.secondary), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + CupertinoIcons.wind, color: data.current.secondary, size: 18,), + Padding( + padding: const EdgeInsets.only(left: 2, right: 2), + child: comfortatext('${day.windspeed} ${data + .settings["Wind"]}', 17, data.settings, color: data.current.secondary), + ), + Padding( + padding: const EdgeInsets.only(left: 3, right: 3, bottom: 1), + child: RotationTransition( + turns: AlwaysStoppedAnimation(day.wind_dir / 360), + child: Icon(CupertinoIcons.arrow_up_circle_fill, + color: data.current.secondary, size: 16,) + ) + ), + ], + ) + ], + ), + ), + Padding( + padding: const EdgeInsets.only(right: 14), + child: Icon(Icons.arrow_forward_ios, color: data.palette.primaryFixedDim, size: 14,), + ), + ], + ), + ], + ), + ), ); } ), diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 65fd950..3065509 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -348,7 +348,6 @@ Map textFilter = { 'sky' : 2000, 'weather': 2000, 'tree': 1000, - 'plant': 1000, 'flower': 1000, 'cliff': 1000, 'mountain': 1000, From 8decbd13ea8c2fe6e95b962534c9b6d4e834f40b Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 5 Aug 2024 20:00:18 +0200 Subject: [PATCH 062/129] reversed direction of wind arrows --- lib/main_ui.dart | 2 +- lib/new_forecast.dart | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/main_ui.dart b/lib/main_ui.dart index cfa4951..ca5e75b 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -137,7 +137,7 @@ Widget Circles(double width, var data, double bottom, color, {align = Alignment. size: width, settings: data.settings, bottom: bottom, - dir: data.current.wind_dir, + dir: data.current.wind_dir + 180, ), ] ) diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index fcb3eee..6acfeac 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -174,7 +174,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { padding: const EdgeInsets.only(left: 5, right: 3), child: RotationTransition( turns: AlwaysStoppedAnimation(day.wind_dir / 360), - child: Icon(CupertinoIcons.arrow_up_circle, + child: Icon(CupertinoIcons.arrow_down_circle, color: data.palette.primaryFixedDim, size: 18,) ) ), @@ -370,7 +370,7 @@ class WindChartPainter extends CustomPainter { canvas.drawCircle(Offset(x, y), dotRadius, paint); textPainter.text = TextSpan( - text: String.fromCharCode(Icons.arrow_forward.codePoint), + text: String.fromCharCode(Icons.arrow_downward.codePoint), style: TextStyle( fontSize: dotRadius * 2, fontFamily: Icons.arrow_forward.fontFamily, @@ -753,7 +753,7 @@ Widget buildNewGlanceDay(var data) => Padding( padding: const EdgeInsets.only(left: 3, right: 3, bottom: 1), child: RotationTransition( turns: AlwaysStoppedAnimation(day.wind_dir / 360), - child: Icon(CupertinoIcons.arrow_up_circle_fill, + child: Icon(CupertinoIcons.arrow_down_circle, color: data.current.secondary, size: 16,) ) ), From 78c1061e6aad825d0d6ba7c06ddf85fd6eaa0d92 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 5 Aug 2024 20:31:38 +0200 Subject: [PATCH 063/129] landed on a daily view i like --- lib/new_displays.dart | 2 +- lib/new_forecast.dart | 78 +++++++++++++++++++++++++------------------ 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 667d81d..2c4f160 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -262,7 +262,7 @@ class _NewSunriseSunsetState extends State Widget NewAirQuality(var data) { return Padding( - padding: const EdgeInsets.only(left: 20, right: 20, bottom: 19, top: 26), + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 19, top: 23), child: Column( children: [ Padding( diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 6acfeac..f1b8a5a 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -653,17 +653,20 @@ Widget buildNewGlanceDay(var data) => Padding( itemBuilder: (context, index) { final day = data.days[index + 3]; return Padding( - padding: const EdgeInsets.only(top: 5, bottom: 5), + padding: const EdgeInsets.only(top: 3, bottom: 3), child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), + borderRadius: + index == 0 ? const BorderRadius.vertical(top: Radius.circular(18.0), bottom: Radius.circular(8)) + : index == data.days.length - 4 ? const BorderRadius.vertical(bottom: Radius.circular(18.0), top: Radius.circular(8)) + : BorderRadius.circular(8), color: data.palette.surfaceContainerLow), child: Column( children: [ Row( children: [ SizedBox( - width: 65, + width: 63, height: 73, child: Padding( padding: const EdgeInsets.only(left: 18), @@ -672,14 +675,14 @@ Widget buildNewGlanceDay(var data) => Padding( crossAxisAlignment: CrossAxisAlignment.start, children: [ comfortatext(day.name.split(", ")[0], 18, data.settings, color: data.palette.primary), - comfortatext(day.name.split(", ")[1], 14, data.settings, color: data.palette.primaryFixedDim), + comfortatext(day.name.split(", ")[1], 14, data.settings, color: data.palette.onSurface), ], ), ), ), SizedBox( height: 30, - width: 40, + width: 43, child: Icon( day.icon, color: data.palette.primary, @@ -692,23 +695,31 @@ Widget buildNewGlanceDay(var data) => Padding( height: 58, width: 43, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(14), - color: data.palette.primaryFixedDim), + borderRadius: BorderRadius.circular(13), + //border: Border.all(width: 1.5, color: data.palette.primaryFixedDim) + color: data.palette.primaryFixedDim + ), child: Row( children: [ Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.arrow_drop_up, color: data.palette.primary, size: 14,), - Icon(Icons.arrow_drop_down, color: data.palette.primary, size: 14,), + Padding( + padding: const EdgeInsets.only(bottom: 2), + child: Icon(Icons.keyboard_arrow_up, color: data.palette.shadow, size: 14,), + ), + Icon(Icons.keyboard_arrow_down, color: data.palette.shadow, size: 14,), ], ), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - comfortatext(day.minmaxtemp.split("/")[1], 14, data.settings, color: data.palette.primary), - comfortatext(day.minmaxtemp.split("/")[0], 14, data.settings,color: data.palette.primary), + Padding( + padding: const EdgeInsets.only(bottom: 2), + child: comfortatext(day.minmaxtemp.split("/")[1], 14, data.settings, color: data.palette.shadow), + ), + comfortatext(day.minmaxtemp.split("/")[0], 14, data.settings,color: data.palette.shadow), ], ), ), @@ -720,41 +731,44 @@ Widget buildNewGlanceDay(var data) => Padding( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.water_drop_outlined, - color: data.current.secondary, size: 18,), - Padding( - padding: const EdgeInsets.only(left: 2, right: 5), - child: comfortatext('${day.precip_prob}%', 17, data.settings, - color: data.current.secondary), - ), - Icon( - Icons.water_drop, color: data.current.secondary, size: 18,), - Padding( - padding: const EdgeInsets.only(left: 2, right: 2), - child: comfortatext(day.total_precip.toString() + - data.settings["Precipitation"], 17, data.settings, color: data.current.secondary), - ), - ], + Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.water_drop_outlined, + color: data.palette.primaryFixedDim, size: 18,), + Padding( + padding: const EdgeInsets.only(left: 2, right: 8), + child: comfortatext('${day.precip_prob}%', 17, data.settings, + color: data.palette.onSurface), + ), + Icon( + Icons.water_drop, color: data.palette.primaryFixedDim, size: 18,), + Padding( + padding: const EdgeInsets.only(left: 2, right: 2), + child: comfortatext(day.total_precip.toString() + + data.settings["Precipitation"], 17, data.settings, color: data.palette.onSurface), + ), + ], + ), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( - CupertinoIcons.wind, color: data.current.secondary, size: 18,), + CupertinoIcons.wind, color: data.palette.primaryFixedDim, size: 18,), Padding( padding: const EdgeInsets.only(left: 2, right: 2), child: comfortatext('${day.windspeed} ${data - .settings["Wind"]}', 17, data.settings, color: data.current.secondary), + .settings["Wind"]}', 17, data.settings, color: data.palette.onSurface), ), Padding( padding: const EdgeInsets.only(left: 3, right: 3, bottom: 1), child: RotationTransition( turns: AlwaysStoppedAnimation(day.wind_dir / 360), child: Icon(CupertinoIcons.arrow_down_circle, - color: data.current.secondary, size: 16,) + color: data.palette.primary, size: 16,) ) ), ], From ba03cfb4f98e2f3615dcba5c9aef3ddceddcb454 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 6 Aug 2024 16:03:49 +0200 Subject: [PATCH 064/129] trying to implement expandable daily --- lib/main_screens.dart | 2 +- lib/main_ui.dart | 14 +- lib/new_forecast.dart | 871 +++++++++++++++++++++++++----------------- lib/radar.dart | 5 +- 4 files changed, 537 insertions(+), 355 deletions(-) diff --git a/lib/main_screens.dart b/lib/main_screens.dart index ba896e7..818ba3a 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -143,7 +143,7 @@ class _NewMainState extends State { RadarSmall( data: data, key: Key("${data.place}, ${data.current.backcolor}")), buildNewDays(data), - buildNewGlanceDay(data), + buildNewGlanceDay(data: data), Padding( padding: const EdgeInsets.only(top: 10, bottom: 30), diff --git a/lib/main_ui.dart b/lib/main_ui.dart index ca5e75b..fb9cd15 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -722,12 +722,20 @@ Widget buildHours(List hours, data) => SizedBox( Widget providerSelector(settings, updateLocation, textcolor, highlight, primary, provider, latlng, real_loc) { return Padding( - padding: const EdgeInsets.all(20.0), + padding: const EdgeInsets.only(left: 20, right: 20, top: 15, bottom: 30), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - comfortatext(translation('Weather provider', settings["Language"]), 19, settings, - color: textcolor), + Padding( + padding: const EdgeInsets.only(left: 5, top: 0), + child: Align( + alignment: Alignment.centerLeft, + child: comfortatext( + translation('Weather provider', settings["Language"]), 16, + settings, + color: textcolor), + ), + ), Padding( padding: const EdgeInsets.only(top: 10), child: Container( diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index f1b8a5a..d1cf30d 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -27,15 +27,21 @@ import 'ui_helper.dart'; class NewDay extends StatefulWidget { final data; final index; + final state; + final onExpandTapped; - NewDay({Key? key, required this.data, required this.index}) : super(key: key); + NewDay({Key? key, required this.data, required this.index, required this.state, + required this.onExpandTapped}) : super(key: key); @override - _NewDayState createState() => _NewDayState(data); + _NewDayState createState() => _NewDayState(data, index, state, onExpandTapped); } class _NewDayState extends State with AutomaticKeepAliveClientMixin { final data; + final index; + final bool state; + final onExpandTapped; int _value = 0; PageController _pageController = PageController(); @@ -43,7 +49,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { void _onItemTapped(int index) { _pageController.animateToPage( index, - duration: Duration(milliseconds: 400), + duration: const Duration(milliseconds: 400), curve: Curves.fastEaseInToSlowEaseOut, ); } @@ -51,7 +57,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { @override bool get wantKeepAlive => true; - _NewDayState(this.data); + _NewDayState(this.data, this.index, this.state, this.onExpandTapped); @override Widget build(BuildContext context) { @@ -59,222 +65,235 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { print(("here", _value)); final day = data.days[widget.index]; - return Padding( - padding: const EdgeInsets.only(left: 20, right: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 5, top: 0), - child: Align( - alignment: Alignment.centerLeft, - child: comfortatext( + Color highlight = state ? data.palette.surfaceContainerHigh : data.palette.surfaceContainer; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(left: state ? 10 : 5, top: 0), + child: Row( + children: [ + comfortatext( day.name, 16, data.settings, color: data.palette.onSurface), - ), - ), - Padding( - padding: const EdgeInsets.only(top: 20, left: 23, right: 25), - child: Row( - children: [ - SizedBox( - width: 35, - child: Icon(day.icon, size: 38.0 * day.iconSize, color: data.palette.primary,)), - Padding( - padding: const EdgeInsets.only(left: 12.0, top: 3), - child: comfortatext(day.text, 20, data.settings, color: data.palette.onSurface, - weight: FontWeight.w400), + const Spacer(), + Padding( + padding: const EdgeInsets.only(right: 14), + child: IconButton( + icon: Icon(Icons.expand_less, color: data + .palette.primaryFixedDim, size: 20,), + onPressed: () { + onExpandTapped(index); + }, ), - const Spacer(), - Padding( - padding: const EdgeInsets.only(top: 4), - child: Row( - children: [ - comfortatext(day.minmaxtemp.split("/")[0], 19, data.settings, color: data.palette.primary), - Padding( - padding: const EdgeInsets.only(left: 5, right: 4), - child: comfortatext("/", 19, data.settings, color: data.palette.onSurface), - ), - comfortatext(day.minmaxtemp.split("/")[1], 19, data.settings, color: data.palette.primary), - ], - ), - ) - ], - ), + ), + ], ), - Padding( - padding: const EdgeInsets.only(left: 8, right: 8, top: 20, bottom: 10), - child: Container( - height: 85, - padding: const EdgeInsets.only(top: 8, bottom: 8, left: 10, right: 10), - decoration: BoxDecoration( - //border: Border.all(width: 1, color: data.palette.outline), - color: data.palette.surfaceContainerLow, - borderRadius: BorderRadius.circular(18), + ), + Padding( + padding: const EdgeInsets.only(top: 13, left: 23, right: 25), + child: Row( + children: [ + SizedBox( + width: 35, + child: Icon(day.icon, size: 38.0 * day.iconSize, color: data.palette.primary,)), + Padding( + padding: const EdgeInsets.only(left: 12.0, top: 3), + child: comfortatext(day.text, 20, data.settings, color: data.palette.onSurface, + weight: FontWeight.w400), ), - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return GridView.count( - padding: const EdgeInsets.all(0), - physics: const NeverScrollableScrollPhysics(), - crossAxisSpacing: 1, - mainAxisSpacing: 1, - crossAxisCount: 2, - childAspectRatio: constraints.maxWidth / constraints.maxHeight, - children: [ - Padding( - padding: const EdgeInsets.only( - left: 8, right: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.water_drop_outlined, - color: data.palette.primaryFixedDim, size: 21), - Padding( - padding: const EdgeInsets.only(left: 10, top: 3), - child: comfortatext('${day.precip_prob}%', 18, data.settings, - color: data.palette.primary), - ), - ], - ), + const Spacer(), + Padding( + padding: const EdgeInsets.only(top: 4), + child: Row( + children: [ + comfortatext(day.minmaxtemp.split("/")[0], 19, data.settings, color: data.palette.primary), + Padding( + padding: const EdgeInsets.only(left: 5, right: 4), + child: comfortatext("/", 19, data.settings, color: data.palette.onSurface), + ), + comfortatext(day.minmaxtemp.split("/")[1], 19, data.settings, color: data.palette.primary), + ], + ), + ) + ], + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8, right: 8, top: 20, bottom: 10), + child: Container( + height: 85, + padding: const EdgeInsets.only(top: 8, bottom: 8, left: 10, right: 10), + decoration: BoxDecoration( + //border: Border.all(width: 1, color: data.palette.outline), + color: state ? data.palette.surfaceContainer : data.palette.surfaceContainerLow, + borderRadius: BorderRadius.circular(18), + ), + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return GridView.count( + padding: const EdgeInsets.all(0), + physics: const NeverScrollableScrollPhysics(), + crossAxisSpacing: 1, + mainAxisSpacing: 1, + crossAxisCount: 2, + childAspectRatio: constraints.maxWidth / constraints.maxHeight, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 8, right: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.water_drop_outlined, + color: data.palette.primaryFixedDim, size: 21), + Padding( + padding: const EdgeInsets.only(left: 10, top: 3), + child: comfortatext('${day.precip_prob}%', 18, data.settings, + color: data.palette.primary), + ), + ], ), - Padding( - padding: const EdgeInsets.only( - left: 8, right: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.water_drop, color: data.palette.primaryFixedDim, size: 21), - Padding( - padding: const EdgeInsets.only(top: 3, left: 10), - child: comfortatext(day.total_precip.toString() + - data.settings["Precipitation"], 18, data.settings, - color: data.palette.primary), - ), - ], - ), + ), + Padding( + padding: const EdgeInsets.only( + left: 8, right: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.water_drop, color: data.palette.primaryFixedDim, size: 21), + Padding( + padding: const EdgeInsets.only(top: 3, left: 10), + child: comfortatext(day.total_precip.toString() + + data.settings["Precipitation"], 18, data.settings, + color: data.palette.primary), + ), + ], ), - Padding( - padding: const EdgeInsets.only( - left: 8, right: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - CupertinoIcons.wind, color: data.palette.primaryFixedDim, size: 21,), - Padding( - padding: const EdgeInsets.only(top: 3, left: 10), - child: comfortatext('${day.windspeed} ${data - .settings["Wind"]}', 18, data.settings, - color: data.palette.primary), - ), - Padding( - padding: const EdgeInsets.only(left: 5, right: 3), - child: RotationTransition( - turns: AlwaysStoppedAnimation(day.wind_dir / 360), - child: Icon(CupertinoIcons.arrow_down_circle, - color: data.palette.primaryFixedDim, size: 18,) - ) - ), - ], - ), + ), + Padding( + padding: const EdgeInsets.only( + left: 8, right: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + CupertinoIcons.wind, color: data.palette.primaryFixedDim, size: 21,), + Padding( + padding: const EdgeInsets.only(top: 3, left: 10), + child: comfortatext('${day.windspeed} ${data + .settings["Wind"]}', 18, data.settings, + color: data.palette.primary), + ), + Padding( + padding: const EdgeInsets.only(left: 5, right: 3), + child: RotationTransition( + turns: AlwaysStoppedAnimation(day.wind_dir / 360), + child: Icon(CupertinoIcons.arrow_down_circle, + color: data.palette.primaryFixedDim, size: 18,) + ) + ), + ], ), - Padding( - padding: const EdgeInsets.only( - left: 8, right: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(CupertinoIcons.sun_max, - color: data.palette.primaryFixedDim, size: 21), - Padding( - padding: const EdgeInsets.only(top: 3, left: 10), - child: comfortatext('${day.uv} UV', 18, data.settings, - color: data.palette.primary), - ), - ], - ), + ), + Padding( + padding: const EdgeInsets.only( + left: 8, right: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(CupertinoIcons.sun_max, + color: data.palette.primaryFixedDim, size: 21), + Padding( + padding: const EdgeInsets.only(top: 3, left: 10), + child: comfortatext('${day.uv} UV', 18, data.settings, + color: data.palette.primary), + ), + ], ), - ] - ); - } - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 15), - child: Wrap( - spacing: 5.0, - children: List.generate( - 4, - (int index) { - print((_value, index)); - - return ChoiceChip( - elevation: 0.0, - checkmarkColor: data.palette.onPrimaryFixed, - color: WidgetStateProperty.resolveWith((states) { - if (index == _value) { - return data.palette.primaryFixedDim; - } - return data.palette.surface; - }), - side: BorderSide(color: data.palette.primaryFixedDim, width: 1.0), - label: comfortatext( - ['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, - color: _value == index ? data.palette.onPrimaryFixed : data.palette.onSurface), - selected: _value == index, - onSelected: (bool selected) { - //setState(() { - // updateChip(index); - //}); - _value = index; - setState(() { - _onItemTapped(index); - }); - /* - setState(() { - _onItemTapped(index); - }); - */ - }, + ), + ] ); - }, - ).toList(), + } ), ), - SizedBox( - height: 260, - child: PageView( - controller: _pageController, - children: [ - buildTemp(day.hourly, data), - buildPrecip(day.hourly, data), - WindReport(hours: day.hourly, data: data,), - buildUV(day.hourly, data), - ], - ), + ), + Padding( + padding: const EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 15), + child: Wrap( + spacing: 5.0, + children: List.generate( + 4, + (int index) { + print((_value, index)); + + return ChoiceChip( + elevation: 0.0, + checkmarkColor: data.palette.onPrimaryFixed, + color: WidgetStateProperty.resolveWith((states) { + if (index == _value) { + return data.palette.primaryFixedDim; + } + return state ? data.palette.surfaceContainerLow : data.palette.surface; + }), + side: BorderSide(color: data.palette.primaryFixedDim, width: 1.0), + label: comfortatext( + ['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, + color: _value == index ? data.palette.onPrimaryFixed : data.palette.onSurface), + selected: _value == index, + onSelected: (bool selected) { + //setState(() { + // updateChip(index); + //}); + _value = index; + setState(() { + _onItemTapped(index); + }); + /* + setState(() { + _onItemTapped(index); + }); + */ + }, + ); + }, + ).toList(), ), - ], - ), + ), + SizedBox( + height: 260, + child: PageView( + controller: _pageController, + children: [ + buildTemp(day.hourly, data, highlight), + buildPrecip(day.hourly, data, data.palette.surfaceContainerHigh), + WindReport(hours: day.hourly, data: data, highlight: data.palette.surfaceContainerHigh,), + buildUV(day.hourly, data, highlight), + ], + ), + ), + ], ); } } Widget buildNewDays(data) { return ListView.builder( + padding: const EdgeInsets.only(top: 50, left: 20, right: 20), physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: 3, itemBuilder: (BuildContext context, int index) { - return NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.backcolor}"),); + return NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.backcolor}"), + state: false, onExpandTapped: null,); }, ); } -Widget buildTemp(List hours, data) => ListView( +Widget buildTemp(List hours, data, Color highlight) => ListView( physics: const BouncingScrollPhysics(), scrollDirection: Axis.horizontal, shrinkWrap: true, @@ -294,7 +313,7 @@ Widget buildTemp(List hours, data) => ListView( width: 14, height: 105, decoration: BoxDecoration( - color: data.palette.surfaceContainer, + color: highlight, //border: Border.all(color: data.palette.outline,), borderRadius: const BorderRadius.all(Radius.circular(20)) ), @@ -334,6 +353,7 @@ Widget buildTemp(List hours, data) => ListView( class WindChartPainter extends CustomPainter { final List hours; final data; + final highlight; final double dotRadius; final double smallDotRadius; final double spacing; @@ -342,6 +362,7 @@ class WindChartPainter extends CustomPainter { WindChartPainter({ required this.hours, required this.data, + required this.highlight, this.dotRadius = 7.0, this.smallDotRadius = 1.8, this.spacing = 55.0, @@ -355,7 +376,7 @@ class WindChartPainter extends CustomPainter { ..strokeWidth = 2.0; final smallDotPaint = Paint() - ..color = data.palette.surfaceContainerHigh + ..color = highlight ..strokeWidth = 1.0; final textPainter = TextPainter( @@ -412,8 +433,9 @@ class WindChartPainter extends CustomPainter { class WindReport extends StatelessWidget { final hours; final data; + final Color highlight; - WindReport({required this.hours, required this.data}); + WindReport({required this.hours, required this.data, required this.highlight}); @override Widget build(BuildContext context) { @@ -426,7 +448,7 @@ class WindReport extends StatelessWidget { padding: const EdgeInsets.only(top: 45, bottom: 20), child: CustomPaint( size: Size(hours.length * 55.0, 105.0), - painter: WindChartPainter(hours: hours, data: data), + painter: WindChartPainter(hours: hours, data: data, highlight: highlight), ), ), SizedBox( @@ -482,7 +504,7 @@ class WindReport extends StatelessWidget { } } -Widget buildUV(List hours, data) => ListView( +Widget buildUV(List hours, data, highlight) => ListView( physics: const BouncingScrollPhysics(), scrollDirection: Axis.horizontal, shrinkWrap: true, @@ -498,7 +520,8 @@ Widget buildUV(List hours, data) => ListView( SizedBox( height: 105, child: ListView.builder( - physics: NeverScrollableScrollPhysics(), + padding: EdgeInsets.zero, + physics: const NeverScrollableScrollPhysics(), itemCount: 10, itemExtent: 10, itemBuilder: (BuildContext context, int index) { @@ -509,7 +532,7 @@ Widget buildUV(List hours, data) => ListView( height: 5, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: data.palette.surfaceContainerHigh, + color: highlight, ), ), ); @@ -551,7 +574,7 @@ Widget buildUV(List hours, data) => ListView( ); -Widget buildPrecip(List hours, data) => ListView( +Widget buildPrecip(List hours, data, Color highlight) => ListView( physics: const BouncingScrollPhysics(), scrollDirection: Axis.horizontal, shrinkWrap: true, @@ -575,10 +598,11 @@ Widget buildPrecip(List hours, data) => ListView( height: 101, width: 15.5, child: GridView.builder( + padding: EdgeInsets.zero, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, ), - physics: NeverScrollableScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), itemCount: 26, reverse: true, itemBuilder: (BuildContext context, int index) { @@ -590,7 +614,7 @@ Widget buildPrecip(List hours, data) => ListView( child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: data.palette.surfaceContainerHigh, + color: highlight, ), ), ); @@ -631,163 +655,314 @@ Widget buildPrecip(List hours, data) => ListView( ); -Widget buildNewGlanceDay(var data) => Padding( - padding: const EdgeInsets.only(left: 24, right: 24, bottom: 10), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(left: 1, top: 0, bottom: 6), - child: Align( - alignment: Alignment.centerLeft, - child: comfortatext( - "daily", 16, - data.settings, - color: data.palette.onSurface), - ), - ), - ListView.builder( - shrinkWrap: true, - padding: const EdgeInsets.only(top: 5, bottom: 5, left: 0, right: 0), - physics: const NeverScrollableScrollPhysics(), - itemCount: data.days.length - 3, - itemBuilder: (context, index) { - final day = data.days[index + 3]; - return Padding( - padding: const EdgeInsets.only(top: 3, bottom: 3), - child: Container( - decoration: BoxDecoration( - borderRadius: - index == 0 ? const BorderRadius.vertical(top: Radius.circular(18.0), bottom: Radius.circular(8)) - : index == data.days.length - 4 ? const BorderRadius.vertical(bottom: Radius.circular(18.0), top: Radius.circular(8)) - : BorderRadius.circular(8), - color: data.palette.surfaceContainerLow), - child: Column( - children: [ - Row( - children: [ - SizedBox( - width: 63, - height: 73, - child: Padding( - padding: const EdgeInsets.only(left: 18), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - comfortatext(day.name.split(", ")[0], 18, data.settings, color: data.palette.primary), - comfortatext(day.name.split(", ")[1], 14, data.settings, color: data.palette.onSurface), - ], +class buildNewGlanceDay extends StatefulWidget { + final data; + + buildNewGlanceDay({Key? key, required this.data}) : super(key: key); + + @override + _buildNewGlanceDayState createState() => _buildNewGlanceDayState(data); +} + +class _buildNewGlanceDayState extends State with AutomaticKeepAliveClientMixin { + final data; + + late List expand = []; + late List controllers = []; + + @override + void initState() { + super.initState(); + for (int i = 0; i < data.days.length; i++) { + expand.add(false); + controllers.add(PageController()); + } + } + + void _onExpandTapped(int index) { + setState(() { + expand[index] = !expand[index]; + controllers[index].animateToPage( + expand[index] ? 1 : 0, + duration: const Duration(milliseconds: 400), + curve: Curves.fastEaseInToSlowEaseOut, + ); + }); + } + + @override + bool get wantKeepAlive => true; + + _buildNewGlanceDayState(this.data); + + @override + Widget build(BuildContext context) { + super.build(context); + return Padding( + padding: const EdgeInsets.only(left: 24, right: 24, bottom: 10, top: 10), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(left: 1, top: 0, bottom: 6), + child: Align( + alignment: Alignment.centerLeft, + child: comfortatext( + "daily", 16, + data.settings, + color: data.palette.onSurface), + ), + ), + ListView.builder( + shrinkWrap: true, + padding: const EdgeInsets.only( + top: 5, bottom: 5, left: 0, right: 0), + physics: const NeverScrollableScrollPhysics(), + itemCount: data.days.length - 3, + itemBuilder: (context, index) { + final day = data.days[index + 3]; + return SizedBox( + height: expand[index] ? 80 : 600, + child: PageView( + physics: NeverScrollableScrollPhysics(), + //scrollDirection: Axis.vertical, + controller: controllers[index], + children: [ + Padding( + padding: const EdgeInsets.only(top: 3, bottom: 3), + child: Container( + decoration: BoxDecoration( + borderRadius: + index == 0 ? const BorderRadius.vertical( + top: Radius.circular(18.0), + bottom: Radius.circular(8)) + : index == data.days.length - 4 ? const BorderRadius + .vertical(bottom: Radius.circular(18.0), + top: Radius.circular(8)) + : BorderRadius.circular(8), + color: data.palette.surfaceContainerLow), + child: Padding( + padding: const EdgeInsets.only(top: 5, left: 3, right: 3), + child: NewDay(data: data, index: index, state: true, + onExpandTapped: _onExpandTapped,), ), ), ), - SizedBox( - height: 30, - width: 43, - child: Icon( - day.icon, - color: data.palette.primary, - size: 31.0 * day.iconSize, + GlanceDayEntry(data, index, day, _onExpandTapped), + ], + ), + ); + if (expand[index]) { + return Padding( + padding: const EdgeInsets.only(top: 3, bottom: 3), + child: Container( + decoration: BoxDecoration( + borderRadius: + index == 0 ? const BorderRadius.vertical( + top: Radius.circular(18.0), + bottom: Radius.circular(8)) + : index == data.days.length - 4 ? const BorderRadius + .vertical(bottom: Radius.circular(18.0), + top: Radius.circular(8)) + : BorderRadius.circular(8), + color: data.palette.surfaceContainerLow), + child: Padding( + padding: const EdgeInsets.only(top: 5, left: 3, right: 3), + child: NewDay(data: data, index: index, state: true, + onExpandTapped: _onExpandTapped,), + ), + ), + ); + } + return GlanceDayEntry(data, index, day, _onExpandTapped); + } + ), + ], + ), + ); + } +} + + +Widget GlanceDayEntry(data, index, day, onExpandTapped) { + return Padding( + padding: const EdgeInsets.only(top: 3, bottom: 3), + child: Container( + decoration: BoxDecoration( + borderRadius: + index == 0 ? const BorderRadius.vertical( + top: Radius.circular(18.0), + bottom: Radius.circular(8)) + : index == data.days.length - 4 ? const BorderRadius + .vertical(bottom: Radius.circular(18.0), + top: Radius.circular(8)) + : BorderRadius.circular(8), + color: data.palette.surfaceContainerLow), + child: Column( + children: [ + Row( + children: [ + SizedBox( + width: 60, + height: 73, + child: Padding( + padding: const EdgeInsets.only(left: 18), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + comfortatext(day.name.split(", ")[0], 18, + data.settings, + color: data.palette.primary), + comfortatext(day.name.split(", ")[1], 14, + data.settings, + color: data.palette.onSurface), + ], + ), + ), + ), + SizedBox( + height: 30, + width: 43, + child: Icon( + day.icon, + color: data.palette.primary, + size: 31.0 * day.iconSize, + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 10, top: 2, bottom: 2), + child: Container( + height: 56, + width: 43, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(13), + //border: Border.all(width: 1.5, color: data.palette.primaryFixedDim) + color: data.palette.primaryFixedDim + ), + child: Row( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only( + bottom: 2), + child: Icon(Icons.keyboard_arrow_up, + color: data.palette.shadow, + size: 14,), ), - ), - Padding( - padding: const EdgeInsets.only(left: 10, top: 4, bottom: 4), - child: Container( - height: 58, - width: 43, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(13), - //border: Border.all(width: 1.5, color: data.palette.primaryFixedDim) - color: data.palette.primaryFixedDim - ), - child: Row( - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 2), - child: Icon(Icons.keyboard_arrow_up, color: data.palette.shadow, size: 14,), - ), - Icon(Icons.keyboard_arrow_down, color: data.palette.shadow, size: 14,), - ], - ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 2), - child: comfortatext(day.minmaxtemp.split("/")[1], 14, data.settings, color: data.palette.shadow), - ), - comfortatext(day.minmaxtemp.split("/")[0], 14, data.settings,color: data.palette.shadow), - ], - ), - ), - ], + Icon(Icons.keyboard_arrow_down, + color: data.palette.shadow, size: 14,), + ], + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment + .center, + children: [ + Padding( + padding: const EdgeInsets.only( + bottom: 2), + child: comfortatext( + day.minmaxtemp.split("/")[1], 14, + data.settings, + color: data.palette.shadow), ), - ), + comfortatext( + day.minmaxtemp.split("/")[0], 14, + data.settings, + color: data.palette.shadow), + ], ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 4), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.water_drop_outlined, - color: data.palette.primaryFixedDim, size: 18,), - Padding( - padding: const EdgeInsets.only(left: 2, right: 8), - child: comfortatext('${day.precip_prob}%', 17, data.settings, - color: data.palette.onSurface), - ), - Icon( - Icons.water_drop, color: data.palette.primaryFixedDim, size: 18,), - Padding( - padding: const EdgeInsets.only(left: 2, right: 2), - child: comfortatext(day.total_precip.toString() + - data.settings["Precipitation"], 17, data.settings, color: data.palette.onSurface), - ), - ], - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - CupertinoIcons.wind, color: data.palette.primaryFixedDim, size: 18,), - Padding( - padding: const EdgeInsets.only(left: 2, right: 2), - child: comfortatext('${day.windspeed} ${data - .settings["Wind"]}', 17, data.settings, color: data.palette.onSurface), - ), - Padding( - padding: const EdgeInsets.only(left: 3, right: 3, bottom: 1), - child: RotationTransition( - turns: AlwaysStoppedAnimation(day.wind_dir / 360), - child: Icon(CupertinoIcons.arrow_down_circle, - color: data.palette.primary, size: 16,) - ) - ), - ], - ) - ], - ), + ), + ], + ), + ), + ), + Spacer(), + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 4), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.water_drop_outlined, + color: data.palette.primaryFixedDim, + size: 18,), + Padding( + padding: const EdgeInsets.only( + left: 2, right: 8), + child: comfortatext( + '${day.precip_prob}%', 17, + data.settings, + color: data.palette.onSurface), ), + Icon( + Icons.water_drop, + color: data.palette.primaryFixedDim, + size: 18,), Padding( - padding: const EdgeInsets.only(right: 14), - child: Icon(Icons.arrow_forward_ios, color: data.palette.primaryFixedDim, size: 14,), + padding: const EdgeInsets.only( + left: 2, right: 2), + child: comfortatext( + day.total_precip.toString() + + data.settings["Precipitation"], + 17, data.settings, + color: data.palette.onSurface), ), ], ), - ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + CupertinoIcons.wind, + color: data.palette.primaryFixedDim, + size: 18,), + Padding( + padding: const EdgeInsets.only( + left: 2, right: 2), + child: comfortatext( + '${day.windspeed} ${data + .settings["Wind"]}', 17, + data.settings, + color: data.palette.onSurface), + ), + Padding( + padding: const EdgeInsets.only( + left: 3, right: 3, bottom: 1), + child: RotationTransition( + turns: AlwaysStoppedAnimation( + day.wind_dir / 360), + child: Icon( + CupertinoIcons.arrow_down_circle, + color: data.palette.primary, + size: 16,) + ) + ), + ], + ) + ], + ), + Padding( + padding: const EdgeInsets.only(right: 5), + child: IconButton( + padding: EdgeInsets.zero, + icon: Icon(Icons.arrow_forward_ios, color: data + .palette.primaryFixedDim, size: 14,), + onPressed: () { + onExpandTapped(index); + }, ), ), - ); - } + ], + ), + ], ), - ], - ), -); \ No newline at end of file + ), + ); +} \ No newline at end of file diff --git a/lib/radar.dart b/lib/radar.dart index 57617e6..f85ff44 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -674,7 +674,7 @@ class _RadarSmallState extends State { data: SliderTheme.of(context).copyWith( trackHeight: 18, valueIndicatorTextStyle: GoogleFonts.comfortaa( - color: data.palette.surface, + color: data.palette.shadow, fontSize: 12, fontWeight: FontWeight.w500, ), @@ -683,7 +683,6 @@ class _RadarSmallState extends State { enabledThumbRadius: 10, elevation: 0.0, pressedElevation: 0), - overlayColor: BLACK, tickMarkShape: RoundSliderTickMarkShape(tickMarkRadius: 2), overlayShape: SliderComponentShape.noOverlay @@ -901,7 +900,7 @@ class _RadarBigState extends State { data: SliderTheme.of(context).copyWith( trackHeight: 18, valueIndicatorTextStyle: GoogleFonts.comfortaa( - color: data.palette.surface, + color: data.palette.shadow, fontSize: 12, fontWeight: FontWeight.w500, ), From bf238c8a3a340c2ae5ebb6235152c07330422301 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 6 Aug 2024 20:20:33 +0200 Subject: [PATCH 065/129] you can now expand days --- lib/new_forecast.dart | 306 +++++++++++++++++++----------------------- 1 file changed, 137 insertions(+), 169 deletions(-) diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index d1cf30d..db0f921 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -29,16 +29,18 @@ class NewDay extends StatefulWidget { final index; final state; final onExpandTapped; + final day; NewDay({Key? key, required this.data, required this.index, required this.state, - required this.onExpandTapped}) : super(key: key); + required this.onExpandTapped, required this.day}) : super(key: key); @override - _NewDayState createState() => _NewDayState(data, index, state, onExpandTapped); + _NewDayState createState() => _NewDayState(data, index, state, onExpandTapped, day); } class _NewDayState extends State with AutomaticKeepAliveClientMixin { final data; + final day; final index; final bool state; final onExpandTapped; @@ -57,13 +59,11 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { @override bool get wantKeepAlive => true; - _NewDayState(this.data, this.index, this.state, this.onExpandTapped); + _NewDayState(this.data, this.index, this.state, this.onExpandTapped, this.day); @override Widget build(BuildContext context) { super.build(context); - print(("here", _value)); - final day = data.days[widget.index]; Color highlight = state ? data.palette.surfaceContainerHigh : data.palette.surfaceContainer; @@ -71,7 +71,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: EdgeInsets.only(left: state ? 10 : 5, top: 0), + padding: EdgeInsets.only(left: state ? 15 : 5, top: 0), child: Row( children: [ comfortatext( @@ -79,21 +79,24 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { data.settings, color: data.palette.onSurface), const Spacer(), - Padding( - padding: const EdgeInsets.only(right: 14), - child: IconButton( - icon: Icon(Icons.expand_less, color: data - .palette.primaryFixedDim, size: 20,), - onPressed: () { - onExpandTapped(index); - }, + Visibility( + visible: state, + child: Padding( + padding: const EdgeInsets.only(right: 13), + child: GestureDetector( + child: Icon(Icons.expand_less, color: data + .palette.primaryFixedDim, size: 20), + onTap: () { + onExpandTapped(index); + }, + ), ), ), ], ), ), Padding( - padding: const EdgeInsets.only(top: 13, left: 23, right: 25), + padding: const EdgeInsets.only(top: 15, left: 23, right: 25), child: Row( children: [ SizedBox( @@ -287,8 +290,9 @@ Widget buildNewDays(data) { shrinkWrap: true, itemCount: 3, itemBuilder: (BuildContext context, int index) { + final day = data.days[index]; return NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.backcolor}"), - state: false, onExpandTapped: null,); + state: false, onExpandTapped: null, day: day,); }, ); } @@ -386,7 +390,7 @@ class WindChartPainter extends CustomPainter { for (int i = 0; i < hours.length; i++) { final x = 27.5 + i * spacing; - final y = maxHeight - max(min(hours[i].raw_wind * 1.8, maxHeight), 0); + final y = maxHeight - max(min(hours[i].raw_wind * 1.4, maxHeight), 0); canvas.drawCircle(Offset(x, y), dotRadius, paint); @@ -409,7 +413,7 @@ class WindChartPainter extends CustomPainter { if (i < hours.length - 1) { final nextX = 27.5 + (i + 1) * spacing; - final nextY = maxHeight - max(min(hours[i + 1].raw_wind * 1.8, maxHeight), 0); + final nextY = maxHeight - max(min(hours[i + 1].raw_wind * 1.4, maxHeight), 0); int numDots = 4; double dx = (nextX - x) / numDots; @@ -668,25 +672,18 @@ class _buildNewGlanceDayState extends State with AutomaticKee final data; late List expand = []; - late List controllers = []; @override void initState() { super.initState(); for (int i = 0; i < data.days.length; i++) { expand.add(false); - controllers.add(PageController()); } } void _onExpandTapped(int index) { setState(() { expand[index] = !expand[index]; - controllers[index].animateToPage( - expand[index] ? 1 : 0, - duration: const Duration(milliseconds: 400), - curve: Curves.fastEaseInToSlowEaseOut, - ); }); } @@ -720,60 +717,34 @@ class _buildNewGlanceDayState extends State with AutomaticKee itemCount: data.days.length - 3, itemBuilder: (context, index) { final day = data.days[index + 3]; - return SizedBox( - height: expand[index] ? 80 : 600, - child: PageView( - physics: NeverScrollableScrollPhysics(), - //scrollDirection: Axis.vertical, - controller: controllers[index], - children: [ - Padding( - padding: const EdgeInsets.only(top: 3, bottom: 3), - child: Container( - decoration: BoxDecoration( + return Padding( + padding: const EdgeInsets.only(top: 3, bottom: 3), + child: AnimatedContainer( + height: expand[index] ? 520.0 : 70.0, + duration: const Duration(milliseconds:250), + child: SingleChildScrollView( + physics: const NeverScrollableScrollPhysics(), + child: expand[index] ? Container( + decoration: BoxDecoration( borderRadius: index == 0 ? const BorderRadius.vertical( - top: Radius.circular(18.0), - bottom: Radius.circular(8)) + top: Radius.circular(18.0), + bottom: Radius.circular(8)) : index == data.days.length - 4 ? const BorderRadius .vertical(bottom: Radius.circular(18.0), - top: Radius.circular(8)) + top: Radius.circular(8)) : BorderRadius.circular(8), color: data.palette.surfaceContainerLow), - child: Padding( - padding: const EdgeInsets.only(top: 5, left: 3, right: 3), - child: NewDay(data: data, index: index, state: true, - onExpandTapped: _onExpandTapped,), - ), - ), + child: Padding( + padding: const EdgeInsets.only(top: 25, left: 3, right: 3), + child: NewDay(data: data, index: index, state: true, + onExpandTapped: _onExpandTapped, day: day,), ), - GlanceDayEntry(data, index, day, _onExpandTapped), - ], + ) + : GlanceDayEntry(data, index, day, _onExpandTapped), + ), ), ); - if (expand[index]) { - return Padding( - padding: const EdgeInsets.only(top: 3, bottom: 3), - child: Container( - decoration: BoxDecoration( - borderRadius: - index == 0 ? const BorderRadius.vertical( - top: Radius.circular(18.0), - bottom: Radius.circular(8)) - : index == data.days.length - 4 ? const BorderRadius - .vertical(bottom: Radius.circular(18.0), - top: Radius.circular(8)) - : BorderRadius.circular(8), - color: data.palette.surfaceContainerLow), - child: Padding( - padding: const EdgeInsets.only(top: 5, left: 3, right: 3), - child: NewDay(data: data, index: index, state: true, - onExpandTapped: _onExpandTapped,), - ), - ), - ); - } - return GlanceDayEntry(data, index, day, _onExpandTapped); } ), ], @@ -784,104 +755,102 @@ class _buildNewGlanceDayState extends State with AutomaticKee Widget GlanceDayEntry(data, index, day, onExpandTapped) { - return Padding( - padding: const EdgeInsets.only(top: 3, bottom: 3), - child: Container( - decoration: BoxDecoration( - borderRadius: - index == 0 ? const BorderRadius.vertical( - top: Radius.circular(18.0), - bottom: Radius.circular(8)) - : index == data.days.length - 4 ? const BorderRadius - .vertical(bottom: Radius.circular(18.0), - top: Radius.circular(8)) - : BorderRadius.circular(8), - color: data.palette.surfaceContainerLow), - child: Column( - children: [ - Row( - children: [ - SizedBox( - width: 60, - height: 73, - child: Padding( - padding: const EdgeInsets.only(left: 18), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - comfortatext(day.name.split(", ")[0], 18, - data.settings, - color: data.palette.primary), - comfortatext(day.name.split(", ")[1], 14, - data.settings, - color: data.palette.onSurface), - ], - ), + return Container( + decoration: BoxDecoration( + borderRadius: + index == 0 ? const BorderRadius.vertical( + top: Radius.circular(18.0), + bottom: Radius.circular(8)) + : index == data.days.length - 4 ? const BorderRadius + .vertical(bottom: Radius.circular(18.0), + top: Radius.circular(8)) + : BorderRadius.circular(8), + color: data.palette.surfaceContainerLow), + child: Column( + children: [ + Row( + children: [ + SizedBox( + width: 60, + height: 73, + child: Padding( + padding: const EdgeInsets.only(left: 18), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + comfortatext(day.name.split(", ")[0], 18, + data.settings, + color: data.palette.primary), + comfortatext(day.name.split(", ")[1], 14, + data.settings, + color: data.palette.onSurface), + ], ), ), - SizedBox( - height: 30, + ), + SizedBox( + height: 30, + width: 43, + child: Icon( + day.icon, + color: data.palette.primary, + size: 31.0 * day.iconSize, + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 10, top: 2, bottom: 2), + child: Container( + height: 56, width: 43, - child: Icon( - day.icon, - color: data.palette.primary, - size: 31.0 * day.iconSize, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(13), + //border: Border.all(width: 1.5, color: data.palette.primaryFixedDim) + color: data.palette.primaryFixedDim ), - ), - Padding( - padding: const EdgeInsets.only( - left: 10, top: 2, bottom: 2), - child: Container( - height: 56, - width: 43, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(13), - //border: Border.all(width: 1.5, color: data.palette.primaryFixedDim) - color: data.palette.primaryFixedDim - ), - child: Row( - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.center, + child: Row( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only( + bottom: 2), + child: Icon(Icons.keyboard_arrow_up, + color: data.palette.shadow, + size: 14,), + ), + Icon(Icons.keyboard_arrow_down, + color: data.palette.shadow, size: 14,), + ], + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment + .center, children: [ Padding( padding: const EdgeInsets.only( bottom: 2), - child: Icon(Icons.keyboard_arrow_up, - color: data.palette.shadow, - size: 14,), - ), - Icon(Icons.keyboard_arrow_down, - color: data.palette.shadow, size: 14,), - ], - ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment - .center, - children: [ - Padding( - padding: const EdgeInsets.only( - bottom: 2), - child: comfortatext( - day.minmaxtemp.split("/")[1], 14, - data.settings, - color: data.palette.shadow), - ), - comfortatext( - day.minmaxtemp.split("/")[0], 14, + child: comfortatext( + day.minmaxtemp.split("/")[1], 14, data.settings, color: data.palette.shadow), - ], - ), + ), + comfortatext( + day.minmaxtemp.split("/")[0], 14, + data.settings, + color: data.palette.shadow), + ], ), - ], - ), + ), + ], ), ), - Spacer(), - Column( + ), + Expanded( + child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Padding( @@ -948,21 +917,20 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { ) ], ), - Padding( - padding: const EdgeInsets.only(right: 5), - child: IconButton( - padding: EdgeInsets.zero, - icon: Icon(Icons.arrow_forward_ios, color: data - .palette.primaryFixedDim, size: 14,), - onPressed: () { - onExpandTapped(index); - }, - ), + ), + Padding( + padding: const EdgeInsets.only(right: 17), + child: GestureDetector( + child: Icon(Icons.expand_more, color: data + .palette.primaryFixedDim, size: 20,), + onTap: () { + onExpandTapped(index); + }, ), - ], - ), - ], - ), + ), + ], + ), + ], ), ); } \ No newline at end of file From 411b1cf64955909d5d1657ae2d2bdbeef178cea7 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 6 Aug 2024 21:11:44 +0200 Subject: [PATCH 066/129] trying to once again improve temp contrast --- lib/decoders/extra_info.dart | 53 ++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 186b590..ed38740 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -137,20 +137,24 @@ Future getImageColors(Image Uimage, color_mode) async { Color bestcolor = palette.primaryFixedDim; int bestDif = difFromBackColors(bestcolor, dominant); - if (bestDif <= 330) { + int base = diffBetweenBackColors(dominant); + print(("base", base)); + + if (bestDif <= base + 100) { + print("trying"); for (int i = 1; i < 4; i++) { //LIGHT - Color newcolor = lighten(startcolor, i / 25); + Color newcolor = lighten(startcolor, i / 7); int newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < 440) { + if (newdif > bestDif && newdif < base + 250) { bestDif = newdif; bestcolor = newcolor; } //DARK - newcolor = darken(startcolor, i / 25); + newcolor = darken(startcolor, i / 7); newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < 440) { + if (newdif > bestDif && newdif < base + 250) { bestDif = newdif; bestcolor = newcolor; } @@ -158,11 +162,12 @@ Future getImageColors(Image Uimage, color_mode) async { } //if the contrast is still low then we need to choose another color - if (bestDif <= 330) { + if (bestDif <= base + 100) { + print("plan b"); for (int i = 0; i < dominant.length; i++) { Color newcolor = dominant[i]; int newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < 440) { + if (newdif > bestDif && newdif < base + 250) { bestDif = newdif; bestcolor = newcolor; } @@ -180,25 +185,7 @@ Future getImageColors(Image Uimage, color_mode) async { desc_color = bestcolor; } - List gradientColors = getGradientColors(palette.primaryFixedDim, palette.error, 10); - - return [palette, bestcolor, desc_color, gradientColors, dominant]; -} - -List getGradientColors(Color color1, Color color2, int number) { - int r = color1.red; int g = color1.green; int b = color1.blue; - int dif_r = (color2.red - color1.red) ~/ number; - int dif_g = (color2.green - color1.green) ~/ number; - int dif_b = (color2.blue - color1.blue) ~/ number; - - List colors = []; - - for (int i = 0; i < number; i++) { - r += dif_r; b += dif_b; g += dif_g; - colors.add(Color.fromARGB(255, r, g, b)); - } - - return colors; + return [palette, bestcolor, desc_color, dominant]; } int difFromBackColors(Color frontColor, List backcolors) { @@ -209,6 +196,18 @@ int difFromBackColors(Color frontColor, List backcolors) { return smallest; } +int diffBetweenBackColors(List backcolors) { + int diff_sum = 0; + for (int a = 0; a < backcolors.length; a ++) { + for (int b = 0; b < backcolors.length; b ++) { + if (a != b) { + diff_sum += difBetweenTwoColors(backcolors[a], backcolors[b]); + } + } + } + return diff_sum ~/ (backcolors.length * (backcolors.length - 1)); +} + int difBetweenTwoColors(Color color1, Color color2) { int r = (color1.red - color2.red).abs(); int g = (color1.green - color2.green).abs(); @@ -278,7 +277,7 @@ Future _generatorPalette(Image imageWidget) async { PaletteGenerator _paletteGenerator = await PaletteGenerator.fromImage( imageInfo.image, region: region, - maximumColorCount: 3 + maximumColorCount: 4 ); imageProvider.resolve(const ImageConfiguration()).removeListener(listener); From 5b3056832acd206e929f377d1e6037f7929ef0ed Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 7 Aug 2024 16:58:14 +0200 Subject: [PATCH 067/129] started working on material-you color --- lib/decoders/extra_info.dart | 38 ++++++++++++++++--- lib/new_forecast.dart | 11 ++++-- linux/flutter/generated_plugin_registrant.cc | 4 ++ linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 12 +++++- pubspec.yaml | 1 + .../flutter/generated_plugin_registrant.cc | 3 ++ windows/flutter/generated_plugins.cmake | 1 + 9 files changed, 61 insertions(+), 12 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index ed38740..2c9fc38 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -21,7 +21,9 @@ import 'dart:convert'; import 'dart:math'; import 'package:cached_network_image/cached_network_image.dart'; +import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; import 'package:overmorrow/decoders/decode_OM.dart'; import 'package:palette_generator/palette_generator.dart'; @@ -126,10 +128,34 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double return Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover,); } +Future MaterialYouColor(String theme) async { + final corePalette = await DynamicColorPlugin.getCorePalette(); + + Color? mainColor; + if (corePalette != null) { + mainColor = corePalette.toColorScheme().primary; + } else { + mainColor = Colors.blue; + } + final ColorScheme palette = ColorScheme.fromSeed( + seedColor: mainColor, + brightness: theme == 'light' ? Brightness.light : Brightness.dark, + dynamicSchemeVariant: theme == 'original' || theme == 'monochrome' ? DynamicSchemeVariant.fruitSalad : + DynamicSchemeVariant.tonalSpot, + ); + + return palette; +} + Future getImageColors(Image Uimage, color_mode) async { - final ColorScheme palette = await _materialPalette(Uimage, color_mode); final PaletteGenerator pali = await _generatorPalette(Uimage); + //var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + //color_mode = brightness == Brightness.dark ? "dark" : "light"; + //final ColorScheme palette = await MaterialYouColor(color_mode); + + final ColorScheme palette = (await _materialPalette(Uimage, color_mode)); + final List dominant = pali.colors.toList(); Color startcolor = palette.primaryFixedDim; @@ -140,13 +166,13 @@ Future getImageColors(Image Uimage, color_mode) async { int base = diffBetweenBackColors(dominant); print(("base", base)); - if (bestDif <= base + 100) { + if (bestDif <= base + 50) { print("trying"); for (int i = 1; i < 4; i++) { //LIGHT - Color newcolor = lighten(startcolor, i / 7); + Color newcolor = lighten(startcolor, i / 13); int newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < base + 250) { + if (newdif > bestDif && newdif < base + 200) { bestDif = newdif; bestcolor = newcolor; } @@ -154,7 +180,7 @@ Future getImageColors(Image Uimage, color_mode) async { //DARK newcolor = darken(startcolor, i / 7); newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < base + 250) { + if (newdif > bestDif && newdif < base + 200) { bestDif = newdif; bestcolor = newcolor; } @@ -162,7 +188,7 @@ Future getImageColors(Image Uimage, color_mode) async { } //if the contrast is still low then we need to choose another color - if (bestDif <= base + 100) { + if (bestDif <= base + 50) { print("plan b"); for (int i = 0; i < dominant.length; i++) { Color newcolor = dominant[i]; diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index db0f921..33856cc 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -267,7 +267,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { ), ), SizedBox( - height: 260, + height: 250, child: PageView( controller: _pageController, children: [ @@ -291,8 +291,11 @@ Widget buildNewDays(data) { itemCount: 3, itemBuilder: (BuildContext context, int index) { final day = data.days[index]; - return NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.backcolor}"), - state: false, onExpandTapped: null, day: day,); + return Padding( + padding: const EdgeInsets.only(bottom: 10), + child: NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.backcolor}"), + state: false, onExpandTapped: null, day: day,), + ); }, ); } @@ -720,7 +723,7 @@ class _buildNewGlanceDayState extends State with AutomaticKee return Padding( padding: const EdgeInsets.only(top: 3, bottom: 3), child: AnimatedContainer( - height: expand[index] ? 520.0 : 70.0, + height: expand[index] ? 540.0 : 73.0, duration: const Duration(milliseconds:250), child: SingleChildScrollView( physics: const NeverScrollableScrollPhysics(), diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index b2aaa65..a40de73 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,10 +6,14 @@ #include "generated_plugin_registrant.h" +#include #include #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) dynamic_color_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin"); + dynamic_color_plugin_register_with_registrar(dynamic_color_registrar); g_autoptr(FlPluginRegistrar) handy_window_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "HandyWindowPlugin"); handy_window_plugin_register_with_registrar(handy_window_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 067673a..6a5fb62 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + dynamic_color handy_window url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index c0164f1..f60ac80 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import dynamic_color import geolocator_apple import path_provider_foundation import shared_preferences_foundation @@ -12,6 +13,7 @@ import sqflite import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/pubspec.lock b/pubspec.lock index e2aad3b..97a8aa7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -113,6 +113,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dynamic_color: + dependency: "direct main" + description: + name: dynamic_color + sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d + url: "https://pub.dev" + source: hosted + version: "1.7.0" fake_async: dependency: transitive description: @@ -769,10 +777,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: a36e2d7981122fa185006b216eb6b5b97ede3f9a54b7a511bc966971ab98d049 + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.3" url_launcher_windows: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 398fbce..ab4e1a3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,6 +47,7 @@ dependencies: stretchy_header: ^2.0.0 cached_network_image: ^3.3.1 palette_generator: ^0.3.3+4 + dynamic_color: ^1.7.0 # The following adds the Cupertino Icons font to your application. diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 94586cc..20515bb 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,10 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + DynamicColorPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("DynamicColorPluginCApi")); GeolocatorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("GeolocatorWindows")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index f0bcafd..3e1c6f0 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + dynamic_color geolocator_windows url_launcher_windows ) From 0fbdaa0e10d6ad74aea6e60eb725383c5ae8ed4a Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 8 Aug 2024 15:42:54 +0200 Subject: [PATCH 068/129] migrated every color to current. started working on colorful --- lib/decoders/decode_OM.dart | 64 +++++++++------ lib/decoders/decode_wapi.dart | 4 - lib/decoders/extra_info.dart | 32 +++----- lib/main_screens.dart | 52 ++++++------ lib/main_ui.dart | 42 +++++----- lib/new_displays.dart | 46 +++++------ lib/new_forecast.dart | 146 ++++++++++++++++------------------ lib/radar.dart | 68 ++++++++-------- lib/settings_page.dart | 81 ++++++++++++++----- lib/ui_helper.dart | 20 ++--- 10 files changed, 295 insertions(+), 260 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index c468fa8..7944a2c 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -217,34 +217,49 @@ class OMCurrent { final int wind; final int wind_dir; - final Color backcolor; + final Color surface; final Color primary; - final Color colorpop; - final Color textcolor; - final Color secondary; - final Color highlight; + final Color primaryLight; + final Color primaryLighter; + final Color onSurface; + final Color outline; + final Color containerLow; + final Color container; + final Color containerHigh; + final Color colorPop; + final Color descColor; + final Color surfaceVariant; + final Color onPrimaryLight; final Color backup_primary; final Color backup_backcolor; const OMCurrent({ required this.precip, - required this.primary, - required this.backcolor, required this.backdrop, - required this.textcolor, required this.humidity, required this.feels_like, required this.temp, required this.text, required this.uv, required this.wind, - required this.colorpop, - required this.secondary, - required this.highlight, required this.backup_backcolor, required this.backup_primary, required this.wind_dir, + + required this.surface, + required this.primary, + required this.primaryLight, + required this.primaryLighter, + required this.onSurface, + required this.outline, + required this.containerLow, + required this.container, + required this.containerHigh, + required this.colorPop, + required this.descColor, + required this.surfaceVariant, + required this.onPrimaryLight, }); static OMCurrent fromJson(item, settings, sunstatus, timenow, palette) { @@ -266,7 +281,7 @@ class OMCurrent { // ]); - List colors = getNetworkColors(palette, settings); + List colors = getNetworkColors(palette[0], settings); //List colors = palette.colors.toList(); @@ -279,13 +294,20 @@ class OMCurrent { item["current"]["apparent_temperature"], settings["Temperature"]) .round(), - - backcolor: colors[0], + surface: colors[0], primary: colors[1], - textcolor: colors[2], - colorpop: colors[3], - secondary: colors[4], - highlight: colors[5], + primaryLight: colors[2], + primaryLighter: colors[3], + onSurface: colors[4], + outline: colors[5], + containerLow: colors[6], + container: colors[7], + containerHigh: colors[8], + surfaceVariant: colors[9], + onPrimaryLight: colors[10], + + colorPop: palette[1], + descColor: palette[2], backup_backcolor: back, backup_primary: primary, @@ -624,7 +646,7 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as sunstatus: sunstatus, minutely_15_precip: OM15MinutePrecip.fromJson(oMBody, settings), - current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, imageColors[0]), + current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, imageColors), days: days, lat: lat, @@ -640,9 +662,5 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as localtime: real_time.split("T")[1], image: Uimage, - - palette: imageColors[0], - colorpop: imageColors[1], - desc_color: imageColors[2], ); } \ No newline at end of file diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index 7b69ef9..80a0992 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -558,9 +558,5 @@ Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) minutely_15_precip: const OM15MinutePrecip(t_minus: "", precip_sum: 0, precips: []), //because wapi doesn't have 15 minutely image: Uimage, - - palette: imageColors[0], - colorpop: imageColors[1], - desc_color: imageColors[2], ); } diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 2c9fc38..991ece0 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -23,7 +23,6 @@ import 'dart:math'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; import 'package:overmorrow/decoders/decode_OM.dart'; import 'package:palette_generator/palette_generator.dart'; @@ -158,9 +157,9 @@ Future getImageColors(Image Uimage, color_mode) async { final List dominant = pali.colors.toList(); - Color startcolor = palette.primaryFixedDim; + Color startcolor = palette.tertiaryFixedDim; - Color bestcolor = palette.primaryFixedDim; + Color bestcolor = palette.tertiaryFixedDim; int bestDif = difFromBackColors(bestcolor, dominant); int base = diffBetweenBackColors(dominant); @@ -200,7 +199,7 @@ Future getImageColors(Image Uimage, color_mode) async { } } - Color desc_color = palette.surface; + Color desc_color = palette.onPrimaryFixedVariant; int desc_dif = difFromBackColors(desc_color, dominant); print(("diffs", bestDif, desc_dif)); @@ -211,7 +210,7 @@ Future getImageColors(Image Uimage, color_mode) async { desc_color = bestcolor; } - return [palette, bestcolor, desc_color, dominant]; + return [palette, bestcolor, desc_color]; } int difFromBackColors(Color frontColor, List backcolors) { @@ -231,7 +230,8 @@ int diffBetweenBackColors(List backcolors) { } } } - return diff_sum ~/ (backcolors.length * (backcolors.length - 1)); + return 1; + //return (diff_sum / (backcolors.length * (backcolors.length - 1))).round(); } int difBetweenTwoColors(Color color1, Color color2) { @@ -318,7 +318,7 @@ Future _materialPalette(Image imageWidget, theme) async { return ColorScheme.fromImageProvider( provider: imageProvider, brightness: theme == 'light' ? Brightness.light : Brightness.dark, - dynamicSchemeVariant: theme == 'original' || theme == 'monochrome' ? DynamicSchemeVariant.fruitSalad : + dynamicSchemeVariant: theme == 'o' || theme == 'm' ? DynamicSchemeVariant.fruitSalad : DynamicSchemeVariant.tonalSpot, ); } @@ -333,14 +333,17 @@ List ColorPopCorrection(String text) { class WeatherData { final Map settings; + final String place; - final String provider; final String real_loc; - final double lat; final double lng; + final String provider; + final updatedTime; + final fetch_datetime; + final localtime; final days; final current; @@ -349,14 +352,7 @@ class WeatherData { final radar; final minutely_15_precip; - final fetch_datetime; - final image; - final localtime; - - final palette; - final colorpop; - final desc_color; WeatherData({ required this.place, @@ -376,10 +372,6 @@ class WeatherData { required this.localtime, required this.minutely_15_precip, - - required this.palette, - required this.colorpop, - required this.desc_color, }); static Future getFullData(settings, placeName, real_loc, latlong, provider) async { diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 818ba3a..cbdb869 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -56,7 +56,7 @@ class _NewMainState extends State { final FloatingSearchBarController controller = FloatingSearchBarController(); return Scaffold( - backgroundColor: data.current.backcolor, + backgroundColor: data.current.surface, drawer: MyDrawer(primary: data.current.backup_primary, back: data.current.backup_backcolor, settings: data.settings, @@ -72,8 +72,8 @@ class _NewMainState extends State { headerHeight: max(size.height * 0.53, 400), //we don't want it to be smaller than 400 header: ParrallaxBackground(image: data.image, key: Key(data.place), - color: data.current.backcolor == BLACK ? BLACK - : lightAccent(data.current.backcolor, 5000)), + color: data.current.surface == BLACK ? BLACK + : lightAccent(data.current.surface, 5000)), overlay: Stack( children: [ Padding( @@ -91,7 +91,7 @@ class _NewMainState extends State { padding: const EdgeInsets.only(left: 0, bottom: 2), child: comfortatext( "${data.current.temp}°", 69, data.settings, - color: data.colorpop, weight: FontWeight.w300), + color: data.current.colorPop, weight: FontWeight.w300), ), Padding( padding: const EdgeInsets.only(left: 0), @@ -100,21 +100,21 @@ class _NewMainState extends State { weight: data.settings["Color mode"] == "dark" ? FontWeight.w600 : FontWeight.w500, - color: data.desc_color), + color: data.current.descColor), ) ], ), ), MySearchParent(updateLocation: updateLocation, - color: data.current.backcolor, + color: data.current.surface, place: data.place, controller: controller, settings: data.settings, real_loc: data.real_loc, - secondColor: data.current.primary, - textColor: data.current.textcolor, - highlightColor: data.current.highlight, - key: Key("${data.place}, ${data.current.backcolor}"),), + secondColor: data.current.primaryLight, + textColor: data.current.primary, + highlightColor: data.current.containerLow, + key: Key("${data.place}, ${data.current.surface}"),), ], ) ), @@ -127,10 +127,10 @@ class _NewMainState extends State { LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { if (constraints.maxWidth > 500.0) { - return Circles(500, data, 0.5, data.palette.primary); + return Circles(500, data, 0.5, data.current.primary); } else { return Circles(constraints.maxWidth * 0.97, data, 0.5, - data.palette.primary); + data.current.primary); } } ), @@ -141,7 +141,7 @@ class _NewMainState extends State { NewRain15MinuteIndicator(data), NewAirQuality(data), RadarSmall( - data: data, key: Key("${data.place}, ${data.current.backcolor}")), + data: data, key: Key("${data.place}, ${data.current.surface}")), buildNewDays(data), buildNewGlanceDay(data: data), @@ -150,9 +150,9 @@ class _NewMainState extends State { child: providerSelector( data.settings, updateLocation, - data.current.textcolor, - data.current.highlight, - data.current.primary, + data.current.outline, + data.current.container, + data.current.surface, data.provider, "${data.lat}, ${data.lng}", data.real_loc), @@ -163,8 +163,8 @@ class _NewMainState extends State { NewTimes(data, true), buildHihiDays(data), buildGlanceDay(data), - providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, - data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), + providerSelector(data.settings, updateLocation, data.current.outline, data.current.container, + data.current.surface, data.provider, "${data.lat}, ${data.lng}", data.real_loc), */ const Padding(padding: EdgeInsets.only(bottom: 20)) @@ -190,7 +190,7 @@ Widget TabletLayout(data, updateLocation, context) { double heigth = min(max(width / 1.5, 450), 510); return Scaffold( - backgroundColor: data.current.backcolor, + backgroundColor: data.current.surface, drawer: MyDrawer(primary: data.current.backup_primary, back: data.current.backup_backcolor, settings: data.settings, image: data.current.backdrop), body: RefreshIndicator( @@ -198,7 +198,7 @@ Widget TabletLayout(data, updateLocation, context) { await updateLocation("${data.lat}, ${data.lng}", data.real_loc); }, backgroundColor: WHITE, - color: data.current.backcolor, + color: data.current.surface, displacement: 100, child: Padding( padding: EdgeInsets.only(left: 20, right: 10, bottom: 10, top: toppad + 10), @@ -224,7 +224,7 @@ Widget TabletLayout(data, updateLocation, context) { child: ClipRRect( borderRadius: BorderRadius.circular(20), child: ParrallaxBackground(image: data.current.backdrop, key: Key(data.place), - color: darken(data.current.backcolor, 0.1),), + color: darken(data.current.surface, 0.1),), ), ), Padding( @@ -256,15 +256,15 @@ Widget TabletLayout(data, updateLocation, context) { child: Circles(400, data, 0.6, data.current.colorpop, align: Alignment.centerRight), ); } else { - return Circles(constraints.maxWidth * 0.90, data, 1, data.current.primary); + return Circles(constraints.maxWidth * 0.90, data, 1, data.current.surface); } } ), MySearchParent(updateLocation: updateLocation, - color: data.current.highlight, place: data.place, + color: data.current.container, place: data.place, controller: controller, settings: data.settings, real_loc: data.real_loc, - secondColor: data.current.primary, textColor: data.current.textcolor, - highlightColor: data.current.primary, key: Key("${data.place}, ${data.current.backcolor}"),), + secondColor: data.current.surface, textColor: data.current.outline, + highlightColor: data.current.surface, key: Key("${data.place}, ${data.current.surface}"),), ], ), ), @@ -281,7 +281,7 @@ Widget TabletLayout(data, updateLocation, context) { children: [ NewTimes(data, false), buildGlanceDay(data), - providerSelector(data.settings, updateLocation, data.current.textcolor, data.current.highlight, data.current.primary, + providerSelector(data.settings, updateLocation, data.current.outline, data.current.container, data.current.surface, data.provider, "${data.lat}, ${data.lng}", data.real_loc), ], ), diff --git a/lib/main_ui.dart b/lib/main_ui.dart index fb9cd15..1403e1e 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -57,7 +57,7 @@ class WeatherPage extends StatelessWidget { //return PhoneLayout(data, updateLocation, context); return NewMain(data: data, updateLocation: updateLocation, context: context, - key: Key("${data.place}, ${data.current.primary} ${data.image}"),); + key: Key("${data.place}, ${data.current.surface} ${data.image}"),); } } @@ -158,7 +158,7 @@ Widget NewTimes(var data, bool divider) => Column( child: Align( alignment: Alignment.centerLeft, child: comfortatext(translation('sunrise/sunset', data.settings["Language"]), 19, data.settings, - color: data.current.textcolor), + color: data.current.outline), ), ), Center( @@ -229,7 +229,7 @@ Widget NewTimes(var data, bool divider) => Column( child: Align( alignment: Alignment.center, child: comfortatext(data.sunstatus.sunrise, 18, data.settings, - color: data.current.textcolor) + color: data.current.outline) ) ) ), @@ -240,7 +240,7 @@ Widget NewTimes(var data, bool divider) => Column( child: Align( alignment: Alignment.center, child: comfortatext(data.sunstatus.sunset, 18, data.settings, - color: data.current.textcolor) + color: data.current.outline) ) ) ) @@ -259,14 +259,14 @@ Widget NewTimes(var data, bool divider) => Column( child: Align( alignment: Alignment.centerLeft, child: comfortatext(translation('air quality', data.settings["Language"]), 20, data.settings, - color: data.current.textcolor), + color: data.current.outline), ), ), Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), - //border: Border.all(width: 1.2, color: data.current.textcolor) - color: data.current.highlight + //border: Border.all(width: 1.2, color: data.current.outline) + color: data.current.container ), padding: const EdgeInsets.all(13), child: Row( @@ -277,7 +277,7 @@ Widget NewTimes(var data, bool divider) => Column( height: 85, width: 85, decoration: BoxDecoration( - color: data.current.primary, + color: data.current.surface, borderRadius: BorderRadius.circular(20), ), child: Center( @@ -298,7 +298,7 @@ Widget NewTimes(var data, bool divider) => Column( translation(['good', 'moderate', 'slightly unhealthy', 'unhealthy', 'very unhealthy', 'hazardous'][data.aqi.aqi_index - 1], data.settings["Language"]), 16, data.settings, - color: data.current.textcolor, align: TextAlign.center) + color: data.current.outline, align: TextAlign.center) ), ), ), @@ -327,7 +327,7 @@ Widget NewTimes(var data, bool divider) => Column( padding: const EdgeInsets.only(top: 6, right: 30, left: 30), child: Container( height: 2, - color: data.current.highlight, + color: data.current.container, ), ), ), @@ -347,14 +347,14 @@ Widget buildHihiDays(var data) => ListView.builder( children: [ Padding( padding: const EdgeInsets.only(top: 0, bottom: 10), - child: comfortatext(day.name, 19, data.settings, color: data.current.textcolor) + child: comfortatext(day.name, 19, data.settings, color: data.current.outline) ), Padding( padding: const EdgeInsets.all(2.0), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), - color: day.mm_precip > 0.1 ? data.current.highlight : data.current.backcolor, + color: day.mm_precip > 0.1 ? data.current.container : data.current.backcolor, ), padding: const EdgeInsets.only(top: 8, left: 3, right: 5, bottom: 3), child: SizedBox( @@ -371,7 +371,7 @@ Widget buildHihiDays(var data) => ListView.builder( height: 40, ), ), - comfortatext(day.text, 22, data.settings, color: data.current.textcolor), + comfortatext(day.text, 22, data.settings, color: data.current.outline), const Spacer(), Padding( padding: const EdgeInsets.only(right: 6), @@ -379,7 +379,7 @@ Widget buildHihiDays(var data) => ListView.builder( padding: const EdgeInsets.only(top:7,bottom: 7, left: 7, right: 5), decoration: BoxDecoration( //border: Border.all(color: Colors.blueAccent) - color: data.current.primary, + color: data.current.surface, borderRadius: BorderRadius.circular(10) ), child: comfortatext(day.minmaxtemp, 18, data.settings, color: data.current.backcolor) @@ -507,7 +507,7 @@ Widget buildGlanceDay(var data) => Padding( padding: const EdgeInsets.only(bottom: 15), child: Align( alignment: Alignment.centerLeft, - child: comfortatext(translation('Daily', data.settings["Language"]), 19, data.settings, color: data.current.textcolor), + child: comfortatext(translation('Daily', data.settings["Language"]), 19, data.settings, color: data.current.outline), ), ), Container( @@ -528,7 +528,7 @@ Widget buildGlanceDay(var data) => Padding( child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(21), - color: day.mm_precip > rain_limit ? data.current.highlight : data.current.backcolor, + color: day.mm_precip > rain_limit ? data.current.container : data.current.backcolor, ), padding: EdgeInsets.all(day.mm_precip > rain_limit ? 8 : 0), child: Column( @@ -539,13 +539,13 @@ Widget buildGlanceDay(var data) => Padding( height: 75, width: 75, decoration: BoxDecoration( - color: day.mm_precip > rain_limit ? data.current.backcolor : data.current.highlight, + color: day.mm_precip > rain_limit ? data.current.backcolor : data.current.container, borderRadius: BorderRadius.circular(20), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - comfortatext(day.name, 18, data.settings, color: data.current.textcolor), + comfortatext(day.name, 18, data.settings, color: data.current.outline), Container( padding: const EdgeInsets.all(5), child: Image.asset( @@ -563,7 +563,7 @@ Widget buildGlanceDay(var data) => Padding( height: 75, width: 52, decoration: BoxDecoration( - color: data.current.primary, + color: data.current.surface, borderRadius: BorderRadius.circular(20), ), child: Row( @@ -676,7 +676,7 @@ Widget buildHours(List hours, data) => SizedBox( children: [ Padding( padding: const EdgeInsets.only(top: 10, bottom: 10), - child: comfortatext('${hour.temp}°', 22, data.settings, color: data.current.primary), + child: comfortatext('${hour.temp}°', 22, data.settings, color: data.current.surface), ), Stack( alignment: Alignment.bottomCenter, @@ -711,7 +711,7 @@ Widget buildHours(List hours, data) => SizedBox( ), Padding( padding: const EdgeInsets.only(top:20, left: 9, right: 9), - child: comfortatext(hour.time, 17, data.settings, color: data.current.primary) + child: comfortatext(hour.time, 17, data.settings, color: data.current.surface) ) ], ); diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 2c4f160..6a63ef9 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -187,7 +187,7 @@ class _NewSunriseSunsetState extends State child: Align( alignment: Alignment.centerLeft, child: comfortatext(write, 15, widget.data.settings, - color: widget.data.palette.onSurface, + color: widget.data.current.onSurface, weight: FontWeight.w500), ), ), @@ -202,7 +202,7 @@ class _NewSunriseSunsetState extends State height: 4, width: 4, decoration: BoxDecoration( - color: widget.data.palette.primaryFixedDim, + color: widget.data.current.primaryLight, borderRadius: BorderRadius.circular(20), ), ), @@ -214,8 +214,8 @@ class _NewSunriseSunsetState extends State child: CustomPaint( painter: WavePainter( _controller.value, - widget.data.palette.primaryFixedDim, - darken(widget.data.palette.surfaceVariant, 0.03), + widget.data.current.primaryLight, + darken(widget.data.current.surfaceVariant, 0.03), progress), child: Container( width: double.infinity, @@ -231,23 +231,23 @@ class _NewSunriseSunsetState extends State padding: const EdgeInsets.only(right: 4), child: Icon( Icons.wb_sunny_outlined, - color: widget.data.palette.primaryFixedDim, + color: widget.data.current.primaryLight, size: 14, ), ), comfortatext( widget.data.sunstatus.sunrise, 15, widget.data.settings, - color: widget.data.palette.primaryFixedDim, + color: widget.data.current.primaryLight, weight: FontWeight.w500), const Spacer(), comfortatext( widget.data.sunstatus.sunset, 15, widget.data.settings, - color: widget.data.palette.outline, + color: widget.data.current.outline, weight: FontWeight.w500), Padding( padding: const EdgeInsets.only(left: 4), child: Icon(Icons.nightlight_outlined, - color: widget.data.palette.outline, size: 14), + color: widget.data.current.outline, size: 14), ), ], ), @@ -273,14 +273,14 @@ Widget NewAirQuality(var data) { translation('air quality', data.settings["Language"]), 16, data.settings, - color: data.palette.onSurface), + color: data.current.onSurface), const Spacer(), Padding( padding: const EdgeInsets.only(right: 5), child: Icon( Icons.arrow_forward, size: 16, - color: data.palette.onSurface, + color: data.current.onSurface, ), ) ], @@ -293,13 +293,13 @@ Widget NewAirQuality(var data) { child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), - color: data.palette.surfaceContainerLow), + color: data.current.containerLow), width: 65, height: 65, child: Center( child: comfortatext( data.aqi.aqi_index.toString(), 32, data.settings, - color: data.palette.primaryFixedDim)), + color: data.current.primaryLight)), ), ), Expanded( @@ -312,7 +312,7 @@ Widget NewAirQuality(var data) { data.aqi.aqi_title, 20, data.settings, - color: data.palette.primaryFixedDim, + color: data.current.primaryLight, align: TextAlign.left, weight: FontWeight.w600, ), @@ -320,7 +320,7 @@ Widget NewAirQuality(var data) { Padding( padding: const EdgeInsets.all(3.0), child: comfortatext(data.aqi.aqi_desc, 14, data.settings, - color: data.palette.onSurface, weight: FontWeight.w500), + color: data.current.onSurface, weight: FontWeight.w500), ), ], ), @@ -351,7 +351,7 @@ Widget NewRain15MinuteIndicator(var data) { padding: const EdgeInsets.only(left: 21, right: 21, top: 23, bottom: 15), child: Container( decoration: BoxDecoration( - color: data.palette.surfaceContainerLow, + color: data.current.containerLow, borderRadius: BorderRadius.circular(18), ), padding: const EdgeInsets.all(18), @@ -366,16 +366,16 @@ Widget NewRain15MinuteIndicator(var data) { const EdgeInsets.only(left: 5, bottom: 2, right: 3), child: Icon( Icons.water_drop_outlined, - color: data.palette.primary, + color: data.current.primary, size: 20, ), ), comfortatext(data.minutely_15_precip.precip_sum.toStringAsFixed(1), 20, data.settings, - color: data.palette.primary, weight: FontWeight.w500), + color: data.current.primary, weight: FontWeight.w500), comfortatext( data.settings["Precipitation"], 20, data.settings, - color: data.palette.primary), + color: data.current.primary), Expanded( child: Padding( padding: const EdgeInsets.only(left: 8), @@ -383,7 +383,7 @@ Widget NewRain15MinuteIndicator(var data) { "rain expected in ${data.minutely_15_precip.t_minus}", 14, data.settings, - color: data.palette.onPrimaryContainer, weight: FontWeight.w500), + color: data.current.outline, weight: FontWeight.w500), ), ), ], @@ -405,7 +405,7 @@ Widget NewRain15MinuteIndicator(var data) { decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: data.minutely_15_precip.precips[index] == 0 - ? data.palette.primaryFixedDim : data.palette.primary, + ? data.current.primaryLight : data.current.primary, ), ), ); @@ -419,9 +419,9 @@ Widget NewRain15MinuteIndicator(var data) { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - comfortatext('now', 13, data.settings, color: data.palette.onPrimaryContainer), - comfortatext('3hr', 13, data.settings, color: data.palette.onPrimaryContainer), - comfortatext('6hr', 13, data.settings, color: data.palette.onPrimaryContainer) + comfortatext('now', 13, data.settings, color: data.current.outline), + comfortatext('3hr', 13, data.settings, color: data.current.outline), + comfortatext('6hr', 13, data.settings, color: data.current.outline) ], ), ) diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 33856cc..2863c9b 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -65,7 +65,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { Widget build(BuildContext context) { super.build(context); - Color highlight = state ? data.palette.surfaceContainerHigh : data.palette.surfaceContainer; + Color highlight = state ? data.current.containerHigh : data.current.container; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -77,7 +77,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { comfortatext( day.name, 16, data.settings, - color: data.palette.onSurface), + color: data.current.onSurface), const Spacer(), Visibility( visible: state, @@ -85,7 +85,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { padding: const EdgeInsets.only(right: 13), child: GestureDetector( child: Icon(Icons.expand_less, color: data - .palette.primaryFixedDim, size: 20), + .current.primaryLight, size: 20), onTap: () { onExpandTapped(index); }, @@ -101,10 +101,10 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { children: [ SizedBox( width: 35, - child: Icon(day.icon, size: 38.0 * day.iconSize, color: data.palette.primary,)), + child: Icon(day.icon, size: 38.0 * day.iconSize, color: data.current.primary,)), Padding( padding: const EdgeInsets.only(left: 12.0, top: 3), - child: comfortatext(day.text, 20, data.settings, color: data.palette.onSurface, + child: comfortatext(day.text, 20, data.settings, color: data.current.onSurface, weight: FontWeight.w400), ), const Spacer(), @@ -112,12 +112,12 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { padding: const EdgeInsets.only(top: 4), child: Row( children: [ - comfortatext(day.minmaxtemp.split("/")[0], 19, data.settings, color: data.palette.primary), + comfortatext(day.minmaxtemp.split("/")[0], 19, data.settings, color: data.current.primary), Padding( padding: const EdgeInsets.only(left: 5, right: 4), - child: comfortatext("/", 19, data.settings, color: data.palette.onSurface), + child: comfortatext("/", 19, data.settings, color: data.current.onSurface), ), - comfortatext(day.minmaxtemp.split("/")[1], 19, data.settings, color: data.palette.primary), + comfortatext(day.minmaxtemp.split("/")[1], 19, data.settings, color: data.current.primary), ], ), ) @@ -130,8 +130,8 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { height: 85, padding: const EdgeInsets.only(top: 8, bottom: 8, left: 10, right: 10), decoration: BoxDecoration( - //border: Border.all(width: 1, color: data.palette.outline), - color: state ? data.palette.surfaceContainer : data.palette.surfaceContainerLow, + //border: Border.all(width: 1, color: data.current.outline), + color: state ? data.current.container : data.current.containerLow, borderRadius: BorderRadius.circular(18), ), child: LayoutBuilder( @@ -151,11 +151,11 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.water_drop_outlined, - color: data.palette.primaryFixedDim, size: 21), + color: data.current.primaryLight, size: 21), Padding( padding: const EdgeInsets.only(left: 10, top: 3), child: comfortatext('${day.precip_prob}%', 18, data.settings, - color: data.palette.primary), + color: data.current.primary), ), ], ), @@ -167,12 +167,12 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( - Icons.water_drop, color: data.palette.primaryFixedDim, size: 21), + Icons.water_drop, color: data.current.primaryLight, size: 21), Padding( padding: const EdgeInsets.only(top: 3, left: 10), child: comfortatext(day.total_precip.toString() + data.settings["Precipitation"], 18, data.settings, - color: data.palette.primary), + color: data.current.primary), ), ], ), @@ -184,19 +184,19 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( - CupertinoIcons.wind, color: data.palette.primaryFixedDim, size: 21,), + CupertinoIcons.wind, color: data.current.primaryLight, size: 21,), Padding( padding: const EdgeInsets.only(top: 3, left: 10), child: comfortatext('${day.windspeed} ${data .settings["Wind"]}', 18, data.settings, - color: data.palette.primary), + color: data.current.primary), ), Padding( padding: const EdgeInsets.only(left: 5, right: 3), child: RotationTransition( turns: AlwaysStoppedAnimation(day.wind_dir / 360), child: Icon(CupertinoIcons.arrow_down_circle, - color: data.palette.primaryFixedDim, size: 18,) + color: data.current.primaryLight, size: 18,) ) ), ], @@ -209,11 +209,11 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(CupertinoIcons.sun_max, - color: data.palette.primaryFixedDim, size: 21), + color: data.current.primaryLight, size: 21), Padding( padding: const EdgeInsets.only(top: 3, left: 10), child: comfortatext('${day.uv} UV', 18, data.settings, - color: data.palette.primary), + color: data.current.primary), ), ], ), @@ -235,31 +235,23 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { return ChoiceChip( elevation: 0.0, - checkmarkColor: data.palette.onPrimaryFixed, + checkmarkColor: data.current.onPrimaryLight, color: WidgetStateProperty.resolveWith((states) { if (index == _value) { - return data.palette.primaryFixedDim; + return data.current.primaryLight; } - return state ? data.palette.surfaceContainerLow : data.palette.surface; + return state ? data.current.containerLow : data.current.surface; }), - side: BorderSide(color: data.palette.primaryFixedDim, width: 1.0), + side: BorderSide(color: data.current.primaryLight, width: 1.0), label: comfortatext( ['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, - color: _value == index ? data.palette.onPrimaryFixed : data.palette.onSurface), + color: _value == index ? data.current.onPrimaryLight : data.current.onSurface), selected: _value == index, onSelected: (bool selected) { - //setState(() { - // updateChip(index); - //}); _value = index; setState(() { _onItemTapped(index); }); - /* - setState(() { - _onItemTapped(index); - }); - */ }, ); }, @@ -272,8 +264,8 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { controller: _pageController, children: [ buildTemp(day.hourly, data, highlight), - buildPrecip(day.hourly, data, data.palette.surfaceContainerHigh), - WindReport(hours: day.hourly, data: data, highlight: data.palette.surfaceContainerHigh,), + buildPrecip(day.hourly, data, data.current.containerHigh), + WindReport(hours: day.hourly, data: data, highlight: data.current.containerHigh,), buildUV(day.hourly, data, highlight), ], ), @@ -293,7 +285,7 @@ Widget buildNewDays(data) { final day = data.days[index]; return Padding( padding: const EdgeInsets.only(bottom: 10), - child: NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.backcolor}"), + child: NewDay(data: data, index: index, key: Key("${data.place}, ${data.current.surface}"), state: false, onExpandTapped: null, day: day,), ); }, @@ -311,7 +303,7 @@ Widget buildTemp(List hours, data, Color highlight) => ListView( children: [ Padding( padding: const EdgeInsets.only(top: 10, bottom: 10), - child: comfortatext('${hour.temp}°', 19, data.settings, color: data.palette.primary), + child: comfortatext('${hour.temp}°', 19, data.settings, color: data.current.primary), ), Stack( alignment: Alignment.bottomCenter, @@ -321,7 +313,7 @@ Widget buildTemp(List hours, data, Color highlight) => ListView( height: 105, decoration: BoxDecoration( color: highlight, - //border: Border.all(color: data.palette.outline,), + //border: Border.all(color: data.current..outline,), borderRadius: const BorderRadius.all(Radius.circular(20)) ), ), @@ -329,8 +321,8 @@ Widget buildTemp(List hours, data, Color highlight) => ListView( width: 13, height: hour.raw_temp * 1.8 + 30, decoration: BoxDecoration( - color: data.palette.primaryFixedDim, - //border: Border.all(color: data.palette.primaryFixedDim, width: 2), + color: data.current.primaryLight, + //border: Border.all(color: data.current.primaryLight, width: 2), borderRadius: const BorderRadius.all(Radius.circular(20)) ), ), @@ -342,14 +334,14 @@ Widget buildTemp(List hours, data, Color highlight) => ListView( height: 30, child: Icon( hour.icon, - color: data.palette.primary, + color: data.current.primary, size: 31.0 * hour.iconSize, ), ) ), Padding( padding: const EdgeInsets.only(top:13), - child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) + child: comfortatext(hour.time, 15, data.settings, color: data.current.onSurface) ) ], ), @@ -379,7 +371,7 @@ class WindChartPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final paint = Paint() - ..color = data.palette.primaryFixedDim + ..color = data.current.primaryLight ..strokeWidth = 2.0; final smallDotPaint = Paint() @@ -402,7 +394,7 @@ class WindChartPainter extends CustomPainter { style: TextStyle( fontSize: dotRadius * 2, fontFamily: Icons.arrow_forward.fontFamily, - color: data.palette.primary, + color: data.current.primary, ), ); textPainter.layout(); @@ -475,9 +467,9 @@ class WindReport extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - comfortatext('${hour.wind}', 18, data.settings, color: data.palette.primary, + comfortatext('${hour.wind}', 18, data.settings, color: data.current.primary, weight: FontWeight.w500), - comfortatext('${data.settings["Wind"]}', 9, data.settings, color: data.palette.primary), + comfortatext('${data.settings["Wind"]}', 9, data.settings, color: data.current.primary), ], ), ), @@ -490,14 +482,14 @@ class WindReport extends StatelessWidget { height: 30, child: Icon( hour.icon, - color: data.palette.primary, + color: data.current.primary, size: 31.0 * hour.iconSize, ), ) ), Padding( padding: const EdgeInsets.only(top:13), - child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) + child: comfortatext(hour.time, 15, data.settings, color: data.current.onSurface) ) ], ), @@ -522,7 +514,7 @@ Widget buildUV(List hours, data, highlight) => ListView( children: [ Padding( padding: const EdgeInsets.only(top: 10, bottom: 15), - child: comfortatext('${hour.uv}', 19, data.settings, color: data.palette.primary), + child: comfortatext('${hour.uv}', 19, data.settings, color: data.current.primary), ), SizedBox( height: 105, @@ -551,7 +543,7 @@ Widget buildUV(List hours, data, highlight) => ListView( height: 5, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: data.palette.primaryFixedDim, + color: data.current.primaryLight, ), ), ); @@ -565,14 +557,14 @@ Widget buildUV(List hours, data, highlight) => ListView( height: 30, child: Icon( hour.icon, - color: data.palette.primary, + color: data.current.primary, size: 31.0 * hour.iconSize, ), ) ), Padding( padding: const EdgeInsets.only(top:13), - child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) + child: comfortatext(hour.time, 15, data.settings, color: data.current.onSurface) ) ], ), @@ -595,9 +587,9 @@ Widget buildPrecip(List hours, data, Color highlight) => ListView( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - comfortatext('${hour.precip}', 18, data.settings, color: data.palette.primary, + comfortatext('${hour.precip}', 18, data.settings, color: data.current.primary, weight: FontWeight.w500), - comfortatext('${data.settings["Precipitation"]}', 9, data.settings, color: data.palette.primary), + comfortatext('${data.settings["Precipitation"]}', 9, data.settings, color: data.current.primary), ], ), ), @@ -632,7 +624,7 @@ Widget buildPrecip(List hours, data, Color highlight) => ListView( child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: data.palette.primaryFixedDim, + color: data.current.primaryLight, ), ), ); @@ -646,14 +638,14 @@ Widget buildPrecip(List hours, data, Color highlight) => ListView( height: 30, child: Icon( hour.icon, - color: data.palette.primary, + color: data.current.primary, size: 31.0 * hour.iconSize, ), ) ), Padding( padding: const EdgeInsets.only(top:13), - child: comfortatext(hour.time, 15, data.settings, color: data.palette.onSurface) + child: comfortatext(hour.time, 15, data.settings, color: data.current.onSurface) ) ], ), @@ -709,7 +701,7 @@ class _buildNewGlanceDayState extends State with AutomaticKee child: comfortatext( "daily", 16, data.settings, - color: data.palette.onSurface), + color: data.current.onSurface), ), ), ListView.builder( @@ -723,7 +715,7 @@ class _buildNewGlanceDayState extends State with AutomaticKee return Padding( padding: const EdgeInsets.only(top: 3, bottom: 3), child: AnimatedContainer( - height: expand[index] ? 540.0 : 73.0, + height: expand[index] ? 528.0 : 73.0, duration: const Duration(milliseconds:250), child: SingleChildScrollView( physics: const NeverScrollableScrollPhysics(), @@ -737,7 +729,7 @@ class _buildNewGlanceDayState extends State with AutomaticKee .vertical(bottom: Radius.circular(18.0), top: Radius.circular(8)) : BorderRadius.circular(8), - color: data.palette.surfaceContainerLow), + color: data.current.containerLow), child: Padding( padding: const EdgeInsets.only(top: 25, left: 3, right: 3), child: NewDay(data: data, index: index, state: true, @@ -768,7 +760,7 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { .vertical(bottom: Radius.circular(18.0), top: Radius.circular(8)) : BorderRadius.circular(8), - color: data.palette.surfaceContainerLow), + color: data.current.containerLow), child: Column( children: [ Row( @@ -784,10 +776,10 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { children: [ comfortatext(day.name.split(", ")[0], 18, data.settings, - color: data.palette.primary), + color: data.current.primary), comfortatext(day.name.split(", ")[1], 14, data.settings, - color: data.palette.onSurface), + color: data.current.onSurface), ], ), ), @@ -797,7 +789,7 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { width: 43, child: Icon( day.icon, - color: data.palette.primary, + color: data.current.primary, size: 31.0 * day.iconSize, ), ), @@ -809,8 +801,8 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { width: 43, decoration: BoxDecoration( borderRadius: BorderRadius.circular(13), - //border: Border.all(width: 1.5, color: data.palette.primaryFixedDim) - color: data.palette.primaryFixedDim + //border: Border.all(width: 1.5, color: data.current.primaryLight) + color: data.current.primaryLight ), child: Row( children: [ @@ -821,11 +813,11 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { padding: const EdgeInsets.only( bottom: 2), child: Icon(Icons.keyboard_arrow_up, - color: data.palette.shadow, + color: data.current.onPrimaryLight, size: 14,), ), Icon(Icons.keyboard_arrow_down, - color: data.palette.shadow, size: 14,), + color: data.current.onPrimaryLight, size: 14,), ], ), Expanded( @@ -839,12 +831,12 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { child: comfortatext( day.minmaxtemp.split("/")[1], 14, data.settings, - color: data.palette.shadow), + color: data.current.onPrimaryLight), ), comfortatext( day.minmaxtemp.split("/")[0], 14, data.settings, - color: data.palette.shadow), + color: data.current.onPrimaryLight), ], ), ), @@ -862,7 +854,7 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.water_drop_outlined, - color: data.palette.primaryFixedDim, + color: data.current.primaryLight, size: 18,), Padding( padding: const EdgeInsets.only( @@ -870,11 +862,11 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { child: comfortatext( '${day.precip_prob}%', 17, data.settings, - color: data.palette.onSurface), + color: data.current.onSurface), ), Icon( Icons.water_drop, - color: data.palette.primaryFixedDim, + color: data.current.primaryLight, size: 18,), Padding( padding: const EdgeInsets.only( @@ -883,7 +875,7 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { day.total_precip.toString() + data.settings["Precipitation"], 17, data.settings, - color: data.palette.onSurface), + color: data.current.onSurface), ), ], ), @@ -893,7 +885,7 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { children: [ Icon( CupertinoIcons.wind, - color: data.palette.primaryFixedDim, + color: data.current.primaryLight, size: 18,), Padding( padding: const EdgeInsets.only( @@ -902,7 +894,7 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { '${day.windspeed} ${data .settings["Wind"]}', 17, data.settings, - color: data.palette.onSurface), + color: data.current.onSurface), ), Padding( padding: const EdgeInsets.only( @@ -912,7 +904,7 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { day.wind_dir / 360), child: Icon( CupertinoIcons.arrow_down_circle, - color: data.palette.primary, + color: data.current.primary, size: 16,) ) ), @@ -925,7 +917,7 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { padding: const EdgeInsets.only(right: 17), child: GestureDetector( child: Icon(Icons.expand_more, color: data - .palette.primaryFixedDim, size: 20,), + .current.primaryLight, size: 20,), onTap: () { onExpandTapped(index); }, diff --git a/lib/radar.dart b/lib/radar.dart index f85ff44..9d37eb4 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -80,7 +80,7 @@ class _RadarMapState extends State { child: Align( alignment: Alignment.centerLeft, child: comfortatext(translation('radar', data.settings["Language"]), 19, data.settings, - color: data.current.textcolor), + color: data.current.onSurface), ), ), Padding( @@ -156,7 +156,7 @@ class _RadarMapState extends State { MaterialPageRoute(builder: (context) => RadarPage(data: data,)), ); }, - child: Icon(Icons.open_in_full, color: data.current.primary, size: 25,), + child: Icon(Icons.open_in_full, color: data.current.surface, size: 25,), ), ), ), @@ -300,8 +300,8 @@ class _RadarPageState extends State { @override Widget build(BuildContext context) { double x = MediaQuery.of(context).padding.top; - Color main = data.current.textcolor; - Color top = lighten(data.current.highlight, 0.1); + Color main = data.current.onSurface; + Color top = lighten(data.current.container, 0.1); return Stack( children: [ FlutterMap( @@ -533,7 +533,7 @@ class _RadarSmallState extends State { child: comfortatext( translation('radar', data.settings["Language"]), 16, data.settings, - color: data.palette.onSurface), + color: data.current.onSurface), ), ), Padding( @@ -543,10 +543,10 @@ class _RadarSmallState extends State { aspectRatio: 1.57, child: Container( decoration: BoxDecoration( - color: data.palette.surface, + color: data.current.surface, borderRadius: BorderRadius.circular(18), border: Border.all( - width: 2.2, color: data.palette.surfaceContainerHigh) + width: 2.2, color: data.current.containerHigh) ), child: Stack( children: [ @@ -604,7 +604,7 @@ class _RadarSmallState extends State { style: ElevatedButton.styleFrom( padding: const EdgeInsets.all(10), elevation: 0.0, - backgroundColor: data.palette.surfaceContainer, + backgroundColor: data.current.container, //side: BorderSide(width: 3, color: main), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15) @@ -618,7 +618,7 @@ class _RadarSmallState extends State { ); }, child: Icon(CupertinoIcons.fullscreen, - color: data.palette.primaryFixedDim, size: 20,), + color: data.current.primaryLight, size: 20,), ), ), ), @@ -648,17 +648,17 @@ class _RadarSmallState extends State { style: ElevatedButton.styleFrom( elevation: 0.0, padding: const EdgeInsets.all(10), - backgroundColor: data.palette.surfaceContainer, + backgroundColor: data.current.container, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), - //side: BorderSide(width: 2, color: data.palette.primaryFixed) + //side: BorderSide(width: 2, color: data.current.primaryLighter) ) ), onPressed: () async { togglePlayPause(); }, child: Icon(isPlaying ? Icons.pause_outlined : Icons.play_arrow, - color: data.palette.primaryFixedDim, size: 18,), + color: data.current.primaryLight, size: 18,), ), ), @@ -674,7 +674,7 @@ class _RadarSmallState extends State { data: SliderTheme.of(context).copyWith( trackHeight: 18, valueIndicatorTextStyle: GoogleFonts.comfortaa( - color: data.palette.shadow, + color: data.current.onSurface, fontSize: 12, fontWeight: FontWeight.w500, ), @@ -695,9 +695,9 @@ class _RadarSmallState extends State { label: times[currentFrameIndex.toInt()] .toString(), - activeColor: data.palette.primaryFixed, - inactiveColor: data.palette.surface, - //thumbColor: data.palette.primary, + activeColor: data.current.primaryLighter, + inactiveColor: data.current.surface, + //thumbColor: data.current.primary, onChanged: (double value) { setState(() { @@ -711,26 +711,26 @@ class _RadarSmallState extends State { padding: const EdgeInsets.only(left: 16, right: 16, top: 9), child: Row( children: [ - comfortatext('-2hr', 13, data.settings, color: data.palette.onSurface), + comfortatext('-2hr', 13, data.settings, color: data.current.onSurface), Expanded( flex: 6, child: Align( alignment: Alignment.centerRight, - child: comfortatext('-1hr', 13, data.settings, color: data.palette.onSurface) + child: comfortatext('-1hr', 13, data.settings, color: data.current.onSurface) ), ), Expanded( flex: 6, child: Align( alignment: Alignment.centerRight, - child: comfortatext('now', 13, data.settings, color: data.palette.onSurface) + child: comfortatext('now', 13, data.settings, color: data.current.onSurface) ), ), Expanded( flex: 3, child: Align( alignment: Alignment.centerRight, - child: comfortatext('30m', 13, data.settings, color: data.palette.onSurface) + child: comfortatext('30m', 13, data.settings, color: data.current.onSurface) ), ), ], @@ -851,7 +851,7 @@ class _RadarBigState extends State { height: 100, decoration: BoxDecoration( borderRadius: BorderRadius.circular(18), - color: data.palette.surface, + color: data.current.surface, ), child: Padding( padding: const EdgeInsets.only(left: 24, right: 12), @@ -873,17 +873,17 @@ class _RadarBigState extends State { style: ElevatedButton.styleFrom( elevation: 0.0, padding: const EdgeInsets.all(10), - backgroundColor: data.palette.surfaceContainer, + backgroundColor: data.current.container, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), - //side: BorderSide(width: 2, color: data.palette.primaryFixed) + //side: BorderSide(width: 2, color: data.current.primaryLighter) ) ), onPressed: () async { togglePlayPause(); }, child: Icon(isPlaying ? Icons.pause_outlined : Icons.play_arrow, - color: data.palette.primaryFixedDim, size: 18,), + color: data.current.primaryLight, size: 18,), ), ), @@ -900,7 +900,7 @@ class _RadarBigState extends State { data: SliderTheme.of(context).copyWith( trackHeight: 18, valueIndicatorTextStyle: GoogleFonts.comfortaa( - color: data.palette.shadow, + color: data.current.onSurface, fontSize: 12, fontWeight: FontWeight.w500, ), @@ -921,9 +921,9 @@ class _RadarBigState extends State { label: times[currentFrameIndex.toInt()] .toString(), - activeColor: data.palette.primaryFixed, - inactiveColor: data.palette.surface, - //thumbColor: data.palette.primary, + activeColor: data.current.primaryLighter, + inactiveColor: data.current.surface, + //thumbColor: data.current.primary, onChanged: (double value) { setState(() { @@ -937,26 +937,26 @@ class _RadarBigState extends State { padding: const EdgeInsets.only(left: 16, right: 16, top: 9), child: Row( children: [ - comfortatext('-2hr', 13, data.settings, color: data.palette.onPrimaryContainer), + comfortatext('-2hr', 13, data.settings, color: data.current.onSurface), Expanded( flex: 6, child: Align( alignment: Alignment.centerRight, - child: comfortatext('-1hr', 13, data.settings, color: data.palette.onPrimaryContainer) + child: comfortatext('-1hr', 13, data.settings, color: data.current.onSurface) ), ), Expanded( flex: 6, child: Align( alignment: Alignment.centerRight, - child: comfortatext('now', 13, data.settings, color: data.palette.onPrimaryContainer) + child: comfortatext('now', 13, data.settings, color: data.current.onSurface) ), ), Expanded( flex: 3, child: Align( alignment: Alignment.centerRight, - child: comfortatext('30m', 13, data.settings, color: data.palette.onPrimaryContainer) + child: comfortatext('30m', 13, data.settings, color: data.current.onSurface) ), ), ], @@ -984,7 +984,7 @@ class _RadarBigState extends State { style: ElevatedButton.styleFrom( padding: const EdgeInsets.all(10), elevation: 0.0, - backgroundColor: data.palette.surface, + backgroundColor: data.current.surface, //side: BorderSide(width: 3, color: main), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15) @@ -994,7 +994,7 @@ class _RadarBigState extends State { Navigator.of(context).pop(); }, child: Icon(CupertinoIcons.fullscreen_exit, - color: data.palette.primaryFixedDim, size: 21,), + color: data.current.primaryLight, size: 21,), ), ), ), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index f281826..e047a1c 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -120,52 +120,89 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { String x = force == "-1" ? settings["Color mode"] : force; + //surface + //primary + //primaryLight + //primaryLighter + //onSurface + //outline + //containerLow + //container + //containerHigh + //surfaceVariant + //onPrimaryLight + List colors = [ palette.onPrimaryFixedVariant, palette.tertiary, - WHITE, - palette.onPrimaryFixedVariant, - WHITE, - darken(palette.onPrimaryFixedVariant, 0.07) + palette.tertiaryFixed, + palette.secondaryFixed, + palette.onSurface, + palette.outline, + darken2(palette.onPrimaryFixedVariant, 0.09), + darken2(palette.onPrimaryFixedVariant, 0.15), + darken2(palette.onPrimaryFixedVariant, 0.2), + darken2(palette.onPrimaryFixedVariant, 0.1), + palette.onTertiaryFixed, ]; if (x == "monochrome") { colors = [ - palette.onPrimaryFixedVariant, - WHITE, - WHITE, - palette.onPrimaryFixedVariant, - WHITE, - darken(palette.onPrimaryFixedVariant, 0.07) + palette.surface, + palette.primary, + palette.primaryFixedDim, + palette.primaryFixed, + palette.onSurface, + palette.outline, + palette.surfaceContainerLow, + palette.surfaceContainer, + palette.surfaceContainerHigh, + palette.surfaceContainerHighest, + palette.onPrimaryFixed, ]; } else if (x == "colorful") { colors = [ - palette.primaryContainer, - palette.tertiary, - palette.onPrimaryContainer, - palette.primaryContainer, - palette.onPrimaryContainer, - darken(palette.primaryContainer, 0.1) + palette.surface, + palette.primary, + palette.primaryFixedDim, + palette.primaryFixed, + palette.onSurface, + palette.outline, + palette.surfaceContainerLow, + palette.surfaceContainer, + palette.surfaceContainerHigh, + palette.surfaceContainerHighest, + palette.onPrimaryFixed, ]; } else if (x == "light") { colors = [ palette.surface, - palette.primaryFixedDim, palette.primary, palette.primaryFixedDim, + palette.primaryFixed, + palette.onSurface, + palette.outline, + palette.surfaceContainerLow, + palette.surfaceContainer, + palette.surfaceContainerHigh, + palette.surfaceContainerHighest, palette.onPrimaryFixed, - palette.primaryContainer ]; } else if (x == "dark") { colors = [ palette.surface, - palette.primaryFixedDim, - palette.secondary, - palette.primaryFixedDim, + palette.primary, + palette.primaryFixed, + palette.primaryFixed, + palette.onSurface, + palette.outline, + palette.surfaceContainerLow, + palette.surfaceContainer, + palette.surfaceContainerHigh, + palette.surfaceContainerHighest, palette.onPrimaryFixed, - palette.primaryContainer ]; } return colors; diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index c196dd6..fd8c90a 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -208,13 +208,13 @@ class _FadingWidgetState extends State { children: [ Padding( padding: const EdgeInsets.only(right: 3), - child: Icon(Icons.access_time, color: widget.data.current.textcolor, size: 13,), + child: Icon(Icons.access_time, color: widget.data.current.primary, size: 13,), ), comfortatext('${split[0]},', 13, widget.data.settings, - color: widget.data.current.textcolor, weight: FontWeight.w500), + color: widget.data.current.primary, weight: FontWeight.w500), comfortatext(split.length > 1 ?split[1] : "", 13, widget.data.settings, - color: widget.data.current.primary, weight: FontWeight.w500), + color: widget.data.current.onSurface, weight: FontWeight.w500), ], ), ), @@ -310,7 +310,7 @@ Widget NewAqiDataPoints(String name, double value, var data) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - comfortatext(name, 15, data.settings, color: data.palette.primary, + comfortatext(name, 15, data.settings, color: data.current.primary, align: TextAlign.end), Padding( padding: const EdgeInsets.all(3.0), @@ -319,11 +319,11 @@ Widget NewAqiDataPoints(String name, double value, var data) { height: 2.5, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: data.palette.primaryFixedDim, + color: data.current.primaryLight, ), ), ), - comfortatext(value.toString(), 15, data.settings, color: data.palette.primaryFixedDim, + comfortatext(value.toString(), 15, data.settings, color: data.current.primaryLight, align: TextAlign.end, weight: FontWeight.w600), ], ); @@ -346,18 +346,18 @@ Widget aqiDataPoints(String name, double value, var data) { padding: const EdgeInsets.only(left: 10, bottom: 1.5, top: 1.5), child: Row( children: [ - comfortatext(name, 18, data.settings, color: data.current.textcolor, + comfortatext(name, 18, data.settings, color: data.current.outline, weight: FontWeight.w400), const Spacer(), Container( padding: const EdgeInsets.only(top:4,bottom: 3, left: 4, right: 4), decoration: BoxDecoration( //border: Border.all(color: Colors.blueAccent) - color: data.current.primary, + color: data.current.surface, borderRadius: BorderRadius.circular(10) ), child: comfortatext(value.toString(), 17, data.settings, - color: data.current.highlight, weight: FontWeight.w600) + color: data.current.container, weight: FontWeight.w600) ) ], ), @@ -578,7 +578,7 @@ class BarChartPainter extends CustomPainter { void paint(Canvas canvas, Size size) { Paint paint = Paint() - ..color = data.current.primary + ..color = data.current.surface ..style = PaintingStyle.fill; double maxValue = 10; From b21a76e0636663b50a1aeb27944202add625830c Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 8 Aug 2024 19:42:27 +0200 Subject: [PATCH 069/129] working on all themes --- lib/decoders/decode_OM.dart | 2 +- lib/decoders/decode_wapi.dart | 2 +- lib/decoders/extra_info.dart | 24 +++++++++++++----------- lib/main_screens.dart | 25 ++++++++++++++----------- lib/new_displays.dart | 8 ++++---- lib/search_screens.dart | 15 ++++++++------- 6 files changed, 41 insertions(+), 35 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 7944a2c..22fd870 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -638,7 +638,7 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as oMBody["current"]["weather_code"], sunstatus, real_time), real_loc, lat, lng); //GET COLORS - List imageColors = await getImageColors(Uimage, settings["Color mode"]); + List imageColors = await getImageColors(Uimage, settings["Color mode"], settings); return WeatherData( radar: await RainviewerRadar.getData(), diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index 80a0992..805babf 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -524,7 +524,7 @@ Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) Image Uimage = await getUnsplashImage(text, real_loc, lat, lng); //GET COLORS - List imageColors = await getImageColors(Uimage, settings["Color mode"]); + List imageColors = await getImageColors(Uimage, settings["Color mode"], settings); //String real_time = wapi_body["location"]["localtime"]; int epoch = wapi_body["location"]["localtime_epoch"]; diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 991ece0..4931660 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -24,6 +24,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:overmorrow/decoders/decode_OM.dart'; +import 'package:overmorrow/settings_page.dart'; import 'package:palette_generator/palette_generator.dart'; import '../api_key.dart'; @@ -146,7 +147,7 @@ Future MaterialYouColor(String theme) async { return palette; } -Future getImageColors(Image Uimage, color_mode) async { +Future getImageColors(Image Uimage, color_mode, settings) async { final PaletteGenerator pali = await _generatorPalette(Uimage); //var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; @@ -155,31 +156,33 @@ Future getImageColors(Image Uimage, color_mode) async { final ColorScheme palette = (await _materialPalette(Uimage, color_mode)); + final List used_colors = getNetworkColors(palette, settings); + final List dominant = pali.colors.toList(); - Color startcolor = palette.tertiaryFixedDim; + Color startcolor = used_colors[2]; - Color bestcolor = palette.tertiaryFixedDim; + Color bestcolor = used_colors[2]; int bestDif = difFromBackColors(bestcolor, dominant); - int base = diffBetweenBackColors(dominant); + int base = (diffBetweenBackColors(dominant) * 0.7).round(); print(("base", base)); if (bestDif <= base + 50) { print("trying"); for (int i = 1; i < 4; i++) { //LIGHT - Color newcolor = lighten(startcolor, i / 13); + Color newcolor = lighten(startcolor, i / 20); int newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < base + 200) { + if (newdif > bestDif && newdif < base + 150) { bestDif = newdif; bestcolor = newcolor; } //DARK - newcolor = darken(startcolor, i / 7); + newcolor = darken(startcolor, i / 20); newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < base + 200) { + if (newdif > bestDif && newdif < base + 150) { bestDif = newdif; bestcolor = newcolor; } @@ -199,7 +202,7 @@ Future getImageColors(Image Uimage, color_mode) async { } } - Color desc_color = palette.onPrimaryFixedVariant; + Color desc_color = used_colors[0]; int desc_dif = difFromBackColors(desc_color, dominant); print(("diffs", bestDif, desc_dif)); @@ -230,8 +233,7 @@ int diffBetweenBackColors(List backcolors) { } } } - return 1; - //return (diff_sum / (backcolors.length * (backcolors.length - 1))).round(); + return (diff_sum / (backcolors.length * (backcolors.length - 1))).round(); } int difBetweenTwoColors(Color color1, Color color2) { diff --git a/lib/main_screens.dart b/lib/main_screens.dart index cbdb869..359eade 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -67,7 +67,7 @@ class _NewMainState extends State { await updateLocation("${data.lat}, ${data.lng}", data.real_loc); }, headerData: HeaderData( - //backgroundColor: WHITE, + //backgroundColor: WHITE, blurContent: false, headerHeight: max(size.height * 0.53, 400), //we don't want it to be smaller than 400 @@ -105,16 +105,19 @@ class _NewMainState extends State { ], ), ), - MySearchParent(updateLocation: updateLocation, - color: data.current.surface, - place: data.place, - controller: controller, - settings: data.settings, - real_loc: data.real_loc, - secondColor: data.current.primaryLight, - textColor: data.current.primary, - highlightColor: data.current.containerLow, - key: Key("${data.place}, ${data.current.surface}"),), + Container( + padding: EdgeInsets.zero, + child: MySearchParent(updateLocation: updateLocation, + color: data.current.surface, + place: data.place, + controller: controller, + settings: data.settings, + real_loc: data.real_loc, + secondColor: data.current.primaryLight, + textColor: data.current.primary, + highlightColor: data.current.container, + key: Key("${data.place}, ${data.current.surface}"),), + ), ], ) ), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 6a63ef9..38f7cc8 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -383,7 +383,7 @@ Widget NewRain15MinuteIndicator(var data) { "rain expected in ${data.minutely_15_precip.t_minus}", 14, data.settings, - color: data.current.outline, weight: FontWeight.w500), + color: data.current.onSurface, weight: FontWeight.w500), ), ), ], @@ -419,9 +419,9 @@ Widget NewRain15MinuteIndicator(var data) { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - comfortatext('now', 13, data.settings, color: data.current.outline), - comfortatext('3hr', 13, data.settings, color: data.current.outline), - comfortatext('6hr', 13, data.settings, color: data.current.outline) + comfortatext('now', 13, data.settings, color: data.current.onSurface), + comfortatext('3hr', 13, data.settings, color: data.current.onSurface), + comfortatext('6hr', 13, data.settings, color: data.current.onSurface) ], ), ) diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 2786dbe..7b34712 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -58,14 +58,15 @@ Widget searchBar(Color color, List recommend, ), margins: secondColor == highlightColor ? const EdgeInsets.only(left: 10, right: 10, top: 20) - : EdgeInsets.only(left: 10, right: 10, top: MediaQuery.of(context).padding.top + 15), + : EdgeInsets.only(left: 17, right: 17, top: MediaQuery.of(context).padding.top + 15), borderRadius: BorderRadius.circular(23), backgroundColor: color, - accentColor: secondColor, + accentColor: color, + elevation: 0, - height: 60, + height: 62, scrollPadding: const EdgeInsets.only(top: 16, bottom: 56), transitionDuration: const Duration(milliseconds: 800), transitionCurve: Curves.easeInOut, @@ -111,7 +112,7 @@ Widget searchBar(Color color, List recommend, showIfOpened: false, showIfClosed: true, child: IconButton( - icon: Icon(Icons.menu, color: secondColor, size: 26,), + icon: Icon(Icons.menu_rounded, color: secondColor, size: 25,), onPressed: () { Scaffold.of(context).openDrawer(); }, @@ -389,16 +390,16 @@ Widget LocationButton(Function updateProg, Function updateLocation, Color color, Color secondColor, Color textColor) { if (real_loc == 'CurrentLocation') { return Padding( - padding: const EdgeInsets.only(right: 6, top: 3, bottom: 3), + padding: const EdgeInsets.only(right: 6.5, top: 4, bottom: 4), child: AspectRatio( aspectRatio: 1, child: ElevatedButton( style: ElevatedButton.styleFrom( elevation: 0, padding: const EdgeInsets.all(10), - backgroundColor: textColor, + backgroundColor: secondColor, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20) + borderRadius: BorderRadius.circular(19) ) ), onPressed: () async {}, From 53853f1d0a14cbb34072e08cbcd6c39bf787e336 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 8 Aug 2024 20:11:39 +0200 Subject: [PATCH 070/129] updated search bar a bit --- lib/main_screens.dart | 6 ++-- lib/search_screens.dart | 80 +++++++++++++++++++++++------------------ lib/ui_helper.dart | 25 ++++++++----- 3 files changed, 66 insertions(+), 45 deletions(-) diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 359eade..3dd6227 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -116,7 +116,8 @@ class _NewMainState extends State { secondColor: data.current.primaryLight, textColor: data.current.primary, highlightColor: data.current.container, - key: Key("${data.place}, ${data.current.surface}"),), + key: Key("${data.place}, ${data.current.surface}"), + extraTextColor: data.current.onSurface,), ), ], ) @@ -267,7 +268,8 @@ Widget TabletLayout(data, updateLocation, context) { color: data.current.container, place: data.place, controller: controller, settings: data.settings, real_loc: data.real_loc, secondColor: data.current.surface, textColor: data.current.outline, - highlightColor: data.current.surface, key: Key("${data.place}, ${data.current.surface}"),), + highlightColor: data.current.surface, key: Key("${data.place}, ${data.current.surface}"), + extraTextColor: data.current.onSurface,), ], ), ), diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 7b34712..62fa03c 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -21,6 +21,7 @@ import 'dart:math'; import 'dart:ui'; import 'dart:io'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -37,7 +38,7 @@ Widget searchBar(Color color, List recommend, Function updateIsEditing, bool isEditing, Function updateFav, List favorites, Function updateRec, String place, var context, bool prog, Function updateProg, Map settings, String real_loc, Color secondColor, - Color textColor, Color highlightColor) { + Color textColor, Color highlightColor, Color extraTextColor) { return FloatingSearchBar( hint: translation('Search...', settings["Language"]!), @@ -46,14 +47,14 @@ Widget searchBar(Color color, List recommend, child: comfortatext(place, 24, settings, color: textColor, weight: FontWeight.w400) ), hintStyle: GoogleFonts.comfortaa( - color: textColor, - fontSize: 18 * getFontSize(settings["Font size"]!), + color: extraTextColor, + fontSize: 16 * getFontSize(settings["Font size"]!), fontWeight: FontWeight.w100, ), queryStyle: GoogleFonts.comfortaa( - color: textColor, - fontSize: 22 * getFontSize(settings["Font size"]!), + color: extraTextColor, + fontSize: 21 * getFontSize(settings["Font size"]!), fontWeight: FontWeight.w100, ), @@ -62,8 +63,7 @@ Widget searchBar(Color color, List recommend, borderRadius: BorderRadius.circular(23), backgroundColor: color, - accentColor: color, - + accentColor: textColor, elevation: 0, height: 62, @@ -101,7 +101,7 @@ Widget searchBar(Color color, List recommend, child: Padding( padding: const EdgeInsets.only(right: 12), child: CircularButton( - icon: Icon(Icons.arrow_back_outlined, color: secondColor), + icon: Icon(Icons.arrow_back_outlined, color: secondColor, size: 22,), onPressed: () { controller.close(); }, @@ -156,7 +156,7 @@ Widget searchBar(Color color, List recommend, }, child: decideSearch(color, recommend, updateLocation, controller, updateIsEditing, isEditing, updateFav, - favorites, controller.query, settings, textColor) + favorites, controller.query, settings, textColor, extraTextColor) ); } ); @@ -165,17 +165,17 @@ Widget searchBar(Color color, List recommend, Widget decideSearch(Color color, List recommend, Function updateLocation, FloatingSearchBarController controller, Function updateIsEditing, bool isEditing, Function updateFav, - List favorites, String entered, Map settings, textColor) { + List favorites, String entered, Map settings, textColor, extraTextColor) { if (entered == '') { return defaultSearchScreen(color, updateLocation, - controller, updateIsEditing, isEditing, updateFav, favorites, settings, textColor); + controller, updateIsEditing, isEditing, updateFav, favorites, settings, textColor, extraTextColor); } else{ if (recommend.isNotEmpty) { return recommendSearchScreen( color, recommend, updateLocation, controller, - favorites, updateFav, settings, textColor); + favorites, updateFav, settings, textColor, extraTextColor); } } return Container(); @@ -184,11 +184,11 @@ Widget decideSearch(Color color, List recommend, Widget defaultSearchScreen(Color color, Function updateLocation, FloatingSearchBarController controller, Function updateIsEditing, bool isEditing, Function updateFav, - List favorites, Map settings, textColor) { + List favorites, Map settings, textColor, extraTextColor) { List Myicon = [ const Icon(null), - Icon(Icons.close, color: color,), + Icon(Icons.close, color: color, size: 20,), ]; Icon editIcon = const Icon(Icons.icecream, color: WHITE,); @@ -199,7 +199,7 @@ Widget defaultSearchScreen(Color color, for (String _ in favorites) { icons.add(1); } - editIcon = Icon(Icons.check, color: color,); + editIcon = Icon(Icons.check, color: color, size: 20,); rectColor = textColor; text = color; } @@ -207,7 +207,7 @@ Widget defaultSearchScreen(Color color, for (String _ in favorites) { icons.add(0); } - editIcon = Icon(Icons.edit, color: textColor,); + editIcon = Icon(Icons.create_outlined, color: textColor, size: 20,); rectColor = color; text = textColor; } @@ -215,11 +215,19 @@ Widget defaultSearchScreen(Color color, return Column( children: [ Padding( - padding: const EdgeInsets.only(top:5, bottom: 10, right: 20, left: 20), + padding: const EdgeInsets.only(top:5, bottom: 8, right: 20, left: 20), child: Row( children: [ - comfortatext(translation("Favorites", settings["Language"]!), 26 * getFontSize(settings["Font size"]!), - settings, color: WHITE), + Padding( + padding: const EdgeInsets.only(left: 1, top: 4, bottom: 0), + child: Align( + alignment: Alignment.centerLeft, + child: comfortatext( + "favorites", 20, + settings, + color: extraTextColor), + ), + ), const Spacer(), AnimatedSwitcher( duration: const Duration(milliseconds: 300), @@ -233,10 +241,11 @@ Widget defaultSearchScreen(Color color, child: ElevatedButton( style: ElevatedButton.styleFrom( elevation: 0, - padding: const EdgeInsets.all(6), + padding: const EdgeInsets.all(2), backgroundColor: rectColor, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20) + //side: BorderSide(color: rectColor, width: 1.5), + borderRadius: BorderRadius.circular(18) ) ), onPressed: () async { @@ -260,7 +269,7 @@ Widget defaultSearchScreen(Color color, decoration: BoxDecoration( color: rectColor, //border: Border.all(width: 1.2, color: WHITE), - borderRadius: BorderRadius.circular(20), + borderRadius: BorderRadius.circular(18), ), child: ListView.builder( shrinkWrap: true, @@ -276,7 +285,7 @@ Widget defaultSearchScreen(Color color, controller.close(); }, child: Container( - padding: const EdgeInsets.only(left: 20, bottom: 3, right: 10, top: 3), + padding: const EdgeInsets.only(left: 20, bottom: 1, right: 10, top: 1), child: Row( mainAxisSize: MainAxisSize.max, children: [ @@ -285,10 +294,10 @@ Widget defaultSearchScreen(Color color, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - comfortatext(split["name"], 25 * getFontSize(settings["Font size"]!), settings, + comfortatext(split["name"], 24 * getFontSize(settings["Font size"]!), settings, color: text), - comfortatext(split["region"] + ", " + generateAbbreviation(split["country"]), 18 - * getFontSize(settings["Font size"]!), settings, color: text) + comfortatext(split["region"] + ", " + generateAbbreviation(split["country"]), 16 + * getFontSize(settings["Font size"]!), settings, color: extraTextColor) ], ), ), @@ -315,15 +324,15 @@ Widget defaultSearchScreen(Color color, Widget recommendSearchScreen(Color color, List recommend, Function updateLocation, FloatingSearchBarController controller, List favorites, - Function updateFav, var settings, textColor) { + Function updateFav, var settings, textColor, extraTextColor) { List icons = []; for (String n in recommend) { if (favorites.contains(n)) { - icons.add(Icon(Icons.favorite, color: textColor,),); + icons.add(Icon(Icons.favorite, color: textColor, size: 21,),); } else{ - icons.add(Icon(Icons.favorite_border, color: textColor,),); + icons.add(Icon(Icons.favorite_border, color: textColor, size: 21,),); } } @@ -348,18 +357,18 @@ Widget recommendSearchScreen(Color color, List recommend, controller.close(); }, child: Container( - padding: const EdgeInsets.only(left: 20, bottom: 3, - right: 10, top: 3), + padding: const EdgeInsets.only(left: 20, bottom: 1, + right: 10, top: 1), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - comfortatext(split["name"], 25 * getFontSize(settings["Font size"]), + comfortatext(split["name"], 24 * getFontSize(settings["Font size"]), settings, color: textColor), - comfortatext(split["region"] + ", " + generateAbbreviation(split["country"]), 18 * getFontSize(settings["Font size"]), - settings, color: textColor) + comfortatext(split["region"] + ", " + generateAbbreviation(split["country"]), 16 * getFontSize(settings["Font size"]), + settings, color: extraTextColor) //comfortatext(split[0], 23) ], ), @@ -504,7 +513,8 @@ class dumbySearch extends StatelessWidget { ), MySearchParent(updateLocation: updateLocation, color: colors[0], place: place, controller: controller, settings: settings, - real_loc: place, secondColor: colors[1], textColor: colors[2], highlightColor: colors[5],), + real_loc: place, secondColor: colors[1], textColor: colors[2], highlightColor: colors[5], + extraTextColor: colors[5],), ], ) ), diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index fd8c90a..1ab7a68 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -731,16 +731,18 @@ class MySearchParent extends StatefulWidget{ final secondColor; final textColor; final highlightColor; + final extraTextColor; const MySearchParent({super.key, required this.updateLocation, required this.color, required this.place, required this.controller, required this.settings, required this.real_loc, required this.secondColor, required this.textColor, - required this.highlightColor}); + required this.highlightColor, required this.extraTextColor}); @override _MySearchParentState createState() => _MySearchParentState(color: color, place: place, controller: controller, settings: settings, real_loc: real_loc, - secondColor: secondColor, textColor: textColor, highlightColor: highlightColor); + secondColor: secondColor, textColor: textColor, highlightColor: highlightColor, + extraTextColor: extraTextColor); } class _MySearchParentState extends State { @@ -754,10 +756,11 @@ class _MySearchParentState extends State { final secondColor; final textColor; final highlightColor; + final extraTextColor; _MySearchParentState({required this.color, required this.place, required this.controller, required this.settings, required this.real_loc, required this.secondColor, - required this.textColor, required this.highlightColor}); + required this.textColor, required this.highlightColor, required this.extraTextColor}); late Future _prefsFuture; @@ -803,7 +806,8 @@ class _MySearchParentState extends State { return MySearchWidget(updateLocation: widget.updateLocation, color: color, favorites: favorites, prefs: snapshot.data, place: place, controller: controller, settings: settings, real_loc: real_loc, - secondColor: secondColor, textColor: textColor, highlightColor: highlightColor,); + secondColor: secondColor, textColor: textColor, highlightColor: highlightColor, + extraTextColor: extraTextColor,); }, ); } @@ -821,17 +825,20 @@ class MySearchWidget extends StatefulWidget{ final secondColor; final textColor; final highlightColor; + final extraTextColor; const MySearchWidget({super.key, required this.color, required this.updateLocation, required this.favorites, required this.prefs, required this.place, required this.controller, required this.settings, required this.real_loc, - required this.secondColor, required this.textColor, required this.highlightColor}); + required this.secondColor, required this.textColor, required this.highlightColor, + required this.extraTextColor}); @override _MySearchWidgetState createState() => _MySearchWidgetState(color: color, updateLocation: updateLocation, favorites: favorites, prefs: prefs, place: place, controller: controller, settings: settings, real_loc: real_loc, - secondColor: secondColor, textColor: textColor, highlightColor: highlightColor); + secondColor: secondColor, textColor: textColor, highlightColor: highlightColor, + extraTextColor: extraTextColor); } class _MySearchWidgetState extends State { @@ -846,6 +853,7 @@ class _MySearchWidgetState extends State { final secondColor; final textColor; final highlightColor; + final extraTextColor; List favorites; @@ -855,7 +863,8 @@ class _MySearchWidgetState extends State { _MySearchWidgetState({required this.color, required this.updateLocation, required this.favorites, required this.prefs, required this.place, required this.controller, required this.settings, required this.real_loc, - required this.secondColor, required this.textColor, required this.highlightColor}); + required this.secondColor, required this.textColor, required this.highlightColor, + required this.extraTextColor}); List recommend = []; @@ -901,7 +910,7 @@ class _MySearchWidgetState extends State { return searchBar(color, recommend, updateLocation, controller, updateIsEditing, isEditing, updateFav, favorites, updateRec, place, context, prog, updateProg, settings, real_loc, secondColor, - textColor, highlightColor); + textColor, highlightColor, extraTextColor); } } \ No newline at end of file From 848ebefbed9a23eeb9e65b105d132d94958c4eee Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 8 Aug 2024 20:21:57 +0200 Subject: [PATCH 071/129] finished all color themes --- lib/main_screens.dart | 4 ++-- lib/main_ui.dart | 10 +++++----- lib/settings_page.dart | 32 ++++++++++++++++---------------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 3dd6227..4dc2d03 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -154,9 +154,9 @@ class _NewMainState extends State { child: providerSelector( data.settings, updateLocation, - data.current.outline, + data.current.onSurface, data.current.container, - data.current.surface, + data.current.primary, data.provider, "${data.lat}, ${data.lng}", data.real_loc), diff --git a/lib/main_ui.dart b/lib/main_ui.dart index 1403e1e..8d8ed36 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -722,12 +722,12 @@ Widget buildHours(List hours, data) => SizedBox( Widget providerSelector(settings, updateLocation, textcolor, highlight, primary, provider, latlng, real_loc) { return Padding( - padding: const EdgeInsets.only(left: 20, right: 20, top: 15, bottom: 30), + padding: const EdgeInsets.only(left: 23, right: 23, top: 15, bottom: 30), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: const EdgeInsets.only(left: 5, top: 0), + padding: const EdgeInsets.only(left: 2, top: 0), child: Align( alignment: Alignment.centerLeft, child: comfortatext( @@ -749,11 +749,11 @@ Widget providerSelector(settings, updateLocation, textcolor, highlight, primary, borderRadius: BorderRadius.circular(20), icon: Padding( padding: const EdgeInsets.only(left:5), - child: Icon(Icons.arrow_drop_down_circle, color: primary,), + child: Icon(Icons.arrow_drop_down_circle, color: primary, size: 20,), ), style: GoogleFonts.comfortaa( - color: WHITE, - fontSize: 20 * getFontSize(settings["Font size"]), + color: primary, + fontSize: 18 * getFontSize(settings["Font size"]), fontWeight: FontWeight.w300, ), //value: selected_temp_unit.isNotEmpty ? selected_temp_unit : null, // guard it with null if empty diff --git a/lib/settings_page.dart b/lib/settings_page.dart index e047a1c..c24e688 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -147,31 +147,31 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { ]; if (x == "monochrome") { colors = [ - palette.surface, - palette.primary, - palette.primaryFixedDim, - palette.primaryFixed, + palette.onPrimaryFixedVariant, + WHITE, + WHITE, + WHITE, palette.onSurface, - palette.outline, - palette.surfaceContainerLow, - palette.surfaceContainer, - palette.surfaceContainerHigh, - palette.surfaceContainerHighest, - palette.onPrimaryFixed, + WHITE, + darken2(palette.onPrimaryFixedVariant, 0.09), + darken2(palette.onPrimaryFixedVariant, 0.15), + darken2(palette.onPrimaryFixedVariant, 0.2), + darken2(palette.onPrimaryFixedVariant, 0.1), + WHITE ]; } else if (x == "colorful") { colors = [ - palette.surface, + palette.onTertiaryFixedVariant, palette.primary, - palette.primaryFixedDim, + palette.primaryFixed, palette.primaryFixed, palette.onSurface, palette.outline, - palette.surfaceContainerLow, - palette.surfaceContainer, - palette.surfaceContainerHigh, - palette.surfaceContainerHighest, + darken2(palette.onTertiaryFixedVariant, 0.09), + darken2(palette.onTertiaryFixedVariant, 0.15), + darken2(palette.onTertiaryFixedVariant, 0.2), + darken2(palette.onTertiaryFixedVariant, 0.1), palette.onPrimaryFixed, ]; } From eb629014c9dce7910eac81b7c34e2c3b90df783f Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 9 Aug 2024 16:24:46 +0200 Subject: [PATCH 072/129] minor tweaks all around. trying to improve the consistency --- lib/decoders/extra_info.dart | 15 ++++++++++----- lib/main_screens.dart | 31 ++++++++++++++----------------- lib/new_forecast.dart | 4 ++-- lib/search_screens.dart | 12 ++++++------ lib/settings_page.dart | 2 +- lib/weather_refact.dart | 3 ++- 6 files changed, 35 insertions(+), 32 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 4931660..19981c1 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -90,8 +90,13 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double for (int x = 0; x < textToUnsplashText.length; x ++) { for (int y = 0; y < textToUnsplashText[keys2[x]]!.length; y ++) { int reward = keys2[x] == _text ? -3000 : 1000; + if (textToUnsplashText[_text]!.contains(textToUnsplashText[keys2[x]]![y])) { + if (reward == 1000) { + reward = 0; + } + } if (desc.contains(textToUnsplashText[keys2[x]]![y])) { - print(("punished", textToUnsplashText[keys2[x]]![y], reward)); + print(("punished1", textToUnsplashText[keys2[x]]![y], reward)); unaccuracy += reward; // i had to reverse it } } @@ -99,7 +104,7 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double for (int x = 0; x < textFilter.length; x ++) { if (desc.contains(keys1[x])) { - print(("punished", keys1[x], -textFilter[keys1[x]]!)); + print(("punished2", keys1[x], -textFilter[keys1[x]]!)); unaccuracy -= textFilter[keys1[x]]!; // i had to reverse it } } @@ -168,7 +173,7 @@ Future getImageColors(Image Uimage, color_mode, settings) async { int base = (diffBetweenBackColors(dominant) * 0.7).round(); print(("base", base)); - if (bestDif <= base + 50) { + if (bestDif <= base + 80) { print("trying"); for (int i = 1; i < 4; i++) { //LIGHT @@ -190,7 +195,7 @@ Future getImageColors(Image Uimage, color_mode, settings) async { } //if the contrast is still low then we need to choose another color - if (bestDif <= base + 50) { + if (bestDif <= base + 80) { print("plan b"); for (int i = 0; i < dominant.length; i++) { Color newcolor = dominant[i]; @@ -209,7 +214,7 @@ Future getImageColors(Image Uimage, color_mode, settings) async { print(("desc_dif", desc_dif)); - if (desc_dif < 200) { + if (desc_dif < base + 40) { desc_color = bestcolor; } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 4dc2d03..7012e2e 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -97,28 +97,25 @@ class _NewMainState extends State { padding: const EdgeInsets.only(left: 0), child: comfortatext( data.current.text, 32, data.settings, - weight: data.settings["Color mode"] == "dark" - ? FontWeight.w600 - : FontWeight.w500, + weight: data.settings["Color mode"] == "light" + ? FontWeight.w500 + : FontWeight.w600, color: data.current.descColor), ) ], ), ), - Container( - padding: EdgeInsets.zero, - child: MySearchParent(updateLocation: updateLocation, - color: data.current.surface, - place: data.place, - controller: controller, - settings: data.settings, - real_loc: data.real_loc, - secondColor: data.current.primaryLight, - textColor: data.current.primary, - highlightColor: data.current.container, - key: Key("${data.place}, ${data.current.surface}"), - extraTextColor: data.current.onSurface,), - ), + MySearchParent(updateLocation: updateLocation, + color: data.current.surface, + place: data.place, + controller: controller, + settings: data.settings, + real_loc: data.real_loc, + secondColor: data.settings["Color mode"] == "light" ? data.current.primary : data.current.primaryLight, + textColor: data.settings["Color mode"] == "light" ? data.current.primaryLight : data.current.primary, + highlightColor: data.current.container, + key: Key("${data.place}, ${data.current.surface}"), + extraTextColor: data.current.onSurface,), ], ) ), diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 2863c9b..f523946 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -238,11 +238,11 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { checkmarkColor: data.current.onPrimaryLight, color: WidgetStateProperty.resolveWith((states) { if (index == _value) { - return data.current.primaryLight; + return data.current.primaryLighter; } return state ? data.current.containerLow : data.current.surface; }), - side: BorderSide(color: data.current.primaryLight, width: 1.0), + side: BorderSide(color: data.current.primaryLighter, width: 1.0), label: comfortatext( ['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, color: _value == index ? data.current.onPrimaryLight : data.current.onSurface), diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 62fa03c..429e57e 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -44,7 +44,7 @@ Widget searchBar(Color color, List recommend, hint: translation('Search...', settings["Language"]!), title: Container( padding: const EdgeInsets.only(left: 5, top: 3), - child: comfortatext(place, 24, settings, color: textColor, weight: FontWeight.w400) + child: comfortatext(place, 24, settings, color: secondColor, weight: FontWeight.w400) ), hintStyle: GoogleFonts.comfortaa( color: extraTextColor, @@ -112,7 +112,7 @@ Widget searchBar(Color color, List recommend, showIfOpened: false, showIfClosed: true, child: IconButton( - icon: Icon(Icons.menu_rounded, color: secondColor, size: 25,), + icon: Icon(Icons.menu_rounded, color: textColor, size: 25,), onPressed: () { Scaffold.of(context).openDrawer(); }, @@ -406,13 +406,13 @@ Widget LocationButton(Function updateProg, Function updateLocation, Color color, style: ElevatedButton.styleFrom( elevation: 0, padding: const EdgeInsets.all(10), - backgroundColor: secondColor, + backgroundColor: textColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(19) ) ), onPressed: () async {}, - child: Icon(Icons.place_outlined, color: color,), + child: Icon(Icons.place_outlined, color: textColor,), ), ), ); @@ -427,7 +427,7 @@ Widget LocationButton(Function updateProg, Function updateLocation, Color color, elevation: 0, padding: const EdgeInsets.all(10), backgroundColor: color, - side: BorderSide(width: 1.7, color: textColor), + side: BorderSide(width: 1.7, color: secondColor), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20) ) @@ -435,7 +435,7 @@ Widget LocationButton(Function updateProg, Function updateLocation, Color color, onPressed: () async { updateLocation('40.7128, 74.0060', 'CurrentLocation'); }, //^ this is new york for backup - child: Icon(Icons.place_outlined, color: secondColor,), + child: Icon(Icons.place_outlined, color: textColor,), ), ), ); diff --git a/lib/settings_page.dart b/lib/settings_page.dart index c24e688..7128765 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -157,7 +157,7 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { darken2(palette.onPrimaryFixedVariant, 0.15), darken2(palette.onPrimaryFixedVariant, 0.2), darken2(palette.onPrimaryFixedVariant, 0.1), - WHITE + palette.onTertiaryFixed, ]; } else if (x == "colorful") { diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 3065509..0966384 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -339,7 +339,7 @@ Map> textToUnsplashText = { 'Heavy Snow': ['heavy snow', 'snow', 'snowing', 'snows'], 'Fog': ['fog', 'mist', 'haze'], 'Snow': ['snow', 'snowing', 'snows'], - 'Heavy Rain': ['heavy rain', 'rain', 'drop', 'rainy', 'raining'], + 'Heavy Rain': ['heavy rain', 'rain', 'drop', 'rainy', 'raining', 'drops'], 'Cloudy Night' : ['cloudy night', 'night'] //if you specify cloudy then it gives cloudy results }; @@ -360,6 +360,7 @@ Map textFilter = { 'fabric': -10000, 'texture': -10000, 'pattern': -10000, + 'text': -10000, 'man': -10000000, //trying to not have people in images 'male': -1000000, 'couple': -1000000, From 24a7eacdc910d12f5619de9967125ba33a3bebc4 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 9 Aug 2024 17:46:10 +0200 Subject: [PATCH 073/129] trying to make original images work too --- lib/decoders/decode_OM.dart | 51 +++++---- lib/decoders/decode_wapi.dart | 2 +- lib/decoders/extra_info.dart | 5 +- lib/main_screens.dart | 12 +-- lib/main_ui.dart | 6 +- lib/new_displays.dart | 40 +++---- lib/new_forecast.dart | 4 +- lib/settings_page.dart | 197 ++++++++++++++++++++++------------ lib/ui_helper.dart | 4 +- 9 files changed, 184 insertions(+), 137 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 22fd870..e4f3ada 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -207,7 +207,6 @@ double oMIconSizeCorrection(String text) { class OMCurrent { final String text; - final String backdrop; final int temp; final int humidity; final int feels_like; @@ -234,9 +233,10 @@ class OMCurrent { final Color backup_primary; final Color backup_backcolor; + final Image image; + const OMCurrent({ required this.precip, - required this.backdrop, required this.humidity, required this.feels_like, required this.temp, @@ -260,9 +260,26 @@ class OMCurrent { required this.descColor, required this.surfaceVariant, required this.onPrimaryLight, + + required this.image, }); - static OMCurrent fromJson(item, settings, sunstatus, timenow, palette) { + static Future fromJson(item, settings, sunstatus, timenow) async { + + // GET IMAGE + //Image Uimage = await getUnsplashImage(oMCurrentTextCorrection( + // oMBody["current"]["weather_code"], sunstatus, real_time), real_loc, lat, lng); + + String imagePath = oMBackdropCorrection( + oMCurrentTextCorrection( + item["current"]["weather_code"], sunstatus, timenow), + ); + Image Uimage = Image.asset("assets/backdrops/$imagePath", fit: BoxFit.cover, + width: double.infinity, height: double.infinity,); + + //GET COLORS + List palette = await getImageColors(Uimage, settings["Color mode"], settings); + Color back = BackColorCorrection( oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), @@ -277,15 +294,17 @@ class OMCurrent { //List colors = getColors(primary, back, settings, // ColorPopCorrection( oMCurrentTextCorrection( // item["current"]["weather_code"], sunstatus, timenow),)[ - // settings["Color mode"] == "dark" ? 1 : 0 - // ]); + // settings["Color mode"] == "dark" ? 1 : 0 + //]); - List colors = getNetworkColors(palette[0], settings); + List colors = getNetworkColors(palette, settings); //List colors = palette.colors.toList(); return OMCurrent( + image: Uimage, + text: translation(oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), settings["Language"]), @@ -306,17 +325,12 @@ class OMCurrent { surfaceVariant: colors[9], onPrimaryLight: colors[10], - colorPop: palette[1], - descColor: palette[2], + colorPop: colors[11], + descColor: colors[12], backup_backcolor: back, backup_primary: primary, - backdrop: oMBackdropCorrection( - oMCurrentTextCorrection( - item["current"]["weather_code"], sunstatus, timenow), - ), - precip: double.parse(unit_coversion( item["daily"]["precipitation_sum"][0], settings["Precipitation"]) .toStringAsFixed(1)), @@ -633,20 +647,13 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as DateTime localtime = OMGetLocalTime(oMBody); String real_time = "jT${localtime.hour}:${localtime.minute}"; - // GET IMAGE - Image Uimage = await getUnsplashImage(oMCurrentTextCorrection( - oMBody["current"]["weather_code"], sunstatus, real_time), real_loc, lat, lng); - - //GET COLORS - List imageColors = await getImageColors(Uimage, settings["Color mode"], settings); - return WeatherData( radar: await RainviewerRadar.getData(), aqi: await OMAqi.fromJson(oMBody, lat, lng), sunstatus: sunstatus, minutely_15_precip: OM15MinutePrecip.fromJson(oMBody, settings), - current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, imageColors), + current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time), days: days, lat: lat, @@ -660,7 +667,5 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as fetch_datetime: fetch_datetime, updatedTime: DateTime.now(), localtime: real_time.split("T")[1], - - image: Uimage, ); } \ No newline at end of file diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index 805babf..d3210da 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -557,6 +557,6 @@ Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) localtime: WapiGetLocalTime(wapi_body), minutely_15_precip: const OM15MinutePrecip(t_minus: "", precip_sum: 0, precips: []), //because wapi doesn't have 15 minutely - image: Uimage, + //image: Uimage, ); } diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 19981c1..71bee2f 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -161,7 +161,7 @@ Future getImageColors(Image Uimage, color_mode, settings) async { final ColorScheme palette = (await _materialPalette(Uimage, color_mode)); - final List used_colors = getNetworkColors(palette, settings); + final List used_colors = getNetworkColors([palette, ], settings); final List dominant = pali.colors.toList(); @@ -359,8 +359,6 @@ class WeatherData { final radar; final minutely_15_precip; - final image; - WeatherData({ required this.place, required this.settings, @@ -375,7 +373,6 @@ class WeatherData { required this.current, required this.fetch_datetime, required this.updatedTime, - required this.image, required this.localtime, required this.minutely_15_precip, diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 7012e2e..68d33b3 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -60,7 +60,7 @@ class _NewMainState extends State { drawer: MyDrawer(primary: data.current.backup_primary, back: data.current.backup_backcolor, settings: data.settings, - image: data.current.backdrop,), + image: data.current.image,), body: StretchyHeader.listView( displacement: 130, onRefresh: () async { @@ -71,7 +71,7 @@ class _NewMainState extends State { blurContent: false, headerHeight: max(size.height * 0.53, 400), //we don't want it to be smaller than 400 - header: ParrallaxBackground(image: data.image, key: Key(data.place), + header: ParrallaxBackground(image: data.current.image, key: Key(data.place), color: data.current.surface == BLACK ? BLACK : lightAccent(data.current.surface, 5000)), overlay: Stack( @@ -99,7 +99,7 @@ class _NewMainState extends State { data.current.text, 32, data.settings, weight: data.settings["Color mode"] == "light" ? FontWeight.w500 - : FontWeight.w600, + : FontWeight.w400, color: data.current.descColor), ) ], @@ -111,7 +111,7 @@ class _NewMainState extends State { controller: controller, settings: data.settings, real_loc: data.real_loc, - secondColor: data.settings["Color mode"] == "light" ? data.current.primary : data.current.primaryLight, + secondColor: data.current.onSurface, textColor: data.settings["Color mode"] == "light" ? data.current.primaryLight : data.current.primary, highlightColor: data.current.container, key: Key("${data.place}, ${data.current.surface}"), @@ -193,7 +193,7 @@ Widget TabletLayout(data, updateLocation, context) { return Scaffold( backgroundColor: data.current.surface, drawer: MyDrawer(primary: data.current.backup_primary, back: data.current.backup_backcolor, - settings: data.settings, image: data.current.backdrop), + settings: data.settings, image: data.current.image), body: RefreshIndicator( onRefresh: () async { await updateLocation("${data.lat}, ${data.lng}", data.real_loc); @@ -224,7 +224,7 @@ Widget TabletLayout(data, updateLocation, context) { padding: const EdgeInsets.only(top: 100), child: ClipRRect( borderRadius: BorderRadius.circular(20), - child: ParrallaxBackground(image: data.current.backdrop, key: Key(data.place), + child: ParrallaxBackground(image: data.current.image, key: Key(data.place), color: darken(data.current.surface, 0.1),), ), ), diff --git a/lib/main_ui.dart b/lib/main_ui.dart index 8d8ed36..168ecd6 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -57,7 +57,7 @@ class WeatherPage extends StatelessWidget { //return PhoneLayout(data, updateLocation, context); return NewMain(data: data, updateLocation: updateLocation, context: context, - key: Key("${data.place}, ${data.current.surface} ${data.image}"),); + key: Key("${data.place}, ${data.current.surface} ${data.current.image}"),); } } @@ -749,12 +749,12 @@ Widget providerSelector(settings, updateLocation, textcolor, highlight, primary, borderRadius: BorderRadius.circular(20), icon: Padding( padding: const EdgeInsets.only(left:5), - child: Icon(Icons.arrow_drop_down_circle, color: primary, size: 20,), + child: Icon(Icons.arrow_drop_down_circle_outlined, color: primary, size: 22,), ), style: GoogleFonts.comfortaa( color: primary, fontSize: 18 * getFontSize(settings["Font size"]), - fontWeight: FontWeight.w300, + fontWeight: FontWeight.w500, ), //value: selected_temp_unit.isNotEmpty ? selected_temp_unit : null, // guard it with null if empty value: provider.toString(), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 38f7cc8..666d405 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -202,7 +202,7 @@ class _NewSunriseSunsetState extends State height: 4, width: 4, decoration: BoxDecoration( - color: widget.data.current.primaryLight, + color: widget.data.current.primaryLighter, borderRadius: BorderRadius.circular(20), ), ), @@ -214,7 +214,7 @@ class _NewSunriseSunsetState extends State child: CustomPaint( painter: WavePainter( _controller.value, - widget.data.current.primaryLight, + widget.data.current.primaryLighter, darken(widget.data.current.surfaceVariant, 0.03), progress), child: Container( @@ -231,13 +231,13 @@ class _NewSunriseSunsetState extends State padding: const EdgeInsets.only(right: 4), child: Icon( Icons.wb_sunny_outlined, - color: widget.data.current.primaryLight, + color: widget.data.current.primaryLighter, size: 14, ), ), comfortatext( widget.data.sunstatus.sunrise, 15, widget.data.settings, - color: widget.data.current.primaryLight, + color: widget.data.current.primaryLighter, weight: FontWeight.w500), const Spacer(), comfortatext( @@ -265,25 +265,15 @@ Widget NewAirQuality(var data) { padding: const EdgeInsets.only(left: 20, right: 20, bottom: 19, top: 23), child: Column( children: [ - Padding( - padding: const EdgeInsets.only(bottom: 6, left: 5), - child: Row( - children: [ - comfortatext( - translation('air quality', data.settings["Language"]), - 16, - data.settings, - color: data.current.onSurface), - const Spacer(), - Padding( - padding: const EdgeInsets.only(right: 5), - child: Icon( - Icons.arrow_forward, - size: 16, - color: data.current.onSurface, - ), - ) - ], + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.only(bottom: 6, left: 5), + child: comfortatext( + translation('air quality', data.settings["Language"]), + 16, + data.settings, + color: data.current.onSurface), ), ), Row( @@ -299,7 +289,7 @@ Widget NewAirQuality(var data) { child: Center( child: comfortatext( data.aqi.aqi_index.toString(), 32, data.settings, - color: data.current.primaryLight)), + color: data.current.primaryLighter)), ), ), Expanded( @@ -312,7 +302,7 @@ Widget NewAirQuality(var data) { data.aqi.aqi_title, 20, data.settings, - color: data.current.primaryLight, + color: data.current.primaryLighter, align: TextAlign.left, weight: FontWeight.w600, ), diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index f523946..05e5115 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -242,7 +242,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { } return state ? data.current.containerLow : data.current.surface; }), - side: BorderSide(color: data.current.primaryLighter, width: 1.0), + side: BorderSide(color: data.current.primaryLighter, width: 1.4), label: comfortatext( ['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, color: _value == index ? data.current.onPrimaryLight : data.current.onSurface), @@ -802,7 +802,7 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { decoration: BoxDecoration( borderRadius: BorderRadius.circular(13), //border: Border.all(width: 1.5, color: data.current.primaryLight) - color: data.current.primaryLight + color: data.current.primaryLighter ), child: Row( children: [ diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 7128765..bfc8e03 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -55,20 +55,36 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { String x = force == "-1" ? settings["Color mode"] : force; - //0 BACKCOLOR - //1 PRIMARY - //2 TEXT COLOR - //3 COLOR POP - //4 SECONDARY - //5 HIGHLIGHT + //surface + //primary + //primaryLight + //primaryLighter + //onSurface + //outline + //containerLow + //container + //containerHigh + //surfaceVariant + //onPrimaryLight + + //colorpop + //desc List colors = [ primary, back, WHITE, - [back, WHITE, WHITE][dif], + lighten2(back, 0.03), WHITE, - darken(primary) + WHITE, + darken(primary, 0.03), + darken(primary, 0.06), + darken(primary, 0.06), + darken(primary, 0.03), + WHITE, + + [back, WHITE, WHITE][dif], + WHITE ]; if (x == "monochrome") { @@ -78,7 +94,15 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { WHITE, WHITE, WHITE, - darken(primary) + WHITE, + darken(primary, 0.03), + darken(primary, 0.06), + darken(primary, 0.06), + darken(primary, 0.03), + primary, + + WHITE, + WHITE ]; } @@ -87,20 +111,37 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { back, primary, WHITE, - [back, WHITE, WHITE][dif], + lighten2(primary, 0.03), WHITE, - darken(back) + WHITE, + darken(back, 0.03), + darken(back, 0.06), + darken(back, 0.06), + darken(back, 0.03), + WHITE, + + [back, WHITE, WHITE][dif], + WHITE ]; } else if (x == "light") { colors = [ //backcolor, primary, text - const Color(0xffeeeeee), - primary, - BLACK, WHITE, primary, - lighten(lightAccent(primary, 60000), 0.25), + lighten(primary, 0.1), + lighten(primary, 0.15), + Color.fromARGB(250, 30, 30, 30), + Color.fromARGB(250, 50, 50, 50), + Color.fromARGB(250, 245, 245, 245), + Color.fromARGB(250, 230, 230, 230), + Color.fromARGB(250, 220, 220, 220), + Color.fromARGB(250, 190, 190, 190), + primary, + + WHITE, + WHITE, + ]; } else if (x == "dark") { @@ -117,7 +158,7 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { return colors; } -List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { +List getNetworkColors(List palette, settings, {force = "-1"}) { String x = force == "-1" ? settings["Color mode"] : force; //surface @@ -133,76 +174,91 @@ List getNetworkColors(ColorScheme palette, settings, {force = "-1"}) { //onPrimaryLight List colors = [ - palette.onPrimaryFixedVariant, - palette.tertiary, - palette.tertiaryFixed, - palette.secondaryFixed, - palette.onSurface, - palette.outline, - darken2(palette.onPrimaryFixedVariant, 0.09), - darken2(palette.onPrimaryFixedVariant, 0.15), - darken2(palette.onPrimaryFixedVariant, 0.2), - darken2(palette.onPrimaryFixedVariant, 0.1), - palette.onTertiaryFixed, + palette[0].onPrimaryFixedVariant, + palette[0].primaryFixed, + palette[0].tertiaryFixed, + palette[0].secondaryFixed, + palette[0].onSurface, + palette[0].outline, + darken2(palette[0].onPrimaryFixedVariant, 0.09), + darken2(palette[0].onPrimaryFixedVariant, 0.15), + darken2(palette[0].onPrimaryFixedVariant, 0.2), + darken2(palette[0].onPrimaryFixedVariant, 0.1), + palette[0].onTertiaryFixed, + + palette[1], + palette[2], ]; if (x == "monochrome") { colors = [ - palette.onPrimaryFixedVariant, + palette[0].onPrimaryFixedVariant, WHITE, WHITE, WHITE, - palette.onSurface, + palette[0].onSurface, WHITE, - darken2(palette.onPrimaryFixedVariant, 0.09), - darken2(palette.onPrimaryFixedVariant, 0.15), - darken2(palette.onPrimaryFixedVariant, 0.2), - darken2(palette.onPrimaryFixedVariant, 0.1), - palette.onTertiaryFixed, + darken2(palette[0].onPrimaryFixedVariant, 0.09), + darken2(palette[0].onPrimaryFixedVariant, 0.15), + darken2(palette[0].onPrimaryFixedVariant, 0.2), + darken2(palette[0].onPrimaryFixedVariant, 0.1), + palette[0].onTertiaryFixed, + + palette[1], + palette[2], ]; } else if (x == "colorful") { colors = [ - palette.onTertiaryFixedVariant, - palette.primary, - palette.primaryFixed, - palette.primaryFixed, - palette.onSurface, - palette.outline, - darken2(palette.onTertiaryFixedVariant, 0.09), - darken2(palette.onTertiaryFixedVariant, 0.15), - darken2(palette.onTertiaryFixedVariant, 0.2), - darken2(palette.onTertiaryFixedVariant, 0.1), - palette.onPrimaryFixed, + palette[0].onTertiaryFixedVariant, + palette[0].tertiaryFixed, + palette[0].primaryFixed, + palette[0].secondaryFixed, + palette[0].onSurface, + palette[0].outline, + darken2(palette[0].onTertiaryFixedVariant, 0.09), + darken2(palette[0].onTertiaryFixedVariant, 0.15), + darken2(palette[0].onTertiaryFixedVariant, 0.2), + darken2(palette[0].onTertiaryFixedVariant, 0.1), + palette[0].onPrimaryFixed, + + palette[1], + palette[2], ]; } else if (x == "light") { colors = [ - palette.surface, - palette.primary, - palette.primaryFixedDim, - palette.primaryFixed, - palette.onSurface, - palette.outline, - palette.surfaceContainerLow, - palette.surfaceContainer, - palette.surfaceContainerHigh, - palette.surfaceContainerHighest, - palette.onPrimaryFixed, + palette[0].surface, + palette[0].primary, + palette[0].primaryFixedDim, + palette[0].primaryFixed, + palette[0].onSurface, + palette[0].outline, + palette[0].surfaceContainerLow, + palette[0].surfaceContainer, + palette[0].surfaceContainerHigh, + palette[0].surfaceContainerHighest, + palette[0].onPrimaryFixed, + + palette[1], + palette[2], ]; } else if (x == "dark") { colors = [ - palette.surface, - palette.primary, - palette.primaryFixed, - palette.primaryFixed, - palette.onSurface, - palette.outline, - palette.surfaceContainerLow, - palette.surfaceContainer, - palette.surfaceContainerHigh, - palette.surfaceContainerHighest, - palette.onPrimaryFixed, + palette[0].surface, + palette[0].primary, + palette[0].primaryFixed, + palette[0].primaryFixed, + palette[0].onSurface, + palette[0].outline, + palette[0].surfaceContainerLow, + palette[0].surfaceContainer, + palette[0].surfaceContainerHigh, + palette[0].surfaceContainerHighest, + palette[0].onPrimaryFixed, + + palette[1], + palette[2], ]; } return colors; @@ -431,7 +487,7 @@ class _SettingsPageState extends State { } Widget SettingsMain(Color primary, Map? settings, Function updatePage, - Function goBack, Color back, String image, context) { + Function goBack, Color back, Image image, context) { List colors = getColors(primary, back, settings, 0); @@ -461,7 +517,7 @@ Widget SettingsMain(Color primary, Map? settings, Function updat } Widget settingsMain(Color color, Map settings, Function updatePage, - Color textcolor, Color secondary, highlight, Color colorpop, String image, Color primary, + Color textcolor, Color secondary, highlight, Color colorpop, Image image, Color primary, Color back) { //var entryList = settings.entries.toList(); @@ -529,8 +585,7 @@ Widget settingsMain(Color color, Map settings, Function updatePa height: 220, child: Stack( children: [ - ParrallaxBackground(image: Image.asset("assets/backdrops/$image", - fit: BoxFit.fill, width: double.infinity, height: double.infinity,), color: color), + ParrallaxBackground(image: image, color: color), Padding( padding: const EdgeInsets.only(left: 10, bottom: 15), child: Column( diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 1ab7a68..721695b 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -319,11 +319,11 @@ Widget NewAqiDataPoints(String name, double value, var data) { height: 2.5, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: data.current.primaryLight, + color: data.current.primaryLighter, ), ), ), - comfortatext(value.toString(), 15, data.settings, color: data.current.primaryLight, + comfortatext(value.toString(), 15, data.settings, color: data.current.primaryLighter, align: TextAlign.end, weight: FontWeight.w600), ], ); From f6faecb63975ce706de944cb8706bd04c80370b7 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 10 Aug 2024 16:34:08 +0200 Subject: [PATCH 074/129] tweaked all colors to try to get back the original color feelings --- lib/decoders/decode_OM.dart | 29 +++++++++++++++------------ lib/decoders/extra_info.dart | 5 ++--- lib/main_screens.dart | 5 ++--- lib/new_displays.dart | 16 +++++++-------- lib/new_forecast.dart | 2 +- lib/radar.dart | 2 +- lib/settings_page.dart | 38 +++++++++++++++++++++++------------- lib/ui_helper.dart | 4 ++-- 8 files changed, 57 insertions(+), 44 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index e4f3ada..79f213b 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -229,6 +229,7 @@ class OMCurrent { final Color descColor; final Color surfaceVariant; final Color onPrimaryLight; + final Color primarySecond; final Color backup_primary; final Color backup_backcolor; @@ -260,6 +261,7 @@ class OMCurrent { required this.descColor, required this.surfaceVariant, required this.onPrimaryLight, + required this.primarySecond, required this.image, }); @@ -277,9 +279,6 @@ class OMCurrent { Image Uimage = Image.asset("assets/backdrops/$imagePath", fit: BoxFit.cover, width: double.infinity, height: double.infinity,); - //GET COLORS - List palette = await getImageColors(Uimage, settings["Color mode"], settings); - Color back = BackColorCorrection( oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), @@ -290,15 +289,20 @@ class OMCurrent { item["current"]["weather_code"], sunstatus, timenow), ); + List colors; - //List colors = getColors(primary, back, settings, - // ColorPopCorrection( oMCurrentTextCorrection( - // item["current"]["weather_code"], sunstatus, timenow),)[ - // settings["Color mode"] == "dark" ? 1 : 0 - //]); - + if (settings["Color mode"] == "light" || settings["Color mode"] == "dark") { + List palette = await getImageColors(Uimage, settings["Color mode"], settings); + colors = getNetworkColors(palette, settings); + } + else { + colors = getColors(primary, back, settings, + ColorPopCorrection( oMCurrentTextCorrection( + item["current"]["weather_code"], sunstatus, timenow),)[ + settings["Color mode"] == "dark" ? 1 : 0 + ]); + } - List colors = getNetworkColors(palette, settings); //List colors = palette.colors.toList(); @@ -324,9 +328,10 @@ class OMCurrent { containerHigh: colors[8], surfaceVariant: colors[9], onPrimaryLight: colors[10], + primarySecond: colors[11], - colorPop: colors[11], - descColor: colors[12], + colorPop: colors[12], + descColor: colors[13], backup_backcolor: back, backup_primary: primary, diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 71bee2f..607c842 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -152,7 +152,7 @@ Future MaterialYouColor(String theme) async { return palette; } -Future getImageColors(Image Uimage, color_mode, settings) async { +Future> getImageColors(Image Uimage, color_mode, settings) async { final PaletteGenerator pali = await _generatorPalette(Uimage); //var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; @@ -161,10 +161,9 @@ Future getImageColors(Image Uimage, color_mode, settings) async { final ColorScheme palette = (await _materialPalette(Uimage, color_mode)); - final List used_colors = getNetworkColors([palette, ], settings); + final List used_colors = getNetworkColors([palette, BLACK, BLACK], settings); final List dominant = pali.colors.toList(); - Color startcolor = used_colors[2]; Color bestcolor = used_colors[2]; diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 68d33b3..0d44968 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -111,7 +111,7 @@ class _NewMainState extends State { controller: controller, settings: data.settings, real_loc: data.real_loc, - secondColor: data.current.onSurface, + secondColor: data.settings["Color mode"] == "light" ? data.current.primary : data.current.onSurface, textColor: data.settings["Color mode"] == "light" ? data.current.primaryLight : data.current.primary, highlightColor: data.current.container, key: Key("${data.place}, ${data.current.surface}"), @@ -141,8 +141,7 @@ class _NewMainState extends State { NewSunriseSunset(data: data, key: Key(data.place), size: size,), NewRain15MinuteIndicator(data), NewAirQuality(data), - RadarSmall( - data: data, key: Key("${data.place}, ${data.current.surface}")), + RadarSmall(data: data, key: Key("${data.place}, ${data.current.surface}")), buildNewDays(data), buildNewGlanceDay(data: data), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 666d405..99fcdb4 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -202,7 +202,7 @@ class _NewSunriseSunsetState extends State height: 4, width: 4, decoration: BoxDecoration( - color: widget.data.current.primaryLighter, + color: widget.data.current.primarySecond, borderRadius: BorderRadius.circular(20), ), ), @@ -214,7 +214,7 @@ class _NewSunriseSunsetState extends State child: CustomPaint( painter: WavePainter( _controller.value, - widget.data.current.primaryLighter, + widget.data.current.primarySecond, darken(widget.data.current.surfaceVariant, 0.03), progress), child: Container( @@ -231,13 +231,13 @@ class _NewSunriseSunsetState extends State padding: const EdgeInsets.only(right: 4), child: Icon( Icons.wb_sunny_outlined, - color: widget.data.current.primaryLighter, + color: widget.data.current.primarySecond, size: 14, ), ), comfortatext( widget.data.sunstatus.sunrise, 15, widget.data.settings, - color: widget.data.current.primaryLighter, + color: widget.data.current.primarySecond, weight: FontWeight.w500), const Spacer(), comfortatext( @@ -289,7 +289,7 @@ Widget NewAirQuality(var data) { child: Center( child: comfortatext( data.aqi.aqi_index.toString(), 32, data.settings, - color: data.current.primaryLighter)), + color: data.current.primarySecond)), ), ), Expanded( @@ -302,15 +302,15 @@ Widget NewAirQuality(var data) { data.aqi.aqi_title, 20, data.settings, - color: data.current.primaryLighter, + color: data.current.primarySecond, align: TextAlign.left, - weight: FontWeight.w600, + weight: FontWeight.w500, ), ), Padding( padding: const EdgeInsets.all(3.0), child: comfortatext(data.aqi.aqi_desc, 14, data.settings, - color: data.current.onSurface, weight: FontWeight.w500), + color: data.current.onSurface, weight: FontWeight.w400), ), ], ), diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 05e5115..45ad7c6 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -242,7 +242,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { } return state ? data.current.containerLow : data.current.surface; }), - side: BorderSide(color: data.current.primaryLighter, width: 1.4), + side: BorderSide(color: data.current.primaryLighter, width: 1.5), label: comfortatext( ['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, color: _value == index ? data.current.onPrimaryLight : data.current.onSurface), diff --git a/lib/radar.dart b/lib/radar.dart index 9d37eb4..33f6d40 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -527,7 +527,7 @@ class _RadarSmallState extends State { return Column( children: [ Padding( - padding: const EdgeInsets.only(left: 25, top: 20), + padding: const EdgeInsets.only(left: 25, top: 40), child: Align( alignment: Alignment.centerLeft, child: comfortatext( diff --git a/lib/settings_page.dart b/lib/settings_page.dart index bfc8e03..451cd38 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -66,6 +66,7 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { //containerHigh //surfaceVariant //onPrimaryLight + //primarySecond //colorpop //desc @@ -73,15 +74,16 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { List colors = [ primary, back, + lighten2(primary, 0.8), + darken2(primary, 0.4), WHITE, - lighten2(back, 0.03), - WHITE, - WHITE, - darken(primary, 0.03), - darken(primary, 0.06), - darken(primary, 0.06), + lighten2(primary, 1), + darken(primary, 0.02), + darken(primary, 0.04), + darken(primary, 0.04), darken(primary, 0.03), - WHITE, + back, + back, [back, WHITE, WHITE][dif], WHITE @@ -100,6 +102,7 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { darken(primary, 0.06), darken(primary, 0.03), primary, + WHITE, WHITE, WHITE @@ -110,15 +113,16 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { colors = [ //default colorful option back, primary, + lighten2(back, 0.8), + darken(back, 0.1), WHITE, - lighten2(primary, 0.03), - WHITE, - WHITE, + lighten2(back, 1), + darken(back, 0.02), + darken(back, 0.04), + darken(back, 0.04), darken(back, 0.03), - darken(back, 0.06), - darken(back, 0.06), - darken(back, 0.03), - WHITE, + primary, + primary, [back, WHITE, WHITE][dif], WHITE @@ -172,6 +176,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { //containerHigh //surfaceVariant //onPrimaryLight + //primarySecond List colors = [ palette[0].onPrimaryFixedVariant, @@ -185,6 +190,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { darken2(palette[0].onPrimaryFixedVariant, 0.2), darken2(palette[0].onPrimaryFixedVariant, 0.1), palette[0].onTertiaryFixed, + palette[0].primaryFixed, palette[1], palette[2], @@ -202,6 +208,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { darken2(palette[0].onPrimaryFixedVariant, 0.2), darken2(palette[0].onPrimaryFixedVariant, 0.1), palette[0].onTertiaryFixed, + WHITE, palette[1], palette[2], @@ -220,6 +227,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { darken2(palette[0].onTertiaryFixedVariant, 0.2), darken2(palette[0].onTertiaryFixedVariant, 0.1), palette[0].onPrimaryFixed, + palette[0].tertiaryFixed, palette[1], palette[2], @@ -238,6 +246,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { palette[0].surfaceContainerHigh, palette[0].surfaceContainerHighest, palette[0].onPrimaryFixed, + palette[0].primaryFixedDim, palette[1], palette[2], @@ -256,6 +265,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { palette[0].surfaceContainerHigh, palette[0].surfaceContainerHighest, palette[0].onPrimaryFixed, + palette[0].primaryFixed, palette[1], palette[2], diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 721695b..f41574c 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -319,11 +319,11 @@ Widget NewAqiDataPoints(String name, double value, var data) { height: 2.5, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: data.current.primaryLighter, + color: data.current.primarySecond, ), ), ), - comfortatext(value.toString(), 15, data.settings, color: data.current.primaryLighter, + comfortatext(value.toString(), 15, data.settings, color: data.current.primarySecond, align: TextAlign.end, weight: FontWeight.w600), ], ); From 798f971549bd150fc3ecb8e9e42ed24d2a215857 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 10 Aug 2024 17:28:12 +0200 Subject: [PATCH 075/129] worked back to network images + trying to add back rain charts --- lib/decoders/decode_OM.dart | 16 +++-- lib/decoders/extra_info.dart | 11 ++-- lib/new_forecast.dart | 4 ++ lib/search_screens.dart | 3 +- lib/settings_page.dart | 4 +- lib/ui_helper.dart | 123 ++++++----------------------------- lib/weather_refact.dart | 8 +-- 7 files changed, 48 insertions(+), 121 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 79f213b..14afb2f 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -266,12 +266,13 @@ class OMCurrent { required this.image, }); - static Future fromJson(item, settings, sunstatus, timenow) async { + static Future fromJson(item, settings, sunstatus, timenow, real_loc, lat, lng) async { - // GET IMAGE - //Image Uimage = await getUnsplashImage(oMCurrentTextCorrection( - // oMBody["current"]["weather_code"], sunstatus, real_time), real_loc, lat, lng); + //GET IMAGE + Image Uimage = await getUnsplashImage(oMCurrentTextCorrection( + item["current"]["weather_code"], sunstatus, timenow), real_loc, lat, lng); + /* String imagePath = oMBackdropCorrection( oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), @@ -279,6 +280,8 @@ class OMCurrent { Image Uimage = Image.asset("assets/backdrops/$imagePath", fit: BoxFit.cover, width: double.infinity, height: double.infinity,); + */ + Color back = BackColorCorrection( oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), @@ -291,7 +294,8 @@ class OMCurrent { List colors; - if (settings["Color mode"] == "light" || settings["Color mode"] == "dark") { + //if (settings["Color mode"] == "light" || settings["Color mode"] == "dark") { + if (true) { List palette = await getImageColors(Uimage, settings["Color mode"], settings); colors = getNetworkColors(palette, settings); } @@ -658,7 +662,7 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as sunstatus: sunstatus, minutely_15_precip: OM15MinutePrecip.fromJson(oMBody, settings), - current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time), + current: await OMCurrent.fromJson(oMBody, settings, sunstatus, real_time, real_loc, lat, lng), days: days, lat: lat, diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 607c842..2f896a5 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -130,7 +130,8 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double print(index); print(unsplash_body[index]["links"]["html"]); - return Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover,); + return Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover, + width: double.infinity, height: double.infinity,); } Future MaterialYouColor(String theme) async { @@ -164,9 +165,10 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { final List used_colors = getNetworkColors([palette, BLACK, BLACK], settings); final List dominant = pali.colors.toList(); - Color startcolor = used_colors[2]; + Color startcolor = settings["Color mode"] == "light" || settings["Color mode"] == "dark" + ?used_colors[2] : used_colors[0]; - Color bestcolor = used_colors[2]; + Color bestcolor = startcolor; int bestDif = difFromBackColors(bestcolor, dominant); int base = (diffBetweenBackColors(dominant) * 0.7).round(); @@ -206,7 +208,8 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { } } - Color desc_color = used_colors[0]; + Color desc_color = settings["Color mode"] == "light" || settings["Color mode"] == "dark" + ?used_colors[0] : used_colors[1]; int desc_dif = difFromBackColors(desc_color, dominant); print(("diffs", bestDif, desc_dif)); diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 45ad7c6..a8b10d1 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -124,6 +124,10 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { ], ), ), + Visibility( + visible: day.mm_precip > 0.1, + child: RainWidget(data, day) + ), Padding( padding: const EdgeInsets.only(left: 8, right: 8, top: 20, bottom: 10), child: Container( diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 429e57e..236345f 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -475,7 +475,8 @@ class dumbySearch extends StatelessWidget { List colors = getColors(primary, back, settings, 0); return Scaffold( - drawer: MyDrawer(primary: primary, settings: settings, back: back, image: "grayscale_snow2.jpg"), + drawer: MyDrawer(primary: primary, settings: settings, back: back, image: Image.asset("assets/backdrops/grayscale_snow2.jpg", + fit: BoxFit.cover, width: double.infinity, height: double.infinity,)), backgroundColor: colors[0], body: StretchyHeader.singleChild( displacement: 150, diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 451cd38..1f8e136 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -180,7 +180,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { List colors = [ palette[0].onPrimaryFixedVariant, - palette[0].primaryFixed, + palette[0].tertiaryFixed, palette[0].tertiaryFixed, palette[0].secondaryFixed, palette[0].onSurface, @@ -190,7 +190,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { darken2(palette[0].onPrimaryFixedVariant, 0.2), darken2(palette[0].onPrimaryFixedVariant, 0.1), palette[0].onTertiaryFixed, - palette[0].primaryFixed, + palette[0].tertiaryFixed, palette[1], palette[2], diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index f41574c..dc69b4e 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -368,98 +368,13 @@ Widget aqiDataPoints(String name, double value, var data) { ); } -Widget WindWidget(data, day) { - List hours = day.hourly_for_precip; - - List wind = []; - - for (var i = 0; i < hours.length; i+= 2) { - double x = min(round((hours[i].wind + hours[i + 1].wind) * 0.5, decimals: 0) / 2, 10); - wind.add(x); - } - - return Column( - children: [ - Flex( - direction: Axis.horizontal, - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 15, right: 5, bottom: 5, top: 5), - child: Container( - height: 150, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all(width: 1.2, color: data.current.secondary) - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(18), - child: Padding( - padding: const EdgeInsets.all(6), - child: MyChart(wind, data), - ) - ), - ), - ), - ), - SizedBox( - height: 165, - width: 55, - child: ListView.builder( - reverse: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: 3, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.only(top: 30, bottom: 10, right: 4, left: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - comfortatext((index * 10).round().toString(), 17, data.settings), - comfortatext('m/s', 12, data.settings), - ], - ), - ); - } - ), - ) - ] - ), - Padding( - padding: const EdgeInsets.only(left: 33, top: 0, right: 70, bottom: 15), - child: Visibility( - visible: data.settings["Time mode"] == "24 hour", - replacement: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - comfortatext("3am", 14,data. settings), - comfortatext("9am", 14, data.settings), - comfortatext("3pm", 14, data.settings), - comfortatext("9pm", 14, data.settings), - ] - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - comfortatext("3:00", 14, data.settings), - comfortatext("9:00", 14, data.settings), - comfortatext("15:00", 14, data.settings), - comfortatext("21:00", 14, data.settings), - ] - ), - ) - ) - ], - ); -} - Widget RainWidget(data, day) { List hours = day.hourly_for_precip; List precip = []; - for (var i = 0; i < hours.length; i+= 2) { - double x = min(round((hours[i].precip + hours[i + 1].precip) * 4, decimals: 0) / 2, 10); + for (var i = 0; i < hours.length; i++) { + double x = min(round(hours[i].precip * 8, decimals: 0) / 2, 10); precip.add(x); } @@ -475,7 +390,7 @@ Widget RainWidget(data, day) { height: 150, decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), - border: Border.all(width: 1.2, color: data.current.secondary) + border: Border.all(width: 1.2, color: data.current.primary) ), child: ClipRRect( borderRadius: BorderRadius.circular(18), @@ -502,8 +417,8 @@ Widget RainWidget(data, day) { crossAxisAlignment: CrossAxisAlignment.end, children: [ comfortatext((index * 0.2).toStringAsFixed(1), 17, data.settings, - color: data.current.secondary), - comfortatext('in', 12, data.settings, color: data.current.secondary), + color: data.current.primary), + comfortatext('in', 12, data.settings, color: data.current.primary), ], ), ); @@ -515,8 +430,8 @@ Widget RainWidget(data, day) { crossAxisAlignment: CrossAxisAlignment.end, children: [ comfortatext((index * 5).toString(), 17, data.settings, - color: data.current.secondary), - comfortatext('mm', 12, data.settings, color: data.current.secondary), + color: data.current.primary), + comfortatext('mm', 12, data.settings, color: data.current.primary), ], ), ); @@ -533,19 +448,19 @@ Widget RainWidget(data, day) { replacement: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - comfortatext("3am", 14,data. settings, color: data.current.secondary), - comfortatext("9am", 14, data.settings, color: data.current.secondary), - comfortatext("3pm", 14, data.settings, color: data.current.secondary), - comfortatext("9pm", 14, data.settings, color: data.current.secondary), + comfortatext("3am", 14,data. settings, color: data.current.primary), + comfortatext("9am", 14, data.settings, color: data.current.primary), + comfortatext("3pm", 14, data.settings, color: data.current.primary), + comfortatext("9pm", 14, data.settings, color: data.current.primary), ] ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - comfortatext("3:00", 14, data.settings, color: data.current.secondary), - comfortatext("9:00", 14, data.settings, color: data.current.secondary), - comfortatext("15:00", 14, data.settings, color: data.current.secondary), - comfortatext("21:00", 14, data.settings, color: data.current.secondary), + comfortatext("3:00", 14, data.settings, color: data.current.primary), + comfortatext("9:00", 14, data.settings, color: data.current.primary), + comfortatext("15:00", 14, data.settings, color: data.current.primary), + comfortatext("21:00", 14, data.settings, color: data.current.primary), ] ), ) @@ -578,19 +493,19 @@ class BarChartPainter extends CustomPainter { void paint(Canvas canvas, Size size) { Paint paint = Paint() - ..color = data.current.surface + ..color = data.current.primary ..style = PaintingStyle.fill; double maxValue = 10; double scaleY = size.height / maxValue; - int numberOfBars = precip.length; // get rid of the extra precip points - double totalWidth = size.width; // Subtract padding + int numberOfBars = precip.length; + double totalWidth = size.width; double barWidth = totalWidth / numberOfBars; for (int i = 0; i < numberOfBars; i++) { double barHeight = precip[i] * scaleY; - double x = i * barWidth; // Add half of the remaining padding + double x = i * barWidth; double y = size.height - barHeight; double topRadius = 6.0; diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 0966384..c626d1c 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -327,10 +327,10 @@ Map> conversionTable = { //I am trying to convert conditions to text that unsplash better understands //for example: blue sky instead of clear sky tends to help a lot Map> textToUnsplashText = { - 'Clear Night': ['night', 'clear', 'night'], //somehow just 'night' always gives you clear skies: stars or moon - 'Partly Cloudy': ['cloudy', 'cloud', 'clouds',], //this is also some simplification which improves a lot - 'Clear Sky': ['blue sky', 'sunny', 'sun', 'clear',], //it doesn't understand clear as much so i use blue instead - 'Overcast': ['overcast', 'clouds'], + 'Clear Night': ['night', 'clear', 'moon'], //somehow just 'night' always gives you clear skies: stars or moon + 'Partly Cloudy': ['cloudy', 'cloud',], //this is also some simplification which improves a lot + 'Clear Sky': ['blue sky', 'sunny', 'sun', 'clear', 'cloud'], //it doesn't understand clear as much so i use blue instead + 'Overcast': ['overcast', 'cloud'], 'Haze': ['haze', 'fog', 'mist'], 'Rain': ['rain', 'drop', 'rainy', 'raining', 'drops'], 'Sleet': ['freezing rain', 'sleet', 'ice'],//this works much better From 8533e60b1a6a8d35ea2e13a32783a19093bdec9b Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sun, 11 Aug 2024 16:13:39 +0200 Subject: [PATCH 076/129] added rain charts + added precip chance for hourly + some tweaks to colors --- lib/decoders/decode_OM.dart | 5 +- lib/decoders/extra_info.dart | 30 +++--- lib/main_ui.dart | 4 +- lib/new_displays.dart | 2 +- lib/new_forecast.dart | 22 ++-- lib/settings_page.dart | 10 +- lib/ui_helper.dart | 201 +++++++++++++++++------------------ lib/weather_refact.dart | 2 +- 8 files changed, 137 insertions(+), 139 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 14afb2f..5dc468b 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -98,7 +98,7 @@ Future> OMRequestData(double lat, double lng, String real_loc) asy "longitude": lng.toString(), "minutely_15" : ["precipitation"], "current": ["temperature_2m", "relative_humidity_2m", "apparent_temperature", "weather_code", "wind_speed_10m", 'wind_direction_10m'], - "hourly": ["temperature_2m", "precipitation", "weather_code", "wind_speed_10m", "wind_direction_10m", "uv_index"], + "hourly": ["temperature_2m", "precipitation", "weather_code", "wind_speed_10m", "wind_direction_10m", "uv_index", "precipitation_probability"], "daily": ["weather_code", "temperature_2m_max", "temperature_2m_min", "uv_index_max", "precipitation_sum", "precipitation_probability_max", "wind_speed_10m_max", "wind_direction_10m_dominant", "sunrise", "sunset"], "timezone": "auto", "forecast_days": "14", @@ -515,6 +515,7 @@ class OMHour { final String time; final String text; final double precip; + final int precip_prob; final double wind; final int wind_dir; final int uv; @@ -536,6 +537,7 @@ class OMHour { required this.raw_wind, required this.wind_dir, required this.uv, + required this.precip_prob, }); static OMHour fromJson(item, index, settings, sunstatus) => OMHour( @@ -549,6 +551,7 @@ class OMHour { time: settings["Time mode"] == '12 hour'? oMamPmTime(item["hourly"]["time"][index]) : oM24hour(item["hourly"]["time"][index]), precip: unit_coversion(item["hourly"]["precipitation"][index], settings["Precipitation"]), + precip_prob: item["hourly"]["precipitation_probability"][index], wind: double.parse( unit_coversion(item["hourly"]["wind_speed_10m"][index], settings["Wind"]).toStringAsFixed(1)), wind_dir: item["hourly"]["wind_direction_10m"][index], diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 2f896a5..db04852 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -174,21 +174,21 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { int base = (diffBetweenBackColors(dominant) * 0.7).round(); print(("base", base)); - if (bestDif <= base + 80) { + if (bestDif <= base + 120) { print("trying"); for (int i = 1; i < 4; i++) { //LIGHT - Color newcolor = lighten(startcolor, i / 20); + Color newcolor = lighten2(startcolor, i / 9); int newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < base + 150) { + if (newdif > bestDif && newdif < base + 200) { bestDif = newdif; bestcolor = newcolor; } //DARK - newcolor = darken(startcolor, i / 20); + newcolor = darken2(startcolor, i / 7); newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < base + 150) { + if (newdif > bestDif && newdif < base + 200) { bestDif = newdif; bestcolor = newcolor; } @@ -196,15 +196,14 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { } //if the contrast is still low then we need to choose another color - if (bestDif <= base + 80) { + if (bestDif <= base + 120) { print("plan b"); - for (int i = 0; i < dominant.length; i++) { - Color newcolor = dominant[i]; - int newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < base + 250) { - bestDif = newdif; - bestcolor = newcolor; - } + Color newcolor = settings["Color mode"] == "light" || settings["Color mode"] == "dark" + ?used_colors[0] : used_colors[2]; + int newdif = difFromBackColors(newcolor, dominant); + if (newdif > bestDif && newdif < base + 250) { + bestDif = newdif; + bestcolor = newcolor; } } @@ -216,7 +215,7 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { print(("desc_dif", desc_dif)); - if (desc_dif < base + 40) { + if (desc_dif < base + 100) { desc_color = bestcolor; } @@ -320,14 +319,13 @@ Future _generatorPalette(Image imageWidget) async { return _paletteGenerator; } - Future _materialPalette(Image imageWidget, theme) async { final ImageProvider imageProvider = imageWidget.image; return ColorScheme.fromImageProvider( provider: imageProvider, brightness: theme == 'light' ? Brightness.light : Brightness.dark, - dynamicSchemeVariant: theme == 'o' || theme == 'm' ? DynamicSchemeVariant.fruitSalad : + dynamicSchemeVariant: theme == 'light' || theme == 'dark' ? DynamicSchemeVariant.tonalSpot : DynamicSchemeVariant.tonalSpot, ); } diff --git a/lib/main_ui.dart b/lib/main_ui.dart index 168ecd6..64c4ba8 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -389,7 +389,7 @@ Widget buildHihiDays(var data) => ListView.builder( ), Visibility( visible: day.mm_precip > 0.1, - child: RainWidget(data, day) + child: RainWidget(data, day, data.current.container) ), ], ), @@ -651,7 +651,7 @@ Widget buildGlanceDay(var data) => Padding( visible: day.mm_precip > rain_limit, child: Padding( padding: const EdgeInsets.only(top: 5), - child: RainWidget(data, day), + child: RainWidget(data, day, data.current.container), ) ), ], diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 99fcdb4..050dc6d 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -310,7 +310,7 @@ Widget NewAirQuality(var data) { Padding( padding: const EdgeInsets.all(3.0), child: comfortatext(data.aqi.aqi_desc, 14, data.settings, - color: data.current.onSurface, weight: FontWeight.w400), + color: data.current.primary, weight: FontWeight.w500), ), ], ), diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index a8b10d1..c239df6 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -126,10 +126,10 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { ), Visibility( visible: day.mm_precip > 0.1, - child: RainWidget(data, day) + child: RainWidget(data, day, highlight) ), Padding( - padding: const EdgeInsets.only(left: 8, right: 8, top: 20, bottom: 10), + padding: const EdgeInsets.only(left: 8, right: 8, top: 15, bottom: 10), child: Container( height: 85, padding: const EdgeInsets.only(top: 8, bottom: 8, left: 10, right: 10), @@ -263,7 +263,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { ), ), SizedBox( - height: 250, + height: state? 280 : 250, child: PageView( controller: _pageController, children: [ @@ -587,18 +587,23 @@ Widget buildPrecip(List hours, data, Color highlight) => ListView( child: Column( children: [ Padding( - padding: const EdgeInsets.only(top: 10, bottom: 10), + padding: const EdgeInsets.only(top: 10), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ comfortatext('${hour.precip}', 18, data.settings, color: data.current.primary, weight: FontWeight.w500), comfortatext('${data.settings["Precipitation"]}', 9, data.settings, color: data.current.primary), + Padding( + padding: const EdgeInsets.only(top: 6), + child: comfortatext('${hour.precip_prob}%', 14, data.settings, color: data.current.primaryLight, + weight: FontWeight.w600), + ), ], ), ), SizedBox( - height: 101, + height: 99, width: 15.5, child: GridView.builder( padding: EdgeInsets.zero, @@ -606,7 +611,7 @@ Widget buildPrecip(List hours, data, Color highlight) => ListView( crossAxisCount: 2, ), physics: const NeverScrollableScrollPhysics(), - itemCount: 26, + itemCount: 24, reverse: true, itemBuilder: (BuildContext context, int index) { double prec = hour.precip > 0 ? 1 : 0; @@ -637,7 +642,7 @@ Widget buildPrecip(List hours, data, Color highlight) => ListView( ), ), Padding( - padding: const EdgeInsets.only(top: 12, left: 3, right: 3), + padding: const EdgeInsets.only(top: 5, left: 3, right: 3), child: SizedBox( height: 30, child: Icon( @@ -719,7 +724,8 @@ class _buildNewGlanceDayState extends State with AutomaticKee return Padding( padding: const EdgeInsets.only(top: 3, bottom: 3), child: AnimatedContainer( - height: expand[index] ? 528.0 : 73.0, + height: expand[index] ? (day.mm_precip > 0.1 + ? (MediaQuery.of(context).size.width - 112) / 2.2 + 610: 528.0) : 73.0, duration: const Duration(milliseconds:250), child: SingleChildScrollView( physics: const NeverScrollableScrollPhysics(), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 1f8e136..ea4dd7e 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -180,17 +180,17 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { List colors = [ palette[0].onPrimaryFixedVariant, + palette[0].tertiary, palette[0].tertiaryFixed, - palette[0].tertiaryFixed, palette[0].secondaryFixed, - palette[0].onSurface, + palette[0].secondaryFixed, palette[0].outline, darken2(palette[0].onPrimaryFixedVariant, 0.09), darken2(palette[0].onPrimaryFixedVariant, 0.15), darken2(palette[0].onPrimaryFixedVariant, 0.2), darken2(palette[0].onPrimaryFixedVariant, 0.1), palette[0].onTertiaryFixed, - palette[0].tertiaryFixed, + palette[0].secondaryFixed, palette[1], palette[2], @@ -217,7 +217,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { else if (x == "colorful") { colors = [ palette[0].onTertiaryFixedVariant, - palette[0].tertiaryFixed, + palette[0].tertiary, palette[0].primaryFixed, palette[0].secondaryFixed, palette[0].onSurface, @@ -227,7 +227,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { darken2(palette[0].onTertiaryFixedVariant, 0.2), darken2(palette[0].onTertiaryFixedVariant, 0.1), palette[0].onPrimaryFixed, - palette[0].tertiaryFixed, + palette[0].secondaryFixed, palette[1], palette[2], diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index dc69b4e..2bcc15e 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -311,7 +311,7 @@ Widget NewAqiDataPoints(String name, double value, var data) { mainAxisAlignment: MainAxisAlignment.center, children: [ comfortatext(name, 15, data.settings, color: data.current.primary, - align: TextAlign.end), + align: TextAlign.end, weight: FontWeight.w500), Padding( padding: const EdgeInsets.all(3.0), child: Container( @@ -368,117 +368,77 @@ Widget aqiDataPoints(String name, double value, var data) { ); } -Widget RainWidget(data, day) { +Widget RainWidget(data, day, highlight) { List hours = day.hourly_for_precip; List precip = []; for (var i = 0; i < hours.length; i++) { - double x = min(round(hours[i].precip * 8, decimals: 0) / 2, 10); + double x = min(hours[i].precip, 10); precip.add(x); } - return Column( - children: [ - Flex( - direction: Axis.horizontal, + return Padding( + padding: const EdgeInsets.only(left: 14, right: 14, top: 15), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + //color: data.current.containerLow, + border: data.settings["Color mode"] == "dark" || data.settings["Color mode"] == "light" + ? Border.all(width: 3, color: highlight) + : Border.all(width: 1.6, color: data.current.primaryLight) + + ), + child: Column( children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 15, right: 5, bottom: 5, top: 5), - child: Container( - height: 150, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all(width: 1.2, color: data.current.primary) - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(18), - child: Padding( - padding: const EdgeInsets.all(6), - child: MyChart(precip, data), - ) - ), - ), + Padding( + padding: EdgeInsets.only(top: 14, right: 18, left: 18), + child: AspectRatio( + aspectRatio: 2.2, + child: MyChart(precip, data, highlight) ), ), - SizedBox( - height: 165, - width: 55, - child: ListView.builder( - reverse: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: 3, - itemBuilder: (context, index) { - if (data.settings["Precipitation"] == 'in') { - return Padding( - padding: const EdgeInsets.only(top: 30, bottom: 10, right: 4, left: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - comfortatext((index * 0.2).toStringAsFixed(1), 17, data.settings, - color: data.current.primary), - comfortatext('in', 12, data.settings, color: data.current.primary), - ], - ), - ); - } - else { - return Padding( - padding: const EdgeInsets.only(top: 30, bottom: 10, right: 4, left: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - comfortatext((index * 5).toString(), 17, data.settings, - color: data.current.primary), - comfortatext('mm', 12, data.settings, color: data.current.primary), - ], - ), - ); - } - } - ), + Padding( + padding: const EdgeInsets.only(top: 12, bottom: 14), + child: Visibility( + visible: data.settings["Time mode"] == "24 hour", + replacement: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + comfortatext("3am", 14,data. settings, color: data.current.outline), + comfortatext("9am", 14, data.settings, color: data.current.outline), + comfortatext("3pm", 14, data.settings, color: data.current.outline), + comfortatext("9pm", 14, data.settings, color: data.current.outline), + ] + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + comfortatext("3:00", 14, data.settings, color: data.current.outline), + comfortatext("9:00", 14, data.settings, color: data.current.outline), + comfortatext("15:00", 14, data.settings, color: data.current.outline), + comfortatext("21:00", 14, data.settings, color: data.current.outline), + ] + ), + ) ) - ] - ), - Padding( - padding: const EdgeInsets.only(left: 33, top: 0, right: 70, bottom: 15), - child: Visibility( - visible: data.settings["Time mode"] == "24 hour", - replacement: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - comfortatext("3am", 14,data. settings, color: data.current.primary), - comfortatext("9am", 14, data.settings, color: data.current.primary), - comfortatext("3pm", 14, data.settings, color: data.current.primary), - comfortatext("9pm", 14, data.settings, color: data.current.primary), - ] - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - comfortatext("3:00", 14, data.settings, color: data.current.primary), - comfortatext("9:00", 14, data.settings, color: data.current.primary), - comfortatext("15:00", 14, data.settings, color: data.current.primary), - comfortatext("21:00", 14, data.settings, color: data.current.primary), - ] - ), - ) - ) - ], + ], + ), + ), ); } class MyChart extends StatelessWidget { final List precip; // Sample data for the chart final data; + final highlight; - const MyChart(this.precip, this.data, {super.key}); + const MyChart(this.precip, this.data, this.highlight, {super.key}); @override Widget build(BuildContext context) { return CustomPaint( - painter: BarChartPainter(precip, data), + painter: BarChartPainter(precip, data, highlight), ); } } @@ -486,39 +446,70 @@ class MyChart extends StatelessWidget { class BarChartPainter extends CustomPainter { final List precip; final data; + final highlight; - BarChartPainter(this.precip, this.data); + BarChartPainter(this.precip, this.data, this.highlight); @override void paint(Canvas canvas, Size size) { - Paint paint = Paint() - ..color = data.current.primary + Paint circle_paint = Paint() + ..color = data.current.primaryLight ..style = PaintingStyle.fill; - double maxValue = 10; - double scaleY = size.height / maxValue; + Paint circle_paint2 = Paint() + ..color = highlight + ..style = PaintingStyle.fill; int numberOfBars = precip.length; double totalWidth = size.width; double barWidth = totalWidth / numberOfBars; for (int i = 0; i < numberOfBars; i++) { - double barHeight = precip[i] * scaleY; double x = i * barWidth; - double y = size.height - barHeight; - double topRadius = 6.0; + int circles = 10; + double y_dis = size.height / circles; + double start = size.height - barWidth * 0.5; - RRect roundedRect = RRect.fromLTRBR( - x + barWidth * 0.1, - y, - x + barWidth * 0.9, - size.height, - Radius.circular(topRadius), - ); + int smallerThan = (precip[i] * 2).round(); - canvas.drawRRect(roundedRect, paint); + print((precip[i], smallerThan)); + if (smallerThan == 0 && precip[i] > 0) { + smallerThan = 1; + } + + for (int i = 1; i < 21; i++) { + if (i <= smallerThan) { + canvas.drawArc( + Rect.fromCenter( + center: Offset(x + barWidth * 0.5, start), + height: barWidth * 0.8, + width: barWidth * 0.8, + ), + i % 2 == 0 ? pi : pi * 2, + pi, + false, + circle_paint, + ); + } + else { + canvas.drawArc( + Rect.fromCenter( + center: Offset(x + barWidth * 0.5, start), + height: barWidth * 0.8, + width: barWidth * 0.8, + ), + i % 2 == 0 ? pi : pi * 2, + pi, + false, + circle_paint2, + ); + //canvas.drawCircle(Offset(x + barWidth * 0.5, start), barWidth * 0.4, circle_paint2); + } + + start -= i % 2 == 1 ? 0 : y_dis; + } } } diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index c626d1c..fbcb210 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -328,7 +328,7 @@ Map> conversionTable = { //for example: blue sky instead of clear sky tends to help a lot Map> textToUnsplashText = { 'Clear Night': ['night', 'clear', 'moon'], //somehow just 'night' always gives you clear skies: stars or moon - 'Partly Cloudy': ['cloudy', 'cloud',], //this is also some simplification which improves a lot + 'Partly Cloudy': ['cloud',], //this is also some simplification which improves a lot 'Clear Sky': ['blue sky', 'sunny', 'sun', 'clear', 'cloud'], //it doesn't understand clear as much so i use blue instead 'Overcast': ['overcast', 'cloud'], 'Haze': ['haze', 'fog', 'mist'], From e4d7eff797a485d77c1672b3271b851d3b7e3b83 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sun, 11 Aug 2024 17:29:33 +0200 Subject: [PATCH 077/129] almost totally fixed up settigns --- lib/main_screens.dart | 2 +- lib/new_forecast.dart | 6 +- lib/search_screens.dart | 4 +- lib/settings_page.dart | 159 +++++++++++++++++++++++++--------------- lib/ui_helper.dart | 2 +- 5 files changed, 107 insertions(+), 66 deletions(-) diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 0d44968..59b5585 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -151,7 +151,7 @@ class _NewMainState extends State { data.settings, updateLocation, data.current.onSurface, - data.current.container, + data.current.containerLow, data.current.primary, data.provider, "${data.lat}, ${data.lng}", diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index c239df6..4e5def7 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -112,12 +112,12 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { padding: const EdgeInsets.only(top: 4), child: Row( children: [ - comfortatext(day.minmaxtemp.split("/")[0], 19, data.settings, color: data.current.primary), + comfortatext(day.minmaxtemp.split("/")[0], 20, data.settings, color: data.current.primary), Padding( padding: const EdgeInsets.only(left: 5, right: 4), child: comfortatext("/", 19, data.settings, color: data.current.onSurface), ), - comfortatext(day.minmaxtemp.split("/")[1], 19, data.settings, color: data.current.primary), + comfortatext(day.minmaxtemp.split("/")[1], 20, data.settings, color: data.current.primary), ], ), ) @@ -725,7 +725,7 @@ class _buildNewGlanceDayState extends State with AutomaticKee padding: const EdgeInsets.only(top: 3, bottom: 3), child: AnimatedContainer( height: expand[index] ? (day.mm_precip > 0.1 - ? (MediaQuery.of(context).size.width - 112) / 2.2 + 610: 528.0) : 73.0, + ? (MediaQuery.of(context).size.width - 110) / 2.2 + 610: 528.0) : 73.0, duration: const Duration(milliseconds:250), child: SingleChildScrollView( physics: const NeverScrollableScrollPhysics(), diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 236345f..968ec75 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -399,7 +399,7 @@ Widget LocationButton(Function updateProg, Function updateLocation, Color color, Color secondColor, Color textColor) { if (real_loc == 'CurrentLocation') { return Padding( - padding: const EdgeInsets.only(right: 6.5, top: 4, bottom: 4), + padding: const EdgeInsets.only(right: 7, top: 4.5, bottom: 4.5), child: AspectRatio( aspectRatio: 1, child: ElevatedButton( @@ -412,7 +412,7 @@ Widget LocationButton(Function updateProg, Function updateLocation, Color color, ) ), onPressed: () async {}, - child: Icon(Icons.place_outlined, color: textColor,), + child: Icon(Icons.place_outlined, color: color,), ), ), ); diff --git a/lib/settings_page.dart b/lib/settings_page.dart index ea4dd7e..5cb9400 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -23,6 +23,7 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/donation_page.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'decoders/decode_wapi.dart'; +import 'decoders/extra_info.dart'; import 'languages.dart'; import 'main.dart'; import 'main_ui.dart'; @@ -148,6 +149,7 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { ]; } + else if (x == "dark") { colors = [ //backcolor, primary, text BLACK, @@ -186,7 +188,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { palette[0].secondaryFixed, palette[0].outline, darken2(palette[0].onPrimaryFixedVariant, 0.09), - darken2(palette[0].onPrimaryFixedVariant, 0.15), + darken2(palette[0].onPrimaryFixedVariant, 0.12), darken2(palette[0].onPrimaryFixedVariant, 0.2), darken2(palette[0].onPrimaryFixedVariant, 0.1), palette[0].onTertiaryFixed, @@ -204,7 +206,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { palette[0].onSurface, WHITE, darken2(palette[0].onPrimaryFixedVariant, 0.09), - darken2(palette[0].onPrimaryFixedVariant, 0.15), + darken2(palette[0].onPrimaryFixedVariant, 0.12), darken2(palette[0].onPrimaryFixedVariant, 0.2), darken2(palette[0].onPrimaryFixedVariant, 0.1), palette[0].onTertiaryFixed, @@ -223,7 +225,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { palette[0].onSurface, palette[0].outline, darken2(palette[0].onTertiaryFixedVariant, 0.09), - darken2(palette[0].onTertiaryFixedVariant, 0.15), + darken2(palette[0].onTertiaryFixedVariant, 0.12), darken2(palette[0].onTertiaryFixedVariant, 0.2), darken2(palette[0].onTertiaryFixedVariant, 0.1), palette[0].onPrimaryFixed, @@ -274,6 +276,39 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { return colors; } +Future> getTotalColor(settings, primary, back, image) async { + List colors; + List> allColor = []; + + List palette = await getImageColors(image, settings["Color mode"], settings); + + if (settings["Color mode"] == "light" || settings["Color mode"] == "dark") { + //if (true) { + colors = getNetworkColors(palette, settings); + + allColor.add(getNetworkColors(palette, settings, force: "original")); + allColor.add(getNetworkColors(palette, settings, force: "colorful")); + allColor.add(getNetworkColors(palette, settings, force: "monochrome")); + allColor.add(getNetworkColors(palette, settings, force: "light")); + allColor.add(getNetworkColors(palette, settings, force: "dark")); + } + else { + colors = getColors(primary, back, settings, 0); + + allColor.add(getColors(primary, back, settings, 0, force: "original")); + allColor.add(getColors(primary, back, settings, 0, force: "colorful")); + allColor.add(getColors(primary, back, settings, 0, force: "dark")); + allColor.add(getNetworkColors(palette, settings, force: "light")); //because the light and dark use the + allColor.add(getNetworkColors(palette, settings, force: "dark")); // material palette generator anyway + } + return [colors, allColor]; +} + +Future> getSettingsAndColors(primary, back, image) async { + Map settings = await getSettingsUsed(); + List colors = await getTotalColor(settings, primary, back, image); + return [settings, colors]; +} Future> getSettingsUsed() async { Map settings = {}; @@ -362,14 +397,15 @@ Widget dropdown(Color bgcolor, String name, Function updatePage, String unit, se } ); } -Widget settingEntry(icon, text, settings, highlight, updatePage, textcolor, primary) { + +Widget settingEntry(icon, text, settings, highlight, updatePage, textcolor, primaryLight, primary) { return Padding( padding: const EdgeInsets.only(top: 3, bottom: 3), child: Row( children: [ Padding( padding: const EdgeInsets.only(right: 20), - child: Icon(icon, color: textcolor), + child: Icon(icon, color: primary), ), Expanded( flex: 10, @@ -382,7 +418,7 @@ Widget settingEntry(icon, text, settings, highlight, updatePage, textcolor, prim ), const Spacer(), dropdown( - darken(highlight), text, updatePage, settings[text]!, settings, textcolor, primary + darken(highlight), text, updatePage, settings[text]!, settings, textcolor, primaryLight ), ], ), @@ -401,9 +437,7 @@ Widget NavButton(text, settings, textcolor, icon) { ); } -Widget ColorCircle(name, primary, back, settings, updatePage, {w = 2, tap = 0}) { - - List colors = getColors(primary, back, settings, 0, force: name); +Widget ColorCircle(name, outline, inside, settings, updatePage, {w = 2, tap = 0}) { return Expanded( child: GestureDetector( @@ -424,10 +458,10 @@ Widget ColorCircle(name, primary, back, settings, updatePage, {w = 2, tap = 0}) child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(200), - border: Border.all(width: w * 1.0, color: colors[1]), - color: colors[0] + border: Border.all(width: w * 1.0, color: outline), + color: inside ), - child: tap == 1 ? Center(child: comfortatext(name[0], 20, settings, color: colors[2])) + child: tap == 1 ? Center(child: comfortatext(name[0], 20, settings, color: outline)) : Container(), ), ), @@ -478,31 +512,30 @@ class _SettingsPageState extends State { @override Widget build(BuildContext context) { - return FutureBuilder>( - future: getSettingsUsed(), + return FutureBuilder>( + future: getSettingsAndColors(primary, back, image), builder: (BuildContext context, - AsyncSnapshot> snapshot) { + AsyncSnapshot> snapshot) { if (snapshot.connectionState != ConnectionState.done) { return Container(); } else if (snapshot.hasError) { - print(snapshot.error); + print((snapshot.error, snapshot.stackTrace)); return Center( child: ErrorWidget(snapshot.error as Object), ); } - return SettingsMain(primary, snapshot.data, updatePage, goBack, back, image, context); + return SettingsMain(primary, snapshot.data?[0], updatePage, goBack, back, image, context, + snapshot.data?[1][0], snapshot.data?[1][1]); }, ); } } Widget SettingsMain(Color primary, Map? settings, Function updatePage, - Function goBack, Color back, Image image, context) { - - List colors = getColors(primary, back, settings, 0); + Function goBack, Color back, Image image, context, colors, allColors) { return Material( - color: colors[5], + color: colors[6], child: CustomScrollView( slivers: [ SliverAppBar.large( @@ -511,14 +544,14 @@ Widget SettingsMain(Color primary, Map? settings, Function updat goBack(); }), title: comfortatext(translation('Settings', settings!["Language"]!), 30, settings, color: colors[2]), - backgroundColor: colors[5], + backgroundColor: colors[6], pinned: false, ), // Just some content big enough to have something to scroll. SliverToBoxAdapter( child: Container( - color: colors[0], - child: settingsMain(colors[0], settings, updatePage, colors[2], colors[4], colors[5], colors[3], image, primary, back), + color: colors[6], + child: settingsMain(settings, updatePage, image, colors, allColors), ), ), ], @@ -526,14 +559,21 @@ Widget SettingsMain(Color primary, Map? settings, Function updat ); } -Widget settingsMain(Color color, Map settings, Function updatePage, - Color textcolor, Color secondary, highlight, Color colorpop, Image image, Color primary, - Color back) { +Widget settingsMain(Map settings, Function updatePage, Image image, List colors, + allColors) { + + Color containerLow = colors[6]; + Color onSurface = colors[4]; + Color primary = colors[1]; + Color primaryLight = colors[2]; + Color surface = colors[0]; + Color colorpop = colors[12]; + //var entryList = settings.entries.toList(); return Container( padding: const EdgeInsets.only(left: 20, right: 15), - color: highlight, + color: containerLow, child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Center( @@ -560,15 +600,15 @@ Widget settingsMain(Color color, Map settings, Function updatePa children: [ Padding( padding: const EdgeInsets.only(right: 20), - child: Icon(CupertinoIcons.circle_lefthalf_fill, color: textcolor, ), + child: Icon(CupertinoIcons.circle_lefthalf_fill, color: primary, ), ), Expanded( flex: 10, child: comfortatext(translation('Color mode', settings["Language"]!), 20, settings, - color: textcolor), + color: onSurface), ), const Spacer(), - comfortatext(settings["Color mode"]!, 20, settings, color: textcolor) + comfortatext(settings["Color mode"]!, 20, settings, color: primaryLight) ], ), ), @@ -585,7 +625,7 @@ Widget settingsMain(Color color, Map settings, Function updatePa borderRadius: const BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20)), - color: color, + color: surface, ), child: ClipRRect( borderRadius: BorderRadius.circular(20), @@ -595,7 +635,7 @@ Widget settingsMain(Color color, Map settings, Function updatePa height: 220, child: Stack( children: [ - ParrallaxBackground(image: image, color: color), + ParrallaxBackground(image: image, color: surface), Padding( padding: const EdgeInsets.only(left: 10, bottom: 15), child: Column( @@ -616,10 +656,11 @@ Widget settingsMain(Color color, Map settings, Function updatePa child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - ColorCircle(settings["Color mode"], primary, back, settings, updatePage), - ColorCircle(settings["Color mode"], primary, back, settings, updatePage), - ColorCircle(settings["Color mode"], primary, back, settings, updatePage), - ColorCircle(settings["Color mode"], primary, back, settings, updatePage), + //ColorCircle(settings["Color mode"], primary, surface, settings, updatePage), + ColorCircle("", primary, surface, settings, updatePage), + ColorCircle("", primary, surface, settings, updatePage), + ColorCircle("", primary, surface, settings, updatePage), + ColorCircle("", primary, surface, settings, updatePage) ], ), ) @@ -645,11 +686,11 @@ Widget settingsMain(Color color, Map settings, Function updatePa child: Row( mainAxisSize: MainAxisSize.min, children: [ - ColorCircle("original", primary, back, settings, updatePage, w: 4, tap: 1), - ColorCircle("colorful", primary, back, settings, updatePage, w: 4, tap: 1), - ColorCircle("monochrome", primary, back, settings, updatePage, w: 4, tap: 1), - ColorCircle("light", primary, back, settings, updatePage, w: 4, tap: 1), - ColorCircle("dark", primary, back, settings, updatePage, w: 4, tap: 1), + ColorCircle("original", primary, surface, settings, updatePage, w: 4, tap: 1), + ColorCircle("colorful", primary, surface, settings, updatePage, w: 4, tap: 1), + ColorCircle("monochrome", primary, surface, settings, updatePage, w: 4, tap: 1), + ColorCircle("light", primary, surface, settings, updatePage, w: 4, tap: 1), + ColorCircle("dark", primary, surface, settings, updatePage, w: 4, tap: 1), ] ), ), @@ -657,35 +698,35 @@ Widget settingsMain(Color color, Map settings, Function updatePa ), ), - settingEntry(CupertinoIcons.globe, "Language", settings, highlight, updatePage, - textcolor, secondary), - settingEntry(Icons.access_time_filled_sharp, "Time mode", settings, highlight, updatePage, - textcolor, secondary), - settingEntry(CupertinoIcons.textformat_size, "Font size", settings, highlight, updatePage, - textcolor, secondary), + settingEntry(CupertinoIcons.globe, "Language", settings, containerLow, updatePage, + onSurface, primaryLight, primary), + settingEntry(Icons.access_time_filled_sharp, "Time mode", settings, onSurface, updatePage, + onSurface, primaryLight, primary), + settingEntry(CupertinoIcons.textformat_size, "Font size", settings, onSurface, updatePage, + onSurface, primaryLight, primary), - settingEntry(Icons.manage_search_outlined, "Search provider", settings, highlight, updatePage, - textcolor, secondary), + settingEntry(Icons.manage_search_outlined, "Search provider", settings, onSurface, updatePage, + onSurface, primaryLight, primary), Padding( padding: const EdgeInsets.only(top: 20, bottom: 20, left: 12, right: 12), child: Container( height: 2, decoration: BoxDecoration( - color: secondary, + color: primaryLight, borderRadius: BorderRadius.circular(2) ), ), ), - settingEntry(CupertinoIcons.thermometer, "Temperature", settings, highlight, updatePage, - textcolor, secondary), - settingEntry(CupertinoIcons.drop_fill, "Precipitation", settings, highlight, updatePage, - textcolor, secondary), - settingEntry(CupertinoIcons.wind, "Wind", settings, highlight, updatePage, - textcolor, secondary), - settingEntry(CupertinoIcons.timelapse, "Pressure", settings, highlight, updatePage, - textcolor, secondary), + settingEntry(CupertinoIcons.thermometer, "Temperature", settings, onSurface, updatePage, + onSurface, primaryLight, primary), + settingEntry(CupertinoIcons.drop_fill, "Precipitation", settings, onSurface, updatePage, + onSurface, primaryLight, primary), + settingEntry(CupertinoIcons.wind, "Wind", settings, onSurface, updatePage, + onSurface, primaryLight, primary), + settingEntry(CupertinoIcons.timelapse, "Pressure", settings, onSurface, updatePage, + onSurface, primaryLight, primary), const SizedBox( height: 40, diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 2bcc15e..574bdf4 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -379,7 +379,7 @@ Widget RainWidget(data, day, highlight) { } return Padding( - padding: const EdgeInsets.only(left: 14, right: 14, top: 15), + padding: const EdgeInsets.only(left: 13, right: 13, top: 15), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(18), From 60791a3c9b130c940ad428bdcb0e323ee2ca8959 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 12 Aug 2024 16:39:30 +0200 Subject: [PATCH 078/129] finished with settings page color theme picker --- lib/main_screens.dart | 2 +- lib/settings_page.dart | 35 ++++++++++++++++++++--------------- lib/weather_refact.dart | 1 + 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 59b5585..66b2459 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -69,7 +69,7 @@ class _NewMainState extends State { headerData: HeaderData( //backgroundColor: WHITE, blurContent: false, - headerHeight: max(size.height * 0.53, 400), + headerHeight: max(size.height * 0.525, 400), //we don't want it to be smaller than 400 header: ParrallaxBackground(image: data.current.image, key: Key(data.place), color: data.current.surface == BLACK ? BLACK diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 5cb9400..aa3b21d 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -280,26 +280,31 @@ Future> getTotalColor(settings, primary, back, image) async { List colors; List> allColor = []; - List palette = await getImageColors(image, settings["Color mode"], settings); + final String mode = settings["Color mode"]; - if (settings["Color mode"] == "light" || settings["Color mode"] == "dark") { - //if (true) { - colors = getNetworkColors(palette, settings); + List lightPalette = await getImageColors(image, "light" , settings); + List darkPalette = await getImageColors(image, "dark" , settings); - allColor.add(getNetworkColors(palette, settings, force: "original")); - allColor.add(getNetworkColors(palette, settings, force: "colorful")); - allColor.add(getNetworkColors(palette, settings, force: "monochrome")); - allColor.add(getNetworkColors(palette, settings, force: "light")); - allColor.add(getNetworkColors(palette, settings, force: "dark")); + allColor.add(getNetworkColors(darkPalette, settings, force: "original")); + allColor.add(getNetworkColors(darkPalette, settings, force: "colorful")); + allColor.add(getNetworkColors(darkPalette, settings, force: "monochrome")); + allColor.add(getNetworkColors(lightPalette, settings, force: "light")); + allColor.add(getNetworkColors(darkPalette, settings, force: "dark")); + + //if (mode == "light" || mode == "dark") { + if (true) { + colors = getNetworkColors(mode == "light" ? lightPalette : darkPalette ,settings); } else { colors = getColors(primary, back, settings, 0); + /* allColor.add(getColors(primary, back, settings, 0, force: "original")); allColor.add(getColors(primary, back, settings, 0, force: "colorful")); allColor.add(getColors(primary, back, settings, 0, force: "dark")); allColor.add(getNetworkColors(palette, settings, force: "light")); //because the light and dark use the allColor.add(getNetworkColors(palette, settings, force: "dark")); // material palette generator anyway + */ } return [colors, allColor]; } @@ -535,7 +540,7 @@ Widget SettingsMain(Color primary, Map? settings, Function updat Function goBack, Color back, Image image, context, colors, allColors) { return Material( - color: colors[6], + color: colors[1], child: CustomScrollView( slivers: [ SliverAppBar.large( @@ -686,11 +691,11 @@ Widget settingsMain(Map settings, Function updatePage, Image ima child: Row( mainAxisSize: MainAxisSize.min, children: [ - ColorCircle("original", primary, surface, settings, updatePage, w: 4, tap: 1), - ColorCircle("colorful", primary, surface, settings, updatePage, w: 4, tap: 1), - ColorCircle("monochrome", primary, surface, settings, updatePage, w: 4, tap: 1), - ColorCircle("light", primary, surface, settings, updatePage, w: 4, tap: 1), - ColorCircle("dark", primary, surface, settings, updatePage, w: 4, tap: 1), + ColorCircle("original", allColors[0][1], allColors[0][0], settings, updatePage, w: 4, tap: 1), + ColorCircle("colorful", allColors[1][1], allColors[1][0], settings, updatePage, w: 4, tap: 1), + ColorCircle("monochrome", allColors[2][1], allColors[2][0], settings, updatePage, w: 4, tap: 1), + ColorCircle("light", allColors[3][1], allColors[3][0], settings, updatePage, w: 4, tap: 1), + ColorCircle("dark", allColors[4][1], allColors[4][0], settings, updatePage, w: 4, tap: 1), ] ), ), diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index fbcb210..9e355be 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -360,6 +360,7 @@ Map textFilter = { 'fabric': -10000, 'texture': -10000, 'pattern': -10000, + 'wall' : -10000, 'text': -10000, 'man': -10000000, //trying to not have people in images 'male': -1000000, From a084ac4207e5dad0d6c2ddc96476fafcaddc98d4 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 13 Aug 2024 17:18:32 +0200 Subject: [PATCH 079/129] cleaned up the error screen --- lib/decoders/decode_OM.dart | 18 +------ lib/main.dart | 4 +- lib/main_screens.dart | 17 +++--- lib/search_screens.dart | 41 +++++++++------ lib/settings_page.dart | 100 +++++++++++++++++++++--------------- 5 files changed, 99 insertions(+), 81 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 5dc468b..d44d242 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -292,21 +292,7 @@ class OMCurrent { item["current"]["weather_code"], sunstatus, timenow), ); - List colors; - - //if (settings["Color mode"] == "light" || settings["Color mode"] == "dark") { - if (true) { - List palette = await getImageColors(Uimage, settings["Color mode"], settings); - colors = getNetworkColors(palette, settings); - } - else { - colors = getColors(primary, back, settings, - ColorPopCorrection( oMCurrentTextCorrection( - item["current"]["weather_code"], sunstatus, timenow),)[ - settings["Color mode"] == "dark" ? 1 : 0 - ]); - } - + List colors = await getMainColor(settings, primary, back, Uimage); //List colors = palette.colors.toList(); @@ -335,7 +321,7 @@ class OMCurrent { primarySecond: colors[11], colorPop: colors[12], - descColor: colors[13], + descColor: colors[14], backup_backcolor: back, backup_primary: primary, diff --git a/lib/main.dart b/lib/main.dart index 06e2729..49f7ddc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -163,7 +163,7 @@ class _MyAppState extends State { return dumbySearch(errorMessage: "general error at place 1: ${hihi.toString()}", updateLocation: updateLocation, icon: Icons.bug_report, place: backupName, settings: settings, provider: weather_provider, latlng: absoluteProposed, - shouldAdd: "Please try another weather provider",); + shouldAdd: "Please try another weather provider!",); } on SocketException { return dumbySearch(errorMessage: translation("Not connected to the internet", settings["Language"]!), updateLocation: updateLocation, @@ -189,7 +189,7 @@ class _MyAppState extends State { return dumbySearch(errorMessage: "general error at place X: $e", updateLocation: updateLocation, icon: Icons.bug_report, place: backupName, settings: settings, provider: weather_provider, latlng: 'query', - shouldAdd: "Please try another weather provider",); + shouldAdd: "Please try another weather provider!",); } else { return getDays(true, proposedLoc, backupName, startup); diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 66b2459..fd4383a 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -57,10 +57,11 @@ class _NewMainState extends State { return Scaffold( backgroundColor: data.current.surface, - drawer: MyDrawer(primary: data.current.backup_primary, - back: data.current.backup_backcolor, - settings: data.settings, - image: data.current.image,), + drawer: MyDrawer(backupprimary: data.current.backup_primary, + backupback: data.current.backup_backcolor, settings: data.settings, image: data.current.image, + primary: data.current.primary, onSurface: data.current.onSurface, + surface: data.current.surface, + ), body: StretchyHeader.listView( displacement: 130, onRefresh: () async { @@ -169,7 +170,6 @@ class _NewMainState extends State { */ const Padding(padding: EdgeInsets.only(bottom: 20)) - ], ), ); @@ -191,8 +191,11 @@ Widget TabletLayout(data, updateLocation, context) { return Scaffold( backgroundColor: data.current.surface, - drawer: MyDrawer(primary: data.current.backup_primary, back: data.current.backup_backcolor, - settings: data.settings, image: data.current.image), + drawer: MyDrawer(backupprimary: data.current.backup_primary, + backupback: data.current.backup_backcolor, settings: data.settings, image: data.current.image, + primary: data.current.primary, onSurface: data.current.onSurface, + surface: data.current.surface, + ), body: RefreshIndicator( onRefresh: () async { await updateLocation("${data.lat}, ${data.lng}", data.real_loc); diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 968ec75..1dcf8ee 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -475,8 +475,10 @@ class dumbySearch extends StatelessWidget { List colors = getColors(primary, back, settings, 0); return Scaffold( - drawer: MyDrawer(primary: primary, settings: settings, back: back, image: Image.asset("assets/backdrops/grayscale_snow2.jpg", - fit: BoxFit.cover, width: double.infinity, height: double.infinity,)), + drawer: MyDrawer(backupprimary: primary, settings: settings, backupback: back, image: Image.asset("assets/backdrops/grayscale_snow2.jpg", + fit: BoxFit.cover, width: double.infinity, height: double.infinity,), surface: colors[0], + onSurface: colors[4], primary: colors[1], + ), backgroundColor: colors[0], body: StretchyHeader.singleChild( displacement: 150, @@ -485,13 +487,13 @@ class dumbySearch extends StatelessWidget { }, headerData: HeaderData( blurContent: false, - headerHeight: max(size.height * 0.54, 400), //we don't want it to be smaller than 400 + headerHeight: max(size.height * 0.525, 400), //we don't want it to be smaller than 400 header: ParrallaxBackground(image: Image.asset("assets/backdrops/grayscale_snow2.jpg", fit: BoxFit.cover,), key: Key(place), color: darken(colors[0], 0.1),), overlay: Stack( children: [ Padding( - padding: const EdgeInsets.all(20), + padding: const EdgeInsets.all(40), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -499,29 +501,38 @@ class dumbySearch extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.only(top: 50, bottom: 20), - child: Icon(icon, color: Colors.black54, size: 25), + child: Icon(icon, color: Colors.black54, size: 20), ), - comfortatext(newStr, 20, settings, color: Colors.black54, weight: FontWeight.w300, + comfortatext(newStr, 17, settings, color: Colors.black54, weight: FontWeight.w500, align: TextAlign.center), - Padding( - padding: const EdgeInsets.only(top: 20), - child: comfortatext(shouldAdd ?? "", 20, settings, color: Colors.black54, weight: FontWeight.w500, - align: TextAlign.center), - ), ], ), ), ), MySearchParent(updateLocation: updateLocation, color: colors[0], place: place, controller: controller, settings: settings, - real_loc: place, secondColor: colors[1], textColor: colors[2], highlightColor: colors[5], - extraTextColor: colors[5],), + real_loc: place, + secondColor: settings["Color mode"] == "light" ? colors[1] : colors[4], + textColor: settings["Color mode"] == "light" ? colors[2] : colors[1], + highlightColor: colors[6], + extraTextColor: colors[4],), ], ) ), child: - providerSelector(settings, updateLocation, colors[2], colors[5], - colors[1], provider, latlng, place), + Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 20), + child: comfortatext(shouldAdd ?? "", 16, settings, color: colors[4], weight: FontWeight.w400,), + ), + Padding( + padding: const EdgeInsets.only(top: 20), + child: providerSelector(settings, updateLocation, colors[4], colors[7], + colors[1], provider, latlng, place), + ), + ], + ), ), ); } diff --git a/lib/settings_page.dart b/lib/settings_page.dart index aa3b21d..21a87ac 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -130,22 +130,17 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { ]; } - else if (x == "light") { + else if (x == "light") { //only the error page uses these because it's otherwise the network palette colors = [ //backcolor, primary, text WHITE, primary, - lighten(primary, 0.1), + lighten(primary, 0.05), lighten(primary, 0.15), - Color.fromARGB(250, 30, 30, 30), - Color.fromARGB(250, 50, 50, 50), - Color.fromARGB(250, 245, 245, 245), - Color.fromARGB(250, 230, 230, 230), - Color.fromARGB(250, 220, 220, 220), - Color.fromARGB(250, 190, 190, 190), - primary, - - WHITE, - WHITE, + BLACK, + BLACK, + const Color.fromARGB(250, 245, 245, 245), + const Color.fromARGB(250, 240, 240, 240), + const Color.fromARGB(250, 230, 230, 230), ]; } @@ -153,11 +148,14 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { else if (x == "dark") { colors = [ //backcolor, primary, text BLACK, - lighten(primary, 0.25), - lighten(lightAccent(primary, 50000), 0.3), - [BLACK, primary, WHITE][dif], - lighten(lightAccent(primary, 60000), 0.25), - const Color(0xff141414), + primary, + lighten(primary, 0.1), + lighten(primary, 0.15), + WHITE, + WHITE, + const Color.fromARGB(250, 15, 15, 15), + const Color.fromARGB(250, 25, 25, 25), + const Color.fromARGB(250, 35, 35, 35), ]; } @@ -276,6 +274,23 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { return colors; } +Future> getMainColor(settings, primary, back, image) async { + List colors; + + final String mode = settings["Color mode"]; + + List palette = await getImageColors(image, mode , settings); + + //if (mode == "light" || mode == "dark") { + if (true) { + colors = getNetworkColors(palette ,settings); + } + else { + colors = getColors(primary, back, settings, 0); + } + return colors; +} + Future> getTotalColor(settings, primary, back, image) async { List colors; List> allColor = []; @@ -573,6 +588,7 @@ Widget settingsMain(Map settings, Function updatePage, Image ima Color primaryLight = colors[2]; Color surface = colors[0]; Color colorpop = colors[12]; + Color desc_color = colors[13]; //var entryList = settings.entries.toList(); @@ -648,8 +664,8 @@ Widget settingsMain(Map settings, Function updatePage, Image ima crossAxisAlignment: CrossAxisAlignment.start, children: [ comfortatext("${unit_coversion(29, settings["Temperature"]!).toInt()}°", 36, settings, color: colorpop), - comfortatext(translation("Partly Cloudy", settings["Language"]!), 20, - settings, color: WHITE) + comfortatext(translation("Clear Sky", settings["Language"]!), 20, + settings, color: desc_color) ], ), ), @@ -748,75 +764,77 @@ Widget settingsMain(Map settings, Function updatePage, Image ima class MyDrawer extends StatelessWidget { - final primary; - final back; + final backupprimary; + final backupback; final settings; final image; - const MyDrawer({super.key, required this.settings, required this.primary, required this.back, - required this.image}); + final primary; + final surface; + final onSurface; + + const MyDrawer({super.key, required this.settings, required this.backupback, required this.backupprimary, + required this.image, required this.surface, required this.primary, required this.onSurface}); @override Widget build(BuildContext context) { - List colors = getColors(primary, back, settings, 0); - return Drawer( - backgroundColor: colors[0], + backgroundColor: surface, elevation: 0, child: ListView( padding: EdgeInsets.zero, children: [ DrawerHeader( decoration: BoxDecoration( - color: colors[1], + color: primary, ), child: Column( children: [ Align( alignment: Alignment.center, - child: comfortatext('Overmorrow', 30, settings, color: colors[0]) + child: comfortatext('Overmorrow', 30, settings, color: surface) ), Align( alignment: Alignment.centerRight, - child: comfortatext('Weather', 30, settings, color: colors[0]) + child: comfortatext('Weather', 30, settings, color: surface) ), ], ), ), ListTile( title: comfortatext(translation('Settings', settings["Language"]), 25, - settings, color: colors[2]), - leading: Icon(Icons.settings, color: colors[2],), + settings, color: onSurface), + leading: Icon(Icons.settings, color: primary,), onTap: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => SettingsPage(primary: primary, - back: back, image: image,)), + MaterialPageRoute(builder: (context) => SettingsPage(primary: backupprimary, + back: backupback, image: image,)), ); }, ), ListTile( title: comfortatext(translation('About', settings["Language"]), 25, - settings, color: colors[2]), - leading: Icon(Icons.info_outline, color: colors[2],), + settings, color: onSurface), + leading: Icon(Icons.info_outline, color: primary,), onTap: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => InfoPage(primary: primary, settings: settings, - back: back,)), + MaterialPageRoute(builder: (context) => InfoPage(primary: backupprimary, settings: settings, + back: backupback,)), ); }, ), ListTile( title: comfortatext(translation('Donate', settings["Language"]), 25, - settings, color: colors[2]), - leading: Icon(Icons.favorite_border, color: colors[2],), + settings, color: onSurface), + leading: Icon(Icons.favorite_border, color: primary,), onTap: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => DonationPage(primary: primary, settings: settings, - back: back,)), + MaterialPageRoute(builder: (context) => DonationPage(primary: backupprimary, settings: settings, + back: backupback,)), ); }, ), From 3b9ef38ee76a866502518bf411d25627daf2e53e Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 13 Aug 2024 17:20:15 +0200 Subject: [PATCH 080/129] fixed a number i mistyped --- lib/decoders/decode_OM.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index d44d242..e81f05a 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -321,7 +321,7 @@ class OMCurrent { primarySecond: colors[11], colorPop: colors[12], - descColor: colors[14], + descColor: colors[13], backup_backcolor: back, backup_primary: primary, From 468ea19b878076dc6ab8f3f391bda98c567dae75 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 13 Aug 2024 17:50:36 +0200 Subject: [PATCH 081/129] brought all variables to settings --- lib/decoders/decode_OM.dart | 26 +++++++++++++------------- lib/decoders/extra_info.dart | 12 ++++++++---- lib/languages.dart | 29 +++++++++++++++++++++++++++++ lib/settings_page.dart | 27 ++++++++++++++++++++++----- 4 files changed, 72 insertions(+), 22 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index e81f05a..1e2a1db 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -269,18 +269,20 @@ class OMCurrent { static Future fromJson(item, settings, sunstatus, timenow, real_loc, lat, lng) async { //GET IMAGE - Image Uimage = await getUnsplashImage(oMCurrentTextCorrection( - item["current"]["weather_code"], sunstatus, timenow), real_loc, lat, lng); + Image Uimage; - /* - String imagePath = oMBackdropCorrection( - oMCurrentTextCorrection( - item["current"]["weather_code"], sunstatus, timenow), - ); - Image Uimage = Image.asset("assets/backdrops/$imagePath", fit: BoxFit.cover, - width: double.infinity, height: double.infinity,); - - */ + if (settings["Image source"] == "network") { + Uimage = await getUnsplashImage(oMCurrentTextCorrection( + item["current"]["weather_code"], sunstatus, timenow), real_loc, lat, lng); + } + else { + String imagePath = oMBackdropCorrection( + oMCurrentTextCorrection( + item["current"]["weather_code"], sunstatus, timenow), + ); + Uimage = Image.asset("assets/backdrops/$imagePath", fit: BoxFit.cover, + width: double.infinity, height: double.infinity,); + } Color back = BackColorCorrection( oMCurrentTextCorrection( @@ -294,8 +296,6 @@ class OMCurrent { List colors = await getMainColor(settings, primary, back, Uimage); - //List colors = palette.colors.toList(); - return OMCurrent( image: Uimage, diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index db04852..3404a35 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -154,13 +154,17 @@ Future MaterialYouColor(String theme) async { } Future> getImageColors(Image Uimage, color_mode, settings) async { + final PaletteGenerator pali = await _generatorPalette(Uimage); - //var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; - //color_mode = brightness == Brightness.dark ? "dark" : "light"; - //final ColorScheme palette = await MaterialYouColor(color_mode); + ColorScheme palette; - final ColorScheme palette = (await _materialPalette(Uimage, color_mode)); + if (settings["Color source"] == "image") { + palette = await _materialPalette(Uimage, color_mode); + } + else { + palette = await MaterialYouColor(color_mode); + } final List used_colors = getNetworkColors([palette, BLACK, BLACK], settings); diff --git a/lib/languages.dart b/lib/languages.dart index 5aff0b2..25a62f5 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -1253,6 +1253,35 @@ Map> mainTranslate = { 'Εύρεση τοποθεσίας...' ], + 'Color source': [ + 'Color source', + 'Szín forrása', + 'Fuente de color', + 'Source de couleur', + 'Farbquelle', + 'Fonte di colore', + 'Fonte de cor', + 'Источник цвета', + '颜色来源', + 'カラーソース', + 'Źródło koloru', + 'Πηγή χρώματος' + ], + 'Image source': [ + 'Image source', + 'Kép forrása', + 'Fuente de imagen', + "Source d'image", + 'Bildquelle', + "Fonte dell'immagine", + 'Fonte de imagem', + 'Источник изображения', + '图片来源', + '画像ソース', + 'Źródło obrazu', + 'Πηγή εικόνας' + ], + 'Search translation': [ //used for getting the codes used for translation of city names //If none are available then en (english) is the default // for more info visit https://open-meteo.com/en/docs/geocoding-api diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 21a87ac..6e38fc3 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -43,6 +43,9 @@ Map> settingSwitches = { 'Color mode' : ['original', 'colorful', 'monochrome', 'light', 'dark'], + 'Color source' : ['image', 'wallpaper'], + 'Image source' : ['network', 'asset'], + 'Search provider' : ['weatherapi', 'open-meteo'], }; @@ -281,8 +284,7 @@ Future> getMainColor(settings, primary, back, image) async { List palette = await getImageColors(image, mode , settings); - //if (mode == "light" || mode == "dark") { - if (true) { + if ((mode == "light" || mode == "dark") || settings["Image source"] == 'network') { colors = getNetworkColors(palette ,settings); } else { @@ -306,8 +308,7 @@ Future> getTotalColor(settings, primary, back, image) async { allColor.add(getNetworkColors(lightPalette, settings, force: "light")); allColor.add(getNetworkColors(darkPalette, settings, force: "dark")); - //if (mode == "light" || mode == "dark") { - if (true) { + if ((mode == "light" || mode == "dark") || settings["Image source"] == 'network') { colors = getNetworkColors(mode == "light" ? lightPalette : darkPalette ,settings); } else { @@ -621,7 +622,7 @@ Widget settingsMain(Map settings, Function updatePage, Image ima children: [ Padding( padding: const EdgeInsets.only(right: 20), - child: Icon(CupertinoIcons.circle_lefthalf_fill, color: primary, ), + child: Icon(Icons.palette_outlined, color: primary, ), ), Expanded( flex: 10, @@ -719,6 +720,22 @@ Widget settingsMain(Map settings, Function updatePage, Image ima ), ), + settingEntry(Icons.invert_colors_on, "Color source", settings, containerLow, updatePage, + onSurface, primaryLight, primary), + settingEntry(Icons.landscape_outlined, "Image source", settings, containerLow, updatePage, + onSurface, primaryLight, primary), + + Padding( + padding: const EdgeInsets.only(top: 20, bottom: 20, left: 12, right: 12), + child: Container( + height: 2, + decoration: BoxDecoration( + color: primaryLight, + borderRadius: BorderRadius.circular(2) + ), + ), + ), + settingEntry(CupertinoIcons.globe, "Language", settings, containerLow, updatePage, onSurface, primaryLight, primary), settingEntry(Icons.access_time_filled_sharp, "Time mode", settings, onSurface, updatePage, From 479f01723b1d9c39f53cc762bbff1807cde521b0 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 13 Aug 2024 18:14:46 +0200 Subject: [PATCH 082/129] fixed all the bugs that came with the new settings page items --- lib/decoders/extra_info.dart | 2 +- lib/settings_page.dart | 39 ++++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 3404a35..ad897fa 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -146,7 +146,7 @@ Future MaterialYouColor(String theme) async { final ColorScheme palette = ColorScheme.fromSeed( seedColor: mainColor, brightness: theme == 'light' ? Brightness.light : Brightness.dark, - dynamicSchemeVariant: theme == 'original' || theme == 'monochrome' ? DynamicSchemeVariant.fruitSalad : + dynamicSchemeVariant: theme == 'original' || theme == 'monochrome' ? DynamicSchemeVariant.tonalSpot : DynamicSchemeVariant.tonalSpot, ); diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 6e38fc3..f7a0876 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -79,7 +79,7 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { primary, back, lighten2(primary, 0.8), - darken2(primary, 0.4), + darken2(primary, 0.2), WHITE, lighten2(primary, 1), darken(primary, 0.02), @@ -282,14 +282,16 @@ Future> getMainColor(settings, primary, back, image) async { final String mode = settings["Color mode"]; - List palette = await getImageColors(image, mode , settings); + List palette = await getImageColors(image, mode, settings); - if ((mode == "light" || mode == "dark") || settings["Image source"] == 'network') { + if ((mode == "light" || mode == "dark") || settings["Image source"] == 'network' + || settings["Color source"] == 'wallpaper') { colors = getNetworkColors(palette ,settings); } else { colors = getColors(primary, back, settings, 0); } + return colors; } @@ -302,26 +304,29 @@ Future> getTotalColor(settings, primary, back, image) async { List lightPalette = await getImageColors(image, "light" , settings); List darkPalette = await getImageColors(image, "dark" , settings); - allColor.add(getNetworkColors(darkPalette, settings, force: "original")); - allColor.add(getNetworkColors(darkPalette, settings, force: "colorful")); - allColor.add(getNetworkColors(darkPalette, settings, force: "monochrome")); - allColor.add(getNetworkColors(lightPalette, settings, force: "light")); - allColor.add(getNetworkColors(darkPalette, settings, force: "dark")); - - if ((mode == "light" || mode == "dark") || settings["Image source"] == 'network') { - colors = getNetworkColors(mode == "light" ? lightPalette : darkPalette ,settings); + if (settings["Image source"] == 'network' || settings["Color source"] == 'wallpaper') { + allColor.add(getNetworkColors(darkPalette, settings, force: "original")); + allColor.add(getNetworkColors(darkPalette, settings, force: "colorful")); + allColor.add(getNetworkColors(darkPalette, settings, force: "monochrome")); + allColor.add(getNetworkColors(lightPalette, settings, force: "light")); + allColor.add(getNetworkColors(darkPalette, settings, force: "dark")); } else { - colors = getColors(primary, back, settings, 0); - - /* allColor.add(getColors(primary, back, settings, 0, force: "original")); allColor.add(getColors(primary, back, settings, 0, force: "colorful")); allColor.add(getColors(primary, back, settings, 0, force: "dark")); - allColor.add(getNetworkColors(palette, settings, force: "light")); //because the light and dark use the - allColor.add(getNetworkColors(palette, settings, force: "dark")); // material palette generator anyway - */ + allColor.add(getNetworkColors(lightPalette, settings, force: "light")); //because the light and dark use the + allColor.add(getNetworkColors(darkPalette, settings, force: "dark")); // material palette generator anyway + } + + if ((mode == "light" || mode == "dark") || settings["Image source"] == 'network' + || settings["Color source"] == 'wallpaper') { + colors = getNetworkColors(mode == "light" ? lightPalette : darkPalette ,settings); + } + else { + colors = getColors(primary, back, settings, 0); } + return [colors, allColor]; } From 26a0999d5b5a6bac96bcba1bb8ad8d79e0da2b9c Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 14 Aug 2024 17:50:04 +0200 Subject: [PATCH 083/129] did some minor tweaks all around --- lib/decoders/extra_info.dart | 6 ++---- lib/main_screens.dart | 8 ++++---- lib/new_displays.dart | 6 +----- lib/settings_page.dart | 2 +- lib/ui_helper.dart | 8 ++++++++ 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index ad897fa..6d79906 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -169,8 +169,7 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { final List used_colors = getNetworkColors([palette, BLACK, BLACK], settings); final List dominant = pali.colors.toList(); - Color startcolor = settings["Color mode"] == "light" || settings["Color mode"] == "dark" - ?used_colors[2] : used_colors[0]; + Color startcolor = used_colors[2]; Color bestcolor = startcolor; int bestDif = difFromBackColors(bestcolor, dominant); @@ -211,8 +210,7 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { } } - Color desc_color = settings["Color mode"] == "light" || settings["Color mode"] == "dark" - ?used_colors[0] : used_colors[1]; + Color desc_color = used_colors[0]; int desc_dif = difFromBackColors(desc_color, dominant); print(("diffs", bestDif, desc_dif)); diff --git a/lib/main_screens.dart b/lib/main_screens.dart index fd4383a..4db9516 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -92,15 +92,15 @@ class _NewMainState extends State { padding: const EdgeInsets.only(left: 0, bottom: 2), child: comfortatext( "${data.current.temp}°", 69, data.settings, - color: data.current.colorPop, weight: FontWeight.w300), + color: data.current.colorPop, weight: FontWeight.w300, + ) ), Padding( padding: const EdgeInsets.only(left: 0), child: comfortatext( data.current.text, 32, data.settings, - weight: data.settings["Color mode"] == "light" - ? FontWeight.w500 - : FontWeight.w400, + weight: estimateBrightnessForColor(data.current.descColor) + ? FontWeight.w500 : FontWeight.w700, color: data.current.descColor), ) ], diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 050dc6d..ba3ec50 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -299,11 +299,7 @@ Widget NewAirQuality(var data) { Align( alignment: Alignment.topLeft, child: comfortatext( - data.aqi.aqi_title, - 20, - data.settings, - color: data.current.primarySecond, - align: TextAlign.left, + data.aqi.aqi_title, 18, data.settings, color: data.current.primary, align: TextAlign.left, weight: FontWeight.w500, ), ), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index f7a0876..07728ec 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -286,7 +286,7 @@ Future> getMainColor(settings, primary, back, image) async { if ((mode == "light" || mode == "dark") || settings["Image source"] == 'network' || settings["Color source"] == 'wallpaper') { - colors = getNetworkColors(palette ,settings); + colors = getNetworkColors(palette, settings); } else { colors = getColors(primary, back, settings, 0); diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 574bdf4..e4d61b9 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -69,6 +69,14 @@ Widget comfortatext(String text, double size, settings, ); } +bool estimateBrightnessForColor(Color color) { + final double relativeLuminance = color.computeLuminance(); + + const double kThreshold = 0.15; + print((relativeLuminance + 0.05) * (relativeLuminance + 0.05) > kThreshold); + return (relativeLuminance + 0.05) * (relativeLuminance + 0.05) > kThreshold; +} + Color darken(Color color, [double amount = .1]) { assert(amount >= 0 && amount <= 1); From cb7d7018142397a86b0406189c5408206f6406d5 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 15 Aug 2024 09:36:54 +0200 Subject: [PATCH 084/129] weatherapi decoding is back. both providers functioning --- lib/decoders/decode_OM.dart | 1 - lib/decoders/decode_wapi.dart | 157 ++++++++++++++++++++++++---------- lib/main_ui.dart | 2 +- lib/new_displays.dart | 7 +- lib/settings_page.dart | 6 +- lib/ui_helper.dart | 12 +-- 6 files changed, 125 insertions(+), 60 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 1e2a1db..bd5a9be 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -268,7 +268,6 @@ class OMCurrent { static Future fromJson(item, settings, sunstatus, timenow, real_loc, lat, lng) async { - //GET IMAGE Image Uimage; if (settings["Image source"] == "network") { diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index d3210da..ee5aaa9 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -211,6 +211,7 @@ String getName(index, settings) { String backdropCorrection(name, isday) { String text = textCorrection(name, isday); String backdrop = weather_refactor.textBackground[text] ?? "haze.jpg"; + return backdrop; } @@ -245,7 +246,6 @@ List contentColorCorrection(name, isday) { class WapiCurrent { final String text; - final String backdrop; final int temp; final int humidity; final int feels_like; @@ -255,63 +255,103 @@ class WapiCurrent { final int wind; final int wind_dir; - final Color backcolor; + final Color surface; final Color primary; - final Color colorpop; - final Color textcolor; - final Color secondary; - final Color highlight; + final Color primaryLight; + final Color primaryLighter; + final Color onSurface; + final Color outline; + final Color containerLow; + final Color container; + final Color containerHigh; + final Color colorPop; + final Color descColor; + final Color surfaceVariant; + final Color onPrimaryLight; + final Color primarySecond; final Color backup_primary; final Color backup_backcolor; + final Image image; + const WapiCurrent({ - required this.feels_like, required this.precip, - required this.backcolor, - required this.backdrop, required this.humidity, + required this.feels_like, required this.temp, required this.text, required this.uv, required this.wind, - required this.textcolor, - required this.secondary, - required this.primary, - required this.highlight, - required this.backup_primary, required this.backup_backcolor, - required this.colorpop, + required this.backup_primary, required this.wind_dir, + + required this.surface, + required this.primary, + required this.primaryLight, + required this.primaryLighter, + required this.onSurface, + required this.outline, + required this.containerLow, + required this.container, + required this.containerHigh, + required this.colorPop, + required this.descColor, + required this.surfaceVariant, + required this.onPrimaryLight, + required this.primarySecond, + + required this.image, }); - static WapiCurrent fromJson(item, settings) { + static Future fromJson(item, settings, real_loc, lat, lng) async { + + Image Uimage; + + if (settings["Image source"] == "network") { + Uimage = await getUnsplashImage(textCorrection( + item["current"]["weather_code"], item["current"]["is_day"]), real_loc, lat, lng); + } + else { + String imagePath = backdropCorrection( + item["current"]["condition"]["code"], item["current"]["is_day"] + ); + Uimage = Image.asset("assets/backdrops/$imagePath", fit: BoxFit.cover, + width: double.infinity, height: double.infinity,); + } + Color back = BackColorCorrection( textCorrection( - item["current"]["condition"]["code"], item["current"]["is_day"], + item["current"]["condition"]["code"], item["current"]["is_day"], ), ); Color primary = PrimaryColorCorrection( - textCorrection( - item["current"]["condition"]["code"], item["current"]["is_day"], - ), + textCorrection( + item["current"]["condition"]["code"], item["current"]["is_day"], + ) ); - List colors = getColors(primary, back, settings, - ColorPopCorrection(textCorrection( - item["current"]["weather_code"], item["current"]["is_day"]),)[ - settings["Color mode"] == "dark" ? 1 : 0 - ]); + List colors = await getMainColor(settings, primary, back, Uimage); return WapiCurrent( - backcolor: colors[0], + surface: colors[0], primary: colors[1], - textcolor: colors[2], - colorpop: colors[3], - secondary: colors[4], - highlight: colors[5], + primaryLight: colors[2], + primaryLighter: colors[3], + onSurface: colors[4], + outline: colors[5], + containerLow: colors[6], + container: colors[7], + containerHigh: colors[8], + surfaceVariant: colors[9], + onPrimaryLight: colors[10], + primarySecond: colors[11], + + colorPop: colors[12], + descColor: colors[13], backup_backcolor: back, backup_primary: primary, @@ -320,9 +360,7 @@ class WapiCurrent { item["current"]["condition"]["code"], item["current"]["is_day"], language: settings["Language"] ), - backdrop: backdropCorrection( - item["current"]["condition"]["code"], item["current"]["is_day"] - ), + image: Uimage, temp: unit_coversion(item["current"]["temp_c"], settings["Temperature"]) .round(), feels_like: unit_coversion( @@ -343,6 +381,7 @@ class WapiCurrent { class WapiDay { final String text; final IconData icon; + final double iconSize; final String name; final String minmaxtemp; final List hourly; @@ -359,6 +398,7 @@ class WapiDay { const WapiDay({ required this.text, required this.icon, + required this.iconSize, required this.name, required this.minmaxtemp, required this.hourly, @@ -379,6 +419,9 @@ class WapiDay { icon: iconCorrection( item["day"]["condition"]["code"], 1 ), + iconSize: oMIconSizeCorrection(textCorrection( + item["day"]["condition"]["code"], 1, language: settings["Language"] + ),), name: getName(index, settings), minmaxtemp: '${unit_coversion(item["day"]["maxtemp_c"], settings["Temperature"]).round()}°' '/${unit_coversion(item["day"]["mintemp_c"], settings["Temperature"]).round()}°', @@ -414,10 +457,21 @@ class WapiDay { class WapiHour { final int temp; + final IconData icon; + final double iconSize; + final String time; final String text; final double precip; + final int precip_prob; + final double wind; + final int wind_dir; + final int uv; + + final double raw_temp; + final double raw_precip; + final double raw_wind; const WapiHour( { @@ -426,6 +480,14 @@ class WapiHour { required this.icon, required this.text, required this.precip, + required this.wind, + required this.iconSize, + required this.raw_precip, + required this.raw_temp, + required this.raw_wind, + required this.wind_dir, + required this.uv, + required this.precip_prob, }); static WapiHour fromJson(item, settings) => WapiHour( @@ -435,10 +497,23 @@ class WapiHour { icon: iconCorrection( item["condition"]["code"], item["is_day"] ), - //temp:double.parse(unit_coversion(item["temp_c"], settings["Temperature"]).toStringAsFixed(1)), + iconSize: oMIconSizeCorrection(textCorrection( + item["condition"]["code"], item["is_day"], language: settings["Language"] + ),), temp: unit_coversion(item["temp_c"], settings["Temperature"]).round(), time: getTime(item["time"], settings["Time mode"] == '12 hour'), - precip: item["precip_mm"] + (item["snow_cm"] / 10), + precip: unit_coversion(item["precip_mm"] + (item["snow_cm"] / 10), settings["Precipitation"]), + + raw_temp: item["temp_c"], + raw_precip: item["precip_mm"] + (item["snow_cm"] / 10), + raw_wind: item["wind_kph"], + + wind: double.parse(unit_coversion(item["wind_kph"], settings["Wind"]).toStringAsFixed(1)), + + precip_prob: max(item["chance_of_rain"], item["chance_of_snow"]), + uv: item["uv"].round(), + wind_dir: item["wind_degree"], + ); } @@ -516,16 +591,6 @@ Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) var wapi_body = wapi[0]; DateTime fetch_datetime = wapi[1]; - final text = textCorrection( - wapi_body["current"]["condition"]["code"], wapi_body["current"]["is_day"], - language: "English"); - - //GET IMAGE - Image Uimage = await getUnsplashImage(text, real_loc, lat, lng); - - //GET COLORS - List imageColors = await getImageColors(Uimage, settings["Color mode"], settings); - //String real_time = wapi_body["location"]["localtime"]; int epoch = wapi_body["location"]["localtime_epoch"]; WapiSunstatus sunstatus = WapiSunstatus.fromJson(wapi_body, settings); @@ -546,7 +611,7 @@ Future WapiGetWeatherData(lat, lng, real_loc, settings, placeName) lat: lat, lng: lng, - current: WapiCurrent.fromJson(wapi_body, settings,), + current: await WapiCurrent.fromJson(wapi_body, settings, real_loc, lat, lng), days: days, sunstatus: sunstatus, aqi: WapiAqi.fromJson(wapi_body), diff --git a/lib/main_ui.dart b/lib/main_ui.dart index 64c4ba8..80f6195 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -57,7 +57,7 @@ class WeatherPage extends StatelessWidget { //return PhoneLayout(data, updateLocation, context); return NewMain(data: data, updateLocation: updateLocation, context: context, - key: Key("${data.place}, ${data.current.surface} ${data.current.image}"),); + key: Key("${data.place}, ${data.current.surface} ${data.current.image} ${data.provider}"),); } } diff --git a/lib/new_displays.dart b/lib/new_displays.dart index ba3ec50..bb5f86e 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -299,14 +299,15 @@ Widget NewAirQuality(var data) { Align( alignment: Alignment.topLeft, child: comfortatext( - data.aqi.aqi_title, 18, data.settings, color: data.current.primary, align: TextAlign.left, + data.aqi.aqi_title, 19, data.settings, color: data.current.primarySecond, align: TextAlign.left, weight: FontWeight.w500, ), ), Padding( - padding: const EdgeInsets.all(3.0), + padding: const EdgeInsets.only(top: 5, left: 2), child: comfortatext(data.aqi.aqi_desc, 14, data.settings, - color: data.current.primary, weight: FontWeight.w500), + color: data.settings["Color mode"] == "light" ? data.current.primary : data.current.onSurface, + weight: FontWeight.w500), ), ], ), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 07728ec..cafcaea 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -117,10 +117,10 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { colors = [ //default colorful option back, primary, - lighten2(back, 0.8), + lighten2(back, 0.73), darken(back, 0.1), - WHITE, - lighten2(back, 1), + lighten2(back, 0.73), + lighten2(back, 0.73), darken(back, 0.02), darken(back, 0.04), darken(back, 0.04), diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index e4d61b9..829d172 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -343,8 +343,8 @@ Widget aqiDataPoints(String name, double value, var data) { child: LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { double width; - if (constraints.maxWidth > 300) { - width = 200; + if (constraints.maxWidth > 100) { + width = 100; } else {width = constraints.maxWidth;} @@ -354,18 +354,18 @@ Widget aqiDataPoints(String name, double value, var data) { padding: const EdgeInsets.only(left: 10, bottom: 1.5, top: 1.5), child: Row( children: [ - comfortatext(name, 18, data.settings, color: data.current.outline, + comfortatext(name, 16, data.settings, color: data.current.primary, weight: FontWeight.w400), const Spacer(), Container( padding: const EdgeInsets.only(top:4,bottom: 3, left: 4, right: 4), decoration: BoxDecoration( //border: Border.all(color: Colors.blueAccent) - color: data.current.surface, + color: data.current.primaryLight, borderRadius: BorderRadius.circular(10) ), - child: comfortatext(value.toString(), 17, data.settings, - color: data.current.container, weight: FontWeight.w600) + child: comfortatext(value.toString(), 15, data.settings, + color: data.current.onPrimaryLight, weight: FontWeight.w500) ) ], ), From abc2241772c71d558b7ec44cd599d51124cd345e Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 15 Aug 2024 16:58:32 +0200 Subject: [PATCH 085/129] started on some translations --- lib/decoders/decode_OM.dart | 33 +++-- lib/languages.dart | 252 ++++++++++++++++++++++++++++-------- lib/main_screens.dart | 2 +- lib/new_forecast.dart | 116 +++++++++-------- lib/settings_page.dart | 4 +- lib/weather_refact.dart | 2 +- 6 files changed, 285 insertions(+), 124 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index bd5a9be..520624f 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -36,6 +36,24 @@ String OMConvertTime(String time) { return time.split("T")[1]; } +String OmAqiDesc(index, language) { + String desc = ['Air quality is excellent; no health risk.', + 'Acceptable air quality; minor risk for sensitive people.', + 'Sensitive individuals may experience mild effects.', + 'Health effects possible for everyone, serious for sensitive groups.', + 'Serious health effects for everyone.', + 'Emergency conditions; severe health effects for all.'] + [index - 1]; + return translation(desc, language); +} + + +String OmAqiTitle(index, language) { + String desc = ['good', 'fair', 'moderate', 'poor', 'very poor', 'unhealthy'] + [index - 1]; + return translation(desc, language); +} + String OMamPmTime(String time) { String a = time.split("T")[1]; List num = a.split(":"); @@ -593,7 +611,7 @@ class OMAqi{ required this.aqi_title, }); - static Future fromJson(item, lat, lng) async { + static Future fromJson(item, lat, lng, settings) async { final params = { "latitude": lat.toString(), "longitude": lng.toString(), @@ -613,16 +631,9 @@ class OMAqi{ no2: item["nitrogen_dioxide"], o3: item["ozone"], - aqi_title: ['good', 'fair', 'moderate', 'poor', 'very poor', 'unhealthy'] - [index - 1], + aqi_title: OmAqiTitle(index, settings["Language"]), - aqi_desc: ['Air quality is excellent; no health risk.', - 'Acceptable air quality; minor risk for sensitive people.', - 'Sensitive individuals may experience mild effects.', - 'Health effects possible for everyone, serious for sensitive groups.', - 'Serious health effects for everyone.', - 'Emergency conditions; severe health effects for all.'] - [index - 1], + aqi_desc: OmAqiDesc(index, settings["Language"]), ); } } @@ -646,7 +657,7 @@ Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) as return WeatherData( radar: await RainviewerRadar.getData(), - aqi: await OMAqi.fromJson(oMBody, lat, lng), + aqi: await OMAqi.fromJson(oMBody, lat, lng, settings), sunstatus: sunstatus, minutely_15_precip: OM15MinutePrecip.fromJson(oMBody, settings), diff --git a/lib/languages.dart b/lib/languages.dart index 25a62f5..b08067b 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -900,6 +900,7 @@ Map> mainTranslate = { 'jakość powietrza', 'ποιότητα αέρος' ], + 'good': [ 'good', 'jó', @@ -908,39 +909,67 @@ Map> mainTranslate = { 'gut', 'buono', 'bom', - 'хорошо', + 'хороший', '好', - '良好', - 'dobra', - 'καλή' + '良い', + 'dobry', + 'καλός' + ], + 'fair': [ + 'fair', + 'elfogadható', + 'aceptable', + 'passable', + 'akzeptabel', + 'accettabile', + 'razoável', + 'удовлетворительный', + '公平', + '公平', + 'dopuszczalny', + 'δίκαιος' ], 'moderate': [ 'moderate', - 'közepes', + 'mérsékelt', 'moderado', 'modéré', 'mäßig', 'moderato', 'moderado', 'умеренный', - '适度', + '适中', '適度', - 'średnia', - 'μέτρια' - ], - 'slightly unhealthy': [ - 'slightly unhealthy', - 'enyhén egészségtelen', - 'ligeramente insalubre', - 'légèrement malsain', - 'leicht ungesund', - 'lievemente insalubre', - 'levemente insalubre', - 'слегка нездоровый', - '轻微不健康', - '軽度不健康', - 'lekko szkodliwa', - 'ελαφρώς επιβλαβής' + 'umiarkowany', + 'μέτριος' + ], + 'poor': [ + 'poor', + 'gyenge', + 'pobre', + 'pauvre', + 'schlecht', + 'scarso', + 'pobre', + 'плохой', + '较差', + '悪い', + 'słaby', + 'κακός' + ], + 'very poor': [ + 'very poor', + 'nagyon gyenge', + 'muy pobre', + 'très pauvre', + 'sehr schlecht', + 'molto scarso', + 'muito pobre', + 'очень плохой', + '非常差', + '非常に悪い', + 'bardzo słaby', + 'πολύ κακός' ], 'unhealthy': [ 'unhealthy', @@ -948,42 +977,15 @@ Map> mainTranslate = { 'insalubre', 'malsain', 'ungesund', + 'malsano', 'insalubre', - 'não saudável', - 'нездоровый', + 'вредный для здоровья', '不健康', '不健康', - 'szkodliwa', - 'επιβλαβής' - ], - 'very unhealthy': [ - 'very unhealthy', - 'nagyon egészségtelen', - 'muy insalubre', - 'très malsain', - 'sehr ungesund', - 'molto insalubre', - 'muito insalubre', - 'очень нездоровый', - '非常不健康', - '非常に不健康', - 'bardzo szkodliwa', - 'πολύ επιβλαβής' - ], - 'hazardous': [ - 'hazardous', - 'veszélyes', - 'peligroso', - 'dangereux', - 'gefährlich', - 'pericoloso', - 'perigoso', - 'опасный', - '危险', - '有害', - 'niebezpieczna', - 'επικίνδυνος' + 'niezdrowy', + 'ανθυγιεινός' ], + 'precipitation': [ 'precipitation', 'csapadék', @@ -1282,6 +1284,148 @@ Map> mainTranslate = { 'Πηγή εικόνας' ], + 'temp': [ + 'temp', + 'hőmérs.', + 'temp', + 'temp', + 'temp', + 'temp', + 'temp', + 'темп', + '温度', + '気温', + 'temp', + 'θερμ.' + ], + 'precip': [ + 'precip', + 'csapad.', + 'precip', + 'précip', + 'Niederschl.', + 'precip', + 'precip', + 'осадки', + '降水', + '降水', + 'opad', + 'κατ. βροχής' + ], + 'wind': [ + 'wind', + 'szél', + 'viento', + 'vent', + 'wind', + 'vento', + 'vento', + 'ветер', + '风', + '風', + 'wiatr', + 'άνεμος' + ], + 'uv': [ + 'uv', + 'uv', + 'uv', + 'uv', + 'uv', + 'uv', + 'uv', + 'ув', + '紫外线', + '紫外線', + 'uv', + 'uv' + ], + + 'Air quality is excellent; no health risk.': [ + 'Air quality is excellent; no health risk.', + 'A levegő minősége kiváló; nincs egészségügyi kockázat.', + 'La calidad del aire es excelente; no hay riesgo para la salud.', + "La qualité de l'air est excellente; aucun risque pour la santé.", + 'Die Luftqualität ist ausgezeichnet; kein Gesundheitsrisiko.', + "La qualità dell'aria è eccellente; nessun rischio per la salute.", + 'A qualidade do ar é excelente; sem risco à saúde.', + 'Качество воздуха отличное; угрозы для здоровья нет.', + '空气质量极佳;无健康风险。', + '空気の質は非常に良好です。健康へのリスクはありません。', + 'Jakość powietrza jest doskonała; brak ryzyka dla zdrowia.', + 'Η ποιότητα του αέρα είναι εξαιρετική. Δεν υπάρχει κίνδυνος για την υγεία.' + ], + 'Acceptable air quality; minor risk for sensitive people.': [ + 'Acceptable air quality; minor risk for sensitive people.', + 'Elfogadható a levegő minősége; kisebb kockázat az érzékeny emberek számára.', + 'Calidad del aire aceptable; riesgo menor para personas sensibles.', + "Qualité de l'air acceptable; risque mineur pour les personnes sensibles.", + 'Akzeptable Luftqualität; geringes Risiko für empfindliche Personen.', + "Qualità dell'aria accettabile; rischio minore per le persone sensibili.", + 'Qualidade do ar aceitável; risco menor para pessoas sensíveis.', + 'Приемлемое качество воздуха; незначительный риск для чувствительных людей.', + '可接受的空气质量;对敏感人群有轻微风险。', + '許容できる空気の質。敏感な人にわずかなリスクがあります。', + 'Akceptowalna jakość powietrza; niewielkie ryzyko dla osób wrażliwych.', + 'Αποδεκτή ποιότητα αέρα· ελάχιστος κίνδυνος για ευαίσθητα άτομα.' + ], + 'Sensitive individuals may experience mild effects.': [ + 'Sensitive individuals may experience mild effects.', + 'Az érzékeny egyének enyhe hatásokat tapasztalhatnak.', + 'Las personas sensibles pueden experimentar efectos leves.', + 'Les personnes sensibles peuvent ressentir des effets légers.', + 'Empfindliche Personen können leichte Auswirkungen erfahren.', + 'Gli individui sensibili possono sperimentare effetti lievi.', + 'Indivíduos sensíveis podem sentir efeitos leves.', + 'Чувствительные люди могут испытывать легкие эффекты.', + '敏感人群可能会出现轻微影响。', + '敏感な人々は軽度の影響を受ける可能性があります。', + 'Osoby wrażliwe mogą odczuwać łagodne skutki.', + 'Τα ευαίσθητα άτομα ενδέχεται να παρουσιάσουν ήπια αποτελέσματα.' + ], + 'Health effects possible for everyone, serious for sensitive groups.': [ + 'Health effects possible for everyone, serious for sensitive groups.', + 'Egészségügyi hatások mindenkire, súlyos hatások az érzékeny csoportokra.', + 'Posibles efectos en la salud para todos, graves para grupos sensibles.', + 'Effets sur la santé possibles pour tout le monde, graves pour les groupes sensibles.', + 'Gesundheitliche Auswirkungen möglich für alle, ernst für empfindliche Gruppen.', + 'Effetti sulla salute possibili per tutti, seri per i gruppi sensibili.', + 'Efeitos na saúde possíveis para todos, sérios para grupos sensíveis.', + 'Возможны последствия для здоровья у всех, серьезные для чувствительных групп.', + '可能对所有人造成健康影响,对敏感人群影响严重。', + 'すべての人に健康への影響があり、敏感なグループにとって深刻です。', + 'Możliwe skutki zdrowotne dla wszystkich, poważne dla grup wrażliwych.', + 'Πιθανές επιπτώσεις στην υγεία για όλους, σοβαρές για τις ευαίσθητες ομάδες.' + ], + 'Serious health effects for everyone.': [ + 'Serious health effects for everyone.', + 'Súlyos egészségügyi hatások mindenkire.', + 'Graves efectos en la salud para todos.', + 'Effets graves sur la santé pour tout le monde.', + 'Schwere gesundheitliche Auswirkungen für alle.', + 'Effetti gravi sulla salute per tutti.', + 'Graves efeitos na saúde para todos.', + 'Серьезные последствия для здоровья у всех.', + '对所有人都有严重的健康影响。', + 'すべての人に深刻な健康への影響があります。', + 'Poważne skutki zdrowotne dla wszystkich.', + 'Σοβαρές επιπτώσεις στην υγεία για όλους.' + ], + 'Emergency conditions; severe health effects for all.': [ + 'Emergency conditions; severe health effects for all.', + 'Vészhelyzet; súlyos egészségügyi hatások mindenkire.', + 'Condiciones de emergencia; graves efectos en la salud para todos.', + "Conditions d'urgence; effets graves sur la santé pour tout le monde.", + 'Notfallbedingungen; schwere gesundheitliche Auswirkungen für alle.', + 'Condizioni di emergenza; gravi effetti sulla salute per tutti.', + 'Condições de emergência; graves efeitos na saúde para todos.', + 'Чрезвычайные условия; серьезные последствия для здоровья у всех.', + '紧急情况;对所有人造成严重的健康影响。', + '緊急事態。すべての人に深刻な健康への影響があります。', + 'Warunki awaryjne; poważne skutki zdrowotne dla wszystkich.', + 'Συνθήκες έκτακτης ανάγκης· σοβαρές επιπτώσεις στην υγεία για όλους.' + ], + 'Search translation': [ //used for getting the codes used for translation of city names //If none are available then en (english) is the default // for more info visit https://open-meteo.com/en/docs/geocoding-api diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 4db9516..d3f0403 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -100,7 +100,7 @@ class _NewMainState extends State { child: comfortatext( data.current.text, 32, data.settings, weight: estimateBrightnessForColor(data.current.descColor) - ? FontWeight.w500 : FontWeight.w700, + ? FontWeight.w400 : FontWeight.w600, color: data.current.descColor), ) ], diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 4e5def7..c466a94 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -21,6 +21,7 @@ import 'dart:math'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:overmorrow/settings_page.dart'; import 'ui_helper.dart'; @@ -248,7 +249,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { }), side: BorderSide(color: data.current.primaryLighter, width: 1.5), label: comfortatext( - ['temp', 'precip', 'wind', 'uv'][index], 14, data.settings, + translation(['temp', 'precip', 'wind', 'uv'][index], data.settings["Language"]), 14, data.settings, color: _value == index ? data.current.onPrimaryLight : data.current.onSurface), selected: _value == index, onSelected: (bool selected) { @@ -699,62 +700,67 @@ class _buildNewGlanceDayState extends State with AutomaticKee @override Widget build(BuildContext context) { super.build(context); - return Padding( - padding: const EdgeInsets.only(left: 24, right: 24, bottom: 10, top: 10), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(left: 1, top: 0, bottom: 6), - child: Align( - alignment: Alignment.centerLeft, - child: comfortatext( - "daily", 16, - data.settings, - color: data.current.onSurface), + if (data.days.length > 3) { + return Padding( + padding: const EdgeInsets.only(left: 24, right: 24, bottom: 10, top: 10), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(left: 1, top: 0, bottom: 6), + child: Align( + alignment: Alignment.centerLeft, + child: comfortatext( + "daily", 16, + data.settings, + color: data.current.onSurface), + ), ), - ), - ListView.builder( - shrinkWrap: true, - padding: const EdgeInsets.only( - top: 5, bottom: 5, left: 0, right: 0), - physics: const NeverScrollableScrollPhysics(), - itemCount: data.days.length - 3, - itemBuilder: (context, index) { - final day = data.days[index + 3]; - return Padding( - padding: const EdgeInsets.only(top: 3, bottom: 3), - child: AnimatedContainer( - height: expand[index] ? (day.mm_precip > 0.1 - ? (MediaQuery.of(context).size.width - 110) / 2.2 + 610: 528.0) : 73.0, - duration: const Duration(milliseconds:250), - child: SingleChildScrollView( - physics: const NeverScrollableScrollPhysics(), - child: expand[index] ? Container( - decoration: BoxDecoration( - borderRadius: - index == 0 ? const BorderRadius.vertical( - top: Radius.circular(18.0), - bottom: Radius.circular(8)) - : index == data.days.length - 4 ? const BorderRadius - .vertical(bottom: Radius.circular(18.0), - top: Radius.circular(8)) - : BorderRadius.circular(8), - color: data.current.containerLow), - child: Padding( - padding: const EdgeInsets.only(top: 25, left: 3, right: 3), - child: NewDay(data: data, index: index, state: true, - onExpandTapped: _onExpandTapped, day: day,), - ), - ) - : GlanceDayEntry(data, index, day, _onExpandTapped), + ListView.builder( + shrinkWrap: true, + padding: const EdgeInsets.only( + top: 5, bottom: 5, left: 0, right: 0), + physics: const NeverScrollableScrollPhysics(), + itemCount: data.days.length - 3, + itemBuilder: (context, index) { + final day = data.days[index + 3]; + return Padding( + padding: const EdgeInsets.only(top: 3, bottom: 3), + child: AnimatedContainer( + height: expand[index] ? (day.mm_precip > 0.1 + ? (MediaQuery.of(context).size.width - 110) / 2.2 + 610: 528.0) : 73.0, + duration: const Duration(milliseconds:250), + child: SingleChildScrollView( + physics: const NeverScrollableScrollPhysics(), + child: expand[index] ? Container( + decoration: BoxDecoration( + borderRadius: + index == 0 ? const BorderRadius.vertical( + top: Radius.circular(18.0), + bottom: Radius.circular(8)) + : index == data.days.length - 4 ? const BorderRadius + .vertical(bottom: Radius.circular(18.0), + top: Radius.circular(8)) + : BorderRadius.circular(8), + color: data.current.containerLow), + child: Padding( + padding: const EdgeInsets.only(top: 25, left: 3, right: 3), + child: NewDay(data: data, index: index, state: true, + onExpandTapped: _onExpandTapped, day: day,), + ), + ) + : GlanceDayEntry(data, index, day, _onExpandTapped), + ), ), - ), - ); - } - ), - ], - ), - ); + ); + } + ), + ], + ), + ); + } + else { + return Container(); + } } } diff --git a/lib/settings_page.dart b/lib/settings_page.dart index cafcaea..b837d68 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -566,10 +566,10 @@ Widget SettingsMain(Color primary, Map? settings, Function updat slivers: [ SliverAppBar.large( leading: - IconButton(icon: Icon(Icons.arrow_back, color: colors[2],), onPressed: () { + IconButton(icon: Icon(Icons.arrow_back, color: colors[11],), onPressed: () { goBack(); }), - title: comfortatext(translation('Settings', settings!["Language"]!), 30, settings, color: colors[2]), + title: comfortatext(translation('Settings', settings!["Language"]!), 30, settings, color: colors[11]), backgroundColor: colors[6], pinned: false, ), diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 9e355be..80774c5 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -279,7 +279,7 @@ Map accentColors = { 'Clear Night': const Color(0xFF8D8F7D), 'Partly Cloudy': const Color(0xff526181), 'Clear Sky': const Color(0xFFA1C1D2), - 'Overcast': const Color(0xFFE3BC9D), + 'Overcast': const Color(0xFFCDA07E), 'Haze': const Color(0xFF968C82), 'Rain': const Color(0xFF262A3D), 'Sleet': const Color(0xFFD2B1C5), From c43c0e41dcb3b6b1aeb5aad192bb83b1926a7af2 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 16 Aug 2024 08:42:25 +0200 Subject: [PATCH 086/129] radar color fix + trying new ways to make themes more colorful --- lib/decoders/extra_info.dart | 12 ++++++++++-- lib/radar.dart | 4 ++-- lib/settings_page.dart | 4 ++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 6d79906..4994455 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -160,7 +160,7 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { ColorScheme palette; if (settings["Color source"] == "image") { - palette = await _materialPalette(Uimage, color_mode); + palette = await _materialPalette(Uimage, color_mode, pali.colors.toList()[0]); } else { palette = await MaterialYouColor(color_mode); @@ -321,15 +321,23 @@ Future _generatorPalette(Image imageWidget) async { return _paletteGenerator; } -Future _materialPalette(Image imageWidget, theme) async { +Future _materialPalette(Image imageWidget, theme, color) async { final ImageProvider imageProvider = imageWidget.image; + /* return ColorScheme.fromImageProvider( provider: imageProvider, brightness: theme == 'light' ? Brightness.light : Brightness.dark, dynamicSchemeVariant: theme == 'light' || theme == 'dark' ? DynamicSchemeVariant.tonalSpot : DynamicSchemeVariant.tonalSpot, ); + */ + + return ColorScheme.fromSeed( + seedColor: color, + brightness: theme == 'light' ? Brightness.light : Brightness.dark, + dynamicSchemeVariant: DynamicSchemeVariant.tonalSpot + ); } Color PrimaryColorCorrection(String text) { diff --git a/lib/radar.dart b/lib/radar.dart index 33f6d40..1af6fa1 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -674,7 +674,7 @@ class _RadarSmallState extends State { data: SliderTheme.of(context).copyWith( trackHeight: 18, valueIndicatorTextStyle: GoogleFonts.comfortaa( - color: data.current.onSurface, + color: data.current.onPrimaryLight, fontSize: 12, fontWeight: FontWeight.w500, ), @@ -900,7 +900,7 @@ class _RadarBigState extends State { data: SliderTheme.of(context).copyWith( trackHeight: 18, valueIndicatorTextStyle: GoogleFonts.comfortaa( - color: data.current.onSurface, + color: data.current.onPrimaryLight, fontSize: 12, fontWeight: FontWeight.w500, ), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index b837d68..78ced22 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -193,7 +193,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { darken2(palette[0].onPrimaryFixedVariant, 0.2), darken2(palette[0].onPrimaryFixedVariant, 0.1), palette[0].onTertiaryFixed, - palette[0].secondaryFixed, + palette[0].tertiaryFixed, palette[1], palette[2], @@ -230,7 +230,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { darken2(palette[0].onTertiaryFixedVariant, 0.2), darken2(palette[0].onTertiaryFixedVariant, 0.1), palette[0].onPrimaryFixed, - palette[0].secondaryFixed, + palette[0].primaryFixed, palette[1], palette[2], From 553f183a296aa8b2668031f07ebb9b5a2264f15b Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 16 Aug 2024 16:58:41 +0200 Subject: [PATCH 087/129] radar now starts from the start --- lib/decoders/extra_info.dart | 17 +++++++++++------ lib/radar.dart | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 4994455..f7c2f6f 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -155,12 +155,14 @@ Future MaterialYouColor(String theme) async { Future> getImageColors(Image Uimage, color_mode, settings) async { - final PaletteGenerator pali = await _generatorPalette(Uimage); + final List genPalette = await _generatorPalette(Uimage); + final PaletteGenerator pali = genPalette[0]; + final PaletteGenerator paliTotal = genPalette[1]; ColorScheme palette; if (settings["Color source"] == "image") { - palette = await _materialPalette(Uimage, color_mode, pali.colors.toList()[0]); + palette = await _materialPalette(Uimage, color_mode, paliTotal.colors.first); } else { palette = await MaterialYouColor(color_mode); @@ -272,7 +274,7 @@ Color BackColorCorrection(String text) { return accentColors[text] ?? WHITE; } -Future _generatorPalette(Image imageWidget) async { +Future> _generatorPalette(Image imageWidget) async { final ImageProvider imageProvider = imageWidget.image; final Completer completer = Completer(); @@ -315,16 +317,19 @@ Future _generatorPalette(Image imageWidget) async { region: region, maximumColorCount: 4 ); + PaletteGenerator _paletteGenerator2 = await PaletteGenerator.fromImage( + imageInfo.image, + maximumColorCount: 1 + ); imageProvider.resolve(const ImageConfiguration()).removeListener(listener); - return _paletteGenerator; + return [_paletteGenerator, _paletteGenerator2]; } Future _materialPalette(Image imageWidget, theme, color) async { - final ImageProvider imageProvider = imageWidget.image; - /* + final ImageProvider imageProvider = imageWidget.image; return ColorScheme.fromImageProvider( provider: imageProvider, brightness: theme == 'light' ? Brightness.light : Brightness.dark, diff --git a/lib/radar.dart b/lib/radar.dart index 1af6fa1..6708af9 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -477,6 +477,8 @@ class _RadarSmallState extends State { double currentFrameIndex = 12; late Timer timer; + bool hasBeenPlayed = false; + final data; List times = []; @@ -517,9 +519,18 @@ class _RadarSmallState extends State { } void togglePlayPause() { - setState(() { - isPlaying = !isPlaying; - }); + if (hasBeenPlayed) { + setState(() { + isPlaying = !isPlaying; + }); + } + else { + setState(() { + hasBeenPlayed = true; + currentFrameIndex = 0; + isPlaying = !isPlaying; + }); + } } @override @@ -701,6 +712,7 @@ class _RadarSmallState extends State { onChanged: (double value) { setState(() { + hasBeenPlayed = true; currentFrameIndex = value; }); }, @@ -763,6 +775,8 @@ class _RadarBigState extends State { List times = []; + bool hasBeenPlayed = false; + final data; _RadarBigState({this.data}); @@ -802,9 +816,18 @@ class _RadarBigState extends State { } void togglePlayPause() { - setState(() { - isPlaying = !isPlaying; - }); + if (hasBeenPlayed) { + setState(() { + isPlaying = !isPlaying; + }); + } + else { + setState(() { + hasBeenPlayed = true; + currentFrameIndex = 0; + isPlaying = !isPlaying; + }); + } } @override @@ -927,6 +950,7 @@ class _RadarBigState extends State { onChanged: (double value) { setState(() { + hasBeenPlayed = true; currentFrameIndex = value; }); }, From cc47a37ff6e6d805e4c09c9d578251b6a1481364 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 17 Aug 2024 09:45:28 +0200 Subject: [PATCH 088/129] added links to photos from unsplash --- lib/decoders/decode_OM.dart | 21 ++++- lib/decoders/decode_wapi.dart | 23 +++++- lib/decoders/extra_info.dart | 25 +++--- lib/donation_page.dart | 1 + lib/languages.dart | 15 ++++ lib/main_screens.dart | 2 +- lib/ui_helper.dart | 140 ++++++++++++++++++++++++---------- 7 files changed, 167 insertions(+), 60 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 520624f..0891f9b 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -254,6 +254,10 @@ class OMCurrent { final Image image; + final String photographerName; + final String photographerUrl; + final String photoUrl; + const OMCurrent({ required this.precip, required this.humidity, @@ -282,15 +286,25 @@ class OMCurrent { required this.primarySecond, required this.image, + required this.photographerName, + required this.photographerUrl, + required this.photoUrl, }); static Future fromJson(item, settings, sunstatus, timenow, real_loc, lat, lng) async { Image Uimage; + String photographerName = ""; + String photorgaperUrl = ""; + String photoLink = ""; if (settings["Image source"] == "network") { - Uimage = await getUnsplashImage(oMCurrentTextCorrection( + final ImageData = await getUnsplashImage(oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), real_loc, lat, lng); + Uimage = ImageData[0]; + photographerName = ImageData[1]; + photorgaperUrl = ImageData[2]; + photoLink = ImageData[3]; } else { String imagePath = oMBackdropCorrection( @@ -313,8 +327,13 @@ class OMCurrent { List colors = await getMainColor(settings, primary, back, Uimage); + print((photographerName, photorgaperUrl, photoLink)); + return OMCurrent( image: Uimage, + photographerName: photographerName, + photographerUrl: photorgaperUrl, + photoUrl: photoLink, text: translation(oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index ee5aaa9..ee409ff 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -275,6 +275,10 @@ class WapiCurrent { final Image image; + final String photographerName; + final String photographerUrl; + final String photoUrl; + const WapiCurrent({ required this.precip, required this.humidity, @@ -303,15 +307,26 @@ class WapiCurrent { required this.primarySecond, required this.image, + required this.photographerName, + required this.photographerUrl, + required this.photoUrl, }); static Future fromJson(item, settings, real_loc, lat, lng) async { Image Uimage; + String photographerName = ""; + String photorgaperUrl = ""; + String photoLink = ""; + if (settings["Image source"] == "network") { - Uimage = await getUnsplashImage(textCorrection( + final ImageData = await getUnsplashImage(textCorrection( item["current"]["weather_code"], item["current"]["is_day"]), real_loc, lat, lng); + Uimage = ImageData[0]; + photographerName = ImageData[1]; + photorgaperUrl = ImageData[2]; + photoLink = ImageData[3]; } else { String imagePath = backdropCorrection( @@ -373,7 +388,11 @@ class WapiCurrent { settings["Precipitation"]).toStringAsFixed(1)), wind: unit_coversion(item["current"]["wind_kph"], settings["Wind"]) .round(), - wind_dir: item["current"]["wind_degree"] + wind_dir: item["current"]["wind_degree"], + + photographerName: photographerName, + photographerUrl: photorgaperUrl, + photoUrl: photoLink ); } } diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index f7c2f6f..9d0c7ba 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -34,7 +34,7 @@ import '../ui_helper.dart'; import '../weather_refact.dart'; import 'decode_wapi.dart'; -Future getUnsplashImage(String _text, String real_loc, double lat, double lng) async { +Future> getUnsplashImage(String _text, String real_loc, double lat, double lng) async { List keys1 = textFilter.keys.toList(); //this is all to make sure that none @@ -130,8 +130,15 @@ Future getUnsplashImage(String _text, String real_loc, double lat, double print(index); print(unsplash_body[index]["links"]["html"]); - return Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover, - width: double.infinity, height: double.infinity,); + final String userLink = unsplash_body[index]["user"]["links"]["html"] ?? ""; + final String username = unsplash_body[index]["user"]["name"] ?? ""; + final String photoLink = unsplash_body[index]["links"]["html"] ?? ""; + + print((username, userLink)); + + + return [Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover, + width: double.infinity, height: double.infinity,), username, userLink, photoLink]; } Future MaterialYouColor(String theme) async { @@ -200,18 +207,6 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { } } - //if the contrast is still low then we need to choose another color - if (bestDif <= base + 120) { - print("plan b"); - Color newcolor = settings["Color mode"] == "light" || settings["Color mode"] == "dark" - ?used_colors[0] : used_colors[2]; - int newdif = difFromBackColors(newcolor, dominant); - if (newdif > bestDif && newdif < base + 250) { - bestDif = newdif; - bestcolor = newcolor; - } - } - Color desc_color = used_colors[0]; int desc_dif = difFromBackColors(desc_color, dominant); diff --git a/lib/donation_page.dart b/lib/donation_page.dart index 89cef9b..48aaefe 100644 --- a/lib/donation_page.dart +++ b/lib/donation_page.dart @@ -448,6 +448,7 @@ class _InfoPageState extends State { } } + Future _launchUrl(String url) async { final Uri _url = Uri.parse(url); if (!await launchUrl(_url)) { diff --git a/lib/languages.dart b/lib/languages.dart index b08067b..33b998a 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -1426,6 +1426,21 @@ Map> mainTranslate = { 'Συνθήκες έκτακτης ανάγκης· σοβαρές επιπτώσεις στην υγεία για όλους.' ], + 'photo by x on Unsplash': [ + 'photo by x on Unsplash', + 'fotó: x az Unsplashen', + 'foto de x en Unsplash', + 'photo de x sur Unsplash', + 'Foto von x auf Unsplash', + 'foto di x su Unsplash', + 'foto de x no Unsplash', + 'фото x на Unsplash', + '由 x 拍摄,发布于 Unsplash', + '写真: x on Unsplash', + 'zdjęcie x na Unsplash', + 'φωτογραφία από τον x στο Unsplash' + ], + 'Search translation': [ //used for getting the codes used for translation of city names //If none are available then en (english) is the default // for more info visit https://open-meteo.com/en/docs/geocoding-api diff --git a/lib/main_screens.dart b/lib/main_screens.dart index d3f0403..3c8a9dc 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -123,7 +123,7 @@ class _NewMainState extends State { children: [ Stack( children: [ - UpdatedNotifier(data: data, + FadingWidget(data: data, time: data.updatedTime, key: Key(data.updatedTime.toString())), LayoutBuilder( diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 829d172..c73d7bd 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -21,13 +21,13 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/search_screens.dart'; import 'package:latlong2/latlong.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:url_launcher/url_launcher.dart'; import 'api_key.dart'; import 'caching.dart'; @@ -51,7 +51,8 @@ double getFontSize(String set) { } Widget comfortatext(String text, double size, settings, - {Color color = WHITE, TextAlign align = TextAlign.left, weight = FontWeight.w400}) { + {Color color = WHITE, TextAlign align = TextAlign.left, weight = FontWeight.w400, + decoration = TextDecoration.none}) { double x = getFontSize(settings["Font size"]); return Text( @@ -61,6 +62,8 @@ Widget comfortatext(String text, double size, settings, fontSize: size * x, fontWeight: weight, height: 1.1, + decoration: decoration, + decorationColor: color, ), overflow: TextOverflow.ellipsis, maxLines: 40, @@ -121,31 +124,10 @@ Color lightAccent(Color color, int intensity) { return Color.fromRGBO(sqrt(color.red * x).toInt(), sqrt(color.green * x).toInt(), sqrt(color.blue * x).toInt(), 1); } -class UpdatedNotifier extends StatefulWidget { - final data; - final time; - - UpdatedNotifier({Key? key, required this.data, required this.time}) : super(key: key); - - @override - _FadeWidgetState createState() => _FadeWidgetState(); -} - -class _FadeWidgetState extends State with AutomaticKeepAliveClientMixin { - bool _hasBeenShown = false; - - @override - bool get wantKeepAlive => true; - - @override - Widget build(BuildContext context) { - super.build(context); - - if (!_hasBeenShown) { - _hasBeenShown = true; - return FadingWidget(data: widget.data, time: widget.time); - } - return Container(); +Future _launchUrl(String url) async { + final Uri _url = Uri.parse(url); + if (!await launchUrl(_url)) { + throw Exception('Could not launch $_url'); } } @@ -159,10 +141,13 @@ class FadingWidget extends StatefulWidget { _FadingWidgetState createState() => _FadingWidgetState(); } -class _FadingWidgetState extends State { - bool _isVisible = false; +class _FadingWidgetState extends State with AutomaticKeepAliveClientMixin { + bool _isVisible = true; Timer? _timer; + @override + bool get wantKeepAlive => true; + @override void initState() { super.initState(); @@ -173,7 +158,7 @@ class _FadingWidgetState extends State { }); } }); - _timer = Timer(Duration(milliseconds: 3500), () { + _timer = Timer(Duration(milliseconds: 2000), () { if (mounted) { setState(() { _isVisible = false; @@ -191,14 +176,12 @@ class _FadingWidgetState extends State { @override Widget build(BuildContext context) { + super.build(context); final dif = widget.time.difference(widget.data.fetch_datetime).inMinutes; String text = translation('updated, just now', widget.data.settings["Language"]); - - print(dif); - if (dif > 0) { text = translation('updated, x min ago', widget.data.settings["Language"]); text = text.replaceAll('x', dif.toString()); @@ -206,10 +189,51 @@ class _FadingWidgetState extends State { List split = text.split(','); - return AnimatedOpacity( - duration: const Duration(milliseconds: 400), - opacity: _isVisible ? 1.0 : 0.0, - child: Padding( + return AnimatedSwitcher( + duration: const Duration(milliseconds: 1000), + transitionBuilder: (Widget child, Animation animation) { + final inAnimation = CurvedAnimation( + parent: animation, + curve: const Interval(0.5, 1.0, curve: Curves.easeIn), + ); + final outAnimation = CurvedAnimation( + parent: animation, + curve: const Interval(1.0, 0.5, curve: Curves.easeOut), + ); + return FadeTransition( + opacity: _isVisible ? outAnimation : inAnimation, + child: child, + ); + }, + child: SinceLastUpdate( + key: ValueKey(_isVisible), + split: split, + data: widget.data, + isVisible: _isVisible, + ), + ); + } +} + + +class SinceLastUpdate extends StatefulWidget { + final split; + final data; + final isVisible; + + SinceLastUpdate({Key? key, required this.data, required this.split, required this.isVisible}) : super(key: key); + + @override + _SinceLastUpdateState createState() => _SinceLastUpdateState(); +} + +class _SinceLastUpdateState extends State{ + + @override + Widget build(BuildContext context) { + + if (widget.isVisible) { + return Padding( padding: const EdgeInsets.only(top: 6, right: 10), child: Row( mainAxisAlignment: MainAxisAlignment.end, @@ -218,18 +242,52 @@ class _FadingWidgetState extends State { padding: const EdgeInsets.only(right: 3), child: Icon(Icons.access_time, color: widget.data.current.primary, size: 13,), ), - comfortatext('${split[0]},', 13, widget.data.settings, + comfortatext('${widget.split[0]},', 13, widget.data.settings, color: widget.data.current.primary, weight: FontWeight.w500), - comfortatext(split.length > 1 ?split[1] : "", 13, widget.data.settings, + comfortatext(widget.split.length > 1 ? widget.split[1] : "", 13, widget.data.settings, color: widget.data.current.onSurface, weight: FontWeight.w500), ], ), - ), - ); + ); + } else { + return Padding( + padding: const EdgeInsets.only(top: 5, right: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + GestureDetector( + onTap: () async { + await _launchUrl(widget.data.current.photoUrl); + }, + child: comfortatext("Photo", 12, widget.data.settings, color: widget.data.current.onSurface, + decoration: TextDecoration.underline), + ), + comfortatext(" by ", 12, widget.data.settings, color: widget.data.current.onSurface), + GestureDetector( + onTap: () async { + await _launchUrl(widget.data.current.photographerUrl); + }, + child: comfortatext(widget.data.current.photographerName, 13, widget.data.settings, color: widget.data.current.onSurface, + decoration: TextDecoration.underline), + ), + comfortatext(" on ", 12, widget.data.settings, color: widget.data.current.onSurface), + GestureDetector( + onTap: () async { + await _launchUrl("https://unsplash.com/"); + }, + child: comfortatext("Unsplash", 12, widget.data.settings, color: widget.data.current.onSurface, + decoration: TextDecoration.underline), + ), + ], + ), + ); + } } } + + class DescriptionCircle extends StatelessWidget { final String text; From d0e5a2e7814b2a442747405960503d08da45e2e0 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 17 Aug 2024 15:34:43 +0200 Subject: [PATCH 089/129] went to a more simple and modern about page --- lib/decoders/extra_info.dart | 10 +- lib/donation_page.dart | 358 ++++++++++++----------------------- lib/main_screens.dart | 4 +- lib/search_screens.dart | 4 +- lib/settings_page.dart | 8 +- lib/ui_helper.dart | 5 +- lib/weather_refact.dart | 1 + 7 files changed, 139 insertions(+), 251 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 9d0c7ba..c5beb57 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -48,8 +48,6 @@ Future> getUnsplashImage(String _text, String real_loc, double lat String text_query = textToUnsplashText[_text]![0]; - //String addon = wapi_body["current"]["is_day"] == 1 ? 'daytime' : 'nighttime'; - final params2 = { 'client_id': access_key, 'query' : "$text_query, $loc", @@ -68,8 +66,6 @@ Future> getUnsplashImage(String _text, String real_loc, double lat var unsplash_body = jsonDecode(response2); - //var rng = Random(); - //int index = rng.nextInt(3); int index = 0; double best = 99999999999; @@ -188,9 +184,9 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { if (bestDif <= base + 120) { print("trying"); - for (int i = 1; i < 4; i++) { + for (int i = 1; i < 5; i++) { //LIGHT - Color newcolor = lighten2(startcolor, i / 9); + Color newcolor = lighten2(startcolor, i / 4); int newdif = difFromBackColors(newcolor, dominant); if (newdif > bestDif && newdif < base + 200) { bestDif = newdif; @@ -198,7 +194,7 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { } //DARK - newcolor = darken2(startcolor, i / 7); + newcolor = darken2(startcolor, i / 4); newdif = difFromBackColors(newcolor, dominant); if (newdif > bestDif && newdif < base + 200) { bestDif = newdif; diff --git a/lib/donation_page.dart b/lib/donation_page.dart index 48aaefe..a80de2c 100644 --- a/lib/donation_page.dart +++ b/lib/donation_page.dart @@ -16,6 +16,7 @@ along with this program. If not, see . */ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:overmorrow/ui_helper.dart'; @@ -175,23 +176,29 @@ class _DonationPageState extends State { class InfoPage extends StatefulWidget { final Color primary; - final Color back; + final Color surface; final settings; + final onSurface; + final hihglight; - const InfoPage({Key? key, required this.primary, required this.settings, required this.back}) + const InfoPage({Key? key, required this.primary, required this.settings, required this.surface, required this.onSurface, + required this.hihglight}) : super(key: key); @override _InfoPageState createState() => - _InfoPageState(primary: primary, settings: settings, back: back); + _InfoPageState(primary: primary, settings: settings, surface: surface, highlight: hihglight, onSurface: onSurface); } class _InfoPageState extends State { final primary; final settings; - final back; + final surface; + final onSurface; + final highlight; - _InfoPageState({required this.primary, required this.settings, required this.back}); + _InfoPageState({required this.primary, required this.settings, required this.surface, required this.onSurface, + required this.highlight}); void goBack() { Navigator.pop(context); @@ -199,252 +206,131 @@ class _InfoPageState extends State { @override Widget build(BuildContext context) { + return Material( + color: surface, + child: CustomScrollView( + slivers: [ + SliverAppBar.large( + leading: + IconButton(icon: Icon(Icons.arrow_back, color: surface,), + onPressed: () { + goBack(); + }), + title: comfortatext( + translation('About', settings!["Language"]!), 30, settings, + color: surface), + backgroundColor: primary, + pinned: false, + ), + // Just some content big enough to have something to scroll. + SliverToBoxAdapter( + child: Container( + color: surface, + child: Padding( + padding: const EdgeInsets.only(top: 60, left: 20, right: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + comfortatext('OVRMRW', 40, settings, color: primary, weight: FontWeight.w400), - List colors = getColors(primary, back, settings, 0); - Color link = colors[1]; - - return Scaffold( - backgroundColor: colors[0], - appBar: AppBar( - toolbarHeight: 65, - shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(0)), - elevation: 0, - leadingWidth: 50, - backgroundColor: colors[0], - title: comfortatext(translation('About', settings["Language"]), 25, settings, - color: colors[2]), - leading: IconButton( - onPressed: () { - goBack(); - }, - icon: Icon( - Icons.arrow_back, - color: colors[2], - ), - )), - body: Padding( - padding: const EdgeInsets.all(15.0), - child: SingleChildScrollView( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(top: 10, bottom: 40), - child: Container( - height: 150.0, - width: 150.0, - decoration: BoxDecoration( - image: const DecorationImage( - image: AssetImage('assets/icons/Overmorrow_white_classic.png'), - fit: BoxFit.cover, - ), - borderRadius: BorderRadius.circular(40), + Padding( + padding: const EdgeInsets.only(top: 30, bottom: 10), + child: comfortatext( + "developed by:", 16, + settings, + color: onSurface), ), - ), - ), - comfortatext( - translation( - 'Overmorrow is a beautiful minimalist weather app.', - settings["Language"]), - 22, settings, color: colors[2], align: TextAlign.center), - Padding( - padding: const EdgeInsets.only(top: 40, bottom: 10), - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: colors[5], - borderRadius: BorderRadius.circular(20)), - child: Column( + Row( children: [ - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.only(top: 10, bottom: 10, left: 10), - child: comfortatext( - translation('Features:', settings["Language"]), 20, settings, color: colors[2]), - ), - ), + comfortatext("Balint", 23, settings, color: primary), Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - comfortatext( - '\u2022${translation('accurate weather forecast', settings["Language"])}', - 22, settings, color: colors[2]), - comfortatext( - '\u2022${translation('open source', settings["Language"])}', - 22, settings, color: colors[2]), - comfortatext( - '\u2022${translation('no ads', settings["Language"])}', - 22, settings, color: colors[2]), - comfortatext( - '\u2022${translation('no data collected', settings["Language"])}', - 22, settings, color: colors[2]), - comfortatext( - '\u2022${translation('minimalist design', settings["Language"])}', - 22, settings, color: colors[2]), - comfortatext( - '\u2022${translation('dynamically adapting color scheme', settings["Language"])}', - 22, settings, color: colors[2]), - comfortatext( - '\u2022${translation('languages support', settings["Language"])}', - 22, settings, color: colors[2]), - comfortatext( - '\u2022${translation('place search', settings["Language"])}', - 22, settings, color: colors[2]), - comfortatext( - '\u2022${translation('weather for current location', settings["Language"])}', - 22, settings, color: colors[2]), - comfortatext( - '\u2022${translation('unit swapping', settings["Language"])}', - 22, settings, color: colors[2]), - ], - ), + padding: const EdgeInsets.only(left: 10), + child: comfortatext("(maroti.devel@gmail.com)", 16, settings, color: onSurface), ), ], ), - ), - ), - Padding( - padding: const EdgeInsets.only(top: 20, bottom: 10), - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: colors[5], - borderRadius: BorderRadius.circular(20)), - child: Column(children: [ - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.only(top: 10, bottom: 10, left: 10), - child: comfortatext( - translation('Developed by:', settings["Language"]), 20, settings, - color: colors[2]), + Padding( + padding: const EdgeInsets.only(top: 15, left: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + GestureDetector( + onTap: () { + _launchUrl("https://github.com/bmaroti9/Overmorrow"); + }, + child: comfortatext("source code", 16, settings, color: primary, + decoration: TextDecoration.underline), ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(right: 20), - child: comfortatext('Balint', 22, settings, color: colors[2]), - ), - Padding( - padding: const EdgeInsets.only(right: 20), - child: comfortatext( - '(maroti.devel@gmail.com)', 18, settings, color: colors[2]), - ), - Padding( - padding: const EdgeInsets.only(top: 10), - child: Align( - alignment: Alignment.centerLeft, - child: TextButton( - onPressed: () async { - await _launchUrl( - 'https://github.com/bmaroti9/Overmorrow'); - }, - child: comfortatext('source code', 20, settings, - color: link)), - ), - ) - ], + GestureDetector( + onTap: () { + _launchUrl("https://github.com/bmaroti9/Overmorrow/issues"); + }, + child: comfortatext("report an issue", 16, settings, color: primary, + decoration: TextDecoration.underline), ), - ), - ])), - ), - Padding( - padding: const EdgeInsets.only(top: 20, bottom: 10), - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: colors[5], - borderRadius: BorderRadius.circular(20)), - child: Column(children: [ - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.only(top: 10, bottom: 10, left: 10), - child: comfortatext( - translation('Weather data from:', settings["Language"]), - 20, settings, color: colors[2]), - ), + ], ), - TextButton( - onPressed: () async { - await _launchUrl( - 'https://open-meteo.com'); - }, - child: comfortatext('open-meteo.com', 20, settings, - color: link)), - TextButton( - onPressed: () async { - await _launchUrl( - 'https://www.rainviewer.com/api.html'); - }, - child: comfortatext('www.rainviewer.com', 20, settings, - color: link)), - TextButton( - onPressed: () async { - await _launchUrl('https://www.weatherapi.com/'); - }, - child: comfortatext('www.weatherapi.com', 20, settings, - color: link)) - ]), - ), - ), - Padding( - padding: const EdgeInsets.only(top: 20, bottom: 10), - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: colors[5], - borderRadius: BorderRadius.circular(20)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + ), + Padding( + padding: const EdgeInsets.only(top: 40, bottom: 10), + child: comfortatext( + "weather data:", 16, + settings, + color: onSurface), + ), + Padding( + padding: EdgeInsets.only(left: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: - const EdgeInsets.only(top: 10, bottom: 10, left: 10), - child: comfortatext( - translation('Images used:', settings["Language"]), 20, settings, - color: colors[2]), - ), + GestureDetector( + onTap: () { + _launchUrl("https://open-meteo.com"); + }, + child: comfortatext("open-meteo", 16, settings, color: primary, + decoration: TextDecoration.underline), ), - ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: imageText.length, - itemExtent: 40, - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: const EdgeInsets.only(left: 20), - child: Align( - alignment: Alignment.centerLeft, - child: TextButton( - onPressed: () { - _launchUrl(imageLink[index]); - }, - child: comfortatext( - translation( - imageText[index], settings["Language"]), - 20, settings, - color: link), - ), - ), - ); + GestureDetector( + onTap: () { + _launchUrl("https://www.weatherapi.com/"); }, - ) - ]), - ), - ) - ], + child: comfortatext("weatherapi", 16, settings, color: primary, + decoration: TextDecoration.underline), + ), + GestureDetector( + onTap: () { + _launchUrl("https://www.rainviewer.com/api.html"); + }, + child: comfortatext("rainviewer", 16, settings, color: primary, + decoration: TextDecoration.underline), + ), + ], + ), + ), + Padding( + padding: EdgeInsets.only(top: 40), + child: Wrap( + spacing: 10, + children: [ + comfortatext("all images used are from:", 16, settings, color: onSurface), + GestureDetector( + onTap: () { + _launchUrl("https://unsplash.com/"); + }, + child: comfortatext("unsplash", 16, settings, color: primary, + decoration: TextDecoration.underline), + ), + ], + ), + ), + ], + ), + ) ), ), - )); + ], + ), + ); } } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 3c8a9dc..2994a5c 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -60,7 +60,7 @@ class _NewMainState extends State { drawer: MyDrawer(backupprimary: data.current.backup_primary, backupback: data.current.backup_backcolor, settings: data.settings, image: data.current.image, primary: data.current.primary, onSurface: data.current.onSurface, - surface: data.current.surface, + surface: data.current.surface, hihglight: data.current.containerLow, ), body: StretchyHeader.listView( displacement: 130, @@ -194,7 +194,7 @@ Widget TabletLayout(data, updateLocation, context) { drawer: MyDrawer(backupprimary: data.current.backup_primary, backupback: data.current.backup_backcolor, settings: data.settings, image: data.current.image, primary: data.current.primary, onSurface: data.current.onSurface, - surface: data.current.surface, + surface: data.current.surface, hihglight: data.current.containerLow, ), body: RefreshIndicator( onRefresh: () async { diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 1dcf8ee..9b7eb97 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -476,8 +476,8 @@ class dumbySearch extends StatelessWidget { return Scaffold( drawer: MyDrawer(backupprimary: primary, settings: settings, backupback: back, image: Image.asset("assets/backdrops/grayscale_snow2.jpg", - fit: BoxFit.cover, width: double.infinity, height: double.infinity,), surface: colors[0], - onSurface: colors[4], primary: colors[1], + fit: BoxFit.cover, width: double.infinity, height: double.infinity, color: colors[6],), surface: colors[0], + onSurface: colors[4], primary: colors[1], hihglight: colors[6], ), backgroundColor: colors[0], body: StretchyHeader.singleChild( diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 78ced22..b4bb4a1 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -794,9 +794,11 @@ class MyDrawer extends StatelessWidget { final primary; final surface; final onSurface; + final hihglight; const MyDrawer({super.key, required this.settings, required this.backupback, required this.backupprimary, - required this.image, required this.surface, required this.primary, required this.onSurface}); + required this.image, required this.surface, required this.primary, required this.onSurface, + required this.hihglight}); @override Widget build(BuildContext context) { @@ -843,8 +845,8 @@ class MyDrawer extends StatelessWidget { onTap: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => InfoPage(primary: backupprimary, settings: settings, - back: backupback,)), + MaterialPageRoute(builder: (context) => InfoPage(primary: primary, settings: settings, + surface: surface, onSurface: onSurface, hihglight: hihglight,)), ); }, ), diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index c73d7bd..e865f75 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -250,7 +250,7 @@ class _SinceLastUpdateState extends State{ ], ), ); - } else { + } else if (widget.data.current.photographerName != ""){ return Padding( padding: const EdgeInsets.only(top: 5, right: 10), child: Row( @@ -283,6 +283,9 @@ class _SinceLastUpdateState extends State{ ), ); } + else { + return Container(); + } } } diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 80774c5..043f963 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -362,6 +362,7 @@ Map textFilter = { 'pattern': -10000, 'wall' : -10000, 'text': -10000, + 'sign': -10000, 'man': -10000000, //trying to not have people in images 'male': -1000000, 'couple': -1000000, From 6dd8b80b8c56978dc3b3c15528e1d040ea34cf13 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sun, 18 Aug 2024 15:35:51 +0200 Subject: [PATCH 090/129] added lots of translations for new elements, removed unused ones --- lib/donation_page.dart | 10 +- lib/languages.dart | 351 ++++++++++------------------------------- lib/ui_helper.dart | 9 +- 3 files changed, 95 insertions(+), 275 deletions(-) diff --git a/lib/donation_page.dart b/lib/donation_page.dart index a80de2c..0e37b9c 100644 --- a/lib/donation_page.dart +++ b/lib/donation_page.dart @@ -236,7 +236,7 @@ class _InfoPageState extends State { Padding( padding: const EdgeInsets.only(top: 30, bottom: 10), child: comfortatext( - "developed by:", 16, + translation("developed by:", settings["Language"]), 16, settings, color: onSurface), ), @@ -258,14 +258,14 @@ class _InfoPageState extends State { onTap: () { _launchUrl("https://github.com/bmaroti9/Overmorrow"); }, - child: comfortatext("source code", 16, settings, color: primary, + child: comfortatext(translation("source code", settings["Language"]), 16, settings, color: primary, decoration: TextDecoration.underline), ), GestureDetector( onTap: () { _launchUrl("https://github.com/bmaroti9/Overmorrow/issues"); }, - child: comfortatext("report an issue", 16, settings, color: primary, + child: comfortatext(translation("report an issue", settings["Language"]), 16, settings, color: primary, decoration: TextDecoration.underline), ), ], @@ -274,7 +274,7 @@ class _InfoPageState extends State { Padding( padding: const EdgeInsets.only(top: 40, bottom: 10), child: comfortatext( - "weather data:", 16, + translation("weather data:", settings["Language"]), 16, settings, color: onSurface), ), @@ -312,7 +312,7 @@ class _InfoPageState extends State { child: Wrap( spacing: 10, children: [ - comfortatext("all images used are from:", 16, settings, color: onSurface), + comfortatext(translation("all images used are from:", settings["Language"]), 16, settings, color: onSurface), GestureDetector( onTap: () { _launchUrl("https://unsplash.com/"); diff --git a/lib/languages.dart b/lib/languages.dart index 33b998a..e9240fe 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -508,244 +508,7 @@ Map> mainTranslate = { 'Wspieraj na Patreon', 'Υποστήριξέ με στο Patreon' ], - 'Overmorrow is a beautiful minimalist weather app.': [ - '"Overmorrow is a beautiful minimalist weather app."', - '"Overmorrow egy gyönyörű minimalista időjárás alkalmazás."', - '"Overmorrow es una hermosa aplicación de clima minimalista."', - '"Overmorrow est une belle application météo minimaliste."', - '"Overmorrow ist eine wunderschöne minimalistische Wetter-App."', - '"Overmorrow è una bellissima app meteo minimalista."', - '"Overmorrow é um lindo aplicativo de clima minimalista."', - '"Overmorrow - красивое минималистичное приложение погоды."', - '"Overmorrow是一个美丽的极简天气应用程序。"', - '"Overmorrowは美しいミニマリストの天気アプリです。"', - '"Overmorrow to piękna minimalistyczna aplikacja pogodowa."', - '"Το Overmorrow είναι μία πανέμορφη μινιμαλιστική εφαρμογή καιρού."' - ], - 'Features:': [ - 'Features:', - 'Funkciók:', - 'Características:', - 'Fonctionnalités :', - 'Funktionen:', - 'Caratteristiche:', - 'Recursos:', - 'Функции:', - '特点:', - '特徴:', - 'Funkcje:', - 'Χαρακτηρηστικά:' - ], - 'accurate weather forecast': [ - 'accurate weather forecast', - 'pontos időjárás előrejelzés', - 'pronóstico del tiempo preciso', - 'prévisions météorologiques précises', - 'genaue Wettervorhersage', - 'previsioni meteorologiche accurate', - 'previsão do tempo precisa', - 'точный прогноз погоды', - '准确的天气预报', - '正確な天気予報', - 'dokładna prognoza pogody', - 'ακριβής πρόγνωση καιρού' - ], - 'open source': [ - 'open source', - 'nyílt forráskód', - 'código abierto', - 'open source', - 'Open Source', - 'open source', - 'código aberto', - 'открытый исходный код', - '开源', - 'オープンソース', - 'otwarte źródła', - 'εφαρμογή ανοιχτού κώδικα' - ], - 'no ads': [ - 'no ads', - 'nincsenek hirdetések', - 'sin anuncios', - 'pas de publicités', - 'keine Werbung', - 'nessuna pubblicità', - 'sem anúncios', - 'без рекламы', - '没有广告', - '広告なし', - 'bez reklam', - 'χωρίς διαφημίσεις' - ], - 'no data collected': [ - 'no data collected', - 'nincs adatgyűjtés', - 'no se recopilan datos', - 'pas de collecte de données', - 'keine Datensammlung', - 'nessun dato raccolto', - 'não são coletados dados', - 'нет сбора данных', - '不收集数据', - 'データは収集されません', - 'nie zbiera danych', - 'χωρίς συλλογή δεδομένων' - ], - 'minimalist design': [ - 'minimalist design', - 'minimalista dizájn', - 'diseño minimalista', - 'design minimaliste', - 'minimales Design', - 'design minimalista', - 'design minimalista', - 'минималистический дизайн', - '极简设计', - 'ミニマリストデザイン', - 'minimalistyczny wygląd', - 'μινιμαλιστικός σχεδιασμός' - ], - 'dynamically adapting color scheme': [ - 'dynamically adapting color scheme', - 'dinamikusan alkalmazkodó színtéma', - 'esquema de colores que se adapta dinámicamente', - "schéma de couleurs s'adaptant dynamiquement", - 'dynamisch anpassendes Farbschema', - 'schema di colore adattabile in modo dinamico', - 'esquema de cores que se adapta dinamicamente', - 'динамически адаптирующаяся цветовая схема', - '动态适应颜色方案', - '動的に適応するカラースキーム', - 'dynamiczny schemat kolorów', - 'δυναμικά προσαρμόσιμος συνδυασμός χρωμάτων' - ], - 'languages support': [ - 'languages support', - 'nyelvek támogatása', - 'soporte de idiomas', - 'prise en charge des langues', - 'Sprachunterstützung', - 'supporto lingue', - 'suporte de idiomas', - 'поддержка языков', - '语言支持', - '言語サポート', - 'wsparcie językowe', - 'υποστήριξη γλώσσεων' - ], - 'place search': [ - 'place search', - 'hely keresés', - 'búsqueda de lugar', - 'recherche de lieu', - 'Ortsuche', - 'ricerca di luoghi', - 'pesquisa de lugares', - 'поиск места', - '地点搜索', - '場所検索', - 'wyszukiwarka miejscowości', - 'αναζήτηση τοποθεσιών' - ], - 'weather for current location': [ - 'weather for current location', - 'időjárás az aktuális tartózkodási helyhez', - 'clima para la ubicación actual', - "météo pour l'emplacement actuel", - 'Wetter für aktuellen Standort', - 'meteo per la posizione attuale', - 'tempo para a localização atual', - 'погода для текущего местоположения', - '当前位置的天气', - '現在地の天気', - 'pogoda dla wybranej lokalizacji', - 'καιρός της τρέχουσας τοποθεσίας' - ], - 'unit swapping': [ - 'unit swapping', - 'mértékegység váltás', - 'cambio de unidad', - "changement d'unité", - 'Einheitenumstellung', - 'cambio unità', - 'troca de unidade', - 'смена единиц измерения', - '单位切换', - '単位切替', - 'zmiana jednostek', - 'αλλαγή μονάδων' - ], - 'Developed by:': [ - 'Developed by:', - 'Fejlesztette:', - 'Desarrollado por:', - 'Développé par :', - 'Entwickelt von:', - 'Sviluppato da:', - 'Desenvolvido por:', - 'Разработано:', - '由...开发', - '開発者:', - 'Stworzona przez:', - 'Αναπτύχθηκε από:' - ], - 'contact me': [ - 'contact me', - 'Kapcsolat', - 'contáctame', - 'contactez-moi', - 'Kontaktiere mich', - 'contattami', - 'contacte-me', - 'свяжитесь со мной', - '联系我', - 'お問い合わせ', - 'napisz do mnie', - 'επικοινώνησε μου' - ], - 'Weather data from:': [ - 'Weather data from:', - 'Időjárás adatok innen:', - 'Datos meteorológicos de:', - 'Données météorologiques de :', - 'Wetterdaten von:', - 'Dati meteorologici da:', - 'Dados meteorológicos de:', - 'Данные о погоде от:', - '天气数据来自:', - '天気情報提供元:', - 'Dane dostarcza:', - 'Δεδομένα καιρού από:' - ], - 'Images used:': [ - 'Images used:', - 'Felhasznált képek:', - 'Imágenes utilizadas:', - 'Images utilisées :', - 'Verwendete Bilder:', - 'Immagini utilizzate:', - 'Imagens usadas:', - 'Используемые изображения:', - '使用的图片:', - '使用された画像:', - 'Użyte grafiki:', - 'Εικόνες από:' - ], - 'Source Code:': [ - 'Source Code:', - 'Forráskód:', - 'Código fuente:', - 'Code source :', - 'Quellcode:', - 'Codice sorgente:', - 'Código-fonte:', - 'Исходный код:', - '源代码:', - 'ソースコード:', - 'Kod źródłowy', - 'Πηγαίος Κώδικας:' - ], + 'Weak or no wifi connection': [ 'Weak or no wifi connection', 'Gyenge vagy nincs wifi kapcsolat', @@ -1240,21 +1003,6 @@ Map> mainTranslate = { 'ανανεώθηκε, μόλις τώρα' ], - 'Finding place...': [ - 'Finding place...', - 'Hely keresése...', - 'Buscando lugar...', - 'Recherche de lieu...', - 'Ort finden...', - 'Ricerca del posto...', - 'Encontrando lugar...', - 'Поиск места...', - '寻找位置...', - '場所を見つけています...', - 'Szukanie miejsca...', - 'Εύρεση τοποθεσίας...' - ], - 'Color source': [ 'Color source', 'Szín forrása', @@ -1426,19 +1174,90 @@ Map> mainTranslate = { 'Συνθήκες έκτακτης ανάγκης· σοβαρές επιπτώσεις στην υγεία για όλους.' ], - 'photo by x on Unsplash': [ - 'photo by x on Unsplash', - 'fotó: x az Unsplashen', - 'foto de x en Unsplash', - 'photo de x sur Unsplash', - 'Foto von x auf Unsplash', - 'foto di x su Unsplash', - 'foto de x no Unsplash', - 'фото x на Unsplash', - '由 x 拍摄,发布于 Unsplash', - '写真: x on Unsplash', - 'zdjęcie x na Unsplash', - 'φωτογραφία από τον x στο Unsplash' + 'photo by x on Unsplash': [ //commas are added to separate the clickable text (photo, name, Unsplash) + 'Photo, by ,x, on ,Unsplash', //from the non clickable ones (by, on) + 'Fotó,: ,x, az ,Unsplashen', + 'Foto, de ,x, en ,Unsplash', + 'Photo, de ,x, sur ,Unsplash', + 'Foto, von ,x, auf ,Unsplash', + 'Foto, di ,x, su ,Unsplash', + 'Foto, de ,x, no ,Unsplash', + 'Фото, ,x, на ,Unsplash', + '照片, ,x, 拍摄,发布于 ,Unsplash', + '写真,: ,x, on ,Unsplash', + 'Zdjęcie, ,x, na ,Unsplash', + 'Φωτογραφία, από τον ,x, στο ,Unsplash' + ], + + 'developed by:': [ + 'Developed by:', + 'Fejlesztette:', + 'Desarrollado por:', + 'Développé par :', + 'Entwickelt von:', + 'Sviluppato da:', + 'Desenvolvido por:', + 'Разработано:', + '开发者:', + '開発者:', + 'Opracowane przez:', + 'Αναπτύχθηκε από:', + ], + 'source code': [ + 'Source code', + 'Forráskód', + 'Código fuente', + 'Code source', + 'Quellcode', + 'Codice sorgente', + 'Código-fonte', + 'Исходный код', + '源代码', + 'ソースコード', + 'Kod źródłowy', + 'Πηγαίος κώδικας', + ], + 'report an issue': [ + 'Report an issue', + 'Hiba jelentése', + 'Informar de un problema', + 'Signaler un problème', + 'Ein Problem melden', + 'Segnala un problema', + 'Relatar um problema', + 'Сообщить о проблеме', + '报告问题', + '問題を報告する', + 'Zgłoś problem', + 'Αναφορά προβλήματος', + ], + 'weather data:': [ + 'Weather data:', + 'Időjárási adatok:', + 'Datos meteorológicos:', + 'Données météorologiques :', + 'Wetterdaten:', + 'Dati meteorologici:', + 'Dados meteorológicos:', + 'Метеоданные:', + '天气数据:', + '気象データ:', + 'Dane pogodowe:', + 'Δεδομένα καιρού:', + ], + 'all images used are from:': [ + 'All images used are from:', + 'Minden felhasznált kép forrása:', + 'Todas las imágenes utilizadas son de:', + 'Toutes les images utilisées proviennent de :', + 'Alle verwendeten Bilder stammen von:', + 'Tutte le immagini utilizzate provengono da:', + 'Todas as imagens usadas são de:', + 'Все использованные изображения из:', + '所有使用的图片来自:', + '使用されているすべての画像は次の提供です:', + 'Wszystkie użyte obrazy pochodzą z:', + 'Όλες οι εικόνες που χρησιμοποιούνται είναι από:', ], 'Search translation': [ //used for getting the codes used for translation of city names diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index e865f75..abbbfb7 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -251,6 +251,7 @@ class _SinceLastUpdateState extends State{ ), ); } else if (widget.data.current.photographerName != ""){ + List split = translation("photo by x on Unsplash", widget.data.settings["Language"]).split(","); return Padding( padding: const EdgeInsets.only(top: 5, right: 10), child: Row( @@ -260,10 +261,10 @@ class _SinceLastUpdateState extends State{ onTap: () async { await _launchUrl(widget.data.current.photoUrl); }, - child: comfortatext("Photo", 12, widget.data.settings, color: widget.data.current.onSurface, + child: comfortatext(split[0], 12, widget.data.settings, color: widget.data.current.onSurface, decoration: TextDecoration.underline), ), - comfortatext(" by ", 12, widget.data.settings, color: widget.data.current.onSurface), + comfortatext(split[1], 12, widget.data.settings, color: widget.data.current.onSurface), GestureDetector( onTap: () async { await _launchUrl(widget.data.current.photographerUrl); @@ -271,12 +272,12 @@ class _SinceLastUpdateState extends State{ child: comfortatext(widget.data.current.photographerName, 13, widget.data.settings, color: widget.data.current.onSurface, decoration: TextDecoration.underline), ), - comfortatext(" on ", 12, widget.data.settings, color: widget.data.current.onSurface), + comfortatext(split[3], 12, widget.data.settings, color: widget.data.current.onSurface), GestureDetector( onTap: () async { await _launchUrl("https://unsplash.com/"); }, - child: comfortatext("Unsplash", 12, widget.data.settings, color: widget.data.current.onSurface, + child: comfortatext(split[4], 12, widget.data.settings, color: widget.data.current.onSurface, decoration: TextDecoration.underline), ), ], From bd81d313fd0ca3917bea33225fc8e1a793e2c3a8 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sun, 18 Aug 2024 16:15:35 +0200 Subject: [PATCH 091/129] started working on donation page --- lib/donation_page.dart | 177 ++++++++++++++--------------------------- lib/settings_page.dart | 4 +- 2 files changed, 62 insertions(+), 119 deletions(-) diff --git a/lib/donation_page.dart b/lib/donation_page.dart index 0e37b9c..9bb1544 100644 --- a/lib/donation_page.dart +++ b/lib/donation_page.dart @@ -23,61 +23,33 @@ import 'package:overmorrow/ui_helper.dart'; import 'package:url_launcher/url_launcher.dart'; -final imageText = [ - 'Clear Night', - 'Partly Cloudy', - 'Clear Sky', - 'Overcast', - 'Haze', - 'Rain', - 'Sleet', - 'Drizzle', - 'Thunderstorm', - 'Heavy Snow', - 'Fog', - 'Snow', - 'Heavy Rain', - 'Cloudy Night', - 'Error Screen' -]; - -final imageLink = [ - 'https://unsplash.com/photos/time-lapse-photography-of-stars-at-nighttime-YvOT1lJ0NPQ', - 'https://unsplash.com/photos/ocean-under-clouds-Plkff-dVfNM', - 'https://unsplash.com/photos/blue-and-white-sky-d12K_FkCUN8', - 'https://unsplash.com/photos/view-of-calm-sea-nQM2oClouhY', - 'https://unsplash.com/photos/silhouette-of-trees-and-sea-L-HxY2XlaaY', - 'https://unsplash.com/photos/water-droplets-on-clear-glass-1YHXFeOYpN0', - 'https://unsplash.com/photos/snow-covered-trees-and-road-during-daytime-wyM1KmMUSbA', - 'https://unsplash.com/photos/a-view-of-a-plane-through-a-rain-covered-window-UsYOap7yIMg', - 'https://unsplash.com/photos/lightning-strike-on-the-sky-ley4Kf2iG7Y', - 'https://unsplash.com/photos/snowy-forest-on-mountainside-during-daytime-t4hA-zCALUQ', - 'https://unsplash.com/photos/green-trees-on-mountain-under-white-clouds-during-daytime-obQacWYxB1I', - 'https://unsplash.com/photos/bokeh-photography-of-snows-SH4GNXNj1RA', - 'https://unsplash.com/photos/dew-drops-on-glass-panel-bWtd1ZyEy6w', - 'https://unsplash.com/photos/blue-and-white-starry-night-sky-NpF9JLGYfeQ', - 'https://unsplash.com/photos/snow-covered-grass-at-daytime-KQWEuSh_VR0', -]; - class DonationPage extends StatefulWidget { - final Color primary; - final Color back; + final primary; final settings; + final surface; + final onSurface; + final highlight; + const DonationPage({Key? key, required this.primary, required this.settings, - required this.back}) : super(key: key); + required this.surface, required this.highlight, required this.onSurface}) : super(key: key); @override _DonationPageState createState() => - _DonationPageState(primary: primary, settings: settings, back: back); + _DonationPageState(primary: primary, settings: settings, surface: surface, + onSurface: onSurface, highlight: highlight); } class _DonationPageState extends State { final primary; final settings; - final back; + final surface; + final onSurface; + final highlight; - _DonationPageState({required this.back, required this.settings, required this.primary}); + + _DonationPageState({required this.surface, required this.settings, + required this.primary, required this.onSurface, required this.highlight}); void goBack() { Navigator.pop(context); @@ -85,90 +57,62 @@ class _DonationPageState extends State { @override Widget build(BuildContext context) { - List colors = getColors(primary, back, settings, 0); - return Scaffold( - appBar: AppBar( - toolbarHeight: 65, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0)), - elevation: 0, - leadingWidth: 50, - backgroundColor: colors[0], - title: comfortatext(translation('Donate', settings["Language"]), 25, settings, - color: colors[2]), - leading: IconButton( - onPressed: () { - goBack(); - }, - icon: Icon( - Icons.arrow_back, - color: colors[2], - ), - )), - body: Container( - color: colors[0], - child: Padding( - padding: const EdgeInsets.only(top: 30), - child: Align( - alignment: Alignment.topCenter, - child: Column( - children: [ - Container( - padding: const EdgeInsets.all(20), - child: Image.asset( - 'assets/icons/Overmorrow_white_classic.png', - fit: BoxFit.contain, - height: 100, - ), - ), - SizedBox( - width: 300, + return Material( + color: surface, + child: CustomScrollView( + slivers: [ + SliverAppBar.large( + leading: + IconButton(icon: Icon(Icons.arrow_back, color: surface,), + onPressed: () { + goBack(); + }), + title: comfortatext( + translation('Donate', settings!["Language"]!), 30, settings, + color: surface), + backgroundColor: primary, + pinned: false, + ), + SliverToBoxAdapter( + child: Container( + color: surface, + child: Padding( + padding: const EdgeInsets.only(top: 50, left: 20, right: 20), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ + comfortatext("Overmorrow was always meant to be a totally free app, without any ads or in-app-purchases. " + "\n \nSo if you just want to use it like that then please do enjoy." + "\n \nIf however you like using it and you feel like it's worth \$1 of your money then please consider supporting the project on my Patreon." + , 18, settings, color: onSurface), + Padding( - padding: const EdgeInsets.only(top: 10), - child: comfortatext(translation( - 'Overmorrow is a free app. :)', settings["Language"]), 21, settings, - color: colors[2]) - ), - Padding( - padding: const EdgeInsets.only(top: 15), - child: comfortatext(translation( - 'Support me on Patreon, to help me keep it that way!', - settings["Language"]), 21, settings, - color: colors[2]) - ), - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.only(top: 30, bottom: 40), - child: comfortatext(translation('Thank You! -Balint', - settings["Language"]), 18, settings, - color: colors[2]) + padding: const EdgeInsets.only(top: 40), + child: Center( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 0, + padding: const EdgeInsets.all(15), + backgroundColor: surface, + side: BorderSide(width: 2, color: primary), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + ), + onPressed: () async { + await _launchUrl('https://www.patreon.com/MarotiDevel'); + }, + child: comfortatext('Support on Patreon', + 18, settings, color: primary, weight: FontWeight.w600), + ), ), ), ], ), - ), - ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 6, - padding: const EdgeInsets.all(15), - backgroundColor: Color(0xfff96854), - //side: BorderSide(width: 3, color: main), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10)), - ), - onPressed: () async { - await _launchUrl('https://www.patreon.com/MarotiDevel'); - }, - child: comfortatext(translation('Support me on Patreon', settings["Language"]), - 20, settings, color: WHITE), - ), - ], + ) ), ), - ), + ], ), ); } @@ -222,7 +166,6 @@ class _InfoPageState extends State { backgroundColor: primary, pinned: false, ), - // Just some content big enough to have something to scroll. SliverToBoxAdapter( child: Container( color: surface, diff --git a/lib/settings_page.dart b/lib/settings_page.dart index b4bb4a1..3c2c5f2 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -857,8 +857,8 @@ class MyDrawer extends StatelessWidget { onTap: () { Navigator.push( context, - MaterialPageRoute(builder: (context) => DonationPage(primary: backupprimary, settings: settings, - back: backupback,)), + MaterialPageRoute(builder: (context) => DonationPage(primary: primary, settings: settings, + surface: surface, highlight: hihglight, onSurface: onSurface,)), ); }, ), From 0eba5c87eaef2e8a9d39b85090b3810b6a8cc785 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 19 Aug 2024 08:15:23 +0200 Subject: [PATCH 092/129] worked on some translations --- lib/donation_page.dart | 6 +- lib/languages.dart | 164 +++++++++++++++++++---------------------- lib/new_forecast.dart | 1 + lib/settings_page.dart | 2 +- 4 files changed, 79 insertions(+), 94 deletions(-) diff --git a/lib/donation_page.dart b/lib/donation_page.dart index 9bb1544..1b15205 100644 --- a/lib/donation_page.dart +++ b/lib/donation_page.dart @@ -82,9 +82,7 @@ class _DonationPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - comfortatext("Overmorrow was always meant to be a totally free app, without any ads or in-app-purchases. " - "\n \nSo if you just want to use it like that then please do enjoy." - "\n \nIf however you like using it and you feel like it's worth \$1 of your money then please consider supporting the project on my Patreon." + comfortatext(translation("Overmorrow donate text", settings["Language"]) , 18, settings, color: onSurface), Padding( @@ -102,7 +100,7 @@ class _DonationPageState extends State { onPressed: () async { await _launchUrl('https://www.patreon.com/MarotiDevel'); }, - child: comfortatext('Support on Patreon', + child: comfortatext(translation('Support on Patreon', settings["Language"]), 18, settings, color: primary, weight: FontWeight.w600), ), ), diff --git a/lib/languages.dart b/lib/languages.dart index e9240fe..f7b2bdb 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -32,20 +32,62 @@ Map languageIndex = { //the index of the language used in the mainT }; Map> mainTranslate = { + 'Feels like': [ + 'Feels like', + 'Hőérzet', + 'Sensación', + 'Ressenti', + 'Gefühlt', + 'Percepito', + 'Sensação', + 'Ощущается', + '体感', + '体感', + 'Odczuwaln.', + 'Αίσθηση' + ], + 'Precip.': [ + 'Precip.', + 'Csapad.', + 'Precip.', + 'Précip.', + 'Niedersch.', + 'Precip.', + 'Precip.', + 'Осадки', + '降水', + '降水', + 'Opady', + 'Κατ. βροχ.' + ], 'Humidity': [ 'Humidity', - 'Páratartalom', + 'Páratart.', 'Humedad', 'Humidité', - 'Luftfeuchtigkeit', + 'Luftfeuch.', 'Umidità', - 'Umidade', - 'влажность', + 'Humidade', + 'Влажность', '湿度', '湿度', - 'Wilgotność', + 'Wilgot.', 'Υγρασία' ], + 'Wind': [ + 'Wind', + 'Szél', + 'Viento', + 'Vent', + 'Wind', + 'Vento', + 'Vento', + 'Ветер', + '风', + '風', + 'Wiatr', + 'Άνεμος' + ], 'UV': [ 'UV', 'UV', @@ -88,20 +130,6 @@ Map> mainTranslate = { 'Ustawienia', 'Ρυθμίσεις' ], - 'Feels like': [ - 'Feels like', - 'Érződik, mint', - 'Se siente como', - 'Se sent comme', - 'Fühlt sich an wie', - 'Sembra', - 'Sente-se como', - 'Чувствуется как', - '感觉像', - '感じる', - 'Odczuwalna', - 'Αισθητή' - ], 'Donate': [ 'Donate', 'Adományozás', @@ -130,20 +158,6 @@ Map> mainTranslate = { 'Info', 'Σχετικά με' ], - 'Wind': [ - 'Wind', - 'Szél', - 'Viento', - 'Vent', - 'Wind', - 'Vento', - 'Vento', - 'Ветер', - '风', - '風', - 'Wiatr', - 'Άνεμος' - ], 'Today': [ 'Today', 'Ma', @@ -452,62 +466,6 @@ Map> mainTranslate = { 'Pochmurna noc', 'Συννεφιασμένη Νύχτα' ], - 'Overmorrow is a free app. :)': [ - 'Overmorrow is a free app. :)', - 'Overmorrow egy ingyenes alkalmazás. :)', - 'Overmorrow es una aplicación gratuita. :)', - 'Overmorrow est une application gratuite. :)', - 'Overmorrow ist eine kostenlose App. :)', - 'Overmorrow è un app gratuita. :)', - 'O Overmorrow é um aplicativo gratuito. :)', - 'Overmorrow - бесплатное приложение. :)', - 'Overmorrow是一款免费应用程序。:)', - 'Overmorrowは無料のアプリです。:)', - 'Overmorrow to darmowa aplikacja. :)', - 'Το Overmorrow είναι μία δωρεάν εφαρμογή. :)' - ], - 'Support me on Patreon, to help me keep it that way!': [ - 'Support me on Patreon, to help me keep it that way!', - 'Támogass a Patreonon, hogy segíts nekem fenntartani! :)', - '¡Apóyame en Patreon para ayudarme a mantenerlo así! :)', - 'Soutenez-moi sur Patreon pour m aider à le maintenir de cette manière ! :)', - 'Unterstützen Sie mich auf Patreon, um mir dabei zu helfen, es so zu halten! :)', - 'Sostienimi su Patreon per aiutarmi a mantenerlo in questo modo! :)', - 'Apoie-me no Patreon para me ajudar a mantê-lo assim! :)', - 'Поддержите меня на Patreon, чтобы помочь мне сохранить это так! :)', - '在Patreon上支持我,以帮助我保持这种方式!:)', - 'これを維持するのを助けるためにPatreonで私をサポートしてください!:)', - 'Wesprzyj mnie, wspomóż rozwój aplikacji! :)', - 'Στήριξέ με στο Patreon ώστε να συνεχίσει να είναι έτσι! :)' - ], - 'Thank You! -Balint': [ - 'Thank You! -Balint', - 'Köszönöm! -Balint', - '¡Gracias! -Balint', - 'Merci ! -Balint', - 'Vielen Dank! -Balint', - 'Grazie! -Balint', - 'Obrigado! -Balint', - 'Спасибо! -Балинт', - '谢谢! -巴林特', - 'ありがとうございます! -バリント', - 'Dziękuję! -Balint', - 'Σας ευχαριστώ! -Μπαλίντ' - ], - 'Support me on Patreon': [ - 'Support me on Patreon', - 'Támogass a Patreonon', - 'Apóyame en Patreon', - 'Soutenez-moi sur Patreon', - 'Unterstützen Sie mich auf Patreon', - 'Sostienimi su Patreon', - 'Apoie-me no Patreon', - 'Поддержите меня на Patreon', - '在Patreon上支持我', - 'Patreonでサポートしてください', - 'Wspieraj na Patreon', - 'Υποστήριξέ με στο Patreon' - ], 'Weak or no wifi connection': [ 'Weak or no wifi connection', @@ -1259,6 +1217,34 @@ Map> mainTranslate = { 'Wszystkie użyte obrazy pochodzą z:', 'Όλες οι εικόνες που χρησιμοποιούνται είναι από:', ], + 'Overmorrow donate text': [ + 'Overmorrow was always meant to be a totally free app, without any ads or in-app-purchases. \n \nSo if you just want to use it like that then please do enjoy. \n \nIf however you like using it and you feel like it\'s worth \$1 of your money then please consider supporting the project on my Patreon.', + 'Overmorrow mindig is teljesen ingyenes alkalmazásnak készült, hirdetések és alkalmazáson belüli vásárlások nélkül. \n \nHa csak így szeretnéd használni, akkor élvezd bátran. \n \nHa azonban szereted használni, és úgy érzed, hogy megér egy dollárt, kérlek, fontold meg a projekt támogatását a Patreonomon.', + 'Overmorrow siempre estuvo destinado a ser una aplicación completamente gratuita, sin anuncios ni compras dentro de la aplicación. \n \nAsí que si solo quieres usarla así, disfrútala. \n \nSin embargo, si te gusta usarla y sientes que vale un dólar de tu dinero, considera apoyar el proyecto en mi Patreon.', + 'Overmorrow a toujours été conçu pour être une application totalement gratuite, sans aucune publicité ni achats intégrés. \n \nDonc si vous voulez juste l\'utiliser comme ça, profitez-en. \n \nCependant, si vous aimez l\'utiliser et que vous pensez que cela vaut un dollar, envisagez de soutenir le projet sur mon Patreon.', + 'Overmorrow war immer als völlig kostenlose App gedacht, ohne Werbung oder In-App-Käufe. \n \nWenn du sie also einfach so nutzen möchtest, dann genieße es. \n \nWenn dir die Nutzung gefällt und du denkst, dass sie einen Dollar wert ist, erwäge bitte, das Projekt auf meinem Patreon zu unterstützen.', + 'Overmorrow è sempre stata pensata come un\'app completamente gratuita, senza pubblicità o acquisti in-app. \n \nQuindi, se vuoi usarla così, per favore, goditela. \n \nTuttavia, se ti piace usarla e pensi che valga un dollaro, considera di supportare il progetto su Patreon.', + 'Overmorrow sempre foi planejado para ser um aplicativo totalmente gratuito, sem anúncios ou compras dentro do app. \n \nEntão, se você quiser apenas usá-lo assim, aproveite. \n \nNo entanto, se você gosta de usá-lo e sente que vale um dólar, considere apoiar o projeto no meu Patreon.', + 'Overmorrow всегда задумывался как полностью бесплатное приложение, без рекламы и встроенных покупок. \n \nЕсли вы хотите просто пользоваться им таким образом, пожалуйста, наслаждайтесь. \n \nЕсли вам нравится пользоваться приложением, и вы считаете, что оно стоит одного доллара, пожалуйста, подумайте о поддержке проекта на моем Patreon.', + 'Overmorrow 始终是一款完全免费的应用程序,没有任何广告或应用内购买。\n \n所以如果您只想这样使用它,那么请尽情享用。\n \n但是,如果您喜欢使用它,并觉得它值 1 美元,请考虑在我的 Patreon 上支持该项目。', + 'Overmorrow は、広告やアプリ内購入がない完全無料のアプリとして常に意図されていました。\n \nそれだけで使いたい場合は、ぜひお楽しみください。\n \nただし、気に入っていただけて、それが 1 ドルの価値があると感じた場合は、私の Patreon でプロジェクトをサポートすることをご検討ください。', + 'Overmorrow zawsze miało być całkowicie darmową aplikacją, bez żadnych reklam ani zakupów w aplikacji.\n \nWięc jeśli chcesz jej tak używać, proszę bardzo.\n \nJeśli jednak lubisz ją używać i uważasz, że jest warta dolara, rozważ wsparcie projektu na moim Patreon.', + 'Το Overmorrow προοριζόταν πάντα να είναι μια εντελώς δωρεάν εφαρμογή, χωρίς διαφημίσεις ή αγορές εντός εφαρμογής. \n \nΑν λοιπόν θέλετε να το χρησιμοποιήσετε έτσι, απολαύστε το. \n \nΩστόσο, εάν σας αρέσει να το χρησιμοποιείτε και αισθάνεστε ότι αξίζει 1 δολάριο από τα χρήματά σας, σκεφτείτε να στηρίξετε το έργο στο Patreon μου.' + ], + 'Support on Patreon': [ + 'Support on Patreon', + 'Támogatás a Patreonon', + 'Apoyo en Patreon', + 'Soutien sur Patreon', + 'Unterstützung auf Patreon', + 'Supporto su Patreon', + 'Apoio no Patreon', + 'Поддержка на Patreon', + '在 Patreon 上支持', + 'Patreon でサポート', + 'Wsparcie na Patreon', + 'Υποστήριξη στο Patreon' + ], 'Search translation': [ //used for getting the codes used for translation of city names //If none are available then en (english) is the default diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index c466a94..41e3883 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -266,6 +266,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { SizedBox( height: state? 280 : 250, child: PageView( + physics: const NeverScrollableScrollPhysics(), controller: _pageController, children: [ buildTemp(day.hourly, data, highlight), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 3c2c5f2..78ef70b 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -220,7 +220,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { else if (x == "colorful") { colors = [ palette[0].onTertiaryFixedVariant, - palette[0].tertiary, + palette[0].primary, palette[0].primaryFixed, palette[0].secondaryFixed, palette[0].onSurface, From 874bccbc7bed5358f93487403d70088ece40d31b Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 20 Aug 2024 08:55:44 +0200 Subject: [PATCH 093/129] tablet mode also works now --- lib/main_screens.dart | 114 +++++++++++++++++++++------------------- lib/ui_helper.dart | 1 + lib/weather_refact.dart | 2 +- 3 files changed, 61 insertions(+), 56 deletions(-) diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 2994a5c..9afdc54 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -148,15 +148,9 @@ class _NewMainState extends State { Padding( padding: const EdgeInsets.only(top: 10, bottom: 30), - child: providerSelector( - data.settings, - updateLocation, - data.current.onSurface, - data.current.containerLow, - data.current.primary, - data.provider, - "${data.lat}, ${data.lng}", - data.real_loc), + child: providerSelector(data.settings, updateLocation, data.current.onSurface, + data.current.containerLow, data.current.primary, data.provider, + "${data.lat}, ${data.lng}", data.real_loc), ), @@ -186,7 +180,7 @@ Widget TabletLayout(data, updateLocation, context) { double toppad = MediaQuery.of(context).viewPadding.top; - double width = size.width - min(max(size.width * 0.4, 400), 450); + double width = size.width * 0.6; double heigth = min(max(width / 1.5, 450), 510); return Scaffold( @@ -200,7 +194,7 @@ Widget TabletLayout(data, updateLocation, context) { onRefresh: () async { await updateLocation("${data.lat}, ${data.lng}", data.real_loc); }, - backgroundColor: WHITE, + backgroundColor: data.current.primaryLight, color: data.current.surface, displacement: 100, child: Padding( @@ -223,70 +217,80 @@ Widget TabletLayout(data, updateLocation, context) { child: Stack( children: [ Padding( - padding: const EdgeInsets.only(top: 100), + padding: const EdgeInsets.only(top: 100, left: 6, right: 6), child: ClipRRect( borderRadius: BorderRadius.circular(20), child: ParrallaxBackground(image: data.current.image, key: Key(data.place), color: darken(data.current.surface, 0.1),), ), ), - Padding( - padding: const EdgeInsets.only(top: 100, left: 30, bottom: 31), - child: Align( - alignment: Alignment.bottomLeft, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Spacer(), - Padding( - padding: const EdgeInsets.only(left: 0, bottom: 0), - child: comfortatext("${data.current.temp}°", 65, data.settings, - color: data.current.colorpop, weight: FontWeight.w200), - ), - Padding( - padding: const EdgeInsets.only(left: 0), - child: comfortatext(data.current.text, 25, data.settings, color: data.current.colorpop), - ), - ], - ), - ), - ), - LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - if(constraints.maxWidth > 400.0) { - return Padding( - padding: const EdgeInsets.only(right: 20), - child: Circles(400, data, 0.6, data.current.colorpop, align: Alignment.centerRight), - ); - } else { - return Circles(constraints.maxWidth * 0.90, data, 1, data.current.surface); - } - } - ), MySearchParent(updateLocation: updateLocation, - color: data.current.container, place: data.place, - controller: controller, settings: data.settings, real_loc: data.real_loc, - secondColor: data.current.surface, textColor: data.current.outline, - highlightColor: data.current.surface, key: Key("${data.place}, ${data.current.surface}"), + color: data.current.container, + place: data.place, + controller: controller, + settings: data.settings, + real_loc: data.real_loc, + secondColor: data.settings["Color mode"] == "light" ? data.current.primary : data.current.onSurface, + textColor: data.settings["Color mode"] == "light" ? data.current.primaryLight : data.current.primary, + highlightColor: data.settings["Color mode"] == "light" ? data.current.primary : data.current.onSurface, + key: Key("${data.place}, ${data.current.surface}"), extraTextColor: data.current.onSurface,), ], ), ), ), ), - buildHihiDays(data), + Padding( + padding: const EdgeInsets.only(left: 30, right: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 7), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + comfortatext("${data.current.temp}°", 65, data.settings, + color: data.current.primaryLight, weight: FontWeight.w200), + comfortatext(data.current.text, 25, data.settings, color: data.current.onSurface, + weight: FontWeight.w300), + ], + ), + ), + const Spacer(), + Stack( + alignment: Alignment.topRight, + children: [ + FadingWidget(data: data, + time: data.updatedTime, + key: Key(data.updatedTime.toString())), + Circles(420, data, 0.3, data.current.primary), + ], + ), + ], + ), + ), + + buildNewDays(data), ], ), ), Expanded( child: Padding( - padding: const EdgeInsets.only(left: 20, top: 50), + padding: const EdgeInsets.only(left: 20, top: 0), child: Column( children: [ - NewTimes(data, false), - buildGlanceDay(data), - providerSelector(data.settings, updateLocation, data.current.outline, data.current.container, data.current.surface, - data.provider, "${data.lat}, ${data.lng}", data.real_loc), + NewSunriseSunset(data: data, key: Key(data.place), size: size,), + NewRain15MinuteIndicator(data), + NewAirQuality(data), + RadarSmall(data: data, key: Key("${data.place}, ${data.current.surface}")), + buildNewGlanceDay(data: data, key: Key("${data.place}, ${data.current.primary}"),), + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 30), + child: providerSelector(data.settings, updateLocation, data.current.onSurface, + data.current.containerLow, data.current.primary, data.provider, + "${data.lat}, ${data.lng}", data.real_loc), + ), ], ), ), diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index abbbfb7..8c4edb2 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -451,6 +451,7 @@ Widget RainWidget(data, day, highlight) { return Padding( padding: const EdgeInsets.only(left: 13, right: 13, top: 15), child: Container( + constraints: const BoxConstraints(minWidth: 0, maxWidth: 450), decoration: BoxDecoration( borderRadius: BorderRadius.circular(18), //color: data.current.containerLow, diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 043f963..e8755fa 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -329,7 +329,7 @@ Map> conversionTable = { Map> textToUnsplashText = { 'Clear Night': ['night', 'clear', 'moon'], //somehow just 'night' always gives you clear skies: stars or moon 'Partly Cloudy': ['cloud',], //this is also some simplification which improves a lot - 'Clear Sky': ['blue sky', 'sunny', 'sun', 'clear', 'cloud'], //it doesn't understand clear as much so i use blue instead + 'Clear Sky': ['blue sky', 'sunny', 'sun', 'clear'], //it doesn't understand clear as much so i use blue instead 'Overcast': ['overcast', 'cloud'], 'Haze': ['haze', 'fog', 'mist'], 'Rain': ['rain', 'drop', 'rainy', 'raining', 'drops'], From 55c112c8a1278cf9c8799a6f6c4917f53b138445 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 20 Aug 2024 17:12:33 +0200 Subject: [PATCH 094/129] trying to make themes less blue --- lib/decoders/decode_OM.dart | 8 ++++- lib/decoders/decode_wapi.dart | 10 ++++-- lib/decoders/extra_info.dart | 21 ++++++++++-- lib/main_screens.dart | 27 ++++++++++++++++ lib/settings_page.dart | 11 ++++--- lib/ui_helper.dart | 2 -- lib/weather_refact.dart | 2 ++ pubspec.lock | 60 +++++++++++++++++------------------ 8 files changed, 98 insertions(+), 43 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 0891f9b..06a8477 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -257,6 +257,7 @@ class OMCurrent { final String photographerName; final String photographerUrl; final String photoUrl; + final List imageDebugColors; const OMCurrent({ required this.precip, @@ -289,6 +290,7 @@ class OMCurrent { required this.photographerName, required this.photographerUrl, required this.photoUrl, + required this.imageDebugColors }); static Future fromJson(item, settings, sunstatus, timenow, real_loc, lat, lng) async { @@ -325,7 +327,9 @@ class OMCurrent { item["current"]["weather_code"], sunstatus, timenow), ); - List colors = await getMainColor(settings, primary, back, Uimage); + List x = await getMainColor(settings, primary, back, Uimage); + List colors = x[0]; + List imageDebugColors = x[1]; print((photographerName, photorgaperUrl, photoLink)); @@ -335,6 +339,8 @@ class OMCurrent { photographerUrl: photorgaperUrl, photoUrl: photoLink, + imageDebugColors: imageDebugColors, + text: translation(oMCurrentTextCorrection( item["current"]["weather_code"], sunstatus, timenow), settings["Language"]), diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index ee409ff..caae91f 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -279,6 +279,8 @@ class WapiCurrent { final String photographerUrl; final String photoUrl; + final List imageDebugColors; + const WapiCurrent({ required this.precip, required this.humidity, @@ -310,6 +312,7 @@ class WapiCurrent { required this.photographerName, required this.photographerUrl, required this.photoUrl, + required this.imageDebugColors, }); static Future fromJson(item, settings, real_loc, lat, lng) async { @@ -348,7 +351,9 @@ class WapiCurrent { ) ); - List colors = await getMainColor(settings, primary, back, Uimage); + List x = await getMainColor(settings, primary, back, Uimage); + List colors = x[0]; + List imageDebugColors = x[1]; return WapiCurrent( @@ -392,7 +397,8 @@ class WapiCurrent { photographerName: photographerName, photographerUrl: photorgaperUrl, - photoUrl: photoLink + photoUrl: photoLink, + imageDebugColors: imageDebugColors, ); } } diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index c5beb57..d6eb28c 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -164,8 +164,23 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { ColorScheme palette; + Color primeColor = Colors.amber; + int bestValue = -10000; + + List paliColors = paliTotal.colors.toList(); + + for (int i = 0; i < paliColors.length; i++) { //i am trying to reduce the number of blue palettes + //because they are too common + double v = paliColors[i].red * 1 + paliColors[i].green * 1 - paliColors[i].blue * 5.0; + if (v > bestValue) { + print(("better", i)); + bestValue = v.round(); + primeColor = paliColors[i]; + } + } + if (settings["Color source"] == "image") { - palette = await _materialPalette(Uimage, color_mode, paliTotal.colors.first); + palette = await _materialPalette(Uimage, color_mode, primeColor); } else { palette = await MaterialYouColor(color_mode); @@ -214,7 +229,7 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { desc_color = bestcolor; } - return [palette, bestcolor, desc_color]; + return [[palette, bestcolor, desc_color], paliTotal.colors.toList()]; } int difFromBackColors(Color frontColor, List backcolors) { @@ -310,7 +325,7 @@ Future> _generatorPalette(Image imageWidget) async { ); PaletteGenerator _paletteGenerator2 = await PaletteGenerator.fromImage( imageInfo.image, - maximumColorCount: 1 + maximumColorCount: 5 ); imageProvider.resolve(const ImageConfiguration()).removeListener(listener); diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 9afdc54..cdaba0a 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -138,6 +138,33 @@ class _NewMainState extends State { ), ], ), + /* + Padding( + padding: const EdgeInsets.only(left: 30), + child: SizedBox( + height: 35, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + physics: const NeverScrollableScrollPhysics(), + itemCount: data.current.imageDebugColors.length, + itemBuilder: (context, index) { + return Padding( + padding: EdgeInsets.all(5), + child: Container( + width: 25, + height: 25, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: data.current.imageDebugColors[index] + ), + ), + ); + } + ), + ), + ), + */ NewSunriseSunset(data: data, key: Key(data.place), size: size,), NewRain15MinuteIndicator(data), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 78ef70b..39fe4aa 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -277,12 +277,13 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { return colors; } -Future> getMainColor(settings, primary, back, image) async { +Future> getMainColor(settings, primary, back, image) async { List colors; final String mode = settings["Color mode"]; - List palette = await getImageColors(image, mode, settings); + List x = await getImageColors(image, mode, settings); + List palette = x[0]; if ((mode == "light" || mode == "dark") || settings["Image source"] == 'network' || settings["Color source"] == 'wallpaper') { @@ -292,7 +293,7 @@ Future> getMainColor(settings, primary, back, image) async { colors = getColors(primary, back, settings, 0); } - return colors; + return [colors, x[1]]; } Future> getTotalColor(settings, primary, back, image) async { @@ -301,8 +302,8 @@ Future> getTotalColor(settings, primary, back, image) async { final String mode = settings["Color mode"]; - List lightPalette = await getImageColors(image, "light" , settings); - List darkPalette = await getImageColors(image, "dark" , settings); + List lightPalette = (await getImageColors(image, "light" , settings))[0]; + List darkPalette = (await getImageColors(image, "dark" , settings))[0]; if (settings["Image source"] == 'network' || settings["Color source"] == 'wallpaper') { allColor.add(getNetworkColors(darkPalette, settings, force: "original")); diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 8c4edb2..2d311ec 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -76,7 +76,6 @@ bool estimateBrightnessForColor(Color color) { final double relativeLuminance = color.computeLuminance(); const double kThreshold = 0.15; - print((relativeLuminance + 0.05) * (relativeLuminance + 0.05) > kThreshold); return (relativeLuminance + 0.05) * (relativeLuminance + 0.05) > kThreshold; } @@ -545,7 +544,6 @@ class BarChartPainter extends CustomPainter { int smallerThan = (precip[i] * 2).round(); - print((precip[i], smallerThan)); if (smallerThan == 0 && precip[i] > 0) { smallerThan = 1; } diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index e8755fa..9e28ad6 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -363,6 +363,8 @@ Map textFilter = { 'wall' : -10000, 'text': -10000, 'sign': -10000, + 'grayscale' : -100000, + 'black and white' : -100000, 'man': -10000000, //trying to not have people in images 'male': -1000000, 'couple': -1000000, diff --git a/pubspec.lock b/pubspec.lock index 97a8aa7..f8dbd61 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -37,26 +37,26 @@ packages: dependency: "direct main" description: name: cached_network_image - sha256: "4a5d8d2c728b0f3d0245f69f921d7be90cae4c2fd5288f773088672c0893f819" + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" url: "https://pub.dev" source: hosted - version: "3.4.0" + version: "3.4.1" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: ff0c949e323d2a1b52be73acce5b4a7b04063e61414c8ca542dbba47281630a7 + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "4.1.1" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: "6322dde7a5ad92202e64df659241104a43db20ed594c41ca18de1014598d7996" + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.3.1" characters: dependency: transitive description: @@ -101,10 +101,10 @@ packages: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" cupertino_icons: dependency: "direct main" description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: ffi - sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" file: dependency: transitive description: @@ -162,10 +162,10 @@ packages: dependency: "direct main" description: name: flutter_cache_manager - sha256: a77f77806a790eb9ba0118a5a3a936e81c4fea2b61533033b2b0c3d50bbde5ea + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" url: "https://pub.dev" source: hosted - version: "3.4.0" + version: "3.4.1" flutter_launcher_icons: dependency: "direct main" description: @@ -476,10 +476,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "490539678396d4c3c0b06efdaab75ae60675c3e0c66f72bc04c2e2c1e0e2abeb" + sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" url: "https://pub.dev" source: hosted - version: "2.2.9" + version: "2.2.10" path_provider_foundation: dependency: transitive description: @@ -564,34 +564,34 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: c272f9cabca5a81adc9b0894381e9c1def363e980f960fa903c604c471b22f68 + sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "041be4d9d2dc6079cf342bc8b761b03787e3b71192d658220a56cac9c04a0294" + sha256: a7e8467e9181cef109f601e3f65765685786c1a738a83d7fbbde377589c0d974 url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.1" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "671e7a931f55a08aa45be2a13fe7247f2a41237897df434b30d2012388191833" + sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.5.2" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "2ba0510d3017f91655b7543e9ee46d48619de2a2af38e5c790423f7007c7ccc1" + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: @@ -604,18 +604,18 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2" + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "398084b47b7f92110683cac45c6dc4aae853db47e470e5ddcd52cab7f7196ab2" + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" sky_engine: dependency: transitive description: flutter @@ -737,10 +737,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "94d8ad05f44c6d4e2ffe5567ab4d741b82d62e3c8e288cc1fcea45965edf47c9" + sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79 url: "https://pub.dev" source: hosted - version: "6.3.8" + version: "6.3.9" url_launcher_ios: dependency: transitive description: @@ -753,10 +753,10 @@ packages: dependency: transitive description: name: url_launcher_linux - sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.2.0" url_launcher_macos: dependency: transitive description: From 9db722b4a12e77f7093d57410aa0b556a8f6cd5e Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 20 Aug 2024 17:23:31 +0200 Subject: [PATCH 095/129] did some minor tweaking --- lib/decoders/extra_info.dart | 1 - lib/main_screens.dart | 2 +- lib/weather_refact.dart | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index d6eb28c..cd6b1a7 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -132,7 +132,6 @@ Future> getUnsplashImage(String _text, String real_loc, double lat print((username, userLink)); - return [Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover, width: double.infinity, height: double.infinity,), username, userLink, photoLink]; } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index cdaba0a..263e3f1 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -89,7 +89,7 @@ class _NewMainState extends State { children: [ const Spacer(), Padding( - padding: const EdgeInsets.only(left: 0, bottom: 2), + padding: const EdgeInsets.only(left: 0, bottom: 0), child: comfortatext( "${data.current.temp}°", 69, data.settings, color: data.current.colorPop, weight: FontWeight.w300, diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 9e28ad6..7c52a9a 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -354,6 +354,7 @@ Map textFilter = { 'ice': -10000, 'icy': -10000, 'bubble': -10000, + 'smoke' : -2000, 'instagram': -10000, 'ring': -10000, 'during': 10000, From 11545ddffb94ddf488e58b91e126df01148549ab Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 21 Aug 2024 08:55:06 +0200 Subject: [PATCH 096/129] made unsplash link buttons bigger, because they were practically impossible to tap --- lib/decoders/decode_wapi.dart | 2 +- lib/ui_helper.dart | 42 ++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index caae91f..2456b3f 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -416,7 +416,7 @@ class WapiDay { final double total_precip; final int windspeed; final int uv; - final mm_precip; + final double mm_precip; final int wind_dir; diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 2d311ec..c3578d8 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -150,14 +150,14 @@ class _FadingWidgetState extends State with AutomaticKeepAliveClie @override void initState() { super.initState(); - _timer = Timer(Duration(milliseconds: 400), () { + _timer = Timer(const Duration(milliseconds: 400), () { if (mounted) { setState(() { _isVisible = true; }); } }); - _timer = Timer(Duration(milliseconds: 2000), () { + _timer = Timer(const Duration(milliseconds: 2000), () { if (mounted) { setState(() { _isVisible = false; @@ -252,31 +252,43 @@ class _SinceLastUpdateState extends State{ } else if (widget.data.current.photographerName != ""){ List split = translation("photo by x on Unsplash", widget.data.settings["Language"]).split(","); return Padding( - padding: const EdgeInsets.only(top: 5, right: 10), + padding: const EdgeInsets.only(top: 0, right: 10), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - GestureDetector( - onTap: () async { + TextButton( + onPressed: () async { await _launchUrl(widget.data.current.photoUrl); }, - child: comfortatext(split[0], 12, widget.data.settings, color: widget.data.current.onSurface, + style: TextButton.styleFrom( + padding: const EdgeInsets.all(1), + minimumSize: const Size(0, 22), + tapTargetSize: MaterialTapTargetSize.shrinkWrap,), + child: comfortatext(split[0], 12.5, widget.data.settings, color: widget.data.current.onSurface, decoration: TextDecoration.underline), ), - comfortatext(split[1], 12, widget.data.settings, color: widget.data.current.onSurface), - GestureDetector( - onTap: () async { + comfortatext(split[1], 12.5, widget.data.settings, color: widget.data.current.onSurface), + TextButton( + onPressed: () async { await _launchUrl(widget.data.current.photographerUrl); }, - child: comfortatext(widget.data.current.photographerName, 13, widget.data.settings, color: widget.data.current.onSurface, + style: TextButton.styleFrom( + padding: const EdgeInsets.all(1), + minimumSize: const Size(0, 22), + tapTargetSize: MaterialTapTargetSize.shrinkWrap,), + child: comfortatext(widget.data.current.photographerName, 12.5, widget.data.settings, color: widget.data.current.onSurface, decoration: TextDecoration.underline), ), - comfortatext(split[3], 12, widget.data.settings, color: widget.data.current.onSurface), - GestureDetector( - onTap: () async { + comfortatext(split[3], 12.5, widget.data.settings, color: widget.data.current.onSurface), + TextButton( + onPressed: () async { await _launchUrl("https://unsplash.com/"); }, - child: comfortatext(split[4], 12, widget.data.settings, color: widget.data.current.onSurface, + style: TextButton.styleFrom( + padding: const EdgeInsets.all(1), + minimumSize: const Size(0, 22), + tapTargetSize: MaterialTapTargetSize.shrinkWrap,), + child: comfortatext(split[4], 12.5, widget.data.settings, color: widget.data.current.onSurface, decoration: TextDecoration.underline), ), ], @@ -462,7 +474,7 @@ Widget RainWidget(data, day, highlight) { child: Column( children: [ Padding( - padding: EdgeInsets.only(top: 14, right: 18, left: 18), + padding: const EdgeInsets.only(top: 14, right: 18, left: 18), child: AspectRatio( aspectRatio: 2.2, child: MyChart(precip, data, highlight) From e2532e7688b5d04a0a380d30cdb268f9ab773adf Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 23 Aug 2024 07:58:11 +0200 Subject: [PATCH 097/129] added utm referral links --- lib/decoders/extra_info.dart | 2 +- lib/main_screens.dart | 2 +- lib/ui_helper.dart | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index cd6b1a7..3b6d2b2 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -126,7 +126,7 @@ Future> getUnsplashImage(String _text, String real_loc, double lat print(index); print(unsplash_body[index]["links"]["html"]); - final String userLink = unsplash_body[index]["user"]["links"]["html"] ?? ""; + final String userLink = (unsplash_body[index]["user"]["links"]["html"]) ?? ""; final String username = unsplash_body[index]["user"]["name"] ?? ""; final String photoLink = unsplash_body[index]["links"]["html"] ?? ""; diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 263e3f1..a11bc26 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -93,7 +93,7 @@ class _NewMainState extends State { child: comfortatext( "${data.current.temp}°", 69, data.settings, color: data.current.colorPop, weight: FontWeight.w300, - ) + ), ), Padding( padding: const EdgeInsets.only(left: 0), diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index c3578d8..53ac8cb 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -258,7 +258,7 @@ class _SinceLastUpdateState extends State{ children: [ TextButton( onPressed: () async { - await _launchUrl(widget.data.current.photoUrl); + await _launchUrl(widget.data.current.photoUrl + "?utm_source=overmorrow&utm_medium=referral"); }, style: TextButton.styleFrom( padding: const EdgeInsets.all(1), @@ -270,7 +270,7 @@ class _SinceLastUpdateState extends State{ comfortatext(split[1], 12.5, widget.data.settings, color: widget.data.current.onSurface), TextButton( onPressed: () async { - await _launchUrl(widget.data.current.photographerUrl); + await _launchUrl(widget.data.current.photographerUrl + "?utm_source=overmorrow&utm_medium=referral"); }, style: TextButton.styleFrom( padding: const EdgeInsets.all(1), @@ -282,7 +282,7 @@ class _SinceLastUpdateState extends State{ comfortatext(split[3], 12.5, widget.data.settings, color: widget.data.current.onSurface), TextButton( onPressed: () async { - await _launchUrl("https://unsplash.com/"); + await _launchUrl("https://unsplash.com/?utm_source=overmorrow&utm_medium=referral"); }, style: TextButton.styleFrom( padding: const EdgeInsets.all(1), From 46dc74cfe6fc96640553acaa2b97b2b11fe2e38e Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 23 Aug 2024 15:10:14 +0200 Subject: [PATCH 098/129] added a nice zoom in effect to image --- lib/main_ui.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/main_ui.dart b/lib/main_ui.dart index 80f6195..3a55b7c 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -62,7 +62,6 @@ class WeatherPage extends StatelessWidget { } } - class ParrallaxBackground extends StatelessWidget { final Image image; final Color color; @@ -73,14 +72,18 @@ class ParrallaxBackground extends StatelessWidget { Widget build(BuildContext context) { return TweenAnimationBuilder( - duration: const Duration(milliseconds: 1000), + duration: const Duration(milliseconds: 1300), tween: Tween(begin: 0, end: 1), + curve: Curves.easeOutCubic, builder: (context, value, child) { return Container( color: color, child: Opacity( opacity: value, - child: image, + child: Transform.scale( + scale: 1.0 + (0.06 * value), + child: image, + ), ), ); }, From a543a2a7367772fa35fe6d87e30776bface0d68f Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 23 Aug 2024 15:39:51 +0200 Subject: [PATCH 099/129] supposedly added haptics... can't test on emulator so idk --- android/app/src/main/AndroidManifest.xml | 1 + lib/donation_page.dart | 9 +++++++++ lib/main_ui.dart | 2 ++ lib/new_forecast.dart | 4 ++++ lib/radar.dart | 9 +++++++++ lib/search_screens.dart | 15 +++++++++++++++ lib/settings_page.dart | 7 +++++++ 7 files changed, 47 insertions(+) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index ff90426..60bb879 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + package="com.example.url_launcher_example"> diff --git a/lib/donation_page.dart b/lib/donation_page.dart index 1b15205..c581a27 100644 --- a/lib/donation_page.dart +++ b/lib/donation_page.dart @@ -18,6 +18,7 @@ along with this program. If not, see . import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:overmorrow/ui_helper.dart'; @@ -52,6 +53,7 @@ class _DonationPageState extends State { required this.primary, required this.onSurface, required this.highlight}); void goBack() { + HapticFeedback.selectionClick(); Navigator.pop(context); } @@ -143,6 +145,7 @@ class _InfoPageState extends State { required this.highlight}); void goBack() { + HapticFeedback.selectionClick(); Navigator.pop(context); } @@ -197,6 +200,7 @@ class _InfoPageState extends State { children: [ GestureDetector( onTap: () { + HapticFeedback.selectionClick(); _launchUrl("https://github.com/bmaroti9/Overmorrow"); }, child: comfortatext(translation("source code", settings["Language"]), 16, settings, color: primary, @@ -204,6 +208,7 @@ class _InfoPageState extends State { ), GestureDetector( onTap: () { + HapticFeedback.selectionClick(); _launchUrl("https://github.com/bmaroti9/Overmorrow/issues"); }, child: comfortatext(translation("report an issue", settings["Language"]), 16, settings, color: primary, @@ -226,6 +231,7 @@ class _InfoPageState extends State { children: [ GestureDetector( onTap: () { + HapticFeedback.selectionClick(); _launchUrl("https://open-meteo.com"); }, child: comfortatext("open-meteo", 16, settings, color: primary, @@ -233,6 +239,7 @@ class _InfoPageState extends State { ), GestureDetector( onTap: () { + HapticFeedback.selectionClick(); _launchUrl("https://www.weatherapi.com/"); }, child: comfortatext("weatherapi", 16, settings, color: primary, @@ -240,6 +247,7 @@ class _InfoPageState extends State { ), GestureDetector( onTap: () { + HapticFeedback.selectionClick(); _launchUrl("https://www.rainviewer.com/api.html"); }, child: comfortatext("rainviewer", 16, settings, color: primary, @@ -256,6 +264,7 @@ class _InfoPageState extends State { comfortatext(translation("all images used are from:", settings["Language"]), 16, settings, color: onSurface), GestureDetector( onTap: () { + HapticFeedback.selectionClick(); _launchUrl("https://unsplash.com/"); }, child: comfortatext("unsplash", 16, settings, color: primary, diff --git a/lib/main_ui.dart b/lib/main_ui.dart index 3a55b7c..dfc21d3 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -20,6 +20,7 @@ import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/decoders/decode_wapi.dart'; import 'package:overmorrow/main_screens.dart'; @@ -768,6 +769,7 @@ Widget providerSelector(settings, updateLocation, textcolor, highlight, primary, ); }).toList(), onChanged: (String? value) async { + HapticFeedback.mediumImpact(); SetData('weather_provider', value!); await updateLocation(latlng, real_loc); }, diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 41e3883..f468074 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -21,6 +21,7 @@ import 'dart:math'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:overmorrow/settings_page.dart'; import 'ui_helper.dart'; @@ -88,6 +89,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { child: Icon(Icons.expand_less, color: data .current.primaryLight, size: 20), onTap: () { + HapticFeedback.selectionClick(); onExpandTapped(index); }, ), @@ -255,6 +257,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { onSelected: (bool selected) { _value = index; setState(() { + HapticFeedback.selectionClick(); _onItemTapped(index); }); }, @@ -689,6 +692,7 @@ class _buildNewGlanceDayState extends State with AutomaticKee void _onExpandTapped(int index) { setState(() { + HapticFeedback.selectionClick(); expand[index] = !expand[index]; }); } diff --git a/lib/radar.dart b/lib/radar.dart index 6708af9..1d51b97 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -21,6 +21,7 @@ import 'dart:math'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/settings_page.dart'; @@ -505,6 +506,7 @@ class _RadarSmallState extends State { timer = Timer.periodic(const Duration(milliseconds: 1000), (Timer t) { if (isPlaying) { setState(() { + HapticFeedback.lightImpact(); currentFrameIndex = ((currentFrameIndex + 1) % (data.radar.images.length - 1)); }); @@ -622,6 +624,7 @@ class _RadarSmallState extends State { ), ), onPressed: () { + HapticFeedback.selectionClick(); Navigator.push( context, MaterialPageRoute(builder: (context) => @@ -666,6 +669,7 @@ class _RadarSmallState extends State { ) ), onPressed: () async { + HapticFeedback.selectionClick(); togglePlayPause(); }, child: Icon(isPlaying ? Icons.pause_outlined : Icons.play_arrow, @@ -712,6 +716,7 @@ class _RadarSmallState extends State { onChanged: (double value) { setState(() { + HapticFeedback.lightImpact(); hasBeenPlayed = true; currentFrameIndex = value; }); @@ -801,6 +806,7 @@ class _RadarBigState extends State { timer = Timer.periodic(const Duration(milliseconds: 1600), (Timer t) { if (isPlaying) { + HapticFeedback.lightImpact(); setState(() { currentFrameIndex = ((currentFrameIndex + 1) % (data.radar.images.length - 1)); @@ -903,6 +909,7 @@ class _RadarBigState extends State { ) ), onPressed: () async { + HapticFeedback.selectionClick(); togglePlayPause(); }, child: Icon(isPlaying ? Icons.pause_outlined : Icons.play_arrow, @@ -950,6 +957,7 @@ class _RadarBigState extends State { onChanged: (double value) { setState(() { + HapticFeedback.lightImpact(); hasBeenPlayed = true; currentFrameIndex = value; }); @@ -1015,6 +1023,7 @@ class _RadarBigState extends State { ), ), onPressed: () { + HapticFeedback.selectionClick(); Navigator.of(context).pop(); }, child: Icon(CupertinoIcons.fullscreen_exit, diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 9b7eb97..1ac5a79 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -76,12 +76,17 @@ Widget searchBar(Color color, List recommend, controller: controller, width: 800, + onFocusChanged: (to) { + HapticFeedback.selectionClick(); + }, + onQueryChanged: (query) async { isEditing = false; var result = await getRecommend(query, settings["Search provider"], settings); updateRec(result); }, onSubmitted: (submission) { + HapticFeedback.lightImpact(); updateLocation('query', submission); controller.close(); }, @@ -103,6 +108,7 @@ Widget searchBar(Color color, List recommend, child: CircularButton( icon: Icon(Icons.arrow_back_outlined, color: secondColor, size: 22,), onPressed: () { + HapticFeedback.selectionClick(); controller.close(); }, ), @@ -114,6 +120,7 @@ Widget searchBar(Color color, List recommend, child: IconButton( icon: Icon(Icons.menu_rounded, color: textColor, size: 25,), onPressed: () { + HapticFeedback.selectionClick(); Scaffold.of(context).openDrawer(); }, ), @@ -141,6 +148,7 @@ Widget searchBar(Color color, List recommend, child: CircularButton( icon: Icon(Icons.close, color: textColor,), onPressed: () { + HapticFeedback.lightImpact(); controller.clear(); }, ), @@ -249,6 +257,7 @@ Widget defaultSearchScreen(Color color, ) ), onPressed: () async { + HapticFeedback.lightImpact(); updateIsEditing(!isEditing); }, child: editIcon, @@ -281,6 +290,7 @@ Widget defaultSearchScreen(Color color, return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { + HapticFeedback.lightImpact(); updateLocation('${split["lat"]}, ${split["lon"]}', split["name"]); controller.close(); }, @@ -305,6 +315,7 @@ Widget defaultSearchScreen(Color color, icon: Myicon[icons[index]], onPressed: () { if (isEditing) { + HapticFeedback.mediumImpact(); favorites.remove(favorites[index]); updateFav(favorites); } @@ -353,6 +364,7 @@ Widget recommendSearchScreen(Color color, List recommend, return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { + HapticFeedback.selectionClick(); updateLocation('${split["lat"]}, ${split["lon"]}', split["name"]); controller.close(); }, @@ -376,10 +388,12 @@ Widget recommendSearchScreen(Color color, List recommend, IconButton(onPressed: () { if (favorites.contains(recommend[index])) { + HapticFeedback.mediumImpact(); favorites.remove(recommend[index]); updateFav(favorites); } else{ + HapticFeedback.lightImpact(); favorites.add(recommend[index]); updateFav(favorites); } @@ -433,6 +447,7 @@ Widget LocationButton(Function updateProg, Function updateLocation, Color color, ) ), onPressed: () async { + HapticFeedback.lightImpact(); updateLocation('40.7128, 74.0060', 'CurrentLocation'); }, //^ this is new york for backup child: Icon(Icons.place_outlined, color: textColor,), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 39fe4aa..b137f52 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -18,6 +18,7 @@ along with this program. If not, see . import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:geolocator/geolocator.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/donation_page.dart'; @@ -420,6 +421,7 @@ Widget dropdown(Color bgcolor, String name, Function updatePage, String unit, se ); }).toList(), onChanged: (Object? value) { + HapticFeedback.lightImpact(); updatePage(name, value); } ); @@ -469,6 +471,7 @@ Widget ColorCircle(name, outline, inside, settings, updatePage, {w = 2, tap = 0} return Expanded( child: GestureDetector( onTap: () { + HapticFeedback.mediumImpact(); if (tap == 0) { return; } @@ -568,6 +571,7 @@ Widget SettingsMain(Color primary, Map? settings, Function updat SliverAppBar.large( leading: IconButton(icon: Icon(Icons.arrow_back, color: colors[11],), onPressed: () { + HapticFeedback.selectionClick(); goBack(); }), title: comfortatext(translation('Settings', settings!["Language"]!), 30, settings, color: colors[11]), @@ -832,6 +836,7 @@ class MyDrawer extends StatelessWidget { settings, color: onSurface), leading: Icon(Icons.settings, color: primary,), onTap: () { + HapticFeedback.selectionClick(); Navigator.push( context, MaterialPageRoute(builder: (context) => SettingsPage(primary: backupprimary, @@ -844,6 +849,7 @@ class MyDrawer extends StatelessWidget { settings, color: onSurface), leading: Icon(Icons.info_outline, color: primary,), onTap: () { + HapticFeedback.selectionClick(); Navigator.push( context, MaterialPageRoute(builder: (context) => InfoPage(primary: primary, settings: settings, @@ -856,6 +862,7 @@ class MyDrawer extends StatelessWidget { settings, color: onSurface), leading: Icon(Icons.favorite_border, color: primary,), onTap: () { + HapticFeedback.selectionClick(); Navigator.push( context, MaterialPageRoute(builder: (context) => DonationPage(primary: primary, settings: settings, From 63334dc910bbd77f42b97f4044bd823e90189097 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 23 Aug 2024 15:55:27 +0200 Subject: [PATCH 100/129] removed the totally unnecessary 800ms wait in every load --- lib/main.dart | 9 ++++++--- lib/main_screens.dart | 2 +- lib/search_screens.dart | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 49f7ddc..3f0f825 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -209,8 +209,9 @@ class _MyAppState extends State { updateLocation('40.7128, 74.0060', "New York", time: 300, startup: true); //just for testing } - Future updateLocation(proposedLoc, backupName, {time = 500, startup = false}) async { + Future updateLocation(proposedLoc, backupName, {time = 0, startup = false}) async { setState(() { + HapticFeedback.lightImpact(); if (startup) { startup2 = true; } @@ -228,8 +229,10 @@ class _MyAppState extends State { startup2 = false; } }); - - await Future.delayed(Duration(milliseconds: (800 - time).toInt())); + if (time > 0) { + await Future.delayed(Duration(milliseconds: (800 - time).toInt())); + } + await Future.delayed(const Duration(milliseconds: 200)); setState(() { isLoading = false; diff --git a/lib/main_screens.dart b/lib/main_screens.dart index a11bc26..fa97163 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -65,7 +65,7 @@ class _NewMainState extends State { body: StretchyHeader.listView( displacement: 130, onRefresh: () async { - await updateLocation("${data.lat}, ${data.lng}", data.real_loc); + await updateLocation("${data.lat}, ${data.lng}", data.real_loc, time: 400); }, headerData: HeaderData( //backgroundColor: WHITE, diff --git a/lib/search_screens.dart b/lib/search_screens.dart index 1ac5a79..cd9db1f 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -498,7 +498,7 @@ class dumbySearch extends StatelessWidget { body: StretchyHeader.singleChild( displacement: 150, onRefresh: () async { - await updateLocation(latlng, place); + await updateLocation(latlng, place, time: 400); }, headerData: HeaderData( blurContent: false, From cf826acef2a8896df861f20461f1384d810ece0c Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 24 Aug 2024 14:11:05 +0200 Subject: [PATCH 101/129] fixed issue where currentlocation somehow put you in Tajikistan --- lib/decoders/decode_OM.dart | 3 ++- lib/main.dart | 3 +-- lib/new_displays.dart | 21 ++------------------- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 06a8477..2c9ac67 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -107,7 +107,7 @@ double OMGetSunStatus(item) { int total = sunset.difference(sunrise).inMinutes; int passed = localtime.difference(sunrise).inMinutes; - return passed / total; + return min(1, max(passed / total, 0)); } Future> OMRequestData(double lat, double lng, String real_loc) async { @@ -664,6 +664,7 @@ class OMAqi{ } Future OMGetWeatherData(lat, lng, real_loc, settings, placeName) async { + var OM = await OMRequestData(lat, lng, real_loc); var oMBody = OM[0]; diff --git a/lib/main.dart b/lib/main.dart index 3f0f825..c577179 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -111,14 +111,13 @@ class _MyAppState extends State { Placemark place = placemarks[0]; backupName = place.locality; - + absoluteProposed = "${position.latitude}, ${position.longitude}"; } on FormatException { backupName = "${position.latitude.toStringAsFixed(2)}, ${position.longitude.toStringAsFixed(2)}"; } on PlatformException { backupName = "${position.latitude.toStringAsFixed(2)}, ${position.longitude.toStringAsFixed(2)}"; } - } else { return dumbySearch(errorMessage: translation(loc_status, settings["Language"]!), diff --git a/lib/new_displays.dart b/lib/new_displays.dart index bb5f86e..56569d7 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -98,29 +98,16 @@ class NewSunriseSunset extends StatefulWidget { _NewSunriseSunsetState createState() => _NewSunriseSunsetState(); } -class _NewSunriseSunsetState extends State - with SingleTickerProviderStateMixin { - late DateTime riseDT; - late int total; +class _NewSunriseSunsetState extends State with SingleTickerProviderStateMixin { late int hourdif; late AnimationController _controller; @override void initState() { - final List absoluteSunriseSunset = - widget.data.sunstatus.absoluteSunriseSunset.split('/'); - - final List absoluteRise = absoluteSunriseSunset[0].split(':'); - final List absoluteSet = absoluteSunriseSunset[1].split(':'); - final List absoluteLocalTime = widget.data.localtime.split(':'); final currentTime = DateTime.now(); - riseDT = currentTime.copyWith( - hour: int.parse(absoluteRise[0]), minute: int.parse(absoluteRise[1])); - final setDT = currentTime.copyWith( - hour: int.parse(absoluteSet[0]), minute: int.parse(absoluteSet[1])); final localtimeOld = currentTime.copyWith( hour: int.parse(absoluteLocalTime[0]), @@ -128,8 +115,6 @@ class _NewSunriseSunsetState extends State hourdif = localtimeOld.hour - currentTime.hour; - total = setDT.difference(riseDT).inSeconds; - super.initState(); _controller = AnimationController( vsync: this, @@ -151,9 +136,7 @@ class _NewSunriseSunsetState extends State DateTime now = DateTime.now(); DateTime localTime = now.add(Duration(hours: hourdif)); - final thisdif = localTime.difference(riseDT).inSeconds; - - final double progress = min(max(thisdif / total, 0), 1); + final double progress = widget.data.sunstatus.sunstatus; String write = widget.data.settings["Time mode"] == "24 hour" ? OMConvertTime( From 855419f43eea98a6fefdc406be3d191549aa5ddb Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 24 Aug 2024 14:29:53 +0200 Subject: [PATCH 102/129] updated drawer design a bit --- lib/donation_page.dart | 27 ++++++++++++--------------- lib/settings_page.dart | 33 ++++++++++++++++----------------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/lib/donation_page.dart b/lib/donation_page.dart index c581a27..30b774e 100644 --- a/lib/donation_page.dart +++ b/lib/donation_page.dart @@ -89,22 +89,19 @@ class _DonationPageState extends State { Padding( padding: const EdgeInsets.only(top: 40), - child: Center( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 0, - padding: const EdgeInsets.all(15), - backgroundColor: surface, - side: BorderSide(width: 2, color: primary), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12)), - ), - onPressed: () async { - await _launchUrl('https://www.patreon.com/MarotiDevel'); - }, - child: comfortatext(translation('Support on Patreon', settings["Language"]), - 18, settings, color: primary, weight: FontWeight.w600), + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 0, + padding: const EdgeInsets.all(14), + backgroundColor: primary, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), ), + onPressed: () async { + await _launchUrl('https://www.patreon.com/MarotiDevel'); + }, + child: comfortatext(translation('Support on Patreon', settings["Language"]), + 18, settings, color: surface, weight: FontWeight.w600), ), ), ], diff --git a/lib/settings_page.dart b/lib/settings_page.dart index b137f52..07d905f 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -814,27 +814,26 @@ class MyDrawer extends StatelessWidget { child: ListView( padding: EdgeInsets.zero, children: [ - DrawerHeader( + Container( + height: 240, decoration: BoxDecoration( color: primary, ), - child: Column( - children: [ - Align( - alignment: Alignment.center, - child: comfortatext('Overmorrow', 30, settings, color: surface) - ), - Align( - alignment: Alignment.centerRight, - child: comfortatext('Weather', 30, settings, color: surface) - ), - ], + child: Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: comfortatext('OVRMRW', 40, settings, color: surface, weight: FontWeight.w300), + ) ), ), + const SizedBox( + height: 15, + ), ListTile( - title: comfortatext(translation('Settings', settings["Language"]), 25, + title: comfortatext(translation('Settings', settings["Language"]), 24, settings, color: onSurface), - leading: Icon(Icons.settings, color: primary,), + leading: Icon(Icons.settings_outlined, color: primary, size: 24,), onTap: () { HapticFeedback.selectionClick(); Navigator.push( @@ -845,7 +844,7 @@ class MyDrawer extends StatelessWidget { }, ), ListTile( - title: comfortatext(translation('About', settings["Language"]), 25, + title: comfortatext(translation('About', settings["Language"]), 24, settings, color: onSurface), leading: Icon(Icons.info_outline, color: primary,), onTap: () { @@ -858,9 +857,9 @@ class MyDrawer extends StatelessWidget { }, ), ListTile( - title: comfortatext(translation('Donate', settings["Language"]), 25, + title: comfortatext(translation('Donate', settings["Language"]), 24, settings, color: onSurface), - leading: Icon(Icons.favorite_border, color: primary,), + leading: Icon(Icons.favorite_outline_sharp, color: primary,), onTap: () { HapticFeedback.selectionClick(); Navigator.push( From f6bc27331a418c0a7f406069e792d0a3da7ab7a1 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 24 Aug 2024 21:09:33 +0200 Subject: [PATCH 103/129] started working on new settings page --- lib/settings_page.dart | 17 ++++----- lib/settings_screens.dart | 78 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 lib/settings_screens.dart diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 07d905f..861b8d4 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -22,6 +22,7 @@ import 'package:flutter/services.dart'; import 'package:geolocator/geolocator.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/donation_page.dart'; +import 'package:overmorrow/settings_screens.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'decoders/decode_wapi.dart'; import 'decoders/extra_info.dart'; @@ -565,25 +566,22 @@ Widget SettingsMain(Color primary, Map? settings, Function updat Function goBack, Color back, Image image, context, colors, allColors) { return Material( - color: colors[1], + color: colors[0], child: CustomScrollView( slivers: [ SliverAppBar.large( leading: - IconButton(icon: Icon(Icons.arrow_back, color: colors[11],), onPressed: () { + IconButton(icon: Icon(Icons.arrow_back, color: colors[0],), onPressed: () { HapticFeedback.selectionClick(); goBack(); }), - title: comfortatext(translation('Settings', settings!["Language"]!), 30, settings, color: colors[11]), - backgroundColor: colors[6], + title: comfortatext(translation('Settings', settings!["Language"]!), 30, settings, color: colors[0]), + backgroundColor: colors[1], pinned: false, ), // Just some content big enough to have something to scroll. SliverToBoxAdapter( - child: Container( - color: colors[6], - child: settingsMain(settings, updatePage, image, colors, allColors), - ), + child: NewSettings(settings, updatePage, image, colors, allColors), ), ], ), @@ -789,6 +787,7 @@ Widget settingsMain(Map settings, Function updatePage, Image ima ); } + class MyDrawer extends StatelessWidget { final backupprimary; @@ -822,7 +821,7 @@ class MyDrawer extends StatelessWidget { child: Align( alignment: Alignment.bottomLeft, child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(15.0), child: comfortatext('OVRMRW', 40, settings, color: surface, weight: FontWeight.w300), ) ), diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart new file mode 100644 index 0000000..a118a65 --- /dev/null +++ b/lib/settings_screens.dart @@ -0,0 +1,78 @@ +/* +Copyright (C) <2024> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +import 'package:flutter/material.dart'; +import 'package:overmorrow/ui_helper.dart'; + +Widget settingEntry(String title, String desc, Color highlight, Color primary, Color onSurface, + IconData icon, settings) { + return Padding( + padding: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: highlight, + ), + padding: EdgeInsets.all(23), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(right: 18), + child: Icon(icon, color: primary, size: 24,), + ), + Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + comfortatext(title, 21, settings, color: onSurface), + comfortatext(desc, 16, settings, color: onSurface) + ], + ) + ], + ) + ), + ); +} + +Widget NewSettings(Map settings, Function updatePage, Image image, List colors, + allColors) { + + Color containerLow = colors[6]; + Color onSurface = colors[4]; + Color primary = colors[1]; + Color primaryLight = colors[2]; + Color surface = colors[0]; + + return Padding( + padding: const EdgeInsets.only(top: 20, bottom: 20), + child: Column( + children: [ + settingEntry("Appearance", "color theme, image source", containerLow, primary, onSurface, + Icons.palette_outlined, settings), + settingEntry("General", "time mode, font size", containerLow, primary, onSurface, + Icons.settings_applications, settings), + settingEntry("Language", "the language used", containerLow, primary, onSurface, + Icons.language, settings), + settingEntry("Units", "the units used in the app", containerLow, primary, onSurface, + Icons.pie_chart_outline, settings), + settingEntry("Layout", "widget order, customization", containerLow, primary, onSurface, + Icons.grid_view, settings), + ], + ), + ); +} \ No newline at end of file From c2f2de50d8f5a7dc541667c1aa627b687ad6e760 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sat, 24 Aug 2024 21:33:17 +0200 Subject: [PATCH 104/129] started working on new appearance page --- lib/settings_page.dart | 2 +- lib/settings_screens.dart | 187 +++++++++++++++++++++++++++++++------- 2 files changed, 154 insertions(+), 35 deletions(-) diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 861b8d4..9927879 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -581,7 +581,7 @@ Widget SettingsMain(Color primary, Map? settings, Function updat ), // Just some content big enough to have something to scroll. SliverToBoxAdapter( - child: NewSettings(settings, updatePage, image, colors, allColors), + child: NewSettings(settings, updatePage, image, colors, allColors, context), ), ], ), diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index a118a65..d8a559c 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -17,62 +17,181 @@ along with this program. If not, see . */ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:overmorrow/settings_page.dart'; import 'package:overmorrow/ui_helper.dart'; -Widget settingEntry(String title, String desc, Color highlight, Color primary, Color onSurface, - IconData icon, settings) { +import 'decoders/decode_wapi.dart'; +import 'main_ui.dart'; + +Widget settingEntry(String title, String desc, Color highlight, Color primary, Color onSurface, Color surface, + IconData icon, settings, Widget pushTo, context) { return Padding( padding: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: highlight, + child: GestureDetector( + onTap: () { + HapticFeedback.selectionClick(); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => pushTo) + ); + }, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: highlight, + ), + padding: EdgeInsets.all(23), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(right: 18), + child: Icon(icon, color: primary, size: 24,), + ), + Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + comfortatext(title, 21, settings, color: onSurface), + comfortatext(desc, 16, settings, color: onSurface) + ], + ) + ], + ) ), - padding: EdgeInsets.all(23), - child: Row( - children: [ - Padding( - padding: const EdgeInsets.only(right: 18), - child: Icon(icon, color: primary, size: 24,), - ), - Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - comfortatext(title, 21, settings, color: onSurface), - comfortatext(desc, 16, settings, color: onSurface) - ], - ) - ], - ) ), ); } Widget NewSettings(Map settings, Function updatePage, Image image, List colors, - allColors) { + allColors, context) { Color containerLow = colors[6]; Color onSurface = colors[4]; Color primary = colors[1]; Color primaryLight = colors[2]; Color surface = colors[0]; + Color colorpop = colors[12]; + Color desc_color = colors[13]; + return Padding( padding: const EdgeInsets.only(top: 20, bottom: 20), child: Column( children: [ - settingEntry("Appearance", "color theme, image source", containerLow, primary, onSurface, - Icons.palette_outlined, settings), - settingEntry("General", "time mode, font size", containerLow, primary, onSurface, - Icons.settings_applications, settings), - settingEntry("Language", "the language used", containerLow, primary, onSurface, - Icons.language, settings), - settingEntry("Units", "the units used in the app", containerLow, primary, onSurface, - Icons.pie_chart_outline, settings), - settingEntry("Layout", "widget order, customization", containerLow, primary, onSurface, - Icons.grid_view, settings), + settingEntry("Appearance", "color theme, image source", containerLow, primary, onSurface, surface, + Icons.palette_outlined, settings, + AppearancePage(primary: primary, settings: settings, surface: surface, + onSurface: onSurface, highlight: containerLow, image: image, colorPop: colorpop, descColor: desc_color,), + context, + ), + settingEntry("General", "time mode, font size", containerLow, primary, onSurface, surface, + Icons.settings_applications, settings, Container(), context), + settingEntry("Language", "the language used", containerLow, primary, onSurface, surface, + Icons.language, settings, Container(), context), + settingEntry("Units", "the units used in the app", containerLow, primary, onSurface, surface, + Icons.pie_chart_outline, settings, Container(), context), + settingEntry("Layout", "widget order, customization", containerLow, primary, onSurface, surface, + Icons.grid_view, settings, Container(), context), ], ), ); +} + +class AppearancePage extends StatefulWidget { + final Color primary; + final Color surface; + final settings; + final onSurface; + final highlight; + final colorPop; + final descColor; + final image; + + const AppearancePage({Key? key, required this.primary, required this.settings, required this.surface, required this.onSurface, + required this.highlight, required this.descColor, required this.colorPop, required this.image}) + : super(key: key); + + @override + _AppearancePageState createState() => + _AppearancePageState(primary: primary, settings: settings, surface: surface, highlight: highlight, onSurface: onSurface, + colorPop: colorPop, image: image, descColor: descColor); +} + +class _AppearancePageState extends State { + final primary; + final settings; + final surface; + final onSurface; + final highlight; + final colorPop; + final descColor; + final image; + + _AppearancePageState({required this.primary, required this.settings, required this.surface, required this.onSurface, + required this.highlight, required this.colorPop, required this.descColor, required this.image}); + + void goBack() { + HapticFeedback.selectionClick(); + Navigator.pop(context); + } + + @override + Widget build(BuildContext context) { + return Material( + color: surface, + child: CustomScrollView( + slivers: [ + SliverAppBar.large( + leading: + IconButton(icon: Icon(Icons.arrow_back, color: surface,), + onPressed: () { + goBack(); + }), + title: comfortatext( + "Appearance", 30, settings, + color: surface), + backgroundColor: primary, + pinned: false, + ), + SliverToBoxAdapter( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(top: 40, bottom: 10), + child: Center( + child: SizedBox( + width: 270, + height: 320, + child: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: Stack( + children: [ + ParrallaxBackground(image: image, color: surface), + Padding( + padding: const EdgeInsets.only(left: 10, bottom: 15), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + comfortatext("${unit_coversion(29, settings["Temperature"]!).toInt()}°", 50, settings, color: colorPop), + comfortatext(translation("Clear Sky", settings["Language"]!), 25, + settings, color: descColor) + ], + ), + ), + ], + ), + ), + ), + ), + ) + ], + ), + ), + ], + ), + ); + } } \ No newline at end of file From f2df07d147ac562fdc8c0840ec3865b1d74c7721 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sun, 25 Aug 2024 13:24:02 +0200 Subject: [PATCH 105/129] added the appearance hcanging buttons but still problem with refresh --- lib/settings_screens.dart | 129 +++++++++++++++++++++++++++++++------- 1 file changed, 108 insertions(+), 21 deletions(-) diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index d8a559c..b7a374d 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -81,8 +81,9 @@ Widget NewSettings(Map settings, Function updatePage, Image imag children: [ settingEntry("Appearance", "color theme, image source", containerLow, primary, onSurface, surface, Icons.palette_outlined, settings, - AppearancePage(primary: primary, settings: settings, surface: surface, - onSurface: onSurface, highlight: containerLow, image: image, colorPop: colorpop, descColor: desc_color,), + AppearancePage(primary: primary, settings: settings, surface: surface, onSurface: onSurface, + highlight: containerLow, image: image, colorPop: colorpop, descColor: desc_color, + updatePage: updatePage), context, ), settingEntry("General", "time mode, font size", containerLow, primary, onSurface, surface, @@ -98,6 +99,34 @@ Widget NewSettings(Map settings, Function updatePage, Image imag ); } +Widget ColorThemeButton(String name, IconData icon, Color highlight, Color primary, settings, updatePage) { + bool selected = settings["Color mode"] == name; + return Padding( + padding: const EdgeInsets.all(3.0), + child: GestureDetector( + onTap: () { + updatePage("Color mode", name); + }, + child: Container( + padding: const EdgeInsets.only(top: 22, bottom: 22, left: 8, right: 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + color: selected ? primary : highlight, + ), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(right: 4), + child: Icon(icon, size: 17, color: selected ? highlight : primary,), + ), + comfortatext(name, 17, settings, color: selected ? highlight : primary, weight: FontWeight.w600) + ], + ), + ), + ), + ); +} + class AppearancePage extends StatefulWidget { final Color primary; final Color surface; @@ -107,15 +136,16 @@ class AppearancePage extends StatefulWidget { final colorPop; final descColor; final image; + final updatePage; const AppearancePage({Key? key, required this.primary, required this.settings, required this.surface, required this.onSurface, - required this.highlight, required this.descColor, required this.colorPop, required this.image}) + required this.highlight, required this.descColor, required this.colorPop, required this.image, required this.updatePage}) : super(key: key); @override _AppearancePageState createState() => _AppearancePageState(primary: primary, settings: settings, surface: surface, highlight: highlight, onSurface: onSurface, - colorPop: colorPop, image: image, descColor: descColor); + colorPop: colorPop, image: image, descColor: descColor, updatePage: updatePage); } class _AppearancePageState extends State { @@ -127,9 +157,10 @@ class _AppearancePageState extends State { final colorPop; final descColor; final image; + final updatePage; _AppearancePageState({required this.primary, required this.settings, required this.surface, required this.onSurface, - required this.highlight, required this.colorPop, required this.descColor, required this.image}); + required this.highlight, required this.colorPop, required this.descColor, required this.image, required this.updatePage}); void goBack() { HapticFeedback.selectionClick(); @@ -159,34 +190,90 @@ class _AppearancePageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: const EdgeInsets.only(top: 40, bottom: 10), + padding: const EdgeInsets.only(top: 50, bottom: 10), child: Center( - child: SizedBox( - width: 270, - height: 320, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + color: highlight + ), + width: 240, + height: 330, child: ClipRRect( - borderRadius: BorderRadius.circular(20), - child: Stack( + borderRadius: BorderRadius.circular(18), + child: Column( children: [ - ParrallaxBackground(image: image, color: surface), - Padding( - padding: const EdgeInsets.only(left: 10, bottom: 15), - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.start, + SizedBox( + height: 220, + child: Stack( children: [ - comfortatext("${unit_coversion(29, settings["Temperature"]!).toInt()}°", 50, settings, color: colorPop), - comfortatext(translation("Clear Sky", settings["Language"]!), 25, - settings, color: descColor) + ParrallaxBackground(image: image, color: surface), + Padding( + padding: const EdgeInsets.only(left: 10, bottom: 15), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + comfortatext("${unit_coversion(29, settings["Temperature"]!).toInt()}°", 42, + settings, color: colorPop, weight: FontWeight.w300), + comfortatext(translation("Clear Sky", settings["Language"]!), 22, + settings, color: descColor, weight: FontWeight.w500) + ], + ), + ), ], ), ), + Padding( + padding: const EdgeInsets.only(top: 10, right: 4, left: 4), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: List.generate(4, (index) { + return Expanded( + child: Padding( + padding: const EdgeInsets.all(4.0), + child: AspectRatio( + aspectRatio: 1, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(40), + border: Border.all(color: primary, width: 2), + ), + ), + ), + ), + ); + }), + ) + ), ], ), ), ), ), - ) + ), + Padding( + padding: const EdgeInsets.only(top: 15), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ColorThemeButton("light", Icons.light_mode_outlined, highlight, primary, settings, updatePage), + ColorThemeButton("dark", Icons.dark_mode_outlined, highlight, primary, settings, updatePage), + ColorThemeButton("automatic", Icons.brightness_6_rounded, highlight, primary, settings, updatePage), + ] + ) + ), + Padding( + padding: const EdgeInsets.only(top: 4), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ColorThemeButton("original", Icons.circle_outlined, highlight, primary, settings, updatePage), + ColorThemeButton("colorful", Icons.circle, highlight, primary, settings, updatePage), + ColorThemeButton("monochrome", Icons.invert_colors_on_outlined, highlight, primary, settings, updatePage), + ] + ) + ), ], ), ), From 992e5f9dcfb1ee8541636cf388d0278fc2fad8bd Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 26 Aug 2024 15:37:05 +0200 Subject: [PATCH 106/129] finally solved update problem with multiple screened settings --- lib/settings_screens.dart | 87 +++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 31 deletions(-) diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index b7a374d..ee80a24 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -17,6 +17,7 @@ along with this program. If not, see . */ import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:overmorrow/ui_helper.dart'; @@ -25,7 +26,7 @@ import 'decoders/decode_wapi.dart'; import 'main_ui.dart'; Widget settingEntry(String title, String desc, Color highlight, Color primary, Color onSurface, Color surface, - IconData icon, settings, Widget pushTo, context) { + IconData icon, settings, Widget pushTo, context, updatePage) { return Padding( padding: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5), child: GestureDetector( @@ -74,26 +75,23 @@ Widget NewSettings(Map settings, Function updatePage, Image imag Color colorpop = colors[12]; Color desc_color = colors[13]; - return Padding( padding: const EdgeInsets.only(top: 20, bottom: 20), child: Column( children: [ settingEntry("Appearance", "color theme, image source", containerLow, primary, onSurface, surface, Icons.palette_outlined, settings, - AppearancePage(primary: primary, settings: settings, surface: surface, onSurface: onSurface, - highlight: containerLow, image: image, colorPop: colorpop, descColor: desc_color, - updatePage: updatePage), - context, + AppearancePage(settings: settings, image: image, allColors: allColors, updateMainPage: updatePage,), + context, updatePage ), settingEntry("General", "time mode, font size", containerLow, primary, onSurface, surface, - Icons.settings_applications, settings, Container(), context), + Icons.settings_applications, settings, Container(), context, updatePage), settingEntry("Language", "the language used", containerLow, primary, onSurface, surface, - Icons.language, settings, Container(), context), + Icons.language, settings, Container(), context, updatePage), settingEntry("Units", "the units used in the app", containerLow, primary, onSurface, surface, - Icons.pie_chart_outline, settings, Container(), context), + Icons.pie_chart_outline, settings, Container(), context, updatePage), settingEntry("Layout", "widget order, customization", containerLow, primary, onSurface, surface, - Icons.grid_view, settings, Container(), context), + Icons.grid_view, settings, Container(), context, updatePage), ], ), ); @@ -105,6 +103,7 @@ Widget ColorThemeButton(String name, IconData icon, Color highlight, Color prima padding: const EdgeInsets.all(3.0), child: GestureDetector( onTap: () { + HapticFeedback.mediumImpact(); updatePage("Color mode", name); }, child: Container( @@ -128,39 +127,45 @@ Widget ColorThemeButton(String name, IconData icon, Color highlight, Color prima } class AppearancePage extends StatefulWidget { - final Color primary; - final Color surface; final settings; - final onSurface; - final highlight; - final colorPop; - final descColor; final image; - final updatePage; + final allColors; + final updateMainPage; - const AppearancePage({Key? key, required this.primary, required this.settings, required this.surface, required this.onSurface, - required this.highlight, required this.descColor, required this.colorPop, required this.image, required this.updatePage}) + const AppearancePage({Key? key, required this.allColors, required this.settings, + required this.image, required this.updateMainPage}) : super(key: key); @override _AppearancePageState createState() => - _AppearancePageState(primary: primary, settings: settings, surface: surface, highlight: highlight, onSurface: onSurface, - colorPop: colorPop, image: image, descColor: descColor, updatePage: updatePage); + _AppearancePageState(image: image, settings: settings, allColors: allColors, + updateMainPage: updateMainPage); } class _AppearancePageState extends State { - final primary; - final settings; - final surface; - final onSurface; - final highlight; - final colorPop; - final descColor; + final image; - final updatePage; + final settings; + final allColors; + final updateMainPage; + + _AppearancePageState({required this.image, required this.settings, required this.allColors, required this.updateMainPage}); + + Map copySettings = {}; + + @override + void initState() { + super.initState(); + + copySettings = settings; + } - _AppearancePageState({required this.primary, required this.settings, required this.surface, required this.onSurface, - required this.highlight, required this.colorPop, required this.descColor, required this.image, required this.updatePage}); + void updatePage(String name, String to) { + setState(() { + updateMainPage(name, to); + copySettings[name] = to; + }); + } void goBack() { HapticFeedback.selectionClick(); @@ -169,6 +174,26 @@ class _AppearancePageState extends State { @override Widget build(BuildContext context) { + + String x = "light"; + if (copySettings["Color mode"] == "automatic") { + var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + x = brightness == Brightness.dark ? "dark" : "light"; + } + else { + x = copySettings["Color mode"] ?? "light"; + } + + final colors = allColors[["original", "colorful", "monochrome", "light", "dark"] + .indexOf(x)]; + + Color highlight = colors[7]; + Color onSurface = colors[4]; + Color primary = colors[1]; + Color surface = colors[0]; + Color colorPop = colors[12]; + Color descColor = colors[13]; + return Material( color: surface, child: CustomScrollView( From 0f8c9dcec956ca903322603f2ab9a4ad318c3f75 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 26 Aug 2024 15:54:16 +0200 Subject: [PATCH 107/129] auto is now the default color option --- lib/decoders/extra_info.dart | 2 +- lib/settings_page.dart | 20 ++++++++++++---- lib/settings_screens.dart | 46 ++++++++++++++++++++++++++---------- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 3b6d2b2..5d52855 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -148,7 +148,7 @@ Future MaterialYouColor(String theme) async { final ColorScheme palette = ColorScheme.fromSeed( seedColor: mainColor, brightness: theme == 'light' ? Brightness.light : Brightness.dark, - dynamicSchemeVariant: theme == 'original' || theme == 'monochrome' ? DynamicSchemeVariant.tonalSpot : + dynamicSchemeVariant: theme == 'original' || theme == 'mono' ? DynamicSchemeVariant.tonalSpot : DynamicSchemeVariant.tonalSpot, ); diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 9927879..fd9eede 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -18,6 +18,7 @@ along with this program. If not, see . import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:geolocator/geolocator.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -43,7 +44,7 @@ Map> settingSwitches = { 'Time mode': ['12 hour', '24 hour'], 'Font size': ['normal', 'small', 'very small', 'big'], - 'Color mode' : ['original', 'colorful', 'monochrome', 'light', 'dark'], + 'Color mode' : ['auto', 'original', 'colorful', 'mono', 'light', 'dark'], 'Color source' : ['image', 'wallpaper'], 'Image source' : ['network', 'asset'], @@ -60,6 +61,11 @@ String translation(String text, String language) { List getColors(primary, back, settings, dif, {force = "-1"}) { String x = force == "-1" ? settings["Color mode"] : force; + if (x == "auto") { + var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + x = brightness == Brightness.dark ? "dark" : "light"; + } + //surface //primary @@ -95,7 +101,7 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { WHITE ]; - if (x == "monochrome") { + if (x == "mono") { colors = [ //default colorful option primary, WHITE, @@ -169,6 +175,10 @@ List getColors(primary, back, settings, dif, {force = "-1"}) { List getNetworkColors(List palette, settings, {force = "-1"}) { String x = force == "-1" ? settings["Color mode"] : force; + if (x == "auto") { + var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + x = brightness == Brightness.dark ? "dark" : "light"; + } //surface //primary @@ -200,7 +210,7 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { palette[1], palette[2], ]; - if (x == "monochrome") { + if (x == "mono") { colors = [ palette[0].onPrimaryFixedVariant, WHITE, @@ -310,7 +320,7 @@ Future> getTotalColor(settings, primary, back, image) async { if (settings["Image source"] == 'network' || settings["Color source"] == 'wallpaper') { allColor.add(getNetworkColors(darkPalette, settings, force: "original")); allColor.add(getNetworkColors(darkPalette, settings, force: "colorful")); - allColor.add(getNetworkColors(darkPalette, settings, force: "monochrome")); + allColor.add(getNetworkColors(darkPalette, settings, force: "mono")); allColor.add(getNetworkColors(lightPalette, settings, force: "light")); allColor.add(getNetworkColors(darkPalette, settings, force: "dark")); } @@ -718,7 +728,7 @@ Widget settingsMain(Map settings, Function updatePage, Image ima children: [ ColorCircle("original", allColors[0][1], allColors[0][0], settings, updatePage, w: 4, tap: 1), ColorCircle("colorful", allColors[1][1], allColors[1][0], settings, updatePage, w: 4, tap: 1), - ColorCircle("monochrome", allColors[2][1], allColors[2][0], settings, updatePage, w: 4, tap: 1), + ColorCircle("mono", allColors[2][1], allColors[2][0], settings, updatePage, w: 4, tap: 1), ColorCircle("light", allColors[3][1], allColors[3][0], settings, updatePage, w: 4, tap: 1), ColorCircle("dark", allColors[4][1], allColors[4][0], settings, updatePage, w: 4, tap: 1), ] diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index ee80a24..06ca9fb 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -70,10 +70,7 @@ Widget NewSettings(Map settings, Function updatePage, Image imag Color containerLow = colors[6]; Color onSurface = colors[4]; Color primary = colors[1]; - Color primaryLight = colors[2]; Color surface = colors[0]; - Color colorpop = colors[12]; - Color desc_color = colors[13]; return Padding( padding: const EdgeInsets.only(top: 20, bottom: 20), @@ -107,7 +104,7 @@ Widget ColorThemeButton(String name, IconData icon, Color highlight, Color prima updatePage("Color mode", name); }, child: Container( - padding: const EdgeInsets.only(top: 22, bottom: 22, left: 8, right: 6), + padding: const EdgeInsets.only(top: 22, bottom: 22, left: 10, right: 10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(18), color: selected ? primary : highlight, @@ -116,9 +113,9 @@ Widget ColorThemeButton(String name, IconData icon, Color highlight, Color prima children: [ Padding( padding: const EdgeInsets.only(right: 4), - child: Icon(icon, size: 17, color: selected ? highlight : primary,), + child: Icon(icon, size: 18, color: selected ? highlight : primary,), ), - comfortatext(name, 17, settings, color: selected ? highlight : primary, weight: FontWeight.w600) + comfortatext(name, 18, settings, color: selected ? highlight : primary) ], ), ), @@ -176,7 +173,7 @@ class _AppearancePageState extends State { Widget build(BuildContext context) { String x = "light"; - if (copySettings["Color mode"] == "automatic") { + if (copySettings["Color mode"] == "auto") { var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; x = brightness == Brightness.dark ? "dark" : "light"; } @@ -184,12 +181,12 @@ class _AppearancePageState extends State { x = copySettings["Color mode"] ?? "light"; } - final colors = allColors[["original", "colorful", "monochrome", "light", "dark"] + final colors = allColors[["original", "colorful", "mono", "light", "dark"] .indexOf(x)]; Color highlight = colors[7]; - Color onSurface = colors[4]; Color primary = colors[1]; + Color onSurface = colors[4]; Color surface = colors[0]; Color colorPop = colors[12]; Color descColor = colors[13]; @@ -223,10 +220,11 @@ class _AppearancePageState extends State { color: highlight ), width: 240, - height: 330, + height: 350, child: ClipRRect( borderRadius: BorderRadius.circular(18), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: 220, @@ -250,7 +248,7 @@ class _AppearancePageState extends State { ), ), Padding( - padding: const EdgeInsets.only(top: 10, right: 4, left: 4), + padding: const EdgeInsets.only(top: 10, right: 4, left: 4, bottom: 15), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: List.generate(4, (index) { @@ -271,6 +269,28 @@ class _AppearancePageState extends State { }), ) ), + Padding( + padding: const EdgeInsets.only(left: 10), + child: Container( + width: 150, + height: 4, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: onSurface, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 10, top: 8), + child: Container( + width: 70, + height: 4, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: primary, + ), + ), + ) ], ), ), @@ -284,7 +304,7 @@ class _AppearancePageState extends State { children: [ ColorThemeButton("light", Icons.light_mode_outlined, highlight, primary, settings, updatePage), ColorThemeButton("dark", Icons.dark_mode_outlined, highlight, primary, settings, updatePage), - ColorThemeButton("automatic", Icons.brightness_6_rounded, highlight, primary, settings, updatePage), + ColorThemeButton("auto", Icons.brightness_6_rounded, highlight, primary, settings, updatePage), ] ) ), @@ -295,7 +315,7 @@ class _AppearancePageState extends State { children: [ ColorThemeButton("original", Icons.circle_outlined, highlight, primary, settings, updatePage), ColorThemeButton("colorful", Icons.circle, highlight, primary, settings, updatePage), - ColorThemeButton("monochrome", Icons.invert_colors_on_outlined, highlight, primary, settings, updatePage), + ColorThemeButton("mono", Icons.invert_colors_on_outlined, highlight, primary, settings, updatePage), ] ) ), From 9a0b70bdfee05a096dd439af2eef14cd6c776227 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 26 Aug 2024 16:09:56 +0200 Subject: [PATCH 108/129] added units page, removed pressure because it wasn't used at all --- lib/languages.dart | 14 ----- lib/settings_page.dart | 5 +- lib/settings_screens.dart | 119 +++++++++++++++++++++++++++++++++++--- 3 files changed, 111 insertions(+), 27 deletions(-) diff --git a/lib/languages.dart b/lib/languages.dart index f7b2bdb..d43a372 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -256,20 +256,6 @@ Map> mainTranslate = { 'Opady', 'Βροχόπτωση' ], - 'Pressure': [ - 'Pressure', - 'Nyomás', - 'Presión', - 'Pression', - 'Druck', - 'Pressione', - 'Pressão', - 'Давление', - '压力', - '圧力', - 'Ciśnienie', - 'Πίεση' - ], 'Favorites': [ 'Favorites', 'Kedvencek', diff --git a/lib/settings_page.dart b/lib/settings_page.dart index fd9eede..ffb617e 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -40,7 +40,6 @@ Map> settingSwitches = { 'Temperature': ['˚C', '˚F'], 'Precipitation': ['mm', 'in'], 'Wind': ['m/s', 'kph', 'mph', 'kn'], - 'Pressure' : ['mmHg', 'inHg', 'mb', 'hPa'], 'Time mode': ['12 hour', '24 hour'], 'Font size': ['normal', 'small', 'very small', 'big'], @@ -440,7 +439,7 @@ Widget dropdown(Color bgcolor, String name, Function updatePage, String unit, se Widget settingEntry(icon, text, settings, highlight, updatePage, textcolor, primaryLight, primary) { return Padding( - padding: const EdgeInsets.only(top: 3, bottom: 3), + padding: const EdgeInsets.only(top: 3, bottom: 3, left: 25, right: 25), child: Row( children: [ Padding( @@ -781,8 +780,6 @@ Widget settingsMain(Map settings, Function updatePage, Image ima onSurface, primaryLight, primary), settingEntry(CupertinoIcons.wind, "Wind", settings, onSurface, updatePage, onSurface, primaryLight, primary), - settingEntry(CupertinoIcons.timelapse, "Pressure", settings, onSurface, updatePage, - onSurface, primaryLight, primary), const SizedBox( height: 40, diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index 06ca9fb..950f508 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -16,6 +16,7 @@ along with this program. If not, see . */ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; @@ -25,7 +26,7 @@ import 'package:overmorrow/ui_helper.dart'; import 'decoders/decode_wapi.dart'; import 'main_ui.dart'; -Widget settingEntry(String title, String desc, Color highlight, Color primary, Color onSurface, Color surface, +Widget mainSettingEntry(String title, String desc, Color highlight, Color primary, Color onSurface, Color surface, IconData icon, settings, Widget pushTo, context, updatePage) { return Padding( padding: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5), @@ -76,18 +77,20 @@ Widget NewSettings(Map settings, Function updatePage, Image imag padding: const EdgeInsets.only(top: 20, bottom: 20), child: Column( children: [ - settingEntry("Appearance", "color theme, image source", containerLow, primary, onSurface, surface, + mainSettingEntry("Appearance", "color theme, image source", containerLow, primary, onSurface, surface, Icons.palette_outlined, settings, AppearancePage(settings: settings, image: image, allColors: allColors, updateMainPage: updatePage,), context, updatePage ), - settingEntry("General", "time mode, font size", containerLow, primary, onSurface, surface, + mainSettingEntry("General", "time mode, font size", containerLow, primary, onSurface, surface, Icons.settings_applications, settings, Container(), context, updatePage), - settingEntry("Language", "the language used", containerLow, primary, onSurface, surface, + mainSettingEntry("Language", "the language used", containerLow, primary, onSurface, surface, Icons.language, settings, Container(), context, updatePage), - settingEntry("Units", "the units used in the app", containerLow, primary, onSurface, surface, - Icons.pie_chart_outline, settings, Container(), context, updatePage), - settingEntry("Layout", "widget order, customization", containerLow, primary, onSurface, surface, + mainSettingEntry("Units", "the units used in the app", containerLow, primary, onSurface, surface, + Icons.pie_chart_outline, settings, + UnitsPage(colors: colors, settings: settings, image: image, updateMainPage: updatePage), + context, updatePage), + mainSettingEntry("Layout", "widget order, customization", containerLow, primary, onSurface, surface, Icons.grid_view, settings, Container(), context, updatePage), ], ), @@ -185,6 +188,7 @@ class _AppearancePageState extends State { .indexOf(x)]; Color highlight = colors[7]; + Color primaryLight = colors[2]; Color primary = colors[1]; Color onSurface = colors[4]; Color surface = colors[0]; @@ -287,7 +291,7 @@ class _AppearancePageState extends State { height: 4, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: primary, + color: primaryLight, ), ), ) @@ -309,7 +313,7 @@ class _AppearancePageState extends State { ) ), Padding( - padding: const EdgeInsets.only(top: 4), + padding: const EdgeInsets.only(top: 4, bottom: 30), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -319,6 +323,11 @@ class _AppearancePageState extends State { ] ) ), + settingEntry(Icons.invert_colors_on, "Color source", settings, highlight, updatePage, + onSurface, primaryLight, primary), + settingEntry(Icons.landscape_outlined, "Image source", settings, highlight, updatePage, + onSurface, primaryLight, primary), + const SizedBox(height: 70,), ], ), ), @@ -326,4 +335,96 @@ class _AppearancePageState extends State { ), ); } +} + +class UnitsPage extends StatefulWidget { + final settings; + final image; + final colors; + final updateMainPage; + + const UnitsPage({Key? key, required this.colors, required this.settings, + required this.image, required this.updateMainPage}) + : super(key: key); + + @override + _UnitsPageState createState() => + _UnitsPageState(image: image, settings: settings, colors: colors, + updateMainPage: updateMainPage); +} + +class _UnitsPageState extends State { + + final image; + final settings; + final colors; + final updateMainPage; + + _UnitsPageState({required this.image, required this.settings, required this.colors, required this.updateMainPage}); + + Map copySettings = {}; + + @override + void initState() { + super.initState(); + + copySettings = settings; + } + + void updatePage(String name, String to) { + setState(() { + updateMainPage(name, to); + copySettings[name] = to; + }); + } + + void goBack() { + HapticFeedback.selectionClick(); + Navigator.pop(context); + } + + @override + Widget build(BuildContext context) { + + Color highlight = colors[7]; + Color primaryLight = colors[2]; + Color primary = colors[1]; + Color onSurface = colors[4]; + Color surface = colors[0]; + + return Material( + color: surface, + child: CustomScrollView( + slivers: [ + SliverAppBar.large( + leading: + IconButton(icon: Icon(Icons.arrow_back, color: surface,), + onPressed: () { + goBack(); + }), + title: comfortatext( + "Units", 30, settings, + color: surface), + backgroundColor: primary, + pinned: false, + ), + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.only(top: 30, bottom: 60), + child: Column( + children: [ + settingEntry(CupertinoIcons.thermometer, "Temperature", settings, onSurface, updatePage, + onSurface, primaryLight, primary), + settingEntry(CupertinoIcons.drop_fill, "Precipitation", settings, onSurface, updatePage, + onSurface, primaryLight, primary), + settingEntry(CupertinoIcons.wind, "Wind", settings, onSurface, updatePage, + onSurface, primaryLight, primary), + ], + ), + ), + ), + ], + ), + ); + } } \ No newline at end of file From bc730f1fa18263eb3d6abb20f1f66bc5f53c40fa Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Mon, 26 Aug 2024 16:15:24 +0200 Subject: [PATCH 109/129] minor tweaks to the dropdown --- lib/settings_page.dart | 2 +- lib/settings_screens.dart | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/settings_page.dart b/lib/settings_page.dart index ffb617e..dc542a8 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -457,7 +457,7 @@ Widget settingEntry(icon, text, settings, highlight, updatePage, textcolor, prim ), const Spacer(), dropdown( - darken(highlight), text, updatePage, settings[text]!, settings, textcolor, primaryLight + highlight, text, updatePage, settings[text]!, settings, textcolor, primaryLight ), ], ), diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index 950f508..023f5b0 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -413,11 +413,11 @@ class _UnitsPageState extends State { padding: const EdgeInsets.only(top: 30, bottom: 60), child: Column( children: [ - settingEntry(CupertinoIcons.thermometer, "Temperature", settings, onSurface, updatePage, + settingEntry(CupertinoIcons.thermometer, "Temperature", settings, highlight, updatePage, onSurface, primaryLight, primary), - settingEntry(CupertinoIcons.drop_fill, "Precipitation", settings, onSurface, updatePage, + settingEntry(CupertinoIcons.drop_fill, "Precipitation", settings, highlight, updatePage, onSurface, primaryLight, primary), - settingEntry(CupertinoIcons.wind, "Wind", settings, onSurface, updatePage, + settingEntry(CupertinoIcons.wind, "Wind", settings, highlight, updatePage, onSurface, primaryLight, primary), ], ), From b3ecc1f071720205eb6879bc454098569d448197 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 27 Aug 2024 15:50:37 +0200 Subject: [PATCH 110/129] general and language pages done --- lib/decoders/extra_info.dart | 4 +- lib/settings_page.dart | 4 +- lib/settings_screens.dart | 212 ++++++++++++++++++++++++++++++++++- 3 files changed, 212 insertions(+), 8 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 5d52855..f021e95 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -200,7 +200,7 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { print("trying"); for (int i = 1; i < 5; i++) { //LIGHT - Color newcolor = lighten2(startcolor, i / 4); + Color newcolor = lighten(startcolor, i / 4); int newdif = difFromBackColors(newcolor, dominant); if (newdif > bestDif && newdif < base + 200) { bestDif = newdif; @@ -208,7 +208,7 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { } //DARK - newcolor = darken2(startcolor, i / 4); + newcolor = darken(startcolor, i / 4); newdif = difFromBackColors(newcolor, dominant); if (newdif > bestDif && newdif < base + 200) { bestDif = newdif; diff --git a/lib/settings_page.dart b/lib/settings_page.dart index dc542a8..b513722 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -443,14 +443,14 @@ Widget settingEntry(icon, text, settings, highlight, updatePage, textcolor, prim child: Row( children: [ Padding( - padding: const EdgeInsets.only(right: 20), + padding: const EdgeInsets.only(right: 13), child: Icon(icon, color: primary), ), Expanded( flex: 10, child: comfortatext( translation(text, settings["Language"]!), - 20, + 19, settings, color: textcolor, ), diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index 023f5b0..fece953 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -83,9 +83,13 @@ Widget NewSettings(Map settings, Function updatePage, Image imag context, updatePage ), mainSettingEntry("General", "time mode, font size", containerLow, primary, onSurface, surface, - Icons.settings_applications, settings, Container(), context, updatePage), + Icons.settings_applications, settings, + GeneralSettingsPage(colors: colors, settings: settings, image: image, updateMainPage: updatePage), + context, updatePage), mainSettingEntry("Language", "the language used", containerLow, primary, onSurface, surface, - Icons.language, settings, Container(), context, updatePage), + Icons.language, settings, + LangaugePage(colors: colors, settings: settings, image: image, updateMainPage: updatePage), + context, updatePage), mainSettingEntry("Units", "the units used in the app", containerLow, primary, onSurface, surface, Icons.pie_chart_outline, settings, UnitsPage(colors: colors, settings: settings, image: image, updateMainPage: updatePage), @@ -323,7 +327,8 @@ class _AppearancePageState extends State { ] ) ), - settingEntry(Icons.invert_colors_on, "Color source", settings, highlight, updatePage, + + settingEntry(Icons.colorize_rounded, "Color source", settings, highlight, updatePage, onSurface, primaryLight, primary), settingEntry(Icons.landscape_outlined, "Image source", settings, highlight, updatePage, onSurface, primaryLight, primary), @@ -415,7 +420,7 @@ class _UnitsPageState extends State { children: [ settingEntry(CupertinoIcons.thermometer, "Temperature", settings, highlight, updatePage, onSurface, primaryLight, primary), - settingEntry(CupertinoIcons.drop_fill, "Precipitation", settings, highlight, updatePage, + settingEntry(Icons.water_drop_outlined, "Precipitation", settings, highlight, updatePage, onSurface, primaryLight, primary), settingEntry(CupertinoIcons.wind, "Wind", settings, highlight, updatePage, onSurface, primaryLight, primary), @@ -427,4 +432,203 @@ class _UnitsPageState extends State { ), ); } +} + + +class GeneralSettingsPage extends StatefulWidget { + final settings; + final image; + final colors; + final updateMainPage; + + const GeneralSettingsPage({Key? key, required this.colors, required this.settings, + required this.image, required this.updateMainPage}) + : super(key: key); + + @override + _GeneralSettingsPageState createState() => + _GeneralSettingsPageState(image: image, settings: settings, colors: colors, + updateMainPage: updateMainPage); +} + +class _GeneralSettingsPageState extends State { + + final image; + final settings; + final colors; + final updateMainPage; + + _GeneralSettingsPageState({required this.image, required this.settings, required this.colors, required this.updateMainPage}); + + Map copySettings = {}; + + @override + void initState() { + super.initState(); + + copySettings = settings; + } + + void updatePage(String name, String to) { + setState(() { + updateMainPage(name, to); + copySettings[name] = to; + }); + } + + void goBack() { + HapticFeedback.selectionClick(); + Navigator.pop(context); + } + + @override + Widget build(BuildContext context) { + + Color highlight = colors[7]; + Color primaryLight = colors[2]; + Color primary = colors[1]; + Color onSurface = colors[4]; + Color surface = colors[0]; + + return Material( + color: surface, + child: CustomScrollView( + slivers: [ + SliverAppBar.large( + leading: + IconButton(icon: Icon(Icons.arrow_back, color: surface,), + onPressed: () { + goBack(); + }), + title: comfortatext( + "General", 30, settings, + color: surface), + backgroundColor: primary, + pinned: false, + ), + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.only(top: 30, bottom: 60), + child: Column( + children: [ + settingEntry(Icons.access_time_filled_sharp, "Time mode", settings, highlight, updatePage, + onSurface, primaryLight, primary), + settingEntry(CupertinoIcons.textformat_size, "Font size", settings, highlight, updatePage, + onSurface, primaryLight, primary), + + settingEntry(Icons.manage_search_outlined, "Search provider", settings, highlight, updatePage, + onSurface, primaryLight, primary), + ], + ), + ), + ), + ], + ), + ); + } +} + +class LangaugePage extends StatefulWidget { + final settings; + final image; + final colors; + final updateMainPage; + + const LangaugePage({Key? key, required this.colors, required this.settings, + required this.image, required this.updateMainPage}) + : super(key: key); + + @override + _LangaugePageState createState() => + _LangaugePageState(image: image, settings: settings, colors: colors, + updateMainPage: updateMainPage); +} + +class _LangaugePageState extends State { + + final image; + final settings; + final colors; + final updateMainPage; + + _LangaugePageState({required this.image, required this.settings, required this.colors, required this.updateMainPage}); + + Map copySettings = {}; + + @override + void initState() { + super.initState(); + + copySettings = settings; + } + + void updatePage(String name, String to) { + setState(() { + updateMainPage(name, to); + copySettings[name] = to; + }); + } + + void goBack() { + HapticFeedback.selectionClick(); + Navigator.pop(context); + } + + @override + Widget build(BuildContext context) { + + Color primary = colors[1]; + Color onSurface = colors[4]; + Color surface = colors[0]; + + String selected = copySettings["Language"] ?? "English"; + List options = settingSwitches["Language"]!; + + return Material( + color: surface, + child: CustomScrollView( + slivers: [ + SliverAppBar.large( + leading: + IconButton(icon: Icon(Icons.arrow_back, color: surface,), + onPressed: () { + goBack(); + }), + title: comfortatext( + translation("Language", selected), 30, settings, + color: surface), + backgroundColor: primary, + pinned: false, + ), + SliverToBoxAdapter( + child: ListView.builder( + padding: const EdgeInsets.only(top: 30, left: 10, right: 20, bottom: 40), + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: options.length, + itemBuilder: (BuildContext context, int index) { + return ListTile( + title: comfortatext(options[index], 20, settings, color: onSurface), + leading: Radio( + fillColor: WidgetStateProperty.all(primary), + value: options[index], + groupValue: selected, + onChanged: (String? value) { + setState(() { + HapticFeedback.mediumImpact(); + if (value != null) { + copySettings["Language"] = value; + updateMainPage("Language", value); + } + }); + }, + ), + ); + }, + ), + ), + ], + ), + ); + } } \ No newline at end of file From 7b5a6ccedc387f69a44eb03f7112db1172d4ff96 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 27 Aug 2024 16:28:33 +0200 Subject: [PATCH 111/129] working on layout page --- lib/settings_screens.dart | 135 +++++++++++++++++++++++++++++++++----- 1 file changed, 118 insertions(+), 17 deletions(-) diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index fece953..5d5b5c9 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -95,7 +95,9 @@ Widget NewSettings(Map settings, Function updatePage, Image imag UnitsPage(colors: colors, settings: settings, image: image, updateMainPage: updatePage), context, updatePage), mainSettingEntry("Layout", "widget order, customization", containerLow, primary, onSurface, surface, - Icons.grid_view, settings, Container(), context, updatePage), + Icons.grid_view, settings, + LayoutPage(colors: colors, settings: settings, image: image, updateMainPage: updatePage), + context, updatePage), ], ), ); @@ -367,19 +369,14 @@ class _UnitsPageState extends State { _UnitsPageState({required this.image, required this.settings, required this.colors, required this.updateMainPage}); - Map copySettings = {}; - @override void initState() { super.initState(); - - copySettings = settings; } void updatePage(String name, String to) { setState(() { updateMainPage(name, to); - copySettings[name] = to; }); } @@ -460,19 +457,14 @@ class _GeneralSettingsPageState extends State { _GeneralSettingsPageState({required this.image, required this.settings, required this.colors, required this.updateMainPage}); - Map copySettings = {}; - @override void initState() { super.initState(); - - copySettings = settings; } void updatePage(String name, String to) { setState(() { updateMainPage(name, to); - copySettings[name] = to; }); } @@ -553,19 +545,15 @@ class _LangaugePageState extends State { _LangaugePageState({required this.image, required this.settings, required this.colors, required this.updateMainPage}); - Map copySettings = {}; @override void initState() { super.initState(); - - copySettings = settings; } void updatePage(String name, String to) { setState(() { updateMainPage(name, to); - copySettings[name] = to; }); } @@ -581,7 +569,7 @@ class _LangaugePageState extends State { Color onSurface = colors[4]; Color surface = colors[0]; - String selected = copySettings["Language"] ?? "English"; + String selected = settings["Language"] ?? "English"; List options = settingSwitches["Language"]!; return Material( @@ -617,7 +605,7 @@ class _LangaugePageState extends State { setState(() { HapticFeedback.mediumImpact(); if (value != null) { - copySettings["Language"] = value; + settings["Language"] = value; updateMainPage("Language", value); } }); @@ -631,4 +619,117 @@ class _LangaugePageState extends State { ), ); } +} + + +class LayoutPage extends StatefulWidget { + final settings; + final image; + final colors; + final updateMainPage; + + const LayoutPage({Key? key, required this.colors, required this.settings, + required this.image, required this.updateMainPage}) + : super(key: key); + + @override + _LayoutPageState createState() => + _LayoutPageState(image: image, settings: settings, colors: colors, + updateMainPage: updateMainPage); +} + +class _LayoutPageState extends State { + + final image; + final settings; + final colors; + final updateMainPage; + + _LayoutPageState({required this.image, required this.settings, required this.colors, required this.updateMainPage}); + + + @override + void initState() { + super.initState(); + } + + void updatePage(String name, String to) { + setState(() { + updateMainPage(name, to); + }); + } + + void goBack() { + HapticFeedback.selectionClick(); + Navigator.pop(context); + } + + @override + Widget build(BuildContext context) { + + Color primary = colors[1]; + Color onSurface = colors[4]; + Color surface = colors[0]; + Color highlight = colors[7]; + + final List _items = List.generate(5, (int index) => index); + + return Material( + color: surface, + child: CustomScrollView( + slivers: [ + SliverAppBar.large( + leading: + IconButton(icon: Icon(Icons.arrow_back, color: surface,), + onPressed: () { + goBack(); + }), + title: comfortatext( + "Layout", 30, settings, + color: surface), + backgroundColor: primary, + pinned: false, + ), + SliverToBoxAdapter( + child: ReorderableListView( + shrinkWrap: true, + padding: const EdgeInsets.only(left: 30, right: 30, top: 30, bottom: 50), + children: [ + for (int index = 0; index < _items.length; index += 1) + Container( + color: surface, + key: Key("$index"), + padding: EdgeInsets.all(4), + child: Container( + decoration: BoxDecoration( + color: highlight, + borderRadius: BorderRadius.circular(18), + ), + height: 70, + padding: EdgeInsets.all(10), + child: Row( + children: [ + comfortatext("$index", 20, settings, color: onSurface), + Spacer(), + Icon(Icons.reorder_rounded, color: onSurface,) + ], + ), + ), + ) + ], + onReorder: (int oldIndex, int newIndex) { + setState(() { + if (oldIndex < newIndex) { + newIndex -= 1; + } + final int item = _items.removeAt(oldIndex); + _items.insert(newIndex, item); + }); + }, + ), + ), + ], + ), + ); + } } \ No newline at end of file From e4971e360411ac809f3936014bd32bc1ca1f7f2c Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 27 Aug 2024 16:42:38 +0200 Subject: [PATCH 112/129] finally reordering actually works kinda --- lib/settings_screens.dart | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index 5d5b5c9..9203fb9 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -647,10 +647,13 @@ class _LayoutPageState extends State { _LayoutPageState({required this.image, required this.settings, required this.colors, required this.updateMainPage}); + late List _items; @override void initState() { super.initState(); + _items = ["sun status", "rain indicator", "air quality", "radar", "detailed daily", + "compact daily"]; } void updatePage(String name, String to) { @@ -672,8 +675,6 @@ class _LayoutPageState extends State { Color surface = colors[0]; Color highlight = colors[7]; - final List _items = List.generate(5, (int index) => index); - return Material( color: surface, child: CustomScrollView( @@ -697,32 +698,32 @@ class _LayoutPageState extends State { children: [ for (int index = 0; index < _items.length; index += 1) Container( - color: surface, key: Key("$index"), - padding: EdgeInsets.all(4), + color: surface, + padding: const EdgeInsets.all(4), child: Container( decoration: BoxDecoration( color: highlight, borderRadius: BorderRadius.circular(18), ), height: 70, - padding: EdgeInsets.all(10), + padding: const EdgeInsets.only(left: 20, right: 20), child: Row( children: [ - comfortatext("$index", 20, settings, color: onSurface), + comfortatext("${_items[index]}", 20, settings, color: onSurface), Spacer(), - Icon(Icons.reorder_rounded, color: onSurface,) + Icon(Icons.reorder_rounded, color: onSurface, size: 20,), ], ), ), - ) + ), ], onReorder: (int oldIndex, int newIndex) { setState(() { if (oldIndex < newIndex) { newIndex -= 1; } - final int item = _items.removeAt(oldIndex); + final String item = _items.removeAt(oldIndex); _items.insert(newIndex, item); }); }, From 3b1085c778355348034b4177b4ed776e7bb1e145 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 27 Aug 2024 21:23:08 +0200 Subject: [PATCH 113/129] popup kinda working fixed some auto theme issues. there is still one though --- lib/decoders/extra_info.dart | 11 ++++ lib/main.dart | 1 + lib/main_screens.dart | 47 +++++++++++++- lib/main_ui.dart | 1 + lib/settings_page.dart | 1 + lib/settings_screens.dart | 121 +---------------------------------- 6 files changed, 61 insertions(+), 121 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index f021e95..d3fc6a0 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -23,6 +23,7 @@ import 'dart:math'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; import 'package:overmorrow/decoders/decode_OM.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:palette_generator/palette_generator.dart'; @@ -145,6 +146,12 @@ Future MaterialYouColor(String theme) async { } else { mainColor = Colors.blue; } + + if (theme == "auto") { + var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + theme= brightness == Brightness.dark ? "dark" : "light"; + } + final ColorScheme palette = ColorScheme.fromSeed( seedColor: mainColor, brightness: theme == 'light' ? Brightness.light : Brightness.dark, @@ -342,6 +349,10 @@ Future _materialPalette(Image imageWidget, theme, color) async { DynamicSchemeVariant.tonalSpot, ); */ + if (theme == "auto") { + var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + theme= brightness == Brightness.dark ? "dark" : "light"; + } return ColorScheme.fromSeed( seedColor: color, diff --git a/lib/main.dart b/lib/main.dart index c577179..4d73953 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -204,6 +204,7 @@ class _MyAppState extends State { void initState() { super.initState(); + //defaults to new york when no previous location was found updateLocation('40.7128, 74.0060', "New York", time: 300, startup: true); //just for testing } diff --git a/lib/main_screens.dart b/lib/main_screens.dart index fa97163..5b97821 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -42,11 +42,54 @@ class NewMain extends StatefulWidget { } class _NewMainState extends State { - final data; + late var data; + final realData; final updateLocation; final context; - _NewMainState(this.data, this.updateLocation, this.context); + _NewMainState(this.realData, this.updateLocation, this.context); + + @override + void initState() { + super.initState(); + data = realData; + if (data.settings['networkImageDialogShown'] == "true") { + WidgetsBinding.instance.addPostFrameCallback((_) { + _showFeatureDialog(context); + }); + } + } + + void _showFeatureDialog(BuildContext context) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text("New Feature!"), + content: Text("Would you like to enable this feature?"), + actions: [ + TextButton( + onPressed: () async { + await SetData('settingnetworkImageDialogShown', "false"); + setState(() { + data.settings['networkImageDialogShown'] = "false"; + }); + Navigator.pushNamedAndRemoveUntil(context,'/',(_) => false); + }, + child: Text("Disable"), + ), + TextButton( + onPressed: () async { + await SetData('settingnetworkImageDialogShown', "true"); + Navigator.pushNamedAndRemoveUntil(context,'/',(_) => false); + }, + child: Text("Enable"), + ), + ], + ); + }, + ); + } @override Widget build(BuildContext context) { diff --git a/lib/main_ui.dart b/lib/main_ui.dart index dfc21d3..a84bf1d 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -57,6 +57,7 @@ class WeatherPage extends StatelessWidget { //return PhoneLayout(data, updateLocation, context); + return NewMain(data: data, updateLocation: updateLocation, context: context, key: Key("${data.place}, ${data.current.surface} ${data.current.image} ${data.provider}"),); diff --git a/lib/settings_page.dart b/lib/settings_page.dart index b513722..a286d79 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -49,6 +49,7 @@ Map> settingSwitches = { 'Image source' : ['network', 'asset'], 'Search provider' : ['weatherapi', 'open-meteo'], + 'networkImageDialogShown' : ["false", "true"], }; String translation(String text, String language) { diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index 9203fb9..f6f5b6e 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -43,7 +43,7 @@ Widget mainSettingEntry(String title, String desc, Color highlight, Color primar borderRadius: BorderRadius.circular(20), color: highlight, ), - padding: EdgeInsets.all(23), + padding: const EdgeInsets.all(23), child: Row( children: [ Padding( @@ -94,10 +94,6 @@ Widget NewSettings(Map settings, Function updatePage, Image imag Icons.pie_chart_outline, settings, UnitsPage(colors: colors, settings: settings, image: image, updateMainPage: updatePage), context, updatePage), - mainSettingEntry("Layout", "widget order, customization", containerLow, primary, onSurface, surface, - Icons.grid_view, settings, - LayoutPage(colors: colors, settings: settings, image: image, updateMainPage: updatePage), - context, updatePage), ], ), ); @@ -184,6 +180,7 @@ class _AppearancePageState extends State { String x = "light"; if (copySettings["Color mode"] == "auto") { var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + print(("brightness", brightness)); x = brightness == Brightness.dark ? "dark" : "light"; } else { @@ -619,118 +616,4 @@ class _LangaugePageState extends State { ), ); } -} - - -class LayoutPage extends StatefulWidget { - final settings; - final image; - final colors; - final updateMainPage; - - const LayoutPage({Key? key, required this.colors, required this.settings, - required this.image, required this.updateMainPage}) - : super(key: key); - - @override - _LayoutPageState createState() => - _LayoutPageState(image: image, settings: settings, colors: colors, - updateMainPage: updateMainPage); -} - -class _LayoutPageState extends State { - - final image; - final settings; - final colors; - final updateMainPage; - - _LayoutPageState({required this.image, required this.settings, required this.colors, required this.updateMainPage}); - - late List _items; - - @override - void initState() { - super.initState(); - _items = ["sun status", "rain indicator", "air quality", "radar", "detailed daily", - "compact daily"]; - } - - void updatePage(String name, String to) { - setState(() { - updateMainPage(name, to); - }); - } - - void goBack() { - HapticFeedback.selectionClick(); - Navigator.pop(context); - } - - @override - Widget build(BuildContext context) { - - Color primary = colors[1]; - Color onSurface = colors[4]; - Color surface = colors[0]; - Color highlight = colors[7]; - - return Material( - color: surface, - child: CustomScrollView( - slivers: [ - SliverAppBar.large( - leading: - IconButton(icon: Icon(Icons.arrow_back, color: surface,), - onPressed: () { - goBack(); - }), - title: comfortatext( - "Layout", 30, settings, - color: surface), - backgroundColor: primary, - pinned: false, - ), - SliverToBoxAdapter( - child: ReorderableListView( - shrinkWrap: true, - padding: const EdgeInsets.only(left: 30, right: 30, top: 30, bottom: 50), - children: [ - for (int index = 0; index < _items.length; index += 1) - Container( - key: Key("$index"), - color: surface, - padding: const EdgeInsets.all(4), - child: Container( - decoration: BoxDecoration( - color: highlight, - borderRadius: BorderRadius.circular(18), - ), - height: 70, - padding: const EdgeInsets.only(left: 20, right: 20), - child: Row( - children: [ - comfortatext("${_items[index]}", 20, settings, color: onSurface), - Spacer(), - Icon(Icons.reorder_rounded, color: onSurface, size: 20,), - ], - ), - ), - ), - ], - onReorder: (int oldIndex, int newIndex) { - setState(() { - if (oldIndex < newIndex) { - newIndex -= 1; - } - final String item = _items.removeAt(oldIndex); - _items.insert(newIndex, item); - }); - }, - ), - ), - ], - ), - ); - } } \ No newline at end of file From 533de14ee5283a6aefe7a309ede9c607535b7f3c Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Tue, 27 Aug 2024 21:24:41 +0200 Subject: [PATCH 114/129] fixed one last issue --- lib/settings_page.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/settings_page.dart b/lib/settings_page.dart index a286d79..701d2a5 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -312,7 +312,12 @@ Future> getTotalColor(settings, primary, back, image) async { List colors; List> allColor = []; - final String mode = settings["Color mode"]; + String mode = settings["Color mode"]; + + if (mode == "auto") { + var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + mode = brightness == Brightness.dark ? "dark" : "light"; + } List lightPalette = (await getImageColors(image, "light" , settings))[0]; List darkPalette = (await getImageColors(image, "dark" , settings))[0]; @@ -334,6 +339,7 @@ Future> getTotalColor(settings, primary, back, image) async { if ((mode == "light" || mode == "dark") || settings["Image source"] == 'network' || settings["Color source"] == 'wallpaper') { + colors = getNetworkColors(mode == "light" ? lightPalette : darkPalette ,settings); } else { From f4c00f973e414960fc653ac1f09ad1907cc20fa8 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 28 Aug 2024 14:38:19 +0200 Subject: [PATCH 115/129] fixed some bugs with auto color and refreshing of settings --- lib/decoders/decode_OM.dart | 3 ++- lib/main_screens.dart | 17 ++++++++++++----- lib/settings_page.dart | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 2c9ac67..e0479f0 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -92,7 +92,8 @@ int AqiIndexCorrection(int aqi) { } DateTime OMGetLocalTime(item) { - return DateTime.now().toUtc().add(Duration(seconds: item["utc_offset_seconds"])); + DateTime localTime = DateTime.now().toUtc().add(Duration(seconds: item["utc_offset_seconds"])); + return localTime; } double OMGetSunStatus(item) { diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 5b97821..5484d5b 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -20,6 +20,7 @@ import 'dart:math'; import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; import 'package:overmorrow/new_forecast.dart'; import 'package:overmorrow/radar.dart'; import 'package:overmorrow/settings_page.dart'; @@ -53,7 +54,7 @@ class _NewMainState extends State { void initState() { super.initState(); data = realData; - if (data.settings['networkImageDialogShown'] == "true") { + if (data.settings['networkImageDialogShown'] == "false") { WidgetsBinding.instance.addPostFrameCallback((_) { _showFeatureDialog(context); }); @@ -70,9 +71,9 @@ class _NewMainState extends State { actions: [ TextButton( onPressed: () async { - await SetData('settingnetworkImageDialogShown', "false"); + await SetData('settingnetworkImageDialogShown', "true"); setState(() { - data.settings['networkImageDialogShown'] = "false"; + data.settings['networkImageDialogShown'] = "true"; }); Navigator.pushNamedAndRemoveUntil(context,'/',(_) => false); }, @@ -98,6 +99,12 @@ class _NewMainState extends State { final FloatingSearchBarController controller = FloatingSearchBarController(); + String colorMode = data.settings["Color mode"]; + if (colorMode == "auto") { + var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + colorMode = brightness == Brightness.dark ? "dark" : "light"; + } + return Scaffold( backgroundColor: data.current.surface, drawer: MyDrawer(backupprimary: data.current.backup_primary, @@ -155,8 +162,8 @@ class _NewMainState extends State { controller: controller, settings: data.settings, real_loc: data.real_loc, - secondColor: data.settings["Color mode"] == "light" ? data.current.primary : data.current.onSurface, - textColor: data.settings["Color mode"] == "light" ? data.current.primaryLight : data.current.primary, + secondColor: colorMode == "light" ? data.current.primary : data.current.onSurface, + textColor: colorMode == "light" ? data.current.primaryLight : data.current.primary, highlightColor: data.current.container, key: Key("${data.place}, ${data.current.surface}"), extraTextColor: data.current.onSurface,), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 701d2a5..943edb6 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -439,6 +439,7 @@ Widget dropdown(Color bgcolor, String name, Function updatePage, String unit, se }).toList(), onChanged: (Object? value) { HapticFeedback.lightImpact(); + settings[name] = value; updatePage(name, value); } ); From 5bff577e2eb0a32adf8ebaf22c86b8f7a95f2100 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 28 Aug 2024 15:00:40 +0200 Subject: [PATCH 116/129] finally got the popup to work --- lib/main_screens.dart | 54 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 5484d5b..23f2e26 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -26,6 +26,7 @@ import 'package:overmorrow/radar.dart'; import 'package:overmorrow/settings_page.dart'; import 'package:material_floating_search_bar_2/material_floating_search_bar_2.dart'; import 'package:stretchy_header/stretchy_header.dart'; +import 'main.dart'; import 'main_ui.dart'; import 'new_displays.dart'; import 'ui_helper.dart'; @@ -54,7 +55,7 @@ class _NewMainState extends State { void initState() { super.initState(); data = realData; - if (data.settings['networkImageDialogShown'] == "false") { + if (data.settings['networkImageDialogShown'] == "true") { WidgetsBinding.instance.addPostFrameCallback((_) { _showFeatureDialog(context); }); @@ -66,25 +67,58 @@ class _NewMainState extends State { context: context, builder: (BuildContext context) { return AlertDialog( - title: Text("New Feature!"), - content: Text("Would you like to enable this feature?"), + backgroundColor: data.current.surface, + title: comfortatext("Overmorrow 2.4.0 introduces Network images!", 20, data.settings, color: data.current.primary), + content: SizedBox( + height: 100, + child: Column( + children: [ + comfortatext("Would you like to enable network images?", 16, data.settings, + color: data.current.onSurface), + const SizedBox(height: 20,), + comfortatext("note: you can always change later by going into settings > appearance > image source", 13, data.settings, + color: data.current.onSurface), + ], + ), + ), actions: [ TextButton( onPressed: () async { - await SetData('settingnetworkImageDialogShown', "true"); + await SetData('settingnetworkImageDialogShown', "false"); + await SetData('settingImage source', "asset"); setState(() { - data.settings['networkImageDialogShown'] = "true"; + data.settings['networkImageDialogShown'] = "false"; + data.settings['settingImage source'] = "asset"; }); - Navigator.pushNamedAndRemoveUntil(context,'/',(_) => false); + Navigator.of(context).pop(); + Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (context) { + return const MyApp(); + }, + ), + ); }, - child: Text("Disable"), + child: comfortatext("Disable", 17, data.settings, color: data.current.outline, weight: FontWeight.w600), ), TextButton( onPressed: () async { - await SetData('settingnetworkImageDialogShown', "true"); - Navigator.pushNamedAndRemoveUntil(context,'/',(_) => false); + await SetData('settingnetworkImageDialogShown', "false"); + await SetData('settingImage source', "network"); + setState(() { + data.settings['networkImageDialogShown'] = "false"; + data.settings['settingImage source'] = "network"; + }); + Navigator.of(context).pop(); + Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (context) { + return const MyApp(); + }, + ), + ); }, - child: Text("Enable"), + child: comfortatext("Enable", 17, data.settings, color: data.current.primary, weight: FontWeight.w600), ), ], ); From aec3dbf865f93a15419727299642f46afbd1d294 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 28 Aug 2024 15:26:48 +0200 Subject: [PATCH 117/129] only adding place name to cloud, clear sky, night pictures --- lib/decoders/decode_wapi.dart | 7 +++++-- lib/decoders/extra_info.dart | 9 ++++++--- lib/main_screens.dart | 20 +++++--------------- lib/weather_refact.dart | 17 +++++++++++++++++ 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index 2456b3f..f10b6e9 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -324,8 +324,11 @@ class WapiCurrent { String photoLink = ""; if (settings["Image source"] == "network") { - final ImageData = await getUnsplashImage(textCorrection( - item["current"]["weather_code"], item["current"]["is_day"]), real_loc, lat, lng); + final text = textCorrection( + item["current"]["condition"]["code"], item["current"]["is_day"], + language: settings["Language"] + ); + final ImageData = await getUnsplashImage(text, real_loc, lat, lng); Uimage = ImageData[0]; photographerName = ImageData[1]; photorgaperUrl = ImageData[2]; diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index d3fc6a0..3f28d1e 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -48,19 +48,22 @@ Future> getUnsplashImage(String _text, String real_loc, double lat } String text_query = textToUnsplashText[_text]![0]; + String placeName = shouldUsePlaceName[_text]! ? " $loc" : ""; + + print(("textquery", "$text_query, $loc", _text, text_query + placeName)); final params2 = { 'client_id': access_key, - 'query' : "$text_query, $loc", + 'query' : text_query + placeName, 'content_filter' : 'high', - 'count': '6', + 'count': '8', //'collections' : '893395, 583204, 11649432, 162468, 1492135, 42478673, 8253647, 461360' //'collections' : '893395, 162468, 461360' }; final url2 = Uri.https('api.unsplash.com', 'photos/random', params2); - var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$real_loc $text_query") + var file2 = await cacheManager2.getSingleFile(url2.toString(), key: "$text_query $loc") .timeout(const Duration(seconds: 6)); var response2 = await file2.readAsString(); diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 23f2e26..2a0722d 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -44,18 +44,16 @@ class NewMain extends StatefulWidget { } class _NewMainState extends State { - late var data; - final realData; + final data; final updateLocation; final context; - _NewMainState(this.realData, this.updateLocation, this.context); + _NewMainState(this.data, this.updateLocation, this.context); @override void initState() { super.initState(); - data = realData; - if (data.settings['networkImageDialogShown'] == "true") { + if (data.settings['networkImageDialogShown'] == "false") { WidgetsBinding.instance.addPostFrameCallback((_) { _showFeatureDialog(context); }); @@ -84,12 +82,8 @@ class _NewMainState extends State { actions: [ TextButton( onPressed: () async { - await SetData('settingnetworkImageDialogShown', "false"); + await SetData('settingnetworkImageDialogShown', "true"); await SetData('settingImage source', "asset"); - setState(() { - data.settings['networkImageDialogShown'] = "false"; - data.settings['settingImage source'] = "asset"; - }); Navigator.of(context).pop(); Navigator.of(context).pushReplacement( MaterialPageRoute( @@ -103,12 +97,8 @@ class _NewMainState extends State { ), TextButton( onPressed: () async { - await SetData('settingnetworkImageDialogShown', "false"); + await SetData('settingnetworkImageDialogShown', "true"); await SetData('settingImage source', "network"); - setState(() { - data.settings['networkImageDialogShown'] = "false"; - data.settings['settingImage source'] = "network"; - }); Navigator.of(context).pop(); Navigator.of(context).pushReplacement( MaterialPageRoute( diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 7c52a9a..524ff5e 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -343,6 +343,23 @@ Map> textToUnsplashText = { 'Cloudy Night' : ['cloudy night', 'night'] //if you specify cloudy then it gives cloudy results }; +Map shouldUsePlaceName = { + 'Clear Night': true, + 'Partly Cloudy': true, + 'Clear Sky': true, + 'Overcast': true, + 'Haze': false, + 'Rain': false, + 'Sleet': false, + 'Drizzle': false, + 'Thunderstorm': false, + 'Heavy Snow': false, + 'Fog': false, + 'Snow': false, + 'Heavy Rain': false, + 'Cloudy Night': true, +}; + //trying to assign values for words (for example sky will be rewarded) Map textFilter = { 'sky' : 2000, From 395cac92052aed6b8e6d1b1162cd0c55adf2819e Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Wed, 28 Aug 2024 15:53:44 +0200 Subject: [PATCH 118/129] removed unused prints and tried to improve image quality again --- lib/decoders/decode_OM.dart | 4 ---- lib/decoders/decode_wapi.dart | 4 ---- lib/decoders/extra_info.dart | 2 +- lib/new_forecast.dart | 2 +- lib/settings_screens.dart | 1 - lib/weather_refact.dart | 4 ++-- 6 files changed, 4 insertions(+), 13 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index e0479f0..005df8f 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -332,8 +332,6 @@ class OMCurrent { List colors = x[0]; List imageDebugColors = x[1]; - print((photographerName, photorgaperUrl, photoLink)); - return OMCurrent( image: Uimage, photographerName: photographerName, @@ -496,8 +494,6 @@ class OM15MinutePrecip { precips.add(x); } - print(("closest", closest)); - sum = max(sum, 0.1); //if there is rain then it shouldn't write 0 String t_minus = ""; diff --git a/lib/decoders/decode_wapi.dart b/lib/decoders/decode_wapi.dart index f10b6e9..cee1291 100644 --- a/lib/decoders/decode_wapi.dart +++ b/lib/decoders/decode_wapi.dart @@ -53,8 +53,6 @@ Future> WapiMakeRequest(String latlong, String real_loc) async { }; final url = Uri.http('api.weatherapi.com', 'v1/forecast.json', params); - print(url); - var file = await cacheManager2.getSingleFile(url.toString(), key: "$real_loc, weatherapi.com ") .timeout(const Duration(seconds: 6)); @@ -64,8 +62,6 @@ Future> WapiMakeRequest(String latlong, String real_loc) async { var wapi_body = jsonDecode(response); - print(wapi_body["current"]["air_quality"]); - return [wapi_body, fetch_datetime]; } diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 3f28d1e..5ee4e70 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -89,7 +89,7 @@ Future> getUnsplashImage(String _text, String real_loc, double lat List keys2 = textToUnsplashText.keys.toList(); for (int x = 0; x < textToUnsplashText.length; x ++) { for (int y = 0; y < textToUnsplashText[keys2[x]]!.length; y ++) { - int reward = keys2[x] == _text ? -3000 : 1000; + int reward = keys2[x] == _text ? -3000 : 2000; if (textToUnsplashText[_text]!.contains(textToUnsplashText[keys2[x]]![y])) { if (reward == 1000) { reward = 0; diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index f468074..07cf4a6 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -238,7 +238,7 @@ class _NewDayState extends State with AutomaticKeepAliveClientMixin { children: List.generate( 4, (int index) { - print((_value, index)); + return ChoiceChip( elevation: 0.0, diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index f6f5b6e..d23b94a 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -180,7 +180,6 @@ class _AppearancePageState extends State { String x = "light"; if (copySettings["Color mode"] == "auto") { var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; - print(("brightness", brightness)); x = brightness == Brightness.dark ? "dark" : "light"; } else { diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 524ff5e..57565bb 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -329,7 +329,7 @@ Map> conversionTable = { Map> textToUnsplashText = { 'Clear Night': ['night', 'clear', 'moon'], //somehow just 'night' always gives you clear skies: stars or moon 'Partly Cloudy': ['cloud',], //this is also some simplification which improves a lot - 'Clear Sky': ['blue sky', 'sunny', 'sun', 'clear'], //it doesn't understand clear as much so i use blue instead + 'Clear Sky': ['sunny', 'blue sky', 'sun', 'clear'], //it doesn't understand clear as much so i use blue instead 'Overcast': ['overcast', 'cloud'], 'Haze': ['haze', 'fog', 'mist'], 'Rain': ['rain', 'drop', 'rainy', 'raining', 'drops'], @@ -372,7 +372,7 @@ Map textFilter = { 'icy': -10000, 'bubble': -10000, 'smoke' : -2000, - 'instagram': -10000, + 'instagram': -2000, 'ring': -10000, 'during': 10000, 'fabric': -10000, From 231e6f11be2e7dd6b17d9430f6460df6d9bd7b5e Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 29 Aug 2024 15:54:21 +0200 Subject: [PATCH 119/129] translated rain indicator --- lib/decoders/decode_OM.dart | 22 ++++++--- lib/languages.dart | 99 +++++++++++++++++++++++++++++++++++++ lib/new_displays.dart | 2 +- lib/settings_screens.dart | 21 +++++--- lib/weather_refact.dart | 7 +-- 5 files changed, 130 insertions(+), 21 deletions(-) diff --git a/lib/decoders/decode_OM.dart b/lib/decoders/decode_OM.dart index 005df8f..af33ed1 100644 --- a/lib/decoders/decode_OM.dart +++ b/lib/decoders/decode_OM.dart @@ -500,26 +500,34 @@ class OM15MinutePrecip { if (closest != 100) { if (closest <= 2) { if (end == 2) { - t_minus = "the next half an hour"; + t_minus = translation("rain expected in the next half an hour", settings["Language"]); } else if (end < 4) { - t_minus = "the next ${[15, 30, 45][end - 1]} minutes"; + String x = " ${[15, 30, 45][end - 1]} "; + t_minus = translation("rain expected in the next x minutes", settings["Language"]); + t_minus = t_minus.replaceAll(" x ", x); } else if (end ~/ 4 == 1) { - t_minus = "the next 1 hour"; + t_minus = translation("rain expected in the next 1 hour", settings["Language"]); } else { - t_minus = "the next ${end ~/ 4} hours"; + String x = " ${end ~/ 4} "; + t_minus = translation("rain expected in the next x hours", settings["Language"]); + t_minus = t_minus.replaceAll(" x ", x); } } else if (closest < 4) { - t_minus = "${[15, 30, 45][closest - 1]} minutes"; + String x = " ${[15, 30, 45][closest - 1]} "; + t_minus = translation("rain expected in x minutes", settings["Language"]); + t_minus = t_minus.replaceAll(" x ", x); } else if (closest ~/ 4 == 1) { - t_minus = "1 hour"; + t_minus = translation("rain expected in 1 hour", settings["Language"]); } else { - t_minus = "${closest ~/ 4} hours"; + String x = " ${closest ~/ 4} "; + t_minus = translation("rain expected in x hours", settings["Language"]); + t_minus = t_minus.replaceAll(" x ", x); } } diff --git a/lib/languages.dart b/lib/languages.dart index d43a372..ec08524 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -1232,6 +1232,105 @@ Map> mainTranslate = { 'Υποστήριξη στο Patreon' ], + 'rain expected in the next half an hour': [ + 'rain expected in the next half an hour', + 'eső várható a következő fél órában', + 'se espera lluvia en la próxima media hora', + 'pluie attendue dans la prochaine demi-heure', + 'regen in der nächsten halben Stunde erwartet', + 'pioggia prevista nella prossima mezz\'ora', + 'chuva esperada na próxima meia hora', + 'ожидается дождь в течение следующего получаса', + '预计在接下来的半小时内下雨', + '雨が次の30分以内に予想されます', + 'deszcz spodziewany w ciągu następnych pół godziny', + 'αναμένεται βροχή στο επόμενο μισάωρο' + ], + 'rain expected in the next x minutes': [ + 'rain expected in the next x minutes', + 'eső várható a következő x percben', + 'se espera lluvia en los próximos x minutos', + 'pluie attendue dans les x prochaines minutes', + 'regen in den nächsten x Minuten erwartet', + 'pioggia prevista nei prossimi x minuti', + 'chuva esperada nos próximos x minutos', + 'ожидается дождь в течение следующих x минут', + '预计在接下来的 x 分钟内下雨', + '雨が次の x 分以内に予想されます', + 'deszcz spodziewany w ciągu następnych x minut', + 'αναμένεται βροχή στα επόμενα x λεπτά' + ], + 'rain expected in the next 1 hour': [ + 'rain expected in the next 1 hour', + 'eső várható a következő 1 órában', + 'se espera lluvia en la próxima 1 hora', + 'pluie attendue dans la prochaine heure', + 'regen in der nächsten Stunde erwartet', + 'pioggia prevista nell\'ora successiva', + 'chuva esperada na próxima 1 hora', + 'ожидается дождь в течение следующего часа', + '预计在接下来的 1 小时内下雨', + '雨が次の1時間以内に予想されます', + 'deszcz spodziewany w ciągu następnej godziny', + 'αναμένεται βροχή στην επόμενη 1 ώρα' + ], + 'rain expected in the next x hours': [ + 'rain expected in the next x hours', + 'eső várható a következő x órában', + 'se espera lluvia en las próximas x horas', + 'pluie attendue dans les x prochaines heures', + 'regen in den nächsten x Stunden erwartet', + 'pioggia prevista nelle prossime x ore', + 'chuva esperada nas próximas x horas', + 'ожидается дождь в течение следующих x часов', + '预计在接下来的 x 小时内下雨', + '雨が次の x 時間以内に予想されます', + 'deszcz spodziewany w ciągu następnych x godzin', + 'αναμένεται βροχή στις επόμενες x ώρες' + ], + 'rain expected in x minutes': [ + 'rain expected in x minutes', + 'eső várható x perc múlva', + 'se espera lluvia en x minutos', + 'pluie attendue dans x minutes', + 'regen in x Minuten erwartet', + 'pioggia prevista tra x minuti', + 'chuva esperada em x minutos', + 'ожидается дождь через x минут', + '预计在 x 分钟内下雨', + '雨が x 分以内に予想されます', + 'deszcz spodziewany za x minut', + 'αναμένεται βροχή σε x λεπτά' + ], + 'rain expected in 1 hour': [ + 'rain expected in 1 hour', + 'eső várható 1 óra múlva', + 'se espera lluvia en 1 hora', + 'pluie attendue dans 1 heure', + 'regen in 1 Stunde erwartet', + 'pioggia prevista tra 1 ora', + 'chuva esperada em 1 hora', + 'ожидается дождь через 1 час', + '预计在 1 小时内下雨', + '雨が1時間以内に予想されます', + 'deszcz spodziewany za 1 godzinę', + 'αναμένεται βροχή σε 1 ώρα' + ], + 'rain expected in x hours': [ + 'rain expected in x hours', + 'eső várható x óra múlva', + 'se espera lluvia en x horas', + 'pluie attendue dans x heures', + 'regen in x Stunden erwartet', + 'pioggia prevista tra x ore', + 'chuva esperada em x horas', + 'ожидается дождь через x часов', + '预计在 x 小时内下雨', + '雨が x 時間以内に予想されます', + 'deszcz spodziewany za x godzin', + 'αναμένεται βροχή σε x ώρες' + ], + 'Search translation': [ //used for getting the codes used for translation of city names //If none are available then en (english) is the default // for more info visit https://open-meteo.com/en/docs/geocoding-api diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 56569d7..9259d65 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -350,7 +350,7 @@ Widget NewRain15MinuteIndicator(var data) { child: Padding( padding: const EdgeInsets.only(left: 8), child: comfortatext( - "rain expected in ${data.minutely_15_precip.t_minus}", + data.minutely_15_precip.t_minus, 14, data.settings, color: data.current.onSurface, weight: FontWeight.w500), diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index d23b94a..579d247 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -568,6 +568,16 @@ class _LangaugePageState extends State { String selected = settings["Language"] ?? "English"; List options = settingSwitches["Language"]!; + void onTap(value) { + setState(() { + HapticFeedback.mediumImpact(); + if (value != null) { + settings["Language"] = value; + updateMainPage("Language", value); + } + }); + } + return Material( color: surface, child: CustomScrollView( @@ -592,19 +602,16 @@ class _LangaugePageState extends State { itemCount: options.length, itemBuilder: (BuildContext context, int index) { return ListTile( + onTap: () { + onTap(options[index]); + }, title: comfortatext(options[index], 20, settings, color: onSurface), leading: Radio( fillColor: WidgetStateProperty.all(primary), value: options[index], groupValue: selected, onChanged: (String? value) { - setState(() { - HapticFeedback.mediumImpact(); - if (value != null) { - settings["Language"] = value; - updateMainPage("Language", value); - } - }); + onTap(value); }, ), ); diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 57565bb..6029625 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -340,7 +340,7 @@ Map> textToUnsplashText = { 'Fog': ['fog', 'mist', 'haze'], 'Snow': ['snow', 'snowing', 'snows'], 'Heavy Rain': ['heavy rain', 'rain', 'drop', 'rainy', 'raining', 'drops'], - 'Cloudy Night' : ['cloudy night', 'night'] //if you specify cloudy then it gives cloudy results + 'Cloudy Night' : ['cloudy night', 'night', 'moon'] //if you specify cloudy then it gives cloudy results }; Map shouldUsePlaceName = { @@ -363,11 +363,6 @@ Map shouldUsePlaceName = { //trying to assign values for words (for example sky will be rewarded) Map textFilter = { 'sky' : 2000, - 'weather': 2000, - 'tree': 1000, - 'flower': 1000, - 'cliff': 1000, - 'mountain': 1000, 'ice': -10000, 'icy': -10000, 'bubble': -10000, From 61bdfcbeb5eefc4f03fd0c5275aeebce6450d036 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 29 Aug 2024 17:52:23 +0200 Subject: [PATCH 120/129] tried to improve image accuracy --- lib/decoders/extra_info.dart | 21 ++++++++++----------- lib/settings_screens.dart | 1 + lib/weather_refact.dart | 16 ++++++++-------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 5ee4e70..da8c735 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -83,19 +83,22 @@ Future> getUnsplashImage(String _text, String real_loc, double lat } var desc1 = unsplash_body[i]["description"] ?? " "; - var desc2 = unsplash_body[i]["links"]["html"]; + var desc2 = unsplash_body[i]["links"]["html"] ?? " "; + var desc3 = unsplash_body[i]["alt_description"] ?? " "; - var desc = desc1.toLowerCase() + " " + desc2.toLowerCase(); + String desc = desc1.toLowerCase() + " " + desc3.toLowerCase(); + desc = " ${desc.replaceAll("-", " ")} "; List keys2 = textToUnsplashText.keys.toList(); for (int x = 0; x < textToUnsplashText.length; x ++) { for (int y = 0; y < textToUnsplashText[keys2[x]]!.length; y ++) { + String lookFor = textToUnsplashText[keys2[x]]![y]; int reward = keys2[x] == _text ? -3000 : 2000; - if (textToUnsplashText[_text]!.contains(textToUnsplashText[keys2[x]]![y])) { - if (reward == 1000) { + if (textToUnsplashText[_text]!.contains(lookFor)) { + if (reward == 2000) { reward = 0; } } - if (desc.contains(textToUnsplashText[keys2[x]]![y])) { + if (desc.contains(lookFor)) { print(("punished1", textToUnsplashText[keys2[x]]![y], reward)); unaccuracy += reward; // i had to reverse it } @@ -109,15 +112,11 @@ Future> getUnsplashImage(String _text, String real_loc, double lat } } - if (desc.contains(real_loc.toLowerCase())) { - unaccuracy -= 3000; - } - double ratings = unsplash_body[i]["likes"] * 0.02 ?? 0; ratings += unsplash_body[i]["downloads"] * 0.01 ?? 0; print(("ratings", ratings)); - unaccuracy -= min(ratings, 4000); + unaccuracy -= min(ratings, 2000); print((i, unaccuracy.toStringAsFixed(6), (desc1 ?? "null").trim() + ", " + desc2, unsplash_body[i]["likes"], unsplash_body[i]["downloads"])); if (unaccuracy < best) { @@ -258,7 +257,7 @@ int diffBetweenBackColors(List backcolors) { } } } - return (diff_sum / (backcolors.length * (backcolors.length - 1))).round(); + return (diff_sum / max((backcolors.length * (backcolors.length - 1)), 1)).round(); } int difBetweenTwoColors(Color color1, Color color2) { diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index 579d247..b641bec 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -194,6 +194,7 @@ class _AppearancePageState extends State { Color primary = colors[1]; Color onSurface = colors[4]; Color surface = colors[0]; + Color colorPop = colors[12]; Color descColor = colors[13]; diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 6029625..64bf174 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -326,16 +326,17 @@ Map> conversionTable = { //I am trying to convert conditions to text that unsplash better understands //for example: blue sky instead of clear sky tends to help a lot +// the ones with spaces around them is so that only the work itself will count (sun <- yes, sunglasses <- no) Map> textToUnsplashText = { 'Clear Night': ['night', 'clear', 'moon'], //somehow just 'night' always gives you clear skies: stars or moon - 'Partly Cloudy': ['cloud',], //this is also some simplification which improves a lot - 'Clear Sky': ['sunny', 'blue sky', 'sun', 'clear'], //it doesn't understand clear as much so i use blue instead - 'Overcast': ['overcast', 'cloud'], + 'Partly Cloudy': ['cloud', 'daytime'], //this is also some simplification which improves a lot + 'Clear Sky': ['sunny clear', 'sunny', ' sun ', 'clear' 'daytime'], //it doesn't understand clear as much so i use blue instead + 'Overcast': ['overcast', 'cloud' 'daytime'], 'Haze': ['haze', 'fog', 'mist'], 'Rain': ['rain', 'drop', 'rainy', 'raining', 'drops'], 'Sleet': ['freezing rain', 'sleet', 'ice'],//this works much better 'Drizzle': ['light rain', 'rain', 'rainy', 'raining', 'drop', 'drops'], //somehow understands it more though still not perfect - 'Thunderstorm': ['thunderstorm', 'lightning', 'storm'], + 'Thunderstorm': ['thunderstorm', 'lightning', 'storm', 'thunder'], 'Heavy Snow': ['heavy snow', 'snow', 'snowing', 'snows'], 'Fog': ['fog', 'mist', 'haze'], 'Snow': ['snow', 'snowing', 'snows'], @@ -349,9 +350,9 @@ Map shouldUsePlaceName = { 'Clear Sky': true, 'Overcast': true, 'Haze': false, - 'Rain': false, + 'Rain': true, 'Sleet': false, - 'Drizzle': false, + 'Drizzle': true, 'Thunderstorm': false, 'Heavy Snow': false, 'Fog': false, @@ -362,7 +363,7 @@ Map shouldUsePlaceName = { //trying to assign values for words (for example sky will be rewarded) Map textFilter = { - 'sky' : 2000, + 'sky' : 1000, 'ice': -10000, 'icy': -10000, 'bubble': -10000, @@ -373,7 +374,6 @@ Map textFilter = { 'fabric': -10000, 'texture': -10000, 'pattern': -10000, - 'wall' : -10000, 'text': -10000, 'sign': -10000, 'grayscale' : -100000, From 688f3788346209397bb70af16e4bfed06942d2f2 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 29 Aug 2024 18:15:59 +0200 Subject: [PATCH 121/129] some minor improvements to image generation --- lib/decoders/extra_info.dart | 4 ++-- lib/weather_refact.dart | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index da8c735..0215d69 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -56,7 +56,7 @@ Future> getUnsplashImage(String _text, String real_loc, double lat 'client_id': access_key, 'query' : text_query + placeName, 'content_filter' : 'high', - 'count': '8', + 'count': '6', //'collections' : '893395, 583204, 11649432, 162468, 1492135, 42478673, 8253647, 461360' //'collections' : '893395, 162468, 461360' }; @@ -99,7 +99,7 @@ Future> getUnsplashImage(String _text, String real_loc, double lat } } if (desc.contains(lookFor)) { - print(("punished1", textToUnsplashText[keys2[x]]![y], reward)); + print(("punished1", textToUnsplashText[keys2[x]]![y], reward, lookFor, textToUnsplashText[_text])); unaccuracy += reward; // i had to reverse it } } diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 64bf174..1f7aee9 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -329,9 +329,9 @@ Map> conversionTable = { // the ones with spaces around them is so that only the work itself will count (sun <- yes, sunglasses <- no) Map> textToUnsplashText = { 'Clear Night': ['night', 'clear', 'moon'], //somehow just 'night' always gives you clear skies: stars or moon - 'Partly Cloudy': ['cloud', 'daytime'], //this is also some simplification which improves a lot - 'Clear Sky': ['sunny clear', 'sunny', ' sun ', 'clear' 'daytime'], //it doesn't understand clear as much so i use blue instead - 'Overcast': ['overcast', 'cloud' 'daytime'], + 'Partly Cloudy': ['cloud'], //this is also some simplification which improves a lot + 'Clear Sky': ['sunny clear', 'sunny', ' sun ', 'clear'], //it doesn't understand clear as much so i use blue instead + 'Overcast': ['overcast', 'cloud'], 'Haze': ['haze', 'fog', 'mist'], 'Rain': ['rain', 'drop', 'rainy', 'raining', 'drops'], 'Sleet': ['freezing rain', 'sleet', 'ice'],//this works much better @@ -350,9 +350,9 @@ Map shouldUsePlaceName = { 'Clear Sky': true, 'Overcast': true, 'Haze': false, - 'Rain': true, + 'Rain': false, 'Sleet': false, - 'Drizzle': true, + 'Drizzle': false, 'Thunderstorm': false, 'Heavy Snow': false, 'Fog': false, From c1e48b30d77ed8bb3f73f597585270d1238830c4 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Thu, 29 Aug 2024 18:38:30 +0200 Subject: [PATCH 122/129] added some items to weather refact to improve image accuracy --- lib/weather_refact.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 1f7aee9..133a3fb 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -330,7 +330,7 @@ Map> conversionTable = { Map> textToUnsplashText = { 'Clear Night': ['night', 'clear', 'moon'], //somehow just 'night' always gives you clear skies: stars or moon 'Partly Cloudy': ['cloud'], //this is also some simplification which improves a lot - 'Clear Sky': ['sunny clear', 'sunny', ' sun ', 'clear'], //it doesn't understand clear as much so i use blue instead + 'Clear Sky': ['sunny clear', 'sunny', ' sun ', 'clear', 'blue sky'], //it doesn't understand clear as much so i use blue instead 'Overcast': ['overcast', 'cloud'], 'Haze': ['haze', 'fog', 'mist'], 'Rain': ['rain', 'drop', 'rainy', 'raining', 'drops'], @@ -378,6 +378,7 @@ Map textFilter = { 'sign': -10000, 'grayscale' : -100000, 'black and white' : -100000, + 'meat' : -5000, 'man': -10000000, //trying to not have people in images 'male': -1000000, 'couple': -1000000, From 88baf137d271db08a6a9c0313ad8e15fdd8c2475 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 30 Aug 2024 13:58:07 +0200 Subject: [PATCH 123/129] the settings page is totally translated --- lib/languages.dart | 100 ++++++++++++++++++++++++++++++++++++++ lib/search_screens.dart | 2 +- lib/settings_screens.dart | 10 ++-- lib/weather_refact.dart | 5 ++ 4 files changed, 111 insertions(+), 6 deletions(-) diff --git a/lib/languages.dart b/lib/languages.dart index ec08524..81b5251 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -1331,6 +1331,106 @@ Map> mainTranslate = { 'αναμένεται βροχή σε x ώρες' ], + 'Appearance': [ + 'Appearance', + 'Megjelenés', + 'Apariencia', + 'Apparence', + 'Erscheinungsbild', + 'Aspetto', + 'Aparência', + 'Внешний вид', + '外观', + '外観', + 'Wygląd', + 'Εμφάνιση' + ], + 'General': [ + 'General', + 'Általános', + 'General', + 'Général', + 'Allgemein', + 'Generale', + 'Geral', + 'Общие', + '常规', + '一般', + 'Ogólne', + 'Γενικά' + ], + 'Units': [ + 'Units', + 'Egységek', + 'Unidades', + 'Unités', + 'Einheiten', + 'Unità', + 'Unidades', + 'Единицы', + '单位', + '単位', + 'Jednostki', + 'Μονάδες' + ], + + "color theme, image source": [ + 'color theme, image source', + 'színtéma, kép forrása', + 'tema de color, fuente de imagen', + 'thème de couleur, source d\'image', + 'Farbschema, Bildquelle', + 'tema colore, sorgente immagine', + 'tema de cor, fonte de imagem', + 'цветовая тема, источник изображения', + '颜色主题, 图片来源', + 'カラーテーマ, 画像のソース', + 'motyw kolorystyczny, źródło obrazu', + 'θέμα χρωμάτων, πηγή εικόνας' + ], + "time mode, font size": [ + 'time mode, font size', + 'idő mód, betűméret', + 'modo de tiempo, tamaño de fuente', + 'mode de temps, taille de police', + 'Zeitmodus, Schriftgröße', + 'modalità tempo, dimensione del carattere', + 'modo de tempo, tamanho da fonte', + 'режим времени, размер шрифта', + '时间模式, 字体大小', + '時間モード, フォントサイズ', + 'tryb czasu, rozmiar czcionki', + 'λειτουργία χρόνου, μέγεθος γραμματοσειράς' + ], + "the language used": [ + 'the language used', + 'használt nyelv', + 'el idioma utilizado', + 'la langue utilisée', + 'die verwendete Sprache', + 'la lingua utilizzata', + 'o idioma usado', + 'используемый язык', + '使用的语言', + '使用されている言語', + 'używany język', + 'η χρησιμοποιούμενη γλώσσα' + ], + "the units used in the app": [ + 'the units used in the app', + 'az alkalmazásban használt egységek', + 'las unidades utilizadas en la aplicación', + 'les unités utilisées dans l\'application', + 'die in der App verwendeten Einheiten', + 'le unità utilizzate nell\'app', + 'as unidades usadas no aplicativo', + 'единицы, используемые в приложении', + '应用中使用的单位', + 'アプリで使用される単位', + 'jednostki używane w aplikacji', + 'οι μονάδες που χρησιμοποιούνται στην εφαρμογή' + ], + 'Search translation': [ //used for getting the codes used for translation of city names //If none are available then en (english) is the default // for more info visit https://open-meteo.com/en/docs/geocoding-api diff --git a/lib/search_screens.dart b/lib/search_screens.dart index cd9db1f..8976def 100644 --- a/lib/search_screens.dart +++ b/lib/search_screens.dart @@ -231,7 +231,7 @@ Widget defaultSearchScreen(Color color, child: Align( alignment: Alignment.centerLeft, child: comfortatext( - "favorites", 20, + translation('Favorites', settings["Language"] ?? "English"), 20, settings, color: extraTextColor), ), diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index b641bec..19a8016 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -54,8 +54,8 @@ Widget mainSettingEntry(String title, String desc, Color highlight, Color primar mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.start, children: [ - comfortatext(title, 21, settings, color: onSurface), - comfortatext(desc, 16, settings, color: onSurface) + comfortatext(translation(title, settings["Language"]), 21, settings, color: onSurface), + comfortatext(translation(desc, settings["Language"]), 16, settings, color: onSurface) ], ) ], @@ -209,7 +209,7 @@ class _AppearancePageState extends State { goBack(); }), title: comfortatext( - "Appearance", 30, settings, + translation('Appearance', settings["Language"]), 30, settings, color: surface), backgroundColor: primary, pinned: false, @@ -402,7 +402,7 @@ class _UnitsPageState extends State { goBack(); }), title: comfortatext( - "Units", 30, settings, + translation("Units", settings["Language"]), 30, settings, color: surface), backgroundColor: primary, pinned: false, @@ -490,7 +490,7 @@ class _GeneralSettingsPageState extends State { goBack(); }), title: comfortatext( - "General", 30, settings, + translation("General", settings["Language"]), 30, settings, color: surface), backgroundColor: primary, pinned: false, diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 133a3fb..52f6a9b 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -362,8 +362,12 @@ Map shouldUsePlaceName = { }; //trying to assign values for words (for example sky will be rewarded) +//-10000 is basically taboo Map textFilter = { 'sky' : 1000, + 'tree' : 500, + 'flower': 500, + 'mountain': 500, 'ice': -10000, 'icy': -10000, 'bubble': -10000, @@ -378,6 +382,7 @@ Map textFilter = { 'sign': -10000, 'grayscale' : -100000, 'black and white' : -100000, + 'graffiti' : -2000, 'meat' : -5000, 'man': -10000000, //trying to not have people in images 'male': -1000000, From d3e18e17a1fb9afa29bfc0054d73c413e7f44d21 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 30 Aug 2024 14:13:23 +0200 Subject: [PATCH 124/129] rain indicator totally translated --- lib/languages.dart | 28 ++++++++++++++++++++++++++++ lib/new_displays.dart | 6 +++--- lib/weather_refact.dart | 2 +- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/lib/languages.dart b/lib/languages.dart index 81b5251..8db2191 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -1430,6 +1430,34 @@ Map> mainTranslate = { 'jednostki używane w aplikacji', 'οι μονάδες που χρησιμοποιούνται στην εφαρμογή' ], + "now": [ + 'now', + 'most', + 'ahora', + 'maintenant', + 'jetzt', + 'ora', + 'agora', + 'сейчас', + '现在', + '今', + 'teraz', + 'τώρα' + ], + "hr": [ + 'hr', + 'ó', + 'h', + 'h', + 'Std', + 'h', + 'h', + 'ч', + '小时', + '時', + 'godz.', + 'ώ', + ], 'Search translation': [ //used for getting the codes used for translation of city names //If none are available then en (english) is the default diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 9259d65..662cc6f 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -389,9 +389,9 @@ Widget NewRain15MinuteIndicator(var data) { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - comfortatext('now', 13, data.settings, color: data.current.onSurface), - comfortatext('3hr', 13, data.settings, color: data.current.onSurface), - comfortatext('6hr', 13, data.settings, color: data.current.onSurface) + comfortatext(translation('now', data.settings["Language"]), 13, data.settings, color: data.current.onSurface), + comfortatext('3${translation("hr", data.settings["Language"])}', 13, data.settings, color: data.current.onSurface), + comfortatext('6${translation("hr", data.settings["Language"])}', 13, data.settings, color: data.current.onSurface) ], ), ) diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 52f6a9b..378b522 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -341,7 +341,7 @@ Map> textToUnsplashText = { 'Fog': ['fog', 'mist', 'haze'], 'Snow': ['snow', 'snowing', 'snows'], 'Heavy Rain': ['heavy rain', 'rain', 'drop', 'rainy', 'raining', 'drops'], - 'Cloudy Night' : ['cloudy night', 'night', 'moon'] //if you specify cloudy then it gives cloudy results + 'Cloudy Night' : ['cloud night', 'night', 'moon'] }; Map shouldUsePlaceName = { From 6d9ef337c86fb330d7fdc456133f62a44fb12748 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 30 Aug 2024 14:27:04 +0200 Subject: [PATCH 125/129] saying goodbye to old code. --- lib/api_key_example.dart | 6 +- lib/main_screens.dart | 8 - lib/main_ui.dart | 585 --------------------------------------- lib/new_displays.dart | 2 - lib/radar.dart | 439 +---------------------------- lib/settings_page.dart | 249 ----------------- lib/ui_helper.dart | 39 --- 7 files changed, 6 insertions(+), 1322 deletions(-) diff --git a/lib/api_key_example.dart b/lib/api_key_example.dart index 1094673..d682880 100644 --- a/lib/api_key_example.dart +++ b/lib/api_key_example.dart @@ -23,4 +23,8 @@ along with this program. If not, see . //IMPORTANT: Overmorrow has two weather providers (open-meteo and weatherapi) //but only weatherapi requires an api key. You don't need an api key for open-meteo. -const String wapi_key = "YourApiKey"; //your api key from weatherapi.com \ No newline at end of file +const String wapi_key = "YourWeatherApiKey"; //your api key from weatherapi.com +//the app works without this if you only use the open-meteo provider + +const String access_key = "YourUnsplashApiKey"; //your api key from unsplash.com +//the app works without this if you set the image source to asset \ No newline at end of file diff --git a/lib/main_screens.dart b/lib/main_screens.dart index 2a0722d..f64c835 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -255,14 +255,6 @@ class _NewMainState extends State { ), - /* - NewTimes(data, true), - buildHihiDays(data), - buildGlanceDay(data), - providerSelector(data.settings, updateLocation, data.current.outline, data.current.container, - data.current.surface, data.provider, "${data.lat}, ${data.lng}", data.real_loc), - - */ const Padding(padding: EdgeInsets.only(bottom: 20)) ], diff --git a/lib/main_ui.dart b/lib/main_ui.dart index a84bf1d..9ae3bdb 100644 --- a/lib/main_ui.dart +++ b/lib/main_ui.dart @@ -18,13 +18,10 @@ along with this program. If not, see . import 'dart:ui'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:overmorrow/decoders/decode_wapi.dart'; import 'package:overmorrow/main_screens.dart'; -import 'package:overmorrow/radar.dart'; import 'package:overmorrow/settings_page.dart'; import 'ui_helper.dart'; @@ -42,8 +39,6 @@ class WeatherPage extends StatelessWidget { @override Widget build(BuildContext context) { - // Build the ui for phones - FlutterView view = WidgetsBinding.instance.platformDispatcher.views.first; Size size = view.physicalSize / view.devicePixelRatio; @@ -51,13 +46,6 @@ class WeatherPage extends StatelessWidget { return TabletLayout(data, updateLocation, context); } - //IMPORTANT: i have been testing a new look for Overmorrow - // If you wish to test the old one, uncomment first return - // note: some things might be broken in the old one - - //return PhoneLayout(data, updateLocation, context); - - return NewMain(data: data, updateLocation: updateLocation, context: context, key: Key("${data.place}, ${data.current.surface} ${data.current.image} ${data.provider}"),); @@ -151,579 +139,6 @@ Widget Circles(double width, var data, double bottom, color, {align = Alignment. ); } -Widget NewTimes(var data, bool divider) => Column( - children: - [ - Padding( - padding: const EdgeInsets.all(10), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(left: 15, bottom: 10), - child: Align( - alignment: Alignment.centerLeft, - child: comfortatext(translation('sunrise/sunset', data.settings["Language"]), 19, data.settings, - color: data.current.outline), - ), - ), - Center( - child: Padding( - padding: const EdgeInsets.only(left: 10, right: 10), - child: Container( - height: 50, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all(width: 2, color: data.current.secondary) - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(18), - child: Stack( - children: [ - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.only(left: 20), - child: Icon(CupertinoIcons.sunrise, color: data.current.secondary,), - ), - ), - Align( - alignment: Alignment.centerRight, - child: Padding( - padding: const EdgeInsets.only(right: 20), - child: Icon(CupertinoIcons.sunset, color: data.current.secondary,), - ), - ), - LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Container( - color: data.current.secondary, - height: constraints.maxHeight, - width: constraints.maxWidth * data.sunstatus.sunstatus, - child: Stack( - clipBehavior: Clip.hardEdge, - children: [ - Positioned( - height: constraints.maxHeight, - left: 20, - child: Icon(CupertinoIcons.sunrise, color: data.current.backcolor), - ), - Positioned( - left: constraints.maxWidth - 46, - height: constraints.maxHeight, - child: Icon(CupertinoIcons.sunset, color: data.current.backcolor), - ), - ], - ), - ); - }, - ), - ], - ), - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.only(top: 10, bottom: 10), - child: Stack( - children: [ - Align( - alignment: Alignment.centerLeft, - child: SizedBox( - width: 90, - child: Align( - alignment: Alignment.center, - child: comfortatext(data.sunstatus.sunrise, 18, data.settings, - color: data.current.outline) - ) - ) - ), - Align( - alignment: Alignment.centerRight, - child: SizedBox( - width: 90, - child: Align( - alignment: Alignment.center, - child: comfortatext(data.sunstatus.sunset, 18, data.settings, - color: data.current.outline) - ) - ) - ) - ], - ), - ) - ], - ), - ), - Padding( - padding: const EdgeInsets.only(left: 20, right: 20, bottom: 19, top: 5), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 10), - child: Align( - alignment: Alignment.centerLeft, - child: comfortatext(translation('air quality', data.settings["Language"]), 20, data.settings, - color: data.current.outline), - ), - ), - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - //border: Border.all(width: 1.2, color: data.current.outline) - color: data.current.container - ), - padding: const EdgeInsets.all(13), - child: Row( - children: [ - Column( - children: [ - Container( - height: 85, - width: 85, - decoration: BoxDecoration( - color: data.current.surface, - borderRadius: BorderRadius.circular(20), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.only(top: 5), - child: comfortatext(data.aqi.aqi_index.toString(), 40, data.settings, - color: data.current.backcolor), - ), - ), - ), - Padding( - padding: const EdgeInsets.only(top: 7), - child: Align( - alignment: Alignment.centerLeft, - child: SizedBox( - width: 120, - child: comfortatext( - translation(['good', 'moderate', 'slightly unhealthy', - 'unhealthy', 'very unhealthy', - 'hazardous'][data.aqi.aqi_index - 1], data.settings["Language"]), 16, data.settings, - color: data.current.outline, align: TextAlign.center) - ), - ), - ), - ], - ), - Expanded( - child: Column( - children: [ - aqiDataPoints("PM2.5", data.aqi.pm2_5, data), - aqiDataPoints("PM10", data.aqi.pm10, data), - aqiDataPoints("O3", data.aqi.o3, data), - aqiDataPoints("NO2", data.aqi.no2, data), - ], - ), - ) - ], - ), - ), - ], - ), - ), - RadarMap(data: data, key: Key(data.place),), - Visibility( - visible: divider, - child: Padding( - padding: const EdgeInsets.only(top: 6, right: 30, left: 30), - child: Container( - height: 2, - color: data.current.container, - ), - ), - ), - ], -); - -Widget buildHihiDays(var data) => ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: (BuildContext context, int index) { - if (index < 3) { - final day = data.days[index]; - return Padding( - padding: const EdgeInsets.only(left: 20, right: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(top: 0, bottom: 10), - child: comfortatext(day.name, 19, data.settings, color: data.current.outline) - ), - Padding( - padding: const EdgeInsets.all(2.0), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: day.mm_precip > 0.1 ? data.current.container : data.current.backcolor, - ), - padding: const EdgeInsets.only(top: 8, left: 3, right: 5, bottom: 3), - child: SizedBox( - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.only(left: 10, right: 20), - child: Image.asset( - 'assets/icons/' + day.icon, - fit: BoxFit.contain, - height: 40, - ), - ), - comfortatext(day.text, 22, data.settings, color: data.current.outline), - const Spacer(), - Padding( - padding: const EdgeInsets.only(right: 6), - child: Container( - padding: const EdgeInsets.only(top:7,bottom: 7, left: 7, right: 5), - decoration: BoxDecoration( - //border: Border.all(color: Colors.blueAccent) - color: data.current.surface, - borderRadius: BorderRadius.circular(10) - ), - child: comfortatext(day.minmaxtemp, 18, data.settings, color: data.current.backcolor) - ), - ) - ], - ), - Visibility( - visible: day.mm_precip > 0.1, - child: RainWidget(data, day, data.current.container) - ), - ], - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 6, right: 6, top: 15, bottom: 30), - child: Container( - height: 85, - padding: const EdgeInsets.only(top: 8, bottom: 8, left: 20, right: 20), - decoration: BoxDecoration( - border: Border.all(width: 1.2, color: data.current.secondary), - borderRadius: BorderRadius.circular(20) - ), - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return GridView.count( - padding: const EdgeInsets.all(0), - physics: const NeverScrollableScrollPhysics(), - crossAxisSpacing: 1, - mainAxisSpacing: 1, - crossAxisCount: 2, - childAspectRatio: constraints.maxWidth / constraints.maxHeight, - children: [ - Padding( - padding: const EdgeInsets.only( - left: 8, right: 8), - child: Row( - children: [ - Icon(Icons.water_drop_outlined, - color: data.current.secondary, size: 21), - Padding( - padding: const EdgeInsets.only(left: 10, top: 2), - child: comfortatext('${day.precip_prob}%', 19, data.settings, - color: data.current.secondary), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 8, right: 8), - child: Row( - children: [ - Icon( - Icons.water_drop, color: data.current.secondary, size: 21), - Padding( - padding: const EdgeInsets.only(top: 2, left: 10), - child: comfortatext(day.total_precip.toString() + - data.settings["Precipitation"], 19, data.settings, - color: data.current.secondary), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 8, right: 8), - child: Row( - children: [ - Icon( - CupertinoIcons.wind, color: data.current.secondary, size: 21,), - Padding( - padding: const EdgeInsets.only(top: 2, left: 10), - child: comfortatext('${day.windspeed} ${data - .settings["Wind"]}', 19, data.settings, - color: data.current.secondary), - ), - Padding( - padding: const EdgeInsets.only(left: 5, right: 3), - child: RotationTransition( - turns: AlwaysStoppedAnimation(day.wind_dir / 360), - child: Icon(CupertinoIcons.arrow_up_circle_fill, color: data.current.secondary, size: 18,) - ) - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.only( - left: 8, right: 8), - child: Row( - children: [ - Icon(CupertinoIcons.sun_min, - color: data.current.secondary, size: 21), - Padding( - padding: const EdgeInsets.only(top: 2, left: 10), - child: comfortatext('${day.uv} UV', 19, data.settings, - color: data.current.secondary), - ), - ], - ), - ), - ] - ); - } - ), - ), - ), - buildHours(day.hourly, data), - ], - ), - ); - } - return null; - }, -); - -Widget buildGlanceDay(var data) => Padding( - padding: const EdgeInsets.only(left: 20, right: 20, bottom: 10), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 15), - child: Align( - alignment: Alignment.centerLeft, - child: comfortatext(translation('Daily', data.settings["Language"]), 19, data.settings, color: data.current.outline), - ), - ), - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all(width: 1.2, color: data.current.secondary), - ), - child: ListView.builder( - shrinkWrap: true, - padding: const EdgeInsets.only(top: 5, bottom: 5, left: 10, right: 10), - physics: const NeverScrollableScrollPhysics(), - itemCount: data.days.length - 3, - itemBuilder: (context, index) { - final day = data.days[index + 3]; - const int rain_limit = 2; - return Padding( - padding: const EdgeInsets.only(top: 5, bottom: 5), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(21), - color: day.mm_precip > rain_limit ? data.current.container : data.current.backcolor, - ), - padding: EdgeInsets.all(day.mm_precip > rain_limit ? 8 : 0), - child: Column( - children: [ - Row( - children: [ - Container( - height: 75, - width: 75, - decoration: BoxDecoration( - color: day.mm_precip > rain_limit ? data.current.backcolor : data.current.container, - borderRadius: BorderRadius.circular(20), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - comfortatext(day.name, 18, data.settings, color: data.current.outline), - Container( - padding: const EdgeInsets.all(5), - child: Image.asset( - 'assets/icons/' + day.icon, - fit: BoxFit.contain, - height: 28, - ), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.only(left: 10), - child: Container( - height: 75, - width: 52, - decoration: BoxDecoration( - color: data.current.surface, - borderRadius: BorderRadius.circular(20), - ), - child: Row( - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.arrow_drop_up, color: data.current.backcolor, size: 20,), - Icon(Icons.arrow_drop_down, color: data.current.backcolor, size: 20,), - ], - ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - comfortatext(day.minmaxtemp.split("/")[1], 16, data.settings, color: data.current.backcolor), - comfortatext(day.minmaxtemp.split("/")[0], 16, data.settings,color: data.current.backcolor), - ], - ), - ), - ], - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 10), - child: Container( - height: 75, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all(color: data.current.secondary, width: 1.2) - ), - padding: const EdgeInsets.all(3), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.water_drop_outlined, - color: data.current.secondary, size: 18,), - Padding( - padding: const EdgeInsets.only(left: 2, right: 5), - child: comfortatext('${day.precip_prob}%', 17, data.settings, - color: data.current.secondary), - ), - Icon( - Icons.water_drop, color: data.current.secondary, size: 18,), - Padding( - padding: const EdgeInsets.only(left: 2, right: 2), - child: comfortatext(day.total_precip.toString() + - data.settings["Precipitation"], 17, data.settings, color: data.current.secondary), - ), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - CupertinoIcons.wind, color: data.current.secondary, size: 18,), - Padding( - padding: const EdgeInsets.only(left: 2, right: 2), - child: comfortatext('${day.windspeed} ${data - .settings["Wind"]}', 17, data.settings, color: data.current.secondary), - ), - Padding( - padding: const EdgeInsets.only(left: 3, right: 3, bottom: 1), - child: RotationTransition( - turns: AlwaysStoppedAnimation(day.wind_dir / 360), - child: Icon(CupertinoIcons.arrow_up_circle_fill, - color: data.current.secondary, size: 16,) - ) - ), - ], - ) - ], - ), - ), - ), - ) - ], - ), - Visibility( - visible: day.mm_precip > rain_limit, - child: Padding( - padding: const EdgeInsets.only(top: 5), - child: RainWidget(data, day, data.current.container), - ) - ), - ], - ), - ), - ); - } - ) - ), - ], - ), -); - -Widget buildHours(List hours, data) => SizedBox( - height: 285, - child: ListView( - physics: const BouncingScrollPhysics(), - scrollDirection: Axis.horizontal, - shrinkWrap: true, - children: hours.map((hour) { - return Column( - children: [ - Padding( - padding: const EdgeInsets.only(top: 10, bottom: 10), - child: comfortatext('${hour.temp}°', 22, data.settings, color: data.current.surface), - ), - Stack( - alignment: Alignment.bottomCenter, - children: [ - Container( - width: 15, - height: 100, - decoration: BoxDecoration( - border: Border.all( - color: data.current.secondary, - ), - borderRadius: const BorderRadius.all(Radius.circular(20)) - ), - ), - Container( - width: 15, - height: temp_multiply_for_scale(hour.temp, data.settings['Temperature']!), - decoration: BoxDecoration( - color: data.current.secondary, - borderRadius: const BorderRadius.all(Radius.circular(20)) - ), - ), - ], - ), - Padding( - padding: const EdgeInsets.only(top: 20, left: 3, right: 3), - child: Image.asset( - 'assets/icons/' + hour.icon, - fit: BoxFit.scaleDown, - height: 38, - ), - ), - Padding( - padding: const EdgeInsets.only(top:20, left: 9, right: 9), - child: comfortatext(hour.time, 17, data.settings, color: data.current.surface) - ) - ], - ); - }).toList(), - ), -); - Widget providerSelector(settings, updateLocation, textcolor, highlight, primary, provider, latlng, real_loc) { return Padding( diff --git a/lib/new_displays.dart b/lib/new_displays.dart index 662cc6f..c0ab1b8 100644 --- a/lib/new_displays.dart +++ b/lib/new_displays.dart @@ -17,9 +17,7 @@ along with this program. If not, see . */ import 'dart:math'; -import 'dart:ui'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/settings_page.dart'; diff --git a/lib/radar.dart b/lib/radar.dart index 1d51b97..3ab51ab 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -17,7 +17,6 @@ along with this program. If not, see . */ import 'dart:async'; -import 'dart:math'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -28,442 +27,6 @@ import 'package:overmorrow/settings_page.dart'; import 'package:overmorrow/ui_helper.dart'; import 'package:latlong2/latlong.dart'; -class RadarMap extends StatefulWidget { - - final data; - - const RadarMap({Key? key, required this.data}) : super(key: key); - - @override - _RadarMapState createState() => _RadarMapState(data); -} - -class _RadarMapState extends State { - int currentFrameIndex = 0; - late Timer timer; - - final data; - _RadarMapState(this.data); - bool isPlaying = false; - - @override - void initState() { - super.initState(); - - timer = Timer.periodic(const Duration(milliseconds: 1500), (Timer t) { - if (isPlaying) { - setState(() { - currentFrameIndex = - ((currentFrameIndex + 1) % data.radar.images.length).toInt(); - }); - } - }); - } - - @override - void dispose() { - timer.cancel(); - super.dispose(); - } - - void togglePlayPause() { - setState(() { - isPlaying = !isPlaying; - }); - } - - @override - Widget build(BuildContext context) { - return Column( - children: [ - Padding( - padding: const EdgeInsets.only(left: 20, bottom: 0), - child: Align( - alignment: Alignment.centerLeft, - child: comfortatext(translation('radar', data.settings["Language"]), 19, data.settings, - color: data.current.onSurface), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 20, right: 20, top: 20, bottom: 10), - child: AspectRatio( - aspectRatio: 1.5, - child: Container( - decoration: BoxDecoration( - color: WHITE, - borderRadius: BorderRadius.circular(20), - border: Border.all(width: 1.2, color: data.current.secondary) - ), - child: Stack( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(20), - child: FlutterMap( - options: MapOptions( - onTap: (tapPosition, point) => { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => RadarPage(data: data,)), - ) - }, - initialCenter: LatLng(data.lat, data.lng), - initialZoom: 6, - backgroundColor: WHITE, - keepAlive: true, - maxZoom: 6, - minZoom: 6, - interactionOptions: const InteractionOptions(flags: InteractiveFlag.drag | InteractiveFlag.flingAnimation), - cameraConstraint: CameraConstraint.containCenter( - bounds: LatLngBounds( - LatLng(data.lat - 3, data.lng - 3), - LatLng(data.lat + 3, data.lng + 3), - ), - ), - ), - children: [ - TileLayer( - urlTemplate: data.settings["Color mode"] == "dark" - ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' - : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', - ), - TileLayer( - urlTemplate: data.radar.images[currentFrameIndex] + "/256/{z}/{x}/{y}/8/1_1.png", - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.only(right: 10, top: 10), - child: Align( - alignment: Alignment.topRight, - child: Hero( - tag: 'switch', - child: SizedBox( - height: 48, - width: 48, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 10, - padding: const EdgeInsets.all(10), - backgroundColor: data.current.backcolor, - //side: BorderSide(width: 3, color: main), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20) - ), - ), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => RadarPage(data: data,)), - ); - }, - child: Icon(Icons.open_in_full, color: data.current.surface, size: 25,), - ), - ), - ), - ), - ), - ], - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 200), - transitionBuilder: (Widget child, Animation animation) { - return ScaleTransition(scale: animation, child: child,); - }, - child: Hero( - tag: 'playpause', - key: ValueKey (isPlaying), - child: SizedBox( - height: 48, - width: 48, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.all(10), - backgroundColor: data.current.secondary, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20) - ) - ), - onPressed: () async { - togglePlayPause(); - }, - child: Icon(isPlaying? Icons.pause : Icons.play_arrow, color: data.current.backcolor, size: 18,), - ), - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Hero( - tag: 'progress', - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Container( - height: 50, - width: constraints.maxWidth, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all(width: 1.2, color: data.current.secondary)), - child: ClipRRect( - borderRadius: BorderRadius.circular(18), - child: Stack( - children: [ - Container( - color: data.current.secondary, - width: constraints.maxWidth * - (max(currentFrameIndex - 1, 0) / data.radar.images.length), - ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - transitionBuilder: (Widget child, Animation animation) => - SizeTransition(sizeFactor: animation, axis: Axis.horizontal, child: child), - child: Container( - key: ValueKey(currentFrameIndex), - color: data.current.secondary, - width: constraints.maxWidth * - (currentFrameIndex / data.radar.images.length), - ), - ), - ], - ), - ), - ); - } - ), - ), - ), - ) - ], - ), - ) - ], - ); - } -} - -class RadarPage extends StatefulWidget { - final data; - - const RadarPage({Key? key, this.data}) : super(key: key); - - @override - _RadarPageState createState() => _RadarPageState(data: data); -} - -class _RadarPageState extends State { - final data; - - _RadarPageState({this.data}); - - int currentFrameIndex = 0; - late Timer timer; - bool isPlaying = false; - - @override - void initState() { - super.initState(); - - timer = Timer.periodic(const Duration(milliseconds: 1500), (Timer t) { - if (isPlaying) { - setState(() { - currentFrameIndex = - ((currentFrameIndex + 1) % data.radar.images.length).toInt(); - }); - } - }); - } - - @override - void dispose() { - timer.cancel(); - super.dispose(); - } - - void togglePlayPause() { - setState(() { - isPlaying = !isPlaying; - }); - } - - void goBack() { - Navigator.pop(context); - } - - @override - Widget build(BuildContext context) { - double x = MediaQuery.of(context).padding.top; - Color main = data.current.onSurface; - Color top = lighten(data.current.container, 0.1); - return Stack( - children: [ - FlutterMap( - options: MapOptions( - initialCenter: LatLng(data.lat, data.lng), - initialZoom: 5, - minZoom: 2, - maxZoom: 8, - - backgroundColor: WHITE, - interactionOptions: const InteractionOptions(flags: InteractiveFlag.all & ~InteractiveFlag.rotate,), - ), - children: [ - Container( - color: data.settings["Color mode"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), - ), - TileLayer( - urlTemplate: data.settings["Color mode"] == "dark" - ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' - : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', - ), - TileLayer( - urlTemplate: data.radar.images[currentFrameIndex] + "/256/{z}/{x}/{y}/8/1_1.png", - ), - TileLayer( - urlTemplate: data.settings["Color mode"] == "dark" - ? 'https://{s}.basemaps.cartocdn.com/dark_only_labels/{z}/{x}/{y}.png' - : 'https://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', - ), - ], - ), - Align( - alignment: Alignment.bottomCenter, - child: Container( - constraints: const BoxConstraints(maxWidth: 500), - child: Padding( - padding: const EdgeInsets.only(left: 20, bottom: 20, right: 20), - child: Material( - borderRadius: BorderRadius.circular(20), - elevation: 10, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(18), - color: top, - ), - padding: const EdgeInsets.all(6), - child: Row( - children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 200), - transitionBuilder: (Widget child, Animation animation) { - return ScaleTransition(scale: animation, child: child,); - }, - child: Hero( - key: ValueKey (isPlaying), - tag: 'playpause', - child: SizedBox( - height: 48, - width: 48, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 8, - padding: const EdgeInsets.all(10), - backgroundColor: top, - //side: const BorderSide(width: 5, color: WHITE), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16) - ), - ), - onPressed: () async { - togglePlayPause(); - }, - child: Icon(isPlaying? Icons.pause : Icons.play_arrow, color: main, size: 18,), - ), - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 6), - child: Hero( - tag: 'progress', - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Material( - borderRadius: BorderRadius.circular(13), - elevation: 8, - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: Container( - height: 48, - color: top, - child: Stack( - children: [ - Container( - color: main, - width: constraints.maxWidth * - (max(currentFrameIndex - 1, 0) / data.radar.images.length), - ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - transitionBuilder: (Widget child, Animation animation) => - SizeTransition(sizeFactor: animation, axis: Axis.horizontal, child: child), - child: Container( - key: ValueKey(currentFrameIndex), - color: main, - width: constraints.maxWidth * - (currentFrameIndex / data.radar.images.length), - ), - ), - ], - ), - ), - ), - ); - } - ), - ), - ), - ) - ], - ), - ), - ), - ), - ), - ), - Padding( - padding: EdgeInsets.only(right: 20, top: x + 20), - child: Align( - alignment: Alignment.topRight, - child: Hero( - tag: 'switch', - child: SizedBox( - height: 52, - width: 52, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - elevation: 10, - padding: const EdgeInsets.all(10), - backgroundColor: top, - //side: BorderSide(width: 3, color: main), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20) - ), - ), - onPressed: () { - Navigator.of(context).pop(); - }, - child: Icon(Icons.close_fullscreen, color: main, size: 26,), - ), - ), - ), - ), - ) - ], - ); - } -} - - class RadarSmall extends StatefulWidget { final data; @@ -572,7 +135,7 @@ class _RadarSmallState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => RadarPage(data: data,)), + builder: (context) => RadarBig(data: data,)), ) }, initialCenter: LatLng(data.lat, data.lng), diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 943edb6..6fa6b6e 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -16,7 +16,6 @@ along with this program. If not, see . */ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; @@ -25,11 +24,9 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:overmorrow/donation_page.dart'; import 'package:overmorrow/settings_screens.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'decoders/decode_wapi.dart'; import 'decoders/extra_info.dart'; import 'languages.dart'; import 'main.dart'; -import 'main_ui.dart'; import 'ui_helper.dart'; Map> settingSwitches = { @@ -472,54 +469,6 @@ Widget settingEntry(icon, text, settings, highlight, updatePage, textcolor, prim ); } -Widget NavButton(text, settings, textcolor, icon) { - return Row( - children: [ - Padding( - padding: const EdgeInsets.only(left: 8, right: 12, top: 15, bottom: 15), - child: Icon(icon, color: textcolor, size: 26,), - ), - comfortatext(text, 21, settings, color: textcolor), - ], - ); -} - -Widget ColorCircle(name, outline, inside, settings, updatePage, {w = 2, tap = 0}) { - - return Expanded( - child: GestureDetector( - onTap: () { - HapticFeedback.mediumImpact(); - if (tap == 0) { - return; - } - else { - updatePage("Color mode", name); - } - }, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(left: 4, right: 4, bottom: 10), - child: AspectRatio( - aspectRatio: 1, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(200), - border: Border.all(width: w * 1.0, color: outline), - color: inside - ), - child: tap == 1 ? Center(child: comfortatext(name[0], 20, settings, color: outline)) - : Container(), - ), - ), - ), - ], - ), - ), - ); -} - class SettingsPage extends StatefulWidget { final primary; @@ -605,204 +554,6 @@ Widget SettingsMain(Color primary, Map? settings, Function updat ); } -Widget settingsMain(Map settings, Function updatePage, Image image, List colors, - allColors) { - - Color containerLow = colors[6]; - Color onSurface = colors[4]; - Color primary = colors[1]; - Color primaryLight = colors[2]; - Color surface = colors[0]; - Color colorpop = colors[12]; - Color desc_color = colors[13]; - - - //var entryList = settings.entries.toList(); - return Container( - padding: const EdgeInsets.only(left: 20, right: 15), - color: containerLow, - child: SingleChildScrollView( - physics: const BouncingScrollPhysics(), - child: Center( - child: Container( - constraints: const BoxConstraints(maxWidth: 800), - padding: const EdgeInsets.all(2), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - - /* - NavButton('Appearance', settings, textcolor, Icons.color_lens), - NavButton('Language', settings, textcolor, Icons.language), - NavButton('Units', settings, textcolor, Icons.graphic_eq), - NavButton('Advanced', settings, textcolor, Icons.code), - - */ - - - Padding( - padding: const EdgeInsets.only(left: 10, right: 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(right: 20), - child: Icon(Icons.palette_outlined, color: primary, ), - ), - Expanded( - flex: 10, - child: comfortatext(translation('Color mode', settings["Language"]!), 20, settings, - color: onSurface), - ), - const Spacer(), - comfortatext(settings["Color mode"]!, 20, settings, color: primaryLight) - ], - ), - ), - Padding( - padding: const EdgeInsets.only(top: 40, bottom: 30), - child: SizedBox( - height: 300, - child: Align( - alignment: Alignment.center, - child: AspectRatio( - aspectRatio: 0.72, - child: Container( - decoration: BoxDecoration( - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20)), - color: surface, - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(20), - child: Column( - children: [ - SizedBox( - height: 220, - child: Stack( - children: [ - ParrallaxBackground(image: image, color: surface), - Padding( - padding: const EdgeInsets.only(left: 10, bottom: 15), - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - comfortatext("${unit_coversion(29, settings["Temperature"]!).toInt()}°", 36, settings, color: colorpop), - comfortatext(translation("Clear Sky", settings["Language"]!), 20, - settings, color: desc_color) - ], - ), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.only(top: 10, right: 4, left: 4), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - //ColorCircle(settings["Color mode"], primary, surface, settings, updatePage), - ColorCircle("", primary, surface, settings, updatePage), - ColorCircle("", primary, surface, settings, updatePage), - ColorCircle("", primary, surface, settings, updatePage), - ColorCircle("", primary, surface, settings, updatePage) - ], - ), - ) - ], - ), - ), - ), - ), - ), - ), - ), - - Padding( - padding: const EdgeInsets.only(left: 20, right: 20), - //somehow this was the only way i found to limit the width. - //otherwise the row would disregard the max size and expand beyond - child: Container( - constraints: const BoxConstraints(maxHeight: 90), - child: Align( - alignment: Alignment.center, - child: AspectRatio( - aspectRatio: 4, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - ColorCircle("original", allColors[0][1], allColors[0][0], settings, updatePage, w: 4, tap: 1), - ColorCircle("colorful", allColors[1][1], allColors[1][0], settings, updatePage, w: 4, tap: 1), - ColorCircle("mono", allColors[2][1], allColors[2][0], settings, updatePage, w: 4, tap: 1), - ColorCircle("light", allColors[3][1], allColors[3][0], settings, updatePage, w: 4, tap: 1), - ColorCircle("dark", allColors[4][1], allColors[4][0], settings, updatePage, w: 4, tap: 1), - ] - ), - ), - ), - ), - ), - - settingEntry(Icons.invert_colors_on, "Color source", settings, containerLow, updatePage, - onSurface, primaryLight, primary), - settingEntry(Icons.landscape_outlined, "Image source", settings, containerLow, updatePage, - onSurface, primaryLight, primary), - - Padding( - padding: const EdgeInsets.only(top: 20, bottom: 20, left: 12, right: 12), - child: Container( - height: 2, - decoration: BoxDecoration( - color: primaryLight, - borderRadius: BorderRadius.circular(2) - ), - ), - ), - - settingEntry(CupertinoIcons.globe, "Language", settings, containerLow, updatePage, - onSurface, primaryLight, primary), - settingEntry(Icons.access_time_filled_sharp, "Time mode", settings, onSurface, updatePage, - onSurface, primaryLight, primary), - settingEntry(CupertinoIcons.textformat_size, "Font size", settings, onSurface, updatePage, - onSurface, primaryLight, primary), - - settingEntry(Icons.manage_search_outlined, "Search provider", settings, onSurface, updatePage, - onSurface, primaryLight, primary), - - Padding( - padding: const EdgeInsets.only(top: 20, bottom: 20, left: 12, right: 12), - child: Container( - height: 2, - decoration: BoxDecoration( - color: primaryLight, - borderRadius: BorderRadius.circular(2) - ), - ), - ), - - settingEntry(CupertinoIcons.thermometer, "Temperature", settings, onSurface, updatePage, - onSurface, primaryLight, primary), - settingEntry(CupertinoIcons.drop_fill, "Precipitation", settings, onSurface, updatePage, - onSurface, primaryLight, primary), - settingEntry(CupertinoIcons.wind, "Wind", settings, onSurface, updatePage, - onSurface, primaryLight, primary), - - const SizedBox( - height: 40, - ) - - - ] - ), - ), - ), - ), - ); -} - - class MyDrawer extends StatelessWidget { final backupprimary; diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 53ac8cb..12b05fd 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -410,45 +410,6 @@ Widget NewAqiDataPoints(String name, double value, var data) { ); } -Widget aqiDataPoints(String name, double value, var data) { - return Align( - alignment: Alignment.centerRight, - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - double width; - if (constraints.maxWidth > 100) { - width = 100; - } - else {width = constraints.maxWidth;} - - return SizedBox( - width: width, - child: Padding( - padding: const EdgeInsets.only(left: 10, bottom: 1.5, top: 1.5), - child: Row( - children: [ - comfortatext(name, 16, data.settings, color: data.current.primary, - weight: FontWeight.w400), - const Spacer(), - Container( - padding: const EdgeInsets.only(top:4,bottom: 3, left: 4, right: 4), - decoration: BoxDecoration( - //border: Border.all(color: Colors.blueAccent) - color: data.current.primaryLight, - borderRadius: BorderRadius.circular(10) - ), - child: comfortatext(value.toString(), 15, data.settings, - color: data.current.onPrimaryLight, weight: FontWeight.w500) - ) - ], - ), - ) - ); - } - ) - ); -} - Widget RainWidget(data, day, highlight) { List hours = day.hourly_for_precip; From 3fdcd584ec4d6a1fa1cf07bfce343c8968513977 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 30 Aug 2024 14:38:19 +0200 Subject: [PATCH 126/129] fixed 2 fatal bugs --- lib/settings_page.dart | 9 +++++++-- lib/settings_screens.dart | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/settings_page.dart b/lib/settings_page.dart index 6fa6b6e..48401ab 100644 --- a/lib/settings_page.dart +++ b/lib/settings_page.dart @@ -289,11 +289,16 @@ List getNetworkColors(List palette, settings, {force = "-1"}) { Future> getMainColor(settings, primary, back, image) async { List colors; - final String mode = settings["Color mode"]; + String mode = settings["Color mode"]; List x = await getImageColors(image, mode, settings); List palette = x[0]; + if (mode == "auto") { + var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + mode = brightness == Brightness.dark ? "dark" : "light"; + } + if ((mode == "light" || mode == "dark") || settings["Image source"] == 'network' || settings["Color source"] == 'wallpaper') { colors = getNetworkColors(palette, settings); @@ -329,7 +334,7 @@ Future> getTotalColor(settings, primary, back, image) async { else { allColor.add(getColors(primary, back, settings, 0, force: "original")); allColor.add(getColors(primary, back, settings, 0, force: "colorful")); - allColor.add(getColors(primary, back, settings, 0, force: "dark")); + allColor.add(getColors(primary, back, settings, 0, force: "mono")); allColor.add(getNetworkColors(lightPalette, settings, force: "light")); //because the light and dark use the allColor.add(getNetworkColors(darkPalette, settings, force: "dark")); // material palette generator anyway } diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index 19a8016..1109739 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -189,6 +189,8 @@ class _AppearancePageState extends State { final colors = allColors[["original", "colorful", "mono", "light", "dark"] .indexOf(x)]; + print((colors, x)); + Color highlight = colors[7]; Color primaryLight = colors[2]; Color primary = colors[1]; From c9521a02237307ffe7cdb87f97d17cd198d2dc88 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Fri, 30 Aug 2024 15:01:36 +0200 Subject: [PATCH 127/129] translated pop-up asking you if you want network images --- lib/languages.dart | 71 +++++++++++++++++++++++++++++++++++++++++ lib/main_screens.dart | 15 +++++---- lib/weather_refact.dart | 1 - 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/lib/languages.dart b/lib/languages.dart index 8db2191..4f25d51 100644 --- a/lib/languages.dart +++ b/lib/languages.dart @@ -1459,6 +1459,77 @@ Map> mainTranslate = { 'ώ', ], + "Overmorrow 2.4.0 introduces Network images!": [ + 'Overmorrow 2.4.0 introduces Network images!', + 'Az Overmorrow 2.4.0 hálózati képeket vezet be!', + '¡Overmorrow 2.4.0 introduce imágenes de red!', + 'Overmorrow 2.4.0 introduit des images réseau !', + 'Overmorrow 2.4.0 führt Netzwerkbilder ein!', + 'Overmorrow 2.4.0 introduce immagini di rete!', + 'Overmorrow 2.4.0 introduz imagens de rede!', + 'Overmorrow 2.4.0 представляет сетевые изображения!', + 'Overmorrow 2.4.0 引入了网络图像!', + 'Overmorrow 2.4.0 にネットワーク画像を導入!', + 'Overmorrow 2.4.0 wprowadza obrazy z sieci!', + 'Το Overmorrow 2.4.0 εισάγει εικόνες δικτύου!' + ], + "Would you like to enable network images?": [ + 'Would you like to enable network images?', + 'Szeretnéd engedélyezni a hálózati képeket?', + '¿Te gustaría habilitar imágenes de red?', + 'Souhaitez-vous activer les images réseau ?', + 'Möchten Sie Netzwerkbilder aktivieren?', + 'Vuoi abilitare le immagini di rete?', + 'Gostaria de ativar as imagens de rede?', + 'Хотите включить сетевые изображения?', + '您想启用网络图像吗?', + 'ネットワーク画像を有効にしますか?', + 'Czy chcesz włączyć obrazy z sieci?', + 'Θέλετε να ενεργοποιήσετε τις εικόνες δικτύου;' + ], + "note: you can always change later by going into settings > appearance > image source": [ + 'note: you can always change later by going into settings > appearance > image source', + 'megjegyzés: később bármikor módosíthatja a beállítások > megjelenés > kép forrása menüpontban', + 'nota: siempre puedes cambiarlo más tarde en configuración > apariencia > fuente de imagen', + 'remarque : vous pouvez toujours modifier plus tard en allant dans paramètres > apparence > source d\'image', + 'Hinweis: Sie können dies später jederzeit unter Einstellungen > Erscheinungsbild > Bildquelle ändern', + 'nota: puoi sempre modificarlo in seguito andando su impostazioni > aspetto > sorgente immagine', + 'nota: você pode sempre mudar depois indo para configurações > aparência > fonte de imagem', + 'примечание: вы всегда можете изменить это позже в настройках > внешний вид > источник изображения', + '注意:您可以随时通过进入设置 > 外观 > 图片来源来更改', + '注意:設定 > 外観 > 画像のソース で後からいつでも変更できます', + 'uwaga: zawsze możesz to zmienić później, przechodząc do ustawień > wygląd > źródło obrazu', + 'σημείωση: μπορείτε πάντα να αλλάξετε αργότερα πηγαίνοντας στις ρυθμίσεις > εμφάνιση > πηγή εικόνας' + ], + "Disable": [ + 'Disable', + 'Letiltás', + 'Desactivar', + 'Désactiver', + 'Deaktivieren', + 'Disabilita', + 'Desativar', + 'Отключить', + '禁用', + '無効化', + 'Wyłącz', + 'Απενεργοποίηση' + ], + "Enable": [ + 'Enable', + 'Engedélyezés', + 'Habilitar', + 'Activer', + 'Aktivieren', + 'Abilita', + 'Ativar', + 'Включить', + '启用', + '有効化', + 'Włącz', + 'Ενεργοποίηση' + ], + 'Search translation': [ //used for getting the codes used for translation of city names //If none are available then en (english) is the default // for more info visit https://open-meteo.com/en/docs/geocoding-api diff --git a/lib/main_screens.dart b/lib/main_screens.dart index f64c835..004a03a 100644 --- a/lib/main_screens.dart +++ b/lib/main_screens.dart @@ -55,26 +55,27 @@ class _NewMainState extends State { super.initState(); if (data.settings['networkImageDialogShown'] == "false") { WidgetsBinding.instance.addPostFrameCallback((_) { - _showFeatureDialog(context); + _showFeatureDialog(context, data.settings); }); } } - void _showFeatureDialog(BuildContext context) { + void _showFeatureDialog(BuildContext context, settings) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( backgroundColor: data.current.surface, - title: comfortatext("Overmorrow 2.4.0 introduces Network images!", 20, data.settings, color: data.current.primary), + title: comfortatext(translation("Overmorrow 2.4.0 introduces Network images!", settings["Language"]), 20, data.settings, color: data.current.primary), content: SizedBox( height: 100, child: Column( children: [ - comfortatext("Would you like to enable network images?", 16, data.settings, + comfortatext(translation("Would you like to enable network images?", settings["Language"]), 16, data.settings, color: data.current.onSurface), const SizedBox(height: 20,), - comfortatext("note: you can always change later by going into settings > appearance > image source", 13, data.settings, + comfortatext(translation("note: you can always change later by going into settings > appearance > image source", + settings["Language"]), 13, data.settings, color: data.current.onSurface), ], ), @@ -93,7 +94,7 @@ class _NewMainState extends State { ), ); }, - child: comfortatext("Disable", 17, data.settings, color: data.current.outline, weight: FontWeight.w600), + child: comfortatext(translation("Disable", settings["Language"]), 17, data.settings, color: data.current.outline, weight: FontWeight.w600), ), TextButton( onPressed: () async { @@ -108,7 +109,7 @@ class _NewMainState extends State { ), ); }, - child: comfortatext("Enable", 17, data.settings, color: data.current.primary, weight: FontWeight.w600), + child: comfortatext(translation("Enable", settings["Language"]), 17, data.settings, color: data.current.primary, weight: FontWeight.w600), ), ], ); diff --git a/lib/weather_refact.dart b/lib/weather_refact.dart index 378b522..6081dc8 100644 --- a/lib/weather_refact.dart +++ b/lib/weather_refact.dart @@ -16,7 +16,6 @@ along with this program. If not, see . */ -import 'dart:ui'; import 'package:overmorrow/Icons/overmorrow_weather_icons_icons.dart'; import 'package:flutter/material.dart'; From 155f6360c9491379544376f09fd2dcdb65b595c3 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sun, 1 Sep 2024 11:19:27 +0200 Subject: [PATCH 128/129] fixed some issues i found while testing, bumped version twice --- android/app/build.gradle | 4 ++-- lib/decoders/extra_info.dart | 26 +++++++++++--------------- lib/new_forecast.dart | 19 ++++++++++++------- lib/radar.dart | 31 ++++++++++++++++++++++++------- lib/settings_screens.dart | 2 -- 5 files changed, 49 insertions(+), 33 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 74b9bc7..429651c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -51,8 +51,8 @@ android { // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdkVersion flutter.minSdkVersion targetSdkVersion flutter.targetSdkVersion - versionCode 39 - versionName "2.3.11" + versionCode 41 + versionName "2.4.1" } buildTypes { diff --git a/lib/decoders/extra_info.dart b/lib/decoders/extra_info.dart index 0215d69..7dfb41e 100644 --- a/lib/decoders/extra_info.dart +++ b/lib/decoders/extra_info.dart @@ -50,7 +50,7 @@ Future> getUnsplashImage(String _text, String real_loc, double lat String text_query = textToUnsplashText[_text]![0]; String placeName = shouldUsePlaceName[_text]! ? " $loc" : ""; - print(("textquery", "$text_query, $loc", _text, text_query + placeName)); + //print(("textquery", "$text_query, $loc", _text, text_query + placeName)); final params2 = { 'client_id': access_key, @@ -83,7 +83,7 @@ Future> getUnsplashImage(String _text, String real_loc, double lat } var desc1 = unsplash_body[i]["description"] ?? " "; - var desc2 = unsplash_body[i]["links"]["html"] ?? " "; + //var desc2 = unsplash_body[i]["links"]["html"] ?? " "; var desc3 = unsplash_body[i]["alt_description"] ?? " "; String desc = desc1.toLowerCase() + " " + desc3.toLowerCase(); @@ -99,7 +99,7 @@ Future> getUnsplashImage(String _text, String real_loc, double lat } } if (desc.contains(lookFor)) { - print(("punished1", textToUnsplashText[keys2[x]]![y], reward, lookFor, textToUnsplashText[_text])); + //print(("punished1", textToUnsplashText[keys2[x]]![y], reward, lookFor, textToUnsplashText[_text])); unaccuracy += reward; // i had to reverse it } } @@ -107,18 +107,18 @@ Future> getUnsplashImage(String _text, String real_loc, double lat for (int x = 0; x < textFilter.length; x ++) { if (desc.contains(keys1[x])) { - print(("punished2", keys1[x], -textFilter[keys1[x]]!)); + //print(("punished2", keys1[x], -textFilter[keys1[x]]!)); unaccuracy -= textFilter[keys1[x]]!; // i had to reverse it } } double ratings = unsplash_body[i]["likes"] * 0.02 ?? 0; ratings += unsplash_body[i]["downloads"] * 0.01 ?? 0; - print(("ratings", ratings)); + //print(("ratings", ratings)); unaccuracy -= min(ratings, 2000); - print((i, unaccuracy.toStringAsFixed(6), (desc1 ?? "null").trim() + ", " + desc2, unsplash_body[i]["likes"], unsplash_body[i]["downloads"])); + //print((i, unaccuracy.toStringAsFixed(6), (desc1 ?? "null").trim() + ", " + desc2, unsplash_body[i]["likes"], unsplash_body[i]["downloads"])); if (unaccuracy < best) { index = i; best = unaccuracy; @@ -126,14 +126,14 @@ Future> getUnsplashImage(String _text, String real_loc, double lat } String image_path = unsplash_body[index]["urls"]["regular"]; - print(index); - print(unsplash_body[index]["links"]["html"]); + //print(index); + //print(unsplash_body[index]["links"]["html"]); final String userLink = (unsplash_body[index]["user"]["links"]["html"]) ?? ""; final String username = unsplash_body[index]["user"]["name"] ?? ""; final String photoLink = unsplash_body[index]["links"]["html"] ?? ""; - print((username, userLink)); + //print((username, userLink)); return [Image(image: CachedNetworkImageProvider(image_path), fit: BoxFit.cover, width: double.infinity, height: double.infinity,), username, userLink, photoLink]; @@ -181,7 +181,6 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { //because they are too common double v = paliColors[i].red * 1 + paliColors[i].green * 1 - paliColors[i].blue * 5.0; if (v > bestValue) { - print(("better", i)); bestValue = v.round(); primeColor = paliColors[i]; } @@ -203,10 +202,9 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { int bestDif = difFromBackColors(bestcolor, dominant); int base = (diffBetweenBackColors(dominant) * 0.7).round(); - print(("base", base)); + //print(("base", base)); if (bestDif <= base + 120) { - print("trying"); for (int i = 1; i < 5; i++) { //LIGHT Color newcolor = lighten(startcolor, i / 4); @@ -229,9 +227,7 @@ Future> getImageColors(Image Uimage, color_mode, settings) async { Color desc_color = used_colors[0]; int desc_dif = difFromBackColors(desc_color, dominant); - print(("diffs", bestDif, desc_dif)); - - print(("desc_dif", desc_dif)); + //print(("diffs", bestDif, desc_dif)); if (desc_dif < base + 100) { desc_color = bestcolor; diff --git a/lib/new_forecast.dart b/lib/new_forecast.dart index 07cf4a6..237cccb 100644 --- a/lib/new_forecast.dart +++ b/lib/new_forecast.dart @@ -935,13 +935,18 @@ Widget GlanceDayEntry(data, index, day, onExpandTapped) { ), ), Padding( - padding: const EdgeInsets.only(right: 17), - child: GestureDetector( - child: Icon(Icons.expand_more, color: data - .current.primaryLight, size: 20,), - onTap: () { - onExpandTapped(index); - }, + padding: const EdgeInsets.only(right: 10), + child: SizedBox( + width: 28, + child: IconButton( + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + icon: Icon(Icons.expand_more, color: data + .current.primaryLight, size: 20,), + onPressed: () { + onExpandTapped(index); + }, + ), ), ), ], diff --git a/lib/radar.dart b/lib/radar.dart index 3ab51ab..be49719 100644 --- a/lib/radar.dart +++ b/lib/radar.dart @@ -20,6 +20,7 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -100,6 +101,14 @@ class _RadarSmallState extends State { @override Widget build(BuildContext context) { + + String mode = data.settings["Color mode"]; + + if (mode == "auto") { + var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + mode = brightness == Brightness.dark ? "dark" : "light"; + } + return Column( children: [ Padding( @@ -140,7 +149,7 @@ class _RadarSmallState extends State { }, initialCenter: LatLng(data.lat, data.lng), initialZoom: 6, - backgroundColor: data.settings["Color mode"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), + backgroundColor: mode == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), keepAlive: true, maxZoom: 6, minZoom: 6, @@ -156,7 +165,7 @@ class _RadarSmallState extends State { ), children: [ TileLayer( - urlTemplate: data.settings["Color mode"] == "dark" + urlTemplate: mode == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', ), @@ -402,7 +411,15 @@ class _RadarBigState extends State { @override Widget build(BuildContext context) { double x = MediaQuery.of(context).padding.top; - + + String mode = data.settings["Color mode"]; + + if (mode == "auto") { + var brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness; + mode = brightness == Brightness.dark ? "dark" : "light"; + } + + return Scaffold( body: Stack( children: [ @@ -413,15 +430,15 @@ class _RadarBigState extends State { minZoom: 2, maxZoom: 8, - backgroundColor: data.settings["Color mode"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), + backgroundColor: mode == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), interactionOptions: const InteractionOptions(flags: InteractiveFlag.all & ~InteractiveFlag.rotate,), ), children: [ Container( - color: data.settings["Color mode"] == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), + color: mode == "dark"? const Color(0xff262626) : const Color(0xffD4DADC), ), TileLayer( - urlTemplate: data.settings["Color mode"] == "dark" + urlTemplate: mode == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', ), @@ -429,7 +446,7 @@ class _RadarBigState extends State { urlTemplate: data.radar.images[currentFrameIndex.toInt()] + "/256/{z}/{x}/{y}/8/1_1.png", ), TileLayer( - urlTemplate: data.settings["Color mode"] == "dark" + urlTemplate: mode == "dark" ? 'https://{s}.basemaps.cartocdn.com/dark_only_labels/{z}/{x}/{y}.png' : 'https://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', ), diff --git a/lib/settings_screens.dart b/lib/settings_screens.dart index 1109739..19a8016 100644 --- a/lib/settings_screens.dart +++ b/lib/settings_screens.dart @@ -189,8 +189,6 @@ class _AppearancePageState extends State { final colors = allColors[["original", "colorful", "mono", "light", "dark"] .indexOf(x)]; - print((colors, x)); - Color highlight = colors[7]; Color primaryLight = colors[2]; Color primary = colors[1]; From d1be38d367623766e98f5e98ad0e40a3c9672285 Mon Sep 17 00:00:00 2001 From: bmaroti9 Date: Sun, 1 Sep 2024 11:23:54 +0200 Subject: [PATCH 129/129] some minor fix to the rain chart which i forgot about --- lib/ui_helper.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ui_helper.dart b/lib/ui_helper.dart index 12b05fd..ac213e5 100644 --- a/lib/ui_helper.dart +++ b/lib/ui_helper.dart @@ -421,13 +421,14 @@ Widget RainWidget(data, day, highlight) { } return Padding( - padding: const EdgeInsets.only(left: 13, right: 13, top: 15), + padding: const EdgeInsets.only(left: 10, right: 10, top: 15), child: Container( constraints: const BoxConstraints(minWidth: 0, maxWidth: 450), decoration: BoxDecoration( borderRadius: BorderRadius.circular(18), //color: data.current.containerLow, border: data.settings["Color mode"] == "dark" || data.settings["Color mode"] == "light" + || data.settings["Color mode"] == "auto" ? Border.all(width: 3, color: highlight) : Border.all(width: 1.6, color: data.current.primaryLight) @@ -435,7 +436,7 @@ Widget RainWidget(data, day, highlight) { child: Column( children: [ Padding( - padding: const EdgeInsets.only(top: 14, right: 18, left: 18), + padding: const EdgeInsets.only(top: 14, right: 15, left: 18), child: AspectRatio( aspectRatio: 2.2, child: MyChart(precip, data, highlight)