Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:label="weather_app"
android:name="${applicationName}"
Expand Down
Binary file removed assets/example/images/background.png
Binary file not shown.
Binary file added assets/example/images/broken clouds.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/example/images/clock.png
Binary file not shown.
Binary file added assets/example/images/icons8-autumn-64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-autumntime-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-cloud-50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-clouds-64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-hygrometer-64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-maple-leaf-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-night-50 (1).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-night-50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-sleet-50 (1).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-sleet-50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-snow-30.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-snow-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-snow-50 (1).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-snow-50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-snow-storm.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-snowflake-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-wind-48 (1).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-windsock-50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-windy-weather-50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-winter-40.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-winter-50 (1).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-winter-50 (2).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/example/images/icons8-winter-50.png
Binary file added assets/example/images/icons8-winter-61.png
Binary file added assets/example/images/icons8-winter-64 (1).png
Binary file added assets/example/images/icons8-winter-64.png
Binary file removed assets/example/images/light-1.png
Diff not rendered.
Binary file removed assets/example/images/light-2.png
Diff not rendered.
Binary file removed assets/example/images/mainImage.png
Diff not rendered.
Binary file added assets/example/images/snow.png
Binary file added assets/example/images/snowy.jpg
Binary file added assets/example/images/sun&cloud.png
Binary file added assets/example/images/wood.jpg
4 changes: 4 additions & 0 deletions ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location when in the background.</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
Expand Down
56 changes: 56 additions & 0 deletions lib/controller/global_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//checking for locationg permission & fetching location of the user's device

import 'package:get/get.dart';
import 'package:geolocator/geolocator.dart';

/*RxBool for creating reactive objects, allows you to store and update location coordinations and notify the listener of changes
setting isLoading to true so it start's loading until we get the location values*/
class GlobalController extends GetxController {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fantastic work on the location controller. I would recommend documenting it.

final RxBool _isLoading = true.obs;
final RxDouble _lattitude = 0.0.obs;
final RxDouble _longitude = 0.0.obs;

RxBool checkLoading() => _isLoading;
RxDouble getLattitude() => _lattitude;
RxDouble getLongitude() => _longitude;

@override
//-event handler-initializing variables, you can use Init()
void onInit() {
if (_isLoading.isTrue) {
getLocation();
}
super.onInit();
}

getLocation() async {
bool isServiceEnabled;
LocationPermission locationPermission;
//waiting for location permission before fetching locationg API
isServiceEnabled = await Geolocator.isLocationServiceEnabled();
if (!isServiceEnabled) {
return Future.error('Location services are enabled');
}

//cheack permission
locationPermission = await Geolocator.checkPermission();
//getting user's location permission
if (locationPermission == LocationPermission.deniedForever) {
return Future.error('Location permissions are denied');
} else if (locationPermission == LocationPermission.denied) {
locationPermission = await Geolocator.requestPermission();
if (locationPermission == LocationPermission.denied) {
return Future.error('Location permission is denied');
}
}

//update values and retrive user location
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high)
.then((value) {
_lattitude.value = value.latitude;
_longitude.value = value.longitude;
_isLoading.value = false;
});
}
}
30 changes: 21 additions & 9 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
import 'package:flutter/material.dart';
import 'package:weather_app/screens/home_screen.dart';
import 'package:weather_app/screens/login_page.dart';

void main() {
runApp(const MainApp());
runApp(MyApp(
initialRoute: LoginPage.route,
routes: {
LoginPage.route: (context) => const LoginPage(),
HomeScreen.route: (context) => const HomeScreen(),
},
));
}

class MainApp extends StatelessWidget {
const MainApp({super.key});
class MyApp extends StatelessWidget {
const MyApp({super.key, required initialRoute, required routes});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To access them, you need variables for them

Suggested change
const MyApp({super.key, required initialRoute, required routes});
const MyApp({super.key, required this.initialRoute, required this.routes});
final String initialRoute;
final Map<String, WidgetBuilder> routes;


@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: Text('Hello World!'),
),
),
return MaterialApp(
title: 'Weather App',
initialRoute: LoginPage.route,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are getting the initial route as a parameter in the constructor, why not use it?

Suggested change
initialRoute: LoginPage.route,
initialRoute: initialRoute,

routes: {
LoginPage.route: (context) => const LoginPage(),
HomeScreen.route: (context) => const HomeScreen(),
},
Comment on lines +23 to +26

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here. you are getting routes from the constructor

home: const LoginPage(),
theme: ThemeData(),
debugShowCheckedModeBanner: false,
);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you forgot to remove debug banner

Suggested change
);
debugShowCheckedModeBanner: false,
);

}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:weather_app/example/MiCard/widgets/details_row.dart';
import 'package:weather_app/models/example/MiCard/widgets/details_row.dart';

class MiCardPageExample extends StatelessWidget {
const MiCardPageExample({super.key});
Expand Down
63 changes: 63 additions & 0 deletions lib/screens/home_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:weather_app/controller/global_controller.dart';
import 'package:weather_app/widgets/current_weather.dart';
import 'package:weather_app/widgets/daily_weather.dart';
import 'package:weather_app/widgets/header.dart';
import 'package:weather_app/widgets/hourly_weather.dart';
import 'package:weather_app/widgets/style.dart';

class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
static const String route = "/HomeScreen";
@override
State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
final GlobalController globalController =
Get.put(GlobalController(), permanent: true);
void navigateNextPage(BuildContext ctx) {
Navigator.of(ctx).push(MaterialPageRoute(builder: (_) {
return const HomeScreen();
}));
}

@override
Widget build(BuildContext context) {
return Scaffold(
//backgroundColor: const Color.fromARGB(255, 226, 238, 238),
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color.fromARGB(255, 198, 205, 205),
Color.fromARGB(255, 225, 255, 251),
Color.fromARGB(255, 245, 255, 254),
],
),
),
child: SafeArea(
child: Obx(() => globalController.checkLoading().isTrue
? const Center(
child: CircularProgressIndicator(),
)
: ListView(
scrollDirection: Axis.vertical,
children: const [
SizedBox(
height: 20,
),
Header(),
CurrentWeather(),
Style(),
HourlyData(),
DailyWeather(),
],
))),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

commas

Suggested change
))),
),),),

),
);
}
}
114 changes: 114 additions & 0 deletions lib/screens/login_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//not complete

import 'package:flutter/material.dart';

import 'package:google_fonts/google_fonts.dart';
import 'package:weather_app/screens/home_screen.dart';

class LoginPage extends StatelessWidget {
const LoginPage({super.key});
static const String route = "/LoginPage";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually you should put all routes in a app_routes.dart class that just contains all the routes.


@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"Weather App",
style: TextStyle(
color: Colors.black87,
),
),
backgroundColor: const Color.fromARGB(255, 15, 99, 159),
),
body: SafeArea(
child: Center(
child: Column(children: <Widget>[
const SizedBox(height: 60),
const Image(
image: AssetImage(
"assets/example/images/icons8-winter-64 (1).png")),
Text("Do You Wanna Build A Snow Man?",
style: GoogleFonts.exo2(
fontSize: 20,
color: Colors.black87,
)),
const SizedBox(height: 40),
const SizedBox(height: 30),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Container(
padding: const EdgeInsets.only(left: 10),
decoration: BoxDecoration(
color: const Color.fromARGB(255, 198, 205, 205),
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(12),
),
child: const TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Email / Phone number'),
),
),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Container(
padding: const EdgeInsets.only(left: 10),
decoration: BoxDecoration(
color: const Color.fromARGB(255, 198, 205, 205),
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(12),
),
child: const TextField(
obscureText: true,
decoration: InputDecoration(
border: InputBorder.none, hintText: 'Password'),
),
),
),
Comment on lines +38 to +70

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since both textfields have the same style couldve wrapped them both in one padding/container

Suggested change
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Container(
padding: const EdgeInsets.only(left: 10),
decoration: BoxDecoration(
color: const Color.fromARGB(255, 198, 205, 205),
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(12),
),
child: const TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Email / Phone number'),
),
),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Container(
padding: const EdgeInsets.only(left: 10),
decoration: BoxDecoration(
color: const Color.fromARGB(255, 198, 205, 205),
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(12),
),
child: const TextField(
obscureText: true,
decoration: InputDecoration(
border: InputBorder.none, hintText: 'Password'),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Container(
padding: const EdgeInsets.only(left: 10),
decoration: BoxDecoration(
color: const Color.fromARGB(255, 198, 205, 205),
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(12),
),
child: Column(
children: [
const TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Email / Phone number',
),
),
const SizedBox(height: 10),
const TextField(
obscureText: true,
decoration: InputDecoration(
border: InputBorder.none, hintText: 'Password',
),
),
],
),
),
),

const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Container(
padding: const EdgeInsets.all(28),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
),
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pushNamed(HomeScreen.route);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You were on the right track but stopped. You made a navigatePage function but didn't complete it

Suggested change
Navigator.of(context).pushNamed(HomeScreen.route);
navigateNextPage();

},
child: Text(
"Sign In",
style: GoogleFonts.exo2(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
)),
),
),
const SizedBox(height: 10),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Forgot Password?",
style: GoogleFonts.exo2(
color: const Color.fromARGB(255, 20, 165, 217),
fontWeight: FontWeight.bold),
),
const SizedBox(height: 80),
const Image(
image: AssetImage(
"assets/example/images/icons8-snowflake-48.png")),
],
)
])),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

commas after every bracket for better formatting

Suggested change
])),
],),),

this will make the autoformatter format your code better

));
}

void navigateNextPage(BuildContext context) {}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could complete it like this:

Suggested change
void navigateNextPage(BuildContext context) {}
void navigateNextPage() {
Navigator.of(context).pushNamed(HomeScreen.route);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function (if connected to a real database) will also validate username and password for input and make sure it is correct before moving on, but for this project it is fine

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also to access context with this function, move it inside the build function

}
Loading