diff --git a/lib/features/landing_page/ui/widgets/landing_feature_card.dart b/lib/features/landing_page/ui/widgets/landing_feature_card.dart index 206b120..72f070e 100644 --- a/lib/features/landing_page/ui/widgets/landing_feature_card.dart +++ b/lib/features/landing_page/ui/widgets/landing_feature_card.dart @@ -20,7 +20,7 @@ class LandingFeatureCard extends StatelessWidget { return Container( height: 100, decoration: BoxDecoration( - color: context.colors.card, + color: context.colors.background, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( diff --git a/lib/features/landing_page/ui/widgets/landing_features_page.dart b/lib/features/landing_page/ui/widgets/landing_features_page.dart index 9d22f0d..d5ced1a 100644 --- a/lib/features/landing_page/ui/widgets/landing_features_page.dart +++ b/lib/features/landing_page/ui/widgets/landing_features_page.dart @@ -54,7 +54,7 @@ class LandingFeaturesPage extends ConsumerWidget { color: const Color.fromARGB(255, 255, 163, 72).withOpacity(0.65), title: 'Актуальность', description: - 'Проверяйте актуальность просматривая данные о последнем изменении расписания', + 'Проверяйте актуальность, просматривая данные о последнем изменении расписания', ), const SizedBox(height: 16), LandingFeatureCard( @@ -68,7 +68,7 @@ class LandingFeaturesPage extends ConsumerWidget { LandingFeatureCard( icon: const Icon(Icons.devices_rounded), color: const Color(0xFF488aff).withOpacity(0.65), - title: 'Мобильность', + title: 'Мультиплатформенность', description: 'Просматривайте расписание с различных устройств', ), const SizedBox(height: 24), diff --git a/lib/features/landing_page/ui/widgets/landing_service_card.dart b/lib/features/landing_page/ui/widgets/landing_service_card.dart index 99f8056..0eb033b 100644 --- a/lib/features/landing_page/ui/widgets/landing_service_card.dart +++ b/lib/features/landing_page/ui/widgets/landing_service_card.dart @@ -25,7 +25,7 @@ class LandingServiceCard extends ConsumerWidget { final manager = ref.watch(landingPageManager); return Container( decoration: BoxDecoration( - color: context.colors.card, + color: context.colors.background, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( diff --git a/lib/features/timetable_page/features/lesson_card/ui/lesson_card.dart b/lib/features/timetable_page/features/lesson_card/ui/lesson_card.dart index e7efd47..ec4ca25 100644 --- a/lib/features/timetable_page/features/lesson_card/ui/lesson_card.dart +++ b/lib/features/timetable_page/features/lesson_card/ui/lesson_card.dart @@ -73,7 +73,7 @@ class LessonCard extends ConsumerWidget { margin: const EdgeInsets.only(top: 8), decoration: BoxDecoration( borderRadius: BorderRadius.circular(7), - color: context.colors.card, + color: context.colors.background, boxShadow: [ BoxShadow( color: context.colors.shadow, diff --git a/lib/features/timetable_page/features/lesson_card/ui/widgets/free_time_window_lesson_card.dart b/lib/features/timetable_page/features/lesson_card/ui/widgets/free_time_window_lesson_card.dart index 6ab7141..7311732 100644 --- a/lib/features/timetable_page/features/lesson_card/ui/widgets/free_time_window_lesson_card.dart +++ b/lib/features/timetable_page/features/lesson_card/ui/widgets/free_time_window_lesson_card.dart @@ -34,7 +34,7 @@ class FreeTimeWindowLessonCard extends ConsumerWidget { height: 40, decoration: BoxDecoration( borderRadius: BorderRadius.circular(7), - color: context.colors.card, + color: context.colors.background, boxShadow: [ BoxShadow( color: context.colors.shadow, diff --git a/lib/features/timetable_page/ui/widgets/timetable_page_day.dart b/lib/features/timetable_page/ui/widgets/timetable_page_day.dart index 5a5550c..546b6d3 100644 --- a/lib/features/timetable_page/ui/widgets/timetable_page_day.dart +++ b/lib/features/timetable_page/ui/widgets/timetable_page_day.dart @@ -35,12 +35,22 @@ class TimetablePageDay extends ConsumerWidget { ); } - if (event.type == TimetableDayEventType.notSelected) { - return const WelcomeEventPage(); - } + switch (event.type) { + case TimetableDayEventType.loading: + break; + + case TimetableDayEventType.welcome: + case TimetableDayEventType.notSelected: + return const WelcomeEventPage(); + + case TimetableDayEventType.holiday: + case TimetableDayEventType.weekend: + return const WeekendEventPage(); - if (event.type == TimetableDayEventType.error) { - return const NoConnectionEventPage(); + case TimetableDayEventType.error: + return const NoConnectionEventPage(); + + case TimetableDayEventType.lessons: } final isKSRS = @@ -50,10 +60,6 @@ class TimetablePageDay extends ConsumerWidget { return const KsrsEventPage(); } - if (event.type == TimetableDayEventType.weekend) { - return const WeekendEventPage(); - } - if (lessons == null) { return const SomethingWentWrongEventPage(); } diff --git a/lib/features/timetable_search_page/managers/timetable_search_page_manager.dart b/lib/features/timetable_search_page/managers/timetable_search_page_manager.dart index f1c6425..fd3c398 100644 --- a/lib/features/timetable_search_page/managers/timetable_search_page_manager.dart +++ b/lib/features/timetable_search_page/managers/timetable_search_page_manager.dart @@ -14,8 +14,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:cube_system/features/timetable_search_page/state_holders/timetable_search_page_event.dart'; -import 'package:cube_system/features/timetable_search_page/state_holders/timetable_search_page_querry_in_progress.dart'; - import 'package:cube_system/features/timetable_search_page/state_holders/timetable_search_page_timer.dart'; final timetableSearchPageManager = Provider((ref) { @@ -26,7 +24,6 @@ final timetableSearchPageManager = Provider((ref) { searchContoller: ref.watch(timetableSearchPageSearchController.notifier), searchFocus: ref.watch(timetableSearchPageSearchFocus.notifier), event: ref.watch(timetableSearchPageEventType.notifier), - querryInProgress: ref.watch(timetableSearchPageQuerryInProgress.notifier), timer: ref.watch(timetableSearchPageTimer.notifier), ); }); @@ -39,7 +36,6 @@ class TimetableSearchPageManager { final StateController searchContoller; final StateController searchFocus; final StateController event; - final TimetableSearchPageQuerryInProgressNotifier querryInProgress; final StateController timer; TimetableSearchPageManager({ @@ -49,7 +45,6 @@ class TimetableSearchPageManager { required this.searchContoller, required this.searchFocus, required this.event, - required this.querryInProgress, required this.timer, }); @@ -65,20 +60,28 @@ class TimetableSearchPageManager { } void unfocusSearch() { - searchFocus.state.unfocus(); + if (searchFocus.state.hasFocus) { + searchFocus.state.unfocus(); + if (event.state == TimetableSearchEventType.inputDelay) { + instantSearch(); + } + } } Future selectTimetable(TimetableInfo timetable) async { await timetablePageManager.selectTimetable(timetable); } - Future instantSearch(String querry) => - search(querry, delayBeforeRequest: false); + Future instantSearch() => + search(searchContoller.state.text, delayBeforeRequest: false); + + Future delayedSearch([String? text]) => + search(text ?? searchContoller.state.text, delayBeforeRequest: true); - Future search(String querry, {bool delayBeforeRequest = true}) async { + Future search(String querry, {required bool delayBeforeRequest}) async { await Future(() {}); timer.state.cancel(); - event.state = TimetableSearchEventType.loading; + event.state = TimetableSearchEventType.inputDelay; if (delayBeforeRequest) { timer.state = Timer(const Duration(milliseconds: 800), () { _search(querry); @@ -91,10 +94,9 @@ class TimetableSearchPageManager { Future _search(String querry) async { await Future(() {}); - querryInProgress.add(); + event.state = TimetableSearchEventType.loading; if (querry.strip().isEmpty) { - querryInProgress.sub(); event.state = TimetableSearchEventType.welcome; return; } @@ -103,14 +105,15 @@ class TimetableSearchPageManager { try { response = await api.apiLessonsAutocompleteGet(q: querry); - querryInProgress.sub(); } catch (e) { - querryInProgress.sub(); event.state = TimetableSearchEventType.error; return; } - if (querryInProgress.state >= 1) return; + // If the text is different, then another request is coming soon + if (searchContoller.state.text != querry) { + return; + } final res = response.body!; diff --git a/lib/features/timetable_search_page/state_holders/timetable_search_page_event.dart b/lib/features/timetable_search_page/state_holders/timetable_search_page_event.dart index e440769..88eb02c 100644 --- a/lib/features/timetable_search_page/state_holders/timetable_search_page_event.dart +++ b/lib/features/timetable_search_page/state_holders/timetable_search_page_event.dart @@ -2,6 +2,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; enum TimetableSearchEventType { welcome, + inputDelay, loading, results, noFound, diff --git a/lib/features/timetable_search_page/state_holders/timetable_search_page_querry_in_progress.dart b/lib/features/timetable_search_page/state_holders/timetable_search_page_querry_in_progress.dart index bcf95d7..d3f5a12 100644 --- a/lib/features/timetable_search_page/state_holders/timetable_search_page_querry_in_progress.dart +++ b/lib/features/timetable_search_page/state_holders/timetable_search_page_querry_in_progress.dart @@ -1,20 +1 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -final timetableSearchPageQuerryInProgress = - StateNotifierProvider( - (ref) { - return TimetableSearchPageQuerryInProgressNotifier( - 0, - ); -}); - -class TimetableSearchPageQuerryInProgressNotifier extends StateNotifier { - TimetableSearchPageQuerryInProgressNotifier(super.state); - - @override - get state => super.state; - - void add() => state = state + 1; - - void sub() => state = state - 1; -} diff --git a/lib/features/timetable_search_page/ui/widgets/timetable_card.dart b/lib/features/timetable_search_page/ui/widgets/timetable_card.dart index 954a1a2..5a81c24 100644 --- a/lib/features/timetable_search_page/ui/widgets/timetable_card.dart +++ b/lib/features/timetable_search_page/ui/widgets/timetable_card.dart @@ -53,7 +53,7 @@ class TimetableCard extends ConsumerWidget { return Container( decoration: BoxDecoration( - color: context.colors.card, + color: context.colors.background, borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( diff --git a/lib/features/timetable_search_page/ui/widgets/timetable_search_page_body.dart b/lib/features/timetable_search_page/ui/widgets/timetable_search_page_body.dart index 356d33e..7145fd9 100644 --- a/lib/features/timetable_search_page/ui/widgets/timetable_search_page_body.dart +++ b/lib/features/timetable_search_page/ui/widgets/timetable_search_page_body.dart @@ -9,7 +9,7 @@ import 'package:cube_system/features/timetable_search_page/state_holders/timetab import 'package:cube_system/features/timetable_search_page/ui/event_pages/welcome_search_event_page.dart'; -import 'package:cube_system/features/timetable_search_page/ui/event_pages/no_connection_search_event_page.dart'; +import 'package:cube_system/ui/widgets/event_pages/no_connection_event_page.dart'; import 'package:go_router/go_router.dart'; class TimetableSearchPageBody extends ConsumerWidget { @@ -25,6 +25,7 @@ class TimetableSearchPageBody extends ConsumerWidget { case TimetableSearchEventType.welcome: return const WelcomeSearchEventPage(); + case TimetableSearchEventType.inputDelay: case TimetableSearchEventType.loading: return const Center( child: Padding( @@ -37,9 +38,11 @@ class TimetableSearchPageBody extends ConsumerWidget { return const NoFoundSearchEventPage(); case TimetableSearchEventType.error: - return const NoConnectionSearchEventPage(); + return NoConnectionEventPage( + onTap: manager.delayedSearch, + ); - default: + case TimetableSearchEventType.results: } return ListView.separated( diff --git a/lib/features/timetable_search_page/ui/widgets/timetable_search_page_text_field.dart b/lib/features/timetable_search_page/ui/widgets/timetable_search_page_text_field.dart index 8b30c57..b76ad96 100644 --- a/lib/features/timetable_search_page/ui/widgets/timetable_search_page_text_field.dart +++ b/lib/features/timetable_search_page/ui/widgets/timetable_search_page_text_field.dart @@ -19,15 +19,16 @@ class TimetableSearchPageTextField extends ConsumerWidget { return TextField( controller: contoller, focusNode: focus, - onChanged: manager.search, - onSubmitted: (value) => manager.instantSearch, - onEditingComplete: () => manager.instantSearch(contoller.text), + onChanged: manager.delayedSearch, + onSubmitted: (value) => manager.unfocusSearch(), + onEditingComplete: manager.unfocusSearch, style: context.textStyles.smallLabel.copyWith( fontSize: 16, ), decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 12), isDense: true, + // filled: true, hintText: 'Найти расписание', hintStyle: context.textStyles.subTitle.copyWith( fontSize: 16, diff --git a/lib/styles/app_colors/app_colors.dart b/lib/styles/app_colors/app_colors.dart index a158509..865ace8 100644 --- a/lib/styles/app_colors/app_colors.dart +++ b/lib/styles/app_colors/app_colors.dart @@ -10,8 +10,7 @@ part 'app_colors.tailor.dart'; ) class _$AppColors { static List primary = [const Color(0xFF38a1ff)]; - static List background = [Colors.blueGrey[50]!]; - static List card = [Colors.blueGrey[50]!]; + static List background = [const Color(0xFFF6F7FF)]; static List text = [const Color(0xFF2B2B2B)]; static List hintText = [const Color.fromARGB(255, 161, 161, 161)]; diff --git a/lib/styles/app_colors/app_colors.tailor.dart b/lib/styles/app_colors/app_colors.tailor.dart index 03aa9f4..906291c 100644 --- a/lib/styles/app_colors/app_colors.tailor.dart +++ b/lib/styles/app_colors/app_colors.tailor.dart @@ -12,7 +12,6 @@ class AppColors extends ThemeExtension { const AppColors({ required this.primary, required this.background, - required this.card, required this.text, required this.hintText, required this.subduedText, @@ -25,7 +24,6 @@ class AppColors extends ThemeExtension { final Color primary; final Color background; - final Color card; final Color text; final Color hintText; final Color subduedText; @@ -38,7 +36,6 @@ class AppColors extends ThemeExtension { static final AppColors light = AppColors( primary: _$AppColors.primary[0], background: _$AppColors.background[0], - card: _$AppColors.card[0], text: _$AppColors.text[0], hintText: _$AppColors.hintText[0], subduedText: _$AppColors.subduedText[0], @@ -57,7 +54,6 @@ class AppColors extends ThemeExtension { AppColors copyWith({ Color? primary, Color? background, - Color? card, Color? text, Color? hintText, Color? subduedText, @@ -70,7 +66,6 @@ class AppColors extends ThemeExtension { return AppColors( primary: primary ?? this.primary, background: background ?? this.background, - card: card ?? this.card, text: text ?? this.text, hintText: hintText ?? this.hintText, subduedText: subduedText ?? this.subduedText, @@ -88,7 +83,6 @@ class AppColors extends ThemeExtension { return AppColors( primary: Color.lerp(primary, other.primary, t)!, background: Color.lerp(background, other.background, t)!, - card: Color.lerp(card, other.card, t)!, text: Color.lerp(text, other.text, t)!, hintText: Color.lerp(hintText, other.hintText, t)!, subduedText: Color.lerp(subduedText, other.subduedText, t)!, @@ -108,7 +102,6 @@ class AppColors extends ThemeExtension { const DeepCollectionEquality().equals(primary, other.primary) && const DeepCollectionEquality() .equals(background, other.background) && - const DeepCollectionEquality().equals(card, other.card) && const DeepCollectionEquality().equals(text, other.text) && const DeepCollectionEquality().equals(hintText, other.hintText) && const DeepCollectionEquality() @@ -128,7 +121,6 @@ class AppColors extends ThemeExtension { runtimeType, const DeepCollectionEquality().hash(primary), const DeepCollectionEquality().hash(background), - const DeepCollectionEquality().hash(card), const DeepCollectionEquality().hash(text), const DeepCollectionEquality().hash(hintText), const DeepCollectionEquality().hash(subduedText), diff --git a/lib/styles/app_theme.dart b/lib/styles/app_theme.dart index 2a16bfe..bf8a279 100644 --- a/lib/styles/app_theme.dart +++ b/lib/styles/app_theme.dart @@ -9,7 +9,7 @@ class AppTheme { }) { final theme = ThemeData.light(); return theme.copyWith( - scaffoldBackgroundColor: colors.card, + scaffoldBackgroundColor: colors.background, dividerColor: colors.subduedBorder, primaryColor: colors.primary, bottomNavigationBarTheme: BottomNavigationBarThemeData( @@ -23,7 +23,7 @@ class AppTheme { appBarTheme: AppBarTheme( centerTitle: true, titleTextStyle: textStyles.appBarTitle, - backgroundColor: colors.card, + backgroundColor: colors.background, shadowColor: colors.shadow, ), extensions: [ diff --git a/lib/features/timetable_search_page/ui/event_pages/no_connection_search_event_page.dart b/lib/ui/widgets/event_pages/no_connection_event_page.dart similarity index 76% rename from lib/features/timetable_search_page/ui/event_pages/no_connection_search_event_page.dart rename to lib/ui/widgets/event_pages/no_connection_event_page.dart index 0cc9b21..b41c97b 100644 --- a/lib/features/timetable_search_page/ui/event_pages/no_connection_search_event_page.dart +++ b/lib/ui/widgets/event_pages/no_connection_event_page.dart @@ -4,8 +4,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:cube_system/gen/assets/assets.gen.dart'; import 'package:cube_system/ui/widgets/event_pages/app_event_page.dart'; -class NoConnectionSearchEventPage extends ConsumerWidget { - const NoConnectionSearchEventPage({super.key}); +class NoConnectionEventPage extends ConsumerWidget { + final VoidCallback onTap; + const NoConnectionEventPage({super.key, required this.onTap}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -15,9 +16,7 @@ class NoConnectionSearchEventPage extends ConsumerWidget { title: 'Ошибка соединения', subTitle: 'Не удалось подключиться к серверу', buttonText: 'Попробовать ещё раз', - onTap: () { - //TODO: implement this - }, + onTap: onTap, ); } }