Implemented home creation and add counter to the sign up screen

This commit is contained in:
Abdullah Alassaf
2024-06-03 00:26:07 +03:00
parent 9877dde78e
commit 6a9c2967d2
12 changed files with 577 additions and 13 deletions

View File

@ -22,7 +22,6 @@ import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/navigation_service.dart'; import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/services/api/spaces_api.dart'; import 'package:syncrow_app/services/api/spaces_api.dart';
import 'package:syncrow_app/utils/helpers/custom_page_route.dart'; import 'package:syncrow_app/utils/helpers/custom_page_route.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';

View File

@ -9,7 +9,6 @@ import 'package:syncrow_app/features/auth/model/user_model.dart';
import 'package:syncrow_app/navigation/navigation_service.dart'; import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/services/api/authentication_api.dart'; import 'package:syncrow_app/services/api/authentication_api.dart';
part 'auth_state.dart'; part 'auth_state.dart';
class AuthCubit extends Cubit<AuthState> { class AuthCubit extends Cubit<AuthState> {
@ -202,15 +201,22 @@ class AuthCubit extends Cubit<AuthState> {
sendOtp() async { sendOtp() async {
try { try {
final response = await AuthenticationAPI.sendOtp(body: {'email': email, 'type': 'VERIFICATION'});
await AuthenticationAPI.sendOtp(body: {'email': email, 'type': 'VERIFICATION'});
// otpCode = response['otp'];
emit(AuthSignUpSuccess()); emit(AuthSignUpSuccess());
} catch (_) { } catch (_) {
emit(AuthLoginError(message: 'Something went wrong')); emit(AuthLoginError(message: 'Something went wrong'));
} }
} }
reSendOtp() async {
try {
await AuthenticationAPI.sendOtp(body: {'email': email, 'type': 'VERIFICATION'});
emit(ResendOtpSuccess());
} catch (_) {
emit(AuthLoginError(message: 'Something went wrong'));
}
}
verifyOtp() async { verifyOtp() async {
emit(AuthLoginLoading()); emit(AuthLoginLoading());
try { try {

View File

@ -24,6 +24,8 @@ class AuthOtpSuccess extends AuthSuccess {}
class AuthSignUpSuccess extends AuthSuccess {} class AuthSignUpSuccess extends AuthSuccess {}
class ResendOtpSuccess extends AuthSuccess {}
class AuthLoginError extends AuthError { class AuthLoginError extends AuthError {
AuthLoginError({required super.message, super.code}); AuthLoginError({required super.message, super.code});
} }

View File

@ -1,3 +1,4 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -9,12 +10,106 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.da
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/life_cycle_event_handler.dart';
import 'package:syncrow_app/utils/helpers/shared_preferences_helper.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class OtpView extends StatelessWidget { class OtpView extends StatefulWidget {
const OtpView({super.key}); const OtpView({super.key});
@override
State<OtpView> createState() => _OtpViewState();
}
class _OtpViewState extends State<OtpView> {
bool timerCanceled = false;
Timer? countdownTimer;
Duration myDuration = const Duration();
late LifecycleEventHandler _lifecycleEventHandler;
String otpCode = '';
int? remainingSec = 30;
@override
void initState() {
super.initState();
bool timerStarted = false;
_lifecycleEventHandler = LifecycleEventHandler(
resumeCallBack: () async {
SharedPreferencesHelper.saveBoolToSP('timeStampSaved', false);
String timeStampInBackground = await SharedPreferencesHelper.readStringFromSP('timeStamp');
int savedCounter = await SharedPreferencesHelper.readIntFromSP('savedCounter');
DateTime currentTime = DateTime.now();
int differenceInSeconds = timeStampInBackground.isNotEmpty
? currentTime.difference(DateTime.parse(timeStampInBackground)).inSeconds
: 0;
remainingSec = differenceInSeconds > savedCounter ? 0 : savedCounter - differenceInSeconds;
timerStarted = true;
startTimer(remainingSec ?? 0);
return;
},
suspendingCallBack: () async {
handleTimerOnBackground();
},
onPauseCallBack: () async {
handleTimerOnBackground();
},
inactiveCallBack: () async {
handleTimerOnBackground();
},
);
WidgetsBinding.instance.addObserver(_lifecycleEventHandler);
if (!timerStarted) {
timerStarted = false;
startTimer(remainingSec ?? 0);
}
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(_lifecycleEventHandler);
super.dispose();
}
handleTimerOnBackground() async {
bool timeStampSaved = await SharedPreferencesHelper.readBoolFromSP('timeStampSaved') ?? false;
if (!timeStampSaved) {
final dateInString = DateTime.now().toString();
SharedPreferencesHelper.saveIntToSP('savedCounter', remainingSec ?? 0);
SharedPreferencesHelper.saveStringToSP('timeStamp', dateInString);
SharedPreferencesHelper.saveBoolToSP('timeStampSaved', true);
}
}
void startTimer(int sec) {
timerCanceled = false;
if (countdownTimer != null) {
countdownTimer!.cancel();
countdownTimer = null;
}
myDuration = Duration(seconds: sec);
int seconds = sec;
countdownTimer = Timer.periodic(const Duration(seconds: 1), (values) {
seconds = seconds - 1;
remainingSec = seconds;
if (mounted) {
if (seconds < 0) {
setState(() {
countdownTimer!.cancel();
timerCanceled = true;
WidgetsBinding.instance.removeObserver(_lifecycleEventHandler);
});
} else {
setState(() {
myDuration = Duration(seconds: remainingSec ?? seconds);
});
}
}
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String maskedEmail = AuthCubit.get(context).maskEmail(AuthCubit.get(context).email); String maskedEmail = AuthCubit.get(context).maskEmail(AuthCubit.get(context).email);
@ -23,6 +118,9 @@ class OtpView extends StatelessWidget {
if (state is AuthOtpSuccess) { if (state is AuthOtpSuccess) {
Navigator.pushNamedAndRemoveUntil(context, Routes.homeRoute, (value) => false); Navigator.pushNamedAndRemoveUntil(context, Routes.homeRoute, (value) => false);
} }
if (state is ResendOtpSuccess) {
startTimer(30);
}
}, },
builder: (context, state) { builder: (context, state) {
return Scaffold( return Scaffold(
@ -215,10 +313,18 @@ class OtpView extends StatelessWidget {
Colors.white, Colors.white,
), ),
), ),
child: const Text( child: Text(
'Resend', timerCanceled
? 'Resend'
: myDuration.inSeconds
.remainder(60)
.toString()
.padLeft(2, '0'),
), ),
onPressed: () async { onPressed: () async {
if (!timerCanceled) {
return;
}
if ((state is! AuthLoading)) { if ((state is! AuthLoading)) {
await AuthCubit.get(context).sendOtp(); await AuthCubit.get(context).sendOtp();
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
@ -241,6 +347,5 @@ class OtpView extends StatelessWidget {
); );
}, },
); );
;
} }
} }

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
class ForgetPassword extends StatelessWidget { class ForgetPassword extends StatelessWidget {
@ -14,7 +15,7 @@ class ForgetPassword extends StatelessWidget {
const Spacer(), const Spacer(),
TextButton( TextButton(
onPressed: () { onPressed: () {
//TODO Navigate to forgot password Navigator.popAndPushNamed(context, Routes.otpRoute);
}, },
child: BodyMedium( child: BodyMedium(
text: "Forgot Password?", text: "Forgot Password?",

View File

@ -1,7 +1,9 @@
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:syncrow_app/features/auth/model/user_model.dart';
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_event.dart'; import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_event.dart';
import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_state.dart'; import 'package:syncrow_app/features/menu/bloc/create_unit_bloc/create_unit_state.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/services/api/home_creation_api.dart';
class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> { class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
List<String> rooms = []; List<String> rooms = [];
@ -11,6 +13,7 @@ class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
CreateUnitBloc() : super(InitialState()) { CreateUnitBloc() : super(InitialState()) {
on<CreateRoomEvent>(_createRoom); on<CreateRoomEvent>(_createRoom);
on<RemoveRoomEvent>(_removeRoom); on<RemoveRoomEvent>(_removeRoom);
on<SaveRooms>(_save);
} }
void _createRoom(CreateRoomEvent event, Emitter<CreateUnitState> emit) async { void _createRoom(CreateRoomEvent event, Emitter<CreateUnitState> emit) async {
@ -39,4 +42,189 @@ class CreateUnitBloc extends Bloc<CreateUnitEvent, CreateUnitState> {
return; return;
} }
} }
void _save(SaveRooms event, Emitter<CreateUnitState> emit) async {
try {
emit(LoadingState());
if (rooms.isEmpty) {
const ErrorState(message: 'Please add at least one room!');
return;
}
var storage = const FlutterSecureStorage();
var userId = await storage.read(key: UserModel.userUuidKey) ?? '';
Map<String, String> communityBody = {'communityName': event.communityName};
final response = await HomeCreation.createCommunity(communityBody);
if (response['data']['uuid'] != '') {
// final result =
// await _assignToCommunity(communityId: response['data']['uuid'], userId: userId);
// if (result) {
String buildingId = await _createBuilding(
buildingName: event.buildingName,
communityId: response['data']['uuid'],
userId: userId);
if (buildingId.isNotEmpty) {
final floorId = await _createFloor(
floorName: event.floorName, buildingId: buildingId, userId: userId);
if (floorId.isNotEmpty) {
final unitId =
await _createUnit(unitName: event.unitName, floorId: floorId, userId: userId);
if (unitId.isNotEmpty && rooms.isNotEmpty) {
rooms.forEach((room) async {
await _createNewRoom(roomName: room, unitId: unitId, userId: userId);
});
}
}
}
// }
}
emit(RoomsSavedSuccessfully());
} catch (_) {
emit(const ErrorState(message: 'Something went wrong'));
return;
}
}
}
Future<bool> _assignToCommunity({required String communityId, required String userId}) async {
try {
Map<String, String> body = {
'communityUuid': communityId,
'userUuid': userId,
};
final response = await HomeCreation.assignUserToCommunity(body);
return response['success'] ?? false;
} catch (_) {
return false;
}
}
Future<String> _createBuilding(
{required String buildingName, required String communityId, required String userId}) async {
try {
Map<String, String> body = {'buildingName': buildingName, 'communityUuid': communityId};
final response = await HomeCreation.createBuilding(body);
// if (response['data']['uuid'] != '') {
// final result = await _assignToBuilding(buildingId: response['data']['uuid'], userId: userId);
return response['data']['uuid'] ?? '';
// } else {
// return '';
// }
} catch (_) {
return '';
}
}
Future<bool> _assignToBuilding({required String buildingId, required String userId}) async {
try {
Map<String, String> body = {
'buildingUuid': buildingId,
'userUuid': userId,
};
final response = await HomeCreation.assignUserToBuilding(body);
return response['success'] ?? false;
} catch (_) {
return false;
}
}
Future<String> _createFloor(
{required String floorName, required String buildingId, required String userId}) async {
try {
Map<String, String> body = {'floorName': floorName, 'buildingUuid': buildingId};
final response = await HomeCreation.createFloor(body);
// if (response['data']['uuid'] != '') {
// final result = await _assignToFloor(buildingId: response['data']['uuid'], userId: userId);
return response['data']['uuid'] ?? '';
// } else {
// return '';
// }
} catch (_) {
return '';
}
}
Future<bool> _assignToFloor({required String buildingId, required String userId}) async {
try {
Map<String, String> body = {
'floorUuid': buildingId,
'userUuid': userId,
};
final response = await HomeCreation.assignUserToFloor(body);
return response['success'] ?? false;
} catch (_) {
return false;
}
}
Future<String> _createUnit(
{required String unitName, required String floorId, required String userId}) async {
try {
Map<String, String> body = {'unitName': unitName, 'floorUuid': floorId};
final response = await HomeCreation.createUnit(body);
if (response['data']['uuid'] != '') {
final result = await _assignToUnit(unitId: response['data']['uuid'], userId: userId);
return result ? response['data']['uuid'] : '';
} else {
return '';
}
} catch (_) {
return '';
}
}
Future<bool> _assignToUnit({required String unitId, required String userId}) async {
try {
Map<String, String> body = {
'unitUuid': unitId,
'userUuid': userId,
};
final response = await HomeCreation.assignUserToUnit(body);
return response['success'] ?? false;
} catch (_) {
return false;
}
}
Future<String> _createNewRoom(
{required String roomName, required String unitId, required String userId}) async {
try {
Map<String, String> body = {'roomName': roomName, 'unitUuid': unitId};
final response = await HomeCreation.createRoom(body);
// if (response['data']['uuid'] != '') {
// final result = await _assignToRoom(roomId: response['data']['uuid'], userId: userId);
return response['data']['uuid'] ?? '';
// } else {
// return '';
// }
} catch (e) {
return '';
}
}
Future<bool> _assignToRoom({required String roomId, required String userId}) async {
try {
Map<String, String> body = {
'roomUuid': roomId,
'userUuid': userId,
};
final response = await HomeCreation.assignUserToRoom(body);
return response['success'] ?? false;
} catch (_) {
return false;
}
} }

View File

@ -28,3 +28,20 @@ class RemoveRoomEvent extends CreateUnitEvent {
@override @override
List<Object> get props => [roomName]; List<Object> get props => [roomName];
} }
class SaveRooms extends CreateUnitEvent {
final String communityName;
final String buildingName;
final String floorName;
final String unitName;
const SaveRooms({
required this.communityName,
required this.buildingName,
required this.floorName,
required this.unitName,
});
@override
List<Object> get props => [communityName, buildingName, floorName, unitName];
}

View File

@ -20,6 +20,8 @@ class CreateRoomState extends CreateUnitState {
List<Object> get props => [roomList]; List<Object> get props => [roomList];
} }
class RoomsSavedSuccessfully extends CreateUnitState {}
class ErrorState extends CreateUnitState { class ErrorState extends CreateUnitState {
final String message; final String message;

View File

@ -11,6 +11,8 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/navigation/navigation_service.dart';
import 'package:syncrow_app/navigation/routing_constants.dart';
import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
@ -26,6 +28,14 @@ class CreateUnitView extends StatelessWidget {
return BlocProvider( return BlocProvider(
create: (context) => CreateUnitBloc(), create: (context) => CreateUnitBloc(),
child: BlocConsumer<CreateUnitBloc, CreateUnitState>(listener: (context, state) { child: BlocConsumer<CreateUnitBloc, CreateUnitState>(listener: (context, state) {
if (state is RoomsSavedSuccessfully) {
CustomSnackBar.displaySnackBar('Saved successfully');
NavigationService.navigatorKey.currentState!.pushNamedAndRemoveUntil(
Routes.homeRoute,
(Route route) => false,
);
}
if (state is ErrorState) { if (state is ErrorState) {
CustomSnackBar.displaySnackBar(state.message); CustomSnackBar.displaySnackBar(state.message);
} }
@ -34,7 +44,17 @@ class CreateUnitView extends StatelessWidget {
return DefaultScaffold( return DefaultScaffold(
actions: [ actions: [
TextButton( TextButton(
onPressed: () {}, onPressed: () {
if (unitName.isNotEmpty) {
BlocProvider.of<CreateUnitBloc>(context).add(SaveRooms(
communityName: 'Community Test',
buildingName: 'Building Test',
floorName: 'Floor Test',
unitName: unitName));
} else {
CustomSnackBar.displaySnackBar('Please enter the unit name');
}
},
child: const BodyLarge( child: const BodyLarge(
text: 'Save', text: 'Save',
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,

View File

@ -28,7 +28,7 @@ class _SplashViewState extends State<SplashView> {
if (state is AuthTokenSuccess) { if (state is AuthTokenSuccess) {
Navigator.pushNamedAndRemoveUntil(context, Routes.homeRoute, (route) => false); Navigator.pushNamedAndRemoveUntil(context, Routes.homeRoute, (route) => false);
} else if (state is AuthTokenError) { } else if (state is AuthTokenError) {
Future.delayed(const Duration(seconds: 1), () { Future.delayed(const Duration(seconds: 2), () {
Navigator.pushReplacement( Navigator.pushReplacement(
context, context,
CustomPageRoute(builder: (context) => const LoginView()), CustomPageRoute(builder: (context) => const LoginView()),

View File

@ -0,0 +1,166 @@
import 'package:syncrow_app/services/api/api_links_endpoints.dart';
import 'package:syncrow_app/services/api/http_service.dart';
class HomeCreation {
static final HTTPService _httpService = HTTPService();
static Future<Map<String, dynamic>> createCommunity(Map<String, String> body) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addCommunity,
body: body,
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<Map<String, dynamic>> assignUserToCommunity(Map<String, String> body) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addCommunityToUser,
body: body,
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<Map<String, dynamic>> createBuilding(Map<String, String> body) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addBuilding,
body: body,
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<Map<String, dynamic>> assignUserToBuilding(Map<String, String> body) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addBuildingToUser,
body: body,
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<Map<String, dynamic>> createFloor(Map<String, String> body) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addFloor,
body: body,
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<Map<String, dynamic>> assignUserToFloor(Map<String, String> body) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addBuildingToUser,
body: body,
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<Map<String, dynamic>> createUnit(Map<String, String> body) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addUnit,
body: body,
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<Map<String, dynamic>> assignUserToUnit(Map<String, String> body) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addUnitToUser,
body: body,
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<Map<String, dynamic>> createRoom(Map<String, String> body) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addRoom,
body: body,
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
static Future<Map<String, dynamic>> assignUserToRoom(Map<String, String> body) async {
try {
final response = await _httpService.post(
path: ApiEndpoints.addRoomToUser,
body: body,
showServerMessage: false,
expectedResponseModel: (json) {
return json;
},
);
return response;
} catch (e) {
rethrow;
}
}
}

View File

@ -0,0 +1,58 @@
import 'package:shared_preferences/shared_preferences.dart';
class SharedPreferencesHelper {
static saveStringToSP(String key, String value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(key, value);
}
static saveBoolToSP(String key, bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(key, value);
}
static saveIntToSP(String key, int value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt(key, value);
}
static saveDoubleToSP(String key, double value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setDouble(key, value);
}
static saveStringListToSP(String key, List<String> value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setStringList(key, value);
}
static Future<String> readStringFromSP(String key) async {
final prefs = await SharedPreferences.getInstance();
String value = prefs.getString(key) ?? '';
return value;
}
static Future<bool?> readBoolFromSP(String key) async {
final prefs = await SharedPreferences.getInstance();
bool? value = prefs.getBool(key);
return value;
}
static Future<int> readIntFromSP(String key) async {
final prefs = await SharedPreferences.getInstance();
int value = prefs.getInt(key) ?? 0;
return value;
}
static Future<List<String>> readStringListFromSP(String key) async {
final prefs = await SharedPreferences.getInstance();
List<String>? value = prefs.getStringList(key) ?? [];
return value;
}
static Future<bool> removeValueFromSP(String key) async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(key);
return true;
}
}