First Commit

This commit is contained in:
Abdullah Salah 2024-12-26 09:10:35 +03:00
commit cf9784f468
34 changed files with 2278 additions and 0 deletions

43
.gitignore vendored Normal file
View File

@ -0,0 +1,43 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

45
.metadata Normal file
View File

@ -0,0 +1,45 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "4cf269e36de2573851eaef3c763994f8f9be494d"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
- platform: android
create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
- platform: ios
create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
- platform: linux
create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
- platform: macos
create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
- platform: web
create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
- platform: windows
create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

16
README.md Normal file
View File

@ -0,0 +1,16 @@
# baligh_dashboard
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

28
analysis_options.yaml Normal file
View File

@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

BIN
assets/fonts/Cairo-Bold.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

1
firebase.json Normal file
View File

@ -0,0 +1 @@
{"flutter":{"platforms":{"dart":{"lib/firebase_options.dart":{"projectId":"baligh-fbef7","configurations":{"web":"1:580708075572:web:72a4af92dc560d72702261"}}}}}}

66
lib/constants/theme.dart Normal file
View File

@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
class MyCustomTheme {
static Color primaryColor = const Color.fromARGB(255, 42, 61, 171);
static Color cardColor = const Color(0xFFECECEC);
static Color textColor = const Color(0xFF181818);
static Color bgColor = const Color(0xFFF8FAFC);
static Color dividerColor = const Color(0xFF4C4C4C);
static ThemeData theme = ThemeData(
primaryColor: primaryColor,
useMaterial3: true,
cardColor: cardColor,
scaffoldBackgroundColor: bgColor,
dividerColor: dividerColor,
textTheme: TextTheme(
headlineLarge: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
fontFamily: "Cairo",
color: textColor,
),
titleLarge: TextStyle(
fontSize: 22,
fontWeight: FontWeight.w500,
fontFamily: "Cairo",
color: textColor,
),
bodyLarge: TextStyle(
fontSize: 18,
fontWeight: FontWeight.normal,
fontFamily: "Cairo",
color: textColor,
),
bodyMedium: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: "Cairo",
color: textColor,
),
bodySmall: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
fontFamily: "Cairo",
color: textColor,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ButtonStyle(
elevation: const WidgetStatePropertyAll(0),
backgroundColor: WidgetStatePropertyAll(primaryColor),
shape: WidgetStatePropertyAll(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
)),
outlinedButtonTheme: OutlinedButtonThemeData(
style: ButtonStyle(
elevation: const WidgetStatePropertyAll(0),
shape: WidgetStatePropertyAll(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
)),
)),
);
}

64
lib/firebase_options.dart Normal file
View File

@ -0,0 +1,64 @@
// File generated by FlutterFire CLI.
// ignore_for_file: type=lint
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for android - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.iOS:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for ios - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.macOS:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for macos - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyBwuk1s6fLiPK0DjEpjYK-s9aZby8z-FiM',
appId: '1:580708075572:web:72a4af92dc560d72702261',
messagingSenderId: '580708075572',
projectId: 'baligh-fbef7',
authDomain: 'baligh-fbef7.firebaseapp.com',
storageBucket: 'baligh-fbef7.appspot.com',
measurementId: 'G-KQX9WQ9Y8M',
);
}

34
lib/main.dart Normal file
View File

@ -0,0 +1,34 @@
import 'package:baligh_dashboard/constants/theme.dart';
import 'package:baligh_dashboard/firebase_options.dart';
import 'package:baligh_dashboard/screens/login_screen.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'بلغ',
debugShowCheckedModeBanner: false,
theme: MyCustomTheme.theme,
locale: const Locale("ar"),
builder: BotToastInit(),
home: const LoginScreen(),
);
}
}

View File

@ -0,0 +1,156 @@
import 'package:baligh_dashboard/widgets/app_toast.dart';
import 'package:baligh_dashboard/widgets/custom_button.dart';
import 'package:baligh_dashboard/widgets/custom_text_field.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class AdminScreen extends StatefulWidget {
const AdminScreen({super.key});
@override
State<AdminScreen> createState() => _AdminScreenState();
}
class _AdminScreenState extends State<AdminScreen> {
TextEditingController usernameController = TextEditingController();
TextEditingController passwordController = TextEditingController();
String selectedRole = "التحرش";
List<String> availableRoles = [
"التحرش",
"التعنيف",
"الابتزاز",
"المخدرات",
"الرشوة",
];
bool isLoading = false;
@override
void dispose() {
usernameController.dispose();
passwordController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
body: SafeArea(
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500,
minWidth: 100,
),
child: ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(15),
children: [
Text(
"اضافى مشرف",
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(
height: 50,
),
CustomTextField(
controller: usernameController,
labelText: "اسم المشرف",
inputType: TextInputType.text),
const SizedBox(
height: 10,
),
CustomTextField(
controller: passwordController,
labelText: "كلمة المرور",
inputType: TextInputType.text,
isPassword: true,
),
const SizedBox(
height: 10,
),
Row(
children: [
DropdownMenu<String>(
initialSelection: "التحرش",
label: const Text("نوع البلاغ"),
onSelected: (String? value) {
setState(() {
selectedRole = value ?? "التحرش";
});
},
dropdownMenuEntries: availableRoles
.map<DropdownMenuEntry<String>>((value) {
return DropdownMenuEntry<String>(
value: value,
label: value,
);
}).toList(),
),
],
),
const SizedBox(
height: 15,
),
CustomButton(
label: "اضافة المشرف",
isElevated: true,
onPressed: handleCreateAdmin,
isLoading: isLoading,
),
],
),
),
),
),
),
);
}
Future<void> handleCreateAdmin() async {
if (passwordController.text.trim().isEmpty ||
usernameController.text.trim().isEmpty) {
BotToast.showCustomText(toastBuilder: (_) {
return const AppToast(text: "يجب ملئ جميع الحقول");
});
return;
}
setState(() {
isLoading = true;
});
try {
await FirebaseFirestore.instance.collection("admins").add({
"role": selectedRole,
"username": usernameController.text.trim(),
"password": passwordController.text.trim(),
"createdAt": FieldValue.serverTimestamp(),
});
setState(() {
isLoading = false;
usernameController.clear();
passwordController.clear();
});
// if (!mounted) return;
BotToast.showCustomText(toastBuilder: (_) {
return const AppToast(text: "تم اضافة مشرف");
});
} catch (e) {
print(e);
setState(() {
isLoading = false;
});
BotToast.showCustomText(toastBuilder: (_) {
return const AppToast(text: "حدث خطأ ما");
});
}
}
}

View File

@ -0,0 +1,245 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:baligh_dashboard/screens/admin_screen.dart';
import 'package:baligh_dashboard/widgets/custom_button.dart';
import 'package:baligh_dashboard/widgets/dashboard_tile.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class DashboardScreen extends StatefulWidget {
const DashboardScreen({super.key, required this.adminRole});
final String adminRole;
@override
State<DashboardScreen> createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen> {
bool isLoading = false;
String? error;
List<Map<String, dynamic>> reports = [];
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
getInitialData();
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(
height: 50,
),
AutoSizeText(
"البلاغات",
style: Theme.of(context).textTheme.titleLarge,
minFontSize: 12,
),
if (isLoading) ...[
const SizedBox(
height: 50,
),
Text("جار التحميل",
style: Theme.of(context).textTheme.bodyLarge),
] else if (error != null) ...[
const SizedBox(
height: 50,
),
Text(error!, style: Theme.of(context).textTheme.bodyLarge),
] else ...[
if (widget.adminRole == "admin") ...[
const SizedBox(
height: 10,
),
SizedBox(
width: 200,
child: CustomButton(
label: "اضافة مشرف",
isElevated: true,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AdminScreen()));
},
),
),
],
const SizedBox(
height: 30,
),
Row(
children: [
Expanded(
child: AutoSizeText(
"اسم صاحب البلاغ",
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
"عنوان صاحب البلاغ",
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
"المدرسة",
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
"نوع البلاغ",
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
"الحالة",
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
],
),
const SizedBox(
height: 10,
),
Expanded(
child: ListView.separated(
shrinkWrap: true,
itemCount: reports.length,
separatorBuilder: (context, index) => const SizedBox(
height: 10,
),
itemBuilder: (context, index) => DashboardTile(
id: reports[index]["id"] ?? "",
name: reports[index]["name"] ?? "",
age: reports[index]["age"] ?? "",
phone: reports[index]["phone"] ?? "",
address: reports[index]["address"] ?? "",
school: reports[index]["schoolName"] ?? "",
nationalIdNumber:
reports[index]["nationalIdNumber"] ?? "",
description: reports[index]["description"] ?? "",
attachments: reports[index]["attachments"] ?? "",
type: reports[index]["type"] ?? "",
createdAt: reports[index]["createdAt"] ?? "",
status: reports[index]["status"] ?? ""),
),
)
]
],
),
),
),
),
);
}
Future<void> getInitialData() async {
try {
setState(() {
isLoading = true;
});
var temp = await getReportsWithUsers();
setState(() {
isLoading = false;
reports = temp;
});
} catch (e, s) {
setState(() {
isLoading = false;
error = "حدث خطأ ما";
});
}
}
Future<List<Map<String, dynamic>>> getReportsWithUsers() async {
QuerySnapshot reportsSnapshot;
if (widget.adminRole == "admin") {
reportsSnapshot = await FirebaseFirestore.instance
.collection('reports')
.orderBy('createdAt', descending: true)
.get();
} else {
reportsSnapshot = await FirebaseFirestore.instance
.collection('reports')
.where('type', isEqualTo: widget.adminRole)
.orderBy('createdAt', descending: true)
.get();
}
List<Map<String, dynamic>> reportsWithUsers = [];
Set<DocumentReference> userRefs = {};
// Collect unique user references
for (var reportDoc in reportsSnapshot.docs) {
var reportData = reportDoc.data() as Map<String, dynamic>;
if (reportData['userRef'] == null) continue;
userRefs.add(reportData['userRef'] as DocumentReference);
reportsWithUsers.add({
'id': reportDoc.id,
'type': reportData["type"],
'description': reportData["description"],
'attachments': reportData["attachments"],
'status': reportData["status"],
'createdAt': reportData["createdAt"],
'userId': reportData["userId"],
});
}
// Fetch all user data in one go
var userDocs = await Future.wait(userRefs.map((ref) => ref.get()));
for (var el in userDocs) {
int index = reportsWithUsers.indexWhere((r) => r["userId"] == el["uid"]);
reportsWithUsers[index]["name"] = el["name"];
reportsWithUsers[index]["phone"] = el["phone"];
reportsWithUsers[index]["age"] = el["age"];
reportsWithUsers[index]["schoolName"] = el["schoolName"];
reportsWithUsers[index]["stage"] = el["stage"];
reportsWithUsers[index]["address"] = el["address"];
reportsWithUsers[index]["nationalIdNumber"] = el["nationalIdNumber"];
}
return reportsWithUsers;
}
}

View File

@ -0,0 +1,136 @@
import 'package:baligh_dashboard/screens/dashboard_screen.dart';
import 'package:baligh_dashboard/widgets/app_toast.dart';
import 'package:baligh_dashboard/widgets/custom_button.dart';
import 'package:baligh_dashboard/widgets/custom_text_field.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@override
State<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController usernameController = TextEditingController();
TextEditingController passwordController = TextEditingController();
bool isLoading = false;
@override
void dispose() {
usernameController.dispose();
passwordController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
body: SafeArea(
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 500,
minWidth: 100,
),
child: ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(15),
children: [
Text(
"تسجيل الدخول",
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(
height: 50,
),
CustomTextField(
controller: usernameController,
labelText: "اسم المشرف",
inputType: TextInputType.text),
const SizedBox(
height: 10,
),
CustomTextField(
controller: passwordController,
labelText: "كلمة المرور",
inputType: TextInputType.text,
isPassword: true,
),
const SizedBox(
height: 15,
),
CustomButton(
label: "تسجيل الدخول",
isElevated: true,
onPressed: handleLogIn,
isLoading: isLoading,
),
],
),
),
),
),
),
);
}
Future<void> handleLogIn() async {
if (usernameController.text.trim().isEmpty ||
passwordController.text.trim().isEmpty) {
BotToast.showCustomText(toastBuilder: (_) {
return const AppToast(text: "يجب ملئ جميع الحقول");
});
return;
}
setState(() {
isLoading = true;
});
try {
final QuerySnapshot snapshot = await FirebaseFirestore.instance
.collection('admins')
.where('username', isEqualTo: usernameController.text.trim())
.where('password', isEqualTo: passwordController.text.trim())
.get();
if (snapshot.docs.isEmpty) {
setState(() {
isLoading = false;
});
BotToast.showCustomText(toastBuilder: (_) {
return const AppToast(text: "اسم المشرف او كلمة المرور خطأ");
});
return;
}
var admin = snapshot.docs.first.data() as Map<String, dynamic>;
setState(() {
isLoading = false;
});
if (!mounted) return;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DashboardScreen(adminRole: admin["role"])),
);
} catch (e) {
print(e);
setState(() {
isLoading = false;
});
BotToast.showCustomText(toastBuilder: (_) {
return const AppToast(text: "حدث خطأ ما");
});
}
}
}

View File

@ -0,0 +1,244 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:baligh_dashboard/utils/file_classification.dart';
import 'package:baligh_dashboard/widgets/app_toast.dart';
import 'package:baligh_dashboard/widgets/dashboard_tile.dart';
import 'package:baligh_dashboard/widgets/file_card.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class ReportDetailsScreen extends StatefulWidget {
const ReportDetailsScreen({
super.key,
required this.id,
required this.name,
required this.address,
required this.school,
required this.type,
required this.status,
required this.age,
required this.attachments,
required this.createdAt,
required this.description,
required this.nationalIdNumber,
required this.phone,
});
final String id;
final String name;
final String address;
final String school;
final String type;
final String status;
final Timestamp createdAt;
final int age;
final String phone;
final int nationalIdNumber;
final String description;
final List attachments;
@override
State<ReportDetailsScreen> createState() => _ReportDetailsScreenState();
}
class _ReportDetailsScreenState extends State<ReportDetailsScreen> {
String selectedStatus = "قيد الانتظار";
List<String> availableStatus = [
"قيد الانتظار",
"قيد المعالجة",
"مكتمل",
];
@override
void initState() {
setState(() {
selectedStatus = widget.status;
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
body: SafeArea(
child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 15),
children: [
const SizedBox(
height: 50,
),
AutoSizeText(
"تفاصيل البلاغ",
style: Theme.of(context).textTheme.titleLarge,
minFontSize: 12,
),
const SizedBox(
height: 30,
),
Wrap(
children: [
Text(
"حالة البلاغ:",
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(
width: 5,
),
DropdownMenu<String>(
initialSelection: "قيد الانتظار",
label: const Text("الحالة"),
onSelected: (String? value) async {
var old = selectedStatus;
setState(() {
selectedStatus = value ?? "قيد الانتظار";
});
try {
await FirebaseFirestore.instance
.collection("reports")
.doc(widget.id)
.update({
'status': selectedStatus,
});
} catch (e) {
setState(() {
selectedStatus = old;
});
BotToast.showCustomText(toastBuilder: (_) {
return const AppToast(text: "حدث خطأ ما");
});
}
},
dropdownMenuEntries:
availableStatus.map<DropdownMenuEntry<String>>((value) {
return DropdownMenuEntry<String>(
value: value,
label: value,
);
}).toList(),
),
],
),
const SizedBox(
height: 15,
),
Row(
children: [
Expanded(
child: AutoSizeText(
"اسم صاحب البلاغ",
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
"عنوان صاحب البلاغ",
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
"المدرسة",
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
"نوع البلاغ",
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
"الحالة",
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
],
),
const SizedBox(
height: 10,
),
DashboardTile(
id: widget.id,
name: widget.name,
age: widget.age,
phone: widget.phone,
address: widget.address,
school: widget.school,
nationalIdNumber: widget.nationalIdNumber,
description: widget.description,
attachments: widget.attachments,
type: widget.type,
createdAt: widget.createdAt,
status: widget.status,
),
const SizedBox(
height: 20,
),
AutoSizeText(
"وصف البلاغ",
style: Theme.of(context).textTheme.bodyLarge,
minFontSize: 12,
),
const SizedBox(
height: 10,
),
Text(
widget.description,
style: Theme.of(context).textTheme.bodySmall,
),
const SizedBox(
height: 20,
),
AutoSizeText(
"الملفات المرفقة",
style: Theme.of(context).textTheme.bodyLarge,
minFontSize: 12,
),
const SizedBox(
height: 10,
),
Wrap(
children: widget.attachments
.map(
(el) => FileCard(
type: FileClassification.getFileClass(el),
filename: FileClassification.getFileName(el) ?? "",
fileUrl: el,),
)
.toList(),
),
const SizedBox(
height: 30,
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,54 @@
import 'package:file_saver/file_saver.dart';
class FileClassification {
static String? getFileName(String url) {
Uri uri = Uri.parse(url);
return uri.pathSegments.isNotEmpty ? uri.pathSegments.last : null;
}
static String getFileClass(String url) {
String? fileName = getFileName(url);
if (fileName == null) return 'unknown';
// Get the file extension
String extension = fileName.split('.').last.toLowerCase();
// Determine the class based on the file extension
if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].contains(extension)) {
return 'image';
} else if (['mp3', 'wav', 'ogg', 'aac'].contains(extension)) {
return 'audio';
} else if (['mp4', 'mkv', 'webm', 'avi', 'mov'].contains(extension)) {
return 'video';
} else {
return 'unknown';
}
}
static MimeType getMimeType(String filename) {
String extension = filename.split('.').last.toLowerCase();
switch (extension.toLowerCase()) {
case 'jpg':
case 'jpeg':
return MimeType.jpeg;
case 'png':
return MimeType.png;
case 'gif':
return MimeType.gif;
case 'bmp':
return MimeType.bmp;
case 'mp3':
return MimeType.mp3;
case 'aac':
return MimeType.aac;
case 'mp4':
return MimeType.mp4Video;
case 'avi':
return MimeType.avi;
default:
return MimeType.other; // Fallback for unknown types
}
}
}

View File

@ -0,0 +1,42 @@
import 'package:flutter/material.dart';
class AppToast extends StatelessWidget {
const AppToast({
super.key,
required this.text,
this.bottomPadding,
this.color,
this.textStyle,
});
final String text;
final double? bottomPadding;
final Color? color;
final TextStyle? textStyle;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(bottom: bottomPadding ?? 100),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: color ?? Theme.of(context).scaffoldBackgroundColor,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.4),
offset: const Offset(2, 2),
blurRadius: 5,
spreadRadius: 1
)
]
),
child: Text(
text,
style: textStyle ?? Theme.of(context).textTheme.bodyMedium,
),
),
);
}
}

View File

@ -0,0 +1,86 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:baligh_dashboard/constants/theme.dart';
import 'package:baligh_dashboard/widgets/small_spinner.dart';
import 'package:flutter/material.dart';
class CustomButton extends StatelessWidget {
const CustomButton({
super.key,
required this.onPressed,
required this.label,
required this.isElevated,
this.isLoading = false,
this.textStyle,
this.color,
});
final void Function() onPressed;
final String label;
final bool isLoading;
final bool isElevated;
final TextStyle? textStyle;
final Color? color;
@override
Widget build(BuildContext context) {
return isElevated
? ElevatedButton(
onPressed: isLoading ? null : onPressed,
style: Theme.of(context).elevatedButtonTheme.style?.copyWith(
backgroundColor: WidgetStatePropertyAll(color ?? MyCustomTheme.primaryColor)
),
child: isLoading
? const SmallSpinner()
: Padding(
padding: const EdgeInsets.symmetric(horizontal: 3),
child: Row(
children: [
Expanded(
child: AutoSizeText(
label,
minFontSize: 8,
maxFontSize: 14,
maxLines: 1,
textAlign: TextAlign.center,
style: textStyle ?? Theme.of(context).textTheme.bodyLarge?.copyWith(
color: MyCustomTheme.bgColor,
)
),
),
],
),
),
)
: OutlinedButton(
onPressed: isLoading ? null : onPressed,
style: Theme.of(context).elevatedButtonTheme.style?.copyWith(
backgroundColor: WidgetStatePropertyAll(Theme.of(context).scaffoldBackgroundColor),
side: WidgetStatePropertyAll(BorderSide(
width: 1.5,
color: color ?? MyCustomTheme.primaryColor,
))
),
child: isLoading
? SmallSpinner(color: MyCustomTheme.primaryColor,)
: Padding(
padding: const EdgeInsets.symmetric(horizontal: 3),
child: Row(
children: [
Expanded(
child: AutoSizeText(
label,
minFontSize: 8,
maxFontSize: 14,
maxLines: 1,
textAlign: TextAlign.center,
style: textStyle ?? Theme.of(context).textTheme.bodyLarge?.copyWith(
color: color ?? MyCustomTheme.primaryColor,
)
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,77 @@
import 'package:flutter/material.dart';
class CustomTextField extends StatefulWidget {
const CustomTextField({
super.key,
required this.controller,
required this.labelText,
required this.inputType,
this.errorText,
this.isPassword = false,
this.maxLines = 1,
this.focusNode,
});
final TextEditingController controller;
final String labelText;
final TextInputType inputType;
final String? errorText;
final bool isPassword;
final int maxLines;
final FocusNode? focusNode;
@override
State<CustomTextField> createState() => _CustomTextFieldState();
}
class _CustomTextFieldState extends State<CustomTextField> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return TextField(
controller: widget.controller,
focusNode: widget.focusNode,
keyboardType: widget.inputType,
obscureText: widget.isPassword,
enableSuggestions: !widget.isPassword,
autocorrect: false,
maxLines: widget.maxLines,
textDirection: TextDirection.rtl,
style: Theme.of(context).textTheme.bodyMedium,
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(vertical: 5, horizontal: 20),
labelText: widget.labelText,
alignLabelWithHint: true,
labelStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: Theme.of(context).dividerColor),
floatingLabelStyle: Theme.of(context).textTheme.bodySmall?.copyWith(color: Theme.of(context).dividerColor),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Theme.of(context).cardColor, width: 1.5)
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Theme.of(context).dividerColor, width: 1)
),
filled: true,
fillColor: Theme.of(context).cardColor,
errorText: widget.errorText,
errorStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.red
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.red, width: 1.5)
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.red, width: 1.5)
),
),
);
}
}

View File

@ -0,0 +1,127 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:baligh_dashboard/screens/report_details_screen.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class DashboardTile extends StatelessWidget {
const DashboardTile({
super.key,
required this.id,
required this.name,
required this.address,
required this.school,
required this.type,
required this.status,
required this.age,
required this.attachments,
required this.createdAt,
required this.description,
required this.nationalIdNumber,
required this.phone,
});
final String id;
final String name;
final String address;
final String school;
final String type;
final String status;
final Timestamp createdAt;
final int age;
final String phone;
final int nationalIdNumber;
final String description;
final List attachments;
@override
Widget build(BuildContext context) {
return InkWell(
borderRadius: const BorderRadius.all(Radius.circular(12)),
hoverColor: Colors.transparent,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ReportDetailsScreen(
id: id,
name: name,
age: age,
phone: phone,
address: address,
school: school,
nationalIdNumber: nationalIdNumber,
description: description,
attachments: attachments,
type: type,
createdAt: createdAt,
status: status,
)));
},
child: Container(
width: double.infinity,
clipBehavior: Clip.hardEdge,
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
child: Row(
children: [
Expanded(
child: AutoSizeText(
name,
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
address,
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
school,
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
type,
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
status,
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 3,
minFontSize: 8,
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,94 @@
import 'dart:html' as html;
import 'package:auto_size_text/auto_size_text.dart';
import 'package:baligh_dashboard/widgets/app_toast.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class FileCard extends StatelessWidget {
const FileCard(
{super.key,
required this.type,
required this.filename,
required this.fileUrl});
final String type;
final String filename;
final String fileUrl;
@override
Widget build(BuildContext context) {
return InkWell(
borderRadius: const BorderRadius.all(Radius.circular(12)),
hoverColor: Colors.transparent,
onTap: () async {
try {
html.AnchorElement(href: fileUrl)
..setAttribute('target', '_blank')
..setAttribute('download', '$filename.pdf') // Specify the filename
..click();
BotToast.showCustomText(toastBuilder: (_) {
return const AppToast(text: "تم التحميل");
});
} catch (e) {
print(e);
BotToast.showCustomText(toastBuilder: (_) {
return const AppToast(text: "حدث خطأ ما في التحميل");
});
}
},
child: Container(
width: 180,
clipBehavior: Clip.hardEdge,
padding: const EdgeInsets.all(8),
margin: const EdgeInsets.symmetric(horizontal: 3),
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: type == "image"
? Colors.red.withOpacity(0.2)
: type == "video"
? Colors.blue.withOpacity(0.2)
: Colors.grey.withOpacity(0.2),
borderRadius: const BorderRadius.all(Radius.circular(8)),
),
child: Center(
child: Icon(
type == "image"
? FontAwesomeIcons.image
: type == "video"
? FontAwesomeIcons.video
: FontAwesomeIcons.microphone,
color: type == "image"
? Colors.red
: type == "video"
? Colors.blue
: Colors.grey,
size: 18,
),
),
),
const SizedBox(
width: 5,
),
Expanded(
child: AutoSizeText(
filename,
style: Theme.of(context).textTheme.bodySmall,
minFontSize: 6,
),
)
],
),
),
);
}
}

View File

@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
class SmallSpinner extends StatelessWidget {
final Color? color;
const SmallSpinner({super.key, this.color});
@override
Widget build(BuildContext context) {
return SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 3,
color: color ?? Colors.white,
),
);
}
}

490
pubspec.lock Normal file
View File

@ -0,0 +1,490 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_flutterfire_internals:
dependency: transitive
description:
name: _flutterfire_internals
sha256: "5534e701a2c505fed1f0799e652dd6ae23bd4d2c4cf797220e5ced5764a7c1c2"
url: "https://pub.dev"
source: hosted
version: "1.3.44"
async:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.11.0"
auto_size_text:
dependency: "direct main"
description:
name: auto_size_text
sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
bot_toast:
dependency: "direct main"
description:
name: bot_toast
sha256: "6b93030a99a98335b8827ecd83021e92e885ffc61d261d3825ffdecdd17f3bdf"
url: "https://pub.dev"
source: hosted
version: "4.1.3"
characters:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
clock:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.1"
cloud_firestore:
dependency: "direct main"
description:
name: cloud_firestore
sha256: bdc7607e9169ee3ce736bbbe6a81c2a6cb15c41379346b74f77f8e641211a17f
url: "https://pub.dev"
source: hosted
version: "5.4.4"
cloud_firestore_platform_interface:
dependency: transitive
description:
name: cloud_firestore_platform_interface
sha256: "884fa34c6be2d9c7c1f4af86f90f36c0a3b3afef585a12b350a5d15368e7ec7a"
url: "https://pub.dev"
source: hosted
version: "6.4.3"
cloud_firestore_web:
dependency: transitive
description:
name: cloud_firestore_web
sha256: "6e621bbcc999f32db0bc6bfcb18d9991617ec20f8d6bf51b6a1571f5c324fafd"
url: "https://pub.dev"
source: hosted
version: "4.3.2"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.18.0"
csslib:
dependency: transitive
description:
name: csslib
sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
dio:
dependency: transitive
description:
name: dio
sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260"
url: "https://pub.dev"
source: hosted
version: "5.7.0"
dio_web_adapter:
dependency: transitive
description:
name: dio_web_adapter
sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
file_saver:
dependency: "direct main"
description:
name: file_saver
sha256: "017a127de686af2d2fbbd64afea97052d95f2a0f87d19d25b87e097407bf9c1e"
url: "https://pub.dev"
source: hosted
version: "0.2.14"
firebase_auth:
dependency: "direct main"
description:
name: firebase_auth
sha256: d453acec0d958ba0e25d41a9901b32cb77d1535766903dea7a61b2788c304596
url: "https://pub.dev"
source: hosted
version: "5.3.1"
firebase_auth_platform_interface:
dependency: transitive
description:
name: firebase_auth_platform_interface
sha256: "78966c2ef774f5bf2a8381a307222867e9ece3509110500f7a138c115926aa65"
url: "https://pub.dev"
source: hosted
version: "7.4.7"
firebase_auth_web:
dependency: transitive
description:
name: firebase_auth_web
sha256: "77ad3b252badedd3f08dfa21a4c7fe244be96c6da3a4067f253b13ea5d32424c"
url: "https://pub.dev"
source: hosted
version: "5.13.2"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
sha256: "51dfe2fbf3a984787a2e7b8592f2f05c986bfedd6fdacea3f9e0a7beb334de96"
url: "https://pub.dev"
source: hosted
version: "3.6.0"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
sha256: e30da58198a6d4b49d5bce4e852f985c32cb10db329ebef9473db2b9f09ce810
url: "https://pub.dev"
source: hosted
version: "5.3.0"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
sha256: f967a7138f5d2ffb1ce15950e2a382924239eaa521150a8f144af34e68b3b3e5
url: "https://pub.dev"
source: hosted
version: "2.18.1"
firebase_storage:
dependency: "direct main"
description:
name: firebase_storage
sha256: "8a8a21f3a359129a1257e2e77ece1de9678f40e43876635b3d411388ee388729"
url: "https://pub.dev"
source: hosted
version: "12.3.2"
firebase_storage_platform_interface:
dependency: transitive
description:
name: firebase_storage_platform_interface
sha256: "462621bbdb5ab496518aa0f4785cb6db87763d5f1063aa228e1f65562937af1d"
url: "https://pub.dev"
source: hosted
version: "5.1.31"
firebase_storage_web:
dependency: transitive
description:
name: firebase_storage_web
sha256: "40c52d5585ce63659b4b698fee0d47412ce499392ae3edf69c8e6141c22daf9a"
url: "https://pub.dev"
source: hosted
version: "3.10.2"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
font_awesome_flutter:
dependency: "direct main"
description:
name: font_awesome_flutter
sha256: "275ff26905134bcb59417cf60ad979136f1f8257f2f449914b2c3e05bbb4cd6f"
url: "https://pub.dev"
source: hosted
version: "10.7.0"
html:
dependency: "direct main"
description:
name: html
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
url: "https://pub.dev"
source: hosted
version: "0.15.4"
http:
dependency: transitive
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev"
source: hosted
version: "1.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
lints:
dependency: transitive
description:
name: lints
sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev"
source: hosted
version: "1.15.0"
path:
dependency: transitive
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
path_provider:
dependency: transitive
description:
name: path_provider
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
url: "https://pub.dev"
source: hosted
version: "2.1.4"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: f7544c346a0742aee1450f9e5c0f5269d7c602b9c95fdbcd9fb8f5b1df13b1cc
url: "https://pub.dev"
source: hosted
version: "2.2.11"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
url: "https://pub.dev"
source: hosted
version: "2.4.0"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev"
source: hosted
version: "2.3.0"
platform:
dependency: transitive
description:
name: platform
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
url: "https://pub.dev"
source: hosted
version: "3.1.5"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.1.8"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.2"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
url: "https://pub.dev"
source: hosted
version: "14.2.5"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev"
source: hosted
version: "1.1.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
sdks:
dart: ">=3.5.2 <4.0.0"
flutter: ">=3.24.0"

108
pubspec.yaml Normal file
View File

@ -0,0 +1,108 @@
name: baligh_dashboard
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1
environment:
sdk: ^3.5.2
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
auto_size_text: ^3.0.0
font_awesome_flutter: ^10.7.0
firebase_core: ^3.6.0
firebase_auth: ^5.3.1
cloud_firestore: ^5.4.3
bot_toast: ^4.1.3
firebase_storage: ^12.3.2
file_saver: ^0.2.14
html: ^0.15.4
dev_dependencies:
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^4.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/to/asset-from-package
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
fonts:
- family: Cairo
fonts:
- asset: assets/fonts/Cairo-Light.ttf
weight: 300
- family: Cairo
fonts:
- asset: assets/fonts/Cairo-Regular.ttf
weight: 400
- family: Cairo
fonts:
- asset: assets/fonts/Cairo-Medium.ttf
weight: 500
- family: Cairo
fonts:
- asset: assets/fonts/Cairo-SemiBold.ttf
weight: 600
- family: Cairo
fonts:
- asset: assets/fonts/Cairo-Bold.ttf
weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package

30
test/widget_test.dart Normal file
View File

@ -0,0 +1,30 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:baligh_dashboard/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}

BIN
web/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

BIN
web/icons/Icon-192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
web/icons/Icon-512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

38
web/index.html Normal file
View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="baligh_dashboard">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>baligh_dashboard</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<script src="flutter_bootstrap.js" async></script>
</body>
</html>

35
web/manifest.json Normal file
View File

@ -0,0 +1,35 @@
{
"name": "baligh_dashboard",
"short_name": "baligh_dashboard",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "A new Flutter project.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "icons/Icon-maskable-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "icons/Icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}