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
*.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

View File

@ -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
}

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;
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));

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/model/user.dart';
class AuthService {
static bool isLoggedIn = false;
static User get dummyUser => User(-1, "demo@example.com", "Denish", "Navadiya");
static Future<Map<String, String>?> loginUser(
Map<String, dynamic> 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."};
}
}
}

View File

@ -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";

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_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<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> with UIMixin{
class _LoginScreenState extends State<LoginScreen> with UIMixin {
late LoginController controller;
@override
@ -29,114 +30,198 @@ class _LoginScreenState extends State<LoginScreen> with UIMixin{
@override
Widget build(BuildContext context) {
return AuthLayout(
child: GetBuilder(
child: GetBuilder<LoginController>(
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'),
),
),
],
),
);
},),
),
);
},
),
);
}
}

View File

@ -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"))

View File

@ -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

View File

@ -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: