diff --git a/.gitignore b/.gitignore index 29a3a50..5d6fa2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ +# Do not remove or rename entries in this file, only add new ones +# See https://github.com/flutter/flutter/issues/128635 for more context. + # Miscellaneous *.class +*.lock *.log *.pyc *.swp @@ -16,10 +20,46 @@ migrate_working_dir/ *.iws .idea/ -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ +# Visual Studio Code related +.classpath +.project +.settings/ +.vscode/* +.ccls-cache + +# This file, on the master branch, should never exist or be checked-in. +# +# On a *final* release branch, that is, what will ship to stable or beta, the +# file can be force added (git add --force) and checked-in in order to effectively +# "pin" the engine artifact version so the flutter tool does not need to use git +# to determine the engine artifacts. +# +# See https://github.com/flutter/flutter/blob/main/docs/tool/Engine-artifacts.md. +/bin/internal/engine.version + +# Flutter repo-specific +/bin/cache/ +/bin/internal/bootstrap.bat +/bin/internal/bootstrap.sh +/bin/internal/engine.realm +/bin/mingit/ +/dev/benchmarks/mega_gallery/ +/dev/bots/.recipe_deps +/dev/bots/android_tools/ +/dev/devicelab/ABresults*.json +/dev/docs/doc/ +/dev/docs/api_docs.zip +/dev/docs/flutter.docs.zip +/dev/docs/lib/ +/dev/docs/pubspec.yaml +/dev/integration_tests/**/xcuserdata +/dev/integration_tests/**/Pods +/packages/flutter/coverage/ +version +analysis_benchmark.json + +# packages file containing multi-root paths +.packages.generated # Flutter/Dart/Pub related **/doc/api/ @@ -27,17 +67,97 @@ migrate_working_dir/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies +**/generated_plugin_registrant.dart +.packages +.pub-preload-cache/ .pub-cache/ .pub/ -/build/ +build/ +flutter_*.png +linked_*.ds +unlinked.ds +unlinked_spec.ds -# Symbolication related +# Android related +**/android/**/gradle-wrapper.jar +.gradle/ +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/**/GeneratedPluginRegistrant.java +**/android/key.properties +*.jks +local.properties +**/.cxx/ + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/.last_build_id +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/ephemeral +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# macOS +**/Flutter/ephemeral/ +**/Pods/ +**/macos/Flutter/GeneratedPluginRegistrant.swift +**/macos/Flutter/ephemeral +**/xcuserdata/ + +# Windows +**/windows/flutter/ephemeral/ +**/windows/flutter/generated_plugin_registrant.cc +**/windows/flutter/generated_plugin_registrant.h +**/windows/flutter/generated_plugins.cmake + +# Linux +**/linux/flutter/ephemeral/ +**/linux/flutter/generated_plugin_registrant.cc +**/linux/flutter/generated_plugin_registrant.h +**/linux/flutter/generated_plugins.cmake + +# Coverage +coverage/ + +# Symbols app.*.symbols -# Obfuscation related -app.*.map.json +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +!/dev/ci/**/Gemfile.lock +!.vscode/settings.json -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release +# Monorepo +.cipd +.gclient +.gclient_entries +.python-version +.gclient_previous_custom_vars +.gclient_previous_sync_commits \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index b9e43bd..a42444d 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false + id "com.android.application" version "8.2.1" apply false id "org.jetbrains.kotlin.android" version "1.8.22" apply false } diff --git a/assets/auth_background.jpg b/assets/auth_background.jpg index 7a75ac9..4ef1982 100644 Binary files a/assets/auth_background.jpg and b/assets/auth_background.jpg differ diff --git a/assets/logo/logo_dark.png b/assets/logo/logo_dark.png index 4049058..ba9c246 100644 Binary files a/assets/logo/logo_dark.png and b/assets/logo/logo_dark.png differ diff --git a/lib/controller/auth/login_controller.dart b/lib/controller/auth/login_controller.dart index 978112e..9f3059c 100644 --- a/lib/controller/auth/login_controller.dart +++ b/lib/controller/auth/login_controller.dart @@ -10,12 +10,12 @@ class LoginController extends MyController { bool showPassword = false, isChecked = false; - final String _dummyEmail = "demo@example.com"; - final String _dummyPassword = "1234567"; + final String _dummyEmail = "admin@marcobms.com"; + final String _dummyPassword = "User@123"; @override void onInit() { - basicValidator.addField('email', required: true, label: "Email", validators: [MyEmailValidator()], controller: TextEditingController(text: _dummyEmail)); + basicValidator.addField('username', required: true, label: "User_Name", validators: [MyEmailValidator()], controller: TextEditingController(text: _dummyEmail)); basicValidator.addField('password', required: true, label: "Password", validators: [MyLengthValidator(min: 6, max: 10)], controller: TextEditingController(text: _dummyPassword)); diff --git a/lib/helpers/services/auth_service.dart b/lib/helpers/services/auth_service.dart index 5ada735..9e2b706 100644 --- a/lib/helpers/services/auth_service.dart +++ b/lib/helpers/services/auth_service.dart @@ -1,22 +1,31 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; import 'package:marco/helpers/services/storage/local_storage.dart'; -import 'package:marco/model/user.dart'; class AuthService { static bool isLoggedIn = false; - static User get dummyUser => User(-1, "demo@example.com", "Denish", "Navadiya"); - static Future?> loginUser( Map data) async { - await Future.delayed(Duration(seconds: 1)); - if (data['email'] != dummyUser.email) { - return {"email": "This email is not registered"}; - } else if (data['password'] != "1234567") { - return {"password": "Password is incorrect"}; - } + try { + final response = await http.post( + Uri.parse('https://api.marcoaiot.com/api/auth/login'), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode(data), + ); - isLoggedIn = true; - await LocalStorage.setLoggedInUser(true); - return null; + if (response.statusCode == 200) { + isLoggedIn = true; + await LocalStorage.setLoggedInUser(true); + // You can also store the user details in local storage if needed + return null; // No error, login successful + } else if (response.statusCode == 401) { + return {"password": "Invalid email or password"}; + } else { + return {"error": "Something went wrong. Please try again."}; + } + } catch (e) { + return {"error": "Network error. Please check your connection."}; + } } } diff --git a/lib/model/user.dart b/lib/model/user.dart index f1c11f1..53656f2 100644 --- a/lib/model/user.dart +++ b/lib/model/user.dart @@ -1,9 +1,9 @@ import 'package:marco/model/identifier_model.dart'; class User extends IdentifierModel { - final String email, firstName, lastName; + final String username, firstName, lastName; - User(super.id, this.email, this.firstName, this.lastName); + User(super.id, this.username, this.firstName, this.lastName); String get name => "$firstName $lastName"; diff --git a/lib/view/auth/login_screen.dart b/lib/view/auth/login_screen.dart index 04e0a6a..eb99c61 100644 --- a/lib/view/auth/login_screen.dart +++ b/lib/view/auth/login_screen.dart @@ -9,6 +9,7 @@ import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/helpers/widgets/my_text_style.dart'; import 'package:marco/view/layouts/auth_layout.dart'; +import 'package:marco/images.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @@ -17,7 +18,7 @@ class LoginScreen extends StatefulWidget { State createState() => _LoginScreenState(); } -class _LoginScreenState extends State with UIMixin{ +class _LoginScreenState extends State with UIMixin { late LoginController controller; @override @@ -29,114 +30,198 @@ class _LoginScreenState extends State with UIMixin{ @override Widget build(BuildContext context) { return AuthLayout( - child: GetBuilder( + child: GetBuilder( init: controller, tag: 'login_controller', builder: (controller) { - return Form( - key: controller.basicValidator.formKey, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - MyText.titleLarge("Sign in with email", fontWeight: 600), - MySpacing.height(12), - MyText.bodyMedium("Make a new doc to bring your words, data and terms together. For free", fontWeight: 600, xMuted: true), - MySpacing.height(12), - TextFormField( - validator: controller.basicValidator.getValidation('email'), - controller: controller.basicValidator.getController('email'), - keyboardType: TextInputType.emailAddress, - style: MyTextStyle.labelMedium(), - decoration: InputDecoration( - labelText: "Email Address", - labelStyle: MyTextStyle.bodySmall(xMuted: true), - border: OutlineInputBorder(borderSide: BorderSide.none), - filled: true, - fillColor: contentTheme.secondary.withAlpha(36), - prefixIcon: const Icon(LucideIcons.mail, size: 16), - contentPadding: MySpacing.all(14), - isDense: true, - isCollapsed: true, - floatingLabelBehavior: FloatingLabelBehavior.never), - ), - MySpacing.height(20), - TextFormField( - validator: controller.basicValidator.getValidation('password'), - controller: controller.basicValidator.getController('password'), - keyboardType: TextInputType.visiblePassword, - obscureText: !controller.showPassword, - style: MyTextStyle.labelMedium(), - decoration: InputDecoration( - labelText: "Password", - labelStyle: MyTextStyle.bodySmall(xMuted: true), - border: OutlineInputBorder(borderSide: BorderSide.none), - filled: true, - fillColor: contentTheme.secondary.withAlpha(36), - prefixIcon: const Icon(LucideIcons.mail, size: 16), - contentPadding: MySpacing.all(16), - isCollapsed: true, - isDense: true, - floatingLabelBehavior: FloatingLabelBehavior.never, - suffixIcon: InkWell( - onTap: controller.onChangeShowPassword, - child: Icon(controller.showPassword ? LucideIcons.eye : LucideIcons.eye_off, size: 16), - )), - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - InkWell( - onTap: () => controller.onChangeCheckBox(!controller.isChecked), - child: Row( - children: [ - Checkbox( - onChanged: controller.onChangeCheckBox, - value: controller.isChecked, - fillColor: WidgetStatePropertyAll(Colors.white), - activeColor: theme.colorScheme.primary, - checkColor: contentTheme.primary, - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - visualDensity: getCompactDensity, + return Form( + key: controller.basicValidator.formKey, + child: SingleChildScrollView( + padding: MySpacing.xy(2, 40), + child: Container( + width: double.infinity, + padding: MySpacing.all(24), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withOpacity(0.02), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: contentTheme.primary.withOpacity(0.5), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + /// Logo + Center( + child: Image.asset( + Images.logoDark, + height: 120, + fit: BoxFit.contain, + ), + ), + MySpacing.height(20), + + /// Welcome Text + Center( + child: MyText.bodyLarge("Welcome Back!", fontWeight: 600), + ), + MySpacing.height(4), + Center( + child: MyText.bodySmall("Please sign in to continue."), + ), + MySpacing.height(20), + + /// Email Field + MyText.bodySmall("Email Address", fontWeight: 600), + MySpacing.height(8), + Material( + elevation: 2, + shadowColor: contentTheme.secondary.withAlpha(30), + borderRadius: BorderRadius.circular(12), + child: TextFormField( + validator: + controller.basicValidator.getValidation('username'), + controller: + controller.basicValidator.getController('username'), + keyboardType: TextInputType.emailAddress, + style: MyTextStyle.labelMedium(), + decoration: InputDecoration( + hintText: "Enter your email", + hintStyle: MyTextStyle.bodySmall(xMuted: true), + filled: true, + fillColor: theme.cardColor, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(2), + borderSide: BorderSide.none, + ), + prefixIcon: const Icon(LucideIcons.mail, size: 18), + contentPadding: MySpacing.xy(12, 16), + ), + ), + ), + MySpacing.height(16), + + /// Password Field Label + MyText.bodySmall("Password", fontWeight: 600), + MySpacing.height(8), + Material( + elevation: 2, + shadowColor: contentTheme.secondary.withAlpha(25), + borderRadius: BorderRadius.circular(12), + child: TextFormField( + validator: + controller.basicValidator.getValidation('password'), + controller: + controller.basicValidator.getController('password'), + keyboardType: TextInputType.visiblePassword, + obscureText: !controller.showPassword, + style: MyTextStyle.labelMedium(), + decoration: InputDecoration( + hintText: "Enter your password", + hintStyle: MyTextStyle.bodySmall(xMuted: true), + filled: true, + fillColor: theme.cardColor, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(2), + borderSide: BorderSide.none, + ), + prefixIcon: const Icon(LucideIcons.lock, size: 18), + suffixIcon: InkWell( + onTap: controller.onChangeShowPassword, + child: Icon( + controller.showPassword + ? LucideIcons.eye + : LucideIcons.eye_off, + size: 18, + ), + ), + contentPadding: MySpacing.all(3), + ), + ), + ), + + MySpacing.height(16), + + /// Remember Me + Forgot Password + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () => controller + .onChangeCheckBox(!controller.isChecked), + child: Row( + children: [ + Checkbox( + onChanged: controller.onChangeCheckBox, + value: controller.isChecked, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + ), + fillColor: WidgetStatePropertyAll( + contentTheme.secondary), + checkColor: contentTheme.onPrimary, + visualDensity: getCompactDensity, + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + ), + MySpacing.width(8), + MyText.bodySmall("Remember Me"), + ], + ), + ), + MyButton.text( + onPressed: controller.goToForgotPassword, + elevation: 0, + padding: MySpacing.xy(8, 0), + splashColor: contentTheme.secondary.withAlpha(36), + child: MyText.bodySmall( + 'Forgot password?', + fontWeight: 600, + color: contentTheme.secondary, + ), ), - MySpacing.width(8), - MyText.bodySmall("Remember Me"), ], ), - ), - MyButton.text( - onPressed: controller.goToForgotPassword, - elevation: 0, - padding: MySpacing.xy(8, 0), - splashColor: contentTheme.secondary.withAlpha(36), - child: MyText.bodySmall('Forgot password?', color: contentTheme.secondary), - ), - ], - ), - MySpacing.height(28), - Center( - child: MyButton.rounded( - onPressed: controller.onLogin, - elevation: 0, - padding: MySpacing.xy(20, 16), - backgroundColor: contentTheme.primary, - child: MyText.labelMedium('Login', color: contentTheme.onPrimary), + MySpacing.height(28), + + /// Login Button + Center( + child: MyButton.rounded( + onPressed: controller.onLogin, + elevation: 2, + padding: MySpacing.xy(24, 16), + borderRadiusAll: 16, + backgroundColor: contentTheme.primary, + child: MyText.labelMedium( + 'Login', + fontWeight: 600, + color: contentTheme.onPrimary, + ), + ), + ), + MySpacing.height(16), + + /// Register Link + Center( + child: MyButton.text( + onPressed: controller.gotoRegister, + elevation: 0, + padding: MySpacing.xy(12, 8), + splashColor: contentTheme.secondary.withAlpha(30), + child: MyText.bodySmall( + "Request a Demo", + color: contentTheme.secondary, + fontWeight: 600, + ), + ), + ), + ], ), ), - Center( - child: MyButton.text( - onPressed: controller.gotoRegister, - elevation: 0, - padding: MySpacing.x(16), - splashColor: contentTheme.secondary.withValues(alpha:0.1), - child: MyText.bodySmall('I haven\'t account'), - ), - ), - ], - ), - ); - },), + ), + ); + }, + ), ); } } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 8d64b90..be27872 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,12 +5,14 @@ import FlutterMacOS import Foundation +import file_picker import path_provider_foundation import quill_native_bridge_macos import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) QuillNativeBridgePlugin.register(with: registry.registrar(forPlugin: "QuillNativeBridgePlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/pubspec.lock b/pubspec.lock index f074c30..8c8a093 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -157,10 +157,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "89500471922dd3a89ab0d6e13ab4a2268c25474bff4ca7c628f55c76e0ced1de" + sha256: cacfdc5abe93e64d418caa9256eef663499ad791bb688d9fd12c85a311968fba url: "https://pub.dev" source: hosted - version: "8.1.5" + version: "8.3.2" file_selector_linux: dependency: transitive description: @@ -366,7 +366,7 @@ packages: source: hosted version: "0.15.5" http: - dependency: transitive + dependency: "direct main" description: name: http sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 diff --git a/pubspec.yaml b/pubspec.yaml index 8b242a4..e443141 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,6 +58,8 @@ dependencies: appflowy_board: ^0.1.2 syncfusion_flutter_calendar: ^28.2.6 syncfusion_flutter_maps: ^28.1.33 + http: ^1.2.2 + dev_dependencies: flutter_test: