How to show SnackBar in class - flutter

i want call snack bar in this class on error method :
class serverRequest {
String _Url = "*****";
Future<String> getRequest(String Url, Map<String, dynamic> map) async {
String BaseUrl = _Url + Url;
var dio = Dio();
print(BaseUrl.toString());
dio.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
print("REQUEST[${options?.method}] => PATH: ${options?.path}");
return options; //continue
}, onResponse: (Response response) async {
print(
"RESPONSE[${response?.statusCode}] => PATH: ${response?.request?.path}");
return response; // continue
}, onError: (DioError err) async {
print("ERROR[${err.toString()}] => PATH: ${err?.request?.path}");
if (err.response.statusCode == 403) {
// i want call snack bar here
}
return err; //continue
}));
Response response = await dio.post(BaseUrl, queryParameters: map);
print(response.toString());
return response.toString();
}
dynamic requestInterceptor(RequestOptions options) async {
return options;
}
this serverRequest class call in some pages for request and i want when have server error show snack bar in app.

you can add an extra argument to the ```getRequest`` method like so
class serverRequest {
String _Url = "*****";
Future<String> getRequest(String Url, Map<String, dynamic> map, Function onError) async {
////
if (err.response.statusCode == 403) {
// i want call snack bar here
onError(statusCode);
}
and when your calling this function in your widget, you can pass this
Function showErrorSnackBar(errorCode) {
Scaffold.of(context).showSnackBar(
SnackBar(
)
)
}
/// where you call it, pass this function
MaterialButton(
// other props
onPressed: () {
serverRequest().getRequest(x,y, showErrorSnackBar)
}
)

Related

Riverpod : future provider is stuck on loading

Describe the bug
when executing the provider with ref.read or ref.watch the result is the same , it is stuck on the loading block , while testing the api in postman works fine , the funny thing is that the api call gets executed and whenever i print something inside it it appears in the console
To Reproduce
in presentation layer
onpressed:()=>ref
.read(getPatientProvider(
r.api_token))
.when(data: (data) {
data.fold(
(l) => print(
"something wrong happened"),
(r) async {
print(r.id);
print("hello");
patient.value = patient.value
.copyWith(
name: r.name,
aliid: r.id,
appointments: r
.patient_appointments,
fcmtoken: token);
ref.read(docexist(r.id)).when(
loading: () =>
print("loading"),
error: (error, _) =>
print(error),
data: (data) async {
print("heloo");
if (data.isEmpty) {
print(
"data is not empty");
} else {
return print(
"logged in normally");
}
});
});
}, error: (error, _) {
print(error);
}, loading: () {
print("object");
})
Provider with riverpod generator
#riverpod
Future<Either<ApiFailures, dynamic>> getPatient(
GetPatientRef ref, String token) async {
final patientProvider = ref.watch(patientRepositoryProvider);
return patientProvider.getInfo(token);
}
infrastructure layer
#override
Future<Either<ApiFailures, dynamic>> getInfo(String token) {
var dio = Dio();
final result = TaskEither<ApiFailures, PatientModel>(() async {
try {
final response = await dio.get(
"https://xxxxxxxx/GetInfo?api_token=$token");
if (response.data == null) {
return const Left(ApiFailures.notfound());
} else {
PatientModel patientModel =
PatientModel.fromJson(response.data["User"]);
return Right(patientModel);
}
} catch (err, st) {
final message = 'error ${err.runtimeType}]';
if (kDebugMode) log(message, error: err, stackTrace: st);
if (err is DioError) {
return Left(ApiFailures.fromDioError(error: err));
}
return const Left(ApiFailures.internalError());
}
});
return result.map((r) => r).run();
}
Expected behavior
it should get the data as always
Calling when inside a click handler such as onPressed as you did does not make sense.
"when" does not wait for the future to complete. It executes immediately based on the current status of the future.
Considering that when you call it, you just triggered the future, then the future at that time will always be in a loading state.
What you want is something like async/await, where you can wait until the completion of your future.
You could do that with:
onPressed: () async {
final value = await ref.read(provider.future);
}

How to access future content

I have this function that is working inside a future builder:
Future<Data> fetchData(String barCode, String url) async {
final response = await http.get(Uri.parse(url + barCode));
Map<String, dynamic> novoJson = json.decode(utf8.decode(response.bodyBytes));
novoJson.forEach((key, value) {
if (value == null) {
novoJson.update(key, (value) => "Não encontrado");
}
});
if (response.statusCode == 200) {
return Data.fromJson(novoJson);
} else {
throw Exception('Failed to load album');
}
}
class Data {
final Map<String, dynamic> response;
Data({required this.response});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(response: json);
}
}
Now i'm trying to access the json it returns inside a ElevatedButton, like this:
onPressed: () {
if (_formKey.currentState!.validate()) {
var futureData = fetchData(myController.text, args.url);
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(title: animacaoRespostaApi());
});
futureData.whenComplete(() {
Navigator.of(context).pop();
print(futureData);
return Navigator.pushNamed(context, args.rota, arguments: ParametrosRetornoConsulta(myController.text, args.url));
});
}
}
But when print it I get an instance of Future instead of the object, and I can't access it's content with futureData['id'] for example.
How can I make futureData stop being an Future and become a iterable object ?
Future<Data> fetchData is Future, you need to use await for data.
onPressed: () async {
if (_formKey.currentState!.validate()) {
var futureData = await fetchData(myController.text, args.url);

how to set values in initState method using riverpod

right now i have a ChangeNotifierProvider, and i want to set some values straight in the initState method.
those values come from a backend API, that are retrieved in that provider.
I am stuck is this situation for a while now, hope i can get some help.
Here is the ChangeNotifierProvider
final userProvider = ChangeNotifierProvider.autoDispose.family<UserProxy, String>((ref, id) {
var notifier = UserProxy(userId: id);
notifier.load();
return notifier;
});
class UserProxy extends ChangeNotifier {
String userId;
User? user;
UserProxy({this.userId = ""});
void load() async {
await getUser().then((value) => generateObject(value));
}
Future<String> getUser() async {
Map<String, String> queryParams = {
"id": userId,
};
var url = Uri.https("asdadas.asdasd.com", "endpoint", queryParams);
Map<String, String> headers = {
'content-type': "application/json",
};
var response = await http.get(url,
headers: headers,);
print(response.body);
return response.body;
}
User generateObject(String jsonString) {
this.user = User.fromJson(jsonDecode(jsonString));
notifyListeners();
return this.user ?? User();
}
}
For this case I would suggest
FutureProvider.autoDispose.family<UserProxy, String>((ref, id) async { .... })
then change your StateWidget to ConsumerStatefulWidget and ConsumerState<>
then
ref.watch(provider(11)).when(
loading: (){},
error: (Object err, StackTrace? st){ },
data: (user){
// build widget with result here.
},
)

I Want to get the token from my API by Dio flutter?

I'm trying to get my token from the API but it's empty
This is dio functions
import 'package:dio/dio.dart';
class DioHelper
{
static Dio dio;
static init()
{
print('dioHelper Initialized');
dio = Dio(
BaseOptions(
baseUrl:'my api link',
receiveDataWhenStatusError: true,
));
}
static Future<Response> getData ({
String url,
Map<String,dynamic> query,
String lang = 'en',
String token,
Map<String,dynamic> data,
})async
{
dio.options.headers =
{
'lang':'$lang',
'Content-Type':'application/json',
'Authorization' : '$token'
};
return await dio.get(
url,
queryParameters: query
);
}
static Future<Response> postData ({
String url,
Map<String,dynamic> query,
Map<String,dynamic> data,
String lang = 'ar',
String token
})async
{
dio.options.headers =
{
'lang':'$lang',
'Content-Type':'application/json',
'Authorization' : '$token'
};
return await dio.post(
url,
queryParameters: query,
data: data,
);
}
static Future<Response> putData ({
String url,
Map<String,dynamic> query,
Map<String,dynamic> data,
String lang = 'ar',
String token
})async
{
dio.options.headers =
{
'lang':'$lang',
'Content-Type':'application/json',
'Authorization' : '$token'
};
return await dio.put(
url,
queryParameters: query,
data: data,
);
}
static Future<Response> deleteData ({
String url,
String lang = 'ar',
String token
})async
{
dio.options.headers =
{
'lang':'$lang',
'Content-Type':'application/json',
'Authorization' : '$token'
};
return await dio.delete(url);
}
}
and pass value in this variable
String token = '';
and fuctions sharedPreferences
import 'package:shared_preferences/shared_preferences.dart';
class CacheHelper
{
static SharedPreferences sharedPreferences;
static init () async {
sharedPreferences = await SharedPreferences.getInstance();
}
static dynamic getData(String key, ){
return sharedPreferences.get(key);
}
static Future<bool> saveData({ String key, dynamic value})async{
if(value is String) return await sharedPreferences.setString(key, value);
if(value is int) return await sharedPreferences.setInt(key, value);
if(value is bool) return await sharedPreferences.setBool(key, value);
return await sharedPreferences.setDouble(key, value);
}
static Future<bool> removeData (String key)async{
return await sharedPreferences.remove(key);
}
}
*CALL THE TOKEN*
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
Bloc.observer = MyBlocObserver();
await DioHelper.init();
await CacheHelper.init();
token = CacheHelper.getData('token');
var IsLogin = CacheHelper.getData( 'IsLogin');
var IsBoarding = CacheHelper.getData( 'IsBoarding');
print(IsLogin);
print(IsBoarding);
print(token);
var widget;
if (IsBoarding != null) {
if (token == null) {
widget = ShopingScreen();
} else {
widget = Login_Screen();
}
} else {
widget = BordScreen();
}
THANKS
Is there any solution
I described my problem a few days ago, but without details, there was no useful solution
Tried a lot but it didn't solve this problem. I tried wiping the phone data or reformatting the codes and restarting the device several times.

What the equivalent code in flutter dio compare to android retrofit #body?

Now I try to transform my Andorid project to flutter. but I stucked on an api call.
here is my android code in Kotlin:
/**
* sendSms
*
* #return
*/
#Headers("Content-Type: application/json;charset=UTF-8")
#POST("uaa/sms/send/code")
fun sendSms(#Body params: Map<String, String?>): Observable<ApiResult<String>>
Now I want to implement this api call in flutter use dio, but I still got wrong, my flutter code
is :
class Req {
static Req _instance;
static const int connectTimeOut = 5 * 1000;
static const int receiveTimeOut = 7 * 1000;
static Req getInstance() {
if (_instance == null) {
_instance = Req._internal();
}
return _instance;
}
Dio _client;
Req._internal() {
if (_client == null) {
BaseOptions options = new BaseOptions();
options.connectTimeout = connectTimeOut;
options.receiveTimeout = receiveTimeOut;
_client = new Dio(BaseOptions(
baseUrl: 'https://gw.ec.iunicorn.com/',
));
// 添加缓存插件
_client.interceptors.add(Global.netCache);
//添加token
_client.interceptors.add(Global.tokenInterceptor);
_client.interceptors.add(Global.logInterceptor);
// dio.options.headers[HttpHeaders.authorizationHeader] = Global.profile.token;
_client.options.headers['source'] = 'ANDROID';
if (!Global.isRelease) {
(_client.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
// client.findProxy = (uri) {
// return "PROXY 10.1.10.250:8888";
// };
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
};
}
}
}
//post请求
void post(
String url,
OnData callBack, {
Map<String, String> params,
Options options,
FormData formData,
OnError errorCallBack,
CancelToken token,
}) async {
this._request(
url,
callBack,
method: RequestType.POST,
options: options,
formData: formData,
params: params,
errorCallBack: errorCallBack,
token: token,
);
}
void _request(
String url,
OnData callBack, {
RequestType method,
Map<String, String> params,
Options options,
FormData formData,
OnError errorCallBack,
ProgressCallback progressCallBack,
CancelToken token,
}) async {
final id = _id++;
int statusCode;
try {
Response response;
if (method == RequestType.GET) {
if (mapNoEmpty(params)) {
response = await _client.get(url,
queryParameters: params, cancelToken: token);
} else {
response = await _client.get(url, cancelToken: token);
}
} else {
if (mapNoEmpty(params) || formData != null) {
response = await _client.post(
url,
data: formData ?? params,
onSendProgress: progressCallBack,
cancelToken: token,
);
} else {
response = await _client.post(url, cancelToken: token);
}
}
statusCode = response.statusCode;
if (response != null) {
if (response.data is List) {
Map data = response.data[0];
callBack(data);
} else {
Map data = response.data;
callBack(data);
}
print('HTTP_REQUEST_URL::[$id]::$url');
print('HTTP_REQUEST_BODY::[$id]::${params ?? ' no'}');
print('HTTP_RESPONSE_BODY::[$id]::${response.data}');
}
if (statusCode < 0) {
_handError(errorCallBack, statusCode);
return;
}
} catch (e) {
_handError(errorCallBack, statusCode);
}
}
///处理异常
static void _handError(OnError errorCallback, int statusCode) {
String errorMsg = 'Network request error';
if (errorCallback != null) {
errorCallback(errorMsg, statusCode);
}
print("HTTP_RESPONSE_ERROR::$errorMsg code:$statusCode");
}
}
void sendSms(BuildContext context, Callback callback) async {
Req.getInstance().post(
ApiPath.SEND_SMS,
(t) {
SmsResponse r = SmsResponse.fromJson(t);
print(r);
if (callback != null) {
callback();
}
},
formData: FormData.fromMap({
'phoneNumber':'182********'
}),
options: RequestOptions(
headers: {
HttpHeaders.contentTypeHeader: 'application/json;charset=UTF-8',
}),
errorCallBack: (msg, code) {
Fluttertoast.showToast(
msg: AppLocalizations.of(context).send_sms_fail,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.orangeAccent,
timeInSecForIosWeb: 1);
});
}
Now I want to know is the data in dio is equivalent to the #Body in java retrofit, if not, how can I do?
Doing this in plain Dio leads to a lot of boilerplate. There is also an equivalent retrofit package for Flutter inspired by the same package for Android. https://pub.dev/packages?q=retrofit
From there it's almost the same, you just add () after #Body. Here is an example
#POST('/auth/change-password')
Future<bool> changePassword({
#required #Body() Map<String, dynamic> params,
#required #Header('auth-token') String token,
});