diff --git a/lib/assets/icons/Dicon.ttf b/lib/assets/icons/Dicon.ttf index c8fad57..d843dd2 100644 Binary files a/lib/assets/icons/Dicon.ttf and b/lib/assets/icons/Dicon.ttf differ diff --git a/lib/assets/icons/ai-icon.svg b/lib/assets/icons/ai-icon.svg new file mode 100644 index 0000000..13a7a9f --- /dev/null +++ b/lib/assets/icons/ai-icon.svg @@ -0,0 +1,9 @@ + + ai-outline-icons-simple-stock-illustration-stock-vector + + + + + + \ No newline at end of file diff --git a/lib/constants/app_icons.dart b/lib/constants/app_icons.dart index e85977a..f535aef 100644 --- a/lib/constants/app_icons.dart +++ b/lib/constants/app_icons.dart @@ -12,9 +12,12 @@ /// - asset: fonts/Dicon.ttf /// /// +/// * Material Design Icons, Copyright (C) Google, Inc +/// Author: Google +/// License: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) +/// Homepage: https://design.google.com/icons/ /// // ignore_for_file: constant_identifier_names -/// import 'package:flutter/widgets.dart'; @@ -74,35 +77,35 @@ class DidvanIcons { IconData(0xe817, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData arrow_up_regular = IconData(0xe818, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData arrow_up_solid = + static const IconData avatar_regular = IconData(0xe819, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData avatar_light = IconData(0xe81a, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData avatar_regular = - IconData(0xe81b, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData avatar_solid = + IconData(0xe81b, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData filter_regular = IconData(0xe81c, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData back_light = + static const IconData arrow_up_solid = IconData(0xe81d, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData back_regular = + static const IconData back_light = IconData(0xe81e, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData back_solid = + static const IconData back_regular = IconData(0xe81f, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData bitcoin_solid = + static const IconData back_solid = IconData(0xe820, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData bookmark_light = + static const IconData bitcoin_solid = IconData(0xe821, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData bookmark_regular = + static const IconData bookmark_light = IconData(0xe822, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData bookmark_solid = + static const IconData bookmark_regular = IconData(0xe823, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData calendar_day_light = + static const IconData bookmark_solid = IconData(0xe824, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData calendar_day_regular = + static const IconData calendar_day_light = IconData(0xe825, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData calendar_day_solid = + static const IconData calendar_day_regular = IconData(0xe826, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData calendar_range_light = + static const IconData calendar_day_solid = IconData(0xe827, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData calendar_range_regular = IconData(0xe828, fontFamily: _kFontFam, fontPackage: _kFontPkg); @@ -116,37 +119,37 @@ class DidvanIcons { IconData(0xe82c, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData capital_market_solid = IconData(0xe82d, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData caret_down_regular = - IconData(0xe82e, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData caret_down_solid = - IconData(0xe82f, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData category_light = - IconData(0xe830, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData category_regular = - IconData(0xe831, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData caret_down_light = + IconData(0xe82e, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData caret_down_regular = + IconData(0xe82f, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData caret_down_solid = + IconData(0xe830, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData category_light = + IconData(0xe831, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData calendar_range_light = IconData(0xe832, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData category_solid = + static const IconData category_regular = IconData(0xe833, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData chart_light = + static const IconData category_solid = IconData(0xe834, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData chart_regular = + static const IconData chart_light = IconData(0xe835, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData chart_solid = + static const IconData chart_regular = IconData(0xe836, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData chats_light = + static const IconData chart_solid = IconData(0xe837, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData chats_regular = + static const IconData chats_light = IconData(0xe838, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData chats_solid = IconData(0xe839, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData check_light = + static const IconData chats_regular = IconData(0xe83a, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData check_regular = - IconData(0xe83b, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData check_solid = - IconData(0xe83c, fontFamily: _kFontFam, fontPackage: _kFontPkg); + IconData(0xe83b, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData check_circle_light = + IconData(0xe83c, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData check_regular = IconData(0xe83d, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData check_circle_regular = IconData(0xe83e, fontFamily: _kFontFam, fontPackage: _kFontPkg); @@ -170,29 +173,29 @@ class DidvanIcons { IconData(0xe847, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData close_circle_solid = IconData(0xe848, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData commodity_solid = + static const IconData check_light = IconData(0xe849, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData currency_solid = + static const IconData commodity_solid = IconData(0xe84a, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData description_regular = + static const IconData currency_solid = IconData(0xe84b, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData didvan_light = - IconData(0xe84c, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData didvan_regular = - IconData(0xe84d, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData didvan_solid = - IconData(0xe84e, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData dislike_light = - IconData(0xe84f, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData dislike_regular = - IconData(0xe850, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData dislike_solid = - IconData(0xe851, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData description_light = - IconData(0xe852, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData download_light = - IconData(0xe853, fontFamily: _kFontFam, fontPackage: _kFontPkg); + IconData(0xe84c, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData filter_solid = + IconData(0xe84d, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData description_solid = + IconData(0xe84e, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData description_regular = + IconData(0xe84f, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData didvan_light = + IconData(0xe850, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData didvan_regular = + IconData(0xe851, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData didvan_solid = + IconData(0xe852, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData dislike_light = + IconData(0xe853, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData dislike_regular = IconData(0xe854, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData download_regular = IconData(0xe855, fontFamily: _kFontFam, fontPackage: _kFontPkg); @@ -202,33 +205,33 @@ class DidvanIcons { IconData(0xe857, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData evaluation_regular = IconData(0xe858, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData evaluation_solid = - IconData(0xe859, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData exclamation_triangle_light = - IconData(0xe85a, fontFamily: _kFontFam, fontPackage: _kFontPkg); + IconData(0xe859, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData exclamation_triangle_regular = - IconData(0xe85b, fontFamily: _kFontFam, fontPackage: _kFontPkg); + IconData(0xe85a, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData exclamation_triangle_solid = - IconData(0xe85c, fontFamily: _kFontFam, fontPackage: _kFontPkg); + IconData(0xe85b, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData eye_close_solid = - IconData(0xe85d, fontFamily: _kFontFam, fontPackage: _kFontPkg); + IconData(0xe85c, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData eye_light = - IconData(0xe85e, fontFamily: _kFontFam, fontPackage: _kFontPkg); + IconData(0xe85d, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData eye_regular = - IconData(0xe85f, fontFamily: _kFontFam, fontPackage: _kFontPkg); + IconData(0xe85e, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData eye_solid = - IconData(0xe860, fontFamily: _kFontFam, fontPackage: _kFontPkg); + IconData(0xe85f, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData eye_slash_light = - IconData(0xe861, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData eye_slash_regular = - IconData(0xe862, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData eye_slash_solid = - IconData(0xe863, fontFamily: _kFontFam, fontPackage: _kFontPkg); + IconData(0xe860, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData filter_light = + IconData(0xe861, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData evaluation_solid = + IconData(0xe862, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData eye_slash_regular = + IconData(0xe863, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData download_light = IconData(0xe864, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData filter_regular = + static const IconData dislike_solid = IconData(0xe865, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData filter_solid = + static const IconData eye_slash_solid = IconData(0xe866, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData fingerprint_light = IconData(0xe867, fontFamily: _kFontFam, fontPackage: _kFontPkg); @@ -326,232 +329,246 @@ class DidvanIcons { IconData(0xe895, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData media_forward_solid = IconData(0xe896, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData menu_light = - IconData(0xe897, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData menu_regular = - IconData(0xe898, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData menu_solid = - IconData(0xe899, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData message_light = - IconData(0xe89a, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData message_regular = - IconData(0xe89b, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData message_solid = - IconData(0xe89c, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData metal_solid = - IconData(0xe89d, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData mic_light = - IconData(0xe89e, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData mic_regular = - IconData(0xe89f, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData mic_solid = - IconData(0xe8a0, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData minimize_light = - IconData(0xe8a1, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData minimize_regular = - IconData(0xe8a2, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData minimize_solid = - IconData(0xe8a3, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData news_light = - IconData(0xe8a4, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData news_regular = - IconData(0xe8a5, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData news_solid = - IconData(0xe8a6, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData non_tick_square_regular = - IconData(0xe8a7, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData note_solid = - IconData(0xe8a8, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData notification_light = - IconData(0xe8a9, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData notification_regular = - IconData(0xe8aa, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData notification_solid = - IconData(0xe8ab, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData pause_light = - IconData(0xe8ac, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData pause_regular = - IconData(0xe8ad, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData pause_solid = - IconData(0xe8ae, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData pause_circle_light = - IconData(0xe8af, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData pause_circle_regular = - IconData(0xe8b0, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData pause_circle_solid = - IconData(0xe8b1, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData people_solid = - IconData(0xe8b2, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData play_light = - IconData(0xe8b3, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData play_regular = - IconData(0xe8b4, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData play_solid = - IconData(0xe8b5, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData play_circle_light = - IconData(0xe8b6, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData play_circle_regular = - IconData(0xe8b7, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData play_circle_solid = - IconData(0xe8b8, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData podcast_light = - IconData(0xe8b9, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData podcast_regular = - IconData(0xe8ba, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData podcast_solid = - IconData(0xe8bb, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData profile_light = - IconData(0xe8bc, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData profile_regular = - IconData(0xe8bd, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData profile_solid = - IconData(0xe8be, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData puzzle_light = - IconData(0xe8bf, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData puzzle_regular = - IconData(0xe8c0, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData puzzle_solid = - IconData(0xe8c1, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData radar_light = - IconData(0xe8c2, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData radar_regular = - IconData(0xe8c3, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData radar_solid = - IconData(0xe8c4, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData refresh_light = - IconData(0xe8c5, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData refresh_regular = - IconData(0xe8c6, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData refresh_solid = - IconData(0xe8c7, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData saha_light = - IconData(0xe8c8, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData saha_regular = - IconData(0xe8c9, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData saha_solid = - IconData(0xe8ca, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData scanning_light = - IconData(0xe8cb, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData scanning_regular = - IconData(0xe8cc, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData scanning_solid = - IconData(0xe8cd, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData search_light = - IconData(0xe8ce, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData search_regular = - IconData(0xe8cf, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData search_solid = - IconData(0xe8d0, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData send_light = - IconData(0xe8d1, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData send_regular = - IconData(0xe8d2, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData send_solid = - IconData(0xe8d3, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData setting_light = - IconData(0xe8d4, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData setting_regular = - IconData(0xe8d5, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData setting_solid = - IconData(0xe8d6, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sign_out_light = - IconData(0xe8d7, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sign_out_regular = - IconData(0xe8d8, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sign_out_solid = - IconData(0xe8d9, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sleep_enabled_light = - IconData(0xe8da, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sleep_enabled_regular = - IconData(0xe8db, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sleep_enabled_solid = - IconData(0xe8dc, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sleep_timer_light = - IconData(0xe8dd, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sleep_timer_regular = - IconData(0xe8de, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sleep_timer_solid = - IconData(0xe8df, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sort_light = - IconData(0xe8e0, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sort_regular = - IconData(0xe8e1, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sort_solid = - IconData(0xe8e2, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData star_circle_solid = - IconData(0xe8e3, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData star_light = - IconData(0xe8e4, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData star_regular = - IconData(0xe8e5, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData star_solid = - IconData(0xe8e6, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData startup_solid = - IconData(0xe8e7, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData stats__light = - IconData(0xe8e8, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData stats__regular = - IconData(0xe8e9, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData stats__solid = - IconData(0xe8ea, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData stop_circle_light = - IconData(0xe8eb, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData stop_circle_regular = - IconData(0xe8ec, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData stop_circle_solid = - IconData(0xe8ed, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sub_category_light = - IconData(0xe8ee, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sub_category_regular = - IconData(0xe8ef, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData sub_category_solid = - IconData(0xe8f0, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData support_light = - IconData(0xe8f1, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData support_regular = - IconData(0xe8f2, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData support_solid = - IconData(0xe8f3, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData technology_solid = - IconData(0xe8f4, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData theme_light = - IconData(0xe8f5, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData theme_regular = - IconData(0xe8f6, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData theme_solid = - IconData(0xe8f7, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData tick_square_regular = - IconData(0xe8f8, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData timer_light = - IconData(0xe8f9, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData timer_regular = - IconData(0xe8fa, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData timer_solid = - IconData(0xe8fb, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData trash_light = - IconData(0xe8fc, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData trash_regular = - IconData(0xe8fd, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData trash_solid = - IconData(0xe8fe, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData user_edit_light = - IconData(0xe8ff, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData user_edit_regular = - IconData(0xe900, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData user_edit_solid = - IconData(0xe901, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData user_shield_light = - IconData(0xe902, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData user_shield_regular = - IconData(0xe903, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData user_shield_solid = - IconData(0xe904, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData video_light = - IconData(0xe905, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData video_regular = - IconData(0xe906, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData video_solid = - IconData(0xe907, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData mention_icon = + IconData(0xe897, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData menu_light = + IconData(0xe898, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData menu_regular = + IconData(0xe899, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData menu_solid = + IconData(0xe89a, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData message_light = + IconData(0xe89b, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData message_regular = + IconData(0xe89c, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData message_solid = + IconData(0xe89d, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData metal_solid = + IconData(0xe89e, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData mic_light = + IconData(0xe89f, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData mic_regular = + IconData(0xe8a0, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData mic_solid = + IconData(0xe8a1, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData minimize_light = + IconData(0xe8a2, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData minimize_regular = + IconData(0xe8a3, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData minimize_solid = + IconData(0xe8a4, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData news_light = + IconData(0xe8a5, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData news_regular = + IconData(0xe8a6, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData news_solid = + IconData(0xe8a7, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData non_tick_square_regular = + IconData(0xe8a8, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData note_solid = + IconData(0xe8a9, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData notification_light = + IconData(0xe8aa, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData notification_regular = + IconData(0xe8ab, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData notification_solid = + IconData(0xe8ac, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData pause_light = + IconData(0xe8ad, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData pause_regular = + IconData(0xe8ae, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData pause_solid = + IconData(0xe8af, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData pause_circle_light = + IconData(0xe8b0, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData pause_circle_regular = + IconData(0xe8b1, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData pause_circle_solid = + IconData(0xe8b2, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData people_solid = + IconData(0xe8b3, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData play_light = + IconData(0xe8b4, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData play_regular = + IconData(0xe8b5, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData play_solid = + IconData(0xe8b6, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData play_circle_light = + IconData(0xe8b7, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData play_circle_regular = + IconData(0xe8b8, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData play_circle_solid = + IconData(0xe8b9, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData podcast_light = + IconData(0xe8ba, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData podcast_regular = + IconData(0xe8bb, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData podcast_solid = + IconData(0xe8bc, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData profile_light = + IconData(0xe8bd, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData profile_regular = + IconData(0xe8be, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData profile_solid = + IconData(0xe8bf, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData puzzle_light = + IconData(0xe8c0, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData puzzle_regular = + IconData(0xe8c1, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData puzzle_solid = + IconData(0xe8c2, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData radar_light = + IconData(0xe8c3, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData radar_regular = + IconData(0xe8c4, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData radar_solid = + IconData(0xe8c5, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData refresh_light = + IconData(0xe8c6, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData refresh_regular = + IconData(0xe8c7, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData refresh_solid = + IconData(0xe8c8, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData saha_light = + IconData(0xe8c9, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData saha_regular = + IconData(0xe8ca, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData saha_solid = + IconData(0xe8cb, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData scanning_light = + IconData(0xe8cc, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData scanning_regular = + IconData(0xe8cd, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData scanning_solid = + IconData(0xe8ce, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData search_light = + IconData(0xe8cf, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData search_regular = + IconData(0xe8d0, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData search_solid = + IconData(0xe8d1, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData send_light = + IconData(0xe8d2, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData send_regular = + IconData(0xe8d3, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData send_solid = + IconData(0xe8d4, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData setting_light = + IconData(0xe8d5, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData setting_regular = + IconData(0xe8d6, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData setting_solid = + IconData(0xe8d7, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sign_out_light = + IconData(0xe8d8, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sign_out_regular = + IconData(0xe8d9, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sign_out_solid = + IconData(0xe8da, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sleep_enabled_light = + IconData(0xe8db, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sleep_enabled_regular = + IconData(0xe8dc, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sleep_enabled_solid = + IconData(0xe8dd, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sleep_timer_light = + IconData(0xe8de, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sleep_timer_regular = + IconData(0xe8df, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sleep_timer_solid = + IconData(0xe8e0, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sort_light = + IconData(0xe8e1, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sort_regular = + IconData(0xe8e2, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sort_solid = + IconData(0xe8e3, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData star_circle_solid = + IconData(0xe8e4, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData star_light = + IconData(0xe8e5, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData star_regular = + IconData(0xe8e6, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData star_solid = + IconData(0xe8e7, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData startup_solid = + IconData(0xe8e8, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData stats__light = + IconData(0xe8e9, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData stats__regular = + IconData(0xe8ea, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData stats__solid = + IconData(0xe8eb, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData stop_circle_light = + IconData(0xe8ec, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData stop_circle_regular = + IconData(0xe8ed, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData stop_circle_solid = + IconData(0xe8ee, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sub_category_light = + IconData(0xe8ef, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sub_category_regular = + IconData(0xe8f0, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData sub_category_solid = + IconData(0xe8f1, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData support_light = + IconData(0xe8f2, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData support_regular = + IconData(0xe8f3, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData support_solid = + IconData(0xe8f4, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData technology_solid = + IconData(0xe8f5, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData theme_light = + IconData(0xe8f6, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData theme_regular = + IconData(0xe8f7, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData theme_solid = + IconData(0xe8f8, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData tick_square_regular = + IconData(0xe8f9, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData timer_light = + IconData(0xe8fa, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData timer_regular = + IconData(0xe8fb, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData timer_solid = + IconData(0xe8fc, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData trash_light = + IconData(0xe8fd, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData trash_regular = + IconData(0xe8fe, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData trash_solid = + IconData(0xe8ff, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData user_edit_light = + IconData(0xe900, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData user_edit_regular = + IconData(0xe901, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData user_edit_solid = + IconData(0xe902, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData user_shield_light = + IconData(0xe903, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData user_shield_regular = + IconData(0xe904, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData user_shield_solid = + IconData(0xe905, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData video_light = + IconData(0xe906, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData video_regular = + IconData(0xe907, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData video_solid = IconData(0xe908, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData contact_us_solid = + IconData(0xe909, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData ai_regular = + IconData(0xe90a, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData ai_solid = + IconData(0xe90b, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData add_regular = + IconData(0xe90c, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData copy_regular = + IconData(0xe90d, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData note_regular = + IconData(0xe90e, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData font_size_solid = + IconData(0xe90f, fontFamily: _kFontFam, fontPackage: _kFontPkg); } diff --git a/lib/main.dart b/lib/main.dart index 1d51f59..ae284aa 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,6 +15,7 @@ import 'package:didvan/services/app_home_widget/home_widget_repository.dart'; import 'package:didvan/services/media/media.dart'; import 'package:didvan/services/notification/firebase_api.dart'; import 'package:didvan/services/notification/notification_service.dart'; +import 'package:didvan/views/ai/history_ai_chat_state.dart'; import 'package:didvan/views/podcasts/podcasts_state.dart'; import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart'; import 'package:firebase_core/firebase_core.dart'; @@ -140,6 +141,9 @@ class _DidvanState extends State with WidgetsBindingObserver { ChangeNotifierProvider( create: (context) => StudioDetailsState(), ), + ChangeNotifierProvider( + create: (context) => HistoryAiChatState(), + ), ], child: Consumer( builder: (context, themeProvider, child) => Container( diff --git a/lib/models/ai/ai_chat_args.dart b/lib/models/ai/ai_chat_args.dart new file mode 100644 index 0000000..0caf703 --- /dev/null +++ b/lib/models/ai/ai_chat_args.dart @@ -0,0 +1,8 @@ +import 'package:didvan/models/ai/bots_model.dart'; + +class AiChatArgs { + final BotsModel bot; + final int? chatId; + + AiChatArgs({required this.bot, this.chatId}); +} diff --git a/lib/models/ai/bots_model.dart b/lib/models/ai/bots_model.dart new file mode 100644 index 0000000..6a243ab --- /dev/null +++ b/lib/models/ai/bots_model.dart @@ -0,0 +1,21 @@ +class BotsModel { + int? id; + String? name; + String? image; + + BotsModel({this.id, this.name, this.image}); + + BotsModel.fromJson(Map json) { + id = json['id']; + name = json['name']; + image = json['image']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['name'] = name; + data['image'] = image; + return data; + } +} diff --git a/lib/models/ai/chats_model.dart b/lib/models/ai/chats_model.dart new file mode 100644 index 0000000..20282f4 --- /dev/null +++ b/lib/models/ai/chats_model.dart @@ -0,0 +1,108 @@ +import 'package:didvan/models/ai/bots_model.dart'; + +class ChatsModel { + int? id; + int? userId; + int? botId; + String? title; + String? createdAt; + String? updatedAt; + BotsModel? bot; + List? prompts; + + ChatsModel( + {this.id, + this.userId, + this.botId, + this.title, + this.createdAt, + this.updatedAt, + this.bot, + this.prompts}); + + ChatsModel.fromJson(Map json) { + id = json['id']; + userId = json['userId']; + botId = json['botId']; + title = json['title']; + createdAt = json['createdAt']; + updatedAt = json['updatedAt']; + bot = json['bot'] != null ? BotsModel.fromJson(json['bot']) : null; + if (json['prompts'] != null) { + prompts = []; + json['prompts'].forEach((v) { + prompts!.add(Prompts.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['userId'] = userId; + data['botId'] = botId; + data['title'] = title; + data['createdAt'] = createdAt; + data['updatedAt'] = updatedAt; + if (bot != null) { + data['bot'] = bot!.toJson(); + } + if (prompts != null) { + data['prompts'] = prompts!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class Prompts { + int? id; + int? chatId; + String? text; + String? role; + String? createdAt; + bool? finished; + + Prompts( + {this.id, + this.chatId, + this.text, + this.role, + this.createdAt, + this.finished}); + + Prompts.fromJson(Map json) { + id = json['id']; + chatId = json['chatId']; + text = json['text']; + role = json['role']; + createdAt = json['createdAt']; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['chatId'] = chatId; + data['text'] = text; + data['role'] = role; + data['createdAt'] = createdAt; + return data; + } + + Prompts copyWith({ + int? id, + int? chatId, + String? text, + String? role, + String? createdAt, + bool? finished, + }) { + return Prompts( + id: id ?? this.id, + chatId: chatId ?? this.chatId, + text: text ?? this.text, + role: role ?? this.role, + createdAt: createdAt ?? this.createdAt, + finished: finished ?? this.finished, + ); + } +} diff --git a/lib/models/view/action_sheet_data.dart b/lib/models/view/action_sheet_data.dart index e695f52..f1b533d 100644 --- a/lib/models/view/action_sheet_data.dart +++ b/lib/models/view/action_sheet_data.dart @@ -17,8 +17,7 @@ class ActionSheetData { final bool isBackgroundDropBlur; final Color? backgroundColor; - - const ActionSheetData( { + const ActionSheetData({ required this.content, this.title, this.confrimTitle, diff --git a/lib/routes/route_generator.dart b/lib/routes/route_generator.dart index f4b9307..6ded8a5 100644 --- a/lib/routes/route_generator.dart +++ b/lib/routes/route_generator.dart @@ -1,3 +1,10 @@ +// ignore_for_file: unused_import + +import 'package:didvan/models/ai/ai_chat_args.dart'; +import 'package:didvan/views/ai/ai_chat_page.dart'; +import 'package:didvan/views/ai/ai_chat_state.dart'; +import 'package:didvan/views/ai/history_ai_chat_page.dart'; +import 'package:didvan/views/ai/history_ai_chat_state.dart'; import 'package:didvan/views/authentication/authentication.dart'; import 'package:didvan/views/authentication/authentication_state.dart'; import 'package:didvan/views/comments/comments.dart'; @@ -13,6 +20,7 @@ import 'package:didvan/views/home/infography/infography_screen.dart'; import 'package:didvan/views/home/infography/infography_screen_state.dart'; import 'package:didvan/views/home/main/main_page_state.dart'; import 'package:didvan/views/home/home_state.dart'; +import 'package:didvan/views/home/new_statistic/new_statistic.dart'; import 'package:didvan/views/home/new_statistic/new_statistics_state.dart'; import 'package:didvan/views/home/new_statistic/statistics_details/stat_cats_general_screen.dart'; import 'package:didvan/views/home/new_statistic/statistics_details/stat_cats_general_state.dart'; @@ -82,6 +90,11 @@ class RouteGenerator { )), ); + // case Routes.newStatic: + // return _createRoute(ChangeNotifierProvider( + // create: (context) => NewStatisticState(), + // child: const NewStatistic())); + case Routes.notificationStatusStep: return _createRoute( ChangeNotifierProvider( @@ -110,12 +123,11 @@ class RouteGenerator { ChangeNotifierProvider( create: (context) => StatisticState(), ), - ChangeNotifierProvider( - create: (context) => NewStatisticState(), - ), ChangeNotifierProvider( create: (context) => BookmarksState(), ), + ChangeNotifierProvider( + create: (context) => NewStatisticState()) ], child: const Home(), ), @@ -126,7 +138,9 @@ class RouteGenerator { ); case Routes.profile: return _createRoute( - const ProfilePage(), + ChangeNotifierProvider( + create: (context) => GeneralSettingsState(), + child: const ProfilePage()), ); case Routes.generalSettings: return _createRoute( @@ -285,6 +299,13 @@ class RouteGenerator { (settings.arguments as Map)['onDeleted']), ), ); + + case Routes.aiChat: + return _createRoute(ChangeNotifierProvider( + create: (context) => AiChatState(), + child: AiChatPage( + args: settings.arguments as AiChatArgs, + ))); default: return _errorRoute(settings.name ?? ''); } diff --git a/lib/routes/routes.dart b/lib/routes/routes.dart index a837a47..fd655d5 100644 --- a/lib/routes/routes.dart +++ b/lib/routes/routes.dart @@ -1,5 +1,6 @@ class Routes { static const String splash = '/'; + static const String aiChat = '/ai-chat'; static const String home = '/home'; static const String radars = '/radars'; static const String news = '/news'; @@ -30,4 +31,5 @@ class Routes { static const String notificationStatusStep = '/notification-status-step'; static const String notificationTime = '/notification-time'; static const String widgetSetting = '/widget-setting'; + static const String newStatic = '/new-static'; } diff --git a/lib/services/ai/ai_api_service.dart b/lib/services/ai/ai_api_service.dart new file mode 100644 index 0000000..ede12f2 --- /dev/null +++ b/lib/services/ai/ai_api_service.dart @@ -0,0 +1,39 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:didvan/services/storage/storage.dart'; +import 'package:http/http.dart' as http; +import 'package:http/http.dart'; + +class AiApiService { + static const String baseUrl = 'https://api.didvan.app/ai'; + static final _client = http.Client(); + + static Future initial( + {required final String url, + required final String message, + final int? chatId}) async { + final headers = { + "Content-Type": "application/json", + "Authorization": "Bearer ${await StorageService.getValue(key: 'token')}" + }; + + var request = http.Request('POST', Uri.parse(baseUrl + url)) + ..headers.addAll(headers); + + var body = {'prompt': message}; + if (chatId != null) { + body.addAll({'chatId': chatId.toString()}); + } + request.body = jsonEncode(body); + return request; + } + + static Future getResponse(Request request) async { + final res = _client.send(request).timeout( + const Duration(seconds: 15), + ); + final http.StreamedResponse response = await res; + return response.stream; + } +} diff --git a/lib/services/network/request.dart b/lib/services/network/request.dart index 0827389..89a4e64 100644 --- a/lib/services/network/request.dart +++ b/lib/services/network/request.dart @@ -1,6 +1,9 @@ +// ignore_for_file: empty_catches + import 'dart:convert'; import 'dart:developer'; import 'package:didvan/services/storage/storage.dart'; +import 'package:flutter/foundation.dart'; // ignore: depend_on_referenced_packages import 'package:http/http.dart' as http; @@ -44,11 +47,11 @@ class RequestService { if (body != null) _requestBody = body; if (requestHeaders != null) _headers.addAll(requestHeaders); if (useAutherization) _headers.addAll({'Authorization': 'Bearer $token'}); - // print('Authorization : Bearer $token'); - // _headers.addAll({ - // 'Authorization': - // 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NCwicm9sZUlkIjo0LCJhcHBJZCI6MCwiaWF0IjoxNzEzOTM1NzkwfQ.i-SO9tLy0M9j-_C2Wh8tdp01vtYGlDZIBFPygglHQF0' - // }); + if (kDebugMode) { + try { + print('Authorization : Bearer $token'); + } catch (e) {} + } if (body != null) _requestBody = body; } @@ -63,7 +66,7 @@ class RequestService { headers: _headers, ) .timeout( - const Duration(seconds: 30), + const Duration(seconds: 100), ) .catchError( (e) => throw e, @@ -83,7 +86,7 @@ class RequestService { headers: _headers, ) .timeout( - const Duration(seconds: 10), + const Duration(seconds: 100), ) .catchError( (e) { @@ -105,7 +108,7 @@ class RequestService { headers: _headers, ) .timeout( - const Duration(seconds: 10), + const Duration(seconds: 100), ) .catchError( (e) => throw e, @@ -146,7 +149,7 @@ class RequestService { final streamedResponse = await request .send() .timeout( - const Duration(seconds: 30), + const Duration(seconds: 100), ) .catchError( (e) => throw e, @@ -167,7 +170,7 @@ class RequestService { headers: _headers, ) .timeout( - const Duration(seconds: 10), + const Duration(seconds: 100), ) .catchError( (e) => throw e, diff --git a/lib/services/network/request_helper.dart b/lib/services/network/request_helper.dart index 942bd01..39c2d71 100644 --- a/lib/services/network/request_helper.dart +++ b/lib/services/network/request_helper.dart @@ -200,6 +200,15 @@ class RequestHelper { static String deleteComment(int id) => '$baseUrl/comment/$id'; static String reportComment(int id) => '$baseUrl/comment/$id/report'; static String widgetNews() => '$baseUrl/user/widget'; + static String aiChats() => '$baseUrl/ai/chat'; + static String aiBots() => '$baseUrl/ai/bot'; + static String aiSearchBots(String q) => + '$baseUrl/ai/bot${_urlConcatGenerator([ + MapEntry('q', q), + ])}'; + static String aiAChat(int id) => '$baseUrl/ai/chat/$id'; + static String aiChatId() => '$baseUrl/ai/chat/id'; + static String aiDeleteChats() => '$baseUrl/ai/chat'; static String _urlConcatGenerator(List> additions) { String result = ''; diff --git a/lib/services/notification/notification_service.dart b/lib/services/notification/notification_service.dart index 2971b52..d1cdfff 100644 --- a/lib/services/notification/notification_service.dart +++ b/lib/services/notification/notification_service.dart @@ -1,4 +1,3 @@ - import 'package:awesome_notifications/awesome_notifications.dart'; import 'package:didvan/models/notification_message.dart'; import 'package:didvan/services/app_home_widget/home_widget_repository.dart'; @@ -153,7 +152,6 @@ class NotificationService { displayOnBackground: true, displayOnForeground: true, wakeUpScreen: true, - icon: 'resource://drawable/logo', roundedLargeIcon: data.notificationType!.contains('2'), payload: data.toPayload()), ); diff --git a/lib/utils/action_sheet.dart b/lib/utils/action_sheet.dart index 4288b5b..602ebfc 100644 --- a/lib/utils/action_sheet.dart +++ b/lib/utils/action_sheet.dart @@ -180,7 +180,9 @@ class ActionSheetUtils { await showDialog( context: context, builder: (context) => BackdropFilter( - filter: ImageFilter.blur(sigmaX: data.isBackgroundDropBlur? 10 : 0, sigmaY: data.isBackgroundDropBlur? 10: 0) , + filter: ImageFilter.blur( + sigmaX: data.isBackgroundDropBlur ? 10 : 0, + sigmaY: data.isBackgroundDropBlur ? 10 : 0), child: Dialog( backgroundColor: data.backgroundColor ?? Theme.of(context).colorScheme.surface, @@ -243,19 +245,20 @@ class ActionSheetUtils { style: ButtonStyleMode.flat, ), ), - if (data.hasDismissButton) + if (data.hasDismissButton && data.hasDismissButton) const SizedBox( width: 20, ), - Expanded( - child: DidvanButton( - onPressed: () { - pop(); - data.onConfirmed?.call(); - }, - title: data.confrimTitle ?? 'تایید', + if (data.hasDismissButton) + Expanded( + child: DidvanButton( + onPressed: () { + pop(); + data.onConfirmed?.call(); + }, + title: data.confrimTitle ?? 'تایید', + ), ), - ), ], ), ], diff --git a/lib/utils/date_time.dart b/lib/utils/date_time.dart index 2eb34a0..d6e3387 100644 --- a/lib/utils/date_time.dart +++ b/lib/utils/date_time.dart @@ -124,18 +124,22 @@ class DateTimeUtils { } static String timeWithAmPm(String input) { - final dateTime = utcToLocalTime(input); - bool isAm = true; - int hour = 0; - int minute = 0; - if (dateTime.hour > 12) { - isAm = false; - hour = dateTime.hour - 12; - } else { - hour = dateTime.hour; + try { + final dateTime = utcToLocalTime(input); + bool isAm = true; + int hour = 0; + int minute = 0; + if (dateTime.hour > 12) { + isAm = false; + hour = dateTime.hour - 12; + } else { + hour = dateTime.hour; + } + minute = dateTime.minute; + return '$hour:${_timeNormalizer(minute)} ${isAm ? 'ق.ظ' : 'ب.ظ'}'; + } catch (e) { + return ''; } - minute = dateTime.minute; - return '$hour:${_timeNormalizer(minute)} ${isAm ? 'ق.ظ' : 'ب.ظ'}'; } static DateTime utcToLocalTime(String input) { diff --git a/lib/views/ai/ai_chat_page.dart b/lib/views/ai/ai_chat_page.dart new file mode 100644 index 0000000..8814568 --- /dev/null +++ b/lib/views/ai/ai_chat_page.dart @@ -0,0 +1,331 @@ +// ignore_for_file: library_private_types_in_public_api, deprecated_member_use + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:didvan/config/design_config.dart'; +import 'package:didvan/config/theme_data.dart'; +import 'package:didvan/constants/app_icons.dart'; +import 'package:didvan/constants/assets.dart'; +import 'package:didvan/main.dart'; +import 'package:didvan/models/ai/ai_chat_args.dart'; +import 'package:didvan/models/ai/chats_model.dart'; +import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/view/alert_data.dart'; +import 'package:didvan/utils/action_sheet.dart'; +import 'package:didvan/utils/date_time.dart'; +import 'package:didvan/views/ai/ai_chat_state.dart'; +import 'package:didvan/views/ai/history_ai_chat_state.dart'; +import 'package:didvan/views/widgets/didvan/icon_button.dart'; +import 'package:didvan/views/widgets/didvan/text.dart'; +import 'package:didvan/views/widgets/state_handlers/empty_state.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:provider/provider.dart'; + +class AiChatPage extends StatefulWidget { + final AiChatArgs args; + const AiChatPage({Key? key, required this.args}) : super(key: key); + + @override + _AiChatPageState createState() => _AiChatPageState(); +} + +class _AiChatPageState extends State { + TextEditingController message = TextEditingController(); + + @override + void initState() { + final state = context.read(); + state.chatId = widget.args.chatId; + if (state.chatId != null) { + state.getAllMessages(state.chatId!); + } + super.initState(); + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + context.read().getChats(); + return true; + }, + child: Scaffold( + appBar: AppBar( + shadowColor: Theme.of(context).colorScheme.border, + title: Row( + children: [ + Padding( + padding: const EdgeInsets.all(12.0), + child: ClipOval( + child: CachedNetworkImage( + width: 32, + height: 32, + imageUrl: widget.args.bot.image.toString(), + ), + ), + ), + Text('چت با ${widget.args.bot.name}'), + ], + ), + automaticallyImplyLeading: false, + actions: [ + DidvanIconButton( + icon: DidvanIcons.angle_left_regular, + onPressed: () { + context.read().getChats(); + navigatorKey.currentState!.pop(); + }, + ) + ], + ), + body: Consumer( + builder: (BuildContext context, AiChatState state, Widget? child) { + return ValueListenableBuilder( + valueListenable: state.loading, + builder: (context, value, child) => value + ? Center( + child: Image.asset( + Assets.loadingAnimation, + width: 60, + height: 60, + ), + ) + : state.messages.isEmpty + ? Center( + child: EmptyState( + asset: Assets.emptyChat, + title: 'اولین پیام را بنویسید...', + ), + ) + : SingleChildScrollView( + reverse: true, + child: ListView.builder( + itemCount: state.messages.length, + controller: state.scrollController, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.only(top: 12, bottom: 90), + itemBuilder: (context, index) { + final message = state.messages[index]; + return messageBubble( + message, context, state, index); + }, + ), + ), + ); + }, + ), + bottomSheet: Container( + width: MediaQuery.sizeOf(context).width, + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: Theme.of(context).colorScheme.cardBorder, + ), + ), + color: Theme.of(context).colorScheme.surface, + ), + child: ValueListenableBuilder( + valueListenable: context.read().onResponsing, + builder: (context, value, child) => Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + width: 12, + ), + SizedBox( + width: 46, + height: 46, + child: Center( + child: value + ? Center( + child: SpinKitThreeBounce( + size: 18, + color: Theme.of(context).colorScheme.primary, + ), + ) + : DidvanIconButton( + icon: DidvanIcons.send_solid, + onPressed: () async { + if (message.text.isEmpty) { + return; + } + + final state = context.read(); + state.messages.add(Prompts( + text: message.text, + finished: true, + role: 'user', + createdAt: DateTime.now() + .subtract(const Duration(minutes: 210)) + .toIso8601String(), + )); + message.clear(); + await state.postMessage(widget.args.bot); + }, + size: 32, + color: Theme.of(context).colorScheme.focusedBorder, + ), + ), + ), + const SizedBox( + width: 12, + ), + Expanded( + flex: 15, + child: Form( + child: TextFormField( + textInputAction: TextInputAction.newline, + style: Theme.of(context).textTheme.bodyMedium, + maxLines: 6, + minLines: 1, + // keyboardType: TextInputType.text, + controller: message, + enabled: !value, + decoration: InputDecoration( + border: InputBorder.none, + hintText: 'بنویسید...', + hintStyle: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + color: + Theme.of(context).colorScheme.disabledText), + ), + onChanged: (value) {}, + ), + ), + ), + ], + ), + ), + ), + ), + ); + } + + Padding messageBubble( + Prompts message, BuildContext context, AiChatState state, int index) { + MarkdownStyleSheet defaultMarkdownStyleSheet = MarkdownStyleSheet( + code: TextStyle( + backgroundColor: Theme.of(context).colorScheme.black, + color: Theme.of(context).colorScheme.white, + ), + codeblockPadding: const EdgeInsets.all(8), + codeblockDecoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: Theme.of(context).colorScheme.black)); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 4), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: message.role.toString().contains('user') + ? CrossAxisAlignment.start + : CrossAxisAlignment.end, + children: [ + Row( + mainAxisAlignment: message.role.toString().contains('user') + ? MainAxisAlignment.start + : MainAxisAlignment.end, + children: [ + Container( + padding: + const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + decoration: BoxDecoration( + borderRadius: DesignConfig.mediumBorderRadius.copyWith( + bottomLeft: !message.role.toString().contains('user') + ? Radius.zero + : null, + bottomRight: message.role.toString().contains('user') + ? Radius.zero + : null, + ), + color: (message.role.toString().contains('user') + ? Theme.of(context).colorScheme.surface + : Theme.of(context).colorScheme.focused) + .withOpacity(0.9), + border: Border.all( + color: Theme.of(context).colorScheme.border, + width: 0.5, + ), + ), + child: Container( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width / 1.5), + child: state.messages[index].finished != null && + !state.messages[index].finished! + ? StreamBuilder( + stream: state.messageOnstream, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return const SizedBox(); + } + return Markdown( + data: "${snapshot.data}...", + selectable: false, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + styleSheet: defaultMarkdownStyleSheet); + }, + ) + : Column( + children: [ + Markdown( + data: state.messages[index].text.toString(), + selectable: true, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + styleSheet: defaultMarkdownStyleSheet, + ), + if (!message.role.toString().contains('user')) + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: InkWell( + onTap: () async { + await Clipboard.setData(ClipboardData( + text: state.messages[index].text + .toString())); + ActionSheetUtils.showAlert(AlertData( + message: "متن با موفقیت کپی شد", + aLertType: ALertType.success)); + }, + child: Icon( + DidvanIcons.copy_regular, + size: 18, + color: Theme.of(context) + .colorScheme + .focusedBorder, + ), + ), + ) + ], + ) + ], + ), + ), + ) + ], + ), + const SizedBox(height: 4), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + DidvanText( + DateTimeUtils.timeWithAmPm(message.createdAt.toString()), + // DateTimeUtils.timeWithAmPm(message.createdAt), + style: Theme.of(context).textTheme.labelSmall, + color: Theme.of(context).colorScheme.caption, + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/views/ai/ai_chat_state.dart b/lib/views/ai/ai_chat_state.dart new file mode 100644 index 0000000..34726d5 --- /dev/null +++ b/lib/views/ai/ai_chat_state.dart @@ -0,0 +1,140 @@ +import 'dart:convert'; + +import 'package:didvan/models/ai/bots_model.dart'; +import 'package:didvan/models/ai/chats_model.dart'; +import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/view/alert_data.dart'; +import 'package:didvan/providers/core.dart'; +import 'package:didvan/services/ai/ai_api_service.dart'; +import 'package:didvan/services/network/request.dart'; +import 'package:didvan/services/network/request_helper.dart'; +import 'package:didvan/utils/action_sheet.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class AiChatState extends CoreProvier { + Stream messageOnstream = const Stream.empty(); + List messages = []; + ValueNotifier onResponsing = ValueNotifier(false); + ValueNotifier loading = ValueNotifier(false); + final ScrollController scrollController = ScrollController(); + int? chatId; + + Future _scrolledEnd() async { + WidgetsBinding.instance.addPostFrameCallback((_) async { + await scrollController.animateTo( + scrollController.position.minScrollExtent, + duration: const Duration(milliseconds: 600), + curve: Curves.easeInOut, + ); + }); + } + + Future _onError(e) async { + onResponsing.value = false; + messages.removeLast(); + messages.removeLast(); + messageOnstream = const Stream.empty(); + + await ActionSheetUtils.showAlert(AlertData( + message: 'خطا در برقراری ارتباط', aLertType: ALertType.error)); + + update(); + } + + Future getChatId() async { + final service = RequestService( + RequestHelper.aiChatId(), + ); + await service.httpGet(); + if (service.isSuccess) { + final id = service.result['id']; + chatId = id; + } + return service; + } + + Future getAllMessages(int chatId) async { + loading.value = true; + onResponsing.value = true; + final service = RequestService( + RequestHelper.aiAChat(chatId), + ); + await service.httpGet(); + if (service.isSuccess) { + messages.clear(); + final allMessages = service.result['prompts']; + for (var i = 0; i < allMessages.length; i++) { + messages.add(Prompts.fromJson(allMessages[i])); + // chats.add("chats: $chats"); + } + appState = AppState.idle; + loading.value = false; + onResponsing.value = false; + + // Add this code to scroll to maxScrollExtent after the ListView is built + update(); + + return; + } + appState = AppState.failed; + loading.value = false; + onResponsing.value = false; + + update(); + } + + Future postMessage(BotsModel bot) async { + onResponsing.value = true; + + update(); + await _scrolledEnd(); + String message = messages.last.text!; + + messages.add(Prompts( + finished: false, + text: '...', + role: 'bot', + createdAt: DateTime.now() + .subtract(const Duration(minutes: 210)) + .toIso8601String())); + final req = await AiApiService.initial( + url: '/${bot.id}/${bot.name}'.toLowerCase(), + message: message, + chatId: chatId); + final res = await AiApiService.getResponse(req).catchError((e) { + _onError(e); + throw e; + }); + String responseMessgae = ''; + var r = res.listen((value) async { + var str = utf8.decode(value); + responseMessgae += str; + messageOnstream = Stream.value(responseMessgae); + + update(); + _scrolledEnd(); + }); + + r.onDone(() async { + if (chatId == null) { + final service = await getChatId(); + if (!service.isSuccess) { + _onError(null); + return; + } + } + onResponsing.value = false; + messages.last = messages.last.copyWith( + finished: true, + text: responseMessgae, + ); + messageOnstream = const Stream.empty(); + + update(); + _scrolledEnd(); + }); + + r.onError(_onError); + } +} diff --git a/lib/views/ai/history_ai_chat_page.dart b/lib/views/ai/history_ai_chat_page.dart new file mode 100644 index 0000000..9081880 --- /dev/null +++ b/lib/views/ai/history_ai_chat_page.dart @@ -0,0 +1,367 @@ +// ignore_for_file: library_private_types_in_public_api + +import 'dart:async'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:didvan/config/theme_data.dart'; +import 'package:didvan/constants/app_icons.dart'; +import 'package:didvan/constants/assets.dart'; +import 'package:didvan/main.dart'; +import 'package:didvan/models/ai/ai_chat_args.dart'; +import 'package:didvan/models/view/action_sheet_data.dart'; +import 'package:didvan/routes/routes.dart'; +import 'package:didvan/utils/action_sheet.dart'; +import 'package:didvan/utils/date_time.dart'; +import 'package:didvan/views/ai/history_ai_chat_state.dart'; +import 'package:didvan/views/widgets/didvan/scaffold.dart'; +import 'package:didvan/views/widgets/didvan/text.dart'; +import 'package:didvan/views/widgets/shimmer_placeholder.dart'; +import 'package:didvan/views/widgets/state_handlers/empty_state.dart'; +import 'package:didvan/views/widgets/state_handlers/sliver_state_handler.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class HistoryAiChatPage extends StatefulWidget { + const HistoryAiChatPage({Key? key}) : super(key: key); + + @override + _HistoryAiChatPageState createState() => _HistoryAiChatPageState(); +} + +class _HistoryAiChatPageState extends State { + ScrollController scrollController = ScrollController(); + @override + void initState() { + final state = context.read(); + Future.delayed( + Duration.zero, + () => state.getChats(), + ); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return DidvanScaffold( + hidePlayer: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only(left: 16, right: 16, bottom: 92), + floatingActionButton: openAiListBtn(context), + scrollController: scrollController, + slivers: [ + Consumer( + builder: (context, state, child) { + return SliverStateHandler( + state: state, + emptyState: EmptyState( + asset: Assets.emptyResult, + title: 'لیست خالی است', + ), + enableEmptyState: state.chats.isEmpty, + placeholder: const _HistoryPlaceholder(), + placeholderCount: 8, + + // builder: (context, state, index) => _HistoryPlaceholder(), + builder: (context, state, index) { + final chat = state.chats[index]; + + return InkWell( + onTap: () { + if (state.chatsToDelete.isEmpty) { + navigatorKey.currentState!.pushNamed(Routes.aiChat, + arguments: + AiChatArgs(bot: chat.bot!, chatId: chat.id!)); + } else { + if (state.chatsToDelete.contains(chat.id)) { + state.chatsToDelete.remove(chat.id!); + } else { + state.chatsToDelete.add(chat.id!); + } + } + state.update(); + }, + onLongPress: () { + if (state.chatsToDelete.isEmpty) { + state.chatsToDelete.add(chat.id!); + } + state.update(); + }, + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: + Theme.of(context).colorScheme.border))), + child: Stack( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox( + width: 46, + height: 46, + ), + const SizedBox( + width: 18, + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + DidvanText( + chat.bot!.name.toString(), + fontWeight: FontWeight.bold, + ), + DidvanText( + DateTimeUtils.momentGenerator( + chat.updatedAt.toString()), + style: + const TextStyle(fontSize: 12)), + ], + ), + SizedBox( + child: DidvanText( + chat.prompts![0].text.toString(), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + ], + ), + Positioned( + bottom: 0, + right: 0, + top: 0, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: ClipOval( + child: CachedNetworkImage( + imageUrl: chat.bot!.image.toString(), + ), + ), + ), + ), + if (state.chatsToDelete.contains(chat.id)) + Positioned( + right: 32, + bottom: 0, + child: Container( + // ignore: prefer_const_constructors + decoration: BoxDecoration( + color: Theme.of(context) + .scaffoldBackgroundColor, + shape: BoxShape.circle), + child: Icon(DidvanIcons.check_circle_solid, + size: 20, + color: + Theme.of(context).colorScheme.success), + ), + ) + ], + ), + ), + ); + }, + childCount: state.chats.length, + onRetry: state.getChats); + }, + ) + ], + appBarData: null, + ); + } + + Widget openAiListBtn(BuildContext context) { + final watch = context.watch(); + final state = context.read(); + return FloatingActionButton( + backgroundColor: watch.chatsToDelete.isEmpty + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.error, + shape: const OvalBorder(), + mini: true, + onPressed: () { + if (watch.chatsToDelete.isEmpty) { + state.getBots(); + state.search = ''; + _botsDialogSelect(context); + } else { + state.addChatToDelete(); + } + }, + child: watch.chatsToDelete.isEmpty + ? const Icon(DidvanIcons.add_regular) + : const Icon(DidvanIcons.trash_regular), + ); + } + + void _botsDialogSelect(BuildContext context) { + final state = context.read(); + + ActionSheetUtils.context = context; + ActionSheetUtils.openDialog( + data: ActionSheetData( + hasConfirmButton: false, + hasDismissButton: false, + content: Column( + children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.end, + // children: [ + // Padding( + // padding: const EdgeInsets.symmetric(vertical: 8.0), + // child: InkWell( + // onTap: () { + // ActionSheetUtils.pop(); + // }, + // child: const Icon(DidvanIcons.close_solid)), + // ) + // ], + // ), + // SearchField( + // title: 'هوش مصنوعی', + // value: state.search, + // onChanged: (value) { + // state.search = value; + // if (value.isEmpty) { + // state.getBots(); + // return; + // } + // state.timer?.cancel(); + // state.timer = Timer(const Duration(seconds: 1), () { + // state.getSearchBots(value); + // }); + // }, + // focusNode: FocusNode()), + // const SizedBox( + // height: 12, + // ), + SizedBox( + width: double.infinity, + height: MediaQuery.sizeOf(context).height / 3, + child: ValueListenableBuilder( + valueListenable: state.loadingBots, + builder: (context, value, child) => value + ? Center( + child: Image.asset( + Assets.loadingAnimation, + width: 60, + height: 60, + ), + ) + : state.bots.isEmpty + ? Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12.0), + child: EmptyState( + asset: Assets.emptyResult, + title: 'نتیجه‌ای پیدا نشد', + height: 120, + ), + ) + : ListView.builder( + padding: + const EdgeInsets.symmetric(vertical: 12), + itemCount: state.bots.length, + physics: const BouncingScrollPhysics(), + shrinkWrap: true, + itemBuilder: (context, index) { + final bot = state.bots[index]; + return InkWell( + onTap: () { + ActionSheetUtils.pop(); + navigatorKey.currentState!.pushNamed( + Routes.aiChat, + arguments: AiChatArgs(bot: bot)); + }, + child: Container( + alignment: Alignment.center, + padding: const EdgeInsets.symmetric( + vertical: 8), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: Theme.of(context) + .colorScheme + .border, + width: 1))), + child: Row( + children: [ + ClipOval( + child: CachedNetworkImage( + imageUrl: bot.image.toString(), + width: 42, + height: 42, + ), + ), + const SizedBox(width: 12), + Text(bot.name.toString()) + ], + ), + ), + ); + }), + ), + ) + ], + ))); + } +} + +class _HistoryPlaceholder extends StatelessWidget { + const _HistoryPlaceholder({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return const Padding( + padding: EdgeInsets.symmetric(vertical: 12.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipOval( + child: ShimmerPlaceholder( + height: 42, + width: 42, + ), + ), + SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ShimmerPlaceholder( + height: 20, + width: 100, + ), + ShimmerPlaceholder( + height: 14, + width: 100, + ), + ], + ), + SizedBox(height: 12), + ShimmerPlaceholder( + height: 16, + width: double.infinity, + ), + SizedBox(height: 8), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/views/ai/history_ai_chat_state.dart b/lib/views/ai/history_ai_chat_state.dart new file mode 100644 index 0000000..6da7030 --- /dev/null +++ b/lib/views/ai/history_ai_chat_state.dart @@ -0,0 +1,111 @@ +import 'dart:async'; + +import 'package:didvan/models/ai/bots_model.dart'; +import 'package:didvan/models/ai/chats_model.dart'; +import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/view/alert_data.dart'; +import 'package:didvan/providers/core.dart'; +import 'package:didvan/services/network/request.dart'; +import 'package:didvan/services/network/request_helper.dart'; +import 'package:didvan/utils/action_sheet.dart'; +import 'package:flutter/cupertino.dart'; + +class HistoryAiChatState extends CoreProvier { + final List chats = []; + final List chatsToDelete = []; + final List bots = []; + ValueNotifier loadingBots = ValueNotifier(false); + Timer? timer; + String search = ''; + + Future getChats() async { + final service = RequestService( + RequestHelper.aiChats(), + ); + await service.httpGet(); + if (service.isSuccess) { + chats.clear(); + final messages = service.result['chats']; + for (var i = 0; i < messages.length; i++) { + chats.add(ChatsModel.fromJson(messages[i])); + } + appState = AppState.idle; + update(); + return; + } + appState = AppState.failed; + update(); + } + + Future getBots() async { + loadingBots.value = true; + final service = RequestService( + RequestHelper.aiBots(), + ); + await service.httpGet(); + if (service.isSuccess) { + bots.clear(); + final messages = service.result['bots']; + for (var i = 0; i < messages.length; i++) { + bots.add(BotsModel.fromJson(messages[i])); + } + appState = AppState.idle; + loadingBots.value = false; + update(); + return; + } + appState = AppState.failed; + loadingBots.value = false; + update(); + } + + Future getSearchBots(String q) async { + loadingBots.value = true; + final service = RequestService( + RequestHelper.aiSearchBots(q), + ); + await service.httpGet(); + if (service.isSuccess) { + bots.clear(); + final messages = service.result['bots']; + for (var i = 0; i < messages.length; i++) { + bots.add(BotsModel.fromJson(messages[i])); + } + appState = AppState.idle; + loadingBots.value = false; + update(); + + return; + } + appState = AppState.failed; + loadingBots.value = false; + update(); + } + + Future addChatToDelete() async { + final service = RequestService(RequestHelper.aiDeleteChats(), + body: {"ids": chatsToDelete}); + await service.delete(); + if (service.isSuccess) { + final List cs = []; + for (var chat in chats) { + if (!chatsToDelete.contains(chat.id)) { + cs.add(chat); + } + } + chatsToDelete.clear(); + chats.clear(); + chats.addAll(cs); + + appState = AppState.idle; + update(); + + return; + } + appState = AppState.failed; + await ActionSheetUtils.showAlert(AlertData( + message: 'خطا در برقراری ارتباط', aLertType: ALertType.error)); + + update(); + } +} diff --git a/lib/views/home/bookmarks/bookmarks.dart b/lib/views/home/bookmarks/bookmarks.dart index 92790b7..ef4ff4a 100644 --- a/lib/views/home/bookmarks/bookmarks.dart +++ b/lib/views/home/bookmarks/bookmarks.dart @@ -2,8 +2,10 @@ import 'dart:async'; import 'package:didvan/config/design_config.dart'; import 'package:didvan/constants/app_icons.dart'; +import 'package:didvan/models/view/app_bar_data.dart'; import 'package:didvan/routes/routes.dart'; import 'package:didvan/views/home/bookmarks/bookmark_state.dart'; +import 'package:didvan/views/widgets/didvan/scaffold.dart'; import 'package:didvan/views/widgets/menu_item.dart'; import 'package:didvan/views/widgets/overview/multitype.dart'; // import 'package:didvan/views/widgets/search_field.dart'; @@ -39,7 +41,11 @@ class _BookmarksState extends State { @override Widget build(BuildContext context) { final state = context.watch(); - return CustomScrollView( + return DidvanScaffold( + appBarData: AppBarData(title: 'رصدخانه من', hasBack: true, isSmall: true), + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.all(8.0), + hidePlayer: true, slivers: [ SliverPadding( padding: const EdgeInsets.symmetric(horizontal: 16), diff --git a/lib/views/home/home.dart b/lib/views/home/home.dart index 0ae4bb9..b989425 100644 --- a/lib/views/home/home.dart +++ b/lib/views/home/home.dart @@ -7,7 +7,7 @@ import 'package:didvan/providers/theme.dart'; import 'package:didvan/services/app_initalizer.dart'; import 'package:didvan/services/notification/notification_service.dart'; import 'package:didvan/utils/action_sheet.dart'; -import 'package:didvan/views/home/bookmarks/bookmarks.dart'; +import 'package:didvan/views/ai/history_ai_chat_page.dart'; import 'package:didvan/views/home/categories/categories_page.dart'; import 'package:didvan/views/home/main/main_page.dart'; import 'package:didvan/views/home/home_state.dart'; @@ -100,10 +100,11 @@ class _HomeState extends State controller: _tabController, children: const [ MainPage(), + CategoriesPage(), + HistoryAiChatPage(), NewStatistic(), //Statistic(), - CategoriesPage(), - Bookmarks(), + // Bookmarks(), ], ), ), diff --git a/lib/views/home/new_statistic/new_statistic.dart b/lib/views/home/new_statistic/new_statistic.dart index e9bb535..4c23bed 100644 --- a/lib/views/home/new_statistic/new_statistic.dart +++ b/lib/views/home/new_statistic/new_statistic.dart @@ -38,266 +38,172 @@ class _NewStatisticState extends State { @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Center( - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12), - color: Theme.of(context).colorScheme.background, - child: DidvanText( - 'دسته‌بندی‌های کلان', - color: Theme.of(context).colorScheme.title, - style: Theme.of(context).textTheme.titleMedium, - ), + return SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16), + color: Theme.of(context).colorScheme.background, + child: DidvanText( + 'دسته‌بندی‌های کلان', + color: Theme.of(context).colorScheme.title, + style: Theme.of(context).textTheme.titleMedium, ), ), - const Padding( - padding: EdgeInsets.only( - left: 20, - right: 20, - top: 16, - ), - child: NewStatisticCategories(), + ), + const Padding( + padding: EdgeInsets.symmetric( + horizontal: 20, ), - const DidvanDivider( - verticalPadding: 4, - ), - StateHandler( - enableEmptyState: false, - onRetry: context.read().init, - state: context.watch(), - placeholder: Padding( - padding: const EdgeInsets.only(top: 48.0), - child: Column( - children: [ - placeholder, - const SizedBox( - height: 8, - ), - placeholder, - const SizedBox( - height: 8, - ), - placeholder, - const SizedBox( - height: 8, - ), - placeholder, - ], - ), - ), - builder: (context, state) => Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + child: NewStatisticCategories(), + ), + const DidvanDivider( + verticalPadding: 4, + ), + StateHandler( + enableEmptyState: false, + onRetry: context.read().init, + state: context.watch(), + placeholder: Padding( + padding: const EdgeInsets.only(top: 48.0), + child: Column( children: [ - GestureDetector( - onTap: () => Future.delayed(Duration.zero, () { - Navigator.of(context) - .pushNamed(Routes.statGeneral, arguments: { - "id": 7, - "title": state.contents[0].header, - }).then((value) => _reset()); - }), - child: StatHeader( - header: state.contents[0].header, - icon: DidvanIcons.star_circle_solid, - )), - SizedBox( - height: 100, - width: 80, - child: ListView.builder( - scrollDirection: Axis.horizontal, - shrinkWrap: true, - physics: const ScrollPhysics(), - itemCount: state.contents[0].contents.length, - itemBuilder: (context, index) => StatMainCard( - statistic: state.contents[0].contents[index], - ), - ), + placeholder, + const SizedBox( + height: 46, ), - const DidvanDivider( - verticalPadding: 4, + placeholder, + const SizedBox( + height: 46, ), - GestureDetector( - onTap: () => Future.delayed(Duration.zero, () { - Navigator.of(context).pushNamed(Routes.statGeneral, - arguments: { - "id": 1, - "title": state.contents[1].header - }); - }).then((value) => _reset()), - child: StatHeader( - header: state.contents[1].header, - icon: DidvanIcons.currency_solid, - )), - SizedBox( - height: 100, - width: 80, - child: ListView.builder( - scrollDirection: Axis.horizontal, - shrinkWrap: true, - physics: const ScrollPhysics(), - itemCount: state.contents[1].contents.length, - itemBuilder: (context, index) => StatMainCard( - statistic: state.contents[1].contents[index]))), - const DidvanDivider( - verticalPadding: 4, + placeholder, + const SizedBox( + height: 46, ), - GestureDetector( - onTap: () => Future.delayed(Duration.zero, () { - Navigator.of(context).pushNamed(Routes.statGeneral, - arguments: { - "id": 2, - "title": state.contents[2].header - }).then((value) => _reset()); - }), - child: StatHeader( - header: state.contents[2].header, - icon: DidvanIcons.bitcoin_solid, - )), - SizedBox( - height: 100, - width: 80, - child: ListView.builder( - scrollDirection: Axis.horizontal, - shrinkWrap: true, - physics: const ScrollPhysics(), - itemCount: state.contents[2].contents.length, - itemBuilder: (context, index) => StatMainCard( - statistic: state.contents[2].contents[index]))), - const DidvanDivider( - verticalPadding: 4, - ), - GestureDetector( - onTap: () => Future.delayed(Duration.zero, () { - Navigator.of(context).pushNamed(Routes.statGeneral, - arguments: { - "id": 3, - "title": state.contents[3].header - }); - }).then((value) => _reset()), - child: StatHeader( - header: state.contents[3].header, - icon: DidvanIcons.metal_solid, - ), - ), - SizedBox( - height: 100, - width: 80, - child: ListView.builder( - scrollDirection: Axis.horizontal, - shrinkWrap: true, - physics: const ScrollPhysics(), - itemCount: state.contents[3].contents.length, - itemBuilder: (context, index) => StatMainCard( - statistic: state.contents[3].contents[index]))), - const DidvanDivider( - verticalPadding: 4, - ), - GestureDetector( - onTap: () => Future.delayed(Duration.zero, () { - Navigator.of(context).pushNamed(Routes.statGeneral, - arguments: { - "id": 4, - "title": state.contents[4].header - }).then((value) => _reset()); - }), - child: StatHeader( - header: state.contents[4].header, - icon: DidvanIcons.commodity_solid, - )), - SizedBox( - height: 100, - width: 80, - child: ListView.builder( - scrollDirection: Axis.horizontal, - shrinkWrap: true, - physics: const ScrollPhysics(), - itemCount: state.contents[4].contents.length, - itemBuilder: (context, index) => StatMainCard( - statistic: state.contents[4].contents[index]))), - const DidvanDivider( - verticalPadding: 4, - ), - GestureDetector( - onTap: () => Future.delayed(Duration.zero, () { - Navigator.of(context) - .pushNamed(Routes.statGeneral, arguments: { - "id": 5, - "title": state.contents[5].header, - }).then((value) => _reset()); - }), - child: StatHeader( - header: state.contents[5].header, - icon: DidvanIcons.industry_solid, - )), - SizedBox( - height: 100, - width: 80, - child: ListView.builder( - scrollDirection: Axis.horizontal, - shrinkWrap: true, - physics: const ScrollPhysics(), - itemCount: state.contents[5].contents.length, - itemBuilder: (context, index) => StatMainCard( - id: 5, - statistic: state.contents[5].contents[index]))), + placeholder, ], ), ), - ], - ), + builder: (context, state) => Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + itemsInStatics(context, state, 0), + itemsInStatics(context, state, 1), + itemsInStatics(context, state, 2), + itemsInStatics(context, state, 3), + itemsInStatics(context, state, 4), + itemsInStatics(context, state, 5, hasDivider: false), + ], + ), + ), + ], ), ); } + Widget itemsInStatics(BuildContext context, NewStatisticState state, int id, + {final bool? hasDivider}) { + bool d = hasDivider ?? true; + return state.contents[id].contents.isEmpty + ? const SizedBox() + : Padding( + padding: const EdgeInsets.only(top: 12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + GestureDetector( + onTap: () => Future.delayed(Duration.zero, () { + Navigator.of(context) + .pushNamed(Routes.statGeneral, arguments: { + "id": id == 0 ? 7 : id, + "title": state.contents[id].header, + }).then((value) => _reset()); + }), + child: StatHeader( + header: state.contents[id].header, + icon: DidvanIcons.star_circle_solid, + )), + SizedBox( + height: 100, + width: 80, + child: ListView.builder( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + physics: const ScrollPhysics(), + itemCount: state.contents[id].contents.length, + itemBuilder: (context, index) => StatMainCard( + statistic: state.contents[id].contents[index], + ), + ), + ), + if (d) + const DidvanDivider( + verticalPadding: 4, + ), + ], + ), + ); + } + static Widget get placeholder => const Column( children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ShimmerPlaceholder( - height: 16, - width: 100, - ), - ShimmerPlaceholder( - height: 16, - width: 50, - ) - ], + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ShimmerPlaceholder( + height: 16, + width: 100, + ), + ShimmerPlaceholder( + height: 16, + width: 50, + ) + ], + ), ), SizedBox( - height: 8, + height: 18, ), - Row( + Flex( + direction: Axis.horizontal, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - DidvanCard( - child: ShimmerPlaceholder( - height: 80, - width: 60, + Flexible( + flex: 1, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0), + child: DidvanCard( + child: ShimmerPlaceholder( + height: 60, + ), + ), ), ), - DidvanCard( - child: ShimmerPlaceholder( - height: 80, - width: 60, + Flexible( + flex: 1, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0), + child: DidvanCard( + child: ShimmerPlaceholder( + height: 60, + ), + ), ), ), - DidvanCard( - child: ShimmerPlaceholder( - height: 80, - width: 60, - ), - ), - DidvanCard( - child: ShimmerPlaceholder( - height: 80, - width: 60, + Flexible( + flex: 1, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0), + child: DidvanCard( + child: ShimmerPlaceholder( + height: 60, + ), + ), ), ), ], diff --git a/lib/views/home/widgets/categories.dart b/lib/views/home/widgets/categories.dart index ced79fd..5bce41f 100644 --- a/lib/views/home/widgets/categories.dart +++ b/lib/views/home/widgets/categories.dart @@ -19,8 +19,8 @@ class MainCategories extends StatelessWidget { ); } else if (link.startsWith('tab-')) { final state = context.read(); - state.currentPageIndex = 1; - state.tabController.animateTo(1); + state.currentPageIndex = 3; + state.tabController.animateTo(3); } else { Navigator.of(context).pushNamed(link); } diff --git a/lib/views/profile/general_settings/settings_state.dart b/lib/views/profile/general_settings/settings_state.dart index 3474fc6..46871b2 100644 --- a/lib/views/profile/general_settings/settings_state.dart +++ b/lib/views/profile/general_settings/settings_state.dart @@ -1,4 +1,5 @@ import 'package:didvan/models/enums.dart'; +import 'package:didvan/models/home_page_content/home_page_content.dart'; import 'package:didvan/providers/core.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; @@ -15,6 +16,41 @@ class GeneralSettingsState extends CoreProvier { String _brightness = 'light'; String time = ""; + bool showSettings = false; + bool showThemes = false; + bool showContactUs = false; + + int unread = 10; + late MainPageContent content; + + void markChangeHandler(String type, int id, bool value) { + content.lists + .firstWhere((element) => element.type == type) + .contents + .firstWhere((element) => element.id == id) + .marked = value; + notifyListeners(); + } + + Future _getMainPageContent() async { + final service = RequestService(RequestHelper.mainPageContent); + + await service.httpGet(); + if (service.isSuccess) { + content = MainPageContent.fromJson(service.result); + unread = service.result['unread']; + appState = AppState.idle; + return; + } + appState = AppState.failed; + } + + void init() { + Future.delayed(Duration.zero, () { + _getMainPageContent(); + }); + } + Future getTime() async { appState = AppState.busy; @@ -23,7 +59,7 @@ class GeneralSettingsState extends CoreProvier { ); await service.httpGet(); if (service.isSuccess) { - time = service.data('time'); + time = service.data('time'); appState = AppState.idle; } else { @@ -33,7 +69,6 @@ class GeneralSettingsState extends CoreProvier { update(); } - set notificationTimeRange(List value) { _notificationTimeRange = value; StorageService.setValue( diff --git a/lib/views/profile/profile.dart b/lib/views/profile/profile.dart index a736c23..2fda0e0 100644 --- a/lib/views/profile/profile.dart +++ b/lib/views/profile/profile.dart @@ -1,102 +1,453 @@ +import 'package:didvan/config/design_config.dart'; +import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; +import 'package:didvan/constants/assets.dart'; +import 'package:didvan/models/view/action_sheet_data.dart'; import 'package:didvan/models/view/app_bar_data.dart'; +import 'package:didvan/providers/theme.dart'; import 'package:didvan/providers/user.dart'; import 'package:didvan/routes/routes.dart'; import 'package:didvan/services/storage/storage.dart'; +import 'package:didvan/utils/action_sheet.dart'; +import 'package:didvan/views/profile/general_settings/settings_state.dart'; +import 'package:didvan/views/widgets/animated_visibility.dart'; +import 'package:didvan/views/widgets/didvan/radial_button.dart'; import 'package:didvan/views/widgets/menu_item.dart'; import 'package:didvan/views/widgets/didvan/card.dart'; import 'package:didvan/views/widgets/didvan/divider.dart'; import 'package:didvan/views/widgets/didvan/scaffold.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/item_title.dart'; +import 'package:didvan/views/widgets/state_handlers/state_handler.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; -class ProfilePage extends StatelessWidget { +class ProfilePage extends StatefulWidget { const ProfilePage({Key? key}) : super(key: key); @override - Widget build(BuildContext context) { - return DidvanScaffold( - padding: const EdgeInsets.all(16), - appBarData: AppBarData( - title: 'تنظیمات', - ), - children: [ - DidvanCard( - child: Column( - children: [ - MenuOption( - title: 'ویرایش پروفایل', - icon: DidvanIcons.user_edit_regular, - suffix: context.watch().user.fullName, - onTap: () => - Navigator.of(context).pushNamed(Routes.editProfile), - ), - const DidvanDivider(), - MenuOption( - title: 'تنظیمات', - icon: DidvanIcons.setting_regular, - onTap: () => - Navigator.of(context).pushNamed(Routes.generalSettings), - ), - const DidvanDivider(), - MenuOption( - title: 'خروج از حساب کاربری', - icon: DidvanIcons.sign_out_regular, - color: Theme.of(context).colorScheme.secondary, - onTap: () async { - StorageService.delete(key: 'token'); - Navigator.of(context).pushNamedAndRemoveUntil( - Routes.splash, - (_) => false, - ); - }, - ), - ], - ), - ), - const ItemTitle( - title: 'درباره ما', - ), - DidvanCard( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - MenuOption( - icon: DidvanIcons.info_circle_regular, - title: 'معرفی دیدوان', - onTap: () => launchUrl(Uri.parse('https://didvan.app/#info')), - ), - const DidvanDivider(), - MenuOption( - icon: DidvanIcons.support_regular, - title: 'پیام به پشتیبانی', - onTap: () { - Navigator.of(context).pushNamed( - Routes.direct, - arguments: {'type': 'پشتیبانی اپلیکیشن'}, - ); - }, - ), - const DidvanDivider(), - MenuOption( - icon: DidvanIcons.alert_regular, - title: 'حریم خصوصی', - onTap: () => launchUrl( - Uri.parse('https://didvan.app/terms-of-use#privacy'), - ), - ), - ], - ), - ), - const SizedBox(height: 16), - DidvanText( - 'نسخه نرم‌افزار: 3.2.2', - style: Theme.of(context).textTheme.bodySmall, - ), - ], + State createState() => _ProfilePageState(); +} + +class _ProfilePageState extends State { + String fontScaleSuffix(double fontSizeScale) { + final fontScale = fontSizeScale; + if (fontScale == 1) return 'متوسط'; + if (fontScale == 1.15) return 'بزرگ'; + return 'کوچک'; + } + + @override + void initState() { + super.initState(); + context.read().init(); + + final state = context.read(); + Future.delayed( + Duration.zero, + () => state.getTime(), ); } -} \ No newline at end of file + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, state, child) => StateHandler( + onRetry: context.read().init, + state: context.read(), + builder: (context, state) => DidvanScaffold( + padding: const EdgeInsets.all(16), + appBarData: AppBarData(title: 'تنظیمات', hasBack: true), + children: [ + DidvanCard( + child: Column( + children: [ + MenuOption( + title: 'ویرایش پروفایل', + icon: DidvanIcons.user_edit_regular, + suffix: context.watch().user.fullName, + onTap: () => Navigator.of(context) + .pushNamed(Routes.editProfile), + ), + const DidvanDivider(), + MenuOption( + title: 'تنظیمات', + icon: DidvanIcons.setting_regular, + onTap: () { + state.showSettings = !state.showSettings; + state.update(); + }, + trailing: Icon( + state.showSettings + ? DidvanIcons.angle_up_regular + : DidvanIcons.angle_down_regular, + size: 18, + color: Theme.of(context).colorScheme.title, + )), + AnimatedVisibility( + duration: DesignConfig.lowAnimationDuration, + isVisible: state.showSettings, + child: Padding( + padding: const EdgeInsets.only(right: 8.0, top: 8), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + vertical: 12.0), + child: MenuOption( + title: 'زمان دریافت اعلان', + onTap: () => + Navigator.of(context).pushNamed( + Routes.notificationTime, + arguments: { + "fromFav": false, + 'onTimeChanged': () => Future.delayed( + Duration.zero, + () => state.getTime(), + ) + }, + ), + icon: DidvanIcons.notification_regular, + suffix: state.time, + // suffix: 'از${DateTimeUtils.normalizeTimeDuration( + // Duration(minutes: state.notificationTimeRange[0]), + // )} تا ${DateTimeUtils.normalizeTimeDuration( + // Duration(minutes: state.notificationTimeRange[1]), + // )}', + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 12.0), + child: MenuOption( + title: 'شخصی سازی محتوا', + onTap: () => Navigator.of(context) + .pushNamed(Routes.favouritesStep, + arguments: {"toTimer": false}), + icon: DidvanIcons.note_regular, + // suffix: 'از${DateTimeUtils.normalizeTimeDuration( + // Duration(minutes: state.notificationTimeRange[0]), + // )} تا ${DateTimeUtils.normalizeTimeDuration( + // Duration(minutes: state.notificationTimeRange[1]), + // )}', + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 12.0), + child: MenuOption( + suffix: state.fontFamily == 'Dana-FA' + ? 'دانا' + : 'ایران سنس', + title: 'فونت برنامه', + onTap: _showFontFamilyBottomSheet, + icon: DidvanIcons.font_regular, + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 12.0), + child: MenuOption( + suffix: + fontScaleSuffix(state.fontSizeScale), + title: 'اندازه متن', + onTap: _showFontScaleBottomSheet, + icon: DidvanIcons.font_size_solid, + )), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 12.0), + child: MenuOption( + title: 'ظاهر برنامه', + onTap: () { + state.showThemes = !state.showThemes; + state.update(); + }, + icon: DidvanIcons.theme_regular, + trailing: Icon( + state.showThemes + ? DidvanIcons.angle_up_regular + : DidvanIcons.angle_down_regular, + size: 18, + color: Theme.of(context) + .colorScheme + .title, + ))), + AnimatedVisibility( + isVisible: state.showThemes, + duration: DesignConfig.lowAnimationDuration, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 12.0), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceAround, + children: [ + _themeItem(context, state, 'light'), + _themeItem(context, state, 'dark'), + ], + ), + ), + ), + ], + ), + ), + ), + const DidvanDivider(), + MenuOption( + title: 'خروج از حساب کاربری', + icon: DidvanIcons.sign_out_regular, + color: Theme.of(context).colorScheme.secondary, + onTap: () async { + StorageService.delete(key: 'token'); + Navigator.of(context).pushNamedAndRemoveUntil( + Routes.splash, + (_) => false, + ); + }, + ), + ], + ), + ), + const ItemTitle( + title: 'درباره ما', + ), + DidvanCard( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + MenuOption( + icon: DidvanIcons.info_circle_regular, + title: 'معرفی دیدوان', + onTap: () => + launchUrl(Uri.parse('https://didvan.app/#info')), + ), + const DidvanDivider(), + MenuOption( + icon: DidvanIcons.contact_us_solid, + title: 'تماس با ما', + onTap: () { + state.showContactUs = !state.showContactUs; + state.update(); + }, + trailing: Icon( + state.showContactUs + ? DidvanIcons.angle_up_regular + : DidvanIcons.angle_down_regular, + size: 18, + color: Theme.of(context).colorScheme.title, + )), + AnimatedVisibility( + isVisible: state.showContactUs, + duration: DesignConfig.lowAnimationDuration, + child: Padding( + padding: + const EdgeInsets.only(right: 8.0, top: 8), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + vertical: 12), + child: MenuOption( + icon: DidvanIcons.support_regular, + title: 'پیام به پشتیبانی', + onTap: () { + Navigator.of(context).pushNamed( + Routes.direct, + arguments: { + 'type': 'پشتیبانی اپلیکیشن' + }, + ); + }, + ), + ), + Padding( + padding: const EdgeInsets.only(top: 12), + child: MenuOption( + icon: DidvanIcons.chats_regular, + title: 'صندوق پیام', + onTap: () { + Navigator.of(context) + .pushNamed(Routes.directList) + .then( + (value) => state.init(), + ); + }, + trailing: Row( + children: [ + if (state.unread > 0) + Container( + width: 18, + height: 18, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context) + .colorScheme + .secondary, + ), + alignment: Alignment.center, + child: DidvanText( + state.unread.toString(), + color: Colors.white, + fontSize: 12, + ), + ), + const SizedBox( + width: 12, + ), + Icon( + DidvanIcons.angle_left_regular, + size: 18, + color: Theme.of(context) + .colorScheme + .title, + ) + ], + ), + ), + ), + ], + ), + )), + const DidvanDivider(), + MenuOption( + icon: DidvanIcons.alert_regular, + title: 'حریم خصوصی', + onTap: () => launchUrl( + Uri.parse( + 'https://didvan.app/terms-of-use#privacy'), + ), + ), + ], + ), + ), + const SizedBox(height: 16), + DidvanText( + 'نسخه نرم‌افزار: 3.2.2', + style: Theme.of(context).textTheme.bodySmall, + ), + ], + ), + )); + } + + Future _showFontFamilyBottomSheet() async { + final themeProvider = context.read(); + final state = context.read(); + final family = state.fontFamily; + await ActionSheetUtils.showBottomSheet( + data: ActionSheetData( + content: StatefulBuilder( + builder: (context, setState) => Column( + children: [ + DidvanRadialButton( + title: 'دانا', + fontFamily: 'Dana-FA', + onSelected: () { + state.fontFamily = 'Dana-FA'; + setState(() {}); + }, + value: state.fontFamily == 'Dana-FA', + ), + const SizedBox(height: 24), + DidvanRadialButton( + title: 'ایران سنس', + fontFamily: 'Iransans-FA', + onSelected: () { + state.fontFamily = 'Iransans-FA'; + setState(() {}); + }, + value: state.fontFamily == 'Iransans-FA', + ), + ], + ), + ), + title: 'انتخاب فونت برنامه', + titleIcon: DidvanIcons.font_regular, + onDismissed: () => state.fontFamily = family, + onConfirmed: () => themeProvider.fontFamily = state.fontFamily, + ), + ); + } + + Future _showFontScaleBottomSheet() async { + final themeProvider = context.read(); + final state = context.read(); + final scale = state.fontSizeScale; + await ActionSheetUtils.showBottomSheet( + data: ActionSheetData( + content: StatefulBuilder( + builder: (context, setState) => Column( + children: [ + DidvanRadialButton( + title: 'بزرگ', + fontSize: 15 * 1.15, + onSelected: () { + state.fontSizeScale = 1.15; + setState(() {}); + }, + value: state.fontSizeScale == 1.15, + ), + const SizedBox(height: 24), + DidvanRadialButton( + title: 'متوسط', + onSelected: () { + state.fontSizeScale = 1; + setState(() {}); + }, + value: state.fontSizeScale == 1, + ), + const SizedBox(height: 24), + DidvanRadialButton( + title: 'کوچک', + fontSize: 15 * 0.85, + onSelected: () { + state.fontSizeScale = 0.85; + setState(() {}); + }, + value: state.fontSizeScale == 0.85, + ), + ], + ), + ), + title: 'انتخاب اندازه متن', + titleIcon: DidvanIcons.font_regular, + onDismissed: () => state.fontSizeScale = scale, + onConfirmed: () => themeProvider.fontScale = state.fontSizeScale, + ), + ); + } + + Widget _themeItem( + BuildContext context, GeneralSettingsState state, String brightness) { + final bool isDarkTheme = brightness == 'dark'; + return GestureDetector( + onTap: () { + state.brightness = brightness; + if (isDarkTheme && DesignConfig.isDark) { + return; + } else if (!isDarkTheme && !DesignConfig.isDark) { + return; + } else { + if (isDarkTheme) { + context.read().themeMode = ThemeMode.dark; + } else { + context.read().themeMode = ThemeMode.light; + } + DesignConfig.updateSystemUiOverlayStyle(); + } + }, + child: Column( + children: [ + SvgPicture.asset(isDarkTheme ? Assets.darkTheme : Assets.lightTheme), + const SizedBox(height: 8), + DidvanText( + isDarkTheme ? 'تیره' : 'روشن', + ), + ], + ), + ); + } +} diff --git a/lib/views/widgets/didvan/app_bar.dart b/lib/views/widgets/didvan/app_bar.dart index 2966f72..a805b89 100644 --- a/lib/views/widgets/didvan/app_bar.dart +++ b/lib/views/widgets/didvan/app_bar.dart @@ -36,17 +36,20 @@ class DidvanAppBar extends StatelessWidget implements PreferredSizeWidget { ), child: Row( children: [ - appBarData.hasBack? Column( - children: [ - IconButton( - onPressed: () => Navigator.of(context).pop(), - color: Theme.of(context).colorScheme.title, - icon: const Icon( - DidvanIcons.back_regular, - ), - ), - ], - ):const SizedBox(), + appBarData.hasBack + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + onPressed: () => Navigator.of(context).pop(), + color: Theme.of(context).colorScheme.title, + icon: const Icon( + DidvanIcons.back_regular, + ), + ), + ], + ) + : const SizedBox(), const SizedBox(width: 16), Expanded( child: Align( diff --git a/lib/views/widgets/didvan/bnb.dart b/lib/views/widgets/didvan/bnb.dart index 2b5d175..06eb1ca 100644 --- a/lib/views/widgets/didvan/bnb.dart +++ b/lib/views/widgets/didvan/bnb.dart @@ -52,23 +52,23 @@ class DidvanBNB extends StatelessWidget { ), _NavBarItem( isSelected: currentTabIndex == 1, - title: 'آمار و داده', - selectedIcon: DidvanIcons.stats__solid, - unselectedIcon: DidvanIcons.stats__light, + title: 'دسته‌بندی', + selectedIcon: DidvanIcons.category_solid, + unselectedIcon: DidvanIcons.category_light, onTap: () => onTabChanged(1), ), _NavBarItem( isSelected: currentTabIndex == 2, - title: 'دسته‌بندی', - selectedIcon: DidvanIcons.category_solid, - unselectedIcon: DidvanIcons.category_light, + title: 'هوش مصنوعی', + selectedIcon: DidvanIcons.ai_solid, + unselectedIcon: DidvanIcons.ai_regular, onTap: () => onTabChanged(2), ), _NavBarItem( isSelected: currentTabIndex == 3, - title: 'رصدخانه من', - selectedIcon: DidvanIcons.antenna_solid, - unselectedIcon: DidvanIcons.antenna_light, + title: 'آمار و داده', + selectedIcon: DidvanIcons.stats__solid, + unselectedIcon: DidvanIcons.stats__light, onTap: () => onTabChanged(3), ), ], diff --git a/lib/views/widgets/didvan/scaffold.dart b/lib/views/widgets/didvan/scaffold.dart index c16c0d7..d64fdd7 100644 --- a/lib/views/widgets/didvan/scaffold.dart +++ b/lib/views/widgets/didvan/scaffold.dart @@ -15,6 +15,7 @@ class DidvanScaffold extends StatefulWidget { final ScrollController? scrollController; final bool showSliversFirst; final bool hidePlayer; + final Widget? floatingActionButton; const DidvanScaffold({ Key? key, @@ -28,6 +29,7 @@ class DidvanScaffold extends StatefulWidget { this.scrollController, this.showSliversFirst = false, this.hidePlayer = false, + this.floatingActionButton, }) : super(key: key); @override @@ -60,6 +62,7 @@ class _DidvanScaffoldState extends State { MediaQuery.of(context).padding.bottom; return Scaffold( backgroundColor: widget.backgroundColor, + floatingActionButton: widget.floatingActionButton, body: Padding( padding: widget.appBarData == null ? EdgeInsets.zero diff --git a/lib/views/widgets/logo_app_bar.dart b/lib/views/widgets/logo_app_bar.dart index 2b65a9d..7cdcb6e 100644 --- a/lib/views/widgets/logo_app_bar.dart +++ b/lib/views/widgets/logo_app_bar.dart @@ -56,38 +56,25 @@ class LogoAppBar extends StatelessWidget implements PreferredSizeWidget { ), Row( children: [ - DidvanIconButton( - icon: DidvanIcons.profile_light, - size: 32, - onPressed: () => - Navigator.of(context).pushNamed(Routes.profile), - ), - Container( - height: 32, - width: 1, - color: Theme.of(context).colorScheme.border, - ), Consumer( builder: (_, state, __) => Stack( children: [ DidvanIconButton( - icon: state.unread == 0 - ? DidvanIcons.message_light - : DidvanIcons.message_solid, + icon: DidvanIcons.profile_light, size: 32, onPressed: () => Navigator.of(context) - .pushNamed(Routes.directList) + .pushNamed(Routes.profile) .then( (value) => state.init(), ), ), if (state.unread > 0) Positioned( - top: 8, - right: 4, + bottom: 15, + right: 12, child: Container( - height: 12, - width: 12, + height: 10, + width: 10, decoration: BoxDecoration( shape: BoxShape.circle, color: Theme.of(context).colorScheme.secondary, @@ -96,7 +83,18 @@ class LogoAppBar extends StatelessWidget implements PreferredSizeWidget { ), ], ), - ) + ), + Container( + height: 32, + width: 1, + color: Theme.of(context).colorScheme.border, + ), + DidvanIconButton( + icon: DidvanIcons.antenna_light, + size: 32, + onPressed: () => + Navigator.of(context).pushNamed(Routes.bookmarks), + ), ], ), ], diff --git a/lib/views/widgets/state_handlers/empty_state.dart b/lib/views/widgets/state_handlers/empty_state.dart index c1e99bb..ce76662 100644 --- a/lib/views/widgets/state_handlers/empty_state.dart +++ b/lib/views/widgets/state_handlers/empty_state.dart @@ -11,6 +11,7 @@ class EmptyState extends StatelessWidget { final String? buttonTitle; final VoidCallback? action; final Color? titleColor; + final double? height; const EmptyState({ Key? key, @@ -20,6 +21,7 @@ class EmptyState extends StatelessWidget { this.buttonTitle, this.subtitle, this.titleColor, + this.height, }) : super(key: key); @override @@ -27,7 +29,7 @@ class EmptyState extends StatelessWidget { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - SizedBox(height: 210, child: SvgPicture.asset(asset)), + SizedBox(height: height ?? 210, child: SvgPicture.asset(asset)), const SizedBox(height: 16), DidvanText( title, diff --git a/lib/views/widgets/state_handlers/sliver_state_handler.dart b/lib/views/widgets/state_handlers/sliver_state_handler.dart index 8338a49..b05cbbe 100644 --- a/lib/views/widgets/state_handlers/sliver_state_handler.dart +++ b/lib/views/widgets/state_handlers/sliver_state_handler.dart @@ -14,6 +14,7 @@ class SliverStateHandler extends SliverList { final EdgeInsets? itemPadding; final bool centerEmptyState; final bool hasConstraints; + final int placeholderCount; SliverStateHandler({ Key? key, required this.state, @@ -26,6 +27,7 @@ class SliverStateHandler extends SliverList { this.enableEmptyState = false, this.centerEmptyState = true, this.hasConstraints = false, + this.placeholderCount = 3, }) : super( key: key, delegate: SliverChildBuilderDelegate( @@ -65,7 +67,7 @@ class SliverStateHandler extends SliverList { ? 1 : childCount : state.appState == AppState.busy - ? 3 + ? placeholderCount : 1, ), ); diff --git a/pubspec.lock b/pubspec.lock index cc66b4a..d51cec8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -371,6 +371,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_markdown: + dependency: "direct main" + description: + name: flutter_markdown + sha256: a23c41ee57573e62fc2190a1f36a0480c4d90bde3a8a8d7126e5d5992fb53fb7 + url: "https://pub.dev" + source: hosted + version: "0.7.3+1" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -661,6 +669,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + markdown: + dependency: transitive + description: + name: markdown + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 + url: "https://pub.dev" + source: hosted + version: "7.2.2" matcher: dependency: transitive description: @@ -1066,6 +1082,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + typewritertext: + dependency: "direct main" + description: + name: typewritertext + sha256: acfe197417b49943694618140ee7080c8361e4011ab8b0e64898ba35b403f9c7 + url: "https://pub.dev" + source: hosted + version: "3.0.8" universal_html: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 79e2f3e..5b0594a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -86,6 +86,8 @@ dependencies: just_audio: ^0.9.39 video_player: ^2.8.7 chewie: ^1.8.3 + typewritertext: ^3.0.8 + flutter_markdown: ^0.7.3+1 # onesignal_flutter: ^3.5.0 dev_dependencies: