From aa125fcdc1b2f80894ea5aec36eacb9f59a9df1d Mon Sep 17 00:00:00 2001 From: Yoshi Date: Sun, 7 Jul 2024 14:49:45 +0300 Subject: [PATCH] Add search cards --- lib/app/controller/controller.dart | 32 ++--- .../modules/cards/view/list_weather_card.dart | 124 +++++++----------- .../cards/widgets/weather_card_list.dart | 115 ++++++++++++++++ lib/app/modules/settings/view/settings.dart | 8 +- lib/app/widgets/text_form.dart | 3 + lib/main.dart | 97 +++++++------- pubspec.lock | 48 ++++--- pubspec.yaml | 12 +- 8 files changed, 271 insertions(+), 168 deletions(-) create mode 100644 lib/app/modules/cards/widgets/weather_card_list.dart diff --git a/lib/app/controller/controller.dart b/lib/app/controller/controller.dart index afd0452..56149f2 100644 --- a/lib/app/controller/controller.dart +++ b/lib/app/controller/controller.dart @@ -472,7 +472,7 @@ class WeatherController extends GetxController { return imagePath; } - void notlification(MainWeatherCache mainWeatherCache) async { + void notification(MainWeatherCache mainWeatherCache) async { DateTime now = DateTime.now(); int startHour = timeConvert(timeStart).hour; int endHour = timeConvert(timeEnd).hour; @@ -483,20 +483,20 @@ class WeatherController extends GetxController { if (notificationTime.isAfter(now) && notificationTime.hour >= startHour && notificationTime.hour <= endHour) { - for (var j = 0; j < mainWeatherCache.timeDaily!.length; j++) { - if (mainWeatherCache.timeDaily![j].day == notificationTime.day) { - NotificationShow().showNotification( - UniqueKey().hashCode, - '$city: ${mainWeatherCache.temperature2M![i]}°', - '${StatusWeather().getText(mainWeatherCache.weathercode![i])} · ${StatusData().getTimeFormat(mainWeatherCache.time![i])}', - notificationTime, - StatusWeather().getImageNotification( - mainWeatherCache.weathercode![i], - mainWeatherCache.time![i], - mainWeatherCache.sunrise![j], - mainWeatherCache.sunset![j], - ), - ); + for (var j = 0; j < mainWeatherCache.timeDaily!.length; j++) { + if (mainWeatherCache.timeDaily![j].day == notificationTime.day) { + NotificationShow().showNotification( + UniqueKey().hashCode, + '$city: ${mainWeatherCache.temperature2M![i]}°', + '${StatusWeather().getText(mainWeatherCache.weathercode![i])} · ${StatusData().getTimeFormat(mainWeatherCache.time![i])}', + notificationTime, + StatusWeather().getImageNotification( + mainWeatherCache.weathercode![i], + mainWeatherCache.time![i], + mainWeatherCache.sunrise![j], + mainWeatherCache.sunset![j], + ), + ); } } } @@ -508,7 +508,7 @@ class WeatherController extends GetxController { final List pendingNotificationRequests = await flutterLocalNotificationsPlugin.pendingNotificationRequests(); if (pendingNotificationRequests.isEmpty) { - notlification(_mainWeather.value); + notification(_mainWeather.value); } } } diff --git a/lib/app/modules/cards/view/list_weather_card.dart b/lib/app/modules/cards/view/list_weather_card.dart index 03e0735..638e338 100644 --- a/lib/app/modules/cards/view/list_weather_card.dart +++ b/lib/app/modules/cards/view/list_weather_card.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:iconsax/iconsax.dart'; import 'package:rain/app/controller/controller.dart'; -import 'package:rain/app/modules/cards/view/info_weather_card.dart'; -import 'package:rain/app/modules/cards/widgets/weather_card_container.dart'; +import 'package:rain/app/modules/cards/widgets/weather_card_list.dart'; +import 'package:rain/app/widgets/text_form.dart'; class ListWeatherCard extends StatefulWidget { const ListWeatherCard({super.key}); @@ -14,6 +14,19 @@ class ListWeatherCard extends StatefulWidget { class _ListWeatherCardState extends State { final weatherController = Get.put(WeatherController()); + TextEditingController searchTasks = TextEditingController(); + String filter = ''; + + applyFilter(String value) async { + filter = value.toLowerCase(); + setState(() {}); + } + + @override + void initState() { + super.initState(); + applyFilter(''); + } @override Widget build(BuildContext context) { @@ -49,87 +62,40 @@ class _ListWeatherCardState extends State { ), ), ) - : ReorderableListView( - onReorder: (oldIndex, newIndex) => - weatherController.reorder(oldIndex, newIndex), - children: [ - ...weatherController.weatherCards.map( - (weatherCardList) => Dismissible( - key: ValueKey(weatherCardList), - direction: DismissDirection.endToStart, - background: Container( - alignment: Alignment.centerRight, - child: const Padding( - padding: EdgeInsets.only(right: 15), - child: Icon( - Iconsax.trush_square, - color: Colors.red, - ), + : NestedScrollView( + physics: const NeverScrollableScrollPhysics(), + headerSliverBuilder: (context, innerBoxIsScrolled) { + return [ + SliverToBoxAdapter( + child: MyTextForm( + labelText: 'search'.tr, + type: TextInputType.text, + icon: const Icon( + Iconsax.search_normal_1, + size: 20, ), - ), - confirmDismiss: (DismissDirection direction) async { - return await showAdaptiveDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog.adaptive( - title: Text( - 'deletedCardWeather'.tr, - style: textTheme.titleLarge, - ), - content: Text( - 'deletedCardWeatherQuery'.tr, - style: titleMedium, - ), - actions: [ - TextButton( - onPressed: () => Get.back(result: false), - child: Text( - 'cancel'.tr, - style: titleMedium?.copyWith( - color: Colors.blueAccent, - ), - ), + controller: searchTasks, + margin: const EdgeInsets.symmetric( + horizontal: 10, vertical: 5), + onChanged: applyFilter, + iconButton: searchTasks.text.isNotEmpty + ? IconButton( + onPressed: () { + searchTasks.clear(); + applyFilter(''); + }, + icon: const Icon( + Iconsax.close_circle, + color: Colors.grey, + size: 20, ), - TextButton( - onPressed: () => Get.back(result: true), - child: Text( - 'delete'.tr, - style: titleMedium?.copyWith( - color: Colors.red, - ), - ), - ), - ], - ); - }, - ); - }, - onDismissed: (DismissDirection direction) async { - await weatherController - .deleteCardWeather(weatherCardList); - }, - child: GestureDetector( - onTap: () => Get.to( - () => InfoWeatherCard( - weatherCard: weatherCardList, - ), - transition: Transition.downToUp, - ), - child: WeatherCardContainer( - time: weatherCardList.time!, - timeDaily: weatherCardList.timeDaily!, - timeDay: weatherCardList.sunrise!, - timeNight: weatherCardList.sunset!, - weather: weatherCardList.weathercode!, - degree: weatherCardList.temperature2M!, - district: weatherCardList.district!, - city: weatherCardList.city!, - timezone: weatherCardList.timezone!, - ), + ) + : null, ), ), - ), - ], + ]; + }, + body: WeatherCardList(searchCity: filter), ), ), ); diff --git a/lib/app/modules/cards/widgets/weather_card_list.dart b/lib/app/modules/cards/widgets/weather_card_list.dart new file mode 100644 index 0000000..aa3a5ec --- /dev/null +++ b/lib/app/modules/cards/widgets/weather_card_list.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:iconsax/iconsax.dart'; +import 'package:rain/app/controller/controller.dart'; +import 'package:rain/app/modules/cards/view/info_weather_card.dart'; +import 'package:rain/app/modules/cards/widgets/weather_card_container.dart'; + +class WeatherCardList extends StatefulWidget { + const WeatherCardList({ + super.key, + required this.searchCity, + }); + final String searchCity; + + @override + State createState() => _WeatherCardListState(); +} + +class _WeatherCardListState extends State { + final weatherController = Get.put(WeatherController()); + + @override + Widget build(BuildContext context) { + final textTheme = context.textTheme; + final titleMedium = textTheme.titleMedium; + + var weatherCards = weatherController.weatherCards + .where((weatherCard) => (widget.searchCity.isEmpty || + weatherCard.city!.toLowerCase().contains(widget.searchCity))) + .toList() + .obs; + + return ReorderableListView( + onReorder: (oldIndex, newIndex) => + weatherController.reorder(oldIndex, newIndex), + children: [ + ...weatherCards.map( + (weatherCardList) => Dismissible( + key: ValueKey(weatherCardList), + direction: DismissDirection.endToStart, + background: Container( + alignment: Alignment.centerRight, + child: const Padding( + padding: EdgeInsets.only(right: 15), + child: Icon( + Iconsax.trush_square, + color: Colors.red, + ), + ), + ), + confirmDismiss: (DismissDirection direction) async { + return await showAdaptiveDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog.adaptive( + title: Text( + 'deletedCardWeather'.tr, + style: textTheme.titleLarge, + ), + content: Text( + 'deletedCardWeatherQuery'.tr, + style: titleMedium, + ), + actions: [ + TextButton( + onPressed: () => Get.back(result: false), + child: Text( + 'cancel'.tr, + style: titleMedium?.copyWith( + color: Colors.blueAccent, + ), + ), + ), + TextButton( + onPressed: () => Get.back(result: true), + child: Text( + 'delete'.tr, + style: titleMedium?.copyWith( + color: Colors.red, + ), + ), + ), + ], + ); + }, + ); + }, + onDismissed: (DismissDirection direction) async { + await weatherController.deleteCardWeather(weatherCardList); + }, + child: GestureDetector( + onTap: () => Get.to( + () => InfoWeatherCard( + weatherCard: weatherCardList, + ), + transition: Transition.downToUp, + ), + child: WeatherCardContainer( + time: weatherCardList.time!, + timeDaily: weatherCardList.timeDaily!, + timeDay: weatherCardList.sunrise!, + timeNight: weatherCardList.sunset!, + weather: weatherCardList.weathercode!, + degree: weatherCardList.temperature2M!, + district: weatherCardList.district!, + city: weatherCardList.city!, + timezone: weatherCardList.timezone!, + ), + ), + ), + ), + ], + ); + } +} diff --git a/lib/app/modules/settings/view/settings.dart b/lib/app/modules/settings/view/settings.dart index 4c3ba48..9f03999 100644 --- a/lib/app/modules/settings/view/settings.dart +++ b/lib/app/modules/settings/view/settings.dart @@ -266,7 +266,7 @@ class _SettingsPageState extends State { isar.settings.putSync(settings); }); if (value) { - weatherController.notlification( + weatherController.notification( weatherController.mainWeather); } else { flutterLocalNotificationsPlugin.cancelAll(); @@ -297,7 +297,7 @@ class _SettingsPageState extends State { newTimeRange: int.parse(newValue!)); if (settings.notifications) { flutterLocalNotificationsPlugin.cancelAll(); - weatherController.notlification( + weatherController.notification( weatherController.mainWeather); } }, @@ -352,7 +352,7 @@ class _SettingsPageState extends State { timeStartPicker.format(context)); if (settings.notifications) { flutterLocalNotificationsPlugin.cancelAll(); - weatherController.notlification( + weatherController.notification( weatherController.mainWeather); } } @@ -408,7 +408,7 @@ class _SettingsPageState extends State { timeEndPicker.format(context)); if (settings.notifications) { flutterLocalNotificationsPlugin.cancelAll(); - weatherController.notlification( + weatherController.notification( weatherController.mainWeather); } } diff --git a/lib/app/widgets/text_form.dart b/lib/app/widgets/text_form.dart index 51e19c2..f0d9d9b 100644 --- a/lib/app/widgets/text_form.dart +++ b/lib/app/widgets/text_form.dart @@ -13,6 +13,7 @@ class MyTextForm extends StatelessWidget { this.validator, this.elevation, this.focusNode, + this.onChanged, }); final String labelText; final TextInputType type; @@ -23,6 +24,7 @@ class MyTextForm extends StatelessWidget { final String? Function(String?)? validator; final double? elevation; final FocusNode? focusNode; + final Function(String)? onChanged; @override Widget build(BuildContext context) { @@ -44,6 +46,7 @@ class MyTextForm extends StatelessWidget { labelText: labelText, ), validator: validator, + onChanged: onChanged, ), ); } diff --git a/lib/main.dart b/lib/main.dart index 6929383..b8513eb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -284,54 +284,57 @@ class _MyAppState extends State { @override Widget build(BuildContext context) { - return DynamicColorBuilder( - builder: (lightColorScheme, darkColorScheme) { - final lightMaterialTheme = - lightTheme(lightColorScheme?.surface, lightColorScheme); - final darkMaterialTheme = - darkTheme(darkColorScheme?.surface, darkColorScheme); - final darkMaterialThemeOled = darkTheme(oledColor, darkColorScheme); + return GestureDetector( + onTap: () => FocusManager.instance.primaryFocus?.unfocus(), + child: DynamicColorBuilder( + builder: (lightColorScheme, darkColorScheme) { + final lightMaterialTheme = + lightTheme(lightColorScheme?.surface, lightColorScheme); + final darkMaterialTheme = + darkTheme(darkColorScheme?.surface, darkColorScheme); + final darkMaterialThemeOled = darkTheme(oledColor, darkColorScheme); - return GetMaterialApp( - themeMode: themeController.theme, - theme: materialColor - ? lightColorScheme != null - ? lightMaterialTheme - : lightTheme(lightColor, colorSchemeLight) - : lightTheme(lightColor, colorSchemeLight), - darkTheme: amoledTheme - ? materialColor - ? darkColorScheme != null - ? darkMaterialThemeOled - : darkTheme(oledColor, colorSchemeDark) - : darkTheme(oledColor, colorSchemeDark) - : materialColor - ? darkColorScheme != null - ? darkMaterialTheme - : darkTheme(darkColor, colorSchemeDark) - : darkTheme(darkColor, colorSchemeDark), - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - translations: Translation(), - locale: locale, - fallbackLocale: const Locale('en', 'US'), - supportedLocales: - appLanguages.map((e) => e['locale'] as Locale).toList(), - debugShowCheckedModeBanner: false, - home: settings.onboard - ? (locationCache.city == null) || - (locationCache.district == null) || - (locationCache.lat == null) || - (locationCache.lon == null) - ? const SelectGeolocation(isStart: true) - : const HomePage() - : const OnBording(), - title: 'Rain', - ); - }, + return GetMaterialApp( + themeMode: themeController.theme, + theme: materialColor + ? lightColorScheme != null + ? lightMaterialTheme + : lightTheme(lightColor, colorSchemeLight) + : lightTheme(lightColor, colorSchemeLight), + darkTheme: amoledTheme + ? materialColor + ? darkColorScheme != null + ? darkMaterialThemeOled + : darkTheme(oledColor, colorSchemeDark) + : darkTheme(oledColor, colorSchemeDark) + : materialColor + ? darkColorScheme != null + ? darkMaterialTheme + : darkTheme(darkColor, colorSchemeDark) + : darkTheme(darkColor, colorSchemeDark), + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + translations: Translation(), + locale: locale, + fallbackLocale: const Locale('en', 'US'), + supportedLocales: + appLanguages.map((e) => e['locale'] as Locale).toList(), + debugShowCheckedModeBanner: false, + home: settings.onboard + ? (locationCache.city == null) || + (locationCache.district == null) || + (locationCache.lat == null) || + (locationCache.lon == null) + ? const SelectGeolocation(isStart: true) + : const HomePage() + : const OnBording(), + title: 'Rain', + ); + }, + ), ); } } diff --git a/pubspec.lock b/pubspec.lock index f276623..e49c808 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -237,10 +237,18 @@ packages: dependency: "direct main" description: name: dio - sha256: "11e40df547d418cc0c4900a9318b26304e665da6fa4755399a9ff9efd09034b5" + sha256: e17f6b3097b8c51b72c74c9f071a605c47bcc8893839bd66732457a5ebe73714 url: "https://pub.dev" source: hosted - version: "5.4.3+1" + version: "5.5.0+1" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "36c5b2d79eb17cdae41e974b7a8284fec631651d2a6f39a8a2ff22327e90aeac" + url: "https://pub.dev" + source: hosted + version: "1.0.1" dynamic_color: dependency: "direct main" description: @@ -322,10 +330,10 @@ packages: dependency: "direct main" description: name: flutter_local_notifications - sha256: "40e6fbd2da7dcc7ed78432c5cdab1559674b4af035fddbfb2f9a8f9c2112fcef" + sha256: "0a9068149f0225e81642b03562e99776106edbd967816ee68bc16310d457c60e" url: "https://pub.dev" source: hosted - version: "17.1.2" + version: "17.2.1+1" flutter_local_notifications_linux: dependency: transitive description: @@ -338,10 +346,10 @@ packages: dependency: transitive description: name: flutter_local_notifications_platform_interface - sha256: "340abf67df238f7f0ef58f4a26d2a83e1ab74c77ab03cd2b2d5018ac64db30b7" + sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66" url: "https://pub.dev" source: hosted - version: "7.1.0" + version: "7.2.0" flutter_localizations: dependency: "direct main" description: flutter @@ -364,10 +372,10 @@ packages: dependency: "direct main" description: name: flutter_timezone - sha256: "06b35132c98fa188db3c4b654b7e1af7ccd01dfe12a004d58be423357605fb24" + sha256: b7448ff8a9e1350606727e40b3f314aa798a6a1cc07127eba58f09b98a66f03f url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "2.0.0" flutter_web_plugins: dependency: transitive description: flutter @@ -385,10 +393,10 @@ packages: dependency: "direct main" description: name: freezed_annotation - sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + sha256: f54946fdb1fa7b01f780841937b1a80783a20b393485f3f6cdf336fd6f4705f2 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" frontend_server_client: dependency: transitive description: @@ -569,10 +577,10 @@ packages: dependency: "direct main" description: name: internet_connection_checker_plus - sha256: "45d33532937eb931a14fb1f885c4b0ade6332983ba98349920fca0a23751d7c9" + sha256: "116a5473ef8b3eadc4f07257d2719885aec1626c54fb043c47e3deda659dbabb" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" intl: dependency: "direct main" description: @@ -617,10 +625,18 @@ packages: dependency: transitive description: name: js - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.7.1" + version: "0.6.7" + js_interop: + dependency: transitive + description: + name: js_interop + sha256: "7ec859c296958ccea34dc770504bd3ff4ae52fdd9e7eeb2bacc7081ad476a1f5" + url: "https://pub.dev" + source: hosted + version: "0.0.1" json_annotation: dependency: "direct main" description: @@ -990,10 +1006,10 @@ packages: dependency: "direct main" description: name: timezone - sha256: a6ccda4a69a442098b602c44e61a1e2b4bf6f5516e875bbf0f427d5df14745d5 + sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" url: "https://pub.dev" source: hosted - version: "0.9.3" + version: "0.9.4" timing: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index dcebe71..fe2b20b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,14 +14,14 @@ dependencies: flutter_localizations: sdk: flutter get: ^4.6.6 - dio: ^5.4.3+1 + dio: ^5.5.0+1 intl: ^0.19.0 isar: version: ^3.1.7 hosted: https://pub.isar-community.dev/ shimmer: ^3.0.0 iconsax: ^0.0.8 - timezone: ^0.9.3 + timezone: ^0.9.4 geocoding: ^3.0.0 geolocator: ^12.0.0 home_widget: ^0.6.0 @@ -32,10 +32,10 @@ dependencies: dynamic_color: ^1.7.0 path_provider: ^2.1.3 json_annotation: ^4.9.0 - flutter_timezone: ^1.0.8 + flutter_timezone: ^2.0.0 package_info_plus: ^8.0.0 connectivity_plus: ^6.0.3 - freezed_annotation: ^2.4.1 + freezed_annotation: ^2.4.2 isar_flutter_libs: version: ^3.1.7 hosted: https://pub.isar-community.dev/ @@ -43,8 +43,8 @@ dependencies: lat_lng_to_timezone: ^0.2.0 flutter_hsvcolor_picker: ^1.5.1 scrollable_positioned_list: ^0.3.8 - flutter_local_notifications: ^17.1.2 - internet_connection_checker_plus: ^2.4.2 + flutter_local_notifications: ^17.2.1+1 + internet_connection_checker_plus: ^2.5.0 # Uncomment this for publishing FLOSS variant # dependency_overrides: