Professional Documents
Culture Documents
Final Project cbc7 Model Temer22
Final Project cbc7 Model Temer22
GEO-LOCALIZATION OF LOST
CHILDREN USING IOT
Graduation Project
Report, Part – 2
Submitted for the fulfillment of
bachelor’s degree requirements
Information Technology
CCIS, PNU
Riyadh, KSA
2021 – 2022
Submitted by:
2|Page
Table of Content
Acknowledgment ____________________________________ 3
Abstract ___________________________________________ 3
Keyword __________________________________________ 3
Chapter 1: Introduction ______________________________ 3
1.1 Introduction _______________________________________ 4
3|Page
2.2 Similarity Methods __________________________________ 7
2.3 Proposed & Similar System Comparison _________________ 4
3.2.1.2 Police___________________________________________ 8
3.2.1.4 Phone___________________________________________ 8
4|Page
3.7.2 Sequence Diagram for (Police) __________________________ 5
6.3.2 Child_______________________________________________ 8
Conclusions _______________________________________ 7
7.1 Conclusions _______________________________________ 8
6|Page
7.2 Future Work _______________________________________ 8
References _________________________________________ 7
7|Page
Table of Figure
8|Page
5.6 Figure of Children (E/A)_________________________________ 7
9|Page
Acknowledgment
The completion of this study could not have been possible without the expertise of
(Dr. Manal Ayadi) our beloved thesis adviser, she has been sitting on our panel and
taking the time to read our thesis and share her thought about it. We would also like
to thank our university who gave us the golden opportunity to build this application.
Finally, we would like to thank our families, because without them none of this would
indeed be possible.
Abstract
The graduation project will be able to help the family after God in protecting their
child from being lost, and we are hoping that it will make the child feel safer by
wearing the watch, it will also help police with tracking their location.
In this project through analyzing the main problem, which is a missing child, with
reading a lot of articles that are related to our project and have used similar methods,
we have found the best solution which is designing an application that is connected to
a bracelet to localize child location. So, if we want to achieve such kind of system, we
specified our requirements from functional to non-functional. At the end of the
graduation project report, we have designed a prototype version of our application
that will demonstrate the interface and easiness, the usefulness of using the
application.
Keyword
10 | P a g e
Chapter 1: Introduction
11 | P a g e
1.1 Introduction:
The phenomenon of missing children under the age of 18 has been reported
worldwide and is becoming a huge global concern. It has been estimated that at least
eight (8) million children go missing each year (International Centre for Missing and
Exploited Children). [1]
Our graduation project is a keystone of geo-localization using IOT, so “the internet of
things” refers to using mechanical and digital machines, objects, animals, or people.
IOT is a type of network connect to anything with the Internet based on stipulated
protocols through information sensing equipment to conduct information exchange
and communications network without requiring human-to-human or human-to-
computer interaction, in order, to achieve smart recognitions, positioning, tracking,
monitoring, and administration.
The main objective of our project is to develop an application that targets the lost
children with the help of IOT definition throughout a chip connected to an application
and developing a system that is concerned with finding the specific location of the
child so it will help the families to find them before it is too late.
12 | P a g e
1.4 Project Domain and Limitation:
1.4.1 Domain:
The project domain targets newborn children to legal age, it’s used by their family,
the boundaries of the application will be around Saudi Arabia and maybe after we
publish it, we will try to develop it in another systematic way so it can be solid all
around the world.
The delimitation of system, interface, rules. The topic we want to consider during
the development (that map should be updated frequently if the chip stops sending a
signal the family should be notified by the application, ease to use), and some that
we will not keep an eye on (how many family members can use the application, the
icons places).
1.4.2 Limitation:
The project boundaries can split into two, systematic problems or personal
problems.
1.4.2.1 Personal problem is related to the user’s usage of the application, the
phone could be out of battery when the kid happens to be lost. It could also
reach the extent of the breakage of the phone that holds the chip information
of the lost child, the misuse of the bracelet may cause many damages to it, the
child could take off the bracelet, which will cause them to lose the bracelet.
1.4.2.2 Systematic problem is related to the outside world and/or the system, for
example, when the child is lost there could be problems with the signals which
will affect the speed of locating the child, and the system should be
maintained (as all systems do).
13 | P a g e
1.5 Waterfall Model:
1.5.2 System Design: the requirement specifications from the first phase are studied
in this phase and the system design is prepared. This system design helps in
specifying hardware and system requirements and helps in defining the overall
system architecture.
1.5.3 Implementation: with inputs from the system design, the system is first
developed in small programs called units, which are integrated with the next phase.
Each unit is developed and tested for its functionality, which is referred to as Unit
Testing.
1.5.4 Testing: all the units developed in the implementation phase are integrated into
a system after testing each unit. Post integration the entire system is tested for any
faults and failures.
1.5.5 Maintenance: after the successful completion of the testing phase, we will
release the “GEO-localization of lost children using IOT application” there are some
issues that come up in the client environment. To fix those issues, patches are
released. Also, to enhance the product some better versions are released. Maintenance
is done to deliver these changes in the customer environment. [3]
14 | P a g e
Chapter 2: Background
Information and Related Work
15 | P a g e
2.1 What is the Internet Of Things (IOT)?
In general, IOT encompasses everything connected to the internet. But it is increasingly
being used to defines objects that communicate with each other. Simple it is made up of
connected devices to gather information, analyse it and create action. So, it is about
network, device, data. So, the purpose of IOT is to connect and exchange data with
other devices and systems over the internet.
16 | P a g e
2.2 Similarity System
i. Pawscout
A digital pet tag and tracker for dogs and cats with social GPS and BLE
connectivity, which works with a connected mobile app and a worldwide tracking
community to keep pets safe. It is attached to the pet collar. [5]
Features:
- Smart pet tracking
- Online community
- Virtual leash
- Detailed digital profile
- Social GPS: finding the lost pets easily
ii. GreenIQ
Control your garden’s lawn irrigation & lighting from anywhere. With GreenIQ
smart sprinklers controller, you will save up to 50% on your outdoor water bills.
[6]
Features:
- Control irrigation saves water
- Connect to leading home automation platforms
- Add accessories to your smart garden hub
Features:
- Play a sound: play a sound on a lost device to help you find it.
- Mark a device as lost: use Lost Mode to protect a lost device so that others cannot
access your personal information.
- Erase a device: remotely erase all your personal information from the device.
17 | P a g e
iv. Google Map
Is a web mapping service developed by, the maps service can be used for your
location determination, users can choose whether they are going by foot, by bike,
by public transport or by car.
Features:
- Directions for driver
- Search for shops, restaurants
- Provides you with option roads that have a similar estimated time of arrival
(ETA)
- Rating of places
- Delays & disruption route comparison
v. Uber
In cities where Uber operates, use the uber app to request a ride. When a nearby
driver accepts your request, your app displays an estimated time of arrival for the
driver heading to your pickup location. Your app notifies you when the driver is
about to arrive.
Features:
- Scheduled Rides
- your driver information
- Real-time tracking of your driver
- Driver review and payment
- Multiple payment methods
Language Location
App Name Ease of Use Tracking Time-Saving
Arb / Eng Alert
GOE-localization of
✓/✓ ✓ ✓ ✓ ✓
lost children using IOT
Pawscout ✗/✓ ✓ ✓ ✓ ✓
GreenIQ ✗/✓ ✓ ✓
Find My iPhone ✗/✓ ✓ ✓ ✓
Google Maps ✓/✓ ✓ ✓
Uber ✓/✓ ✓ ✓ ✓ ✓
18 | P a g e
2.4 IOT Platforms Free & Not Free
i. Axonize
Has developed a disruptive, multi-app architecture, purpose-built for
service providers, and end customers, that enables the deployment of fully
customized smart solutions across all applications, verticals, and device
types. [8]
ii. FogWing
Is the comprehensive industrial available as a service on a subscription
basis, is a no-code platform. It can help to achieve industrial automation;
the user may build custom IOT solutions to prebuilt IOT applications. [8]
iii. UpSwift.io
UpSwift.io provides a plug play device management platform for IOT and
Linux devices. users can deploy OTA. In less than 60 seconds users can be
able to connect any type of Linux or IOT device. [8]
i. Webnms
A tool that strives to bring simplicity to the IOT platform through easy
integrations, smooth onboardings, and a dedicated team of professionals.
Whether you are in the healthcare, manufacturing, or agriculture space
Webnms can help deploy IOT solutions throughout your business. [9]
ii. ThingWorx
Is an IOT platform owned by PTC, a leader in industrial business
solutions. ThingWorx leverages this industry expertise with IOT
technology to create solutions that are tailored to industrial and energy
solutions.
With ThingWorx you can use IOT sensors to monitor equipment in the
supply chain, and ultimately reduce costs and predict maintenance
requests based on sensor information. [9]
19 | P a g e
Chapter 3: System Analysis
20 | P a g e
3.1 Requirements Specification
We have tried many ways to gather information to specify our project requirements
such as:
3.1.1 Searching:
We searched for similar systems that use the same method as our project and
came up with several ways of how to distinguish our project from them.
3.1.2 Survey and Polls:
We’ve used these two methods to know the population thoughts and opinion of
our project polls are questions that do not require detailed responses they are the
only question that has one answer, they are antibiosis of a survey because survey
requires detailed extension feedback, also there must be text comment so every
person will have their own opinion.
ْ؟ٚتشأٌه ٌّارا وصٍش ِٓ األطفاي ٌفمذ ٌُٙعذَ ِراتعح اطفاٚ ً٘ اّ٘اي األ-
ً وصشج حشوح اٌطفً فً األِاوٓ اٌعاِح لذ ٌسثة فً ضٍاع اٌطف-
ْ خثشُٚ تذٍُٙ تعٍذا ً عٓ عائٙر٘اتٚ ٌعذَ اٌرشوٍض تاألِاوٓ اٌعاِح-
َاالعرّاد اٌراَ عٍى اٌخذ- االدسانٚ ًعٌٛعذَ اٚ ي األطفايٛ تسثة فض-
ْٛستّا ٌى- ٌُٙحشورٚ ٌُٙٛ ٌسشعح شذ أرثاٖ األطفاي ٌألشٍاء ِٓ ح-
تسثة أخشاط اٌطفً تاٌٍعةٚتسة ظشأج اٌطفً أ
21 | P a g e
Did you ever helped other families
with finding their missing child?
22 | P a g e
Which feature that you would look Some of the received answers:
?up to in the bracelet or application )تعض األظٛتح اٌرً ٚصٍرٕا):
ِا اٌٍّضج اٌرً ذٛد\ٌٓ تأْ ذرٛاظذ فً اٌسٛاس أٚ -سٍىٕ٘ ْٛان احرّاٌٍٗ وثٍشٖ فً ِعشفٗ ِىاْ اٌطفً لثً فٛاخ االٚاْ
اٌرطثٍك؟ -ذحذٌذ ِٛلع اٌطفً
-عٓ طشٌك ذرثعً ٌٗ تاسرخذاَ اٌعٛاي ِٚعشفح وً ِىاْ ٌز٘ة اٌٍٗ
-ترحذٌذ ِىأٗ ٚعذَ ضٍاع اٌٛلد فً اٌثحس تأِاوٓ اٌرً ال ٌرٛاظذ تٙا
ٌ -ى ْٛسٛاس ِرصً تاٌٛاٌذٌٓ
-ذرثع حشوح اٌطفً عٓ طشٌك اٌعٛاي
-عٓ طشٌك اٌشٍٔٓ إرا اترعذ اٌطفً عٓ االَ
-ستطٗ ِع االً٘ تاسرخذاَ ٚسائً اٌرمٍٕح اٌحذٌصح
-تشٔاِط ذرثع اٌسٛاس
-عٓ طشٌك ششٌحح ذحذد ِىاْ اٌطفً
-تأسساي ذٕثٍٗ ٌٍسٛاس اٌزي ذّرٍىٗ االَ
-اٌعصٛس عٍٍ ُٙعٓ طشٌك GPS
-تأحذاز صٛخ أ ٚإضاءج ٘ٚضاص
ٌٛ -ضع تٗ سلُ ظٛاي االَ ٚاالب ٌٚفضً اٌضا ٚضع ساتظ ٌّٛلع إٌّضي
-ترحذٌذ ِٛلعٗ حرى اْ واْ خاسض ٔطاق اٌشثىح
-ششط اْ ال ٌى ْٛس ًٙاٌخٍع؛ ٚال ٌرأشش تاٌّاء؛ ٌصثح ٌعًّ عٓ طشٌك
اٌرصفٍش فً ظٛاًٌ حاي اترعذ عًٕ ِسافح ِرش
-إرا اترعذ اٌطفً ٌٕثٗ االً٘ عثش اٌرطثٍك فً اٌعٛاي
-عثاسج عٓ حساط ٌشسً اشعاساخ تّىاْ اٌطفً
-تحفظ اٌٛلد اٌضائع فاٌثحس حٍس ٌرُ ذحذٌذ اٌّٛلع اٌّٛظٛد فٍٗ ِثاششج
23 | P a g e
3.2 Requirement Analysis:
3.2.1 Functional Requirements:
Functional requirements specify how a system should work and behave so it is
a set of the list that the system must provide to the end-user.
3.2.1.2 Police:
- The police shall be able to log in
- The police shall be able to post an announcement
The police shall be able to see the location of the child
The police shall be able to know how long the child been missing
The police shall be able to log out
3.2.1.3 Child:
- The child shall be able to send an alert to the parent
- The child shall be able to talk to the parents through a (walkie-
talkie)
3.2.1.4 Bracelet:
- The bracelet shall be able to sense the location of the child
- The bracelet shall be able to send alerts to the Family & Guardian
- The bracelet shall be able to make the child and his Family&
Guardian talk through (walkie-talkie)
24 | P a g e
3.3 Non-Functional Requirements:
Defines system attributes, they serve the system as a constraints restriction on the
designed system. They ensure the useability and effectiveness of the entire system.
Non-Functional requirements are persistent and constraints. In other words, it focuses
on user expectations of the system.
Non-Functional
The system response time for user action should take
Performance
less than a second.
Availability The system will be available at any time anywhere.
The system will ensure that there is no unauthorized
Security access to the application and only the allowed parent
can access their account.
The ability of the application system to recover from a
Recoverability failure in the system and go back to being fully
operational within less than 5 minutes.
The system is user-friendly and easy to use for
Usability
programmers and non-programmer people.
The system can face and manage a high number of
Scalability
users.
The application system should be free of mistakes and
Accuracy share with the parents the specific location of their
child.
25 | P a g e
3.4 Hardware and software requirement:
3.4.1 Hardware Requirements:
o Bracelet:
To connect it with the application and start tracking your child's location.
o Wi-Fi:
So, the application can run on your mobile phone.
o Mobile Phone:
2GB capacity is enough for downloading, testing, and using the system.
o Bluetooth:
To connect the bracelet to the application.
o Apple IOS:
The operating system runs apple’s line.
- iPhone:
Requires IOS 14.4.1 or later.
- iPad:
Requires IOS 14.4.1 or later.
- Apple Watch:
Requires watch OS 2.2 or later.
o Android:
System based on a modified version of the Linux kernel.
- Galaxy:
Requires 11.0.0 version or later.
- Tablet:
Requires 11.0.0 version or later.
- Galaxy Watch:
Requires 1.012 version or later.
26 | P a g e
3.5 Use Case Diagram:
The use cases represent only the functional requirements of a system.
We have used it to summarize some of the relationships between use cases, actors,
and systems.
27 | P a g e
3.6 Use Case Description:
Text-based narrative of a functionality comprised of detailed, step-by-step interaction
between the actor and the system. It describes the outcomes of an action taken to
accomplish a specific goal.
28 | P a g e
Use Case Talk to Parents
Actors Child
This use case allows the user (child) to
Description speak to their parents using a walkie-
talkie in case of no signal/internet.
29 | P a g e
3.7 Sequence Diagram:
30 | P a g e
3.7.2 Sequence Diagram for (Police):
3.8
Class Diagram:
31 | P a g e
The class diagram is the main building block of object-oriented modeling, it describes
the structure of the system by showing the system classes, attributes, methods, and the
relation between classes.
32 | P a g e
Chapter 4: System Design
4.1System Architecture
It shows the types of tiers, and each tier is maintained and developed independently.
33 | P a g e
4.1.1 Application Layer
The top level of the application layer is the user interface. For our project, the
users will be (Family & Gradient) they will do the advanced work on the
application. They can track the child or share their child location with the police.
Of course, the parent can add their child information, and delete the information if
unauthorized access happens.
Child information is stored and can be retrieved from the database. The
information can be edited or removed.
The network layer in our project will be the main root because it will build the
connection between the bracelet and the application and will make sure that there
is a connection between the application and policy.
The bracelet contains sensors that are used to sense the location of the child, the
bracelet can modify the child location on the map through the wireless
connection.
34 | P a g e
Figure 4.2.1: GEO-localization for lost children using IOT
- GEO-localization for lost children using IOT: has 5 tables (Child Database,
Family/Guardian, Police Database, Report Database, Bracelet Database).
- Family Database: has 5 fields (User ID, User Name, User Password, User Address,
User Mobile).
- Police Database: has 6 fields (User ID, User Dep ID, User Name, User Password,
User Mobile, User Address).
35 | P a g e
Figure 4.2.4: Child Database
- Child Database: has 3 fields (User ID, User Name, User DOB).
- Report Database: has 4 fields (Report ID, Date, Report Description, Report Status).
36 | P a g e
4.3 User Interface Design
37 | P a g e
4.3.2 Log-in Page (Arabic, English):
- Log-in Page: the user must-up the form contains (National ID/ Iqama ID Number,
Password).
38 | P a g e
4.3.3 Sign-in Page (Arabic, English):
39 | P a g e
Figure 4.3.4: Home Page
- Home Page: in this page family can (Check Existing Child Location, Add Child,
Certify Bracelet Number, Personal Information).
- My Profile Page: in this page, the user can change account sitting.
41 | P a g e
Figure 4.3.6: Alert Notification Page
- Alert Notification Page: the family can see their child's location who has sent them
an alert message.
42 | P a g e
4.3.7 Reports Page:
- Report Page: the family can see their child's report status.
43 | P a g e
Figure 4.3.8: New Report Page
- New Report: the family can open a new report to the police if they have lost their
child.
44 | P a g e
Chapter 5: Implementation
5.1 Introduction
45 | P a g e
In this chapter, we will describe the implementation of the system including
implementation requirements, the fragment of the main functions in the system, and I/O
screens.
The following are the software and hardware requirements, which offer the suitable
feature to meet the system needs during the implementation stage.
Software Usage
Database Firebase
Hardware Usage
RAM 8 GB Memory
Device HP PAVILION
46 | P a g e
5.3 Implementation Details
This section will introduce the implementation phase of the GP management system in a
short view using the hardware and software mentioned in the requirement section.
The graduation project was written by Dart, Flutter, the Android Studio programming
language for both IOS and Android.
The database is used to store all tables and records Firebase.
- Android Studio:
- Firebase:
- Dart, Flutter:
Dart is the programming language used to code Flutter apps. Dart looks a bit like
C and is an object-oriented programming language. So, if you prefer the C
languages or Java, Dart is the one for you, and you'll likely be proficient in it.
Dart is not only used for mobile app development but is a programming language.
47 | P a g e
Add Child:
48 | P a g e
String imgUrl = await event.ref.getDownloadURL();
var child_id = randomNum();
List list = Pref.get_random_list();
do {
if (list.contains(child_id)) {
child_id = randomNum();}
else {
break; }}
while (true);
Child child = new Child(
child_id, name, imgUrl, Database.loggedUserId());
Database.children().doc(child_id).set(child.toMap()).then((
value) async {
await progressDialog.hide();
Navigator.pop(context);
}).catchError((error) {
progressDialog.hide();
FA.showErrorMsg(context, "Server error".tr());
}); }
}).onError((error) {
progressDialog.hide();
FA.showErrorMsg(context, "Server error".tr());
});}}}
@override
void initState() {
super.initState(); }
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [
SystemUiOverlay.top ]);
return Scaffold(
appBar: AppBar(title: Text(
"Add Child".tr(), style: DesignHelper.barTitleStyle,)),
body: Form(key: formState,
child: Container(alignment: Alignment.topCenter,
width: double.infinity,
child: SingleChildScrollView(
scrollDirection: Axis.vertical, child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 30),
Container(
49 | P a g e
margin: EdgeInsets.symmetric(horizontal: 20),
child: TextFormField(
cursorColor: Theme
.of(context)
.primaryColor,
style: DesignHelper.fieldStyle,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp("[a-zA-Z\\s]"))],
keyboardType: TextInputType.name,
decoration: InputDecoration(
labelText: "Child name".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon: Icon(Icons.person, color:
Theme
.of(context)
.primaryColor),
enabledBorder: DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder:
DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper
.fieldErrorBorder
),
validator: (text) {
if (text!.trim().isEmpty) {
return "Full name".tr() + " " +
"is required".tr();0}
return null;},
onSaved: (text) {
name = text.toString();
},)),
SizedBox(height: 30),
GestureDetector(child: Container(
margin: EdgeInsets.symmetric(horizontal: 20),
width: double.infinity,
height: 200,
padding: EdgeInsets.symmetric(horizontal: 10),
child: image.path == "" ? Container(
alignment: Alignment.center,
child: Row(mainAxisAlignment:
MainAxisAlignment
.center, children: [
50 | P a g e
Icon(Icons.upload, color:
MyColors.primary,),
Text(
"Upload child image".tr(), style:
TextStyle(
color: MyColors.gray,
fontWeight: FontWeight.bold,
fontSize: 18
), textAlign: TextAlign.center)
])) : Image.file(image,
fit: BoxFit.fill)
), onTap: () async {
FilePickerResult? result = await
FilePicker.platform
.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'png'], );
if (result != null) {
PlatformFile file = result.files.first;
setState(() {
fileName = file.name;
image = new File(file.path.toString());
});}},),
SizedBox(height: 35),
SizedBox(width: DesignHelper.buttonWidth2,
height: DesignHelper.buttonHeight2,
child:
ElevatedButton(onPressed: () {
submit();
}, child: Text("Add").tr(),
style: DesignHelper.buttonStyle,
)),
SizedBox(height: 15),],))))); }
String randomNum() {
var rng = new Random();
return (rng.nextInt(900000) + 100000).toString();}}
Child Information:
51 | P a g e
class ChildInfo extends StatefulWidget {
@override
State<StatefulWidget> createState() =>ChildInfoState();}
class ChildInfoState extends State<ChildInfo>{
late Child child;
@override
void initState(){
super.initState();}
@override
Widget build(BuildContext context) {
final Map<String, Object> receivedData =
ModalRoute.of(context)!.settings.arguments as Map<String, Object> ;
child = receivedData['child'] as Child;
return Scaffold(
appBar: AppBar(title: Text("Child Info".tr(),style:
DesignHelper.barTitleStyle),actions:menu1()),
body:Container(
child:FutureBuilder(
future: Database.children().doc(child.child_id).get(),
builder: (context,AsyncSnapshot<DocumentSnapshot<Object?>>
snapshot) {
switch (snapshot.connectionState) {
52 | P a g e
Text("Child ID".tr()+" : ",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 17)),
Text("${child.child_id}",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
fontSize: 17))]),),
SizedBox(height: 20),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
Text("Child Status".tr()+" : ",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 17)),
Text("${(child.is_online)?"Online".tr():"Offline".tr()}",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
fontSize: 17))]),
),
SizedBox(height: 40),
SizedBox(width: DesignHelper.buttonWidth2,
height: DesignHelper.buttonHeight2,
child:
ElevatedButton(onPressed: () {
track();
}, child: Text("Track child").tr(),
style: DesignHelper.buttonStyle,
)),])));}
else{
return SizedBox.shrink();}
};})));}
track() async {
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
FA.showErrorMsg(context, "Please enable location".tr());}
else {
LocationPermission permission;
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
FA.showErrorMsg(context, "Please grant storage
permission").tr();
return; }
return; }
if (permission == LocationPermission.deniedForever) {
FA.showInfoMsg(context, "Please grant location permission from
settings").tr();
openAppSettings();
53 | P a g e
return;
}
if (await FA.isInternetAvailable())
Navigator.of(context).pushNamed("child_map", arguments:
{"child": child});
else
FA.showErrorMsg(context, "No internet").tr();}}
menu1() {
return [
PopupMenuButton<int>(
icon: Icon(Icons.person),
itemBuilder: (BuildContext context) => <PopupMenuItem<int>>[
new PopupMenuItem<int>(
value: 0, child: new Text('Send report'.tr())),
new PopupMenuItem<int>(
value: 1, child: new Text('Update name'.tr())),
new PopupMenuItem<int>(
value: 2, child: new Text('Update image'.tr())),
new PopupMenuItem<int>(
value: 3, child: new Text('Delete child'.tr()))],
onSelected: (int value) {
switch(value){
case 0:
send_report();
break;
case 1:
update_name();
break;
case 2:
update_image();
break;
case 3:
delete_child();
break; }})];}
send_report(){
Navigator.of(context).pushNamed("send_report",arguments:
{"child":child});}
update_name(){
Navigator.of(context).pushReplacementNamed("update_child_name",argument
s: {"child":child});}
update_image(){
Navigator.of(context).pushReplacementNamed("update_child_image",argumen
ts: {"child":child});}
delete_child(){
AwesomeDialog(
context: context,
title: "Are you sure delete child?".tr(),
isDense: true,
btnCancelText: "no".tr(),
btnCancelOnPress: (){},
btnCancelColor: Colors.blue,
btnOkText: "yes".tr(),
btnOkColor: Colors.blue,
dismissOnBackKeyPress: false,
dismissOnTouchOutside: false,
customHeader: Column(
54 | P a g e
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 20),
Icon(Icons.warning,color: Colors.red,size: 55),],),
btnOkOnPress: (){
delete();
}, )..show();}
delete() async {
final ProgressDialog progressDialog = ProgressDialog(
context, isDismissible: false);
progressDialog.style(
message: 'Delete child'.tr() + "....",
messageTextStyle: TextStyle(
color: Theme
.of(context)
.primaryColor, fontSize: 18.0, fontWeight:
FontWeight.normal),
);
if (!await FA.isInternetAvailable()) {
FA.showErrorMsg(context, "No internet");
}
else {
progressDialog.show();
FirebaseStorage.instance.refFromURL(child.imgUrl).delete().then((value)
{
Database.children().doc(child.child_id).delete().then((value){
progressDialog.hide();
Fluttertoast.showToast(
msg: "Delete done".tr(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: MyColors.primary,
textColor: Colors.white,
fontSize: 15.0 );
if(Navigator.canPop(context)){
Navigator.pop(context);}
else{
SystemNavigator.pop(); }
}).catchError((error) async {
progressDialog.hide();
FA.showErrorMsg(context, "Server error".tr());
});
}).catchError((error) async {
progressDialog.hide();
FA.showErrorMsg(context, "Server error".tr());
});}}}
Child Map:
55 | P a g e
class ChildMap extends StatefulWidget {
@override
State<StatefulWidget> createState() =>ChildMapState();}
class ChildMapState extends State<ChildMap> {
late GoogleMapController gmc;
Child child = new Child("","","","");
late LatLng current_latLang;
Set<Marker> markers = {};
late StreamSubscription<Position> ps;
static final CameraPosition defaultPosition = CameraPosition(
target: LatLng(0, 0),
tilt: 59,
zoom: 19.151926040649414, );
void mapSettings() async {
final ProgressDialog progressDialog = ProgressDialog(
context, isDismissible: false);
progressDialog.style(
message: 'Loading map...',
messageTextStyle: TextStyle(
color: MyColors.primary,
fontSize: 18.0,
fontWeight: FontWeight.normal), );
// progressDialog.show();
Position position = await Geolocator.getCurrentPosition();
setState(() {
final Map<String, Object> receivedData = ModalRoute
.of(context)!
.settings
.arguments as Map<String, Object>;
child = receivedData['child'] as Child;
DocumentReference<Object?> reference =
Database.children().doc(child.name==""?"1":child.child_id);
reference.snapshots().listen((snapshot) {
if(snapshot.exists){
Child child = Child.fromMap(snapshot.data() as
Map<String,dynamic>);
childListener(child);
}});
current_latLang = LatLng(position.latitude, position.longitude);
gmc.moveCamera(CameraUpdate.newLatLng(current_latLang));
Marker m1 = Marker(markerId: MarkerId("child"),
position: current_latLang
,
icon:
BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueGreen));
markers.add(m1);});
//progressDialog.hide();}
childListener(Child child){
if(child.is_online){
childMove(child.lat,child.lng);}
else{
Fluttertoast.showToast(
msg: "Child is offline".tr(),
56 | P a g e
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 2,
backgroundColor: MyColors.primary,
textColor: Colors.white,
fontSize: 16.0 );
Navigator.pop(context);} }
@override
void initState() {
super.initState();
Future.delayed(Duration.zero, () {
mapSettings();
});}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(title: Text(
"Track child".tr(), style: DesignHelper.barTitleStyle,),),
body: Container(
child: GoogleMap(
mapType: MapType.normal,
zoomControlsEnabled: false,
myLocationEnabled: false,
initialCameraPosition: defaultPosition,
markers: markers,
onMapCreated: (GoogleMapController controller) {
gmc = controller; },),), );}
Future<void> childMove(latitude, longitude) async {
gmc.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
target: new LatLng(latitude, longitude),
tilt: 59,
zoom: 19.151926040649414,)));
setState(() {
Marker marker = markers.firstWhere((marker) =>
marker.markerId.value == "child");
markers.remove(marker);
markers.add(
Marker(markerId: MarkerId("child"), position: LatLng(latitude,
longitude), icon:
BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueGreen),
infoWindow: InfoWindow(title: child.name)),);});}}
Children:
57 | P a g e
class Children extends StatefulWidget {
@override
State<StatefulWidget> createState() =>ChildrenState();}
class ChildrenState extends State<Children>{
final Stream<QuerySnapshot> stream =
Database.children().orderBy("z_date_created",descending:
false).snapshots();
@override
void initState(){
super.initState();}
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays:[
SystemUiOverlay.top]);
return Scaffold (
body:StreamBuilder<QuerySnapshot>(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Center(child:Text("Server error").tr());}
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Container(
height: double.infinity,
child:Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Loading".tr()+"...."),
SizedBox(width: 30,),
CircularProgressIndicator()],));
default:
if(snapshot.hasData &&
snapshot.data!.docs.length==0){
return Center(child:Text("No Children").tr());}
else{
return Container(
child:
ListView.separated(
separatorBuilder:(context,i){
Child child = Child.fromMap(snapshot.data!.docs[i].data() as
Map<String,dynamic>);
if(child.user_id.toString().compareTo(Database.loggedUserId()) == 0) {
return Divider(thickness: 1,
color: MyColors.gray2,
height: 3,); }
else{
return SizedBox.shrink();}},
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
padding: EdgeInsets.symmetric(vertical: 5),
itemBuilder:(context,i){
Child child =
Child.fromMap(snapshot.data!.docs[i].data() as Map<String,dynamic>);
58 | P a g e
if(child.user_id.toString().compareTo(Database.loggedUserId()) == 0) {
return
Container(
padding:
EdgeInsets.symmetric(vertical: 25),
child: ListTile(
title: Text("${child.name}",
style: TextStyle(
color: Colors.black,
fontSize: 16)),
leading:
Image.network(child.imgUrl),
tileColor: Colors.white,
contentPadding:
EdgeInsets.symmetric(
horizontal: 7),
onTap: () {
Navigator.of(context).pushNamed("child_info",arguments:
{"child":child});},));}
else{
return SizedBox.shrink();}}));
return Text("");}}}));}
static add_child(context){
Navigator.of(context).pushNamed("add_child");
}}
Home:
59 | P a g e
class Home extends StatefulWidget {
@override
State<StatefulWidget> createState() =>HomeState();}
class HomeState extends State<Home> {
int selectedNav =0;
List<Widget> pages = [Children(),Reports(),Profile()];
var titles = ["My Children","Reports","My Profile"];
@override
void initState() {
super.initState();}
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays:[
SystemUiOverlay.top]);
return Scaffold(
appBar:AppBar(title:
Text("${titles[selectedNav]}".tr(),style:DesignHelper.barTitleStyle),
actions: selectedNav==0?menu1():selectedNav==2?menu2():menu3()
,automaticallyImplyLeading: false),
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.white,
selectedItemColor: Theme.of(context).primaryColor,
unselectedItemColor: Colors.grey,
currentIndex: selectedNav,
onTap: (index){
setState(() {
selectedNav = index;});
//Pref.set_navNumber(selectedNav);},
items:[
BottomNavigationBarItem(
icon: Icon(Icons.people),
label: "My Children".tr()),
BottomNavigationBarItem(
icon: Icon(Icons.insert_drive_file),
label: "Reports".tr()),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: "My Profile".tr() ),],),
body:pages.elementAt(selectedNav) );}
menu1() {
return [
IconButton(icon:Icon(Icons.add,color:
Colors.white,),onPressed:(){ChildrenState.add_child(context);}),]; }
menu2() {
return [
PopupMenuButton<int>(
icon: Icon(Icons.language),
itemBuilder: (BuildContext context) => <PopupMenuItem<int>>[
new PopupMenuItem<int>(
value: 0, child: new Text('Lang'.tr())), ],
onSelected: (int value) {
switch(value){
case 0:
setState((){
if(context.locale.languageCode ==
Lang.english.languageCode)
60 | P a g e
context.setLocale(Lang.arabic);
else
context.setLocale(Lang.english); });
break;}})
,IconButton(icon:Icon(Icons.power_settings_new,color:
Colors.white,),onPressed:logout),];}
menu3(){ }
logout(){
AwesomeDialog(
context: context,
title: "Do you want to sign out?".tr(),
isDense: true,
btnCancelText: "no".tr(),
btnCancelOnPress: (){},
btnCancelColor: Colors.blue,
btnOkText: "yes".tr(),
btnOkColor: Colors.blue,
dismissOnBackKeyPress: false,
dismissOnTouchOutside: false,
customHeader: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 20),
Icon(Icons.warning,color: Colors.red,size: 55),
],),
btnOkOnPress: (){
Database.logout();
Navigator.pushReplacementNamed(context,"intro");
},
)..show();}}
Log-In:
61 | P a g e
class Login extends StatefulWidget {
@override
State<StatefulWidget> createState() =>LoginState();}
class LoginState extends State<Login>{
late String email;
late String password;
GlobalKey<FormState> formState = new GlobalKey<FormState>();
submit() async {
var form = formState.currentState;
if(form!.validate()){
form.save();
final ProgressDialog progressDialog = ProgressDialog(
context, isDismissible: false);
progressDialog.style(
message: 'Login'.tr()+"....",
messageTextStyle: TextStyle(
color: Theme
.of(context)
.primaryColor, fontSize: 18.0, fontWeight:
FontWeight.normal),);
if (!await FA.isInternetAvailable()) {
FA.showErrorMsg(context, "No internet".tr());}
else {
progressDialog.show();
try {
await FirebaseAuth.instance
.signInWithEmailAndPassword(
email: email,
password: password );
progressDialog.hide();
Pref.set_isLogin(true);
Pref.set_email(email);
Navigator.pushReplacementNamed(context, "home");
} on FirebaseAuthException catch (e) {
progressDialog.hide();
FA.showErrorMsg(context, "Invalid email or
password").tr();}}}}
@override
void initState(){
super.initState();}
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
return Scaffold(
body:Form(key:formState,child:Container(alignment:Alignment.topCenter,w
idth:double.infinity,child:SingleChildScrollView(scrollDirection:
Axis.vertical,child:Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 10),
Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.symmetric(horizontal: 5),
62 | P a g e
child:Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(onPressed:(){
if (Navigator.canPop(context)) {
Navigator.pop(context);
} else {
SystemNavigator.pop();}
}, icon: Icon(Icons.arrow_back),iconSize: 38),
PopupMenuButton<int>(
icon: Icon(Icons.language),
iconSize: 36,
itemBuilder: (BuildContext context) =>
<PopupMenuItem<int>>[
new PopupMenuItem<int>(
value: 0, child: new Text('Lang'.tr())),
],
onSelected: (int value) {
switch(value){
case 0:
setState((){
if(context.locale.languageCode ==
Lang.english.languageCode)
context.setLocale(Lang.arabic);
else
context.setLocale(Lang.english); });
break;}}),]),),
Image(
image: AssetImage('images/logo.png',),
width: 150,
height: 120,),
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: MyColors.filedColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: "Email address".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.mail,color:MyColors.filedColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder ),
validator: (text){
if(text!.trim().isEmpty){
return "Email address".tr()+" "+"is
required".tr();}
if(! FA.isEmailValid(text)){
return "Invalid email".tr();}
return null; },
onSaved: (text){email=text.toString();},)),
63 | P a g e
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: MyColors.filedColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.visiblePassword,
obscureText: true,
decoration: InputDecoration(
labelText: "Password".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:Icon(Icons.lock,color:MyColors.filedColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder:
DesignHelper.fieldErrorBorder),
validator: (text){
if(text!.trim().isEmpty){
return "Password".tr()+" "+"is required".tr();}
return null; },
onSaved: (text){password=text.toString();},)),
SizedBox(height: 15),
Container(alignment:Alignment.center,
child:TextButton(onPressed: () {
Navigator.of(context).pushNamed("re_password"); },
child:Text("Forgot your
password?".tr(),style:Theme.of(context).textTheme.headline6)),),
SizedBox(height: 25),
SizedBox(width:DesignHelper.buttonWidth2,height:DesignHelper.buttonHeig
ht2,child:
ElevatedButton(onPressed: (){
submit();
}, child: Text("Login").tr(),
style: DesignHelper.buttonStyle,
)),
SizedBox(height: 15),
],)))));}}
Profile:
64 | P a g e
class Profile extends StatefulWidget {
@override
State<StatefulWidget> createState() =>ProfileState();}
class ProfileState extends State<Profile>{
late String email;
late String name;
late String phone;
late String address;
late Users user ;
GlobalKey<FormState> formState = new GlobalKey<FormState>();
submit() async {
var form = formState.currentState;
if(form!.validate()){
form.save();
final ProgressDialog progressDialog =
ProgressDialog(context,isDismissible: false);
progressDialog.style(
message: 'Save'.tr()+".....",
messageTextStyle: TextStyle(
color: Theme.of(context).primaryColor, fontSize: 18.0,
fontWeight: FontWeight.normal),
);
if(! await FA.isInternetAvailable()){
FA.showErrorMsg(context,"No internet".tr());}
else {
progressDialog.show();
user.name = name;
user.phone = phone;
user.address = address;
Database.users().doc(user.uid).set(user.toMap()).then((value)
async {
progressDialog.hide();
Fluttertoast.showToast(
msg: "Save done".tr(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: MyColors.primary,
textColor: Colors.white,
fontSize: 15.0 );})
.catchError((error){
progressDialog.hide();
Fluttertoast.showToast(
msg: "Server error".tr(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: MyColors.primary,
textColor: Colors.white,
fontSize: 15.0
);});}}}
@override
void initState(){
super.initState();}
@override
Widget build(BuildContext context) {
65 | P a g e
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays:[
SystemUiOverlay.top ]);
return Scaffold(
body:FutureBuilder(
future: Database.users().doc(Database.loggedUserId()).get(),
builder: (context,AsyncSnapshot<DocumentSnapshot<Object?>>
snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return
Center(child:CircularProgressIndicator());
default:
if (snapshot.hasData) {
user = Users.fromMap(
snapshot.data!.data() as Map<
String,dynamic>);
return
Form(key:formState,child:Container(alignment:Alignment.topCenter,
width:double.infinity,child:SingleChildScrollView(scrollDirection:
Axis.vertical,child:Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: Theme.of(context).primaryColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.emailAddress,
readOnly: true,
initialValue: user.email,
decoration: InputDecoration(
labelText: "Email address".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.mail,color:Theme.of(context).primaryColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder),
validator: (text){
if(text!.trim().isEmpty){
return "Email address".tr()+" "+"is
required".tr();}
if(! FA.isEmailValid(text)){
return "Invalid email".tr();}
return null; },
onSaved: (text){email=text.toString();},)),
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
66 | P a g e
cursorColor: Theme.of(context).primaryColor,
style: DesignHelper.fieldStyle,
inputFormatters:
[FilteringTextInputFormatter.allow(RegExp("[a-zA-Z\\s]"))],
keyboardType: TextInputType.name,
initialValue: user.name,
decoration: InputDecoration(
labelText: "Full name".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.person,color:Theme.of(context).primaryColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder),
validator: (text){
if(text!.trim().isEmpty){
return "Full name".tr()+" "+"is required".tr();}
return null; },
onSaved: (text){name=text.toString();},)),
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: Theme.of(context).primaryColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.number,
initialValue: user.phone,
decoration: InputDecoration(
labelText: "Phone number".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.person,color:Theme.of(context).primaryColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder),
validator: (text){
if(text!.trim().isEmpty){
return "Phone number".tr()+" "+"is required".tr();}
if(text.length != 10){
return "Phone number must 10 numbers".tr();}
return null; },
onSaved: (text){phone=text.toString();},)),
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: Theme.of(context).primaryColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.streetAddress,
67 | P a g e
initialValue: user.address,
decoration: InputDecoration(
labelText: "Address".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.mail,color:Theme.of(context).primaryColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder
),
validator: (text){
if(text!.trim().isEmpty){
return "Address".tr()+" "+"is required".tr();}
return null; },
onSaved: (text){address=text.toString();},)),
SizedBox(height: 45),
SizedBox(width:DesignHelper.buttonWidth,height:DesignHelper.buttonHeigh
t,child:
ElevatedButton(onPressed: (){
submit();
}, child: Text("Save").tr(),
style: DesignHelper.buttonStyle,
)),
SizedBox(height: 60), ],)) ));}
else{
return SizedBox.shrink(); }}}));}}
Register:
68 | P a g e
class Register extends StatefulWidget {
@override
State<StatefulWidget> createState() =>RegisterState();}
class RegisterState extends State<Register>{
late String email;
late String password;
final TextEditingController passwordEditing =
TextEditingController();
late String name;
late String phone;
late String address;
GlobalKey<FormState> formState = new GlobalKey<FormState>();
submit() async {
var form = formState.currentState;
if(form!.validate()){
form.save();
final ProgressDialog progressDialog =
ProgressDialog(context,isDismissible: false);
progressDialog.style(
message: 'Register'.tr()+".....",
messageTextStyle: TextStyle(
color: Theme.of(context).primaryColor, fontSize: 18.0,
fontWeight: FontWeight.normal),);
if(! await FA.isInternetAvailable()){
FA.showErrorMsg(context,"No internet".tr());}
else {
progressDialog.show();
try {
await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: email,
password: password);
Users user = new
Users(Database.loggedUserId(),email,password,name,phone,address);
Database.users().doc(Database.loggedUserId()).set(user.toMap()).then((v
alue) async {
progressDialog.hide();
Pref.set_isLogin(true);
Pref.set_email(email);
Navigator.pushReplacementNamed(context,"home");
}).catchError((error) {
progressDialog.hide();
FA.showErrorMsg(context,"Server error".tr());});
} on FirebaseAuthException catch (e) {
progressDialog.hide();
if (e.code == 'email-already-in-use') {
FA.showErrorMsg(context,
"Email already exists".tr());}
else {
FA.showErrorMsg(context,
"Server error".tr());}
} catch (e) {
progressDialog.hide();
FA.showErrorMsg(context,e.toString());}}}}
@override
69 | P a g e
void initState(){
super.initState();}
@override
Widget build(BuildContext context){
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
return Scaffold(
body:Form(key:formState,child:Container(alignment:Alignment.topCenter,w
idth:double.infinity,child:SingleChildScrollView(scrollDirection:
Axis.vertical,child:Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 10),
Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.symmetric(horizontal: 5),
child:Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(onPressed:(){
if (Navigator.canPop(context)) {
Navigator.pop(context);
} else {
SystemNavigator.pop();
}
}, icon: Icon(Icons.arrow_back),iconSize: 38),
PopupMenuButton<int>(
icon: Icon(Icons.language),
iconSize: 36,
itemBuilder: (BuildContext context) =>
<PopupMenuItem<int>>[
new PopupMenuItem<int>(
value: 0, child: new Text('Lang'.tr())),
],
onSelected: (int value) {
switch(value){
case 0:
setState((){
if(context.locale.languageCode ==
Lang.english.languageCode)
context.setLocale(Lang.arabic);
else
context.setLocale(Lang.english); });
break; } }),]),),
Container(
margin: EdgeInsets.only(left: 22),
child:Image(
image: AssetImage('images/logo.png',),
width: 140,
height: 120,)),
SizedBox(height: 15),
Container(
child: Text("SIGN UP".tr(),style: TextStyle(fontSize:
26,fontWeight:FontWeight.bold,color:MyColors.gray))),
70 | P a g e
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: Theme.of(context).primaryColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: "Email address".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.mail,color:Theme.of(context).primaryColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder
), validator: (text){
if(text!.trim().isEmpty){
return "Email address".tr()+" "+"is
required".tr();}
if(! FA.isEmailValid(text)){
return "Invalid email".tr();}
return null; },
onSaved: (text){email=text.toString();},)),
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: Theme.of(context).primaryColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.visiblePassword,
obscureText: true,
controller: passwordEditing,
decoration: InputDecoration(
labelText: "Password".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.lock,color:Theme.of(context).primaryColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder),
validator: (text){
if(text!.trim().isEmpty){
return "Password".tr()+" "+"is required".tr();}
if(text.length <8){
return "Password must be equal or grater than
8".tr();}
return null; },
onSaved: (text){password=text.toString();},)),
SizedBox(height: 25),
Container(
71 | P a g e
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: Theme.of(context).primaryColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.visiblePassword,
obscureText: true,//نجوم وضع
decoration: InputDecoration(
labelText: "Re-Password".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.lock,color:Theme.of(context).primaryColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder),
validator: (text){
if(text!.trim().isEmpty){
return "Re-Password".tr()+" "+"is required".tr();}
if(text.compareTo(passwordEditing.text) != 0){
return "Password not match".tr();}
return null; },)),
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: Theme.of(context).primaryColor,
style: DesignHelper.fieldStyle,
inputFormatters:
[FilteringTextInputFormatter.allow(RegExp("[a-zA-Z\\s]"))],
keyboardType: TextInputType.name,
decoration: InputDecoration(
labelText: "Full name".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.person,color:Theme.of(context).primaryColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder),
validator: (text){
if(text!.trim().isEmpty){
return "Full name".tr()+" "+"is required".tr();}
return null; },
onSaved: (text){name=text.toString();},)),
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: Theme.of(context).primaryColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.number,
72 | P a g e
decoration: InputDecoration(
labelText: "Phone number".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.person,color:Theme.of(context).primaryColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder),
validator: (text){
if(text!.trim().isEmpty){
return "Phone number".tr()+" "+"is required".tr();}
if(text.length != 10){
return "Phone number must 10 numbers".tr();}
return null; },
onSaved: (text){phone=text.toString();},)),
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: Theme.of(context).primaryColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.streetAddress,
decoration: InputDecoration(
labelText: "Address".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.mail,color:Theme.of(context).primaryColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder
), validator: (text){
if(text!.trim().isEmpty){
return "Address".tr()+" "+"is required".tr();}
return null; },
onSaved: (text){address=text.toString();},)),
SizedBox(height: 45),
SizedBox(width:DesignHelper.buttonWidth,height:DesignHelper.buttonHeigh
t,child:
ElevatedButton(onPressed: (){
submit();
}, child: Text("Register").tr(),
style: DesignHelper.buttonStyle,)),
SizedBox(height: 60),],))))); }}
Recover Password:
73 | P a g e
class RecoverPassword extends StatefulWidget {
@override
State<StatefulWidget> createState() =>RecoverPasswordState();}
class RecoverPasswordState extends State<RecoverPassword>{
late String email;
late String password;
GlobalKey<FormState> formState = new GlobalKey<FormState>();
submit() async {
var form = formState.currentState;
if(form!.validate()){
form.save();
final ProgressDialog progressDialog = ProgressDialog(
context, isDismissible: false);
progressDialog.style(
message: 'Recover'.tr()+"....",
messageTextStyle: TextStyle(
color: Theme
.of(context)
.primaryColor, fontSize: 18.0, fontWeight:
FontWeight.normal), );
if (!await FA.isInternetAvailable()) {
FA.showErrorMsg(context, "No internet".tr()); }
else {
progressDialog.show();
try {
await FirebaseAuth.instance
.sendPasswordResetEmail(
email: email, );
await progressDialog.hide();
Fluttertoast.showToast(
msg: "Password recovery has been sent to your email".tr(),
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 3,
backgroundColor: MyColors.primary,
textColor: Colors.white,
fontSize: 16.0 );
Navigator.pop(context);
} on FirebaseAuthException catch (e) {
progressDialog.hide();
FA.showErrorMsg(context,
"User not found".tr());}}}}
@override
void initState(){
super.initState();}
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
return Scaffold(
body:Form(key:formState,child:Container(alignment:Alignment.topCenter,w
idth:double.infinity,child:SingleChildScrollView(scrollDirection:
Axis.vertical,child:Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
74 | P a g e
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 10),
Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.symmetric(horizontal: 5),
child:Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(onPressed:(){
if (Navigator.canPop(context)) {
Navigator.pop(context);
} else {
SystemNavigator.pop();}
}, icon: Icon(Icons.arrow_back),iconSize: 38),
PopupMenuButton<int>(
icon: Icon(Icons.language),
iconSize: 36,
itemBuilder: (BuildContext context) =>
<PopupMenuItem<int>>[
new PopupMenuItem<int>(
value: 0, child: new Text('Lang'.tr())),],
onSelected: (int value) {
switch(value){
case 0:
setState((){
if(context.locale.languageCode ==
Lang.english.languageCode)
context.setLocale(Lang.arabic);
else
context.setLocale(Lang.english); });
break; }}), ]),),
Container(
margin: EdgeInsets.only(left: 22),
child:Image(
image: AssetImage('images/logo.png',),
width: 140,
height: 120,)),
SizedBox(height: 35),
Container(
child: Text("Recover Password",style:
TextStyle(fontSize:
24,fontWeight:FontWeight.bold,color:MyColors.gray)).tr()),
SizedBox(height: 30),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: Theme.of(context).primaryColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: "Email address".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
75 | P a g e
Icon(Icons.mail,color:Theme.of(context).primaryColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder
),validator: (text){
if(text!.trim().isEmpty){
return "Email address".tr()+" "+"is
required".tr();}
if(! FA.isEmailValid(text)){
return "Invalid email".tr();}
return null; },
onSaved: (text){email=text.toString();},)),
SizedBox(height: 30),
SizedBox(width:DesignHelper.buttonWidth,height:DesignHelper.buttonHeigh
t,child:
ElevatedButton(onPressed: (){
submit();
}, child: Text("Recover").tr(),
style: DesignHelper.buttonStyle,)),
SizedBox(height: 15), ],))))); }}
Report Info:
class ReportInfo extends StatefulWidget {
@override
76 | P a g e
State<StatefulWidget> createState() =>ReportInfoState();
}
@override
void initState(){
super.initState();
}
@override
Widget build(BuildContext context) {
final Map<String, Object> receivedData =
ModalRoute.of(context)!.settings.arguments as Map<String, Object> ;
child = receivedData['child'] as Child;
report = receivedData['report'] as Report;
number = receivedData['number'] as String;
return Scaffold(
appBar: AppBar(title: Text("Report Info".tr(),style:
DesignHelper.barTitleStyle),actions:menu1()),
body:Container(alignment:Alignment.topCenter,width:double.infinity,chil
d:SingleChildScrollView(scrollDirection: Axis.vertical,child:Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 30),
Image.network(
child.imgUrl,
width: 200,
height: 150,
),
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:Text("#"+"Report".tr()+" ${number}",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 18)),
),
SizedBox(height: 20),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
Text("Child name".tr()+" : ",
style: TextStyle(
color: Colors.black,
77 | P a g e
fontWeight: FontWeight.bold,
fontSize: 17)),
Text("${child.name}",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
fontSize: 17))]),
),
SizedBox(height: 20),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
Text("Child ID".tr()+" : ",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 17)),
Text("${child.child_id}",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
fontSize: 17))]),
),
SizedBox(height: 20),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
Text("Date".tr()+" : ",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 17)),
Text("${report.date}",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
fontSize: 17))]),
),
SizedBox(height: 20),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
Text("Time".tr()+" : ",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 17)),
Text("${report.time}",
style: TextStyle(
78 | P a g e
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
fontSize: 17))]),
),
SizedBox(height: 20),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:Column(
mainAxisAlignment: MainAxisAlignment.center,
children:[
Text("Report content".tr()+" : ",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 17)),
SizedBox(height: 10,),
Text("${report.content}",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontSize: 18))]),
),
SizedBox(height: 20),
]))));
}
menu1() {
return [
IconButton(icon:Icon(Icons.delete,color:
Colors.white,),onPressed:delete_child)
];
}
delete_child(){
AwesomeDialog(
context: context,
title: "Are you sure delete report?".tr(),
isDense: true,
btnCancelText: "no".tr(),
btnCancelOnPress: (){},
btnCancelColor: Colors.blue,
btnOkText: "yes".tr(),
btnOkColor: Colors.blue,
dismissOnBackKeyPress: false,
dismissOnTouchOutside: false,
customHeader: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 20),
Icon(Icons.warning,color: Colors.red,size: 55),
],),
btnOkOnPress: (){
delete();
},
)..show();
}
79 | P a g e
delete() async {
final ProgressDialog progressDialog = ProgressDialog(
context, isDismissible: false);
progressDialog.style(
message: 'Delete report'.tr() + "....",
messageTextStyle: TextStyle(
color: Theme
.of(context)
.primaryColor, fontSize: 18.0, fontWeight:
FontWeight.normal),
);
if (!await FA.isInternetAvailable()) {
FA.showErrorMsg(context, "No internet");
}
else {
progressDialog.show();
Database.report().doc(report.report_id).delete().then((value){
progressDialog.hide();
Fluttertoast.showToast(
msg: "Delete done".tr(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: MyColors.primary,
textColor: Colors.white,
fontSize: 15.0
);
if(Navigator.canPop(context)){
Navigator.pop(context);
}
else{
SystemNavigator.pop();
}
}).catchError((error) async {
progressDialog.hide();
FA.showErrorMsg(context, "Server error".tr());
});
}
}
Reports:
80 | P a g e
}
@override
void initState(){
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body:StreamBuilder<QuerySnapshot>(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Center(child:Text("Server error").tr());
}
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Container(
height: double.infinity,
child:Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Loading".tr()),
SizedBox(width: 30,),
CircularProgressIndicator()
],
));
default:
if(snapshot.hasData &&
snapshot.data!.docs.length==0){
return Center(child:Text("No Reports".tr()));
}
else{
return Container(
child:
ListView.separated(
separatorBuilder:(context,i){
if(report.user_id.toString().compareTo(Database.loggedUserId()) == 0) {
return Divider(thickness: 1,
color: MyColors.gray2,
height: 3,);
}
81 | P a g e
else{
return SizedBox.shrink();
}
},
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
padding: EdgeInsets.symmetric(vertical: 5),
itemBuilder:(context,i) {
Report report =
Report.fromMap(snapshot.data!.docs[i].data() as Map<String,dynamic>);
if(report.user_id.toString().compareTo(Database.loggedUserId()) == 0) {
return Container(child: FutureBuilder(
future:
Database.children().doc(report.child_id).get(),
builder:
(context,AsyncSnapshot<DocumentSnapshot<Object?>> snapshot) {
if (snapshot.hasData) {
Child child = Child.fromMap(
snapshot.data!.data() as
Map<
String,
dynamic>);
return ListTile(
title:
Text("#"+"Report".tr()+" "+(i+1).toString(),
style: TextStyle(
color: Colors.black,
fontSize: 16)),
trailing: Column(
mainAxisSize:
MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children:[Text(report.date,
style: TextStyle(
color:
MyColors.primary,
fontWeight:
FontWeight
.bold,
fontSize: 12)),
SizedBox(height: 8,),
Text(report.time,
style: TextStyle(
color: MyColors.gray,
fontWeight:
FontWeight
.bold,
fontSize: 12))]) ,
subtitle: Container(
82 | P a g e
padding:
EdgeInsets.only(top: 5),
child:
Text("Child".tr()+":
"+child.name,
style: TextStyle(
color:
MyColors.gray,
fontWeight:
FontWeight
.bold,
fontSize: 14))),
leading: ImageIcon(
AssetImage(
"images/file_logo.png"),
size: 47, color: Theme
.of(context)
.primaryColor),
tileColor: Colors.white,
contentPadding:
EdgeInsets.symmetric(
horizontal: 7),
onTap: () {
Navigator.of(context).pushNamed(
"report_info",
arguments: {
"child": child,
"report":report,
"number":(i+1).toString(),
});
},
);
} else {
return SizedBox.shrink();
}
}));
} else{
return SizedBox.shrink();
} }));
return Text("");}}})); }}
Send Report:
@override
83 | P a g e
State<StatefulWidget> createState() =>SendReportState();
}
submit() async {
var form = formState.currentState;
if (form!.validate()) {
form.save();
Database.report().doc(report_id).set(report.toMap()).then((value) {
progressDialog.hide();
Fluttertoast.showToast(
msg: "Send done".tr(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: MyColors.primary,
textColor: Colors.white,
fontSize: 15.0
);
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
else {
SystemNavigator.pop();
}
84 | P a g e
}).catchError((error) {
progressDialog.hide();
FA.showErrorMsg(context, "Server error".tr());
});
}
}
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays:
[
SystemUiOverlay.top
]);
final Map<String, Object> receivedData =
ModalRoute.of(context)!.settings.arguments as Map<String, Object> ;
child = receivedData['child'] as Child;
return Scaffold(
appBar: AppBar(title: Text(
"Send report".tr(), style: DesignHelper.barTitleStyle,)),
body: Form(key: formState,
child: Container(alignment: Alignment.topCenter,
width: double.infinity,
child: SingleChildScrollView(
scrollDirection: Axis.vertical, child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 30),
Container(
height: 6 * 24.0,
margin: EdgeInsets.symmetric(horizontal:
20,vertical: 12),
child: TextFormField(
cursorColor: Theme
.of(context)
.primaryColor,
style: DesignHelper.fieldStyle,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp("[a-zA-Z\\s]"))
],
maxLines: 6,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
labelText: "Report content".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon: Icon(Icons.note, color: Theme
85 | P a g e
.of(context)
.primaryColor),
enabledBorder: DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder:
DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper
.fieldErrorBorder
),
validator: (text) {
if (text!.trim().isEmpty) {
return "Report content".tr() + " " +
"is required".tr();
}
return null;
},
onSaved: (text) {
content = text.toString();
},
)),
SizedBox(height: 35),
SizedBox(width: DesignHelper.buttonWidth2,
height: DesignHelper.buttonHeight2,
child:
ElevatedButton(onPressed: () {
submit();
}, child: Text("Send").tr(),
style: DesignHelper.buttonStyle,
)),
SizedBox(height: 15),
],))
)));
}
}
Child Image:
class UpdateChildImage extends StatefulWidget {
@override
State<StatefulWidget> createState() =>UpdateChildImageState();
}
86 | P a g e
class UpdateChildImageState extends State<UpdateChildImage>{
submit() async {
var form = formState.currentState;
if (form!.validate()) {
form.save();
if (image.path == "") {
FA.showInfoMsg(context, "Please upload child image".tr());
return;
}
FirebaseStorage.instance.refFromURL(child.imgUrl).delete().then((value)
{
Reference reference = FirebaseStorage.instance.ref(
"${Database.loggedUserId()}/${child.child_id}${fileName}");
UploadTask uploadTask = reference.putFile(image);
uploadTask.snapshotEvents.listen((event) async {
if (event.state == TaskState.success) {
String imgUrl = await event.ref.getDownloadURL();
Database.children().doc(child.child_id).update({"imgUrl":imgUrl});
progressDialog.hide();
Fluttertoast.showToast(
msg: "Save done".tr(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: MyColors.primary,
textColor: Colors.white,
fontSize: 15.0
);
back_action();
}
87 | P a g e
}).onError((error) {
progressDialog.hide();
FA.showErrorMsg(context, "Server error".tr());
});
}).catchError((error) {
progressDialog.hide();
FA.showErrorMsg(context, "Server error".tr());
});
}
}
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: [
SystemUiOverlay.top
]);
final Map<String, Object> receivedData =
ModalRoute.of(context)!.settings.arguments as Map<String, Object> ;
child = receivedData['child'] as Child;
return Scaffold(
appBar: AppBar(title: Text(
"Update child".tr(), style: DesignHelper.barTitleStyle,),
leading: new IconButton(
icon: new Icon(Icons.arrow_back),
onPressed: () {
back_action();
})
),
88 | P a g e
MainAxisAlignment
.center, children: [
Icon(Icons.upload, color:
MyColors.primary,),
Text(
"Upload child image".tr(), style:
TextStyle(
color: MyColors.gray,
fontWeight: FontWeight.bold,
fontSize: 18
), textAlign: TextAlign.center)
])) : Image.file(image,
fit: BoxFit.fill
)
), onTap: () async {
FilePickerResult? result = await
FilePicker.platform
.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'png'],
);
if (result != null) {
PlatformFile file = result.files.first;
setState(() {
fileName = file.name;
image = new File(file.path.toString());
});
}
},),
SizedBox(height: 35),
SizedBox(width: DesignHelper.buttonWidth2,
height: DesignHelper.buttonHeight2,
child:
ElevatedButton(onPressed: () {
submit();
}, child: Text("Update").tr(),
style: DesignHelper.buttonStyle,
)),
SizedBox(height: 15),
],)) )))); }
Future<bool> back_action() async {
Navigator.pushReplacementNamed(context, "child_info",arguments:
{"child":child});
return Future.value(false); }}
Child Name:
class UpdateChildName extends StatefulWidget {
@override
State<StatefulWidget> createState() =>UpdateChildNameState();
}
89 | P a g e
class UpdateChildNameState extends State<UpdateChildName>{
submit() async {
var form = formState.currentState;
if (form!.validate()) {
form.save();
Database.children().doc(child.child_id).update({"name":name});
progressDialog.hide();
Fluttertoast.showToast(
msg: "Save done".tr(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: MyColors.primary,
textColor: Colors.white,
fontSize: 15.0
);
back_action();
}
}
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: [
SystemUiOverlay.top
]);
90 | P a g e
final Map<String, Object> receivedData =
ModalRoute.of(context)!.settings.arguments as Map<String, Object> ;
child = receivedData['child'] as Child;
return Scaffold(
appBar: AppBar(title: Text(
"Update child".tr(), style: DesignHelper.barTitleStyle,),
leading: new IconButton(
icon: new Icon(Icons.arrow_back),
onPressed: () {
back_action();
})
),
body:new WillPopScope(
onWillPop: back_action,
child: Form(key: formState,
child: Container(alignment: Alignment.topCenter,
width: double.infinity,
child: SingleChildScrollView(
scrollDirection: Axis.vertical, child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 30),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child: TextFormField(
cursorColor: Theme
.of(context)
.primaryColor,
style: DesignHelper.fieldStyle,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp("[a-zA-Z\\s]"))
],
keyboardType: TextInputType.name,
initialValue: child.name,
decoration: InputDecoration(
labelText: "Child name".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle:
DesignHelper.fieldErrorStyle,
prefixIcon: Icon(Icons.person, color:
Theme
.of(context)
.primaryColor),
enabledBorder:
DesignHelper.fieldBorder,
focusedBorder:
DesignHelper.fieldBorder,
disabledBorder:
DesignHelper.fieldBorder,
errorBorder:
DesignHelper.fieldErrorBorder,
91 | P a g e
focusedErrorBorder: DesignHelper
.fieldErrorBorder
),
validator: (text) {
if (text!.trim().isEmpty) {
return "Child name".tr() + " " +
"is required".tr();
}
return null;
},
onSaved: (text) {
name = text.toString();
},
)),
SizedBox(height: 35),
SizedBox(width: DesignHelper.buttonWidth2,
height: DesignHelper.buttonHeight2,
child:
ElevatedButton(onPressed: () {
submit();
}, child: Text("Save").tr(),
style: DesignHelper.buttonStyle,
)),
SizedBox(height: 15),
],))
))));
}
92 | P a g e
class UpdateChildImageState extends State<UpdateChildImage>{
submit() async {
var form = formState.currentState;
if (form!.validate()) {
form.save();
if (image.path == "") {
FA.showInfoMsg(context, "Please upload child image".tr());
return;
}
FirebaseStorage.instance.refFromURL(child.imgUrl).delete().then((value)
{
Reference reference = FirebaseStorage.instance.ref(
"${Database.loggedUserId()}/${child.child_id}${fileName}");
UploadTask uploadTask = reference.putFile(image);
uploadTask.snapshotEvents.listen((event) async {
if (event.state == TaskState.success) {
String imgUrl = await event.ref.getDownloadURL();
Database.children().doc(child.child_id).update({"imgUrl":imgUrl});
progressDialog.hide();
Fluttertoast.showToast(
msg: "Save done".tr(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: MyColors.primary,
textColor: Colors.white,
fontSize: 15.0
);
back_action(); }
}).onError((error) {
progressDialog.hide();
93 | P a g e
FA.showErrorMsg(context, "Server error".tr());
});
}).catchError((error) {
progressDialog.hide();
FA.showErrorMsg(context, "Server error".tr());
}); }}}
@override
void initState() {
super.initState();}
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: [
SystemUiOverlay.top
]);
final Map<String, Object> receivedData =
ModalRoute.of(context)!.settings.arguments as Map<String, Object> ;
child = receivedData['child'] as Child;
return Scaffold(
appBar: AppBar(title: Text(
"Update child".tr(), style: DesignHelper.barTitleStyle,),
leading: new IconButton(
icon: new Icon(Icons.arrow_back),
onPressed: () {
back_action();
})),
body: new WillPopScope(
onWillPop: back_action,
child:Form(key: formState,
child: Container(alignment: Alignment.topCenter,
width: double.infinity,
child: SingleChildScrollView(
scrollDirection: Axis.vertical, child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 30),
GestureDetector(child: Container(
margin: EdgeInsets.symmetric(horizontal: 20),
width: double.infinity,
height: 200,
padding: EdgeInsets.symmetric(horizontal:
10),
child: image.path == "" ? Container(
alignment: Alignment.center,
child: Row(mainAxisAlignment:
MainAxisAlignment
.center, children: [
Icon(Icons.upload, color:
MyColors.primary,),
Text(
"Upload child image".tr(), style:
TextStyle(
color: MyColors.gray,
fontWeight: FontWeight.bold,
fontSize: 18
94 | P a g e
), textAlign: TextAlign.center)
])) : Image.file(image,
fit: BoxFit.fill
)
), onTap: () async {
FilePickerResult? result = await
FilePicker.platform
.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'png'],
);
if (result != null) {
PlatformFile file = result.files.first;
setState(() {
fileName = file.name;
image = new File(file.path.toString());
});
}
},),
SizedBox(height: 35),
SizedBox(width: DesignHelper.buttonWidth2,
height: DesignHelper.buttonHeight2,
child:
ElevatedButton(onPressed: () {
submit();
}, child: Text("Update").tr(),
style: DesignHelper.buttonStyle,
)),
SizedBox(height: 15),
],))
))));
}
95 | P a g e
class UpdateChildNameState extends State<UpdateChildName>{
late String name;
GlobalKey<FormState> formState = new GlobalKey<FormState>();
late Child child;
submit() async {
var form = formState.currentState;
if (form!.validate()) {
form.save();
final ProgressDialog progressDialog = ProgressDialog(
context, isDismissible: false);
progressDialog.style(
message: 'Update'.tr() + "....",
messageTextStyle: TextStyle(
color: Theme
.of(context)
.primaryColor, fontSize: 18.0, fontWeight:
FontWeight.normal),);
if (!await FA.isInternetAvailable()) {
FA.showErrorMsg(context, "No internet");} else {
progressDialog.show();
Database.children().doc(child.child_id).update({"name":name});
progressDialog.hide();
Fluttertoast.showToast(
msg: "Save done".tr(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: MyColors.primary,
textColor: Colors.white,
fontSize: 15.0);back_action();}}}
@override
void initState() {
super.initState();}
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: [
SystemUiOverlay.top]);
final Map<String, Object> receivedData =
ModalRoute.of(context)!.settings.arguments as Map<String, Object> ;
child = receivedData['child'] as Child;
return Scaffold(
appBar: AppBar(title: Text(
"Update child".tr(), style:
DesignHelper.barTitleStyle,),
leading: new IconButton(
icon: new Icon(Icons.arrow_back),
onPressed: () {
back_action();})),
body:new WillPopScope(
onWillPop: back_action,
child: Form(key: formState,
child: Container(alignment: Alignment.topCenter,
width: double.infinity,
child: SingleChildScrollView(
scrollDirection: Axis.vertical, child: Column(
mainAxisSize: MainAxisSize.max,
96 | P a g e
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 30),
Container(margin:
EdgeInsets.symmetric(horizontal:20),
child: TextFormField(
cursorColor: Theme
.of(context)
.primaryColor,
style: DesignHelper.fieldStyle,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp("[a-zA-Z\\s]"))],
keyboardType: TextInputType.name,
initialValue: child.name,
decoration: InputDecoration(
labelText: "Child name".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle:
DesignHelper.fieldErrorStyle,
prefixIcon: Icon(Icons.person,
color: Theme
.of(context)
.primaryColor),
enabledBorder:
DesignHelper.fieldBorder,
focusedBorder:
DesignHelper.fieldBorder,
disabledBorder:
DesignHelper.fieldBorder,
errorBorder:
DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper
.fieldErrorBorder),
validator: (text) {
if (text!.trim().isEmpty) {
return "Child name".tr() + " " +
"is required".tr();}
return null;},
onSaved: (text) {
name = text.toString();},)),
SizedBox(height: 35),
SizedBox(width: DesignHelper.buttonWidth2,
height: DesignHelper.buttonHeight2,
child:
ElevatedButton(onPressed: () {
submit();}, child: Text("Save").tr(),
style: DesignHelper.buttonStyle,)),
SizedBox(height: 15),],))))));}
Future<bool> back_action() async {
Navigator.pushReplacementNamed(context, "child_info",arguments:
{"child":child});
return Future.value(false);}
97 | P a g e
Main Dart:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await EasyLocalization.ensureInitialized();
Pref.pref = await SharedPreferences.getInstance();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) {runApp(
98 | P a g e
EasyLocalization(
supportedLocales: [Lang.english,Lang.arabic],
path: 'assets/translations',
fallbackLocale: Lang.english,
startLocale: Lang.english ,
child: MyApp() ), );});}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
return MaterialApp(
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
debugShowCheckedModeBanner: false,
home:Splash(),
routes: {
"splash": (context) => Splash(),
"login": (context) => Login(),
"register": (context) => Register(),
"re_password": (context) => RecoverPassword(),
"home": (context) => Home(),
"intro": (context) => Intro(),
"child_info": (context) => ChildInfo(),
"child_map": (context) => ChildMap(),
"children": (context) => Children(),
"add_child": (context) => AddChild(),
"update_child_name": (context) => UpdateChildName(),
"send_report": (context) => SendReport(),
"update_child_image": (context) => UpdateChildImage(),
"report_info": (context) => ReportInfo(),},
theme: ThemeData(
primaryColor: MyColors.primary,
primarySwatch:
MaterialColor(MyColors.primarySwatch,MyColors.color),
colorScheme: ColorScheme.light(
primary: MyColors.primary,
secondary: MyColors.primary,),
fontFamily: (Lang.isArabic(context.locale))?"cairo":"",
unselectedWidgetColor: MyColors.primary,//radio
canvasColor: Colors.white,
brightness: Brightness.light,
textTheme:TextTheme(
subtitle1: TextStyle(
color: MyColors.gray,
fontSize: 15,
fontWeight: FontWeight.bold,
),
subtitle2: TextStyle(
color: MyColors.primary,
fontSize: 17,
fontWeight: FontWeight.bold,
),
headline6:TextStyle(
color: MyColors.primary,
fontFamily: "cairo_bold",
99 | P a g e
fontSize: 15,
),
bodyText2: TextStyle(
color: Colors.black,
)),
),);}}
100 | P a g e
late GoogleMapController gmc;
var child_id = Pref.get_child();
late LatLng current_latLang;
Set<Marker> markers = {};
late StreamSubscription<Position> ps;
static final CameraPosition defaultPosition = CameraPosition(
target: LatLng(0, 0),
tilt: 59,
zoom: 19.151926040649414,
);
void mapSettings() async {
Position position = await Geolocator.getCurrentPosition();
setState(() {
current_latLang = LatLng(position.latitude, position.longitude);
gmc.moveCamera(CameraUpdate.newLatLng(current_latLang));
Database.children().doc(child_id).update({"lat":lat,"lng":lng});});}
@override
void dispose() {
Database.children().doc(child_id).update({"is_online":false});
super.dispose();}
Future<bool> _onWillPop() async {
return (await showDialog(
context: context,
builder: (context) => new AlertDialog(
content: new Text("Do you want to sign out?".tr(),
style:TextStyle(fontSize: 17,color:Colors.black)),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: new Text('no'.tr(),
style:TextStyle(fontSize:
17,color:MyColors.primary)),),
TextButton(
onPressed: () {
Database.children().doc(child_id).update({"is_online":false});
Database.logout();
Navigator.pushReplacementNamed(context,"login");
101 | P a g e
},
child: new Text('yes'.tr(),
style:TextStyle(fontSize:
17,color:MyColors.primary)),),],),
)) ?? false;}@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays:
[
SystemUiOverlay.top
]);
return new WillPopScope(
onWillPop: _onWillPop,
child: new Scaffold(
appBar: AppBar(title: Text(
"Child".tr()+" - "+child_id, style: DesignHelper.barTitleStyle,
), actions: menu1()),
body: Container(
child: GoogleMap(
mapType: MapType.normal,
zoomControlsEnabled: false,
myLocationEnabled: false,
initialCameraPosition: defaultPosition,
markers: markers,
onMapCreated: (GoogleMapController controller) {
gmc = controller;
},),),));}
Future<void> childMove(latitude, longitude) async {
gmc.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
target: new LatLng(latitude, longitude),
tilt: 59,
zoom: 19.151926040649414,
)));
setState(() {
Marker marker = markers.firstWhere((marker) =>
marker.markerId.value == "child");
markers.remove(marker);
markers.add(
Marker(markerId: MarkerId("child"), position: LatLng(latitude,
longitude),
icon:
BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueGreen)
),);});}
menu1() {
return [
PopupMenuButton<int>(
icon: Icon(Icons.language),
itemBuilder: (BuildContext context) => <PopupMenuItem<int>>[
new PopupMenuItem<int>(
value: 0, child: new Text('Lang'.tr())),],
onSelected: (int value) {
switch(value){
case 0:
setState((){
if(context.locale.languageCode ==
Lang.english.languageCode)
102 | P a g e
context.setLocale(Lang.arabic);
else
context.setLocale(Lang.english);
});
break;}})
,IconButton(icon:Icon(Icons.power_settings_new,color:
Colors.white,),onPressed:logout),];}
logout(){
AwesomeDialog(
context: context,
title: "Do you want to sign out?".tr(),
isDense: true,
btnCancelText: "no".tr(),
btnCancelOnPress: (){},
btnCancelColor: Colors.blue,
btnOkText: "yes".tr(),
btnOkColor: Colors.blue,
dismissOnBackKeyPress: false,
dismissOnTouchOutside: false,
customHeader: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 20),
Icon(Icons.warning,color: Colors.red,size: 55),
],),
btnOkOnPress: (){
Database.children().doc(child_id).update({"is_online":false});
Database.logout();
Navigator.pushReplacementNamed(context,"login");
},
)..show();
}
}
Child Log-In:
103 | P a g e
late String child_id;
GlobalKey<FormState> formState = new GlobalKey<FormState>();
submit() async {
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
FA.showErrorMsg(context, "Please enable location".tr());}
else {
LocationPermission permission;
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
FA.showErrorMsg(context, "Please grant storage
permission").tr();
return;
}
return;
}
if (permission == LocationPermission.deniedForever) {
FA.showInfoMsg(
context, "Please grant location permission from
settings").tr();
openAppSettings();
return;
}
}
104 | P a g e
Database.children().doc(child_id).update({"is_online":true});
Navigator.of(context).pushReplacementNamed("child_map");
}}).catchError((error) {
progressDialog.hide();
FA.showErrorMsg(context, "Server error".tr());
});
}
}
}
@override
void initState(){
super.initState();
}
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
return Scaffold(
body:Form(key:formState,child:Container(alignment:Alignment.topCenter,w
idth:double.infinity,child:SingleChildScrollView(scrollDirection:
Axis.vertical,child:Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 10),
Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.symmetric(horizontal: 5),
child:Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(""),
PopupMenuButton<int>(
icon:
Icon(Icons.language,color:MyColors.primary),
iconSize: 36,
105 | P a g e
Image(
image: AssetImage('images/logo.png',),
width: 150,
height: 120,
),
SizedBox(height: 25),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
child:TextFormField(
cursorColor: MyColors.filedColor,
style: DesignHelper.fieldStyle,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: "Child ID".tr(),
labelStyle: DesignHelper.fieldStyle,
errorStyle: DesignHelper.fieldErrorStyle,
prefixIcon:
Icon(Icons.perm_identity,color:MyColors.filedColor),
enabledBorder:DesignHelper.fieldBorder,
focusedBorder: DesignHelper.fieldBorder,
disabledBorder: DesignHelper.fieldBorder,
errorBorder: DesignHelper.fieldErrorBorder,
focusedErrorBorder: DesignHelper.fieldErrorBorder
),
validator: (text){
if(text!.trim().isEmpty){
return "Child ID".tr()+" "+"is required".tr();
}
if(text.length != 6){
return "Child ID must 6 numbers".tr();
}
return null;
},
onSaved: (text){child_id=text.toString();},
)),
SizedBox(height: 25),
SizedBox(width:DesignHelper.buttonWidth2,height:DesignHelper.buttonHeig
ht2,child:
ElevatedButton(onPressed: (){
submit();
}, child: Text("Login").tr(),
style: DesignHelper.buttonStyle,
)),
SizedBox(height: 15),],)) ))); }}
106 | P a g e
EasyLocalization(
supportedLocales: [Lang.english,Lang.arabic],
path: 'assets/translations',
fallbackLocale: Lang.english,
startLocale: Lang.english ,
child: MyApp()),);});}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
return MaterialApp(
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
debugShowCheckedModeBanner: false,
home:Splash(),
routes: {
"splash": (context) => Splash(),
"login": (context) => Login(),
"child_map": (context) => ChildMap(),},
theme: ThemeData(
primaryColor: MyColors.primary,
primarySwatch:
MaterialColor(MyColors.primarySwatch,MyColors.color),
colorScheme: ColorScheme.light(
primary: MyColors.primary,
secondary: MyColors.primary,),
fontFamily: (Lang.isArabic(context.locale))?"cairo":"",
unselectedWidgetColor: MyColors.primary,//radio
canvasColor: Colors.white,
brightness: Brightness.light,
textTheme:TextTheme(
subtitle1: TextStyle(
color: MyColors.gray,
fontSize: 15,
fontWeight: FontWeight.bold,),
subtitle2: TextStyle(
color: MyColors.primary,
fontSize: 17,
fontWeight: FontWeight.bold,),
headline6:TextStyle(
color: MyColors.primary,
fontFamily: "cairo_bold",
fontSize: 15,),
bodyText2: TextStyle( color: Colors.black,)),),);}}
107 | P a g e
Figure 5.6: Splash Screen (E/A)
Log-In (E/A)
Sign-Up (E/A)
108 | P a g e
Figure 5.6: Sign-Up (E/A)
109 | P a g e
Figure 5.6: Add Child (E/A)
Children (E/A)
110 | P a g e
Figure 5.6: Child Information (E/A)
Profile (E/A)
111 | P a g e
Reports (E/A)
112 | P a g e
Send Reports (E/A)
Map (E/A)
113 | P a g e
Chapter 6: Testing
114 | P a g e
6.1 Introduction
System Testing: is a level of testing that validates the complete and fully integrated
software product. The purpose of a system test is to evaluate the end-to-end system
specifications.
115 | P a g e
6.3 The key function of our application:
6.3.1 Parents:
Log-In
Sign-Up
Recover Password
Add Child
Delete Child
Children
Child Information
Profile
Child Map
Reports
Send Reports
Reports Information
Home
6.3.2 Child:
Child Id
Map
116 | P a g e
6.4 Testing Cases
Actor Parents
Function Name Log-In
Description The parent login when they have an account
117 | P a g e
Actor Parents
Function Name Sign-Up
Description The parent provides the required information
118 | P a g e
Actor Parents
Function Name Home Page
Description The parent can view the home page
Actor Parents
Function Name Add Child
Description The parent can Add child Name and Picture
Actor Parents
119 | P a g e
Function Name My Children
Description The parent can see their children list
Actor Parents
Function Name Child Information
Description The parent views their child information
Actor Parents
Function Name Delete Child
Description The parent can delete their children
120 | P a g e
Actor Parents
Function Name Send Report
Description The parent sends a report if they lost their child
Actor Parents
Function Name Report
Description The parent can view the opened reports
Actor Parents
Function Name Report Info
Description The parent can view report info
121 | P a g e
Actor Parents
Function Name Report Info
Description The parent can view report info
Actor Parents
Function Name My Profile
Description The parent can view their personal information
122 | P a g e
Actor Parents
Function Name Child Map
Description The parent can view their child location
Actor Parents
Function Name Recover Password
Description The parent could recover their password if they forgot it
123 | P a g e
Actor Parent
Function Name Update child Image
Description The parent can child their child picture
The parent
Update uploading new
2 wants to change Save done Pass
image child image
child image
Actor Parent
Function Name Update child Name
Description The parent can change their child name
The parent
Update Not typing Child name is
1 wants to change Fail
name child name required
child name
The parent
Update typing child
2 wants to change Save done Pass
name name
child name
124 | P a g e
Actor Child
Function Name Child ID
Description The child enters the verified child id in the parents’ application
125 | P a g e
6.5 Test Result
After applying all the mentioned tests, our test plan could not find any application
error.
Function Result
Log-In Pass
Sign-Up Pass
Recover Password Pass
Add Child Pass
Children Pass
Child Information Pass
Profile Pass
Child Map Pass
Reports Pass
Send Reports Pass
Reports Info Pass
Home Pass
Delete Child Pass
Child ID Pass
Map Pass
126 | P a g e
Conclusion
127 | P a g e
7.1 Conclusions
In our graduation project the system is only used in Saudi Arabia we are hoping that
we can add new features such as:
128 | P a g e
References
129 | P a g e
<https://www.researchgate.net/publication/283647124_Missing_children_and_parenta
l_struggle_From_chaos_to_coping> [Accessed 11 April 2021].
[2] Global Missing Children's Network. 2021. Missing Children's Statistics - Global
Missing Children's Network. [online] Available at:
<https://globalmissingkids.org/awareness/missing-children-
statistics/#:~:text=One%20Missing%20Child%20Is%20One%20Too%20Many&text=I
n%20Australia%2C%20an%20estimated%2020%2C000,are%20reported%20missing
%20each%20year.> [Accessed 11 April 2021].
[4] Fracttal.com. 2021. The 9 most important applications of the Internet of Things
(IoT). [online] Available at: <https://www.fracttal.com/en/blog/the-9-most-important-
applications-of-the-internet-of-things> [Accessed 11 April 2021].
[5] Eastern Peak - Technology Consulting & Development Company. 2021. IoT
Projects Examples. [online] Available at: <https://easternpeak.com/works/iot/>
[Accessed 11 April 2021].
[6] Eastern Peak - Technology Consulting & Development Company. 2021. IoT
Projects Examples. [online] Available at: <https://easternpeak.com/works/iot/>
[Accessed 11 April 2021].
[7] Apple Support. 2021. Use Find My iPhone on iCloud.com on your computer.
[online] Available at: <https://support.apple.com/en-
gb/guide/icloud/mm6b1aa045/icloud> [Accessed 11 April 2021].
[9] Cirelly, J., 2021. 8 Best IoT Platforms For Business (Paid & Free). [online]
ITPRC. Available at: <https://www.itprc.com/iot-platforms-for-business/> [Accessed
11 April 2021].
130 | P a g e
[10] Guru99. 2021. Unit Testing Tutorial: What is, Types, Tools & Test EXAMPLE.
[online] Available at: <https://www.guru99.com/unit-testing-guide.html> [Accessed 30
November 2021].
[11] ZealousWeb. 2021. Unit Testing Vs Functional Testing: A Guide On Why, What &
How. [online] Available at: <https://www.zealousweb.com/unit-testing-vs-functional-
testing-a-guide-on-why-what-how/> [Accessed 30 November 2021].
[13] Docs.oracle.com. 2021. Bookshelf v8.0: Test Objectives. [online] Available at:
<https://docs.oracle.com/cd/B40099_02/books/TestGuide/TestGuide_PlanTesting3.html
> [Accessed 30 November 2021].
131 | P a g e