redesign splash screen

This commit is contained in:
mohamadmahdi jebeli 2025-10-06 14:10:40 +03:30
parent 292f6ec769
commit f96e9557d5
46 changed files with 1270 additions and 309 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,4 @@
<svg width="56" height="57" viewBox="0 0 56 57" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect y="0.5" width="56" height="56" rx="28" fill="#195D80"/>
<path d="M39.7734 23.1801L31.04 16.1934C29.3334 14.8334 26.6667 14.8201 24.9734 16.1801L16.24 23.1801C14.9867 24.1801 14.2267 26.1801 14.4934 27.7534L16.1734 37.8068C16.56 40.0601 18.6534 41.8334 20.9334 41.8334H35.0667C37.32 41.8334 39.4534 40.0201 39.84 37.7934L41.52 27.7401C41.76 26.1801 41 24.1801 39.7734 23.1801ZM29 36.5001C29 37.0468 28.5467 37.5001 28 37.5001C27.4534 37.5001 27 37.0468 27 36.5001V32.5001C27 31.9534 27.4534 31.5001 28 31.5001C28.5467 31.5001 29 31.9534 29 32.5001V36.5001Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 681 B

View File

@ -0,0 +1,6 @@
<svg width="33" height="33" viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.5 16.2166C20.1819 16.2166 23.1667 13.2319 23.1667 9.54997C23.1667 5.86807 20.1819 2.8833 16.5 2.8833C12.8181 2.8833 9.83337 5.86807 9.83337 9.54997C9.83337 13.2319 12.8181 16.2166 16.5 16.2166Z" stroke="#666666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M26.1133 21.2034L21.3933 25.9234C21.2066 26.1101 21.0333 26.4567 20.9933 26.71L20.74 28.51C20.6466 29.1633 21.1 29.6167 21.7533 29.5234L23.5533 29.27C23.8066 29.23 24.1666 29.0567 24.34 28.87L29.0599 24.1501C29.8733 23.3367 30.2599 22.39 29.0599 21.19C27.8733 20.0034 26.9267 20.39 26.1133 21.2034Z" stroke="#666666" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M25.4333 21.8833C25.8333 23.3233 26.9533 24.4433 28.3933 24.8433" stroke="#666666" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.04663 29.55C5.04663 24.39 10.18 20.2167 16.5 20.2167C17.8867 20.2167 19.22 20.4167 20.46 20.79" stroke="#666666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

3
lib/assets/icons/bot.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="41" height="41" viewBox="0 0 41 41" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24.8 11.5C24.2696 11.5 23.7609 11.7107 23.3858 12.0858C23.0108 12.4609 22.8 12.9696 22.8 13.5C22.8 14.0304 23.0108 14.5391 23.3858 14.9142C23.7609 15.2893 24.2696 15.5 24.8 15.5C25.3305 15.5 25.8392 15.2893 26.2143 14.9142C26.5893 14.5391 26.8 14.0304 26.8 13.5C26.8 12.9696 26.5893 12.4609 26.2143 12.0858C25.8392 11.7107 25.3305 11.5 24.8 11.5ZM14.8 13.5C14.8 12.9696 15.0108 12.4609 15.3858 12.0858C15.7609 11.7107 16.2696 11.5 16.8 11.5C17.3305 11.5 17.8392 11.7107 18.2143 12.0858C18.5893 12.4609 18.8 12.9696 18.8 13.5C18.8 14.0304 18.5893 14.5391 18.2143 14.9142C17.8392 15.2893 17.3305 15.5 16.8 15.5C16.2696 15.5 15.7609 15.2893 15.3858 14.9142C15.0108 14.5391 14.8 14.0304 14.8 13.5ZM21.8 5.5C21.8 5.23478 21.6947 4.98043 21.5072 4.79289C21.3196 4.60536 21.0653 4.5 20.8 4.5C20.5348 4.5 20.2805 4.60536 20.0929 4.79289C19.9054 4.98043 19.8 5.23478 19.8 5.5V6.5H13.8C13.0044 6.5 12.2413 6.81607 11.6787 7.37868C11.1161 7.94129 10.8 8.70435 10.8 9.5V17.5C10.8 18.2956 11.1161 19.0587 11.6787 19.6213C12.2413 20.1839 13.0044 20.5 13.8 20.5H27.8C28.5957 20.5 29.3588 20.1839 29.9214 19.6213C30.484 19.0587 30.8 18.2956 30.8 17.5V9.5C30.8 8.70435 30.484 7.94129 29.9214 7.37868C29.3588 6.81607 28.5957 6.5 27.8 6.5H21.8V5.5ZM13.8 8.5H27.8C28.0653 8.5 28.3196 8.60536 28.5072 8.79289C28.6947 8.98043 28.8 9.23478 28.8 9.5V17.5C28.8 17.7652 28.6947 18.0196 28.5072 18.2071C28.3196 18.3946 28.0653 18.5 27.8 18.5H13.8C13.5348 18.5 13.2805 18.3946 13.0929 18.2071C12.9054 18.0196 12.8 17.7652 12.8 17.5V9.5C12.8 9.23478 12.9054 8.98043 13.0929 8.79289C13.2805 8.60536 13.5348 8.5 13.8 8.5ZM21.3 36.496C26.532 36.43 29.69 35.306 31.544 33.616C33.294 32.016 33.7221 30.062 33.7901 28.504H33.8V27.124C33.7995 26.1643 33.4179 25.244 32.7391 24.5656C32.0602 23.8871 31.1398 23.506 30.18 23.506H23.8V23.5H17.8V23.506H11.42C9.42005 23.506 7.80005 25.126 7.80005 27.126V28.504H7.81005C7.87805 30.064 8.30605 32.018 10.056 33.614C11.91 35.306 15.068 36.43 20.3 36.496V36.5H21.3V36.496ZM11.42 25.506H30.18C30.6097 25.506 31.0218 25.6767 31.3256 25.9805C31.6294 26.2843 31.8 26.6963 31.8 27.126V28C31.8 29.38 31.538 30.912 30.196 32.138C28.82 33.392 26.12 34.5 20.8 34.5C15.48 34.5 12.78 33.392 11.404 32.138C10.064 30.912 9.80005 29.378 9.80005 28V27.124C9.80058 26.6947 9.97149 26.2832 10.2752 25.9798C10.579 25.6764 10.9907 25.506 11.42 25.506Z" fill="#666666"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,3 @@
<svg width="32" height="33" viewBox="0 0 32 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M27.7734 11.1801L19.04 4.19344C17.3334 2.83344 14.6667 2.82011 12.9734 4.18011L4.24003 11.1801C2.9867 12.1801 2.2267 14.1801 2.49337 15.7534L4.17337 25.8068C4.56003 28.0601 6.65336 29.8334 8.93336 29.8334H23.0667C25.32 29.8334 27.4534 28.0201 27.84 25.7934L29.52 15.7401C29.76 14.1801 29 12.1801 27.7734 11.1801ZM17 24.5001C17 25.0468 16.5467 25.5001 16 25.5001C15.4534 25.5001 15 25.0468 15 24.5001V20.5001C15 19.9534 15.4534 19.5001 16 19.5001C16.5467 19.5001 17 19.9534 17 20.5001V24.5001Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 621 B

View File

@ -0,0 +1,3 @@
<svg width="29" height="29" viewBox="0 0 29 29" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24 17C24.0025 17.4077 23.8786 17.8062 23.6454 18.1407C23.4121 18.4751 23.081 18.729 22.6975 18.8675L16.25 21.25L13.875 27.7025C13.7343 28.0846 13.4798 28.4143 13.1459 28.6473C12.812 28.8802 12.4146 29.0051 12.0075 29.0051C11.6003 29.0051 11.2029 28.8802 10.869 28.6473C10.5351 28.4143 10.2806 28.0846 10.14 27.7025L7.74995 21.25L1.29745 18.875C0.915366 18.7344 0.585613 18.4799 0.352687 18.146C0.119761 17.812 -0.00512695 17.4147 -0.00512695 17.0075C-0.00512695 16.6003 0.119761 16.203 0.352687 15.869C0.585613 15.5351 0.915366 15.2806 1.29745 15.14L7.74995 12.75L10.125 6.2975C10.2656 5.91541 10.5201 5.58566 10.854 5.35273C11.1879 5.11981 11.5853 4.99492 11.9925 4.99492C12.3996 4.99492 12.797 5.11981 13.1309 5.35273C13.4648 5.58566 13.7193 5.91541 13.86 6.2975L16.25 12.75L22.7025 15.125C23.0862 15.2647 23.4172 15.5202 23.6496 15.856C23.882 16.1919 24.0044 16.5916 24 17ZM17 5H19V7C19 7.26522 19.1053 7.51957 19.2928 7.70711C19.4804 7.89464 19.7347 8 20 8C20.2652 8 20.5195 7.89464 20.7071 7.70711C20.8946 7.51957 21 7.26522 21 7V5H23C23.2652 5 23.5195 4.89464 23.7071 4.70711C23.8946 4.51957 24 4.26522 24 4C24 3.73478 23.8946 3.48043 23.7071 3.29289C23.5195 3.10536 23.2652 3 23 3H21V1C21 0.734784 20.8946 0.48043 20.7071 0.292893C20.5195 0.105357 20.2652 0 20 0C19.7347 0 19.4804 0.105357 19.2928 0.292893C19.1053 0.48043 19 0.734784 19 1V3H17C16.7347 3 16.4804 3.10536 16.2928 3.29289C16.1053 3.48043 16 3.73478 16 4C16 4.26522 16.1053 4.51957 16.2928 4.70711C16.4804 4.89464 16.7347 5 17 5ZM28 9H27V8C27 7.73478 26.8946 7.48043 26.7071 7.29289C26.5195 7.10536 26.2652 7 26 7C25.7347 7 25.4804 7.10536 25.2928 7.29289C25.1053 7.48043 25 7.73478 25 8V9H24C23.7347 9 23.4804 9.10536 23.2928 9.29289C23.1053 9.48043 23 9.73478 23 10C23 10.2652 23.1053 10.5196 23.2928 10.7071C23.4804 10.8946 23.7347 11 24 11H25V12C25 12.2652 25.1053 12.5196 25.2928 12.7071C25.4804 12.8946 25.7347 13 26 13C26.2652 13 26.5195 12.8946 26.7071 12.7071C26.8946 12.5196 27 12.2652 27 12V11H28C28.2652 11 28.5195 10.8946 28.7071 10.7071C28.8946 10.5196 29 10.2652 29 10C29 9.73478 28.8946 9.48043 28.7071 9.29289C28.5195 9.10536 28.2652 9 28 9Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 21.6001C11.116 21.6001 10.4 20.8841 10.4 20.0001C10.4 19.1161 11.116 18.4001 12 18.4001C12.884 18.4001 13.6 19.1161 13.6 20.0001C13.6 20.8841 12.884 21.6001 12 21.6001ZM23.2 19.2001H15.0872C14.728 17.7873 13.456 16.8001 12 16.8001C10.544 16.8001 9.272 17.7873 8.9128 19.2001H0.8C0.3592 19.2001 0 19.5593 0 20.0001C0 20.4409 0.3592 20.8001 0.8 20.8001H8.9128C9.272 22.2129 10.544 23.2001 12 23.2001C13.456 23.2001 14.728 22.2129 15.0872 20.8001H23.2C23.6408 20.8001 24 20.4409 24 20.0001C24 19.5593 23.6408 19.2001 23.2 19.2001ZM20 13.6C19.116 13.6 18.4 12.884 18.4 12C18.4 11.116 19.116 10.4 20 10.4C20.884 10.4 21.6 11.116 21.6 12C21.6 12.884 20.884 13.6 20 13.6ZM23.2 11.2001H23.0872C22.728 9.7873 21.456 8.8001 20 8.8001C18.544 8.8001 17.272 9.7873 16.9128 11.2001H0.8C0.3592 11.2001 0 11.5593 0 12.0001C0 12.4409 0.3592 12.8001 0.8 12.8001H16.9128C17.272 14.2129 18.544 15.2001 20 15.2001C21.456 15.2001 22.728 14.2129 23.0872 12.8001H23.2C23.6408 12.8001 24 12.4409 24 12.0001C24 11.5593 23.6408 11.2001 23.2 11.2001ZM3.99991 2.39999C4.88391 2.39999 5.59991 3.11599 5.59991 3.99999C5.59991 4.88399 4.88391 5.59999 3.99991 5.59999C3.11591 5.59999 2.39991 4.88399 2.39991 3.99999C2.39991 3.11599 3.11591 2.39999 3.99991 2.39999ZM0.8 4.80005H0.9128C1.272 6.21285 2.544 7.20005 4 7.20005C5.456 7.20005 6.728 6.21285 7.0872 4.80005H23.2C23.6408 4.80005 24 4.44085 24 4.00005C24 3.55925 23.6408 3.20005 23.2 3.20005H7.0872C6.728 1.78725 5.456 0.800049 4 0.800049C2.544 0.800049 1.272 1.78725 0.9128 3.20005H0.8C0.3592 3.20005 0 3.55925 0 4.00005C0 4.44085 0.3592 4.80005 0.8 4.80005Z" fill="#666666"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.7048 22.3252L19.5794 18.2947L19.4858 18.1495C19.3034 17.966 19.0598 17.8676 18.8018 17.8676C18.5487 17.8676 18.3003 17.966 18.1227 18.1495C14.6164 21.3641 9.2167 21.5381 5.49928 18.5563C1.78186 15.5709 0.905897 10.3585 3.45098 6.37124C5.99606 2.38514 11.1714 0.863659 15.544 2.81351C19.9178 4.76336 22.1341 9.5798 20.7194 14.0711C20.621 14.3998 20.7002 14.7514 20.9389 14.9998C21.1741 15.2482 21.5305 15.3514 21.8677 15.2758C22.2049 15.2014 22.4773 14.9518 22.5805 14.629C24.2676 9.30022 21.7177 3.56345 16.5808 1.12884C11.4426 -1.30218 5.25569 0.300902 2.02664 4.90255C-1.2036 9.5054 -0.510036 15.7209 3.66217 19.5366C7.82837 23.3476 14.2229 23.6091 18.7035 20.151L22.3549 23.7219C22.7305 24.0927 23.3388 24.0927 23.7192 23.7219C24.0936 23.3512 24.0936 22.7512 23.7192 22.3768L23.7048 22.3252Z" fill="#666666"/>
</svg>

After

Width:  |  Height:  |  Size: 969 B

View File

@ -0,0 +1,7 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 19.8533C7.45333 19.8533 7 19.4 7 18.8533V13.1333C7 12.5866 7.45333 12.1333 8 12.1333C8.54667 12.1333 9 12.5866 9 13.1333V18.8533C9 19.4133 8.54667 19.8533 8 19.8533Z" fill="#007EA7"/>
<path d="M12 21.76C11.4533 21.76 11 21.3067 11 20.76V11.24C11 10.6933 11.4533 10.24 12 10.24C12.5467 10.24 13 10.6933 13 11.24V20.76C13 21.32 12.5467 21.76 12 21.76Z" fill="#007EA7"/>
<path d="M16 23.6666C15.4533 23.6666 15 23.2133 15 22.6666V9.33325C15 8.78659 15.4533 8.33325 16 8.33325C16.5467 8.33325 17 8.78659 17 9.33325V22.6666C17 23.2133 16.5467 23.6666 16 23.6666Z" fill="#007EA7"/>
<path d="M20 21.76C19.4533 21.76 19 21.3067 19 20.76V11.24C19 10.6933 19.4533 10.24 20 10.24C20.5467 10.24 21 10.6933 21 11.24V20.76C21 21.32 20.5467 21.76 20 21.76Z" fill="#007EA7"/>
<path d="M24 19.8533C23.4533 19.8533 23 19.4 23 18.8533V13.1333C23 12.5866 23.4533 12.1333 24 12.1333C24.5467 12.1333 25 12.5866 25 13.1333V18.8533C25 19.4133 24.5467 19.8533 24 19.8533Z" fill="#007EA7"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -7,9 +7,10 @@ class LightThemeConfig {
static const Color _primary = Color(0xFF007EA7);
static const Color _white = Color(0xFFFFFFFF);
static const Color _black = Color(0xFF292929);
static const Color _background = Color(0xFFF8F8FA);
static const Color _background = Color(0xFFFFFFFF);
static ThemeData get themeData => ThemeData(
fontFamily: 'IranYekan',
scaffoldBackgroundColor: _background,
textTheme: _TextThemeData.data,
cardColor: _colorScheme.surface,
@ -53,6 +54,7 @@ class DarkThemeConfig {
static const Color _background = Color(0xFF202224);
static ThemeData get themeData => ThemeData(
fontFamily: 'IranYekan',
scaffoldBackgroundColor: _background,
textTheme: _TextThemeData.data,
iconTheme: IconThemeData(
@ -97,7 +99,6 @@ class DarkThemeConfig {
static const Color hint = Color(0xFFBBBBBB);
static const Color border = Color(0xFF666666);
// Error and success
static const Color errorLight = Color(0xFFF0C9CD);
static const Color error = Color(0xFFF53B3B);
static const Color successLight = Color(0xFFBBD6B4);
@ -120,35 +121,41 @@ class _TextThemeData {
static TextStyle get _headline3Text => TextStyle(
fontSize: 20 * DesignConfig.fontScale,
fontWeight: FontWeight.w600,
fontFamily: 'IranYekan',
);
static TextStyle get _subtitle1Text => TextStyle(
fontSize: 17 * DesignConfig.fontScale,
fontWeight: FontWeight.w700,
fontFamily: 'IranYekan',
);
static TextStyle get _subtitle2Text => TextStyle(
fontSize: 15 * DesignConfig.fontScale,
fontWeight: FontWeight.w700,
fontFamily: 'IranYekan',
);
static TextStyle get _body1Text => TextStyle(
fontSize: 15 * DesignConfig.fontScale,
fontWeight: FontWeight.w700,
fontFamily: 'IranYekan',
);
static TextStyle get _body2Text => TextStyle(
fontSize: 15 * DesignConfig.fontScale,
fontWeight: FontWeight.w400,
fontFamily: 'IranYekan',
);
static TextStyle get _captionText => TextStyle(
fontSize: 13 * DesignConfig.fontScale,
fontWeight: FontWeight.w400,
fontFamily: 'IranYekan',
);
static TextStyle get _overlineText => TextStyle(
fontSize: 12 * DesignConfig.fontScale,
fontWeight: FontWeight.w300,
fontFamily: 'IranYekan',
);
}
extension DidvanColorScheme on ColorScheme {
// Secondary colors
Color get secondaryDisabled => brightness == Brightness.dark
? const Color(0xFFFFC8D7)
: const Color(0xFF703848);
@ -210,7 +217,6 @@ extension DidvanColorScheme on ColorScheme {
: const Color(0xFFffffff);
Color get yellow => const Color(0XFFEAA92A);
// Error and success colors
Color get errorBack => brightness == Brightness.dark
? const Color(0xFF2B2325)
: const Color(0xFFFFF8F8);

View File

@ -1,5 +1,3 @@
// lib/main.dart
// ignore_for_file: deprecated_member_use
import 'dart:async';

View File

View File

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
class ThemeProvider extends CoreProvier {
ThemeMode _themeMode = ThemeMode.system;
String _fontFamily = 'Dana-FA';
String _fontFamily = 'IranYekan';
double _fontScale = 1;
set themeMode(ThemeMode value) {

View File

@ -185,7 +185,7 @@ class AppInitializer {
);
await StorageService.setValue(
key: 'fontFamily',
value: 'Dana-FA',
value: 'IranYekan',
);
await StorageService.setValue(
key: 'fontSizeScale',
@ -196,7 +196,7 @@ class AppInitializer {
value: 'light',
);
return SettingsData(
fontFamily: 'Dana-FA',
fontFamily: 'IranYekan',
fontScale: 1,
themeMode: ThemeMode.light,
);
@ -212,7 +212,7 @@ class AppInitializer {
);
await StorageService.setValue(
key: 'fontFamily',
value: 'Dana-FA',
value: 'IranYekan',
);
await StorageService.setValue(
key: 'fontSizeScale',
@ -223,7 +223,7 @@ class AppInitializer {
value: 'light',
);
return SettingsData(
fontFamily: 'Dana-FA',
fontFamily: 'IranYekan',
fontScale: 1,
themeMode: ThemeMode.light,
);

View File

View File

View File

View File

@ -1,32 +1,19 @@
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/notification_message.dart';
import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/providers/theme.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/services/app_initalizer.dart';
import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/views/ai/ai_state.dart';
import 'package:didvan/views/ai/ai.dart';
import 'package:didvan/views/ai/history_ai_chat_state.dart';
import 'package:didvan/views/ai/widgets/hoshan_drawer.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';
import 'package:didvan/views/home/new_statistic/new_statistic.dart';
import 'package:didvan/views/home/search/search.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/hoshan_app_bar.dart';
import 'package:didvan/views/widgets/ink_wrapper.dart';
import 'package:didvan/views/widgets/logo_app_bar.dart';
import 'package:didvan/views/widgets/didvan/bnb.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart';
import '../../services/app_home_widget/home_widget_repository.dart';
@ -53,20 +40,11 @@ class _HomeState extends State<Home>
final state = context.read<HomeState>();
DesignConfig.updateSystemUiOverlayStyle();
_tabController = TabController(length: 4, vsync: this, initialIndex: 0);
_tabController = TabController(length: 3, vsync: this, initialIndex: 0);
state.tabController = _tabController;
_tabController.addListener(() {
state.currentPageIndex = _tabController.index;
if (_tabController.index == 3) {
// Changed from 2 to 3 for Houshan tab
// با هر بار ورود به تب هوشان، لیست چتها ریست میشود
final historyState = context.read<HistoryAiChatState>();
historyState.chats.clear();
historyState.archivedChats.clear();
historyState.update(); // برای اطمینان از بهروزرسانی UI
historyState.getBots();
}
});
if (!kIsWeb) {
Future.delayed(Duration.zero, () {
@ -87,33 +65,17 @@ class _HomeState extends State<Home>
super.initState();
}
PreferredSizeWidget getAppBar() {
// Show HoshanAppBar only for AI section (index 3)
if (context.watch<HomeState>().tabController.index == 3) {
return HoshanAppBar(
onBack: () {
final state = context.read<AiState>();
if (state.page == 1) {
state.goToAi();
}
},
);
}
// For all other tabs (home, categories, statistics), show LogoAppBar
return const LogoAppBar();
PreferredSizeWidget? getAppBar() {
return null;
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: homeScaffKey,
appBar: getAppBar(),
backgroundColor: Theme.of(context).colorScheme.background,
resizeToAvoidBottomInset: false,
drawer: context.watch<HomeState>().tabController.index == 2
? HoshanDrawer(
scaffKey: homeScaffKey,
)
: null,
drawer: null,
// ignore: deprecated_member_use
body: WillPopScope(
onWillPop: () async {
@ -133,16 +95,6 @@ class _HomeState extends State<Home>
confrimTitle: 'بله',
dismissTitle: 'خیر',
));
} else if (context.read<HomeState>().tabController.index == 3) {
// Changed from 2 to 3
switch (context.read<AiState>().page) {
case 1:
context.read<AiState>().goToAi();
break;
default:
_tabController.animateTo(0);
}
} else {
_tabController.animateTo(0);
}
@ -164,7 +116,6 @@ class _HomeState extends State<Home>
MainPage(),
CategoriesPage(),
NewStatistic(),
Ai(),
],
),
),

View File

@ -1,5 +1,6 @@
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/home_page_content/home_page_list.dart';
import 'package:didvan/models/home_page_content/swot.dart';
@ -14,6 +15,14 @@ import 'package:didvan/views/home/main/widgets/story_section.dart';
import 'package:didvan/views/widgets/didvan/slider.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
import 'package:didvan/views/widgets/search_field.dart';
import 'package:didvan/views/home/home_state.dart';
import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/views/widgets/didvan/checkbox.dart';
import 'package:didvan/views/widgets/text_divider.dart';
import 'package:didvan/views/widgets/item_title.dart';
import 'package:didvan/views/widgets/date_picker_button.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
@ -23,13 +32,10 @@ import 'package:url_launcher/url_launcher_string.dart';
import 'package:didvan/views/home/main/widgets/swot_item_card.dart';
import 'package:flutter/foundation.dart' show kIsWeb, defaultTargetPlatform;
import 'package:flutter/material.dart'; // برای دسترسی به TargetPlatform
// این پکیج فقط برای نسخه وب استفاده میشود
import 'package:universal_html/html.dart' as html;
/// تشخیص میدهد که آیا دستگاه یک موبایل است (چه نیتیو و چه وب)
bool isAnyMobile() {
// اگر کد روی وب در حال اجراست
if (kIsWeb) {
final userAgent = html.window.navigator.userAgent.toLowerCase();
return userAgent.contains('mobile') ||
@ -37,8 +43,6 @@ bool isAnyMobile() {
userAgent.contains('ios');
}
// اگر کد روی پلتفرم نیتیو در حال اجراست
// defaultTargetPlatform پلتفرم اصلی (مثلا اندروید یا iOS) را برمیگرداند
return defaultTargetPlatform == TargetPlatform.android ||
defaultTargetPlatform == TargetPlatform.iOS;
}
@ -79,11 +83,73 @@ class _MainPageState extends State<MainPage> {
print(
"DEBUG: FutureBuilder state.content!.lists.isNotEmpty: ${state.content!.lists.isNotEmpty}");
return ListView(
padding: const EdgeInsets.symmetric(vertical: 16),
padding: const EdgeInsets.only(top: 0, bottom: 16),
children: [
if (state.stories.isNotEmpty) StorySection(stories: state.stories),
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.asset(
Assets.horizontalLogoWithText,
height: 60,
color: Theme.of(context).colorScheme.title,
),
GestureDetector(
onTap: () {
Navigator.pushNamed(context, Routes.profile);
},
child: SizedBox(
width: 44,
height: 44,
child: Center(
child: SvgPicture.asset(
'lib/assets/icons/New_Profile.svg',
width: 30,
height: 30,
color: Theme.of(context).colorScheme.title,
),
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
child: SearchField(
title: 'دیدوان',
focusNode: context.read<HomeState>().searchFieldFocusNode,
onChanged: (value) {
final homeState = context.read<HomeState>();
homeState.search = value;
if (value.length >= 3) {
homeState.searchAll(page: 1);
}
},
onFilterButtonPressed: () => _showFilterBottomSheet(context),
isFiltered: context.watch<HomeState>().filtering,
value: context.watch<HomeState>().search,
extraIconPath: 'lib/assets/icons/profile.svg',
onExtraIconPressed: () {
print('Extra icon pressed!');
},
),
),
if (state.stories.isNotEmpty) ...[
const TextDivider(text: 'دیده‌بان'),
const _DidvanSignalsTitle(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: StorySection(stories: state.stories),
),
],
const SizedBox(height: 12),
const MainPageMainContent(),
const TextDivider(text: 'پیشخوان استراتژیک'),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: MainPageMainContent(),
),
Builder(builder: (context) {
final List<Widget> pageContent = [];
if (state.content != null && state.content!.lists.isNotEmpty) {
@ -117,17 +183,10 @@ class _MainPageState extends State<MainPage> {
child: Row(
children: [
DidvanText(
"همه",
color: Theme.of(context)
.colorScheme
.primary,
"مشاهده همه",
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
),
Icon(
DidvanIcons.angle_left_light,
color: Theme.of(context)
.colorScheme
.primary,
)
],
),
)
@ -161,6 +220,81 @@ class _MainPageState extends State<MainPage> {
},
);
}
Future<void> _showFilterBottomSheet(BuildContext context) async {
final state = Provider.of<HomeState>(context, listen: false);
ActionSheetUtils(context).showBottomSheet(
data: ActionSheetData(
titleIcon: DidvanIcons.filter_regular,
dismissTitle: 'حذف فیلتر',
confrimTitle: 'نمایش نتایج',
onDismissed: () => state.resetFilters(false),
onConfirmed: () => state.searchAll(page: 1),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (state.currentPageIndex != 3) ...[
ItemTitle(
title: 'تاریخ ایجاد',
style: Theme.of(context).textTheme.bodyMedium,
icon: DidvanIcons.calendar_range_regular,
),
const SizedBox(height: 8),
StatefulBuilder(
builder: (context, setState) => Row(
children: [
DatePickerButton(
initialValue: state.startDate,
emptyText: 'از تاریخ',
onPicked: (date) =>
setState(() => state.startDate = date),
lastDate: state.endDate,
),
const SizedBox(width: 8),
DatePickerButton(
initialValue: state.endDate,
emptyText: 'تا تاریخ',
onPicked: (date) => setState(() => state.endDate = date),
firstDate: state.startDate,
),
],
),
),
const SizedBox(height: 28),
],
ItemTitle(
title: 'دسته بندی',
icon: DidvanIcons.category_regular,
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 12),
Wrap(
children: [
for (var i = 0; i < state.categoryFilters.length; i++)
if (state.categoryFilters[i].label != 'هوشان')
SizedBox(
width: (MediaQuery.of(context).size.width - 40) / 2,
child: DidvanCheckbox(
title: state.categoryFilters[i].label,
value: state.selectedCats
.contains(state.categoryFilters[i]),
onChanged: (value) {
if (value) {
state.selectedCats.add(state.categoryFilters[i]);
return;
}
state.selectedCats.remove(state.categoryFilters[i]);
},
),
),
],
),
],
),
),
);
}
}
class _SwotSection extends StatelessWidget {
@ -188,6 +322,7 @@ class _SwotSection extends StatelessWidget {
children: [
SvgPicture.asset(
"lib/assets/images/features/Saha Solid.svg",
color: Theme.of(context).colorScheme.title,
),
const SizedBox(width: 5),
DidvanText(
@ -206,16 +341,13 @@ class _SwotSection extends StatelessWidget {
);
},
child: Padding(
padding: const EdgeInsets.only(left: 20),
padding: EdgeInsets.only(left: 20),
child: Row(
children: [
DidvanText(
"همه",
color: Theme.of(context).colorScheme.primary,
),
Icon(
DidvanIcons.angle_left_light,
"مشاهده همه",
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
),
],
),
@ -253,7 +385,10 @@ class InfoTitle extends StatelessWidget {
Widget build(BuildContext context) {
return Row(
children: [
const Icon(DidvanIcons.infography_solid),
Icon(
DidvanIcons.infography_solid,
color: Theme.of(context).colorScheme.title,
),
const SizedBox(width: 4),
DidvanText(
"اینفوگرافی",
@ -265,6 +400,39 @@ class InfoTitle extends StatelessWidget {
}
}
class _DidvanSignalsTitle extends StatelessWidget {
const _DidvanSignalsTitle();
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
left: 16,
right: 16,
bottom: 16,
top: 0,
),
child: Row(
children: [
SvgPicture.asset(
'lib/assets/icons/voice-square.svg',
color: Theme.of(context).colorScheme.title,
width: 30,
height: 30,
),
const SizedBox(width: 5),
DidvanText(
"سیگنال‌های دیدوان",
style: Theme.of(context).textTheme.titleMedium,
color: Theme.of(context).colorScheme.title,
fontSize: 13,
),
],
),
);
}
}
class _MainPageSection extends StatelessWidget {
final MainPageList list;
final bool isLast;
@ -356,7 +524,11 @@ class _MainPageSection extends StatelessWidget {
children: [
Row(
children: [
if (icon != null) Icon(icon),
if (icon != null)
Icon(
icon,
color: Theme.of(context).colorScheme.title,
),
const SizedBox(width: 4),
DidvanText(
list.header,
@ -370,13 +542,10 @@ class _MainPageSection extends StatelessWidget {
child: Row(
children: [
DidvanText(
list.more,
"مشاهده همه",
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
),
Icon(
DidvanIcons.angle_left_light,
color: Theme.of(context).colorScheme.primary,
)
],
),
)
@ -411,10 +580,7 @@ class _MainPageSection extends StatelessWidget {
return DidvanSlider(
height: 260 + (_maxSublistCount() - (list.type == 'radar' ? 1 : 0)) * 20,
itemCount: list.contents.length,
// -- START: کد اصلاح شده در اینجا قرار دارد --
// از isMobile() برای تنظیم اندازه آیتمها بر اساس موبایل یا دسکتاپ بودن استفاده میکنیم
viewportFraction: isAnyMobile() ? 0.65 : 0.55,
// -- END: کد اصلاح شده --
itemBuilder: (context, index, realIndex) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: MainPageGeneralItem(

View File

@ -1,6 +1,7 @@
import 'package:didvan/models/story_model.dart';
import 'package:didvan/routes/routes.dart';
import 'package:flutter/material.dart';
import 'package:didvan/config/theme_data.dart';
class StorySection extends StatelessWidget {
final List<UserStories> stories;
@ -47,11 +48,9 @@ class _StoryCircle extends StatelessWidget {
@override
Widget build(BuildContext context) {
// ValueNotifier برای پیگیری وضعیت مشاهده همه استوریها
final allStoriesViewed = ValueNotifier<bool>(
userStories.stories.every((story) => story.isViewed.value));
// افزودن Listener به هر استوری
for (var story in userStories.stories) {
story.isViewed.addListener(() {
allStoriesViewed.value =
@ -64,26 +63,27 @@ class _StoryCircle extends StatelessWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// استفاده از ValueListenableBuilder برای تغییر رنگ حاشیه
ValueListenableBuilder<bool>(
valueListenable: allStoriesViewed,
builder: (context, isViewed, child) {
return Container(
width: 85.0,
height: 85.0,
return Hero(
tag: userStories.user.name,
child: Container(
width: 85.0,
height: 85.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: isViewed
? const LinearGradient(
? LinearGradient(
colors: [
Color.fromARGB(255, 184, 184, 184),
Color.fromARGB(255, 184, 184, 184)
Theme.of(context).colorScheme.cardBorder,
Theme.of(context).colorScheme.cardBorder,
],
)
: const LinearGradient(
: LinearGradient(
colors: [
Color.fromARGB(255, 1, 35, 54),
Color.fromARGB(255, 178, 4, 54),
Theme.of(context).colorScheme.primary,
Theme.of(context).colorScheme.primary,
],
begin: Alignment.topRight,
end: Alignment.bottomLeft,
@ -92,25 +92,24 @@ class _StoryCircle extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
shape: BoxShape.circle,
),
child: Padding(
padding: const EdgeInsets.all(4.0),
child: CircleAvatar(
backgroundColor:
const Color.fromARGB(255, 230, 242, 246),
backgroundColor: Theme.of(context).colorScheme.splash,
child: ClipOval(
child: Image.asset(
userStories.user
.profileImageUrl, // Assuming this is a local asset
.profileImageUrl,
fit: BoxFit.cover,
width: 50.0,
height: 50.0,
errorBuilder: (context, error, stackTrace) {
return const Icon(Icons.person,
color: Colors.grey, size: 40.0);
return Icon(Icons.person,
color: Theme.of(context).colorScheme.caption, size: 40.0);
},
),
),
@ -118,6 +117,7 @@ class _StoryCircle extends StatelessWidget {
),
),
),
),
);
},
),

View File

@ -173,7 +173,7 @@ class SearchResultItem extends StatelessWidget {
const SizedBox(width: 8),
Expanded(
child: SizedBox(
height: 80,
height: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,

View File

@ -12,7 +12,18 @@ import 'package:url_launcher/url_launcher_string.dart';
class MainCategories extends StatelessWidget {
const MainCategories({super.key});
void _onTap(String link, BuildContext context) {
void _onTap(String link, String label, BuildContext context) { // label را اضافه کنید
// اگر روی "آمار و داده" کلیک شد، مستقیم به تب مربوطه برود
if (label == 'آمار و داده') {
final state = context.read<HomeState>();
// فرض ما این است که صفحه آمار و داده در ایندکس 2 قرار دارد
// اگر ایندکس دیگری است، آن را تغییر دهید
const statsPageIndex = 2;
state.currentPageIndex = statsPageIndex;
state.tabController.animateTo(statsPageIndex);
return; // از ادامه اجرای کد جلوگیری میکند
}
if (link.startsWith('http')) {
AppInitializer.openWebLink(
context,
@ -39,10 +50,9 @@ class MainCategories extends StatelessWidget {
children: state.menuItems
.map(
(e) => GestureDetector(
onTap: () => _onTap(e.link, context),
onTap: () => _onTap(e.link, e.label, context), // لیبل را اینجا پاس دهید
child: SizedBox(
width: (MediaQuery.of(context).size.width) / 4,
// (MediaQuery.of(context).size.width - 40) / 3,
width: (MediaQuery.of(context).size.width) / 4,
child: Column(
children: [
Container(
@ -72,4 +82,4 @@ class MainCategories extends StatelessWidget {
.toList(),
);
}
}
}

View File

@ -103,8 +103,11 @@ class _GeneralSettingsState extends State<GeneralSettings> {
child: Column(
children: [
MenuOption(
suffix:
state.fontFamily == 'Dana-FA' ? 'دانا' : 'ایران سنس',
suffix: state.fontFamily == 'Dana-FA'
? 'دانا'
: state.fontFamily == 'Iransans-FA'
? 'ایران سنس'
: 'ایران یکان',
title: 'فونت برنامه',
onTap: _showFontFamilyBottomSheet,
),
@ -164,6 +167,16 @@ class _GeneralSettingsState extends State<GeneralSettings> {
},
value: state.fontFamily == 'Iransans-FA',
),
const SizedBox(height: 24),
DidvanRadialButton(
title: 'ایران یکان',
fontFamily: 'IranYekan',
onSelected: () {
state.fontFamily = 'IranYekan';
setState(() {});
},
value: state.fontFamily == 'IranYekan',
),
],
),
),

View File

@ -11,7 +11,7 @@ class GeneralSettingsState extends CoreProvier {
}
List<int> _notificationTimeRange = [0, 24];
String _fontFamily = 'Dana-FA';
String _fontFamily = 'IranYekan';
double _fontSizeScale = 1;
String _brightness = 'light';
String time = "";

View File

@ -139,9 +139,11 @@ class _ProfilePageState extends State<ProfilePage> {
padding: const EdgeInsets.symmetric(
vertical: 12.0),
child: MenuOption(
suffix: state.fontFamily == 'Dana-FA'
? 'دانا'
: 'ایران سنس',
suffix: state.fontFamily == 'Dana-FA'
? 'دانا'
: state.fontFamily == 'Iransans-FA'
? 'ایران سنس'
: 'ایران یکان',
title: 'فونت برنامه',
onTap: _showFontFamilyBottomSheet,
icon: DidvanIcons.font_regular,
@ -394,6 +396,16 @@ class _ProfilePageState extends State<ProfilePage> {
},
value: state.fontFamily == 'Iransans-FA',
),
const SizedBox(height: 24),
DidvanRadialButton(
title: 'ایران یکان',
fontFamily: 'IranYekan',
onSelected: () {
state.fontFamily = 'IranYekan';
setState(() {});
},
value: state.fontFamily == 'IranYekan',
),
],
),
),

View File

@ -1,4 +1,5 @@
import 'package:didvan/config/design_config.dart';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/assets.dart';
import 'package:didvan/main.dart';
import 'package:didvan/providers/media.dart';
@ -9,7 +10,6 @@ import 'package:didvan/routes/routes.dart';
import 'package:didvan/services/app_initalizer.dart';
import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/storage/storage.dart';
import 'package:didvan/views/widgets/didvan/button.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -24,16 +24,35 @@ class Splash extends StatefulWidget {
State<Splash> createState() => _SplashState();
}
class _SplashState extends State<Splash> {
class _SplashState extends State<Splash> with TickerProviderStateMixin {
bool _errorOccured = false;
late ThemeProvider themeProvider;
late UserProvider userProvider;
late MediaProvider mediaProvider;
late AnimationController _pulseController;
late Animation<double> _pulseAnimation;
@override
void initState() {
super.initState();
// Initialize animation controller
_pulseController = AnimationController(
duration: const Duration(milliseconds: 1500),
vsync: this,
);
_pulseAnimation = Tween<double>(
begin: 1.0,
end: 1.1,
).animate(CurvedAnimation(
parent: _pulseController,
curve: Curves.easeInOut,
));
// Start pulse animation
_pulseController.repeat(reverse: true);
themeProvider = context.read<ThemeProvider>();
userProvider = context.read<UserProvider>();
mediaProvider = context.read<MediaProvider>();
@ -41,42 +60,211 @@ class _SplashState extends State<Splash> {
_initialize(themeProvider, userProvider, mediaProvider);
}
@override
void dispose() {
_pulseController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.light;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: DesignConfig.systemUiOverlayStyle.copyWith(
systemNavigationBarColor: Theme.of(context).colorScheme.background,
systemNavigationBarColor: colorScheme.background,
statusBarColor: Colors.transparent,
statusBarIconBrightness: isDark ? Brightness.light : Brightness.dark,
),
child: Material(
child: Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 48, vertical: 60),
color: Theme.of(context).colorScheme.background,
child: Column(
child: Scaffold(
backgroundColor: colorScheme.background,
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
colorScheme.background,
colorScheme.background.withOpacity(0.8),
colorScheme.primary.withOpacity(0.05),
],
),
),
child: Stack(
children: [
const SizedBox(height: 70),
SvgPicture.asset(
Assets.horizontalLogoWithText,
// Floating particles background
_buildFloatingParticles(colorScheme),
SafeArea(
child: Column(
children: [
// Top section with logo
Expanded(
flex: 3,
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Logo with subtle animation
TweenAnimationBuilder<double>(
duration: const Duration(milliseconds: 800),
tween: Tween(begin: 0.0, end: 1.0),
builder: (context, value, child) {
return Transform.scale(
scale: 0.7 + (0.3 * value),
child: Opacity(
opacity: value,
child: AnimatedBuilder(
animation: _pulseAnimation,
builder: (context, child) {
return Transform.scale(
scale: _pulseAnimation.value,
child: Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: RadialGradient(
colors: [
colorScheme.primary.withOpacity(0.05),
Colors.transparent,
],
),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.15),
blurRadius: 30,
spreadRadius: 8,
offset: const Offset(0, 15),
),
],
),
child: SvgPicture.asset(
Assets.horizontalLogoWithText,
height: 80,
),
),
);
},
),
),
);
},
),
],
),
),
),
// Bottom section with loading/error
Expanded(
flex: 2,
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 48),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (!_errorOccured) ...[
// Modern loading indicator
_buildModernLoader(colorScheme),
const SizedBox(height: 24),
// Loading text with fade animation
AnimatedBuilder(
animation: _pulseController,
builder: (context, child) {
return Opacity(
opacity: 0.4 + (0.4 * _pulseController.value),
child: Text(
'در حال بارگذاری...',
style: TextStyle(
fontSize: 16,
color: colorScheme.checkFav.withOpacity(0.7),
fontWeight: FontWeight.w400,
letterSpacing: 0.8,
),
),
);
},
),
],
if (_errorOccured) ...[
// Error state with simple and clean design
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Simple error icon
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: colorScheme.error.withOpacity(0.1),
borderRadius: BorderRadius.circular(30),
),
child: Icon(
Icons.wifi_off_rounded,
size: 28,
color: colorScheme.error,
),
),
const SizedBox(height: 20),
// Clean error message
Text(
'مشکل در اتصال',
style: TextStyle(
fontSize: 16,
color: colorScheme.checkFav,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
Text(
'لطفاً اتصال خود را بررسی کنید',
style: TextStyle(
fontSize: 14,
color: colorScheme.checkFav.withOpacity(0.6),
fontWeight: FontWeight.w400,
),
),
const SizedBox(height: 24),
// Simple retry button
_buildRetryButton(colorScheme),
],
),
],
],
),
),
),
// Brand tagline at bottom
Padding(
padding: const EdgeInsets.only(bottom: 32),
child: TweenAnimationBuilder<double>(
duration: const Duration(milliseconds: 1000),
tween: Tween(begin: 0.0, end: 1.0),
builder: (context, value, child) {
return Opacity(
opacity: value * 0.6,
child: Text(
'توسعه یافته توسط فرتاک',
style: TextStyle(
fontSize: 14,
color: colorScheme.checkFav,
fontWeight: FontWeight.w500,
letterSpacing: 1,
),
),
);
},
),
),
],
),
),
if (!_errorOccured)
Image.asset(
Assets.loadingAnimation,
width: 60,
height: 60,
),
if (_errorOccured) const SizedBox(height: 30),
if (_errorOccured)
DidvanButton(
width: 120,
height: 40,
title: 'تلاش مجدد',
onPressed: () {
setState(() {
_errorOccured = false;
});
_initialize(themeProvider, userProvider, mediaProvider);
},
),
],
),
),
@ -84,6 +272,122 @@ class _SplashState extends State<Splash> {
);
}
Widget _buildFloatingParticles(ColorScheme colorScheme) {
return AnimatedBuilder(
animation: _pulseController,
builder: (context, child) {
return Stack(
children: [
// Particle 1
Positioned(
top: 100 + (20 * _pulseController.value),
right: 50 + (10 * _pulseController.value),
child: Container(
width: 6,
height: 6,
decoration: BoxDecoration(
color: colorScheme.primary.withOpacity(0.3),
shape: BoxShape.circle,
),
),
),
// Particle 2
Positioned(
top: 200 + (15 * (1 - _pulseController.value)),
left: 80 + (8 * _pulseController.value),
child: Container(
width: 4,
height: 4,
decoration: BoxDecoration(
color: colorScheme.secondary.withOpacity(0.4),
shape: BoxShape.circle,
),
),
),
// Particle 3
Positioned(
bottom: 180 + (25 * _pulseController.value),
right: 100 + (12 * (1 - _pulseController.value)),
child: Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: colorScheme.primary.withOpacity(0.2),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.1),
blurRadius: 10,
spreadRadius: 3,
),
],
),
),
),
// Particle 4
Positioned(
bottom: 120 + (18 * (1 - _pulseController.value)),
left: 60 + (15 * _pulseController.value),
child: Container(
width: 5,
height: 5,
decoration: BoxDecoration(
color: colorScheme.tertiary.withOpacity(0.35),
shape: BoxShape.circle,
),
),
),
],
);
},
);
}
Widget _buildModernLoader(ColorScheme colorScheme) {
// استفاده از loading animation اصلی و قدیمی دیدوان
return SizedBox(
width: 60,
height: 60,
child: Image.asset(
Assets.loadingAnimation,
width: 60,
height: 60,
fit: BoxFit.contain,
),
);
}
Widget _buildRetryButton(ColorScheme colorScheme) {
return SizedBox(
width: 140,
height: 44,
child: ElevatedButton(
onPressed: () {
setState(() {
_errorOccured = false;
});
_initialize(themeProvider, userProvider, mediaProvider);
},
style: ElevatedButton.styleFrom(
backgroundColor: colorScheme.primary,
foregroundColor: colorScheme.onPrimary,
elevation: 0,
shadowColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22),
),
),
child: const Text(
'تلاش مجدد',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
),
);
}
Future<void> _initialize(ThemeProvider themeProvider,
UserProvider userProvider, MediaProvider mediaProvider) async {
try {

View File

@ -1,5 +1,3 @@
// lib/views/story_viewer/story_viewer_page.dart
import 'package:cached_network_image/cached_network_image.dart';
import 'package:didvan/models/story_model.dart';
import 'package:didvan/services/story_service.dart';
@ -23,11 +21,21 @@ class StoryViewerPage extends StatefulWidget {
class _StoryViewerPageState extends State<StoryViewerPage> {
late PageController _pageController;
double _currentPage = 0.0;
@override
void initState() {
super.initState();
_pageController = PageController(initialPage: widget.tappedIndex);
_pageController = PageController(
initialPage: widget.tappedIndex,
viewportFraction: 0.999,
);
_currentPage = widget.tappedIndex.toDouble();
_pageController.addListener(() {
setState(() {
_currentPage = _pageController.page!;
});
});
}
@override
@ -46,19 +54,30 @@ class _StoryViewerPageState extends State<StoryViewerPage> {
itemCount: widget.stories.length,
itemBuilder: (context, index) {
final userStories = widget.stories[index];
return UserStoryViewer(
key: ValueKey(userStories.user.name + index.toString()),
userStories: userStories,
onComplete: () {
if (index < widget.stories.length - 1) {
_pageController.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
);
} else {
Navigator.of(context).pop();
}
},
final value = _currentPage - index;
final rotationY = value * 0.8;
final transform = Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateY(rotationY);
return Transform(
alignment:
value > 0 ? Alignment.centerRight : Alignment.centerLeft,
transform: transform,
child: UserStoryViewer(
key: ValueKey(userStories.user.name + index.toString()),
userStories: userStories,
onComplete: () {
if (index < widget.stories.length - 1) {
_pageController.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
);
} else {
Navigator.of(context).pop();
}
},
),
);
},
),
@ -321,42 +340,20 @@ class _AnimatedBar extends StatelessWidget {
Widget build(BuildContext context) {
return Flexible(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 1.5),
child: LayoutBuilder(
builder: (context, constraints) {
return Stack(
children: <Widget>[
Container(
height: 6.0,
width: double.infinity,
decoration: BoxDecoration(
color: position < currentIndex
? Colors.white
// ignore: deprecated_member_use
: Colors.white.withOpacity(0.5),
border: Border.all(color: Colors.black26, width: 0.8),
borderRadius: BorderRadius.circular(30.0),
),
),
if (position == currentIndex)
Align(
alignment: Alignment.centerLeft,
child: AnimatedBuilder(
animation: animationController,
builder: (context, child) {
return Container(
height: 6.0,
width:
constraints.maxWidth * animationController.value,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30.0),
),
);
},
),
),
],
padding: const EdgeInsets.symmetric(horizontal: 2.0),
child: AnimatedBuilder(
animation: animationController,
builder: (context, child) {
return LinearProgressIndicator(
value: (position < currentIndex)
? 1.0
: (position == currentIndex
? animationController.value
: 0.0),
backgroundColor: Colors.white.withOpacity(0.5),
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
minHeight: 4.0,
borderRadius: BorderRadius.circular(30.0),
);
},
),

View File

@ -4,6 +4,7 @@ import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../audio/player_navbar.dart';
@ -31,26 +32,17 @@ class DidvanBNB extends StatelessWidget {
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius:
const BorderRadius.vertical(top: Radius.circular(16)),
boxShadow: [
BoxShadow(
color: const Color(0XFF1B3C59).withValues(alpha: 0.15),
blurRadius: 8,
spreadRadius: 0,
offset: const Offset(0, -8),
)
],
const BorderRadius.vertical(top: Radius.circular(0)),
border: const Border(
top: BorderSide(
color: const Color.fromARGB(255, 224, 224, 224),
width: 1.5,
),
),
),
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
children: [
_NavBarItem(
isSelected: currentTabIndex == 0,
title: 'خانه',
selectedIcon: DidvanIcons.house_solid,
unselectedIcon: DidvanIcons.house_light,
onTap: () => onTabChanged(0),
),
_NavBarItem(
isSelected: currentTabIndex == 1,
title: 'دسته‌بندی',
@ -58,19 +50,56 @@ class DidvanBNB extends StatelessWidget {
unselectedIcon: DidvanIcons.category_light,
onTap: () => onTabChanged(1),
),
_NavBarItem(
_NavBarItem(
isSelected: false,
title: 'هوشان',
selectedIcon: DidvanIcons.ai_solid,
unselectedIcon: DidvanIcons.ai_regular,
onTap: () => Navigator.of(context).pushNamed(Routes.aiSection),
customLogo: SvgPicture.asset(
DesignConfig.isDark
? 'assets/images/logos/logo-vertical-dark.svg'
: 'lib/assets/icons/bot.svg',
width: 32,
height: 32,
),
),
_NavBarItem(
isSelected: currentTabIndex == 0,
title: 'خانه',
selectedIcon: DidvanIcons.house_solid,
unselectedIcon: DidvanIcons.house_light,
onTap: () => onTabChanged(0),
isHomeButton: true,
customLogo: SvgPicture.asset(
DesignConfig.isDark
? 'assets/images/logos/logo-vertical-dark.svg'
: 'lib/assets/icons/New Home.svg',
width: 32,
height: 32,
),
),
_NavBarItem(
isSelected: currentTabIndex == 2,
title: 'آمار و داده',
selectedIcon: DidvanIcons.stats__solid,
unselectedIcon: DidvanIcons.stats__light,
onTap: () => onTabChanged(2),
customLogo: SvgPicture.asset(
DesignConfig.isDark
? 'assets/images/logos/logo-vertical-dark.svg'
: 'lib/assets/icons/bot.svg',
width: 32,
height: 32,
),
),
_NavBarItem(
isSelected: false,
title: 'پروفایل',
selectedIcon: DidvanIcons.profile_solid,
unselectedIcon: DidvanIcons.profile_light,
onTap: () => Navigator.of(context).pushNamed(Routes.profile),
),
],
),
@ -87,6 +116,8 @@ class _NavBarItem extends StatelessWidget {
final String title;
final IconData selectedIcon;
final IconData unselectedIcon;
final bool isHomeButton;
final Widget? customLogo;
const _NavBarItem({
Key? key,
@ -95,6 +126,8 @@ class _NavBarItem extends StatelessWidget {
required this.selectedIcon,
required this.unselectedIcon,
required this.onTap,
this.isHomeButton = false,
this.customLogo,
}) : super(key: key);
@override
@ -116,28 +149,35 @@ class _NavBarItem extends StatelessWidget {
const SizedBox(
height: 4,
),
AnimatedContainer(
padding: const EdgeInsets.all(4),
duration: DesignConfig.lowAnimationDuration,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isSelected
? Theme.of(context).colorScheme.focused
: Theme.of(context).colorScheme.surface,
if (isHomeButton && customLogo != null) ...[
AnimatedContainer(
padding: const EdgeInsets.all(8),
duration: DesignConfig.lowAnimationDuration,
child: SizedBox(
width: 50,
height: 50,
child: customLogo,
),
),
child: Icon(
isSelected ? selectedIcon : unselectedIcon,
size: 32,
color: DesignConfig.isDark
? Theme.of(context).colorScheme.text
: Theme.of(context).colorScheme.title,
] else ...[
AnimatedContainer(
padding: const EdgeInsets.all(4),
duration: DesignConfig.lowAnimationDuration,
child: Icon(
isSelected ? selectedIcon : unselectedIcon,
size: 32,
color: DesignConfig.isDark
? Theme.of(context).colorScheme.text
: Theme.of(context).colorScheme.title,
),
),
),
DidvanText(
title,
style: Theme.of(context).textTheme.bodySmall,
color: Theme.of(context).colorScheme.title,
),
if (!isHomeButton)
DidvanText(
title,
style: Theme.of(context).textTheme.bodySmall,
color: Theme.of(context).colorScheme.title,
),
],
const Spacer(),
],
),

View File

@ -0,0 +1,334 @@
import 'package:didvan/constants/app_icons.dart';
import 'package:flutter/material.dart';
import 'dart:ui';
class DidvanBNB extends StatefulWidget {
final int currentTabIndex;
final void Function(int index) onTabChanged;
const DidvanBNB({
Key? key,
required this.currentTabIndex,
required this.onTabChanged,
}) : super(key: key);
@override
State<DidvanBNB> createState() => _DidvanBNBState();
}
class _DidvanBNBState extends State<DidvanBNB> with TickerProviderStateMixin {
late int _activeIndex;
late AnimationController _blobController;
late Animation<double> _blobAnim;
double _dragProgress = 0.0; // 0..1 between from->to
int _dragFrom = 0;
int _dragTo = 0;
bool _isDragging = false;
final GlobalKey _rowKey = GlobalKey();
@override
void initState() {
super.initState();
_activeIndex = widget.currentTabIndex;
_blobController = AnimationController(
duration: const Duration(milliseconds: 450),
vsync: this,
);
_blobAnim = CurvedAnimation(parent: _blobController, curve: Curves.easeOutCubic);
}
@override
void didUpdateWidget(covariant DidvanBNB oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.currentTabIndex != _activeIndex) {
_animateTo(widget.currentTabIndex);
}
}
void _animateTo(int newIndex) {
setState(() {
_dragFrom = _activeIndex;
_dragTo = newIndex;
_activeIndex = newIndex;
_dragProgress = 0;
_isDragging = false;
});
_blobController.forward(from: 0);
}
void _handleTap(int index) {
if (index == _activeIndex) return;
widget.onTabChanged(index);
}
void _startDrag(DragStartDetails d) {
final box = _rowKey.currentContext?.findRenderObject() as RenderBox?;
if (box == null) return;
final local = box.globalToLocal(d.globalPosition);
final width = box.size.width;
final section = width / 4; // 4 items
_dragFrom = _activeIndex;
_dragTo = _activeIndex;
_dragProgress = 0;
_isDragging = true;
final pointerIndex = (local.dx / section).clamp(0, 3).floor();
if (pointerIndex != _activeIndex) {
_dragTo = pointerIndex;
}
setState(() {});
}
void _updateDrag(DragUpdateDetails d) {
if (!_isDragging) return;
final box = _rowKey.currentContext?.findRenderObject() as RenderBox?;
if (box == null) return;
final width = box.size.width;
final local = box.globalToLocal(d.globalPosition);
final section = width / 4;
final pointerIndex = (local.dx / section).clamp(0, 3).floor();
if (pointerIndex != _dragTo) {
_dragFrom = _activeIndex;
_dragTo = pointerIndex;
}
// progress relative to dragFrom->dragTo centers
final fromCenter = (_dragFrom + 0.5) * section;
final toCenter = (_dragTo + 0.5) * section;
final total = (toCenter - fromCenter);
_dragProgress = total.abs() < 2 ? 0 : ((local.dx - fromCenter) / (total)).clamp(0.0, 1.0);
setState(() {});
}
void _endDrag(DragEndDetails d) {
if (!_isDragging) return;
_isDragging = false;
// decide final index
final threshold = 0.5;
final target = _dragProgress > threshold ? _dragTo : _dragFrom;
if (target != _activeIndex) {
widget.onTabChanged(target);
} else {
setState(() {});
}
}
@override
void dispose() {
_blobController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
return Positioned(
bottom: 12,
left: 0,
right: 0,
child: GestureDetector(
onHorizontalDragStart: _startDrag,
onHorizontalDragUpdate: _updateDrag,
onHorizontalDragEnd: _endDrag,
child: SizedBox(
height: 90,
child: Stack(
alignment: Alignment.center,
children: [
// Liquid blob painter behind icons
LayoutBuilder(
builder: (ctx, constraints) {
final w = constraints.maxWidth;
final section = w / 4;
final fromCenter = (_dragFrom + 0.5) * section;
final toCenter = (_dragTo + 0.5) * section;
final t = _isDragging ? _dragProgress : _blobAnim.value;
final center = fromCenter + (toCenter - fromCenter) * t;
return CustomPaint(
size: Size(w, 70),
painter: _LiquidBlobPainter(
progress: t,
from: fromCenter,
to: toCenter,
center: center,
color: (isDark ? Colors.blueAccent : Colors.deepPurpleAccent).withOpacity(0.18),
highlight: (isDark ? Colors.blueAccent : Colors.deepPurpleAccent).withOpacity(0.35),
),
);
},
),
// Icons row
Align(
alignment: Alignment.center,
child: SizedBox(
height: 70,
child: Row(
key: _rowKey,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_IconItem(
index: 0,
active: _activeIndex == 0,
iconActive: DidvanIcons.house_solid,
iconInactive: DidvanIcons.house_light,
title: 'خانه',
onTap: () => _handleTap(0),
dragTarget: _dragTo,
dragProgress: _dragProgress,
isDragging: _isDragging,
),
_IconItem(
index: 1,
active: _activeIndex == 1,
iconActive: DidvanIcons.category_solid,
iconInactive: DidvanIcons.category_light,
title: 'دسته‌بندی',
onTap: () => _handleTap(1),
dragTarget: _dragTo,
dragProgress: _dragProgress,
isDragging: _isDragging,
),
_IconItem(
index: 3,
active: _activeIndex == 3,
iconActive: DidvanIcons.ai_solid,
iconInactive: DidvanIcons.ai_regular,
title: 'هوشان',
onTap: () => _handleTap(3),
dragTarget: _dragTo,
dragProgress: _dragProgress,
isDragging: _isDragging,
),
_IconItem(
index: 2,
active: _activeIndex == 2,
iconActive: DidvanIcons.stats__solid,
iconInactive: DidvanIcons.stats__light,
title: 'آمار و داده',
onTap: () => _handleTap(2),
dragTarget: _dragTo,
dragProgress: _dragProgress,
isDragging: _isDragging,
),
],
),
),
),
],
),
),
),
);
}
}
class _LiquidBlobPainter extends CustomPainter {
final double progress; // 0..1
final double from;
final double to;
final double center;
final Color color;
final Color highlight;
_LiquidBlobPainter({
required this.progress,
required this.from,
required this.to,
required this.center,
required this.color,
required this.highlight,
});
@override
void paint(Canvas canvas, Size size) {
// Single capsule shape that stretches between from & interpolated center.
final baseY = size.height / 2;
final lerp = center;
final start = from < lerp ? from : lerp;
final end = from < lerp ? lerp : from;
final radius = 26.0;
final rect = Rect.fromLTRB(start - radius, baseY - radius, end + radius, baseY + radius);
final rrect = RRect.fromRectAndRadius(rect, Radius.circular(radius));
final paint = Paint()
..shader = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
color.withOpacity(0.9),
color.withOpacity(0.4),
],
).createShader(rect);
// Draw blurred base using saveLayer for slight glow
canvas.saveLayer(rect.inflate(20), Paint());
canvas.drawRRect(rrect, paint);
final glow = Paint()
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 20)
..color = highlight.withOpacity(0.5);
canvas.drawCircle(Offset(lerp, baseY), 14 + 6 * progress, glow);
canvas.restore();
}
@override
bool shouldRepaint(covariant _LiquidBlobPainter old) =>
old.progress != progress || old.from != from || old.to != to || old.center != center || old.color != color;
}
class _IconItem extends StatelessWidget {
final int index;
final bool active;
final IconData iconActive;
final IconData iconInactive;
final String title;
final VoidCallback onTap;
final int dragTarget;
final double dragProgress;
final bool isDragging;
const _IconItem({
required this.index,
required this.active,
required this.iconActive,
required this.iconInactive,
required this.title,
required this.onTap,
required this.dragTarget,
required this.dragProgress,
required this.isDragging,
});
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
final isDark = scheme.brightness == Brightness.dark;
final base = scheme.onSurface; // fallback since title extension not imported here
final activeColor = scheme.primary;
return GestureDetector(
onTap: onTap,
behavior: HitTestBehavior.translucent,
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeOutCubic,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedScale(
duration: const Duration(milliseconds: 400),
curve: Curves.easeOutBack,
scale: active ? 1.15 : 1.0,
child: Icon(
active ? iconActive : iconInactive,
size: 26,
color: active ? activeColor : base.withOpacity(isDark ? 0.8 : 0.65),
),
),
const SizedBox(height: 2),
AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontSize: 11,
fontWeight: active ? FontWeight.w700 : FontWeight.w500,
color: active ? activeColor : base.withOpacity(0.6),
),
child: Text(title, maxLines: 1, overflow: TextOverflow.fade),
),
],
),
),
);
}
}

View File

@ -101,7 +101,10 @@ class _FloatingNavigationBarState extends State<FloatingNavigationBar> {
height: 48,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.navigation,
borderRadius: BorderRadius.circular(24),
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(24),
bottomRight: Radius.circular(24),
),
border: DesignConfig.isDark
? Border.all(
color: Theme.of(context).colorScheme.cardBorder,
@ -135,26 +138,28 @@ class _FloatingNavigationBarState extends State<FloatingNavigationBar> {
),
),
const Spacer(),
SizedBox(
width: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
DidvanIconButton(
gestureSize: 32,
onPressed: () => Navigator.of(context).pushNamed(
Routes.mentions,
arguments: {
'id': widget.item.id,
'type': widget.isRadar ? 'radar' : 'news',
'title': widget.item.title,
},
),
icon: DidvanIcons.mention_icon,
),
],
DidvanIconButton(
gestureSize: 32,
onPressed: () => Navigator.of(context).pushNamed(
Routes.mentions,
arguments: {
'id': widget.item.id,
'type': widget.isRadar ? 'radar' : 'news',
'title': widget.item.title,
},
),
icon: DidvanIcons.mention_icon,
),
const Spacer(),
DidvanIconButton(
gestureSize: 32,
onPressed: () => Navigator.of(context).pushNamedAndRemoveUntil(
Routes.home,
(route) => false,
),
icon: DidvanIcons.house_regular,
),
const Spacer(),
BookmarkButton(
itemId: widget.item.id,
type: widget.isRadar ? 'radar' : 'news',
@ -171,6 +176,7 @@ class _FloatingNavigationBarState extends State<FloatingNavigationBar> {
},
gestureSize: 32,
),
const Spacer(),
SizedBox(
width: 60,
child: Row(
@ -197,6 +203,7 @@ class _FloatingNavigationBarState extends State<FloatingNavigationBar> {
],
),
),
const Spacer(),
DidvanIconButton(
gestureSize: 32,
onPressed:

View File

@ -5,7 +5,6 @@ import 'package:didvan/models/overview_data.dart';
import 'package:didvan/models/requests/studio.dart';
import 'package:didvan/providers/media.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart';
import 'package:didvan/views/widgets/bookmark_button.dart';
import 'package:didvan/views/widgets/duration_widget.dart';
import 'package:didvan/views/widgets/didvan/card.dart';

View File

@ -1,7 +1,6 @@
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/views/widgets/didvan/icon_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class SearchField extends StatefulWidget {
final String title;
@ -11,6 +10,8 @@ class SearchField extends StatefulWidget {
final VoidCallback? onFilterButtonPressed;
final VoidCallback? onGoBack;
final String? value;
final String? extraIconPath;
final VoidCallback? onExtraIconPressed;
const SearchField({
Key? key,
@ -21,6 +22,8 @@ class SearchField extends StatefulWidget {
this.isFiltered,
this.onGoBack,
this.value,
this.extraIconPath,
this.onExtraIconPressed,
}) : super(key: key);
@override
@ -41,13 +44,14 @@ class _SearchFieldState extends State<SearchField> {
@override
Widget build(BuildContext context) {
return SizedBox(
height: 40,
height: 47,
child: Row(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
color: _fillColor(),
color: const Color.fromARGB(255, 235, 235, 235),
borderRadius: BorderRadius.circular(40),
),
child: TextFormField(
initialValue: widget.value,
@ -68,22 +72,18 @@ class _SearchFieldState extends State<SearchField> {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
margin: const EdgeInsets.only(left: 4),
height: 24,
width: 1,
color: Theme.of(context).colorScheme.border,
),
Stack(
children: [
DidvanIconButton(
onPressed:
widget.onFilterButtonPressed!,
icon: widget.isFiltered!
? DidvanIcons.filter_solid
: DidvanIcons.filter_regular,
size: 24,
gestureSize: 24,
GestureDetector(
onTap: widget.onFilterButtonPressed!,
child: Container(
width: 27,
height: 27,
padding: const EdgeInsets.all(4),
child: SvgPicture.asset(
"lib/assets/icons/search sort.svg",
),
),
),
if (widget.isFiltered!)
Positioned(
@ -108,7 +108,7 @@ class _SearchFieldState extends State<SearchField> {
: null,
focusedBorder: OutlineInputBorder(
borderRadius: const BorderRadius.all(
Radius.circular(4),
Radius.circular(35),
),
borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary,
@ -116,17 +116,21 @@ class _SearchFieldState extends State<SearchField> {
),
prefixIcon: GestureDetector(
onTap: widget.onGoBack,
child: Icon(
widget.onGoBack == null
? DidvanIcons.search_regular
: DidvanIcons.back_light,
color: Theme.of(context).colorScheme.text,
child: Padding(
padding: const EdgeInsets.all(11.0),
child: SvgPicture.asset(
widget.onGoBack == null
? 'lib/assets/icons/search.svg'
: 'lib/assets/icons/search.svg',
width: 23,
height: 23,
),
),
),
prefixIconColor: Theme.of(context).colorScheme.inputText,
enabledBorder: OutlineInputBorder(
borderRadius: const BorderRadius.all(
Radius.circular(4),
Radius.circular(20),
),
borderSide: BorderSide(
color: Theme.of(context).colorScheme.border,
@ -138,25 +142,46 @@ class _SearchFieldState extends State<SearchField> {
right: 12,
),
border: InputBorder.none,
hintText: 'جستجو در ${widget.title}',
hintStyle: TextStyle(
color: Theme.of(context).colorScheme.disabledText,
hintText: 'جست‌وجو در ${widget.title}',
hintStyle: const TextStyle(
color: Color.fromARGB(255, 122, 122, 122),
fontSize: 13,
),
),
),
),
),
if (widget.extraIconPath != null && widget.onExtraIconPressed != null) ...[
const SizedBox(width: 8),
GestureDetector(
onTap: widget.onExtraIconPressed,
child: Container(
width: 47,
height: 47,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
shape: BoxShape.circle,
),
child: Center(
child: SvgPicture.asset(
"lib/assets/icons/live ai.svg",
width: 24,
height: 24,
colorFilter: const ColorFilter.mode(
Colors.white,
BlendMode.srcIn,
),
),
),
),
),
],
],
),
);
}
Color _fillColor() {
if (widget.focusNode.hasFocus) {
return Theme.of(context).colorScheme.surface;
}
return Theme.of(context).colorScheme.surface;
}
@override
void dispose() {

View File

@ -0,0 +1,53 @@
import 'package:flutter/material.dart';
class TextDivider extends StatelessWidget {
final String text;
final Color? textColor;
final Color? lineColor;
final TextStyle? textStyle;
final double? lineThickness;
final EdgeInsets? padding;
const TextDivider({
Key? key,
required this.text,
this.textColor,
this.lineColor,
this.textStyle,
this.lineThickness,
this.padding,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: padding ?? const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Row(
children: [
Expanded(
child: Divider(
color: lineColor ?? Theme.of(context).dividerColor,
thickness: lineThickness ?? 1.0,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
text,
style: textStyle ?? Theme.of(context).textTheme.bodyMedium?.copyWith(
color: textColor ?? Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
),
),
Expanded(
child: Divider(
color: lineColor ?? Theme.of(context).dividerColor,
thickness: lineThickness ?? 1.0,
),
),
],
),
);
}
}

View File

@ -1,6 +1,6 @@
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/Users/arytan/Desktop/Dev/Sdks/flutter
FLUTTER_APPLICATION_PATH=/Users/arytan/Desktop/Flutter Projects/didvan-app
FLUTTER_ROOT=C:\Users\UI-UX\AppData\Local\flutter
FLUTTER_APPLICATION_PATH=C:\Users\UI-UX\Desktop\projects\didvan-app
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_NAME=4.0.1

View File

@ -1,7 +1,7 @@
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/arytan/Desktop/Dev/Sdks/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/arytan/Desktop/Flutter Projects/didvan-app"
export "FLUTTER_ROOT=C:\Users\UI-UX\AppData\Local\flutter"
export "FLUTTER_APPLICATION_PATH=C:\Users\UI-UX\Desktop\projects\didvan-app"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=4.0.1"

View File

@ -126,7 +126,6 @@ dev_dependencies:
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^2.0.1
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
@ -191,6 +190,21 @@ flutter:
- family: Dicon
fonts:
- asset: lib/assets/icons/Dicon.ttf
- family: IranYekan
fonts:
- asset: lib/assets/fonts/IRANYEKANREGULAR.TTF
- asset: lib/assets/fonts/IRANYEKANTHIN.TTF
weight: 100
- asset: lib/assets/fonts/IRANYEKANLIGHT.TTF
weight: 300
- asset: lib/assets/fonts/IRANYEKANMEDIUM.TTF
weight: 500
- asset: lib/assets/fonts/IRANYEKANBOLD.TTF
weight: 700
- asset: lib/assets/fonts/IRANYEKANEXTRABOLD.TTF
weight: 800
- asset: lib/assets/fonts/IRANYEKANBLACK.TTF
weight: 900
# fonts:
# - family: Schyler
# fonts: