Update dependencies, improve login functionality, and enhance .gitignore

- Updated Android Gradle plugin version to 8.2.1
- Added new entries to .gitignore for better file management
- Changed dummy email and password in LoginController for testing
- Updated AuthService to handle login via API with improved error handling
- Modified User model to use username instead of email
- Enhanced login screen UI with better structure and design
- Registered new plugins in GeneratedPluginRegistrant.swift
- Updated package versions in pubspec.yaml and pubspec.lock
This commit is contained in:
Vaibhav Surve 2025-04-17 17:47:34 +05:30
parent 99902e743c
commit 23cfebfc37
11 changed files with 352 additions and 134 deletions

144
.gitignore vendored
View File

@ -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 # Miscellaneous
*.class *.class
*.lock
*.log *.log
*.pyc *.pyc
*.swp *.swp
@ -16,10 +20,46 @@ migrate_working_dir/
*.iws *.iws
.idea/ .idea/
# The .vscode folder contains launch configuration and tasks you configure in # Visual Studio Code related
# VS Code which you may wish to be included in version control, so this line .classpath
# is commented out by default. .project
#.vscode/ .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 # Flutter/Dart/Pub related
**/doc/api/ **/doc/api/
@ -27,17 +67,97 @@ migrate_working_dir/
.dart_tool/ .dart_tool/
.flutter-plugins .flutter-plugins
.flutter-plugins-dependencies .flutter-plugins-dependencies
**/generated_plugin_registrant.dart
.packages
.pub-preload-cache/
.pub-cache/ .pub-cache/
.pub/ .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 app.*.symbols
# Obfuscation related # Exceptions to above rules.
app.*.map.json !**/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 # Monorepo
/android/app/debug .cipd
/android/app/profile .gclient
/android/app/release .gclient_entries
.python-version
.gclient_previous_custom_vars
.gclient_previous_sync_commits

View File

@ -18,7 +18,7 @@ pluginManagement {
plugins { plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0" 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 id "org.jetbrains.kotlin.android" version "1.8.22" apply false
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 970 KiB

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -10,12 +10,12 @@ class LoginController extends MyController {
bool showPassword = false, isChecked = false; bool showPassword = false, isChecked = false;
final String _dummyEmail = "demo@example.com"; final String _dummyEmail = "admin@marcobms.com";
final String _dummyPassword = "1234567"; final String _dummyPassword = "User@123";
@override @override
void onInit() { 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', basicValidator.addField('password',
required: true, label: "Password", validators: [MyLengthValidator(min: 6, max: 10)], controller: TextEditingController(text: _dummyPassword)); required: true, label: "Password", validators: [MyLengthValidator(min: 6, max: 10)], controller: TextEditingController(text: _dummyPassword));

View File

@ -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/helpers/services/storage/local_storage.dart';
import 'package:marco/model/user.dart';
class AuthService { class AuthService {
static bool isLoggedIn = false; static bool isLoggedIn = false;
static User get dummyUser => User(-1, "demo@example.com", "Denish", "Navadiya");
static Future<Map<String, String>?> loginUser( static Future<Map<String, String>?> loginUser(
Map<String, dynamic> data) async { Map<String, dynamic> data) async {
await Future.delayed(Duration(seconds: 1)); try {
if (data['email'] != dummyUser.email) { final response = await http.post(
return {"email": "This email is not registered"}; Uri.parse('https://api.marcoaiot.com/api/auth/login'),
} else if (data['password'] != "1234567") { headers: {'Content-Type': 'application/json'},
return {"password": "Password is incorrect"}; body: jsonEncode(data),
} );
if (response.statusCode == 200) {
isLoggedIn = true; isLoggedIn = true;
await LocalStorage.setLoggedInUser(true); await LocalStorage.setLoggedInUser(true);
return null; // 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."};
}
} }
} }

View File

@ -1,9 +1,9 @@
import 'package:marco/model/identifier_model.dart'; import 'package:marco/model/identifier_model.dart';
class User extends IdentifierModel { 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"; String get name => "$firstName $lastName";

View File

@ -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.dart';
import 'package:marco/helpers/widgets/my_text_style.dart'; import 'package:marco/helpers/widgets/my_text_style.dart';
import 'package:marco/view/layouts/auth_layout.dart'; import 'package:marco/view/layouts/auth_layout.dart';
import 'package:marco/images.dart';
class LoginScreen extends StatefulWidget { class LoginScreen extends StatefulWidget {
const LoginScreen({super.key}); const LoginScreen({super.key});
@ -29,76 +30,139 @@ class _LoginScreenState extends State<LoginScreen> with UIMixin{
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AuthLayout( return AuthLayout(
child: GetBuilder( child: GetBuilder<LoginController>(
init: controller, init: controller,
tag: 'login_controller', tag: 'login_controller',
builder: (controller) { builder: (controller) {
return Form( return Form(
key: controller.basicValidator.formKey, 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( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [ children: [
MyText.titleLarge("Sign in with email", fontWeight: 600), /// Logo
MySpacing.height(12), Center(
MyText.bodyMedium("Make a new doc to bring your words, data and terms together. For free", fontWeight: 600, xMuted: true), child: Image.asset(
MySpacing.height(12), Images.logoDark,
TextFormField( height: 120,
validator: controller.basicValidator.getValidation('email'), fit: BoxFit.contain,
controller: controller.basicValidator.getController('email'), ),
),
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, keyboardType: TextInputType.emailAddress,
style: MyTextStyle.labelMedium(), style: MyTextStyle.labelMedium(),
decoration: InputDecoration( decoration: InputDecoration(
labelText: "Email Address", hintText: "Enter your email",
labelStyle: MyTextStyle.bodySmall(xMuted: true), hintStyle: MyTextStyle.bodySmall(xMuted: true),
border: OutlineInputBorder(borderSide: BorderSide.none),
filled: true, filled: true,
fillColor: contentTheme.secondary.withAlpha(36), fillColor: theme.cardColor,
prefixIcon: const Icon(LucideIcons.mail, size: 16), border: OutlineInputBorder(
contentPadding: MySpacing.all(14), borderRadius: BorderRadius.circular(2),
isDense: true, borderSide: BorderSide.none,
isCollapsed: true,
floatingLabelBehavior: FloatingLabelBehavior.never),
), ),
MySpacing.height(20), prefixIcon: const Icon(LucideIcons.mail, size: 18),
TextFormField( contentPadding: MySpacing.xy(12, 16),
validator: controller.basicValidator.getValidation('password'), ),
controller: controller.basicValidator.getController('password'), ),
),
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, keyboardType: TextInputType.visiblePassword,
obscureText: !controller.showPassword, obscureText: !controller.showPassword,
style: MyTextStyle.labelMedium(), style: MyTextStyle.labelMedium(),
decoration: InputDecoration( decoration: InputDecoration(
labelText: "Password", hintText: "Enter your password",
labelStyle: MyTextStyle.bodySmall(xMuted: true), hintStyle: MyTextStyle.bodySmall(xMuted: true),
border: OutlineInputBorder(borderSide: BorderSide.none),
filled: true, filled: true,
fillColor: contentTheme.secondary.withAlpha(36), fillColor: theme.cardColor,
prefixIcon: const Icon(LucideIcons.mail, size: 16), border: OutlineInputBorder(
contentPadding: MySpacing.all(16), borderRadius: BorderRadius.circular(2),
isCollapsed: true, borderSide: BorderSide.none,
isDense: true, ),
floatingLabelBehavior: FloatingLabelBehavior.never, prefixIcon: const Icon(LucideIcons.lock, size: 18),
suffixIcon: InkWell( suffixIcon: InkWell(
onTap: controller.onChangeShowPassword, onTap: controller.onChangeShowPassword,
child: Icon(controller.showPassword ? LucideIcons.eye : LucideIcons.eye_off, size: 16), child: Icon(
)), controller.showPassword
? LucideIcons.eye
: LucideIcons.eye_off,
size: 18,
), ),
),
contentPadding: MySpacing.all(3),
),
),
),
MySpacing.height(16),
/// Remember Me + Forgot Password
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
InkWell( InkWell(
onTap: () => controller.onChangeCheckBox(!controller.isChecked), onTap: () => controller
.onChangeCheckBox(!controller.isChecked),
child: Row( child: Row(
children: [ children: [
Checkbox( Checkbox(
onChanged: controller.onChangeCheckBox, onChanged: controller.onChangeCheckBox,
value: controller.isChecked, value: controller.isChecked,
fillColor: WidgetStatePropertyAll(Colors.white), shape: RoundedRectangleBorder(
activeColor: theme.colorScheme.primary, borderRadius: BorderRadius.circular(4),
checkColor: contentTheme.primary, ),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, fillColor: WidgetStatePropertyAll(
contentTheme.secondary),
checkColor: contentTheme.onPrimary,
visualDensity: getCompactDensity, visualDensity: getCompactDensity,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
), ),
MySpacing.width(8), MySpacing.width(8),
MyText.bodySmall("Remember Me"), MyText.bodySmall("Remember Me"),
@ -110,33 +174,54 @@ class _LoginScreenState extends State<LoginScreen> with UIMixin{
elevation: 0, elevation: 0,
padding: MySpacing.xy(8, 0), padding: MySpacing.xy(8, 0),
splashColor: contentTheme.secondary.withAlpha(36), splashColor: contentTheme.secondary.withAlpha(36),
child: MyText.bodySmall('Forgot password?', color: contentTheme.secondary), child: MyText.bodySmall(
'Forgot password?',
fontWeight: 600,
color: contentTheme.secondary,
),
), ),
], ],
), ),
MySpacing.height(28), MySpacing.height(28),
/// Login Button
Center( Center(
child: MyButton.rounded( child: MyButton.rounded(
onPressed: controller.onLogin, onPressed: controller.onLogin,
elevation: 0, elevation: 2,
padding: MySpacing.xy(20, 16), padding: MySpacing.xy(24, 16),
borderRadiusAll: 16,
backgroundColor: contentTheme.primary, backgroundColor: contentTheme.primary,
child: MyText.labelMedium('Login', color: contentTheme.onPrimary), child: MyText.labelMedium(
'Login',
fontWeight: 600,
color: contentTheme.onPrimary,
), ),
), ),
),
MySpacing.height(16),
/// Register Link
Center( Center(
child: MyButton.text( child: MyButton.text(
onPressed: controller.gotoRegister, onPressed: controller.gotoRegister,
elevation: 0, elevation: 0,
padding: MySpacing.x(16), padding: MySpacing.xy(12, 8),
splashColor: contentTheme.secondary.withValues(alpha:0.1), splashColor: contentTheme.secondary.withAlpha(30),
child: MyText.bodySmall('I haven\'t account'), child: MyText.bodySmall(
"Request a Demo",
color: contentTheme.secondary,
fontWeight: 600,
),
), ),
), ),
], ],
), ),
),
),
); );
},), },
),
); );
} }
} }

View File

@ -5,12 +5,14 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import file_picker
import path_provider_foundation import path_provider_foundation
import quill_native_bridge_macos import quill_native_bridge_macos
import shared_preferences_foundation import shared_preferences_foundation
import url_launcher_macos import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
QuillNativeBridgePlugin.register(with: registry.registrar(forPlugin: "QuillNativeBridgePlugin")) QuillNativeBridgePlugin.register(with: registry.registrar(forPlugin: "QuillNativeBridgePlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))

View File

@ -157,10 +157,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: file_picker name: file_picker
sha256: "89500471922dd3a89ab0d6e13ab4a2268c25474bff4ca7c628f55c76e0ced1de" sha256: cacfdc5abe93e64d418caa9256eef663499ad791bb688d9fd12c85a311968fba
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.1.5" version: "8.3.2"
file_selector_linux: file_selector_linux:
dependency: transitive dependency: transitive
description: description:
@ -366,7 +366,7 @@ packages:
source: hosted source: hosted
version: "0.15.5" version: "0.15.5"
http: http:
dependency: transitive dependency: "direct main"
description: description:
name: http name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010

View File

@ -58,6 +58,8 @@ dependencies:
appflowy_board: ^0.1.2 appflowy_board: ^0.1.2
syncfusion_flutter_calendar: ^28.2.6 syncfusion_flutter_calendar: ^28.2.6
syncfusion_flutter_maps: ^28.1.33 syncfusion_flutter_maps: ^28.1.33
http: ^1.2.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: