Browse Source

finish app

fix_bug
mohsen zamani 2 years ago
parent
commit
544572e2c2
  1. 2
      android/app/src/main/AndroidManifest.xml
  2. BIN
      android/app/src/main/res/mipmap-hdpi/launcher_icon.png
  3. BIN
      android/app/src/main/res/mipmap-mdpi/launcher_icon.png
  4. BIN
      android/app/src/main/res/mipmap-xhdpi/launcher_icon.png
  5. BIN
      android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png
  6. BIN
      android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png
  7. BIN
      assets/images/png/ic_select_language.png
  8. BIN
      assets/images/png/logo.png
  9. 2
      assets/languages/en.json
  10. 2
      assets/languages/fa.json
  11. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
  12. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
  13. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
  14. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
  15. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
  16. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
  17. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
  18. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
  19. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
  20. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
  21. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
  22. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
  23. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
  24. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
  25. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
  26. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
  27. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
  28. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
  29. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
  30. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
  31. BIN
      ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
  32. 12
      lib/core/language/language_cubit.dart
  33. 34
      lib/core/select_language/cubit/select_language_cubit.dart
  34. 132
      lib/core/select_language/screen/select_language_screen.dart
  35. 26
      lib/core/utils/app_utils.dart
  36. 37
      lib/core/widgets/loading_list_widget.dart
  37. 265
      lib/features/aabout_us/about_us_screen.dart
  38. 9
      lib/features/main/widget/main_item_widget.dart
  39. 161
      lib/features/posts/screen/posts_screen.dart
  40. 22
      lib/features/single_post/screen/single_post_screen.dart
  41. 28
      lib/features/splash/cubit/splash_cubit.dart
  42. 83
      lib/features/splash/screen/splash_screen.dart
  43. 119
      lib/main.dart
  44. 12
      pubspec.lock
  45. 7
      pubspec.yaml

2
android/app/src/main/AndroidManifest.xml

@ -2,7 +2,7 @@
<application <application
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:icon="@mipmap/launcher_icon"
android:label="sonnat"> android:label="sonnat">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

BIN
android/app/src/main/res/mipmap-hdpi/launcher_icon.png

After

Width: 72  |  Height: 72  |  Size: 1.8 KiB

BIN
android/app/src/main/res/mipmap-mdpi/launcher_icon.png

After

Width: 48  |  Height: 48  |  Size: 1.1 KiB

BIN
android/app/src/main/res/mipmap-xhdpi/launcher_icon.png

After

Width: 96  |  Height: 96  |  Size: 2.6 KiB

BIN
android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png

After

Width: 144  |  Height: 144  |  Size: 4.2 KiB

BIN
android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png

After

Width: 192  |  Height: 192  |  Size: 5.9 KiB

BIN
assets/images/png/ic_select_language.png

After

Width: 73  |  Height: 37  |  Size: 996 B

BIN
assets/images/png/logo.png

After

Width: 1772  |  Height: 1772  |  Size: 58 KiB

2
assets/languages/en.json

@ -14,6 +14,8 @@
"send_message_to_us": "Send us a message", "send_message_to_us": "Send us a message",
"send_message": "Write your message", "send_message": "Write your message",
"write_comment": "Write your comment", "write_comment": "Write your comment",
"about_us": "About us",
"select_language": "Select language",
"send": "Send", "send": "Send",
"show_all_comments": "View all comments", "show_all_comments": "View all comments",
"search": "Search" "search": "Search"

2
assets/languages/fa.json

@ -11,6 +11,8 @@
"more_about_us": "با ما بیشتر آشنا شوید", "more_about_us": "با ما بیشتر آشنا شوید",
"main_target": "هدف اصلی ما", "main_target": "هدف اصلی ما",
"contact_to_us": "ارتباط با ما", "contact_to_us": "ارتباط با ما",
"about_us": "درباره ما",
"select_language": "انتخاب زبان",
"send_message_to_us": "ارسال پیام به ما", "send_message_to_us": "ارسال پیام به ما",
"send_message": "پیام خود را بنویسید", "send_message": "پیام خود را بنویسید",
"send": "ارسال", "send": "ارسال",

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png

Before

Width: 1024  |  Height: 1024  |  Size: 11 KiB

After

Width: 1024  |  Height: 1024  |  Size: 39 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png

Before

Width: 20  |  Height: 20  |  Size: 295 B

After

Width: 20  |  Height: 20  |  Size: 404 B

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png

Before

Width: 40  |  Height: 40  |  Size: 406 B

After

Width: 40  |  Height: 40  |  Size: 919 B

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png

Before

Width: 60  |  Height: 60  |  Size: 450 B

After

Width: 60  |  Height: 60  |  Size: 1.4 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png

Before

Width: 29  |  Height: 29  |  Size: 282 B

After

Width: 29  |  Height: 29  |  Size: 629 B

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png

Before

Width: 58  |  Height: 58  |  Size: 462 B

After

Width: 58  |  Height: 58  |  Size: 1.4 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png

Before

Width: 87  |  Height: 87  |  Size: 704 B

After

Width: 87  |  Height: 87  |  Size: 2.3 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png

Before

Width: 40  |  Height: 40  |  Size: 406 B

After

Width: 40  |  Height: 40  |  Size: 919 B

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png

Before

Width: 80  |  Height: 80  |  Size: 586 B

After

Width: 80  |  Height: 80  |  Size: 2.1 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png

Before

Width: 120  |  Height: 120  |  Size: 862 B

After

Width: 120  |  Height: 120  |  Size: 3.2 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png

After

Width: 50  |  Height: 50  |  Size: 1.2 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png

After

Width: 100  |  Height: 100  |  Size: 2.7 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png

After

Width: 57  |  Height: 57  |  Size: 1.3 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png

After

Width: 114  |  Height: 114  |  Size: 3.2 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png

Before

Width: 120  |  Height: 120  |  Size: 862 B

After

Width: 120  |  Height: 120  |  Size: 3.2 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png

Before

Width: 180  |  Height: 180  |  Size: 1.6 KiB

After

Width: 180  |  Height: 180  |  Size: 5.5 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png

After

Width: 72  |  Height: 72  |  Size: 1.8 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png

After

Width: 144  |  Height: 144  |  Size: 4.2 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png

Before

Width: 76  |  Height: 76  |  Size: 762 B

After

Width: 76  |  Height: 76  |  Size: 1.9 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png

Before

Width: 152  |  Height: 152  |  Size: 1.2 KiB

After

Width: 152  |  Height: 152  |  Size: 4.3 KiB

BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png

Before

Width: 167  |  Height: 167  |  Size: 1.4 KiB

After

Width: 167  |  Height: 167  |  Size: 5.1 KiB

12
lib/core/language/language_cubit.dart

@ -9,6 +9,7 @@ import 'package:sonnat/core/utils/base_cubit_type.dart';
enum LanguageState { enum LanguageState {
loading, loading,
loaded, loaded,
notSet,
} }
enum CurrentLanguage { enum CurrentLanguage {
@ -27,8 +28,7 @@ class LanguageCubit extends Cubit<BaseCubitType<LanguageState>> {
Future<void> _initial() async { Future<void> _initial() async {
String? language = _repository.getCurrentLanguage(); String? language = _repository.getCurrentLanguage();
if (language == null || language == '') { if (language == null || language == '') {
await Translator.setNewLanguage(Languages.fa);
emit(BaseCubitType(eventName: LanguageState.loaded, data: CurrentLanguage.fa));
emit(BaseCubitType(eventName: LanguageState.notSet));
return; return;
} }
switch (language) { switch (language) {
@ -56,12 +56,6 @@ class LanguageCubit extends Cubit<BaseCubitType<LanguageState>> {
} }
Future<void> changeLanguage() async { Future<void> changeLanguage() async {
if (getCurrentLanguage() == 'fa') {
await Translator.setNewLanguage(Languages.en);
emit(BaseCubitType(eventName: LanguageState.loaded, data: CurrentLanguage.en));
} else {
await Translator.setNewLanguage(Languages.fa);
emit(BaseCubitType(eventName: LanguageState.loaded, data: CurrentLanguage.fa));
}
emit(BaseCubitType(eventName: LanguageState.loaded));
} }
} }

34
lib/core/select_language/cubit/select_language_cubit.dart

@ -0,0 +1,34 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sonnat/core/language/language_cubit.dart';
import 'package:sonnat/core/language/languages.dart';
import 'package:sonnat/core/language/translator.dart';
import 'package:sonnat/core/utils/base_cubit_type.dart';
class SelectLanguageCubit extends Cubit<BaseCubitType<SelectLanguageState>> {
SelectLanguageCubit() : super(BaseCubitType(eventName: SelectLanguageState.empty));
void empty() => emit(BaseCubitType(eventName: SelectLanguageState.empty));
Future<void> selectLanguage(String language) async {
switch (language) {
case 'fa':
await Translator.setNewLanguage(Languages.fa);
emit(BaseCubitType(eventName: SelectLanguageState.loaded, data: CurrentLanguage.fa));
return;
case 'en':
await Translator.setNewLanguage(Languages.en);
emit(BaseCubitType(eventName: SelectLanguageState.loaded, data: CurrentLanguage.en));
return;
case 'ar':
await Translator.setNewLanguage(Languages.ar);
emit(BaseCubitType(eventName: SelectLanguageState.loaded, data: CurrentLanguage.ar));
return;
}
}
}
enum SelectLanguageState {
empty,
loaded,
}

132
lib/core/select_language/screen/select_language_screen.dart

@ -0,0 +1,132 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sonnat/core/extensions/context_extension.dart';
import 'package:sonnat/core/extensions/string_extension.dart';
import 'package:sonnat/core/language/language_cubit.dart';
import 'package:sonnat/core/select_language/cubit/select_language_cubit.dart';
import 'package:sonnat/core/utils/base_cubit_type.dart';
import 'package:sonnat/features/main/main_screen.dart';
class SelectLanguageScreen extends StatefulWidget {
const SelectLanguageScreen({super.key});
@override
State<SelectLanguageScreen> createState() => _SelectLanguageScreenState();
}
class _SelectLanguageScreenState extends State<SelectLanguageScreen> {
late final SelectLanguageCubit _cubit;
@override
void initState() {
_cubit = BlocProvider.of<SelectLanguageCubit>(context);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xff26237A),
body: SafeArea(
child: BlocBuilder<SelectLanguageCubit, BaseCubitType<SelectLanguageState>>(
builder: (context, state) {
switch (state.eventName!) {
case SelectLanguageState.empty:
break;
case SelectLanguageState.loaded:
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
BlocProvider.of<LanguageCubit>(context).changeLanguage();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const MainScreen();
},
),
);
});
break;
}
return Column(
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'ic_select_language'.pngPath,
width: 72,
height: 36,
),
const SizedBox(height: 15),
const Text(
'Select Your Language',
style: TextStyle(
color: Color(0xffDEDEDE),
fontSize: 16,
fontFamily: 'Cairo',
),
),
],
),
),
GestureDetector(
child: const SelectLanguageButtonWidget(title: 'English'),
onTap: () {
_cubit.selectLanguage('en');
},
),
GestureDetector(
child: const SelectLanguageButtonWidget(title: 'العربیه'),
onTap: () {
_cubit.selectLanguage('fa');
},
),
GestureDetector(
child: const SelectLanguageButtonWidget(title: 'فارسی'),
onTap: () {
_cubit.selectLanguage('fa');
},
),
GestureDetector(
child: const SelectLanguageButtonWidget(title: 'اردو'),
onTap: () {
_cubit.selectLanguage('fa');
},
),
const SizedBox(height: 30),
],
);
},
),
),
);
}
}
class SelectLanguageButtonWidget extends StatelessWidget {
final String title;
const SelectLanguageButtonWidget({super.key, required this.title});
@override
Widget build(BuildContext context) {
return Container(
width: context.width,
decoration: BoxDecoration(
color: const Color(0xff3733A1),
borderRadius: BorderRadius.circular(22),
),
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(vertical: 14),
margin: const EdgeInsets.symmetric(vertical: 7.5, horizontal: 40),
child: Text(
title,
style: const TextStyle(
color: Color(0xffffffff),
fontSize: 16,
),
),
);
}
}

26
lib/core/utils/app_utils.dart

@ -63,26 +63,12 @@ class Utils {
return '${jalali.year}/${jalali.month}/${jalali.day}'; return '${jalali.year}/${jalali.month}/${jalali.day}';
} }
ThemeData getAppTheme(BuildContext context, CurrentLanguage language) {
switch (language) {
case CurrentLanguage.en:
return ThemeData(
scaffoldBackgroundColor: const Color(0xffE7E7F5),
useMaterial3: true,
);
case CurrentLanguage.fa:
return ThemeData(
fontFamily: 'Vazir',
scaffoldBackgroundColor: const Color(0xffE7E7F5),
useMaterial3: true,
);
case CurrentLanguage.ar:
return ThemeData(
fontFamily: 'Cairo',
useMaterial3: true,
scaffoldBackgroundColor: const Color(0xffE7E7F5),
);
}
ThemeData getAppTheme(BuildContext context) {
return ThemeData(
fontFamily: 'Vazir',
scaffoldBackgroundColor: const Color(0xffE7E7F5),
useMaterial3: true,
);
} }
EdgeInsets allMargin(num? num) { EdgeInsets allMargin(num? num) {

37
lib/core/widgets/loading_list_widget.dart

@ -1,35 +1,30 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sonnat/core/extensions/context_extension.dart'; import 'package:sonnat/core/extensions/context_extension.dart';
import 'package:sonnat/core/utils/app_constants.dart'; import 'package:sonnat/core/utils/app_constants.dart';
import 'package:sonnat/core/widgets/shimmer.dart';
class LoadingListWidget extends StatelessWidget { class LoadingListWidget extends StatelessWidget {
const LoadingListWidget({super.key}); const LoadingListWidget({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Shimmer.fromColors(
baseColor: Colors.black12,
highlightColor: Colors.white,
child: ListView.builder(
padding: EdgeInsets.zero,
itemBuilder: (_, __) => Container(
height: 200,
decoration: BoxDecoration(
color: const Color(0xffffffff),
borderRadius: BorderRadius.circular(16),
),
margin: EdgeInsets.only(
left: context.width * 26 / AppConstants.instance.appWidth,
right: context.width * 26 / AppConstants.instance.appWidth,
bottom: context.height * 8 / AppConstants.instance.appHeight,
top: context.height * 8 / AppConstants.instance.appHeight,
),
return ListView.builder(
padding: EdgeInsets.zero,
itemBuilder: (_, __) => Container(
height: 340,
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(16),
),
margin: EdgeInsets.only(
left: context.width * 26 / AppConstants.instance.appWidth,
right: context.width * 26 / AppConstants.instance.appWidth,
bottom: context.height * 8 / AppConstants.instance.appHeight,
top: context.height * 8 / AppConstants.instance.appHeight,
), ),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 10,
), ),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 10,
); );
} }
} }

265
lib/features/aabout_us/about_us_screen.dart

@ -22,148 +22,157 @@ class _AboutUsScreenState extends State<AboutUsScreen> {
return Scaffold( return Scaffold(
body: Padding( body: Padding(
padding: EdgeInsets.symmetric(horizontal: context.width * 25 / AppConstants.instance.appWidth), padding: EdgeInsets.symmetric(horizontal: context.width * 25 / AppConstants.instance.appWidth),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: context.height * 33 / AppConstants.instance.appHeight),
Row(
children: [
const Spacer(),
Text(
Translator.translate('more_about_us'),
style: const TextStyle(
color: Color(0xff222D4E),
fontSize: 16,
fontWeight: FontWeight.bold,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: context.height * 33 / AppConstants.instance.appHeight),
Stack(
children: [
Align(
alignment: AlignmentDirectional.center,
child: Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
Translator.translate('more_about_us'),
style: const TextStyle(
color: Color(0xff222D4E),
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
), ),
),
const Spacer(),
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: SvgPicture.asset(
'ic_back'.svgPath,
Align(
alignment: AlignmentDirectional.centerEnd,
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: SvgPicture.asset(
'ic_back'.svgPath,
),
),
), ),
],
),
SizedBox(height: context.height * 54 / AppConstants.instance.appHeight),
Text(
Translator.translate('main_target'),
style: const TextStyle(color: Color(0xff178756), fontSize: 16),
),
SizedBox(height: context.height * 11 / AppConstants.instance.appHeight),
SingleChildScrollView(
child: FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(
snapshot.data as String,
textDirection: TextDirection.rtl,
style: const TextStyle(
color: Color(0xff636E88),
fontSize: 13,
),
textAlign: TextAlign.justify,
);
}
return const CircularProgressIndicator();
},
future: rootBundle.loadString('assets/meta/about_us.txt'),
), ),
],
),
SizedBox(height: context.height * 54 / AppConstants.instance.appHeight),
Text(
Translator.translate('main_target'),
style: const TextStyle(color: Color(0xff178756), fontSize: 16),
),
SizedBox(height: context.height * 11 / AppConstants.instance.appHeight),
SingleChildScrollView(
child: FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(
snapshot.data as String,
textDirection: TextDirection.rtl,
style: const TextStyle(
color: Color(0xff636E88),
fontSize: 13,
),
textAlign: TextAlign.justify,
);
}
return const CircularProgressIndicator();
},
future: rootBundle.loadString('assets/meta/about_us.txt'),
), ),
),
SizedBox(height: context.height * 20 / AppConstants.instance.appHeight),
Text(
Translator.translate('contact_to_us'),
style: const TextStyle(color: Color(0xff178756), fontSize: 16),
),
SizedBox(height: context.height * 24 / AppConstants.instance.appHeight),
Row(
children: [
GestureDetector(
onTap: _openInstagram,
child: Row(
children: [
const Text(
'Sonnat_islam',
style: TextStyle(color: Color(0xff404966), fontSize: 13),
),
SizedBox(width: context.width * 15 / AppConstants.instance.appWidth),
SvgPicture.asset('ic_instagram'.svgPath),
],
SizedBox(height: context.height * 20 / AppConstants.instance.appHeight),
Text(
Translator.translate('contact_to_us'),
style: const TextStyle(color: Color(0xff178756), fontSize: 16),
),
SizedBox(height: context.height * 24 / AppConstants.instance.appHeight),
Row(
children: [
GestureDetector(
onTap: _openInstagram,
child: Row(
children: [
const Text(
'Sonnat_islam',
style: TextStyle(color: Color(0xff404966), fontSize: 13),
),
SizedBox(width: context.width * 15 / AppConstants.instance.appWidth),
SvgPicture.asset('ic_instagram'.svgPath),
],
),
), ),
),
const Spacer(),
GestureDetector(
onTap: _openPhone,
child: Row(
children: [
const Text(
'+98 92300264',
textDirection: TextDirection.ltr,
style: TextStyle(color: Color(0xff404966), fontSize: 13),
),
SizedBox(width: context.width * 15 / AppConstants.instance.appWidth),
SvgPicture.asset('ic_phone'.svgPath),
],
const Spacer(),
GestureDetector(
onTap: _openPhone,
child: Row(
children: [
const Text(
'+98 92300264',
textDirection: TextDirection.ltr,
style: TextStyle(color: Color(0xff404966), fontSize: 13),
),
SizedBox(width: context.width * 15 / AppConstants.instance.appWidth),
SvgPicture.asset('ic_phone'.svgPath),
],
),
), ),
),
],
),
SizedBox(height: context.height * 29 / AppConstants.instance.appHeight),
Text(
Translator.translate('send_message_to_us'),
style: const TextStyle(color: Color(0xff404966), fontSize: 12),
),
SizedBox(height: context.height * 12 / AppConstants.instance.appHeight),
TextFormField(
autofocus: true,
maxLength: 300,
controller: _controller,
maxLines: 10,
minLines: 4,
style: const TextStyle(
color: Color(0xff8D95AB),
fontSize: 10,
],
), ),
decoration: InputDecoration(
fillColor: Colors.transparent,
hintText: Translator.translate('send_message'),
filled: true,
counterText: '',
hintStyle: const TextStyle(
SizedBox(height: context.height * 29 / AppConstants.instance.appHeight),
Text(
Translator.translate('send_message_to_us'),
style: const TextStyle(color: Color(0xff404966), fontSize: 12),
),
SizedBox(height: context.height * 12 / AppConstants.instance.appHeight),
TextFormField(
autofocus: false,
maxLength: 300,
controller: _controller,
maxLines: 10,
minLines: 4,
style: const TextStyle(
color: Color(0xff8D95AB), color: Color(0xff8D95AB),
fontSize: 10, fontSize: 10,
), ),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xff636E88)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Color(0xff636E88),
decoration: InputDecoration(
fillColor: Colors.transparent,
hintText: Translator.translate('send_message'),
filled: true,
counterText: '',
hintStyle: const TextStyle(
color: Color(0xff8D95AB),
fontSize: 10,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xff636E88)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Color(0xff636E88),
),
), ),
), ),
), ),
),
SizedBox(height: context.height * 9 / AppConstants.instance.appHeight),
Container(
decoration: BoxDecoration(
color: const Color(0xff178756),
borderRadius: BorderRadius.circular(12),
),
padding: EdgeInsets.symmetric(
horizontal: context.width * 20 / AppConstants.instance.appWidth,
vertical: context.height * 10 / AppConstants.instance.appHeight,
),
child: Text(
Translator.translate('send'),
style: const TextStyle(color: Color(0xffffffff), fontSize: 12),
SizedBox(height: context.height * 9 / AppConstants.instance.appHeight),
Container(
decoration: BoxDecoration(
color: const Color(0xff178756),
borderRadius: BorderRadius.circular(12),
),
padding: EdgeInsets.symmetric(
horizontal: context.width * 20 / AppConstants.instance.appWidth,
vertical: context.height * 10 / AppConstants.instance.appHeight,
),
child: Text(
Translator.translate('send'),
style: const TextStyle(color: Color(0xffffffff), fontSize: 12),
),
), ),
),
],
],
),
), ),
), ),
); );

9
lib/features/main/widget/main_item_widget.dart

@ -22,14 +22,19 @@ class MainItemWidget extends StatelessWidget {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
SvgPicture.asset(icon.svgPath),
SvgPicture.asset(
icon.svgPath,
height: 35,
width: 35,
),
SizedBox(height: context.height * 8 / AppConstants.instance.appHeight), SizedBox(height: context.height * 8 / AppConstants.instance.appHeight),
Text( Text(
name, name,
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 16,
fontSize: 14,
), ),
textAlign: TextAlign.center,
), ),
], ],
), ),

161
lib/features/posts/screen/posts_screen.dart

@ -4,9 +4,12 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:sonnat/core/extensions/context_extension.dart'; import 'package:sonnat/core/extensions/context_extension.dart';
import 'package:sonnat/core/extensions/string_extension.dart'; import 'package:sonnat/core/extensions/string_extension.dart';
import 'package:sonnat/core/language/translator.dart'; import 'package:sonnat/core/language/translator.dart';
import 'package:sonnat/core/select_language/cubit/select_language_cubit.dart';
import 'package:sonnat/core/select_language/screen/select_language_screen.dart';
import 'package:sonnat/core/utils/app_constants.dart'; import 'package:sonnat/core/utils/app_constants.dart';
import 'package:sonnat/core/utils/base_cubit_type.dart'; import 'package:sonnat/core/utils/base_cubit_type.dart';
import 'package:sonnat/core/widgets/loading_list_widget.dart'; import 'package:sonnat/core/widgets/loading_list_widget.dart';
import 'package:sonnat/features/aabout_us/about_us_screen.dart';
import 'package:sonnat/features/posts/cubit/posts_cubit.dart'; import 'package:sonnat/features/posts/cubit/posts_cubit.dart';
import 'package:sonnat/features/posts/widgets/filter_item_widget.dart'; import 'package:sonnat/features/posts/widgets/filter_item_widget.dart';
import 'package:sonnat/features/posts/widgets/post_item_widget.dart'; import 'package:sonnat/features/posts/widgets/post_item_widget.dart';
@ -118,40 +121,50 @@ class _PostsScreenState extends State<PostsScreen> {
), ),
], ],
) )
: Row(
: Stack(
children: [ children: [
GestureDetector(
onTap: () {},
child: SvgPicture.asset(
'ic_more'.svgPath,
Align(
alignment: AlignmentDirectional.centerStart,
child: GestureDetector(
onTap: _showOptions,
child: SvgPicture.asset(
'ic_more'.svgPath,
),
), ),
), ),
SizedBox(width: context.width * 8 / AppConstants.instance.appWidth),
GestureDetector(
onTap: () {
setState(() {
_searchMode = !_searchMode;
});
},
child: SvgPicture.asset(
'ic_rounded_search'.svgPath,
PositionedDirectional(
start: context.width * 44 / AppConstants.instance.appWidth,
child: GestureDetector(
onTap: () {
setState(() {
_searchMode = !_searchMode;
});
},
child: SvgPicture.asset('ic_rounded_search'.svgPath),
), ),
), ),
const Spacer(),
Text(
widget.title,
style: const TextStyle(
color: Color(0xff404966),
fontSize: 22,
Align(
alignment: AlignmentDirectional.center,
child: Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
widget.title,
style: const TextStyle(
color: Color(0xff404966),
fontSize: 22,
),
),
), ),
), ),
const Spacer(),
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: SvgPicture.asset(
'ic_back'.svgPath,
Align(
alignment: AlignmentDirectional.centerEnd,
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: SvgPicture.asset(
'ic_back'.svgPath,
),
), ),
), ),
], ],
@ -200,8 +213,8 @@ class _PostsScreenState extends State<PostsScreen> {
: _cubit.query.isEmpty : _cubit.query.isEmpty
? '' ? ''
: _cubit.searchedList.isEmpty : _cubit.searchedList.isEmpty
? "موردی یافت نشد"
: "${_cubit.searchedList.length} مورد یافت شد",
? 'موردی یافت نشد'
: '${_cubit.searchedList.length} مورد یافت شد',
style: const TextStyle( style: const TextStyle(
color: Color(0xff636E88), color: Color(0xff636E88),
fontSize: 12, fontSize: 12,
@ -273,6 +286,74 @@ class _PostsScreenState extends State<PostsScreen> {
), ),
); );
} }
void _showOptions() {
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
builder: (context) {
return Container(
height: 120,
width: context.width,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.white, width: 0.2),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
padding: const EdgeInsets.only(
top: 16,
left: 4,
right: 4,
),
child: Column(
children: [
MoreOptionsWidget(
title: Translator.translate('about_us'),
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const AboutUsScreen();
},
),
);
},
),
const SizedBox(height: 8),
Container(
width: context.width,
height: 1,
color: const Color(0xffD3D8E9),
),
const SizedBox(height: 8),
MoreOptionsWidget(
title: Translator.translate('select_language'),
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return BlocProvider(
child: const SelectLanguageScreen(),
create: (context) => SelectLanguageCubit(),
);
},
),
);
},
),
],
),
);
},
);
}
} }
class FilterItem { class FilterItem {
@ -281,3 +362,25 @@ class FilterItem {
const FilterItem({required this.selected, required this.title}); const FilterItem({required this.selected, required this.title});
} }
class MoreOptionsWidget extends StatelessWidget {
final String title;
final Function() onTap;
const MoreOptionsWidget({super.key, required this.title, required this.onTap});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Text(
title,
style: const TextStyle(
color: Color(0xff222D4E),
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
);
}
}

22
lib/features/single_post/screen/single_post_screen.dart

@ -1,4 +1,3 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
@ -9,7 +8,6 @@ import 'package:sonnat/core/language/translator.dart';
import 'package:sonnat/core/utils/app_constants.dart'; import 'package:sonnat/core/utils/app_constants.dart';
import 'package:sonnat/core/utils/app_utils.dart'; import 'package:sonnat/core/utils/app_utils.dart';
import 'package:sonnat/core/utils/base_cubit_type.dart'; import 'package:sonnat/core/utils/base_cubit_type.dart';
import 'package:sonnat/core/widgets/shimmer.dart';
import 'package:sonnat/features/single_post/cubit/single_post_cubit.dart'; import 'package:sonnat/features/single_post/cubit/single_post_cubit.dart';
import 'package:sonnat/features/single_post/view_models/post.dart'; import 'package:sonnat/features/single_post/view_models/post.dart';
import 'package:sonnat/features/single_post/widget/add_comment_widget.dart'; import 'package:sonnat/features/single_post/widget/add_comment_widget.dart';
@ -57,14 +55,17 @@ class _SinglePostScreenState extends State<SinglePostScreen> {
widget.post.image, widget.post.image,
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
const Positioned(
top: 0,
left: 8,
right: 8,
child: Row(
children: <Widget>[
BackButton(color: Colors.white),
],
PositionedDirectional(
end: 16,
top: 16,
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: const Icon(
Icons.arrow_forward_rounded,
color: Colors.white,
),
), ),
), ),
Positioned( Positioned(
@ -155,6 +156,7 @@ class _SinglePostScreenState extends State<SinglePostScreen> {
padding: EdgeInsetsDirectional.only( padding: EdgeInsetsDirectional.only(
start: context.width * 26 / AppConstants.instance.appWidth, start: context.width * 26 / AppConstants.instance.appWidth,
end: context.width * 37 / AppConstants.instance.appWidth, end: context.width * 37 / AppConstants.instance.appWidth,
top: 16,
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

28
lib/features/splash/cubit/splash_cubit.dart

@ -0,0 +1,28 @@
import 'package:data/app_setting_data/repository/app_setting_box_repository_impl.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:local_db_core/lib/boxes/box_list/setting_box/app_setting_box.dart';
import 'package:repositories/app_setting_box_domain/repository/app_setting_box_repository.dart';
import 'package:sonnat/core/utils/base_cubit_type.dart';
class SplashCubit extends Cubit<BaseCubitType<SplashCubitState>> {
final AppSettingBoxRepository _repository = AppSettingBoxRepositoryImpl(appSettingBox: AppSettingBox());
SplashCubit() : super(BaseCubitType(eventName: SplashCubitState.empty));
void empty() => emit(BaseCubitType(eventName: SplashCubitState.empty));
Future<void> checkLanguageSet() async {
String? language = _repository.getCurrentLanguage();
if(language == null || language == '') {
emit(BaseCubitType(eventName: SplashCubitState.notSet));
} else {
emit(BaseCubitType(eventName: SplashCubitState.set));
}
}
}
enum SplashCubitState {
empty,
set,
notSet,
}

83
lib/features/splash/screen/splash_screen.dart

@ -0,0 +1,83 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sonnat/core/extensions/context_extension.dart';
import 'package:sonnat/core/extensions/string_extension.dart';
import 'package:sonnat/core/select_language/cubit/select_language_cubit.dart';
import 'package:sonnat/core/select_language/screen/select_language_screen.dart';
import 'package:sonnat/core/utils/app_constants.dart';
import 'package:sonnat/core/utils/base_cubit_type.dart';
import 'package:sonnat/features/main/main_screen.dart';
import 'package:sonnat/features/splash/cubit/splash_cubit.dart';
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
@override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
late final SplashCubit _cubit;
@override
void initState() {
_cubit = BlocProvider.of<SplashCubit>(context);
Future.delayed(const Duration(milliseconds: 2500), _cubit.checkLanguageSet);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xff26237A),
body: BlocBuilder<SplashCubit, BaseCubitType<SplashCubitState>>(
builder: (context, state) {
switch (state.eventName!) {
case SplashCubitState.empty:
break;
case SplashCubitState.set:
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const MainScreen();
},
),
);
});
break;
case SplashCubitState.notSet:
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return BlocProvider(
create: (context) => SelectLanguageCubit(),
child: const SelectLanguageScreen(),
);
},
),
);
});
break;
}
return Center(
child: Container(
margin: EdgeInsets.only(
left: context.width * 86 / AppConstants.instance.appWidth,
right: context.width * 86 / AppConstants.instance.appWidth,
),
child: Image.asset(
'ic_main_header'.pngPath,
width: context.width * 200 / AppConstants.instance.appWidth,
height: context.height * 200 / AppConstants.instance.appHeight,
),
),
);
},
),
);
}
}

119
lib/main.dart

@ -1,6 +1,3 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -10,18 +7,13 @@ import 'package:sonnat/core/theme/cubit/theme_cubit.dart';
import 'package:sonnat/core/utils/app_utils.dart'; import 'package:sonnat/core/utils/app_utils.dart';
import 'package:sonnat/core/utils/base_cubit_type.dart'; import 'package:sonnat/core/utils/base_cubit_type.dart';
import 'package:sonnat/core/utils/initializer.dart'; import 'package:sonnat/core/utils/initializer.dart';
import 'package:sonnat/features/main/main_screen.dart';
import 'package:sonnat/features/splash/cubit/splash_cubit.dart';
import 'package:sonnat/features/splash/screen/splash_screen.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await Initializer.instance.initialHive(); await Initializer.instance.initialHive();
if (!kDebugMode) {
await runZonedGuarded<Future<void>>(() async {
runApp(const MyApp());
}, (error, stackTrace) async {});
} else {
runApp(const MyApp());
}
runApp(const MyApp());
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
@ -30,6 +22,7 @@ class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider(create: (context) => LanguageCubit()), BlocProvider(create: (context) => LanguageCubit()),
@ -52,67 +45,59 @@ class _MyHomePageState extends State<MyHomePage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<LanguageCubit, BaseCubitType<LanguageState>>( return BlocBuilder<LanguageCubit, BaseCubitType<LanguageState>>(
builder: (context, state) { builder: (context, state) {
if (state.eventName == LanguageState.loaded) {
Initializer.instance.setAppDirection(
state.data == CurrentLanguage.fa || state.data == CurrentLanguage.ar ? 'rtl' : 'ltr',
);
return MaterialApp(
builder: (context, child) {
Widget error = const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'خطا در نمابش اطلاعات',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w700,
fontSize: 18,
),
textAlign: TextAlign.center,
),
],
),
);
if (child is Scaffold || child is Navigator) {
error = Scaffold(
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
error,
const Icon(
Icons.error_outline_rounded,
size: 130,
color: Colors.red,
),
],
return MaterialApp(
builder: (context, child) {
Widget error = const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'خطا در نمابش اطلاعات',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w700,
fontSize: 18,
), ),
textAlign: TextAlign.center,
),
],
),
);
if (child is Scaffold || child is Navigator) {
error = Scaffold(
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
error,
const Icon(
Icons.error_outline_rounded,
size: 130,
color: Colors.red,
),
],
), ),
);
}
ErrorWidget.builder = (errorDetails) => error;
return ScrollConfiguration(
behavior: DisableScrollEffect().copyWith(scrollbars: false),
child: Directionality(
textDirection: Initializer.instance.getTextDirection(),
child: child!,
), ),
); );
},
theme: Utils.instance.getAppTheme(context, state.data),
debugShowCheckedModeBanner: false,
supportedLocales: Translator.supportedLocales(),
initialRoute: '/',
routes: {
'/': (context) => const MainScreen(),
},
);
}
return MaterialApp(
}
ErrorWidget.builder = (errorDetails) => error;
return ScrollConfiguration(
behavior: DisableScrollEffect().copyWith(scrollbars: false),
child: Directionality(
textDirection: Initializer.instance.getTextDirection(),
child: child!,
),
);
},
theme: Utils.instance.getAppTheme(context),
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
builder: (context, child) {
return Container(color: Colors.white);
supportedLocales: Translator.supportedLocales(),
initialRoute: '/',
routes: {
'/': (context) => BlocProvider(
create: (context) => SplashCubit(),
child: const SplashScreen(),
),
}, },
); );
}, },

12
pubspec.lock

@ -109,10 +109,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: cli_util name: cli_util
sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c"
sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.5"
version: "0.4.0"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@ -225,10 +225,10 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_launcher_icons name: flutter_launcher_icons
sha256: a9de6706cd844668beac27c0aed5910fa0534832b3c2cad61a5fd977fce82a5d
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.10.0"
version: "0.13.1"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -307,10 +307,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: image name: image
sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6"
sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.3.0"
version: "4.0.17"
intl: intl:
dependency: "direct main" dependency: "direct main"
description: description:

7
pubspec.yaml

@ -37,7 +37,7 @@ dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^2.0.0 flutter_lints: ^2.0.0
flutter_launcher_icons: ^0.10.0
flutter_launcher_icons: ^0.13.1
flutter: flutter:
uses-material-design: true uses-material-design: true
assets: assets:
@ -68,3 +68,8 @@ flutter:
- asset: assets/fonts/arabi/Cairo-Medium.ttf - asset: assets/fonts/arabi/Cairo-Medium.ttf
- asset: assets/fonts/arabi/Cairo-Regular.ttf - asset: assets/fonts/arabi/Cairo-Regular.ttf
- asset: assets/fonts/arabi/Cairo-SemiBold.ttf - asset: assets/fonts/arabi/Cairo-SemiBold.ttf
flutter_icons:
android: "launcher_icon"
ios: true
image_path: "assets/images/png/logo.png"
Loading…
Cancel
Save