diff --git a/android/app/build.gradle b/android/app/build.gradle
index 92a32c25..3198c04c 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -34,7 +34,7 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
namespace "in.ac.iitr.mdg.appetizer"
- compileSdkVersion 33
+ compileSdkVersion 34
ndkVersion flutter.ndkVersion
compileOptions {
diff --git a/assets/images/meal_card/Snacks.svg b/assets/images/meal_card/Snacks.svg
new file mode 100644
index 00000000..37e28b6a
--- /dev/null
+++ b/assets/images/meal_card/Snacks.svg
@@ -0,0 +1,330 @@
+
diff --git a/lib/data/constants/env_config.dart b/lib/data/constants/env_config.dart
index cc1de10c..cb33130f 100644
--- a/lib/data/constants/env_config.dart
+++ b/lib/data/constants/env_config.dart
@@ -15,4 +15,6 @@ class EnvironmentConfig {
);
static const String SENTRY_DSN = String.fromEnvironment('SENTRY_DSN');
+ static const String MIXPANEL_PROJECT_KEY =
+ String.fromEnvironment('MIXPANEL_PROJECT_KEY');
}
diff --git a/lib/data/core/router/registry/paths.dart b/lib/data/core/router/registry/paths.dart
index 743e4bd9..add491df 100644
--- a/lib/data/core/router/registry/paths.dart
+++ b/lib/data/core/router/registry/paths.dart
@@ -17,4 +17,5 @@ class AppPathsRegistry {
static const String leavesAndRebate = 'leavesAndRebate';
static const String feedback = 'feedback';
static const String hostelChange = 'hostelChange';
+ static const String resetPassword = 'resetPassword';
}
diff --git a/lib/data/core/router/registry/routes.dart b/lib/data/core/router/registry/routes.dart
index f7f57aa9..19473565 100644
--- a/lib/data/core/router/registry/routes.dart
+++ b/lib/data/core/router/registry/routes.dart
@@ -55,6 +55,10 @@ class AppRoutesRegistry {
path: AppPathsRegistry.feedback,
page: FeedbackRoute.page,
),
+ CustomRoute(
+ path: AppPathsRegistry.resetPassword,
+ page: ResetPasswordRoute.page,
+ ),
CustomRoute(
path: AppPathsRegistry.hostelChange,
page: HostelChangeRoute.page,
diff --git a/lib/domain/amenity/mixpanel_service.dart b/lib/domain/amenity/mixpanel_service.dart
new file mode 100644
index 00000000..acef3b61
--- /dev/null
+++ b/lib/domain/amenity/mixpanel_service.dart
@@ -0,0 +1,12 @@
+import 'package:appetizer/data/constants/env_config.dart';
+import 'package:mixpanel_flutter/mixpanel_flutter.dart';
+
+class MixpanelManager {
+ static Mixpanel? instance;
+
+ static Future init() async {
+ instance ??= await Mixpanel.init(EnvironmentConfig.MIXPANEL_PROJECT_KEY,
+ trackAutomaticEvents: true);
+ return instance!;
+ }
+}
diff --git a/lib/presentation/app/bloc/app_bloc.dart b/lib/presentation/app/bloc/app_bloc.dart
index 24b50b84..846f04ae 100644
--- a/lib/presentation/app/bloc/app_bloc.dart
+++ b/lib/presentation/app/bloc/app_bloc.dart
@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:appetizer/data/constants/constants.dart';
import 'package:appetizer/data/services/local/local_storage_service.dart';
+import 'package:appetizer/domain/amenity/mixpanel_service.dart';
import 'package:appetizer/domain/models/user/user.dart';
import 'package:appetizer/domain/repositories/leave/leave_repository.dart';
import 'package:appetizer/domain/repositories/user/user_repository.dart';
@@ -70,6 +71,8 @@ class AppBloc extends Bloc {
FutureOr _onNavigateToHome(
NavigateToHomeScreen event, Emitter emit) {
+ assert(state.user != null);
+ MixpanelManager.instance?.identify(state.user!.enrNo.toString());
emit(state.copyWith(navigateTo: NavigateTo.showHomeScreen));
}
diff --git a/lib/presentation/bottom_navigator/bottom_navigator_screen.dart b/lib/presentation/bottom_navigator/bottom_navigator_screen.dart
index 3ff16985..eec9ec32 100644
--- a/lib/presentation/bottom_navigator/bottom_navigator_screen.dart
+++ b/lib/presentation/bottom_navigator/bottom_navigator_screen.dart
@@ -2,9 +2,7 @@ import 'package:appetizer/data/core/router/intrinsic_router/intrinsic_router.gr.
import 'package:appetizer/domain/repositories/coupon_repository.dart';
import 'package:appetizer/domain/repositories/leave/leave_repository.dart';
import 'package:appetizer/domain/repositories/menu_repository.dart';
-import 'package:appetizer/presentation/app/bloc/app_bloc.dart';
import 'package:appetizer/domain/repositories/transaction_repositroy.dart';
-import 'package:appetizer/presentation/components/round_edge_container.dart';
import 'package:appetizer/domain/repositories/user/user_repository.dart';
import 'package:appetizer/presentation/leaves_and_rebate/bloc/leaves_and_rebate_bloc.dart';
import 'package:appetizer/presentation/profile/bloc/profile_page_bloc.dart';
@@ -63,26 +61,6 @@ class BottomNavigatorScreen extends StatelessWidget {
return Scaffold(
backgroundColor: Colors.white,
body: child,
- floatingActionButton: Visibility(
- visible: tabRouter.activeIndex == 1,
- child: BlocSelector(
- selector: (appState) => appState.user!.isCheckedOut,
- builder: (context, isCheckedOut) {
- if (isCheckedOut) return const SizedBox();
-
- return GestureDetector(
- onTap: () {
- context
- .read()
- .add(const ToggleCheckOutStatusEvent());
- },
- child: const RoundEdgeTextOnlyContainer(text: "CHECK OUT"),
- );
- },
- ),
- ),
- floatingActionButtonLocation:
- FloatingActionButtonLocation.centerFloat,
bottomNavigationBar: BottomNavigationBar(
key: UniqueKey(),
currentIndex: tabRouter.activeIndex,
diff --git a/lib/presentation/components/app_formfield.dart b/lib/presentation/components/app_formfield.dart
new file mode 100644
index 00000000..b60b85e2
--- /dev/null
+++ b/lib/presentation/components/app_formfield.dart
@@ -0,0 +1,68 @@
+import 'package:appetizer/data/core/theme/dimensional/dimensional.dart';
+import 'package:appetizer/presentation/components/app_textfield.dart';
+import 'package:flutter/material.dart';
+import 'package:google_fonts/google_fonts.dart';
+
+class AppFormField extends StatelessWidget {
+ const AppFormField({
+ super.key,
+ required this.hintText,
+ this.controller,
+ this.onChanged,
+ this.obscureText,
+ this.suffix,
+ this.border,
+ required this.title,
+ this.maxLength,
+ this.maxLines,
+ this.titleStyle,
+ }) : assert(
+ obscureText == null || suffix != null,
+ 'Suffix should be provided if obscureText is provided',
+ ),
+ assert(
+ controller != null || onChanged != null,
+ 'Either controller or onChanged should be provided',
+ );
+
+ final String hintText;
+ final TextEditingController? controller;
+ final Function(String)? onChanged;
+ final bool? obscureText;
+ final Widget? suffix;
+ final InputBorder? border;
+ final String title;
+ final int? maxLength;
+ final int? maxLines;
+ final TextStyle? titleStyle;
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ title,
+ style: titleStyle ??
+ GoogleFonts.notoSans(
+ fontSize: 18.toAutoScaledFont,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+ SizedBox(
+ height: title == "Description" ? 0 : 20.toAutoScaledHeight,
+ ),
+ AppTextField(
+ controller: controller,
+ onChanged: onChanged,
+ obscureText: obscureText,
+ hintText: hintText,
+ suffix: suffix,
+ border: border,
+ maxLength: maxLength,
+ maxLines: maxLines,
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/presentation/components/app_textfield.dart b/lib/presentation/components/app_textfield.dart
new file mode 100644
index 00000000..cc89ed79
--- /dev/null
+++ b/lib/presentation/components/app_textfield.dart
@@ -0,0 +1,61 @@
+import 'package:appetizer/data/core/theme/dimensional/dimensional.dart';
+import 'package:flutter/material.dart';
+import 'package:google_fonts/google_fonts.dart';
+
+class AppTextField extends StatelessWidget {
+ const AppTextField({
+ super.key,
+ required this.hintText,
+ this.controller,
+ this.onChanged,
+ this.obscureText,
+ this.suffix,
+ this.border,
+ this.maxLength,
+ this.maxLines,
+ }) : assert(
+ obscureText == null || suffix != null,
+ 'Suffix should be provided if obscureText is provided',
+ ),
+ assert(
+ controller != null || onChanged != null,
+ 'Either controller or onChanged should be provided',
+ );
+
+ final String hintText;
+ final TextEditingController? controller;
+ final Function(String)? onChanged;
+ final bool? obscureText;
+ final Widget? suffix;
+ final InputBorder? border;
+ final int? maxLength;
+ final int? maxLines;
+
+ @override
+ Widget build(BuildContext context) {
+ return TextField(
+ controller: controller,
+ onChanged: onChanged,
+ obscureText: obscureText ?? false,
+ decoration: InputDecoration(
+ hintText: hintText,
+ hintStyle: GoogleFonts.lato(
+ fontSize: 12.toAutoScaledFont,
+ color: const Color(0xFF111111),
+ fontWeight: FontWeight.w600,
+ ),
+ border: border ??
+ OutlineInputBorder(
+ borderSide: BorderSide(
+ color: const Color(0xFF111111).withOpacity(0.25)),
+ borderRadius: BorderRadius.circular(5),
+ ),
+ contentPadding: EdgeInsets.symmetric(
+ horizontal: 20.toAutoScaledWidth,
+ vertical: 15.toAutoScaledHeight),
+ suffixIcon: suffix),
+ maxLength: maxLength,
+ maxLines: maxLines ?? 1,
+ );
+ }
+}
diff --git a/lib/presentation/components/black_button.dart b/lib/presentation/components/black_button.dart
index 6f650e22..42881b46 100644
--- a/lib/presentation/components/black_button.dart
+++ b/lib/presentation/components/black_button.dart
@@ -7,8 +7,8 @@ class BlackButton extends StatelessWidget {
required this.title,
required this.onTap,
required this.width,
- Key? key,
- }) : super(key: key);
+ super.key,
+ });
final VoidCallback onTap;
final String title;
@@ -48,8 +48,8 @@ class BlackIconButton extends StatelessWidget {
required this.onTap,
required this.width,
required this.icon,
- Key? key,
- }) : super(key: key);
+ super.key,
+ });
final VoidCallback onTap;
final String title;
diff --git a/lib/presentation/components/no_data_found_container.dart b/lib/presentation/components/no_data_found_container.dart
index 69f973ed..46991da2 100644
--- a/lib/presentation/components/no_data_found_container.dart
+++ b/lib/presentation/components/no_data_found_container.dart
@@ -3,44 +3,38 @@ import 'package:flutter/material.dart';
// import 'package:flutter_svg/flutter_svg.dart';
class NoDataFoundContainer extends StatelessWidget {
- const NoDataFoundContainer({
- required this.title,
- Key? key,
- }) : super(key: key);
+ const NoDataFoundContainer({required this.title, super.key});
final String title;
@override
Widget build(BuildContext context) {
- return Container(
- alignment: Alignment.center,
- padding: EdgeInsets.only(top: 150.toAutoScaledHeight),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- // TODO: check why svg doesnt work
- // SvgPicture.asset(
- // 'assets/images/no_data_image.svg',
- // // 'assets/images/no_data_image.svg',
- // height: 178.toAutoScaledHeight,
- // width: 186.toAutoScaledWidth,
- // ),
- Image.asset(
- 'assets/images/no_data_image.png',
- height: 178.toAutoScaledHeight,
- width: 186.toAutoScaledWidth,
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ // TODO: check why svg doesnt work
+ // SvgPicture.asset(
+ // 'assets/images/no_data_image.svg',
+ // // 'assets/images/no_data_image.svg',
+ // height: 178.toAutoScaledHeight,
+ // width: 186.toAutoScaledWidth,
+ // ),
+ Image.asset(
+ 'assets/images/no_data_image.png',
+ height: 178.toAutoScaledHeight,
+ width: 186.toAutoScaledWidth,
+ ),
+ Text(
+ title,
+ style: TextStyle(
+ color: const Color(0xFF111111),
+ fontSize: 18.toAutoScaledFont,
+ fontFamily: 'Noto Sans',
+ fontWeight: FontWeight.w400,
),
- Text(
- title,
- style: TextStyle(
- color: const Color(0xFF111111),
- fontSize: 18.toAutoScaledFont,
- fontFamily: 'Noto Sans',
- fontWeight: FontWeight.w400,
- ),
- ),
- ],
- ),
+ ),
+ ],
);
}
}
diff --git a/lib/presentation/coupons/components/coupon_row.dart b/lib/presentation/coupons/components/coupon_row.dart
index 37f0323a..4ffadb10 100644
--- a/lib/presentation/coupons/components/coupon_row.dart
+++ b/lib/presentation/coupons/components/coupon_row.dart
@@ -4,10 +4,7 @@ import 'package:appetizer/presentation/coupons/components/coupon_card.dart';
import 'package:flutter/material.dart';
class CouponRow extends StatelessWidget {
- const CouponRow({
- required this.coupons,
- Key? key,
- }) : super(key: key);
+ const CouponRow({required this.coupons, super.key});
final List coupons;
diff --git a/lib/presentation/feedback/components/FeedbackTile/feedback_tile.dart b/lib/presentation/feedback/components/FeedbackTile/feedback_tile.dart
index 0dde8a19..d441f677 100644
--- a/lib/presentation/feedback/components/FeedbackTile/feedback_tile.dart
+++ b/lib/presentation/feedback/components/FeedbackTile/feedback_tile.dart
@@ -10,8 +10,8 @@ class FeedbackTile extends StatelessWidget {
required this.title,
required this.parentState,
required this.index,
- Key? key,
- }) : super(key: key);
+ super.key,
+ });
final String title;
final FeedbackPageState parentState;
diff --git a/lib/presentation/feedback/feedback_view.dart b/lib/presentation/feedback/feedback_view.dart
index 7c461893..2f90146a 100644
--- a/lib/presentation/feedback/feedback_view.dart
+++ b/lib/presentation/feedback/feedback_view.dart
@@ -1,6 +1,7 @@
import 'package:appetizer/app_theme.dart';
import 'package:appetizer/data/core/theme/dimensional/dimensional.dart';
import 'package:appetizer/domain/repositories/feedback_repository.dart';
+import 'package:appetizer/presentation/components/app_formfield.dart';
import 'package:appetizer/presentation/components/black_button.dart';
import 'package:appetizer/presentation/feedback/bloc/feedback_page_bloc.dart';
import 'package:appetizer/presentation/feedback/components/FeedbackTile/feedback_tile.dart';
@@ -72,29 +73,26 @@ class FeedbackScreen extends StatelessWidget {
fontWeight: FontWeight.w400,
),
),
- Text(
- 'Description',
- style: TextStyle(
+ AppFormField(
+ hintText: "",
+ title: "Description",
+ controller: textController,
+ titleStyle: TextStyle(
color: Colors.black.withOpacity(0.5400000214576721),
fontSize: 12.toAutoScaledFont,
fontFamily: 'Open Sans',
fontWeight: FontWeight.w400,
),
- ),
- TextField(
- controller: textController,
onChanged: (value) => context
.read()
.add(FeedbackPageDescriptionChangedEvent(
description: value)),
maxLength: 200,
maxLines: 5,
- decoration: InputDecoration(
- border: OutlineInputBorder(
- borderSide: BorderSide(
- width: 0.5.toAutoScaledWidth,
- color: const Color.fromARGB(37, 0, 0, 0),
- ),
+ border: OutlineInputBorder(
+ borderSide: BorderSide(
+ width: 0.5.toAutoScaledWidth,
+ color: const Color.fromARGB(37, 0, 0, 0),
),
),
),
diff --git a/lib/presentation/leaves_and_rebate/components/leave_history.dart b/lib/presentation/leaves_and_rebate/components/leave_history.dart
index c7e27125..47eeaf7e 100644
--- a/lib/presentation/leaves_and_rebate/components/leave_history.dart
+++ b/lib/presentation/leaves_and_rebate/components/leave_history.dart
@@ -14,70 +14,74 @@ class LeaveHistory extends StatelessWidget {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 24),
decoration: ShapeDecoration(
- color: AppTheme.white,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(15),
- ),
- shadows: [
- BoxShadow(
- color: const Color(0x19000000),
- blurRadius: 7.toAutoScaledWidth,
- offset: const Offset(2, 2),
- spreadRadius: 1,
- )
- ]),
+ color: AppTheme.white,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(15),
+ ),
+ shadows: [
+ BoxShadow(
+ color: const Color(0x19000000),
+ blurRadius: 7.toAutoScaledWidth,
+ offset: const Offset(2, 2),
+ spreadRadius: 1,
+ )
+ ],
+ ),
child: SingleChildScrollView(
child: ExpansionTile(
expandedCrossAxisAlignment: CrossAxisAlignment.start,
backgroundColor: AppTheme.white,
title: const SizedBox.shrink(),
- leading: Text("Leave History",
- style: AppTheme.headline3.copyWith(
- fontSize: 16.toAutoScaledFont,
- color: AppTheme.grey2f,
- height: (11.0 / 8.0).toAutoScaledHeight)),
+ leading: Text(
+ "Leave History",
+ style: AppTheme.headline3.copyWith(
+ fontSize: 16.toAutoScaledFont,
+ color: AppTheme.grey2f,
+ height: (11.0 / 8.0).toAutoScaledHeight,
+ ),
+ ),
trailing: const Icon(Icons.expand_more, color: AppTheme.grey2f),
children: [
if (paginatedLeaves.results.isNotEmpty)
Container(
margin: EdgeInsets.only(left: 24.toAutoScaledWidth),
child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- paginatedLeaves.results[0].startDatetime.year
- .toString(),
- style: AppTheme.headline2.copyWith(
- fontSize: 14.toAutoScaledFont,
- color: AppTheme.primary),
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ paginatedLeaves.results[0].startDatetime.year.toString(),
+ style: AppTheme.headline2.copyWith(
+ fontSize: 14.toAutoScaledFont,
+ color: AppTheme.primary),
+ ),
+ 10.toVerticalSizedBox,
+ ...paginatedLeaves.results.map(
+ (leave) => Padding(
+ padding: EdgeInsets.only(bottom: 10.toAutoScaledHeight),
+ child: Row(
+ children: [
+ RichText(
+ text: TextSpan(
+ text: DateFormat('dd MMM -')
+ .format(leave.startDatetime),
+ style: AppTheme.bodyText1
+ .copyWith(height: 1.toAutoScaledHeight),
+ children: [
+ TextSpan(
+ text: leave.startMealType,
+ style: const TextStyle(
+ color: AppTheme.primary),
+ )
+ ],
+ ),
+ ),
+ // const Text("-"),
+ ],
+ ),
),
- 10.toVerticalSizedBox,
- ...paginatedLeaves.results
- .map((leave) => Padding(
- padding: EdgeInsets.only(
- bottom: 10.toAutoScaledHeight),
- child: Row(
- children: [
- RichText(
- text: TextSpan(
- text: DateFormat('dd MMM -')
- .format(leave.startDatetime),
- style: AppTheme.bodyText1.copyWith(
- height: 1.toAutoScaledHeight),
- children: [
- TextSpan(
- text: leave.startMealType,
- style: const TextStyle(
- color: AppTheme.primary),
- )
- ]),
- ),
- // const Text("-"),
- ],
- ),
- ))
- .toList(),
- ]),
+ ),
+ ],
+ ),
)
],
),
diff --git a/lib/presentation/login/components/oauth_webview.dart b/lib/presentation/login/components/oauth_webview.dart
index 623d2f8b..54c55580 100644
--- a/lib/presentation/login/components/oauth_webview.dart
+++ b/lib/presentation/login/components/oauth_webview.dart
@@ -6,7 +6,7 @@ import 'package:auto_route/auto_route.dart';
@RoutePage()
class OAuthWebScreen extends StatelessWidget {
static const id = 'oauth_view';
- OAuthWebScreen({Key? key}) : super(key: key);
+ OAuthWebScreen({super.key});
final ValueNotifier _loadingState = ValueNotifier(1);
@override
@@ -21,13 +21,13 @@ class OAuthWebScreen extends StatelessWidget {
children: [
InAppWebView(
initialUrlRequest: URLRequest(
- url: Uri.parse(AppConstants.omniportSignUpURL),
- ),
- initialOptions: InAppWebViewGroupOptions(
- crossPlatform: InAppWebViewOptions(
- useShouldOverrideUrlLoading: true,
+ url: WebUri.uri(
+ Uri.parse(AppConstants.omniportSignUpURL),
),
),
+ initialSettings: InAppWebViewSettings(
+ useShouldOverrideUrlLoading: true,
+ ),
onLoadStop: (_, uri) {
_loadingState.value = 0;
},
diff --git a/lib/presentation/login/login_screen.dart b/lib/presentation/login/login_screen.dart
index 5ec247ef..50f41a27 100644
--- a/lib/presentation/login/login_screen.dart
+++ b/lib/presentation/login/login_screen.dart
@@ -1,5 +1,7 @@
import 'package:appetizer/data/core/theme/dimensional/dimensional.dart';
import 'package:appetizer/presentation/app/bloc/app_bloc.dart';
+import 'package:appetizer/presentation/components/app_formfield.dart';
+import 'package:appetizer/presentation/components/app_textfield.dart';
import 'package:appetizer/presentation/components/loading_indicator.dart';
import 'package:appetizer/presentation/components/made_by_mdg.dart';
import 'package:appetizer/presentation/components/raise_query_button.dart';
@@ -92,85 +94,50 @@ class LoginScreen extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Text(
- 'Set Password',
- style: GoogleFonts.notoSans(
- fontSize: 18.toAutoScaledFont,
- fontWeight: FontWeight.w600,
- ),
- ),
- 20.toVerticalSizedBox,
- TextField(
+ AppFormField(
controller: _controller,
+ hintText: 'Create Password',
obscureText: !state.showPassword,
- decoration: InputDecoration(
- hintText: 'Create Password',
- hintStyle: GoogleFonts.lato(
- fontSize: 12,
- color: const Color(0xFF111111),
- fontWeight: FontWeight.w600,
- ),
- border: OutlineInputBorder(
- borderSide: BorderSide(
- color: const Color(0xFF111111)
- .withOpacity(0.25)),
- borderRadius: BorderRadius.circular(5),
- ),
- suffixIcon: IconButton(
- onPressed: () {
- context.read().add(
- ToggleObscureCreatePassword(
- showPassword: !state.showPassword,
- showConfirmPassword:
- state.showConfirmPassword,
- ),
- );
- },
- icon: state.showPassword
- ? const Icon(Icons.visibility,
- color: Color(0xFF757575))
- : const Icon(Icons.visibility_off,
- color: Color(0xFF757575)),
+ suffix: IconButton(
+ onPressed: () {
+ context.read().add(
+ ToggleObscureCreatePassword(
+ showPassword: !state.showPassword,
+ showConfirmPassword:
+ state.showConfirmPassword,
+ ),
+ );
+ },
+ icon: Icon(
+ state.showPassword
+ ? Icons.visibility
+ : Icons.visibility_off,
+ color: const Color(0xFF757575),
),
- contentPadding: EdgeInsets.symmetric(
- horizontal: 20.toAutoScaledWidth),
),
+ title: 'Set Password',
),
10.toVerticalSizedBox,
- TextField(
+ AppTextField(
controller: _controller2,
+ hintText: 'Confirm Password',
obscureText: !state.showConfirmPassword,
- decoration: InputDecoration(
- hintText: 'Confirm Password',
- hintStyle: GoogleFonts.lato(
- fontSize: 12.toAutoScaledFont,
- color: const Color(0xFF111111),
- fontWeight: FontWeight.w600,
- ),
- border: OutlineInputBorder(
- borderSide: BorderSide(
- color: const Color(0xFF111111)
- .withOpacity(0.25)),
- borderRadius: BorderRadius.circular(5),
- ),
- suffixIcon: IconButton(
- onPressed: () {
- context.read().add(
- ToggleObscureCreatePassword(
- showPassword: state.showPassword,
- showConfirmPassword:
- !state.showConfirmPassword,
- ),
- );
- },
- icon: state.showConfirmPassword
- ? const Icon(Icons.visibility,
- color: Color(0xFF757575))
- : const Icon(Icons.visibility_off,
- color: Color(0xFF757575)),
+ suffix: IconButton(
+ onPressed: () {
+ context.read().add(
+ ToggleObscureCreatePassword(
+ showPassword: state.showPassword,
+ showConfirmPassword:
+ !state.showConfirmPassword,
+ ),
+ );
+ },
+ icon: Icon(
+ state.showConfirmPassword
+ ? Icons.visibility
+ : Icons.visibility_off,
+ color: const Color(0xFF757575),
),
- contentPadding:
- const EdgeInsets.symmetric(horizontal: 20),
),
),
SizedBox(
@@ -206,54 +173,34 @@ class LoginScreen extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Text(
- state is ForgotPasswordState
+ AppFormField(
+ hintText: state is EnterPassword
+ ? "Password"
+ : state is ForgotPasswordState
+ ? "Email id"
+ : 'Enrollment No.',
+ title: state is ForgotPasswordState
? 'Forgot Password'
: 'Login/SignUp',
- style: GoogleFonts.notoSans(
- fontSize: 18,
- fontWeight: FontWeight.w600,
- ),
- ),
- 20.toVerticalSizedBox,
- TextField(
controller: _controller,
obscureText: state is EnterPassword
? !state.showPassword
: false,
- decoration: InputDecoration(
- hintText: state is EnterPassword
- ? "Password"
- : state is ForgotPasswordState
- ? "Email id"
- : 'Enrollment No.',
- hintStyle: GoogleFonts.lato(
- fontSize: 12.toAutoScaledFont,
- color: const Color(0xFF111111),
- fontWeight: FontWeight.w600,
- ),
- suffixIcon: state is EnterPassword
- ? IconButton(
- onPressed: () {
- context.read().add(
- ShowPasswordPressed(),
- );
- },
- icon: state.showPassword
- ? const Icon(Icons.visibility,
- color: Color(0xFF757575))
- : const Icon(Icons.visibility_off,
- color: Color(0xFF757575)))
- : null,
- border: OutlineInputBorder(
- borderSide: BorderSide(
- color: const Color(0xFF111111)
- .withOpacity(0.25)),
- borderRadius: BorderRadius.circular(5),
- ),
- contentPadding: EdgeInsets.symmetric(
- horizontal: 20.toAutoScaledWidth),
- ),
+ suffix: state is EnterPassword
+ ? IconButton(
+ onPressed: () {
+ context
+ .read()
+ .add(ShowPasswordPressed());
+ },
+ icon: Icon(
+ state.showPassword
+ ? Icons.visibility
+ : Icons.visibility_off,
+ color: const Color(0xFF757575),
+ ),
+ )
+ : const SizedBox(),
),
state is EnterPassword
? SizedBox(
diff --git a/lib/presentation/notifications/components/no_notification_widget.dart b/lib/presentation/notifications/components/no_notification_widget.dart
index fa6a1c33..bbe4e7b9 100644
--- a/lib/presentation/notifications/components/no_notification_widget.dart
+++ b/lib/presentation/notifications/components/no_notification_widget.dart
@@ -6,9 +6,7 @@ class NoNotificationsWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Container(
- alignment: Alignment.center,
- padding: EdgeInsets.only(top: 282.toAutoScaledHeight),
+ return Align(
child: Text(
'No new notifications !',
style: TextStyle(
diff --git a/lib/presentation/notifications/components/notification_card.dart b/lib/presentation/notifications/components/notification_card.dart
index 79841b4e..de6b4971 100644
--- a/lib/presentation/notifications/components/notification_card.dart
+++ b/lib/presentation/notifications/components/notification_card.dart
@@ -4,10 +4,7 @@ import 'package:flutter/material.dart';
import 'package:appetizer/domain/models/user/notification.dart' as notification;
class NotificationCard extends StatelessWidget {
- const NotificationCard({
- required this.data,
- Key? key,
- }) : super(key: key);
+ const NotificationCard({required this.data, super.key});
final notification.Notification data;
diff --git a/lib/presentation/notifications/notification_view.dart b/lib/presentation/notifications/notification_view.dart
index ea2fcfb6..265d81a5 100644
--- a/lib/presentation/notifications/notification_view.dart
+++ b/lib/presentation/notifications/notification_view.dart
@@ -19,72 +19,51 @@ class NotificationScreen extends StatelessWidget {
return Scaffold(
backgroundColor: AppTheme.white,
// TODO: implement Old/New notification bars and logic
- body: BlocProvider(
- create: (context) =>
- NotificationPageBloc(repo: context.read()),
- child: BlocBuilder(
- builder: (context, state) {
- if (state is NotificationPageInitialState) {
- context
- .read()
- .add(const NotificationPageFetchEvent(notifications: []));
- return const Column(
- children: [
- NotificationBanner(),
- NoDataFoundContainer(title: 'Oops! Just a moment...'),
- ],
- );
- }
- if (state is NotificationPageFailedState) {
- // TODO: throw an error, or snackbar
- return const Column(
- children: [
- NotificationBanner(),
- NoDataFoundContainer(title: 'Something went wrong...'),
- ],
- );
- }
- if (state is NotificationPageFetchedState) {
- if (state.notifications.isEmpty) {
- return const Column(
- children: [
- NotificationBanner(),
- NoNotificationsWidget(),
- ],
- );
- }
- return Column(
- children: [
- const NotificationBanner(),
- Container(
- height: 656.toAutoScaledHeight,
- padding: EdgeInsets.only(
- left: 24.toAutoScaledWidth,
- right: 25.toAutoScaledWidth,
- ),
- child: ListView.builder(
- padding: EdgeInsets.zero,
- itemCount: state.notifications.length,
- itemBuilder: (context, index) {
- return Column(
- children: [
- NotificationCard(
- data: state.notifications[index],
- ),
- index < state.notifications.length
- ? 16.toVerticalSizedBox
- : const SizedBox.shrink(),
- ],
- );
- },
- ),
- ),
- ],
- );
- }
- return const NoDataFoundContainer(title: 'Something went wrong !');
- },
- ),
+ body: Column(
+ children: [
+ const NotificationBanner(),
+ Expanded(
+ child: BlocProvider(
+ create: (context) =>
+ NotificationPageBloc(repo: context.read()),
+ child: BlocBuilder(
+ builder: (context, state) {
+ if (state is NotificationPageInitialState) {
+ context.read().add(
+ const NotificationPageFetchEvent(notifications: []));
+ return const NoDataFoundContainer(
+ title: 'Oops! Just a moment...');
+ }
+ if (state is NotificationPageFailedState) {
+ // TODO: throw an error, or snackbar
+ return const NoDataFoundContainer(
+ title: 'Something went wrong...');
+ }
+ if (state is NotificationPageFetchedState) {
+ return Visibility(
+ visible: state.notifications.isNotEmpty,
+ replacement: const NoNotificationsWidget(),
+ child: ListView.separated(
+ padding: 24.toHorizontalPadding,
+ shrinkWrap: true,
+ itemCount: state.notifications.length,
+ separatorBuilder: (context, index) =>
+ 16.toVerticalSizedBox,
+ itemBuilder: (context, index) {
+ return NotificationCard(
+ data: state.notifications[index],
+ );
+ },
+ ),
+ );
+ }
+ return const NoDataFoundContainer(
+ title: 'Something went wrong !');
+ },
+ ),
+ ),
+ ),
+ ],
),
);
}
diff --git a/lib/presentation/profile/components/profile_card.dart b/lib/presentation/profile/components/profile_card.dart
index fb0be707..32d81cd2 100644
--- a/lib/presentation/profile/components/profile_card.dart
+++ b/lib/presentation/profile/components/profile_card.dart
@@ -7,8 +7,8 @@ class Fields extends StatelessWidget {
const Fields({
required this.title,
required this.data,
- Key? key,
- }) : super(key: key);
+ super.key,
+ });
final String title;
final String data;
@@ -41,10 +41,7 @@ class Fields extends StatelessWidget {
}
class ProfileCard extends StatelessWidget {
- const ProfileCard({
- required this.data,
- Key? key,
- }) : super(key: key);
+ const ProfileCard({required this.data, super.key});
final User data;
diff --git a/lib/presentation/profile/components/profile_photo.dart b/lib/presentation/profile/components/profile_photo.dart
index c0f4aef7..735eba3b 100644
--- a/lib/presentation/profile/components/profile_photo.dart
+++ b/lib/presentation/profile/components/profile_photo.dart
@@ -5,10 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ProfilePhoto extends StatelessWidget {
- const ProfilePhoto({
- required this.imageUri,
- Key? key,
- }) : super(key: key);
+ const ProfilePhoto({required this.imageUri, super.key});
final String imageUri;
diff --git a/lib/presentation/profile/profile_view.dart b/lib/presentation/profile/profile_view.dart
index ecc3ee84..854cbdac 100644
--- a/lib/presentation/profile/profile_view.dart
+++ b/lib/presentation/profile/profile_view.dart
@@ -59,6 +59,7 @@ class ProfileScreen extends StatelessWidget {
Container(
padding: EdgeInsets.symmetric(
vertical: 24.toAutoScaledHeight,
+ // horizontal: 43.toAutoScaledWidth,
),
child: Column(
children: [
@@ -76,18 +77,15 @@ class ProfileScreen extends StatelessWidget {
ScaffoldMessenger.of(context)
.showSnackBar(snackBar);
},
- horizontalPadding: 26,
+ horizontalPadding: 10,
width: 115,
),
+ // 5.toHorizontalSizedBox,
ProfileTextButton(
title: 'Reset Password',
onPressed: () {
- const snackBar = SnackBar(
- content: Text('Coming soon!'),
- duration: Duration(milliseconds: 500),
- );
- ScaffoldMessenger.of(context)
- .showSnackBar(snackBar);
+ context.router
+ .push(ResetPasswordRoute());
},
horizontalPadding: 10,
width: 115,
diff --git a/lib/presentation/reset_password/bloc/reset_password_bloc.dart b/lib/presentation/reset_password/bloc/reset_password_bloc.dart
new file mode 100644
index 00000000..6a642fd5
--- /dev/null
+++ b/lib/presentation/reset_password/bloc/reset_password_bloc.dart
@@ -0,0 +1,93 @@
+import 'dart:async';
+
+import 'package:appetizer/data/constants/constants.dart';
+import 'package:appetizer/domain/repositories/user/user_repository.dart';
+import 'package:bloc/bloc.dart';
+import 'package:equatable/equatable.dart';
+
+part 'reset_password_event.dart';
+part 'reset_password_state.dart';
+
+class ResetPasswordBloc extends Bloc {
+ final UserRepository userRepository;
+ ResetPasswordBloc({required this.userRepository})
+ : super(const ResetPassword(
+ showOldPassword: false,
+ showNewPassword: false,
+ showConfirmPassword: false,
+ )) {
+ on(_onResetPasswordPressed);
+ on(_onToggleObscureResetPassword);
+ }
+ FutureOr _onResetPasswordPressed(
+ ResetPasswordPressed event, Emitter emit) async {
+ bool isValidated = true;
+ if (event.oldPassword.isEmpty ||
+ event.newPassword.isEmpty ||
+ event.confirmPassword.isEmpty) {
+ emit(
+ (state as ResetPassword).copyWith(
+ error: 'All fields are required',
+ ),
+ );
+ isValidated = false;
+ } else if (event.newPassword.length < 8) {
+ emit(
+ (state as ResetPassword).copyWith(
+ error: 'Password must be at least 8 characters long',
+ ),
+ );
+ isValidated = false;
+ } else if (event.newPassword != event.confirmPassword) {
+ emit(
+ (state as ResetPassword).copyWith(error: 'Passwords do not match'),
+ );
+ isValidated = false;
+ } else if (event.oldPassword == event.newPassword) {
+ emit(
+ (state as ResetPassword).copyWith(
+ error: 'New password cannot be same as old password',
+ ),
+ );
+ isValidated = false;
+ }
+
+ if (!isValidated) {
+ emit(ResetPassword(
+ error: null,
+ showOldPassword: (state as ResetPassword).showOldPassword,
+ showNewPassword: (state as ResetPassword).showNewPassword,
+ showConfirmPassword: (state as ResetPassword).showConfirmPassword,
+ ));
+ return;
+ }
+
+ emit(Loading());
+ try {
+ await userRepository.changePassword(
+ event.oldPassword,
+ event.newPassword,
+ );
+ emit(const ResetPasswordSuccess());
+ } catch (e) {
+ emit(const ResetPassword(
+ error: AppConstants.GENERIC_FAILURE,
+ showOldPassword: false,
+ showNewPassword: false,
+ showConfirmPassword: false,
+ ));
+ emit((state as ResetPassword).copyWith(error: null));
+ }
+ }
+
+ FutureOr _onToggleObscureResetPassword(ToggleObscureResetPassword event,
+ Emitter emit) async {
+ emit(
+ (state as ResetPassword).copyWith(
+ showOldPassword: event.showOldPassword,
+ showNewPassword: event.showNewPassword,
+ showConfirmPassword: event.showConfirmPassword,
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/reset_password/bloc/reset_password_event.dart b/lib/presentation/reset_password/bloc/reset_password_event.dart
new file mode 100644
index 00000000..2d734289
--- /dev/null
+++ b/lib/presentation/reset_password/bloc/reset_password_event.dart
@@ -0,0 +1,22 @@
+part of 'reset_password_bloc.dart';
+
+abstract class ResetPasswordEvent {}
+
+class ResetPasswordPressed extends ResetPasswordEvent {
+ final String oldPassword;
+ final String newPassword;
+ final String confirmPassword;
+ ResetPasswordPressed(
+ this.oldPassword, this.newPassword, this.confirmPassword);
+}
+
+class ToggleObscureResetPassword extends ResetPasswordEvent {
+ final bool showOldPassword;
+ final bool showNewPassword;
+ final bool showConfirmPassword;
+ ToggleObscureResetPassword({
+ required this.showOldPassword,
+ required this.showNewPassword,
+ required this.showConfirmPassword,
+ });
+}
diff --git a/lib/presentation/reset_password/bloc/reset_password_state.dart b/lib/presentation/reset_password/bloc/reset_password_state.dart
new file mode 100644
index 00000000..2d7e6738
--- /dev/null
+++ b/lib/presentation/reset_password/bloc/reset_password_state.dart
@@ -0,0 +1,45 @@
+part of 'reset_password_bloc.dart';
+
+abstract class ResetPasswordState extends Equatable {
+ const ResetPasswordState();
+
+ @override
+ List