Undo OTP removal

This commit is contained in:
Michael Speed 2024-02-11 20:55:21 +01:00
parent ff2b4c64f1
commit 4800da847d
9 changed files with 348 additions and 50 deletions

View File

@ -106,8 +106,6 @@ android {
signingConfig signingConfigs.release
shrinkResources true
minifyEnabled true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
namespace 'meditofoundation.medito'

View File

@ -34,8 +34,8 @@ import 'constants/environments/environment_constants.dart';
import 'services/notifications/notifications_service.dart';
var audioStateNotifier = AudioStateNotifier();
var currentEnvironment =
kDebugMode ? EnvironmentConstants.stagingEnv : EnvironmentConstants.prodEnv;
var currentEnvironment = EnvironmentConstants.stagingEnv;
// kDebugMode ? EnvironmentConstants.stagingEnv : EnvironmentConstants.prodEnv;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
@ -46,15 +46,8 @@ Future<void> main() async {
var sharedPreferences = await initializeSharedPreferences();
if (await areGooglePlayServicesAvailable()) {
try {
await Firebase.initializeApp();
await registerNotification();
} catch (err) {
unawaited(Sentry.captureException(
err,
stackTrace: err,
));
}
await Firebase.initializeApp();
await registerNotification();
}
usePathUrlStrategy();

View File

@ -2,6 +2,7 @@ import 'package:Medito/constants/constants.dart';
import 'package:Medito/main.dart';
import 'package:Medito/models/models.dart';
import 'package:Medito/repositories/repositories.dart';
import 'package:flutter/foundation.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../me/me_provider.dart';

View File

@ -6,6 +6,7 @@ import 'package:Medito/providers/providers.dart';
import 'package:Medito/utils/utils.dart';
import 'package:Medito/views/auth/join_email_view.dart';
import 'package:Medito/views/auth/join_intro_view.dart';
import 'package:Medito/views/auth/join_verify_OTP_view.dart';
import 'package:Medito/views/auth/join_welcome_view.dart';
import 'package:Medito/views/background_sound/background_sound_view.dart';
import 'package:Medito/views/bottom_navigation/bottom_navigation_bar_view.dart';
@ -75,6 +76,22 @@ final router = GoRouter(
);
},
),
GoRoute(
parentNavigatorKey: _rootNavigatorKey,
path: RouteConstants.joinVerifyOTPPath,
pageBuilder: (context, state) {
final params =
state.extra != null ? state.extra as JoinRouteParamsModel : null;
return MaterialPage(
key: state.pageKey,
child: JoinVerifyOTPView(
email: params?.email ?? '',
fromScreen: params?.screen ?? Screen.splash,
),
);
},
),
GoRoute(
parentNavigatorKey: _rootNavigatorKey,
path: RouteConstants.joinWelcomePath,

View File

@ -25,13 +25,18 @@ Future<void> registerNotification() async {
}
Future<String?> requestGenerateFirebaseToken() async {
try {
if (_messaging != null) {
var token = await _messaging?.getToken();
return token;
}
} catch (e) {
return null;
return null;
}
return null;
}
Future removeFirebaseToken() async {

View File

@ -199,10 +199,14 @@ Future<bool> areGooglePlayServicesAvailable() async {
if (Platform.isIOS) {
return true;
} else if (Platform.isAndroid) {
return (await GoogleApiAvailability.instance
.checkGooglePlayServicesAvailability()) ==
GooglePlayServicesAvailability.success;
var availability = await GoogleApiAvailability.instance
.checkGooglePlayServicesAvailability();
if (availability == GooglePlayServicesAvailability.success) {
return true;
}
}
return false;
} catch (e) {
unawaited(Sentry.captureException(
e,
@ -211,8 +215,6 @@ Future<bool> areGooglePlayServicesAvailable() async {
return false;
}
return false;
}
extension SanitisePath on String {

View File

@ -0,0 +1,273 @@
import 'dart:async';
import 'package:Medito/constants/constants.dart';
import 'package:Medito/models/models.dart';
import 'package:Medito/providers/providers.dart';
import 'package:Medito/routes/routes.dart';
import 'package:Medito/services/network/api_response.dart';
import 'package:Medito/services/notifications/notifications_service.dart';
import 'package:Medito/utils/validation_utils.dart';
import 'package:Medito/widgets/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
import '../../providers/me/me_provider.dart';
import '../../utils/utils.dart';
class JoinVerifyOTPView extends ConsumerStatefulWidget {
const JoinVerifyOTPView({
super.key,
required this.email,
required this.fromScreen,
});
final Screen fromScreen;
final String email;
@override
ConsumerState<JoinVerifyOTPView> createState() => _JoinVerifyOTPViewState();
}
class _JoinVerifyOTPViewState extends ConsumerState<JoinVerifyOTPView> {
late AuthNotifier auth;
final TextEditingController _otpTextEditingController =
TextEditingController();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
void _handleVerify() async {
if (_formKey.currentState!.validate()) {
await auth.verifyOTP(widget.email, _otpTextEditingController.text);
var status = auth.verifyOTPResponse.status;
if (status == Status.COMPLETED) {
await removeFirebaseToken();
await auth.saveFcmTokenEvent();
// ignore: unused_result
ref.invalidate(meProvider);
ref.read(meProvider);
var params = JoinRouteParamsModel(
screen: widget.fromScreen,
email: widget.email,
);
unawaited(context.push(
RouteConstants.joinWelcomePath,
extra: params,
));
} else if (status == Status.ERROR) {
showSnackBar(context, auth.verifyOTPResponse.message.toString());
}
}
}
@override
Widget build(BuildContext context) {
auth = ref.watch(authProvider);
var textTheme = Theme.of(context).textTheme;
var isLoading = auth.verifyOTPResponse == ApiResponse.loading();
return Scaffold(
backgroundColor: ColorConstants.ebony,
body: SafeArea(
maintainBottomViewPadding: true,
bottom: false,
child: Padding(
padding: const EdgeInsets.only(
top: 16, bottom: 0, left: 16, right: 16), // Updated padding
child: Form(
key: _formKey,
child: Column(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
StringConstants.verifyYourAccount,
style: textTheme.headlineMedium?.copyWith(
color: ColorConstants.walterWhite,
fontFamily: SourceSerif,
height: 1.2,
fontSize: 24,
),
),
Padding(
padding: const EdgeInsets.only(top: 16, bottom: 24),
child: Text(
StringConstants.verifyYourAccountInstruction
.replaceAll('replaceme', widget.email),
style: textTheme.bodyMedium?.copyWith(
color: ColorConstants.walterWhite,
fontFamily: DmSans,
height: 1.4,
fontSize: 16,
),
),
),
PinCodeTextField(
appContext: context,
controller: _otpTextEditingController,
backgroundColor: Colors.transparent,
keyboardType: TextInputType.number,
pinTheme: PinTheme(
fieldHeight: 56,
fieldWidth: 56,
selectedColor: ColorConstants.onyx,
borderRadius: BorderRadius.circular(5),
borderWidth: 0,
activeFillColor: ColorConstants.onyx,
inactiveFillColor: ColorConstants.onyx,
selectedFillColor: ColorConstants.onyx,
activeColor: ColorConstants.onyx,
inactiveColor: ColorConstants.onyx,
shape: PinCodeFieldShape.box,
),
textStyle: textTheme.displayMedium?.copyWith(
color: ColorConstants.walterWhite,
fontFamily: SourceSerif,
fontSize: 24,
),
enableActiveFill: true,
autoFocus: true,
animationCurve: Curves.easeIn,
cursorColor: ColorConstants.walterWhite,
length: 6,
validator: ValidationUtils().validateOTP,
onChanged: (String _) => setState(() => {}),
),
Padding(
padding: const EdgeInsets.only(top: 8),
child: _ResendCodeWidget(
email: widget.email,
),
),
height16,
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
height: 48, // Set the height to 48 pixels
child: LoadingButtonWidget(
onPressed: () => context.pop(),
btnText: StringConstants.goBack,
),
),
width8,
Container(
height: 48, // Set the height to 48 pixels
child: LoadingButtonWidget(
onPressed: _otpTextEditingController.text != ''
? _handleVerify
: null,
btnText: StringConstants.verify,
bgColor: ColorConstants.walterWhite,
textColor: ColorConstants.onyx,
isLoading: isLoading,
),
),
],
),
SizedBox(
height: getBottomPadding(context), // Added SizedBox
),
],
),
),
),
),
);
}
}
class _ResendCodeWidget extends ConsumerWidget {
const _ResendCodeWidget({required this.email});
final String email;
@override
Widget build(BuildContext context, WidgetRef ref) {
var textTheme = Theme.of(context).textTheme;
var auth = ref.watch(authProvider);
void _handleResendOTP() async {
await auth.sendOTP(email);
auth.setCounter();
var status = auth.sendOTPResponse.status;
if (status == Status.COMPLETED) {
showSnackBar(context, auth.sendOTPResponse.body.toString());
} else if (status == Status.ERROR) {
showSnackBar(context, auth.sendOTPResponse.message.toString());
auth.setCounter();
}
}
if (auth.sendOTPResponse.status == Status.LOADING) {
return SizedBox(
height: 16,
width: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
color: ColorConstants.walterWhite,
),
);
}
return GestureDetector(
onTap: () => {},
child: Row(
children: [
GestureDetector(
onTap: _handleResendOTP,
child: Text(
auth.counter
? StringConstants.resendCodeIn
: StringConstants.resendCode,
style: textTheme.bodyMedium?.copyWith(
color: ColorConstants.walterWhite,
fontFamily: DmSans,
height: 1.5,
fontSize: 14,
fontWeight: FontWeight.w700,
decoration: auth.counter
? TextDecoration.none
: TextDecoration.underline,
),
),
),
if (auth.counter) _counterAnimation(auth, textTheme),
],
),
);
}
TweenAnimationBuilder<Duration> _counterAnimation(
AuthNotifier auth,
TextTheme textTheme,
) {
return TweenAnimationBuilder<Duration>(
duration: Duration(seconds: 45),
tween: Tween(begin: Duration(seconds: 45), end: Duration.zero),
onEnd: () {
auth.setCounter();
},
builder: (BuildContext context, Duration value, Widget? child) {
final minutes = value.inMinutes;
final seconds = value.inSeconds % 60;
return Text(
'$minutes:$seconds',
textAlign: TextAlign.center,
style: textTheme.bodyMedium?.copyWith(
color: ColorConstants.walterWhite,
fontFamily: DmSans,
height: 1.5,
fontSize: 14,
),
);
},
);
}
}

View File

@ -1000,6 +1000,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "16.0.5"
pin_code_fields:
dependency: "direct main"
description:
name: pin_code_fields
sha256: c8652519d14688f3fe2a8288d86910a46aa0b9046d728f292d3bf6067c31b4c7
url: "https://pub.dev"
source: hosted
version: "7.4.0"
platform:
dependency: transitive
description:

View File

@ -19,45 +19,46 @@ environment:
dependencies:
flutter:
sdk: flutter
http: ^0.13.3
dio: ^5.4.0
flutter_svg: ^1.1.6
path_provider: ^2.0.1
url_launcher: ^6.1.14
flutter_markdown: ^0.6.7
shared_preferences: ^2.2.2
app_settings: ^5.1.1
auto_size_text: ^3.0.0-nullsafety.0
rxdart: ^0.27.1
share: ^2.0.1
flutter_html: ^3.0.0-alpha.2
package_info_plus: ^4.0.2
pedantic: ^1.11.0
back_button_interceptor: ^6.0.2
cached_network_image: ^3.2.3
connectivity: ^3.0.3
device_info_plus: ^9.0.2
dio: ^5.4.0
email_validator: '^2.1.16'
equatable: ^2.0.0
sentry_flutter: ^7.16.0
back_button_interceptor: ^6.0.2
go_router: ^6.5.5
firebase_core: ^1.24.0
firebase_messaging: ^13.1.0
flutter_dotenv: ^5.0.2
flutter_downloader: ^1.10.2
flutter_html: ^3.0.0-alpha.2
flutter_local_notifications: ^15.0.0
flutter_markdown: ^0.6.7
flutter_riverpod: ^2.4.10
riverpod_annotation: ^2.3.4
flutter_svg: ^1.1.6
freezed: ^2.3.2
freezed_annotation: ^2.2.0
json_annotation: ^4.8.1
flutter_dotenv: ^5.0.2
shimmer: ^2.0.0
flutter_downloader: ^1.10.2
cached_network_image: ^3.2.3
email_validator: '^2.1.16'
share_plus: ^7.0.2
firebase_messaging: ^13.1.0
firebase_core: ^1.24.0
flutter_local_notifications: ^15.0.0
marquee: ^2.2.3
image: ^4.0.17
permission_handler: ^11.2.0
app_settings: ^5.1.1
reorderables: ^0.6.0
go_router: ^6.5.5
google_api_availability: ^5.0.0
http: ^0.13.3
image: ^4.0.17
json_annotation: ^4.8.1
marquee: ^2.2.3
package_info_plus: ^4.0.2
path_provider: ^2.0.1
pedantic: ^1.11.0
permission_handler: ^11.2.0
pin_code_fields: ^7.4.0
reorderables: ^0.6.0
riverpod_annotation: ^2.3.4
rxdart: ^0.27.1
sentry_flutter: ^7.16.0
share: ^2.0.1
share_plus: ^7.0.2
shimmer: ^2.0.0
shared_preferences: ^2.2.2
url_launcher: ^6.1.14
workmanager: ^0.5.2
dependency_overrides: