Class Work
Class Work
● Feature Phones: Mobile apps started with basic software on feature phones, like
calendars, calculators, and simple games like Snake on Nokia devices.
● Java and Symbian: In the early 2000s, more advanced apps emerged on
platforms like Java ME (used by many manufacturers) and Symbian OS (led by
Nokia).
● iPhone and App Store (2007-2008): Apple revolutionized mobile apps with the
iPhone and its iOS operating system. 2008 the App Store launched, providing
developers a platform to distribute apps directly to consumers.
● Android and Google Play (2008): Google followed suit with Android and its
marketplace, Google Play (originally called Android Market). Due to its
open-source nature, Android quickly became a major competitor.
● Native App Dominance: Developers began to focus more on native apps (iOS
using Swift, Android using Kotlin) for performance and user experience.
● Hybrid Frameworks: Modern frameworks like React Native and Flutter allow for
near-native performance while simplifying development by offering a single
codebase for multiple platforms.
5. Current Trends:
● AI and AR Integration: Apps are now more interactive with AI features (personal
assistants, image recognition) and augmented reality (AR) for enhanced user
experiences.
● Super Apps: In markets like China, apps like WeChat have grown into all-in-one
platforms, combining messaging, shopping, payments, and services in a single
app.
Flutter and React Native are two popular frameworks for building cross-platform mobile
applications. They allow developers to write a single codebase and deploy it to both iOS
and Android, saving time and resources. Here's a comparison of Flutter and React
Native, breaking down key aspects with percentage-based insights:
1. Performance
● React Native (85%): Launched in 2015 by Facebook, React Native has a large
and mature developer community. Many big apps (e.g., Facebook, Instagram)
have been built using this framework, and it remains highly popular.
● Flutter (75%): Flutter, launched in 2017 by Google, is rapidly growing in
popularity but is newer compared to React Native. Its community is still growing,
but it’s already used by companies like Alibaba and Google.
3. Development Speed
4. UI/UX
● Flutter (95%): Flutter excels in UI design as it comes with its own set of
customizable widgets that offer a consistent look across platforms. It allows
developers more control over the entire screen and UI elements.
● React Native (80%): React Native relies on native components, so the UI/UX
can sometimes differ between iOS and Android. However, with additional
libraries, developers can create visually appealing interfaces.
5. Learning Curve
● React Native (85%): React Native uses JavaScript, a well-known and widely
used language, making it easier for web developers to transition to mobile app
development.
● Flutter (70%): Flutter uses Dart, which is less common than JavaScript, meaning
developers need to learn a new language. However, Dart is relatively easy to
pick up, especially for developers with experience in object-oriented
programming.
● React Native (90%): Since it has been around longer, React Native has a larger
ecosystem of third-party libraries and tools that can extend its functionality.
● Flutter (80%): Flutter's ecosystem is growing, but there are fewer third-party
libraries compared to React Native. However, Google is actively supporting and
expanding Flutter's ecosystem.
● React Native (80%): React Native has been around longer, making it more
stable and mature, though there are still challenges with native module
compatibility and upgrades.
● Flutter (85%): While Flutter is newer, its stability is excellent due to Google's
active development and support. Many developers praise its robust architecture
and smooth updates.
8. Code Reusability
● React Native (85%): React Native allows for significant code reuse across
platforms but may require platform-specific tweaks for complex UIs or
functionality.
● Flutter (90%): With Flutter, almost 100% of the code can be reused for both
platforms, reducing the need for platform-specific adjustments.
9. Development Cost
● React Native (85%): Since JavaScript is more widely known and React Native
has a large community, hiring React Native developers can be cost-effective.
● Flutter (80%): The cost is similar to React Native, though finding experienced
Flutter developers may be slightly harder because Dart is not as popular as
JavaScript.
Summary
Google Ads
● Purpose: This app allows users to manage Google Ads campaigns, track
performance, and get real-time notifications.
● Reason for Using Flutter: Flutter’s fast performance and ability to create
complex UIs across platforms made it a great choice for Google.
2. Alibaba
● Purpose: Alibaba, the giant e-commerce platform, uses Flutter for parts of its
app to ensure a seamless shopping experience across iOS and Android.
● Reason for Using Flutter: The company needed a high-performance framework
that would allow them to ship features faster while maintaining a consistent UI.
3. Reflectly
● Purpose: Reflectly is a personal journal and mental health app that uses AI to
help users reflect on their daily lives.
● Reason for Using Flutter: Flutter’s smooth animations and ability to create
visually engaging UIs helped Reflectly offer an appealing user experience across
both platforms.
4. BMW
● Purpose: The BMW app allows users to interact with their cars
remotely—checking vehicle status, locking/unlocking, and planning trips.
● Reason for Using Flutter: BMW selected Flutter to streamline development for
both iOS and Android, ensuring a consistent experience across devices.
5. eBay Motors
● Purpose: eBay Motors helps users buy, sell, and explore cars, motorcycles, and
parts directly from their mobile phones.
● Reason for Using Flutter: Flutter allowed eBay to develop an intuitive interface
with interactive features for image uploading, browsing, and vehicle details.
Why Dart?
dart
Copy code
void main() {
print(age); // Output: 10
dart
Copy code
void main() {
void main() {
void main() {
dart
Copy code
void main() {
dynamic x = 'Hello'; // Initially, a String
dynamic allows you to change the type of a variable after it has been initialized. This is
not recommended unless necessary, as it can make the code harder to understand and
debug.
Class work
main() {
print(newString);
oid main() {
// Creating a list
fruits.add('Orange');
fruits.addAll(['Pineapple', 'Grapes']);
numbers.remove(20);
emptyList.clear();
numbers.sort();
Class work
main() {
List<String> subjects = [
"maths",
"english",
"physics",
"Bio",
];
//
print("here is length
${number.length}");
// here is length 6
number.add(2000);
// subject
print(subjects.reversed);
// number list
print(number.reversed);
subjects.addAll(["ITC", "ISoftware"]);
// number.insert(4, 2000);
number.remove(1000);
subjects.remove("ISoftware");
number.removeAt(8);
emptyList.clear();
//output
//hree is list before removeal [2, 3, 4,
remove, true]
bool hasGreaterThan30 =
number.any((element) => element > 30);
In Dart, a Map is an unordered collection of key-value pairs. Each key is unique, but
multiple keys can have the same value. Maps are useful when you want to associate
keys with values, similar to objects in JavaScript.
● Key-value pairs: Every entry in a Map has a key and a corresponding value.
● Keys are unique: A key can only appear once in a Map.
● Dynamic size: Maps are growable; you can add or remove entries.
'France': 'Paris',
'Japan': 'Tokyo'
};
print("Original Map: $capitals\n");
'Germany': 'Berlin'
};
capitals.addAll(moreCapitals);
emptyMap.clear();
print("$key: $value");
});
});
print("\nMap entries:");
capitals.entries.forEach((entry) {
print("${entry.key}: ${entry.value}");
});
.putIfAbsent(): Adds a key-value pair only if the key doesn't already exist.
Class work
main() {
Map firstMap = {
"first": "Name",
"second": 20,
"thrid": 12.30,
// }
};
//
print("${firstMap["fourth"][1]}");
// s2
// Map secondMap = {
// "": "",
// "": "",
// "": ""
// };
// {
// "Name": "",
// "class": "",
// "Time": "",
// "Student": [],
// };
void main() {
int a = 10;
int b = 3;
// Addition (+)
int sum = a + b;
// Subtraction (-)
int difference = a - b;
// Multiplication (*)
int product = a * b;
// Division (/)
double quotient = a / b;
// Increment (++)
a++; // Increment a by 1
// Decrement (--)
b--; // Decrement b by 1
if (condition) {
} else {
void main() {
} else {
● Explanation:
○ If age is greater than or equal to 18, the first block (You are an
adult.) is executed.
○ Otherwise, the second block (You are a minor.) runs.
You can also place one if-else statement inside another if-else. This is called
nested if-else, and it allows for checking multiple conditions.
if (condition1) {
if (condition2) {
} else {
}
} else {
void main() {
} else {
Explanation:
● The code first checks if the score is 90 or above. If true, it prints "You got
an A grade."
● If not, it checks if the score is 80 or above. If true, it prints "You got a B
grade."
● If that is also false, it checks if the score is 70 or above and prints "You got
a C grade."
● If none of the conditions are met, the code falls to the last else block and
prints "You need to improve."
void main() {
} else {
} else {
} else {
● Explanation:
○ If the temperature is greater than 30, it first prints "It's a hot day."
○ Inside that block, if the temperature is also greater than 40, it prints
"Make sure to stay hydrated!"
○ Otherwise, it prints "Wear light clothes."
○ If the temperature is not greater than 30, it prints "It's a nice day."
Then it checks if the temperature is below 20 and prints "You might
want a jacket." If it's not below 20, it prints "Perfect weather for a
walk!"
Key Points:
Class work
main() {
// equal to ==
// int a = 11;
// if (a == 10) {
// print("yes the A value is 10");
// } else {
// print("the A vlaue is not 10");
// }
// int a = 9;
// if (a >= 10) {
// print("the a value is 10 or greater
then 10 ");
// } else {
// print("the a value is less then 10");
// }
// the a value is 10 or greater then 10
// the a value is less then 10
// not equal to !=
// String userStatus = "unauthrized";
// String userStatus = "authrized";
// if (userStatus != "unauthrized") {
// } else {
// }
// &&
// int a = 30;
// String b = "Passed";
// if (a >= 80 && b == "Passed") {
// }
// else{
// print("this student marks is not
great");
// //this student marks is not great
// }
// || or
// int b = 40;
// String c = "NotPass";
// }
// else{
// print("this student not passed");
// //this student not passed
// }
//
///////////////////////////////////////////
////if else in side first ( if )
// int a = 11;
// String b = "userlogin";
// List c = ["s1", "s2", "s3", "s4",
"s5"];
// if (a == 10) {
// if (b == "userlogin") {
// if (c.length == 5) {
// nested if else
// nested if else
// int score = 70;
// }
// } else if (score >= 80) {
// print("You got a B grade.");
// } else if (score >= 70) {
// print("You got a C grade.");
// // You got a C grade.
// } else {
// print("You need to improve.");
// //You need to improve.
// }
}
LOOPS in dart
In Dart, loops allow you to execute a block of code multiple times. There are three
commonly used loop structures: for, for-in, and forEach. Let's explore each
one.
1. for Loop
A for loop is used when you know how many times you want to run a block of
code. It consists of three parts:
void main() {
// Loop from 1 to 5
for (int i = 1; i <= 5; i++) {
print("Iteration $i");
}
}
Explanation:
if (number % 2 == 0)
{ print("$number is even"); }
else { print("$number is odd"); }
2. for-in Loop
The for-in loop is used to iterate over elements in a collection like a list, set, or map.
It's easier to use when you just want to access each element directly without worrying
about the index or length of the collection.
Explanation:
● The for-in loop automatically goes through each element in the fruits list
and assigns it to fruit.
● It prints "Apple", "Banana", and "Cherry" one by one.
3. forEach Loop
The forEach method is another way to iterate over collections, and it's typically used
with functions. It executes a function for each element in the collection.
collection.forEach((element) {
// Code to execute for each element
});
void main() {
List<int> numbers = [10, 20, 30];
Explanation:
● The forEach method goes through each element in the numbers list and
executes the function (which prints each number).
● It prints 10, 20, and 30.
Summary:
● for loop: Best when you need full control over the loop index and condition.
● for-in loop: Ideal for iterating over collections without needing the index.
● forEach loop: A clean way to apply a function to every element in a collection.
These loops are all useful in different situations, and Dart gives you the flexibility to choose the
best one for your task.
Class work
import 'dart:developer';
main() {
////////////////////// 1
// List num = [];
///////////////////// 2
// }
//////////////// 3
// forIn loop
for (var a in fruits) {
print("Fruit: $a");
print(a);
}
// for
Functions:
returnType functionName(parameters) {
// Function body
Return Type: Specifies the data type the function will return. If no value is
returned, use void.
void main() {
// 1. Simple Function
print("Simple Function:");
sayHello();
// 2. Function with return type
print("Sum: $result");
greet("Alice", 25);
describe("John");
describe("John", 30);
introduce(name: "David");
orderPizza("Cheese");
orderPizza("Pepperoni", 3);
// 7. Anonymous Function
print("\nAnonymous Function:");
numbers.forEach((number) {
print("Number: $number");
});
// 8. Using a Class
print("\nUsing a Class:");
person.sayDetails();
car.displayInfo();
////////////////////////////////////////////////////////////
/
// Function Examples
// 1. Simple Function
void sayHello() {
print("Hello, Dart!");
}
// 2. Function with Return Type
return a + b;
if (age > 0) {
} else {
}
// 5. Function with Optional Named Parameters
if (age > 0) {
} else {
print("This is $name.");
//2
// nameFun("Atiq", 25);
// my name is Atiq and my age is 25
// nameFun("xyz", 19);
///3
// firstFunction(30, 50);
// here is lenght area 160
//4
//5
//6
forthFunction(name: "XYZ", age: 23);
// here is value of name XYZ and age 23
///////////2
nameFun(String name, int age) {
print("my name is $name and my age is $age");
}
////////////3
//5
////6
return a+b;
}
24.oct
main() {
//calling
// addNumber(a: 300, b: 20);
// // the a value is 300
// // and the b vlaue is 20
///
Let's go through each of these concepts one by one with examples in Dart:
Example:
dart
// Class definition
class Car {
int year = 0;
void displayInfo() {
void main() {
car1.brand = "Toyota";
car1.model = "Corolla";
car1.year = 2021;
car2.brand = "Honda";
car2.model = "Civic";
car2.year = 2022;
class Person {
String name;
int age;
// Constructor
Person(this.name, this.age);
// Method
void greet() {
}
2. Encapsulation
Encapsulation is the concept of hiding the internal details of an object and only
exposing the necessary methods and properties. In Dart, you can make a variable
private by prefixing it with an underscore (_).
Example:
class Counter {
void increment() {
_count++;
void reset() {
_count = 0;
}
counter.increment();
print(counter.count); // Output: 1
//// 2
class BankAccount {
// Constructor
BankAccount(this._accountHolderName, this._balance);
if (amount > 0) {
_balance += amount;
print("Deposited: \$${amount}");
_balance -= amount;
print("Withdrew: \$${amount}");
} else {
print("Insufficient balance");
void main() {
3. Inheritance
Inheritance allows one class (child class) to inherit the properties and methods of
another class (parent class).
Example:
// Constructor
Student(String name, int age, this.school);
// Method
void study() {
print('$name is studying at $school.');
}
}
// Parent class
class Animal {
void makeSound() {
}
}
@override
void strongSmell() {
void main() {
4. Polymorphism
Example:
dart
Copy code
class Animal {
void makeSound() {
@override
void makeSound() {
print("Dog is barking");
@override
void makeSound() {
print("Cat is meowing");
void main() {
Animal animal;
animal = Dog();
animal = Cat();
5. Abstraction
Abstraction allows us to hide the implementation details and show only the
functionality to the user. In Dart, you can achieve abstraction using abstract
classes.
● When you press the volume up button, you don’t care about the circuitry
inside the remote. You just care that it increases the volume.
● The complex details (like wiring and circuits) are hidden from you. You only
interact with the simple buttons.
Example:
// Abstract class
@override
void draw() {
print("Drawing a circle");
@override
void draw() {
print("Drawing a rectangle");
void main() {
Shape shape;
shape = Circle();
shape = Rectangle();
Summary:
1. Intentional Override: It clearly indicates to the reader (and the Dart
compiler) that this method is meant to replace the method in the parent
class.
2. Error Prevention: If you misspell the method name or have a mismatch in
method signature, the compiler will throw an error, preventing potential
bugs.
Flutter UI
Step 1: System Requirements
Before you begin, ensure that your system meets the following minimum requirements:
● Windows 10 or later
● Git for Windows
● At least 600 MB of disk space (excluding IDE/tools)
● USB driver for your Android device (if using Android)
○
○ This command checks your environment for any missing dependencies. Ensure
that all checkmarks are green or install any missing components.
Step 3: Install Android Studio (Optional for Android Device)
To use a physical Android device, you'll need Android Studio for the Android SDK and device
drivers.
In the Command Prompt or VS Code Terminal, run the following command to verify that your
device is detected:
bash
Copy code
flutter devices
○
○ Your connected Android device should appear in the list. If not, ensure that you
have installed the necessary USB drivers for your device.
In the bottom-right corner of VS Code, you should see your physical device listed as a target. If
not, run:
bash
Copy code
flutter devices
○
○ Ensure the device is selected in VS Code.
2. Run the App:
○ Press F5 or go to Run > Start Debugging to run the Flutter app on the
connected physical device.
Step 8: Troubleshooting
If you encounter any issues, run:
bash
Copy code
flutter doctor
● This command helps diagnose any missing dependencies or issues.
● If your physical device isn’t recognized:
○ Ensure USB Debugging is enabled.
○ Check if Google USB Driver is installed via SDK Manager.
○ Try changing the USB mode to File Transfer (MTP) on your Android device.
Flutter, initially released by Google in 2017, has undergone significant development over the
years. Here’s a brief overview of its history with notable version updates:
○
Updates for performance and memory management.
Metarial App.
MaterialApp is an extension of the generic top-level widget provided by Flutter
: WidgetsApp. WidgetsApp is a convenience widget that abstracts away several
features required for most mobile apps, such as setting up a navigator and using an app-wide
theme.
runApp(
MyApp(), //////////2
);
}
@override
Widget build(BuildContext context) {
// ...
return MaterialApp( ////////////4
title: 'App',
debugShowCheckedModeBanner: false,
theme: theme,
home: PageContainer(),
);
}
}
1. SafeArea
○ Description: A widget that insets its child to avoid system UI areas like the
notch, status bar, and bottom navigation.
○ Use Case: Use SafeArea to ensure that the UI elements are displayed within
safe bounds on devices with curved edges, notches, or status bars.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
@override
return MaterialApp(
home: SafeArea(
child: Scaffold(
),
),
);
}
2. Scaffold
○ Description: Provides a basic material design layout structure like an AppBar,
Drawer, FloatingActionButton, and BottomNavigationBar.
○ Use Case: Scaffold is typically the base for building any screen in a Flutter
app.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
@override
return MaterialApp(
home: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
),
);
}
3.
4. Text
○ Description: Used to display a string of text with various styles and
configurations.
○ Use Case: Text is the most commonly used widget for displaying labels, titles,
or other textual information.
dart
Copy code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
@override
return MaterialApp(
home: Scaffold(
body: Center(
child: Text(
'Hello, Flutter!',
),
),
),
);
5.
6. Center
○ Description: A widget that centers its child both horizontally and vertically within
its parent.
○ Use Case: Center is often used to centralize widgets, making the UI design
clean and balanced.
dart
Copy code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
@override
return MaterialApp(
home: Scaffold(
body: Center(
),
);
7.
8. AppBar
○ Description: A material design app bar with optional actions, titles, and icons.
○ Use Case: AppBar is used as the top app bar on each screen, often containing
the screen title, navigation icons, and actions.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
@override
return MaterialApp(
home: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
),
],
),
),
);
9. }
Safearea
Scaffold
Text
center
appbar.
Flutter Widgets 2-Week Study Plan
Day Widgets Topics & Notes
Week
1
Day 2 AppBar, Center, Text AppBar (top bar), Center (centering widget), Text (text
display); create an app with title and centered text.
Day 3 Container, Padding, Align Container (box styling), Padding (spacing), Align
(alignment); explore layout adjustments and spacing
with a styled box.
Day 4 Row, Column, SizedBox Row & Column (layout), SizedBox (spacer); arrange
widgets in rows and columns and manage spacing.
Day 5 Icon, Image, CircleAvatar Icon (display icons), Image (display images),
CircleAvatar (circular image); display an avatar with
icons and images.
Day 6 ListTile, Divider, Card ListTile (list items), Divider (separator), Card (material
card); create a list with separators and cards.
Week
2
Day 8 TextField, Form, Checkbox TextField (input), Form (form validation), Checkbox
(checkbox); create a simple form with input fields and
checkboxes.
Day 9 Switch, Slider, RadioListTile Switch (toggle), Slider (range selector), RadioListTile
(radio button); build a settings screen with switches
and sliders.
The Container widget is one of the most versatile and commonly used widgets in Flutter. It
can be used for styling, positioning, and adding spacing or padding around widgets.
● Properties:
○ color: Sets the background color of the container.
○ margin: Adds space around the container.
○ padding: Adds space inside the container.
○ width & height: Sets the container’s size.
○ alignment: Aligns child widgets within the container.
○ decoration: Adds styling like borders, rounded corners, and shadows.
Example:
dart
Copy code
Container(
width: 150,
height: 100,
color: Colors.blue,
alignment: Alignment.center,
child: Text(
"Hello",
style: TextStyle(color: Colors.white),
),
);
In this example:
2. Padding
The Padding widget provides space around a child widget by specifying padding on one or
more sides. It is generally used to avoid having a widget directly touch another widget or the
edges of the screen.
● Properties:
○ padding: Accepts an EdgeInsets value to specify padding. Commonly used
options include:
■ EdgeInsets.all(double value): Adds equal padding to all sides.
■ EdgeInsets.symmetric(horizontal: double, vertical:
double): Adds padding horizontally or vertically.
■ EdgeInsets.only(left: double, top: double, right:
double, bottom: double): Adds padding to specific sides.
Example:
dart
Copy code
Padding(
padding: EdgeInsets.all(20),
child: Text("This text has padding around it."),
);
In this example:
● The text widget will have a padding of 20 pixels on all sides, creating space around the
text.
3. Align
The Align widget is used to align its child within itself based on alignment coordinates, which
can be positioned anywhere within the parent.
● Properties:
○ alignment: Accepts an Alignment value to specify where the child should be
positioned. Some common values are:
■ Alignment.center: Centers the child widget.
■ Alignment.topLeft: Positions the child at the top left.
■ Alignment.bottomRight: Positions the child at the bottom right.
○ widthFactor & heightFactor: Scale the Align widget based on the child widget's
size.
Example:
dart
Copy code
Align(
alignment: Alignment.bottomRight,
child: Icon(
Icons.star,
size: 50,
color: Colors.yellow,
),
);
In this example:
● The Align widget positions the star icon at the bottom right corner.
Below is an example of how Container, Padding, and Align can work together to create a
simple, styled layout.
dart
Copy code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
In this example:
void main() {
runApp(MyApp());
}
FloatingActionButton
FloatingActionButton (FAB) is a circular button that floats above the UI, usually positioned
at the bottom right of the screen. It’s typically used for primary actions, like adding a new item or
starting a new activity.
● Properties:
○ onPressed: A callback function triggered when the button is pressed.
○ child: A widget (usually an icon) to display on the FAB.
○ backgroundColor: Sets the background color of the button.
○ tooltip: Shows a tooltip on a long press.
Example:
dart
Copy code
FloatingActionButton(
onPressed: () {
print("FAB pressed");
},
backgroundColor: Colors.blue,
tooltip: "Add Item",
child: Icon(Icons.add),
);
This FAB displays a + icon and executes the callback when tapped. It’s commonly used within a
Scaffold widget.
2. ElevatedButton
ElevatedButton is a standard button that elevates (gains a shadow) when pressed, giving it
a 3D look. It's used for primary actions, where you want the button to stand out against the
background.
● Properties:
○ onPressed: A callback function triggered when the button is pressed.
○ child: Text or other widgets to display inside the button.
○ style: Allows customization of the button’s appearance (background color,
padding, shape, etc.).
Example:
dart
Copy code
ElevatedButton(
onPressed: () {
print("ElevatedButton pressed");
},
style: ElevatedButton.styleFrom(
primary: Colors.green, // Background color
onPrimary: Colors.white, // Text color
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), // Rounded corners
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 15),
),
child: Text("Click Me"),
);
In this example, the button has customized padding, rounded corners, and a green background
color with white text.
3. InkWell
InkWell is a touchable area that shows a ripple effect on press. Unlike the other button
widgets, InkWell is more flexible since it can be wrapped around any widget to make it
clickable.
● Properties:
○ onTap: A callback function triggered when the InkWell is tapped.
○ child: The widget inside InkWell that will be interactive.
○ splashColor: Sets the ripple effect color when the InkWell is pressed.
○ borderRadius: Adds rounded corners to the ripple effect.
Example:
dart
Copy code
InkWell(
onTap: () {
print("InkWell tapped");
},
splashColor: Colors.blue.withOpacity(0.3),
borderRadius: BorderRadius.circular(10), // Rounded ripple effect
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.lightBlueAccent,
borderRadius: BorderRadius.circular(10),
),
child: Text("Tap Me"),
),
);
In this example:
The Card widget in Flutter is a material design widget that provides a way to display information
in a rectangular box with rounded corners and an optional shadow effect. It’s commonly used to
highlight content within a container, making it stand out on the screen, such as displaying user
profiles, product details, or other individual data items.
Copy code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
@override
return MaterialApp(
home: Scaffold(
appBar: AppBar(
),
body: Center(
child: Card(
margin: EdgeInsets.all(16),
shape: RoundedRectangleBorder(
child: Padding(
padding: EdgeInsets.all(16),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"John Doe",
),
Text("Software Developer"),
],
),
],
),
),
),
),
),
);
● elevation: Adds a shadow to make the card look lifted. Higher values increase the
shadow.
● margin: Adds space around the card so it doesn’t touch other elements or the screen
edge directly.
● shape: Specifies the card's shape. Here, RoundedRectangleBorder with
borderRadius adds rounded corners.
● Padding inside the Card: Adds internal spacing, so content isn’t directly touching the
edges of the card.
● Row and Column: Used to organize the icon and text within the card.
Additional Customizations
1.
borderRadius: BorderRadius.circular(10),
2.
The Card widget provides a flexible, easy-to-use layout tool for highlighting individual items.
This widget, combined with ListView or GridView, can make lists of Cards that work well for
complex apps like e-commerce and social media applications.
import
'package:flutter/material.dart';
const testingWidget({super.key});
@override
@override
void didChangeDependencies() {
// TODO: implement
didChangeDependencies
super.didChangeDependencies();
print("here is my
didChangeDependencies");
}
@override
void initState() {
super.initState();
print("here is my initState");
int counter = 0;
@override
return Scaffold(
body: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Text(
style: TextStyle(fontSize:
24),
),
TextButton(
onPressed: () {
setState(() {
counter++;
print("here is
counter value $counter");
});
},
child: Text("Increment
Data"))
],
),
);
}
example demonstrates:
1. initState:
● Called when the widget is first created
● Used for one-time initialization
● Initialize controllers and subscriptions
● Make initial API calls
2. didChangeDependencies:
● Called when an InheritedWidget that this widget depends on changes
● Access context-dependent resources
● Update data based on new dependencies
3. setState:
● Used to update the widget's state
● Triggers a rebuild of the widget
● Updates UI based on new state
4. dispose:
● Called when the widget is removed from the tree
● Clean up resources to prevent memory leaks
● Cancel subscriptions and close controllers
dart
import
'package:flutter/material.dart';
class ThemeSwitcherPage extends
StatefulWidget {
@override
_ThemeSwitcherPageState createState()
=> _ThemeSwitcherPageState();
@override
return Scaffold(
appBar: AppBar(
backgroundColor: isDarkMode ?
Colors.black : Colors.blue,
actions: [
IconButton(
icon: Icon(isDarkMode ?
Icons.wb_sunny : Icons.nights_stay),
onPressed: () {
setState(() {
isDarkMode =
!isDarkMode; // Toggle theme mode
});
},
),
],
),
body: Container(
color: isDarkMode ?
Colors.black : Colors.white, //
Background color
alignment: Alignment.center,
child: Text(
"Hello, Flutter!",
style: TextStyle(
fontSize: 24,
color: isDarkMode ?
Colors.white : Colors.black, // Text
color
),
),
),
);
}
Explanation
1. State Variable (isDarkMode): Tracks whether the current theme is dark or light. Initially,
it's set to false (light mode).
2. AppBar: The AppBar includes a toggle button (sun/moon icon) in the actions list to
switch themes.
○ The icon changes based on the current theme (Icons.wb_sunny for light and
Icons.nights_stay for dark).
3. setState: When the icon button is pressed, setState() toggles isDarkMode,
updating the UI.
4. Body:
○ The Container background color changes based on the theme.
○ The Text widget color is also dynamically updated to ensure readability in both
themes (white text for dark mode, black text for light mode).
This code provides a simple, responsive way to switch themes within a single screen using
setState.
ListView in Flutter
ListView is a scrollable list of widgets, commonly used to display data in a vertical list.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('ListView Example')),
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]),
);
},
),
);
}
}
Properties of ListView
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('GridView Example')),
body: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, // Number of columns
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemCount: items.length,
itemBuilder: (context, index) {
return Card(
color: Colors.amber,
child: Center(child: Text(items[index])),
);
},
),
);
}
}
Properties of GridView
class Product {
final String productName;
final String image;
final double price;
final String description;
Product({
required this.productName,
required this.image,
required this.price,
required this.description,
});
}
You can create a list of products in your main widget or in a separate file.
List<Product> products = [
Product(
productName: 'Product 1',
image: 'https://via.placeholder.com/150',
price: 29.99,
description: 'This is the description for Product 1.',
),
Product(
productName: 'Product 2',
image: 'https://via.placeholder.com/150',
price: 19.99,
description: 'This is the description for Product 2.',
),
Product(
productName: 'Product 3',
image: 'https://via.placeholder.com/150',
price: 39.99,
description: 'This is the description for Product 3.',
),
Product(
productName: 'Product 4',
image: 'https://via.placeholder.com/150',
price: 49.99,
description: 'This is the description for Product 4.',
),
];
Now, we can create the main widget that uses ListView.builder to display the list of
products.
import 'package:flutter/material.dart';
1. Basic Properties
dart
Copy code
TextField(
decoration: InputDecoration(
),
keyboardType: TextInputType.text, // Standard text
keyboard
);
2. Styling Properties
dart
Copy code
TextField(
decoration: InputDecoration(
),
style: TextStyle(
fontSize: 18,
color: Colors.black,
),
cursorColor: Colors.blue,
cursorWidth: 2.0,
textAlign: TextAlign.left,
);
3. Behavioral Properties
dart
Copy code
TextField(
onChanged: (text) {
},
onSubmitted: (text) {
},
enabled: true, // Set to false to disable the field
);
dart
Copy code
TextField(
minLines: 1,
);
5. Focus Management Properties
dart
Copy code
TextField(
);
6. Advanced Properties
dart
Copy code
TextField(
textCapitalization: TextCapitalization.words, //
Capitalizes each word
inputFormatters: [LengthLimitingTextInputFormatter(10)],
// Limits length
);
Full Example
dart
Copy code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
return MaterialApp(
home: Scaffold(
body: Padding(
child: MyTextField(),
),
),
);
@override
}
class _MyTextFieldState extends State<MyTextField> {
TextEditingController _controller =
TextEditingController();
@override
void dispose() {
_controller.dispose();
_focusNode.dispose();
super.dispose();
@override
return TextField(
controller: _controller,
focusNode: _focusNode,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(Icons.clear),
),
border: OutlineInputBorder(),
),
keyboardType: TextInputType.text,
obscureText: false,
cursorColor: Colors.green,
cursorWidth: 2.0,
textAlign: TextAlign.left,
onChanged: (text) {
},
onSubmitted: (text) {
},
maxLength: 30,
maxLines: 1,
autofocus: false,
textCapitalization: TextCapitalization.sentences,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp("[a-zA-Z0-9
]")),
LengthLimitingTextInputFormatter(30),
],
);
In this example:
dart
Copy code
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NewScreen()),
);
Navigator.pop(context);
Use Case: Ideal for one-time navigation without the need to manage a specific route name.
2. Named Routes
Named routes allow us to define routes globally, making it easier to manage and navigate to
various screens without specifying each screen’s details repeatedly.
Use Case: When you have multiple screens and want an organized way to reference each one.
Generated routes are helpful for handling complex routing scenarios, especially when dynamic
arguments are passed to screens.
Example:
dart
Copy code
void main() {
runApp(MaterialApp(
onGenerateRoute: (settings) {
if (settings.name == '/second') {
final String message = settings.arguments as String;
return MaterialPageRoute(
builder: (context) => SecondScreen(message: message),
);
}
return null; // Default route
},
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
},
));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Second Screen")),
body: Center(
child: Text(message),
),
);
}
}
Use Case: When needing to pass data with routes or manage routes dynamically.
Using pushReplacement, you replace the current screen with a new one, removing the
previous screen from the stack.
dart
Copy code
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => NewScreen()),
);
Use Case: Common in login flows, where after logging in, the login screen is replaced by the
home screen.
Navigator.pushAndRemoveUntil pushes a new route and removes all previous routes from
the stack until a specific condition is met.
dart
Copy code
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
(route) => false, // Removes all previous routes
);
Use Case: Useful for clearing the stack after actions like logout, where you want to take the
user back to the home screen without a back option.
Custom transitions allow you to modify the default animation between screens, such as adding
a fade or slide effect.
return SlideTransition(
position: offsetAnimation,
child: child,
);
},
),
);
Summary
Routing Method Use Case
Navigator.push/p Simple navigation to new screens and back.
op
Each approach suits different navigation needs, allowing Flutter developers to build responsive
and organized app flows.
In Flutter, you can use Radio, Checkbox, and Switch widgets to create radio buttons, check
buttons, and switch buttons, respectively. To manage their states, you can use setState() to
update the UI whenever the value of these widgets changes.
1. Radio Button
The Radio widget in Flutter lets you create mutually exclusive options where only one can be
selected at a time. To use it, define a common variable to hold the selected value and update it
using setState().
dart
Copy code
import 'package:flutter/material.dart';
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Radio Button
Text(
'Radio Button:',
style: TextStyle(fontSize: 18, fontWeight:
FontWeight.bold),
),
Row(
children: [
Radio(
value: 1,
groupValue: _selectedRadio,
onChanged: _handleRadioValueChange,
),
Text("Option 1"),
Radio(
value: 2,
groupValue: _selectedRadio,
onChanged: _handleRadioValueChange,
),
Text("Option 2"),
],
),
// Checkbox
SizedBox(height: 20),
Text(
'Checkbox:',
style: TextStyle(fontSize: 18, fontWeight:
FontWeight.bold),
),
Row(
children: [
Checkbox(
value: _isChecked,
onChanged: (bool? value) {
setState(() {
_isChecked = value!;
});
},
),
Text("Check this box"),
],
),
// Switch
SizedBox(height: 20),
Text(
'Switch:',
style: TextStyle(fontSize: 18, fontWeight:
FontWeight.bold),
),
Row(
children: [
Switch(
value: _isSwitched,
onChanged: (bool value) {
setState(() {
_isSwitched = value;
});
},
),
Text("Switch this on/off"),
],
),
],
),
);
}
}
Explanation of Code
Provider setState
Designed for managing and sharing state across Useful for managing local state
different widgets in the widget tree. within a single widget.
Makes it easy to separate business logic from UI. Leads to tightly coupled UI and logic.
Can be optimized to reduce unnecessary rebuilds. Rebuilds the entire widget tree for
each change.
Works well for complex applications with shared data. Better for small applications with
simple state.
Below is an example of implementing Switch, Checkbox, and Radio buttons using Provider
to manage state globally.
yaml
Copy code
dependencies:
provider: ^6.0.0
dart
Copy code
import 'package:flutter/foundation.dart';
String? selectedRadioValue;
void toggleSwitch() {
isSwitched = !isSwitched;
notifyListeners();
notifyListeners();
selectedRadioValue = value;
notifyListeners();
dart
Copy code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
child: MyApp(),
),
);
@override
return MaterialApp(
home: Scaffold(
body: SelectionExample(),
),
);
dart
Copy code
@override
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Switch
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Switch: '),
Switch(
value: selectionProvider.isSwitched,
),
],
),
// Checkbox
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Checkbox: '),
Checkbox(
value: selectionProvider.isChecked,
onChanged: selectionProvider.toggleCheckbox,
),
],
),
// Radio Buttons
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Radio 1'),
Radio<String>(
groupValue: selectionProvider.selectedRadioValue,
onChanged: selectionProvider.selectRadio,
),
Text('Radio 2'),
Radio<String>(
groupValue: selectionProvider.selectedRadioValue,
onChanged: selectionProvider.selectRadio,
),
],
),
// Display the selections
Padding(
child: Column(
children: [
Text('Checkbox is ${selectionProvider.isChecked ?
'Checked' : 'Unchecked'}'),
Text('Selected Radio:
${selectionProvider.selectedRadioValue ?? 'None'}'),
],
),
),
],
);
Explanation of Code:
1. SelectionProvider Class: This ChangeNotifier class holds the state for Switch,
Checkbox, and Radio button. Each state-changing method calls
notifyListeners() to update any listening widgets.
2. ChangeNotifierProvider: Wraps the MyApp widget to provide the
SelectionProvider instance throughout the widget tree.
3. Switch, Checkbox, Radio Widgets: These widgets update state using methods in
SelectionProvider, allowing for centralized state management.
By using Provider, you can efficiently manage app-wide state updates without manually
passing data down through constructors, making your code cleaner and more scalable.
Determinate Progress
For determinate progress, you specify a value between 0.0 (0%) and 1.0 (100%).
dart
Copy code
@override
void initState() {
super.initState();
_startProgress();
void _startProgress() {
Future.delayed(Duration(seconds: 1), () {
setState(() {
});
});
@override
return Center(
child: Padding(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: 20),
LinearProgressIndicator(value: _progressValue), //
Determinate progress bar
SizedBox(height: 10),
Text('${(_progressValue * 100).round()}%'),
],
),
),
);
Explanation of Code
class ImagesPath {
static String kOnboarding1 = 'assets/images/onboarding1.png';
static String kOnboarding2 = 'assets/images/onBoarding2.png';
static String kOnboarding3 = 'assets/images/onBoarding3.png';
}
class AppColor {
static Color kPrimary = const Color(0XFF1460F2);
static Color kWhite = const Color(0XFFFFFFFF);
static Color kOnBoardingColor = const Color(0XFFFEFEFE);
static Color kGrayscale40 = const Color(0XFFAEAEB2);
static Color kGrayscaleDark100 = const Color(0XFF1C1C1E);
}
@override
State<OnBoardingScreen> createState() => _OnBoardingScreenState();
}
@override
State<PrimaryButton> createState() => _PrimaryButtonState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
_controller.forward().then((_) {
_controller.reverse();
});
widget.onTap();
},
child: ScaleTransition(
scale: _tween.animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeOut,
reverseCurve: Curves.easeIn,
),
),
child: Card(
elevation: widget.elevation ?? 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(widget.borderRadius!),
),
child: Container(
height: widget.height ?? 55,
alignment: Alignment.center,
width: widget.width ?? double.maxFinite,
decoration: BoxDecoration(
color: widget.bgColor,
borderRadius: BorderRadius.circular(widget.borderRadius!),
),
child: Text(
widget.text,
style: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(
color: widget.textColor,
fontWeight: FontWeight.w500,
fontSize: widget.fontSize),
),
),
),
),
);
}
}
@override
State<OnBoardingCard> createState() => _OnBoardingCardState();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 23),
child: Column(
children: [
Text(
onBoardingModel.title,
textAlign: TextAlign.center,
style: GoogleFonts.plusJakartaSans(
fontSize: 24,
fontWeight: FontWeight.bold,
color: AppColor.kGrayscaleDark100,
).copyWith(fontSize: 24),
),
const SizedBox(
height: 16,
),
Text(
onBoardingModel.description,
textAlign: TextAlign.center,
style: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(color: AppColor.kGrayscale40, fontSize: 14),
),
],
),
);
}
}
class OnBoarding {
String title;
String description;
String image;
OnBoarding({
required this.title,
required this.description,
required this.image,
});
}
List<OnBoarding> onBoardinglist = [
OnBoarding(
title: ' Can be accessed from anywhere at any time',
image: ImagesPath.kOnboarding1,
description:
'The essential language learning tools and resources you need to seamlessly transition into
mastering a new language',
),
OnBoarding(
title: 'Offers a dynamic and interactive experience',
image: ImagesPath.kOnboarding2,
description:
'Engaging features including test, story telling, and conversations that motivate and
inspire language learners to unlock their full potential'),
OnBoarding(
title: "Experience the Premium Features with Our App",
image: ImagesPath.kOnboarding3,
description:
'Updated TalkGpt with premium materials and a dedicated following, providing language
learners with immersive content for effective learning'),
];
//screen 2
class ImagesPath {
static String kGoogleIcon = 'assets/images/googleSymbol.png';
}
class AppColor {
static Color kPrimary = const Color(0XFF1460F2);
static Color kWhite = const Color(0XFFFFFFFF);
static Color kBackground = const Color(0XFFFAFAFA);
static Color kGrayscaleDark100 = const Color(0XFF1C1C1E);
static Color kLine = const Color(0XFFEBEBEB);
static Color kBackground2 = const Color(0XFFF6F6F6);
static Color kGrayscale40 = const Color(0XFFAEAEB2);
}
👋
Text(
'Hi, Welcome Back! ',
textAlign: TextAlign.center,
style: GoogleFonts.plusJakartaSans(
fontSize: 20,
fontWeight: FontWeight.w600,
).copyWith(color: AppColor.kGrayscaleDark100, fontSize: 20),
),
const SizedBox(height: 8),
Text(
'We happy to see you. Sign In to your account',
textAlign: TextAlign.center,
style: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(color: AppColor.kGrayscale40, fontSize: 14),
),
const SizedBox(height: 36),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Email',
style: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(
color: AppColor.kGrayscaleDark100,
fontWeight: FontWeight.w600,
fontSize: 14),
),
const SizedBox(
height: 8,
),
PrimaryTextFormField(
borderRadius: BorderRadius.circular(24),
hintText: '[email protected]',
controller: emailC,
width: 327,
height: 52)
],
),
const SizedBox(
height: 16,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Password',
style: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(
color: AppColor.kGrayscaleDark100,
fontWeight: FontWeight.w600,
fontSize: 14),
),
const SizedBox(height: 8),
PasswordTextField(
borderRadius: BorderRadius.circular(24),
hintText: 'Password',
controller: passwordC,
width: 327,
height: 52)
],
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
PrimaryTextButton(
onPressed: () {},
title: 'Forgot Password?',
textStyle: const TextStyle(),
)
],
),
const SizedBox(height: 32),
Column(
children: [
PrimaryButton(
elevation: 0,
onTap: () {},
text: 'LogIn',
bgColor: AppColor.kPrimary,
borderRadius: 20,
height: 46,
width: 327,
textColor: AppColor.kWhite,
fontSize: 14,
),
const SizedBox(
height: 24,
),
Padding(
padding: const EdgeInsets.only(left: 4),
child: CustomRichText(
title: 'Don’t have an account?',
subtitle: ' Create here',
onTab: () {},
subtitleTextStyle: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(
color: AppColor.kPrimary,
fontWeight: FontWeight.w600,
fontSize: 14),
),
)
],
),
const SizedBox(height: 32),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 45),
child: Column(
children: [
const DividerRow(title: 'Or Sign In with'),
const SizedBox(height: 24),
SecondaryButton(
height: 56,
textColor: AppColor.kGrayscaleDark100,
width: 280,
onTap: () {},
borderRadius: 24,
bgColor: AppColor.kBackground.withOpacity(0.3),
text: 'Continue with Google',
icons: ImagesPath.kGoogleIcon),
],
),
),
const SizedBox(height: 50),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 40),
child: TermsAndPrivacyText(
title1: ' By signing up you agree to our',
title2: ' Terms ',
title3: ' and',
title4: ' Conditions of Use',
),
),
const SizedBox(height: 24),
]),
),
),
),
);
}
}
@override
State<SecondaryButton> createState() => _SecondaryButtonState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
_controller.forward().then((_) {
_controller.reverse();
});
widget.onTap();
},
child: ScaleTransition(
scale: _tween.animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeOut,
reverseCurve: Curves.easeIn,
),
),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 17),
height: widget.height,
alignment: Alignment.center,
width: widget.width,
decoration: BoxDecoration(
color: widget.bgColor,
border: Border.all(color: AppColor.kLine),
borderRadius: BorderRadius.circular(widget.borderRadius),
),
child: Row(
children: [
Image.asset(widget.icons, width: 23.85, height: 23.04),
const SizedBox(width: 12),
Text(widget.text,
style: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(
color: widget.textColor,
fontSize: 14,
fontWeight: FontWeight.w600,
)),
],
),
),
),
);
}
}
@override
State<PrimaryButton> createState() => _PrimaryButtonState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
_controller.forward().then((_) {
_controller.reverse();
});
widget.onTap();
},
child: ScaleTransition(
scale: _tween.animate(
CurvedAnimation(
parent: _controller,
curve: Curves.easeOut,
reverseCurve: Curves.easeIn,
),
),
child: Card(
elevation: widget.elevation ?? 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(widget.borderRadius!),
),
child: Container(
height: widget.height ?? 55,
alignment: Alignment.center,
width: widget.width ?? double.maxFinite,
decoration: BoxDecoration(
color: widget.bgColor,
borderRadius: BorderRadius.circular(widget.borderRadius!),
),
child: Text(
widget.text,
style: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(
color: widget.textColor,
fontWeight: FontWeight.w500,
fontSize: widget.fontSize),
),
),
),
),
);
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPressed,
child: Text(
title,
style: textStyle,
),
);
}
}
return Container(
width: widget.width,
height: widget.height,
decoration: BoxDecoration(
borderRadius: widget.borderRadius,
color: AppColor.kBackground2,
border: Border.all(color: AppColor.kLine)),
child: TextFormField(
obscureText: _obscureText,
controller: widget.controller,
style: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(
color: AppColor.kGrayscaleDark100,
),
decoration: InputDecoration(
filled: true,
contentPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 15),
suffixIcon: IconButton(
icon: Icon(
_obscureText
? Icons.visibility_outlined
: Icons.visibility_off_outlined,
color: AppColor.kGrayscaleDark100,
size: 17,
),
onPressed: () {
setState(() {
_obscureText = !_obscureText;
});
},
),
hintText: widget.hintText,
hintStyle: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(
color: AppColor.kGrayscale40,
fontWeight: FontWeight.w600,
fontSize: 14),
enabledBorder: enabledBorder,
focusedBorder: focusedBorder,
errorBorder: errorBorder,
focusedErrorBorder: focusedErrorBorder,
)),
);
}
}
return Container(
width: width,
height: height,
decoration: BoxDecoration(
borderRadius: borderRadius,
color: AppColor.kBackground,
border: Border.all(color: AppColor.kLine)),
child: TextFormField(
controller: controller,
maxLines: maxLines,
keyboardType: keyboardType,
style: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(
color: AppColor.kGrayscaleDark100,
),
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 15),
filled: true,
hintText: hintText,
hintStyle: GoogleFonts.plusJakartaSans(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColor.kWhite)
.copyWith(
color: AppColor.kGrayscaleDark100,
fontWeight: FontWeight.w600,
fontSize: 14),
prefixIcon: prefixIcon,
prefixIconColor: prefixIconColor,
enabledBorder: enabledBorder,
focusedBorder: focusedBorder,
errorBorder: errorBorder,
focusedErrorBorder: focusedErrorBorder,
),
onChanged: onChanged,
inputFormatters: inputFormatters,
onTapOutside: onTapOutside,
),
);
}
}
class PlanetCard {
final String title;
final String image;
@override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue[50]!, Colors.blueAccent, Colors.purple[300]!],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
),
);
}
}
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
offset: const Offset(0, 26),
blurRadius: 50,
spreadRadius: 0,
color: Colors.white.withOpacity(.25)),
]),
child: TextField(
controller: textController,
onChanged: (value) {
//Do something wi
},
decoration: InputDecoration(
prefixIcon: const Icon(
Icons.search,
color: Color(0xff4338CA),
),
filled: true,
fillColor: Colors.blue[50],
hintText: hintText,
hintStyle:
const TextStyle(color: Colors.grey, fontWeight: FontWeight.w300),
contentPadding:
const EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(50.0)),
),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.white, width: 1.0),
borderRadius: BorderRadius.all(Radius.circular(50.0)),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.white, width: 2.0),
borderRadius: BorderRadius.all(Radius.circular(50.0)),
),
),
),
);
}
}
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(top: 50.0, left: 15.0, right: 15.0),
height: 190,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.0),
boxShadow: [
BoxShadow(
color: Colors.indigo[800]!.withOpacity(.15),
offset: const Offset(0, 10),
blurRadius: 0,
spreadRadius: 0,
)
],
gradient: const RadialGradient(
colors: [Color(0xff0E5C9E), Color(0xff031965)],
focal: Alignment.topCenter,
radius: .85,
)),
padding: const EdgeInsets.all(25.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("Let's Explore",
style: TextStyle(
color: Colors.white,
fontSize: 32,
height: 1.25,
fontFamily: "BigBottom",
fontWeight: FontWeight.bold)),
Text("Travel the galaxy",
style: TextStyle(
color: Colors.white.withOpacity(.75),
fontSize: 14,
)),
],
),
Image.network(
"https://firebasestorage.googleapis.com/v0/b/flutterbricks-public.appspot.com/o/Planets%2Fbox-
1.png?alt=media&token=4b0259b3-8bc3-4ab7-9157-a61baacd3846",
width: 50,
)
],
),
const SizedBox(height: 15.0),
SearchInput(
textController: TextEditingController(),
hintText: "Search",
),
const SizedBox(height: 5.0),
],
),
);
}
}
@override
Widget build(BuildContext context) {
return Center(
child: GestureDetector(
onTap: () => Navigator.push(
context,
PageRouteBuilder(
transitionDuration: const Duration(milliseconds: 700),
pageBuilder: (_, __, ___) => PlanetHero(
planetCard: planetCard,
))),
child: Container(
margin: const EdgeInsets.only(top: 15.0, left: 15.0, right: 15.0),
width: 250,
height: 290,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.0),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(.05),
offset: const Offset(0, 10),
blurRadius: 0,
spreadRadius: 0,
)
],
gradient: const RadialGradient(
colors: [Color(0xff0E5C9E), Color(0xff031965)],
focal: Alignment.topCenter,
radius: .85,
)),
padding: const EdgeInsets.all(15.0),
child: Column(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100.0),
boxShadow: [
BoxShadow(
color: Colors.blue.withOpacity(.3),
offset: const Offset(0, 5),
blurRadius: 25,
spreadRadius: 0,
)
],
),
child: Hero(
tag: planetCard.image,
child: Image.network(
planetCard.image,
width: 170,
),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(planetCard.title,
style: const TextStyle(
color: Colors.white,
fontFamily: "BigBottom",
fontSize: 22)),
Text("About planet",
style: TextStyle(
color: Colors.white.withOpacity(.45),
fontSize: 14)),
],
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100.0),
gradient: const LinearGradient(
colors: [Colors.yellow, Colors.orange],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
),
child: const Icon(
Icons.keyboard_arrow_right,
color: Colors.white,
size: 30,
)),
],
),
),
],
),
),
),
);
}
}
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(top: 25.0, left: 15.0, right: 15.0),
height: 155,
padding: const EdgeInsets.all(25.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40.0),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(.1),
offset: const Offset(0, 10),
blurRadius: 0,
spreadRadius: 0,
)
],
gradient: const RadialGradient(
colors: [Color(0xff0E5C9E), Color(0xff031965)],
focal: Alignment.topCenter,
radius: 1.25,
)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
planetCard.image,
width: 50,
),
const SizedBox(
width: 15,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
planetCard.title,
style: const TextStyle(
fontFamily: "BigBottom",
color: Colors.white,
fontSize: 22),
),
],
),
const SizedBox(height: 10),
Text(
"""Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas vel sint commodi!""",
maxLines: 3,
style: TextStyle(
color: Colors.white.withOpacity(.75), fontSize: 14),
),
],
),
),
],
),
);
}
}
@override
State<PlanetHero> createState() => _PlanetHeroState();
}
@override
State<PlanetCardWidget> createState() => _PlanetCardWidgetState();
}
"https://firebasestorage.googleapis.com/v0/b/flutterbricks-public.appspot.com/o/Planets%2Fplan
et1.png?alt=media&token=b275a4f8-1abb-4e69-b218-b796cf144352",
width: 63,
),
Image.network(
"https://firebasestorage.googleapis.com/v0/b/flutterbricks-public.appspot.com/o/Planets%2Fplan
et2.png?alt=media&token=6dc4d3f4-09d8-47fc-8639-b19eba6e3ed5",
width: 63,
),
Image.network(
"https://firebasestorage.googleapis.com/v0/b/flutterbricks-public.appspot.com/o/Planets%2Fplan
et3.png?alt=media&token=497fbf32-30c7-4ce5-ae0a-c387d517aa1a",
width: 63,
),
Image.network(
"https://firebasestorage.googleapis.com/v0/b/flutterbricks-public.appspot.com/o/Planets%2Fsola
r.png?alt=media&token=50992182-d228-484a-b6a7-ffab59023027",
width: 63,
),
],
)
],
),
),
],
),
);
}
}
Backend FIrebase
Connecting a Flutter app to Firebase involves configuring Firebase in your project and adding
the necessary Firebase packages. Below are the steps to integrate Firebase with a Flutter app,
using Firebase Authentication as an example.
1. Replace ^latest_version with the current plugin versions from pub.dev.
2.
3. Update Android Configuration:
○
○
4. Update iOS Configuration:
○
Run:
bash
Copy code
cd ios
pod install
○
1.
Step 5: Add Firebase Authentication (Optional)
Authentication Example Code: Add the following code to register and sign in users:
dart
Copy code
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Firebase Auth')),
body: Column(
children: [
ElevatedButton(
onPressed: () async {
// Register User
try {
UserCredential userCredential = await
_auth.createUserWithEmailAndPassword(
email: "[email protected]",
password: "123456",
);
print("User registered:
${userCredential.user?.email}");
} catch (e) {
print("Error: $e");
}
},
child: Text("Register"),
),
ElevatedButton(
onPressed: () async {
// Sign In User
try {
UserCredential userCredential = await
_auth.signInWithEmailAndPassword(
email: "[email protected]",
password: "123456",
);
print("User signed in:
${userCredential.user?.email}");
} catch (e) {
print("Error: $e");
}
},
child: Text("Sign In"),
),
],
),
);
}
}
2.
1.
2. Ensure Firebase is working correctly:
○ Test the Firebase Authentication by checking the Authentication section in the
Firebase Console.
Notes
This step-by-step guide should help you connect and integrate Firebase into your Flutter project
effectively.
///
WidgetsFlutterBinding.ensureInitialized()
This is a method in Flutter that ensures the Flutter engine is properly initialized before running
any code that depends on it. It is particularly useful when performing asynchronous operations
during the app's startup or when you need to access native platform services.
1.
2. Accessing Platform-Specific Code Early
If your code depends on platform channels (e.g., accessing native Android/iOS features)
or accessing SharedPreferences/file systems.
3. During Asynchronous Initialization
When you want to perform an asynchronous operation (like fetching data) before calling
runApp().
● The WidgetsFlutterBinding class is the glue between the Flutter framework and
the Flutter engine.
● Calling WidgetsFlutterBinding.ensureInitialized() ensures that the binding
is initialized if it hasn’t been already. It initializes core services like rendering and event
handling.
If you call asynchronous functions or initialize certain plugins (like Firebase) without ensuring
that the WidgetsFlutterBinding is initialized, you may encounter runtime errors, such as:
Without WidgetsFlutterBinding.ensureInitialized()
dart
Copy code
void main() async {
await Firebase.initializeApp(); // ❌ Error: Binding not
initialized!
runApp(MyApp());
}
Correct Way
dart
Copy code
void main() async {
WidgetsFlutterBinding.ensureInitialized(); // Ensures everything is
ready
await Firebase.initializeApp();
runApp(MyApp());
}
Key Points
Validation Logic
1.Email:
○ Should include an @ sign.
2.Password:
○ At least 8 characters.
○ Includes at least:
■ One uppercase letter.
■ One lowercase letter.
■ One digit.
■ One special symbol.
@override
Widget build(BuildContext context) {
final authProvider = Provider.of<FirebaseAuthProvider>(context);
return Scaffold(
appBar: AppBar(title: Text("Sign Up")),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(labelText: "Email"),
validator: (vue) {
if (value == null || value.isEmpty) {
return "Email cannot be empty";
} else if
(!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value)) {
return "Enter a valid email (e.g.,
[email protected])";
}
return null;
},
),
SizedBox(height: 16),
TextFormField(
controller: _passwordController,
obscureText: true,
decoration: InputDecoration(labelText: "Password"),
validator: (value) {
if (value == null || value.isEmpty) {
return "Password cannot be empty";
} else if (value.length < 8) {
return "Password must be at least 8 characters";
} else if
(!RegExp(r'^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%
*?&]{8,}$').hasMatch(value)) {
return "Password must include uppercase,
lowercase, digit, and symbol";
}
return null;
},
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () async {
if (_formKey.currentState!.validate()) {
final email = _emailController.text.trim();
final password = _passwordController.text.trim();
if (result == null) {
// Success
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text("Signup successful!"),
backgroundColor: Colors.green,
));
} else {
// Error
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(result),
backgroundColor: Colors.red,
));
}
}
},
child: Text("Sign Up"),
),
],
),
),
),
);
}
}
Updated FirebaseAuthProvider
dart
Copy code
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class FirebaseAuthProvider with ChangeNotifier {
final FirebaseAuth _auth = FirebaseAuth.instance;
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
return {
'userId': userId ?? '',
'email': email ?? '',
};
}
3. Explanation
You can retrieve and display user data or clear it when required.
Add the login function to authenticate users and retrieve their data:
dart
Copy code
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
UserModel({
required this.userId,
required this.email,
});
UserModel? _currentUser;
// Login Function
Future<String?> login(String email, String password) async {
try {
// Authenticate user with FirebaseAuth
UserCredential userCredential = await
_auth.signInWithEmailAndPassword(
email: email,
password: password,
);
notifyListeners();
return null; // Login successful
} else {
return "User data not found in Firestore.";
}
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
return "No user found for this email.";
} else if (e.code == 'wrong-password') {
return "Incorrect password.";
} else {
return e.message; // Other FirebaseAuth errors
}
} catch (e) {
return "An error occurred. Please try again.";
}
}
// Logout Function
Future<void> logout() async {
await _auth.signOut();
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.clear();
_currentUser = null;
notifyListeners();
}
To show the logged-in user's email in a Drawer on the home screen, you can modify the
HomePage as follows:
dart
Copy code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'firebase_auth_provider.dart';
return Scaffold(
appBar: AppBar(
title: Text("Home"),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
UserAccountsDrawerHeader(
accountName: Text("Welcome!"),
accountEmail: Text(
),
currentAccountPicture: CircleAvatar(
),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
leading: Icon(Icons.home),
title: Text("Home"),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.logout),
title: Text("Logout"),
onTap: () async {
await authProvider.logout();
Navigator.pushReplacementNamed(context, '/login');
},
),
],
),
),
body: Center(
child: Text(
),
),
);
Explanation of Changes
Routing Setup
Ensure your app has routing configured in main.dart for navigation to work correctly:
dart
Copy code
WidgetsFlutterBinding.ensureInitialized();
await authProvider.fetchUserFromPreferences();
runApp(
ChangeNotifierProvider(
child: MyApp(),
),
);
@override
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: '/',
routes: {
'/': (context) => Consumer<FirebaseAuthProvider>(
? HomePage()
: LoginPage();
},
),
},
);
Output
This approach ensures a smooth user experience with a clean and professional interface!
Firebase Provider Class
dart
Copy code
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
// Add Data
Future<void> addPlanet({
}) async {
try {
await _firestore.collection('planets').add({
'uid': uid,
'name': name,
'title': title,
'year': year,
'description': description,
'image': image,
'createdAt': FieldValue.serverTimestamp(),
});
notifyListeners();
} catch (e) {
return _firestore
.collection('planets')
.snapshots()
.map((snapshot) {
return snapshot.docs.map((doc) {
return {
'id': doc.id,
'name': doc['name'],
'title': doc['title'],
'year': doc['year'],
'description': doc['description'],
'image': doc['image'],
};
}).toList();
});
// Update Data
Future<void> updatePlanet({
}) async {
try {
await _firestore.collection('planets').doc(id).update({
'name': name,
'title': title,
'year': year,
'description': description,
'image': image,
'updatedAt': FieldValue.serverTimestamp(),
});
notifyListeners();
} catch (e) {
// Delete Data
Future<void> deletePlanetByUid({
}) async {
try {
.collection('planets')
.get();
// Check if the document exists
if (querySnapshot.docs.isNotEmpty) {
await _firestore.collection('planets').doc(docId).delete();
} else {
} catch (e) {
UI Implementation
Add Planet UI
A simple form to add a planet.
dart
Copy code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'planet_provider.dart';
@override
return Scaffold(
appBar: AppBar(
title: Text("Add Planet"),
),
body: Padding(
child: Column(
children: [
TextField(
controller: nameController,
),
TextField(
controller: titleController,
),
TextField(
controller: yearController,
),
TextField(
controller: descriptionController,
),
TextField(
controller: imageController,
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
planetProvider.addPlanet(
name: nameController.text,
title: titleController.text,
year: yearController.text,
description: descriptionController.text,
image: imageController.text,
);
},
),
],
),
),
);
}
Display Planets using StreamBuilder
dart
Copy code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'planet_provider.dart';
@override
return Scaffold(
appBar: AppBar(
title: Text("Planets"),
),
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
if (!snapshot.hasData || snapshot.data!.isEmpty) {
return ListView.builder(
itemCount: planets.length,
return ListTile(
title: Text(planet['name']),
subtitle: Text(planet['description']),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
planetProvider.deletePlanet(planet['id']);
},
),
onTap: () {
},
);
},
);
},
),
);
Update Planet UI
dart
Copy code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'planet_provider.dart';
required this.id,
required this.name,
required this.title,
required this.year,
required this.description,
required this.image,
});
@override
titleController.text = title;
yearController.text = year;
descriptionController.text = description;
imageController.text = image;
return Scaffold(
appBar: AppBar(
),
body: Padding(
child: Column(
children: [
TextField(
controller: nameController,
),
TextField(
controller: titleController,
),
TextField(
controller: yearController,
),
TextField(
controller: descriptionController,
),
TextField(
controller: imageController,
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
planetProvider.updatePlanet(
id: id,
name: nameController.text,
title: titleController.text,
year: yearController.text,
description: descriptionController.text,
image: imageController.text,
);
},
child: Text("Update Planet"),
),
],
),
),
);
Summary
You can now create routes to navigate between the Add, Update, and Planet List pages
Update Function
dart
Copy code
void _showUpdateDialog({
required BuildContext context,
}) {
TextEditingController(text: currentName);
showDialog(
context: context,
return AlertDialog(
content: TextField(
controller: nameController,
decoration: InputDecoration(
border: OutlineInputBorder(),
),
),
actions: [
TextButton(
child: Text("Cancel"),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text("Update"),
onPressed: () async {
// Update logic
.updatePlanet(
id: planetId,
name: nameController.text,
);
Navigator.of(context).pop();
},
),
],
);
},
);
Delete Function
dart
Copy code
void _showDeleteDialog({
}) {
showDialog(
context: context,
return AlertDialog(
actions: [
TextButton(
child: Text("Cancel"),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text("Delete"),
onPressed: () async {
// Delete logic
.deletePlanet(planetId);
Navigator.of(context).pop();
},
),
],
);
},
);
Ensure the updatePlanet function updates only the provided fields by fetching the document
and merging the new data. Here’s how:
dart
Copy code
Future<void> updatePlanet({
required String id,
String? name,
String? title,
String? year,
String? description,
String? image,
}) async {
try {
final updatedData = {
'updatedAt': FieldValue.serverTimestamp(),
};
await docRef.update(updatedData);
notifyListeners();
} catch (e) {
try {
await _firestore.collection('planets').doc(id).delete();
notifyListeners();
} catch (e) {
Explanation
● Update Functionality:
○ Opens an AlertDialog to update the planet name.
○ Uses the updatePlanet function to update the Firebase record.
○ Other fields remain unchanged.
● Delete Functionality:
○ Confirms deletion via AlertDialog.
○ Deletes the record from Firebase using the deletePlanet function.
This approach ensures real-time updates to your UI using the StreamBuilder.
Updated Code
dart
Copy code
SizedBox(
stream: planetProvider.getPlanetsByUID(
if (snapshot.connectionState == ConnectionState.waiting) {
if (!snapshot.hasData || snapshot.data!.isEmpty) {
itemCount: planets.length,
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
imageUrl: planet['image'],
title: planet['name'],
),
),
);
},
child: commonBGcontainer(
state: 2,
width: double.infinity,
height: height / 5,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
planet['image'],
scale: 10,
),
const SizedBox(
width: 10,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
planet['name'],
style: fontWhite35,
),
Padding(
child: Row(
children: [
IconButton(
onPressed: () {
// Update Functionality
_showUpdateDialog(
context: context,
planetId: planet['id'],
currentName: planet['name'],
);
},
icon: Icon(
Icons.edit,
size: 25,
color: AppColor.homeScreenC5,
),
),
IconButton(
onPressed: () {
// Delete Functionality
_showDeleteDialog(
context: context,
planetId: planet['id'],
);
},
icon: Icon(
Icons.delete,
size: 25,
color: AppColor.homeScreenC5,
),
),
],
),
],
),
SizedBox(
width: 220,
height: 60,
child: Text(
planet["description"],
style: fontwhite14,
),
],
),
],
),
),
);
},
);
},
),
);
Last day
Here's the updated code to pick an image from the gallery, upload it to Firebase Storage, and
print the uploaded image URL in the console.
Complete Functionality:
dart
Copy code
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_storage/firebase_storage.dart';
class ImageHandler {
final ImagePicker imagePicker = ImagePicker();
File? pickedImage;
Size imageSize = Size(0, 0);
bool isImageEmpty = false;
if (img != null) {
// Decode image to get its size
final image = await decodeImageFromList(await
img.readAsBytes());
pickedImage = File(img.path);
imageSize = Size(image.width.toDouble(),
image.height.toDouble());
if (imageUrl != null) {
print("Uploaded Image URL: $imageUrl");
}
} else {
print("No image selected.");
isImageEmpty = true;
}
} catch (e) {
isImageEmpty = true;
print("Error picking or uploading image: $e");
}
}
/// Upload the image to Firebase Storage and return the URL
Future<String?> uploadImageToFirebase(File imageFile) async {
try {
// Define a unique path for the image in Firebase Storage
final storageRef = FirebaseStorage.instance
.ref()
.child("images/${DateTime.now().millisecondsSinceEpoch}.jpg");
Usage:
1. Call the pickImageAndUpload() function from your widget or button press, specifying
the source (ImageSource.gallery or ImageSource.camera):
dart
Copy code
final imageHandler = ImageHandler();
ElevatedButton(
onPressed: () async {
await imageHandler.pickImageAndUpload(ImageSource.gallery);
},
child: Text("Pick Image and Upload"),
);
Key Features:
1. Image Picking: Picks an image from the specified source (gallery or camera).
2. Image Size: Decodes the image to get its dimensions.
3. Firebase Upload: Uploads the image to Firebase Storage and retrieves its download
URL.
4. Error Handling: Prints relevant error messages for debugging
1. Set Up Firebase in Your Project
2. Add Dependencies
yaml
Copy code
dependencies:
firebase_auth: ^5.0.1
firebase_core: ^3.7.0
google_sign_in: ^7.6.0
Run:
bash
Copy code
flutter pub get
3. Initialize Firebase
dart
Copy code
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class GoogleSignInProvider {
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
if (googleUser != null) {
// Obtain the Google authentication details
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
// Sign in to Firebase
final UserCredential userCredential =
await _auth.signInWithCredential(credential);
dart
Copy code
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'google_sign_in.dart';
User? _user;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Google Sign-In with Firebase"),
),
body: Center(
child: _user == null
? ElevatedButton.icon(
icon: Icon(Icons.login),
label: Text("Sign In with Google"),
onPressed: _handleSignIn,
)
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircleAvatar(
backgroundImage: NetworkImage(_user?.photoURL ??
""),
radius: 40,
),
SizedBox(height: 16),
Text("Name: ${_user?.displayName}"),
Text("Email: ${_user?.email}"),
SizedBox(height: 16),
ElevatedButton.icon(
icon: Icon(Icons.logout),
label: Text("Sign Out"),
onPressed: _handleSignOut,
),
],
),
),
);
}
}
Key Features
Notes:
For iOS, configure Info.plist by adding:
xml
Copy code
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.YOUR_CLIENT_ID</string>
</array>
</dict>
</array>
<key>GoogleSignIn</key>
<string>YOUR_CLIENT_ID</string>
This setup will fully integrate Google Sign-In with Firebase in your Flutter app! 🚀
API,s
Understanding APIs and Their Usage in Flutter
What is an API?
1. A Client (e.g., your mobile app) requests data from a Server (e.g., a backend system).
2. The API acts as the waiter in a restaurant:
○ The waiter (API) takes your order (client request).
○ Hands it over to the kitchen (server) for preparation.
○ Returns with the food (response).
3. Similarly, the API receives the client request, processes it, and sends the appropriate
response back to the client.
API Workflow Explained
1. Request:
○ The client sends a request to the API. This includes:
■ Endpoint: The URL of the API (e.g., /users).
■ Method: Defines the type of operation (e.g., GET or POST).
■ Headers: Include metadata like API keys or content types.
■ Body (Optional): Data sent with the request (used in POST, PUT, etc.).
2. Processing:
○ The server receives the request, processes it, and performs the required
operations (e.g., fetch data from a database).
3. Response:
○ The server sends a response back to the client. This includes:
■ Status Code: Indicates success or failure (e.g., 200 OK or 404 Not
Found).
■ Data: The requested information or confirmation of the operation.
Here’s a simple illustration of how APIs act as a bridge between the client and the server:
Copy code
Benefits of APIs
1. Modularity: APIs allow separation of the client and server, enabling independent
updates.
2. Reusability: Same API can be used across different apps (e.g., mobile, web).
3. Scalability: Simplifies data handling between systems.
14.
In Flutter, HTTP APIs are commonly used for communication between a mobile app and a
backend server.
1.
2. Create a Data Model: Models represent structured data, making it easy to parse the API
response and assign values.
3. Create API Service: A dedicated class will handle the API calls (e.g., GET and POST
requests).
4. Show Data in UI: Use Flutter widgets to display the fetched data from the API.
Scenario:
We will fetch and display a list of users from a sample API and post a new user's data.
dart
Copy code
class User {
final int id;
final String name;
final String email;
// Constructor
User({required this.id, required this.name, required this.email});
dart
Copy code
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'user_model.dart';
class ApiService {
final String baseUrl = "https://jsonplaceholder.typicode.com";
if (response.statusCode == 200) {
final List<dynamic> data = jsonDecode(response.body);
return data.map((json) => User.fromJson(json)).toList();
} else {
throw Exception("Failed to load users");
}
} catch (e) {
print("Error fetching users: $e");
throw e;
}
}
if (response.statusCode == 201) {
return User.fromJson(jsonDecode(response.body));
} else {
throw Exception("Failed to create user");
}
} catch (e) {
print("Error creating user: $e");
throw e;
}
}
}
3. Implement UI in Flutter
dart
Copy code
import 'package:flutter/material.dart';
import 'api_service.dart';
import 'user_model.dart';
void main() {
runApp(MyApp());
}
@override
void initState() {
super.initState();
_users = ApiService().fetchUsers();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Users List")),
body: FutureBuilder<List<User>>(
future: _users,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text("Error: ${snapshot.error}"));
} else if (snapshot.hasData) {
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
);
},
);
} else {
return Center(child: Text("No data found"));
}
},
),
);
}
}
dart
Copy code
FloatingActionButton(
onPressed: () async {
final newUser = User(id: 0, name: "John Doe", email:
"[email protected]");
final createdUser = await ApiService().createUser(newUser);
print("User Created: ${createdUser.name}, ${createdUser.email}");
},
child: Icon(Icons.add),
)
4. Explanation
GET API:
POST API:
● createUser method sends a POST request with the new user's data (converted to
JSON using toJson).
● Parses the server's response to create a User object for the new user.
● GET: https://jsonplaceholder.typicode.com/users
● POST: https://jsonplaceholder.typicode.com/users
🚀
This setup demonstrates how to work with APIs in Flutter, from creating models to handling
HTTP requests and displaying data in the UI. Let me know if you have further questions!
short skill
Create website free with hosting
odoo.com..
Prompt Engineering
● Career Opportunities: The demand for prompt engineers is growing, with job
openings and competitive salaries reflecting the importance of this skill in the AI
landscape.
● Evolving Techniques: As generative AI technology advances, new prompting
techniques and strategies will continue to emerge, making prompt engineering a
dynamic field.
● Ethical Considerations: Ensuring fairness and transparency in AI outputs will be
crucial as prompt engineering practices evolve.
https://platform.openai.com/docs/guides/prompt-engineering
Typing Jobs
https://www.truelancer.com/freelance-copy-typing-jobs
https://coursiv.io/v4?prc_id=31&utm_source=google&utm_medium=cpc&utm_campaign=21874
930052&utm_adgroupid=173546800481&utm_keyword=data%20entry%20work%20from%20ho
me&utm_type=nonbrand_s&utm_acc=1308143291&utm_alen=1&gad_source=1&gclid=Cj0KCQ
iAx9q6BhCDARIsACwUxu4ptEolY8NBi5toeNUXYu8qcGeVlGsEEMq2BuTvgwWnQDtQLfLl40U
aAlUBEALw_wcB
https://remotejobsfinder.co/en/onboarding/27/quiz?utm_medium=cpc&utm_medium=cpc&utm_s
ource=google&utm_source=google&utm_campaign=rjf_wide_search_world_exp&utm_campaig
n=cid%7C21541065497%7Caid%7C715695690161&utm_term=data+entry+jobs&utm_content=
gid%7C172155661830%7Cphr%7Ckwd-10388071%7Cdvc%7Cc%7Cpos%7C%7Cmch%7Cb%
7Csrc%7C%7Creg%7C1011084%7Crin%7C%7Ckw%7Cdata+entry+jobs&gad_source=1&gclid
=Cj0KCQiAx9q6BhCDARIsACwUxu4wAskknjpyBiXCwJS016bAue13VLqlIuF7GacCVXwt0hzXD
Xx9nBIaAisUEALw_wcB
https://www.remotejobs.io/welcome/discover-your-dream-remote-job?utm_source=google&utm_
medium=cpc&utm_campaign=20876014487&utm_term=data%20entry%20jobs%20from%20ho
me&network=g&device=c&adposition=&adgroupid=157342343976&placement=&adid=6851406
60878&gad_source=1&gclid=Cj0KCQiAx9q6BhCDARIsACwUxu7pkZ2cT79PXOlz3OqNVtGU3
n9XCD1bfPHdMOYSgIrCOMG_JYO9WtgaAssEEALw_wcB