read GetStorage data inside GetxController - flutter

I use GetStorage to store user data
, I want to read its data in user profile GetxController
class UserHomeController extends GetxController {
final box = GetStorage();
// I found this method **but** i can't convert it to object
// as User get user => (userFromJson(GetStorage().read<User>('user'))
String get userS => (GetStorage().read<String?>('user') ?? "");
#override
Future<void> onInit() async {
super.onInit();
}
Thanks

Check the below code, you can directly read the data using read method with key name:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
class Controller extends GetxController {
final box = GetStorage();
bool get isDark => box.read('darkmode') ?? false;
ThemeData get theme => isDark ? ThemeData.dark() : ThemeData.light();
void changeTheme(bool val) => box.write('darkmode', val);
}

class UserHomeController extends GetxController {
final box = GetStorage();
//Change the following line
// String get userS => (GetStorage().read<String?>('user') ?? "");
// to
String get userS => (box.read('user') ?? "");
#override
Future<void> onInit() async {
super.onInit();
}

Related

How to implement BlocTest function?

I'm trying to implement blocTesting for my flutter app starting with authentication feature. Below are the Authentication and login related files required for this. I'd really appreciate if someone could show me on how I can implement blocTesting based on my code because I've been facing problems in doing so. Below are the bloc, state and event files for the auth bloc.
Authbloc.dart
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
part 'authentication_event.dart';
part 'authentication_state.dart';
class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState> {
final AuthenticationRepository authenticationRepository = AuthenticationRepository();
final SettingsRepository _settingsRepository = SettingsRepository();
AuthenticationBloc() : super(AuthenticationInitial()) {
// Register events here
on<AuthenticationStarted>(_onAuthenticationStarted);
on<AuthenticationLoggedIn>(_onAuthenticationLoggedIn);
on<AuthenticationLoggedOut>(_onAuthenticationLoggedOut);
}
Future<void> _onAuthenticationStarted(AuthenticationStarted event, Emitter<AuthenticationState> emit) async {
try {
final bool hasToken = await authenticationRepository.hasToken();
if (hasToken) {
final Settings _settings = await _settingsRepository.getSettings();
final SysConfig _sysConfig = await _settingsRepository.getSysconfig();
final CountriesModelList _countries = await _settingsRepository.getCountries();
final ReasonsModelList _reasons = await _settingsRepository.getReasons();
final NotificationOptionsList _notificationOptions = await _settingsRepository.getNotificationOptions();
emit(
AuthenticationLoadSuccess(
settings: _settings,
sysConfig: _sysConfig,
countries: _countries,
reasons: _reasons,
notificationOptions: _notificationOptions,
),
);
} else {
emit(AuthenticationUnauthenticated());
}
} catch (e) {
final MYException _exception = e as MYException;
emit(AuthenticationLoadFailure(exception: _exception));
}
}
Future<void> _onAuthenticationLoggedIn(AuthenticationLoggedIn event, Emitter<AuthenticationState> emit) async {
emit(AuthenticationLoadInProgress());
await authenticationRepository.persistToken(event.token);
final Settings _settings = await _settingsRepository.getSettings();
final SysConfig _sysConfig = await _settingsRepository.getSysconfig();
final CountriesModelList _countries = await _settingsRepository.getCountries();
final ReasonsModelList _reasons = await _settingsRepository.getReasons();
final NotificationOptionsList _notificationOptions = await _settingsRepository.getNotificationOptions();
emit(
AuthenticationLoadSuccess(
settings: _settings,
sysConfig: _sysConfig,
countries: _countries,
reasons: _reasons,
notificationOptions: _notificationOptions,
),
);
}
Future<void> _onAuthenticationLoggedOut(AuthenticationLoggedOut event, Emitter<AuthenticationState> emit) async {
await authenticationRepository.deleteToken();
await Future<dynamic>.delayed(const Duration(seconds: 2));
emit(AuthenticationUnauthenticated());
add(AuthenticationStarted());
}
}
Authstate.dart
part of 'authentication_bloc.dart';
abstract class AuthenticationEvent extends Equatable {
const AuthenticationEvent();
#override
List<Object> get props => <Object>[];
}
class AuthenticationStarted extends AuthenticationEvent {}
class AuthenticationLoggedIn extends AuthenticationEvent {
final String token;
const AuthenticationLoggedIn({required this.token});
#override
List<Object> get props => <Object>[token];
}
class AuthenticationLoggedOut extends AuthenticationEvent {}
AuthEvent.dart
part of 'authentication_bloc.dart';
abstract class AuthenticationState extends Equatable {
const AuthenticationState();
#override
List<Object> get props => <Object>[];
}
class AuthenticationInitial extends AuthenticationState {}
class AuthenticationUnauthenticated extends AuthenticationState {}
class AuthenticationLoadSuccess extends AuthenticationState {
final SysConfig sysConfig;
final Settings settings;
final CountriesModelList countries;
final ReasonsModelList reasons;
final NotificationOptionsList notificationOptions;
const AuthenticationLoadSuccess({required this.sysConfig, required this.settings, required this.countries, required this.reasons, required this.notificationOptions});
#override
List<Object> get props => <Object>[sysConfig, settings, countries, reasons, notificationOptions];
}
class AuthenticationLoadInProgress extends AuthenticationState {}
class AuthenticationLoadFailure extends AuthenticationState {
final MYException exception;
const AuthenticationLoadFailure({required this.exception});
#override
List<Object> get props => <Object>[exception];
}
you have to change a lot of thinks.
First of all you need to add the repository/ies to your bloc constructor to inject the mocks.
class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState> {
late final AuthenticationRepository authenticationRepository;
final SettingsRepository _settingsRepository = SettingsRepository();
AuthenticationBloc({required this.authenticationRepository}) : super(AuthenticationInitial()) {
// Register events here
on<AuthenticationStarted>(_onAuthenticationStarted);
on<AuthenticationLoggedIn>(_onAuthenticationLoggedIn);
on<AuthenticationLoggedOut>(_onAuthenticationLoggedOut);
}
Then you can use the mock when creating the bloc in the setup method
setUp(() {
authenticationRepositoryMock = MockWeatherRepository();
authenticationBloc = AuthenticationBloc(authenticationRepository: authenticationRepositoryMock );
});
Then you have to return that bloc in the build function of your blocTest and also you have to setup the mock behavior there
build: () {
when(() => authenticationRepositoryMock .hasToken()).thenAnswer((_) async => true);
return bloc;
},
Then add an event to your bloc in the act function
act: (dynamic b) => b.add(AuthenticationStarted()),
And then you can check the result in the expect function. (i think the initial state will not be emitted here)
expect: () => [
AuthenticationLoadSuccess(...),
It also a good idea to mock the SettingsRepository.

Fill list in flutter from other page

On fetchDept.dart I have:
Future<List<Dept>> fetchDept() async {
final response = await http.get(Uri.https('someurl.com', 'dept'));
if (response.statusCode == 200) {
List<Dept> dept = (json.decode(response.body)["items"] as List)
.map((data) => Dept.fromJson(data))
.toList();
return dept;
} else {
throw Exception('Error');
}
}
How on other dart page load data from fetchDept.dart (fetchDept) to deptList
Details.dart page:
import 'package:services/fetchDept.dart';
class DropListPage extends StatefulWidget {
#override
_DropListPageState createState() => _DropListPageState();
}
class _DropListPageState extends State<DropListPage> {
#override
void initState() {
fetchDept();
super.initState();
}
List deptList;
String _myDept;
//deptList ==> Set here data from fetchDept()
On Details.dart page I need to populate Dropdown list.
on the Details page, you could store your data into a List and use it to build your widgets, like this:
import 'package:services/fetchDept.dart';
class DropListPage extends StatefulWidget {
#override
_DropListPageState createState() => _DropListPageState();
}
class _DropListPageState extends State<DropListPage> {
List deptList=[];
#override
void initState() {
asyncMethod();
super.initState();
}
Future<void> asyncMethod() async{
List result = await fetchDept();
setState((){
deptList=result;
});
}
String _myDept;
//with the help of deptList you could build your widgets

Data not passing to second screen while using constructor

I was trying to send data got from a JSON response to a second screen from the main screen.
My widgets are placed in separate class files. I called a single API call to fetch all data from the API so that there won't be many API calls happening while opening the app.
But I can't pass the data to the second screen in arrMaincategories. What should I do?
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
var arrBanner = [];
var arrImages = [];
var arrMainCategories = [];
#override
void initState() {
super.initState();
this.getBanner();
setState(() {});
}
getBanner() async {
String url = "https://www.clickxpress.in/api/";
var prefs = await SharedPreferences.getInstance();
var custID = prefs.getString('id');
var response = await http.post(Uri.encodeFull(url),
body: (<String, String>{
'type': "homepage",
'secKey': "2a067feaeb67fgh89fyrc6657654fhjj9714b2094818f",
'customerId': custID,
'geoLat': "55.2324",
'geoLong': "23.55556",
})); //for accepting only json response
setState(() {
Map<String, dynamic> map = json.decode(response.body);
var data = map["attributes"];
arrBanner = data['topBanner'];
arrMainCategories = data['mainCategories'];
if (arrBanner != null) {
for (var value in arrBanner) {
final image = value['imageUrl'];
arrImages.add(NetworkImage(image));
}
Called It to a new screen
NewCat(arrMainCategories: arrMainCategories),
trying to fetch on 2nd screen
class NewCat extends StatefulWidget {
NewCat({Key key, #required this.arrMainCategories}) : super(key: key);
final arrMainCategories;
#override
_NewCatState createState() => _NewCatState(arrMainCategories);
}
class _NewCatState extends State<NewCat> {
var arrMainCategories = [];
var arrCatImages = [];
var arrCatName = [];
_NewCatState(
arrMainCategories,
);
But the value is not coming here in the empty array. what to do?
Instead of using the Constructor, You Can also access the data by using this line of code
print(widget.arrMainCategories);
See this resource link for more details
use this
_NewCatState(
widget.arrMainCategories,
);
instead of this
_NewCatState(
arrMainCategories,
);

Could not called initState and update (riverpod state_notifier)

Problem
I'm using riverpod and state_notifier.
The initState() and update() that StateNotifier has are called and No. The other member functions can be called successfully. However, other member functions can be called successfully.
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:riverpod_todo_list/todo_list_notifier.dart';
import 'package:riverpod_todo_list/todo_list_state.dart';
void main() {
print('start~~');
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends HookWidget {
// ...
}
final todoListProvider = StateNotifierProvider((_) => TodoListNotifier());
class MyHomePage extends HookWidget {
final _controller = TextEditingController();
final todoListNotifier = useProvider(todoListProvider);
final TodoListState _todoListState =
useProvider(todoListProvider.state.select((value) => value));
//...
import 'package:riverpod_todo_list/todo.dart';
import 'package:riverpod_todo_list/todo_list_state.dart';
import 'package:state_notifier/state_notifier.dart';
import 'package:uuid/uuid.dart';
class TodoListNotifier extends StateNotifier<TodoListState> with LocatorMixin {
TodoListNotifier() : super(const TodoListState());
Uuid _uuid = Uuid();
// could not run.
#override
void initState() {
super.initState();
print('init state~~~');
}
// could not run.
#override
void update(Locator watch) {
super.update(watch);
print('update');
}
// could run.
void add(String title) {
Todo todo = Todo(id: _uuid.v4(), title: title);
List<Todo> todoList = []..addAll(state.todoList);
todoList.add(todo);
state = state.copyWith(todoList: todoList);
}
// could run.
void toggleStatus(int index) {
List<Todo> todoList = []..addAll(state.todoList);
todoList[index] = state.todoList[index]
.copyWith(completed: !state.todoList[index].completed);
state = state.copyWith(todoList: todoList);
print('changed toggle~~');
}
}
restarted logs
not put initState() and update() logs.
Performing hot restart...
Restarted application in 464ms.
flutter: start~~
The question is already answered on the Github.
LocatorMixin is not supported by Riverpod.
https://github.com/rrousselGit/river_pod/issues/75#issuecomment-671255330
And it's proposed to note it in the document.
In my opinion, LocatorMixin is not needed to use with Riverpod because of ProvidierReference.
final userRepositoryProvider = Provider((ref) => UserRepository());
final userControllerProvider = StateNotifierProvider((ref) {
return UserController(
// Read userRepositoryProvider and create a UserController from the result
repository: ref.watch(userRepositoryProvider),
);
});

why does my global variable keeps getting set back to default when switching pages?

I have a GlobalVariables.dart where i store all the global variables.
library lumieres.globals;
String appLanguage;
bool languageChanged = false;
String appMode = 'dev';
in my main.dart file, I'm checking if shared preference contains 'user', if not I am setting the language to be english.
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
import 'package:intl/intl.dart';
import 'GlobalVariables.dart' as globals;
// void main() => runApp(MyApp());
void main(){
runApp(MyApp());
startingAppFunction();
}
startingAppFunction() async{
print('calling startingappfunction from main');
SharedPreferences sharedpref = await SharedPreferences.getInstance();
var user = sharedpref.getString('user');
if (user != "" && user != null) {
var decodedUser = json.decode(user);
globals.appLanguage = decodedUser['lang'];
}else{
globals.appLanguage = "EN";
}
print('here is the app language from main dart');
print(globals.appLanguage); //prints EN which is correct but on homepage it says null
}
But in my homepage, it's set back to null seems like the global variable is some how getting set back to String appLanguage; which is null.
import 'GlobalVariables.dart' as globals;
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//limiting all results to only 6
// var refreshKey = GlobalKey<RefreshIndicatorState>();
Future<String> dataFuture;
#override
void initState(){
super.initState();
print('printing from home page...');
print(globals.appLanguage); //prints null
}
}
what am I missing? I followed this suggestion from this stackoverflow answer: Global Variables in Dart
It might not be that it is set back to null but because it is an async process your print execute before your value is set.
Your print in startingApp will always display the correct value because it is in the same method.
Try running startingAppFunction() before your runApp(). (using then might be a good option too)
void main(){
startingAppFunction().then((_) {
runApp(MyApp());
});
}