diff --git a/android/app/build.gradle b/android/app/build.gradle index 77f72c4..ae3eeed 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -45,10 +45,11 @@ android { applicationId "com.example.anom_alert" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion flutter.minSdkVersion + minSdkVersion 21 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName + multiDexEnabled true } buildTypes { @@ -64,4 +65,6 @@ flutter { source '../..' } -dependencies {} +dependencies { + implementation 'com.android.support:multidex:2.0.1' +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 7d3e803..6960100 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,8 @@ + android:icon="@mipmap/launcher_icon" + android:enableOnBackInvokedCallback="true"> signInWithGoogle() async { + // Trigger the authentication flow + final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn(); + + // Obtain the auth details from the request + final GoogleSignInAuthentication? googleAuth = + await googleUser?.authentication; + + // Create a new credential + final credential = GoogleAuthProvider.credential( + accessToken: googleAuth?.accessToken, + idToken: googleAuth?.idToken, + ); + + // Once signed in, return the UserCredential + const MainPage(); + return await FirebaseAuth.instance.signInWithCredential(credential); +} + +Future _googleSignIn() async { + await signInWithGoogle(); + const MainPage(); +} + +class GoogleSignInAuth extends StatelessWidget { + const GoogleSignInAuth({super.key}); + + @override + Widget build(BuildContext context) { + return OutlinedButton( + onPressed: _googleSignIn, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Image( + image: AssetImage("assets/images/google-logo.png"), + height: 24, + width: 24, + ), + const SizedBox( + width: 4, + ), + Text( + "Login with Google", + style: GoogleFonts.urbanist(), + ), + ], + )); + } +} diff --git a/lib/screens/auth/login.dart b/lib/screens/auth/login.dart index 02d477a..f6af57f 100644 --- a/lib/screens/auth/login.dart +++ b/lib/screens/auth/login.dart @@ -1,6 +1,14 @@ +import 'dart:convert'; + +import 'package:anom_alert/screens/auth/google_sign_in_auth.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:firebase_auth/firebase_auth.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:http/http.dart' as http; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:anom_alert/screens/home_page.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @@ -12,20 +20,80 @@ class LoginScreen extends StatefulWidget { class _LoginScreenState extends State { final _emailController = TextEditingController(); final _passwordController = TextEditingController(); + late SharedPreferences preferences; + final _client = http.Client(); + final _loginUrl = Uri.parse("login"); + final _registerUrl = Uri.parse("register"); + + @override + void initState() { + // TODO: implement initState + super.initState(); + initSharedPreference(); + } + + void initSharedPreference() async { + preferences = await SharedPreferences.getInstance(); + } + + void logInWithEmail() async { + http.Response response = await _client.post(_loginUrl, + body: json.encode({ + "emailId": _emailController.text.trim(), + "password": _passwordController.text.trim() + })); - Future signIn() async { - try { - await FirebaseAuth.instance.signInWithEmailAndPassword( - email: _emailController.text.trim(), - password: _passwordController.text.trim()); - SnackBar(content: Text("Successfully signed in as")); - } on FirebaseAuthException catch (e) { - showDialog(context: context, builder: (context) { - return AlertDialog(content: const Text("Incorrect email ID or password"),); - }); + if (response.statusCode == 200) { + var json = jsonDecode(response.body); + if (json["status"] == "Login Successfully") { + await EasyLoading.showSuccess(json["status"]); + var myToken = json["token"]; + preferences.setString("token", myToken); + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (ctx) => HomePage( + token: myToken, + ))); + } else { + EasyLoading.showError(json["status"]); + } + } else { + await EasyLoading.showError( + "Error Code : ${response.statusCode.toString()}"); } } + // Future signInWithEmail() async { + // try { + // await FirebaseAuth.instance.signInWithEmailAndPassword( + // email: _emailController.text.trim(), + // password: _passwordController.text.trim()); + // SnackBar(content: Text("Successfully signed in as")); + // } on FirebaseAuthException catch (e) { + // showDialog( + // context: context, + // builder: (context) { + // return AlertDialog( + // icon: Icon(Icons.error_outline), + // iconColor: Colors.redAccent, + // title: Text( + // "Wrong Password", + // style: GoogleFonts.urbanist(color: Colors.redAccent), + // ), + // ); + // }); + // } + // } + // + // Future signInWithGoogle() async { + // final GoogleSignInAccount? gUser = await GoogleSignIn().signIn(); + // final GoogleSignInAuthentication gAuth = await gUser!.authentication; + // + // final credential = GoogleAuthProvider.credential( + // accessToken: gAuth.accessToken, idToken: gAuth.idToken); + // + // return await FirebaseAuth.instance.signInWithCredential(credential); + // } + @override void dispose() { // TODO: implement dispose @@ -36,97 +104,85 @@ class _LoginScreenState extends State { @override Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const BackButton(), - Expanded( - child: SingleChildScrollView( - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 36), - child: Column( - children: [ - Text( - "Welcome back! Glad to see you again", - style: Theme - .of(context) - .textTheme - .titleLarge! - .copyWith(fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 32, - ), - TextField( - style: const TextStyle(color: Color(0xFF515D6B)), - controller: _emailController, - decoration: const InputDecoration( - label: Text("Email"), - hintText: "Enter your email", - ), - ), - const SizedBox( - height: 16, - ), - TextField( - style: const TextStyle(color: Color(0xFF515D6B)), - obscureText: true, - controller: _passwordController, - decoration: const InputDecoration( - label: Text("Password"), - hintText: "Enter your Password", - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - TextButton( - onPressed: () {}, - child: const Text("Forgot Password?")) - ], - ), - const SizedBox( - height: 16, + return GestureDetector( + onTap: () { + FocusScopeNode currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) { + currentFocus.unfocus(); + } + }, + child: Scaffold( + body: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const BackButton(), + Expanded( + child: SingleChildScrollView( + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20, vertical: 36), + child: Column( + children: [ + Text( + "Welcome back! Glad to see you again", + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(fontWeight: FontWeight.bold), + ), + const SizedBox( + height: 32, + ), + TextField( + style: const TextStyle(color: Color(0xFF515D6B)), + controller: _emailController, + decoration: const InputDecoration( + label: Text("Email"), + hintText: "Enter your email", ), - ElevatedButton( - onPressed: signIn, - child: Text( - "Login with Email", - style: GoogleFonts.urbanist( - color: Colors.white, - fontWeight: FontWeight.w500), - )), - const SizedBox( - height: 16, + ), + const SizedBox( + height: 16, + ), + TextField( + style: const TextStyle(color: Color(0xFF515D6B)), + obscureText: true, + controller: _passwordController, + decoration: const InputDecoration( + label: Text("Password"), + hintText: "Enter your Password", ), - OutlinedButton( - onPressed: () {}, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Login with", - style: GoogleFonts.urbanist(), - ), - const SizedBox( - width: 4, - ), - const Image( - image: - AssetImage("assets/images/google-logo.png"), - height: 24, - width: 24, - ) - ], - )) - ], - ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () {}, + child: const Text("Forgot Password?")) + ], + ), + const SizedBox( + height: 16, + ), + ElevatedButton( + onPressed: logInWithEmail, + child: Text( + "Login with Email", + style: GoogleFonts.urbanist( + color: Colors.white, + fontWeight: FontWeight.w500), + )), + const SizedBox( + height: 16, + ), + const GoogleSignInAuth(), + ], ), - )) - ], + ), + )) + ], + ), ), ), ); diff --git a/lib/screens/auth/main_page.dart b/lib/screens/auth/main_page.dart index 78e0463..524f09b 100644 --- a/lib/screens/auth/main_page.dart +++ b/lib/screens/auth/main_page.dart @@ -10,16 +10,17 @@ class MainPage extends StatelessWidget { @override Widget build(BuildContext context) { - return Scaffold( - body: StreamBuilder(stream: FirebaseAuth.instance.authStateChanges(), - builder: (context, snapshot){ - if(snapshot.hasData) { - return const HomePage(); - } - else{ - return const LoginOrRegisterScreen(); - } - },), + return const Scaffold( + body: LoginOrRegisterScreen(), + // body: StreamBuilder(stream: FirebaseAuth.instance.authStateChanges(), + // builder: (context, snapshot){ + // if(snapshot.hasData) { + // return const HomePage(); + // } + // else{ + // return const LoginOrRegisterScreen(); + // } + // },), ); } } diff --git a/lib/screens/auth/register.dart b/lib/screens/auth/register.dart index 739d373..c9f13c1 100644 --- a/lib/screens/auth/register.dart +++ b/lib/screens/auth/register.dart @@ -1,6 +1,13 @@ +import 'dart:convert'; + +import 'package:anom_alert/screens/auth/register_error_messages.dart'; +import 'package:anom_alert/screens/home_page.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class RegisterScreen extends StatefulWidget { const RegisterScreen({super.key}); @@ -14,136 +21,204 @@ class _RegisterScreenState extends State { var _enteredName = ""; var _enteredEmail = ""; var _enteredPassword = ""; + var _reEnteredPassword = ""; + final _client = http.Client(); + final _registerUrl = Uri.parse("register"); + late SharedPreferences preferences; + + void registerUser() async { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); - Future register() async { - await FirebaseAuth.instance.createUserWithEmailAndPassword( - email: _enteredEmail, password: _enteredPassword); + http.Response response = await _client.post(_registerUrl, + body: json.encode({ + "name": _enteredName.trim(), + "emailId": _enteredEmail.trim(), + "password": _enteredPassword.trim() + })); + if (response.statusCode == 200) { + var json = jsonDecode(response.body); + if (json["status"] == "emailId in use") { + await EasyLoading.showError(json["status"]); + } else { + var myToken = json["token"]; + preferences.setString("token", myToken); + EasyLoading.showSuccess(json["status"]); + Navigator.of(context).pushReplacement(MaterialPageRoute( + builder: (ctx) => HomePage( + token: myToken, + ))); + //Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (ctx) => HomePage(token: ))); + } + } else { + await EasyLoading.showError( + "Error Code : ${response.statusCode.toString()}"); + } + } } @override Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - BackButton(onPressed: (){Navigator.of(context).pop();},), - Expanded( - child: SingleChildScrollView( - child: Form( - key: _formKey, - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 36), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Hello! Register to get started", - style: Theme.of(context) - .textTheme - .titleLarge! - .copyWith(fontWeight: FontWeight.bold), - ), - const SizedBox( - height: 32, - ), - TextFormField( - style: const TextStyle(color: Color(0xFF515D6B)), - decoration: const InputDecoration( - label: Text("Name"), - hintText: "Enter your name", - ), - validator: (value) { - if (value == null || - value.isEmpty || - value.trim().length <= 1) { - return "Name must not be empty"; - } - return null; - }, - onSaved: (value) { - _enteredName = value!; - }, - ), - const SizedBox( - height: 16, - ), - TextFormField( - style: const TextStyle(color: Color(0xFF515D6B)), - decoration: const InputDecoration( - label: Text("Email"), - hintText: "Enter your email", - ), - validator: (value) { - if (value == null || value.isEmpty) { - return "Enter a valid Email ID"; - } - return null; - }, - onSaved: (value) { - _enteredEmail = value!; - }, - ), - const SizedBox( - height: 16, - ), - TextFormField( - style: const TextStyle(color: Color(0xFF515D6B)), - obscureText: true, - decoration: const InputDecoration( - label: Text("Password"), - hintText: "Enter password", - ), - validator: (value) { - if (value == null || - value.isEmpty || - value.trim().length < 8) { - return "Password should be of atleast 8 characters"; - } - return null; - }, - onSaved: (value) { - _enteredPassword = value!; - }, - ), - const SizedBox( - height: 16, - ), - TextFormField( - style: const TextStyle(color: Color(0xFF515D6B)), - obscureText: true, - decoration: const InputDecoration( - label: Text("Confirm Password"), - hintText: "Re-Enter password", - ), - validator: (value) { - if (value != _enteredPassword) { - return "Password does not match"; - } - return null; - }, - ), - const SizedBox( - height: 32, + return GestureDetector( + onTap: () { + FocusScopeNode currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) { + currentFocus.unfocus(); + } + }, + child: Scaffold( + body: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + BackButton( + onPressed: () { + Navigator.of(context).pop(); + }, + ), + Expanded( + child: SingleChildScrollView( + child: Form( + key: _formKey, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 20, vertical: 36), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Hello! Register to get started", + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(fontWeight: FontWeight.bold), + ), + const SizedBox( + height: 32, + ), + TextFormField( + style: const TextStyle(color: Color(0xFF515D6B)), + decoration: const InputDecoration( + label: Text("Name"), + hintText: "Enter your name", + ), + validator: (value) { + if (value == null || + value.isEmpty || + value.trim().length <= 1) { + return "Name must not be empty"; + } + return null; + }, + onSaved: (value) { + _enteredName = value!; + }, + ), + const SizedBox( + height: 16, + ), + TextFormField( + style: const TextStyle(color: Color(0xFF515D6B)), + decoration: const InputDecoration( + label: Text("Email"), + hintText: "Enter your email", + ), + validator: (value) { + if (value == null || value.isEmpty) { + return "Enter a valid Email ID"; + } + return null; + }, + onSaved: (value) { + _enteredEmail = value!; + }, + ), + const SizedBox( + height: 16, + ), + TextFormField( + style: const TextStyle(color: Color(0xFF515D6B)), + obscureText: true, + decoration: const InputDecoration( + label: Text("Password"), + hintText: "Enter password", + ), + validator: (value) { + if (value == null || + value.isEmpty || + value.trim().length < 8) { + return "Password should be of atleast 8 characters"; + } + return null; + }, + onSaved: (value) { + _enteredPassword = value!; + }, + ), + const SizedBox( + height: 16, + ), + TextFormField( + style: const TextStyle(color: Color(0xFF515D6B)), + obscureText: true, + decoration: const InputDecoration( + label: Text("Confirm Password"), + hintText: "Re-Enter password", + ), + validator: (value) { + if (_reEnteredPassword != _enteredPassword) { + return "Password does not match"; + } + return null; + }, + onSaved: (value) { + _reEnteredPassword = value!; + }, + ), + const SizedBox( + height: 32, + ), + ElevatedButton( + onPressed: () { + registerUser(); + }, + child: Text( + "Register", + style: GoogleFonts.urbanist( + color: Colors.white, + fontWeight: FontWeight.w500), + )), + const SizedBox( + height: 16, + ), + OutlinedButton( + onPressed: () {}, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Image( + image: AssetImage( + "assets/images/google-logo.png"), + height: 24, + width: 24, + ), + const SizedBox( + width: 4, + ), + Text( + "Sign Up with Google", + style: GoogleFonts.urbanist(), + ), + ], + )) + ], ), - ElevatedButton( - onPressed: (){register(); - Navigator.pop(context);}, - child: Text( - "Register", - style: GoogleFonts.urbanist( - color: Colors.white, - fontWeight: FontWeight.w500), - )) - ], + ), ), - ), - ), - )) - ], - ), - ), - ); + )) + ], + ), + ), + )); } } diff --git a/lib/screens/auth/register_error_messages.dart b/lib/screens/auth/register_error_messages.dart new file mode 100644 index 0000000..6d643dd --- /dev/null +++ b/lib/screens/auth/register_error_messages.dart @@ -0,0 +1,32 @@ +class SignupWithEmailAndPasswordFailure { + final String message; + const SignupWithEmailAndPasswordFailure([this.message = "An Error Occured"]); + + factory SignupWithEmailAndPasswordFailure.code(String code) { + switch (code) { + case 'weak-password': + return const SignupWithEmailAndPasswordFailure( + "Please enter a stronger password."); + case 'invalid-email': + return const SignupWithEmailAndPasswordFailure( + "Email is not valid or badly formatted."); + case 'wrong-password' || 'user-not-found': + return const SignupWithEmailAndPasswordFailure( + "The username or password is invalid."); + case 'email-already-in-use': + return const SignupWithEmailAndPasswordFailure( + "An account already exists with this email."); + case 'operation-not-allowed': + return const SignupWithEmailAndPasswordFailure( + "Operation is not allowed. Please contact support."); + case 'user-disabled': + return const SignupWithEmailAndPasswordFailure( + "This user has been disabled. Please contact support"); + case 'too-many-requests': + return const SignupWithEmailAndPasswordFailure( + "Too many requests. Please wait."); + default: + return const SignupWithEmailAndPasswordFailure(); + } + } +} diff --git a/lib/screens/home_page.dart b/lib/screens/home_page.dart index f57f2da..59d45fa 100644 --- a/lib/screens/home_page.dart +++ b/lib/screens/home_page.dart @@ -1,19 +1,113 @@ +import 'package:anom_alert/providers/camera_provider.dart'; +import 'package:anom_alert/widgets/add_camera.dart'; +import 'package:anom_alert/widgets/new_camera.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:popover/popover.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -class HomePage extends StatefulWidget { - const HomePage({super.key}); +class HomePage extends ConsumerStatefulWidget { + const HomePage({super.key, this.token}); + + final token; @override - State createState() => _HomePageState(); + ConsumerState createState() => _HomePageState(); } -class _HomePageState extends State { - final user = FirebaseAuth.instance.currentUser; +class _HomePageState extends ConsumerState { + //final user = FirebaseAuth.instance.currentUser; + + void addCamera() { + showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + builder: (ctx) { + return const AddCamera(); + }); + } + @override Widget build(BuildContext context) { + final _myCameras = ref.watch(cameraProvider); + final width = MediaQuery.of(context).size.width; + Widget mainContent = Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Center( + child: Transform.flip( + flipX: true, + child: Image.asset( + "assets/images/cctv-camera.png", + height: width / 2, + width: width / 2, + ))), + Text( + "Add a camera to get started!", + style: GoogleFonts.poppins(color: Colors.black), + ), + ], + ); + if(_myCameras.isNotEmpty){ + mainContent = Column(crossAxisAlignment: CrossAxisAlignment.center,children: [ + for(var cam in _myCameras) + NewCamera(cam), + ],); + } return Scaffold( - appBar: AppBar(), + backgroundColor: const Color(0xFFF7F8F9), + appBar: AppBar( + title: Text( + "My Cameras", + style: TextStyle( + color: Theme.of(context).colorScheme.onBackground, + fontWeight: FontWeight.bold), + ), + //backgroundColor: const Color(0xFF1E1E1E), + actions: [ + IconButton( + onPressed: () { + showPopover( + context: context, + bodyBuilder: (context) { + return Column( + children: [ + GestureDetector( + child: Text("Log Out"), + ), + ], + ); + }, + direction: PopoverDirection.top, + width: 250, + height: 150, + backgroundColor: Colors.black54); + }, + icon: const Icon( + Icons.more_vert, + color: Colors.white70, + )) + ], + ), + body: mainContent, + floatingActionButton: Container( + height: 48, + width: 48, + child: IconButton( + onPressed: addCamera, + icon: Icon( + Icons.add, + color: Colors.white, + ), + style: IconButton.styleFrom( + backgroundColor: Color(0xFF1E1E1E), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8))), + ), + ), ); } } diff --git a/lib/screens/login_or_register.dart b/lib/screens/login_or_register.dart index 3fd96d4..8215060 100644 --- a/lib/screens/login_or_register.dart +++ b/lib/screens/login_or_register.dart @@ -7,7 +7,6 @@ import 'package:transparent_image/transparent_image.dart'; class LoginOrRegisterScreen extends StatelessWidget { const LoginOrRegisterScreen({super.key}); - @override Widget build(BuildContext context) { return Scaffold( @@ -36,6 +35,8 @@ class LoginOrRegisterScreen extends StatelessWidget { ], ), const Spacer(), + Image.asset("assets/images/logo-fg.png", height: 96,), + SizedBox(height: 12,), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -48,7 +49,7 @@ class LoginOrRegisterScreen extends StatelessWidget { ), Text( "Alert", - style: Theme.of(context).textTheme.titleLarge, + style: Theme.of(context).textTheme.titleLarge!.copyWith(fontWeight: FontWeight.w500), ), ], ), diff --git a/lib/theme.dart b/lib/theme.dart index f58d1f2..cf17869 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -5,6 +5,9 @@ class AppTheme { AppTheme._(); static ThemeData theme = ThemeData().copyWith( + appBarTheme: AppBarTheme( + backgroundColor: const Color(0xFFF7F8F9), + ), inputDecorationTheme: InputDecorationTheme( fillColor: const Color(0xFFF7F8F9), filled: true, @@ -43,8 +46,15 @@ class AppTheme { borderRadius: BorderRadius.all(Radius.circular(8)), ))), textTheme: TextTheme( - titleLarge: - GoogleFonts.urbanist(fontSize: 28, color: Color(0xFF1E1E1E)), - ), + titleLarge: GoogleFonts.urbanist( + fontSize: 28, + color: const Color(0xFF1E1E1E), + ), + titleMedium: GoogleFonts.urbanist( + fontSize: 24, color: const Color(0xFF1E1E1E)), + bodySmall: GoogleFonts.urbanist( + fontSize: 12, color: const Color(0xFF7D94A0)), + bodyMedium: + GoogleFonts.urbanist(fontSize: 16, fontWeight: FontWeight.w500)), colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF1E1E1E))); } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 53c32ed..87713d3 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,10 +7,16 @@ import Foundation import firebase_auth import firebase_core +import google_sign_in_ios import path_provider_foundation +import shared_preferences_foundation +import sqflite func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) } diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index a2ec33f..96d3fee 100644 --- a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,68 +1,68 @@ { - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" + "info": { + "version": 1, + "author": "xcode" }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} + "images": [ + { + "size": "16x16", + "idiom": "mac", + "filename": "app_icon_16.png", + "scale": "1x" + }, + { + "size": "16x16", + "idiom": "mac", + "filename": "app_icon_32.png", + "scale": "2x" + }, + { + "size": "32x32", + "idiom": "mac", + "filename": "app_icon_32.png", + "scale": "1x" + }, + { + "size": "32x32", + "idiom": "mac", + "filename": "app_icon_64.png", + "scale": "2x" + }, + { + "size": "128x128", + "idiom": "mac", + "filename": "app_icon_128.png", + "scale": "1x" + }, + { + "size": "128x128", + "idiom": "mac", + "filename": "app_icon_256.png", + "scale": "2x" + }, + { + "size": "256x256", + "idiom": "mac", + "filename": "app_icon_256.png", + "scale": "1x" + }, + { + "size": "256x256", + "idiom": "mac", + "filename": "app_icon_512.png", + "scale": "2x" + }, + { + "size": "512x512", + "idiom": "mac", + "filename": "app_icon_512.png", + "scale": "1x" + }, + { + "size": "512x512", + "idiom": "mac", + "filename": "app_icon_1024.png", + "scale": "2x" + } + ] +} \ No newline at end of file diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png index 82b6f9d..7e09381 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png index 13b35eb..6f8052d 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png index 0a3f5fa..7eb0d7a 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png index bdb5722..0b24de7 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png index f083318..92a8aad 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png index 326c0e7..af6cedd 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png index 2f1632c..8559296 100644 Binary files a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/pubspec.lock b/pubspec.lock index 51117c5..cae35a5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.16" + archive: + dependency: transitive + description: + name: archive + sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" + url: "https://pub.dev" + source: hosted + version: "3.4.10" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" async: dependency: transitive description: @@ -33,6 +49,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + url: "https://pub.dev" + source: hosted + version: "0.4.1" clock: dependency: transitive description: @@ -49,6 +81,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" crypto: dependency: transitive description: @@ -65,6 +105,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.6" + email_auth: + dependency: "direct main" + description: + name: email_auth + sha256: d83bce63de8167976693f503eea924af39654af2625f8733d0c1d29d03aef012 + url: "https://pub.dev" + source: hosted + version: "1.1.1" fake_async: dependency: transitive description: @@ -81,6 +129,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" firebase_auth: dependency: "direct main" description: @@ -134,14 +190,38 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_lints: - dependency: "direct dev" + flutter_easyloading: + dependency: "direct main" description: - name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + name: flutter_easyloading + sha256: ba21a3c883544e582f9cc455a4a0907556714e1e9cf0eababfcb600da191d17c url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "3.0.5" + flutter_launcher_icons: + dependency: "direct main" + description: + name: flutter_launcher_icons + sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + url: "https://pub.dev" + source: hosted + version: "0.13.1" + flutter_riverpod: + dependency: "direct main" + description: + name: flutter_riverpod + sha256: "4bce556b7ecbfea26109638d5237684538d4abc509d253e6c5c4c5733b360098" + url: "https://pub.dev" + source: hosted + version: "2.4.10" + flutter_spinkit: + dependency: transitive + description: + name: flutter_spinkit + sha256: b39c753e909d4796906c5696a14daf33639a76e017136c8d82bf3e620ce5bb8e + url: "https://pub.dev" + source: hosted + version: "5.2.0" flutter_test: dependency: "direct dev" description: flutter @@ -160,8 +240,56 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.0" - http: + google_identity_services_web: + dependency: transitive + description: + name: google_identity_services_web + sha256: "0c56c2c5d60d6dfaf9725f5ad4699f04749fb196ee5a70487a46ef184837ccf6" + url: "https://pub.dev" + source: hosted + version: "0.3.0+2" + google_sign_in: + dependency: "direct main" + description: + name: google_sign_in + sha256: "0b8787cb9c1a68ad398e8010e8c8766bfa33556d2ab97c439fb4137756d7308f" + url: "https://pub.dev" + source: hosted + version: "6.2.1" + google_sign_in_android: dependency: transitive + description: + name: google_sign_in_android + sha256: bfd42c81c30c6faba16e0f62968d5505a87504aaa672b3155ee931461abb0a49 + url: "https://pub.dev" + source: hosted + version: "6.1.21" + google_sign_in_ios: + dependency: transitive + description: + name: google_sign_in_ios + sha256: f3336d9e44d4d28063ac90271f6db5caf99f0480cb07281330e7a432edb95226 + url: "https://pub.dev" + source: hosted + version: "5.7.3" + google_sign_in_platform_interface: + dependency: transitive + description: + name: google_sign_in_platform_interface + sha256: "1f6e5787d7a120cc0359ddf315c92309069171306242e181c09472d1b00a2971" + url: "https://pub.dev" + source: hosted + version: "2.4.5" + google_sign_in_web: + dependency: transitive + description: + name: google_sign_in_web + sha256: a278ea2d01013faf341cbb093da880d0f2a552bbd1cb6ee90b5bebac9ba69d77 + url: "https://pub.dev" + source: hosted + version: "0.12.3+2" + http: + dependency: "direct main" description: name: http sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba @@ -176,6 +304,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: "49a0d4b0c12402853d3f227fe7c315601b238d126aa4caa5dbb2dcf99421aa4a" + url: "https://pub.dev" + source: hosted + version: "4.1.6" js: dependency: transitive description: @@ -184,14 +320,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" - lints: + json_annotation: dependency: transitive description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "4.8.1" + jwt_decoder: + dependency: "direct main" + description: + name: jwt_decoder + sha256: "54774aebf83f2923b99e6416b4ea915d47af3bde56884eb622de85feabbc559f" + url: "https://pub.dev" + source: hosted + version: "2.0.1" matcher: dependency: transitive description: @@ -272,6 +416,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" platform: dependency: transitive description: @@ -288,6 +440,86 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + url: "https://pub.dev" + source: hosted + version: "3.7.4" + popover: + dependency: "direct main" + description: + name: popover + sha256: "6a0928ccdcf12d46b407372b644a0d94400b316d0ee072a19dcef03c2bb88c3f" + url: "https://pub.dev" + source: hosted + version: "0.2.9" + riverpod: + dependency: transitive + description: + name: riverpod + sha256: "548e2192eb7aeb826eb89387f814edb76594f3363e2c0bb99dd733d795ba3589" + url: "https://pub.dev" + source: hosted + version: "2.5.0" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + url: "https://pub.dev" + source: hosted + version: "2.3.5" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + url: "https://pub.dev" + source: hosted + version: "2.3.2" sky_engine: dependency: transitive description: flutter @@ -301,6 +533,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + sqflite: + dependency: "direct main" + description: + name: sqflite + sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 + url: "https://pub.dev" + source: hosted + version: "2.3.2" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" + url: "https://pub.dev" + source: hosted + version: "2.5.3" stack_trace: dependency: transitive description: @@ -309,6 +557,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.11.1" + state_notifier: + dependency: transitive + description: + name: state_notifier + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.dev" + source: hosted + version: "1.0.0" stream_channel: dependency: transitive description: @@ -325,6 +581,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" term_glyph: dependency: transitive description: @@ -389,6 +653,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: dart: ">=3.2.4 <4.0.0" - flutter: ">=3.10.0" + flutter: ">=3.16.0" diff --git a/pubspec.yaml b/pubspec.yaml index 1e18e59..b0f76a4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,11 +39,40 @@ dependencies: firebase_core: ^2.24.2 transparent_image: ^2.0.1 google_fonts: ^6.1.0 + google_sign_in: ^6.2.1 + popover: ^0.2.9 + http: ^1.2.0 + flutter_easyloading: ^3.0.5 + jwt_decoder: ^2.0.1 + shared_preferences: ^2.2.2 + email_auth: ^1.1.1 + flutter_launcher_icons: ^0.13.1 + flutter_riverpod: ^2.4.10 + sqflite: ^2.3.2 dev_dependencies: flutter_test: sdk: flutter +flutter_launcher_icons: + android: "launcher_icon" + ios: true + image_path: "assets/images/logo.png" + min_sdk_android: 21 # android min sdk min:16, default 21 + web: + generate: true + image_path: "assets/images/logo.png" + background_color: "#hexcode" + theme_color: "#hexcode" + windows: + generate: true + image_path: "assets/images/logo.png" + icon_size: 48 # min:48, max:256, default: 48 + macos: + generate: true + image_path: "assets/images/logo.png" + + # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your @@ -66,7 +95,12 @@ flutter: assets: - assets/images/login-image.png - assets/images/google-logo.png - + - assets/images/cctv-camera.png + - assets/images/onboarding-bg.png + - assets/images/onboarding-1.png + - assets/images/onboarding-2.png + - assets/images/onboarding-3.png + - assets/images/logo-fg.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware diff --git a/web/favicon.png b/web/favicon.png index 8aaa46a..7eb0d7a 100644 Binary files a/web/favicon.png and b/web/favicon.png differ diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png index b749bfe..f95aab2 100644 Binary files a/web/icons/Icon-192.png and b/web/icons/Icon-192.png differ diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png index 88cfd48..af6cedd 100644 Binary files a/web/icons/Icon-512.png and b/web/icons/Icon-512.png differ diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png index eb9b4d7..f95aab2 100644 Binary files a/web/icons/Icon-maskable-192.png and b/web/icons/Icon-maskable-192.png differ diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png index d69c566..af6cedd 100644 Binary files a/web/icons/Icon-maskable-512.png and b/web/icons/Icon-maskable-512.png differ diff --git a/web/manifest.json b/web/manifest.json index ff5cb01..03dbb8b 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -3,8 +3,8 @@ "short_name": "anom_alert", "start_url": ".", "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", + "background_color": "#hexcode", + "theme_color": "#hexcode", "description": "A new Flutter project.", "orientation": "portrait-primary", "prefer_related_applications": false, @@ -32,4 +32,4 @@ "purpose": "maskable" } ] -} +} \ No newline at end of file diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico index c04e20c..03c14ed 100644 Binary files a/windows/runner/resources/app_icon.ico and b/windows/runner/resources/app_icon.ico differ