Accessing a value in multiple screens in flutter - flutter

I need to access a device id in multiple screens. To get device id from android and ios, am using package:device_info_plus. I don't want to call getId() method multiple times.
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
class DeviceInfo {
String? id;
Future<String?> getId() async {
var deviceInfo = DeviceInfoPlugin();
if (Platform.isIOS) {
var iosDeviceInfo = await deviceInfo.iosInfo;
return iosDeviceInfo.identifierForVendor; // unique ID on iOS
} else if (Platform.isAndroid) {
var androidDeviceInfo = await deviceInfo.androidInfo;
return androidDeviceInfo.androidId; // unique ID on Android
}
}
}
To access this object i registered using package:get_it and accessing the object using the get_it instance.is this correct way to access the objects in multiple screen using locator.get().id ?
// injection.dart file
import 'package:get_it/get_it.dart';
import 'package:orange/utils/device_info.dart';
final locator = GetIt.instance;
void init() async {
locator.registerSingleton<DeviceInfo>(DeviceInfo());
locator.get<DeviceInfo>().id= await locator.get<DeviceInfo>().getId();
}
Am using a flutter bloc in my app. What is the correct way to access values in multiple screens. Is my solution using get it package is correct? or shall i use shared_preferences.

Related

Unit Testing hive abstraction layer

So I created a simpler level of abstraction to use Hive into my Flutter app. This should be the central point, where all hive boxes are administrated and accessed. Since e.g. getApplicationDocumentsDirectory is not available during testing, how can I still manage to test this whole file?
import '../services/workout.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart' as path_rovider;
import 'workout.dart';
class HiveService {
static final HiveService _singleton = HiveService._internal();
static const String _workoutBox = "workoutBox";
factory HiveService() {
return _singleton;
}
HiveService._internal();
static Future<void> init() async {
final appDocumentDirectory =
await path_rovider.getApplicationDocumentsDirectory();
Hive.init(appDocumentDirectory.path);
Hive.registerAdapter(WorkoutAdapter());
}
static Future openWorkouts() {
return Hive.openBox<Workout>(_workoutBox);
}
static Future close() {
return Hive.close();
}
}
First thing first, you need to initial Hive at the top of the main method in your test file, and then you can proceed with the rest of the tests.
You can use it in this way:
void initHive() {
var path = Directory.current.path;
Hive.init(path + '/test/hive_testing_path');
}
main() {
initHive();
//The rest of your test code.
}

how to implement Shared_preferences in my own class elegantly on Flutter?

I created such class to store and update the api address locally. But it doesn't work well. How to add the Shared_preferences in the normal class instead of the flutter state widget? So it would make things clearly.
// The Server class
import 'package:shared_preferences/shared_preferences.dart';
class Server{
String _listUrl;
String _itemUrl;
static String _cache1;
static String _cache2;
static final Server _server = new Server._internal();
factory Server({String listUrl, String itemUrl}) {
_cache1 = listUrl;
_cache2 = itemUrl;
return _server;
}
Server._internal() {
read();
_listUrl=_cache1??"https://www.sjjg.uk./eat/food-items/";
_itemUrl=_cache2??"https://www.sjjg.uk/eat/recipe-details/";
}
String listUrl()=>_listUrl;
String itemUrl()=>_listUrl;
void update({String listUrl, String itemUrl}){
_listUrl = listUrl??_listUrl;
_itemUrl = itemUrl??_itemUrl;
save();
}
void read() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
_cache1=prefs.getString('_listUrl')??"https://www.sjjg.uk./eat/food-items/";
_cache2=prefs.getString('_itemUrl')??"https://www.sjjg.uk/eat/recipe-details/";
// print(_cache1);
// print(_cache1);
}
void save() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('_listUrl', _listUrl);
prefs.setString('_itemUrl', _itemUrl);
}
}
I found the problem.
I should not import 'package:flutter_test_app/server.dart';
Still difference between it with import 'server.dart';

How to save to web local storage in flutter web

I have a web site built with flutter for web and currently, am trying to save to web local storage or cookie but can't seem to find any plugin or way to archive that.
You can use window.localStorage from dart:html
import 'dart:html';
class IdRepository {
final Storage _localStorage = window.localStorage;
Future save(String id) async {
_localStorage['selected_id'] = id;
}
Future<String> getId() async => _localStorage['selected_id'];
Future invalidate() async {
_localStorage.remove('selected_id');
}
}
shared_preferences dart package now supports local storage for the web from version 0.5.4.7+
Similar to shared preference on Android and iOS, the following is the code snippet for local storage on web
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart'; // rememeber to import shared_preferences: ^0.5.4+8
void main() {
runApp(MaterialApp(
home: Scaffold(
body: Center(
child: RaisedButton(
onPressed: _incrementCounter,
child: Text('Increment Counter'),
),
),
),
));
}
_incrementCounter() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
int counter = (prefs.getInt('counter') ?? 0) + 1;
print('Pressed $counter times.');
await prefs.setInt('counter', counter);
}
I ran into a similar issue where my preferences weren't being persisted across runs. I thought window.localStorage was broken. I discovered that Flutter was simply launching with a new port number every time by default, so window.localStorage was getting wiped out.
This ticket talks about setting an explicit port. This fixed my issue, and now window.localStorage persists across runs:
https://github.com/Dart-Code/Dart-Code/issues/1769
In VS Code, you can set the port number in your launch.json file:
{
"name": "Flutter",
"request": "launch",
"type": "dart",
"args": ["--web-port", "8686"]
},
With flutter 1.10 we can use universal_html package:
import 'package:universal_html/html.dart';
// ...
// read preference
var myPref = window.localStorage['mypref'];
// ...
// write preference
window.localStorage['mypref'] = myPref;
I am using shared_preferences package to store data on local storage
class SessionManager {
static SessionManager manager;
static SharedPreferences _prefs;
static Future<SessionManager> getInstance() async {
if (manager == null || _prefs == null) {
manager = SessionManager();
_prefs = await SharedPreferences.getInstance();
}
return manager;
}
void putCityId(String cityId) {
_prefs.setString("KEY_CITY_ID", cityId);
}
String getCityId() {
return _prefs.getString("KEY_CITY_ID") ?? "";
}
}
shared_preferences store data for the current session only.
If you want to store data permanently then you should use cookie to store data.
import 'dart:html';
class CookieManager {
static CookieManager _manager;
static getInstance() {
if (_manager == null) {
_manager = CookieManager();
}
return _manager;
}
void _addToCookie(String key, String value) {
// 2592000 sec = 30 days.
document.cookie = "$key=$value; max-age=2592000; path=/;";
}
String _getCookie(String key) {
String cookies = document.cookie;
List<String> listValues = cookies.isNotEmpty ? cookies.split(";") : List();
String matchVal = "";
for (int i = 0; i < listValues.length; i++) {
List<String> map = listValues[i].split("=");
String _key = map[0].trim();
String _val = map[1].trim();
if (key == _key) {
matchVal = _val;
break;
}
}
return matchVal;
}
}
After upgrading to flutter 1.9, 'dart:html' is not compiled anymore as it is not part of dart SDK that shipped with Flutter.
We can use this package at the moment as it support Android, IOS and WEB:
crypted_preferences

Rx Flutter Request List From JsonPalceHolder

I try to get List from jsonPlaceHolder using flutter rxdart stream and try to apply bloc pattern on it.
this class that response for get post response from api
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../models/post_item.dart';
class ItemApi {
Future<List<JsonItem>> getPost() async {
String _url = 'https://jsonplaceholder.typicode.com/posts';
final _response = await http.get(_url);
if (_response.statusCode == 200) {
return (json.decode(_response.body) as List)
.map((jsonItem) => JsonItem.fromJson(jsonItem))
.toList();
}
}
}
I using repository class to wrap using ItemApi class
import 'json_item_request.dart';
import '../models/post_item.dart';
class Repository{
final jsonItemResponse = ItemApi();
Future<List<JsonItem>> getItem() => jsonItemResponse.getPost();
}
at the last i using bloc class that response for get data and set it inside PublishSubject
import '../models/post_item.dart';
import '../resouces/repository.dart';
import 'package:rxdart/rxdart.dart';
class JsonBloc {
final _repository = Repository();
final _streamOfJsonList = PublishSubject<List<JsonItem>>();
Observable<List<JsonItem>> get jsonList=> _streamOfJsonList.stream;
fetchAllPost() async{
Future<List<JsonItem>> list = _repository.getItem();
}
dispose(){
_streamOfJsonList.close();
}
}
My question is how i can set response inside _streamOfJsonList variable to using it when list changed.
Sounds like you already have all the moving parts connected? If so you just need to add the item list to the PublishSubject:
void fetchAllPost() async {
List<JsonItem> list = await _repository.getItem();
_streamOfJsonList.add(list);
}
This will trigger the onListen callback with the new list on anything that is listening to the stream.
You can add error and data to ReplaySubject like below :
void fetchAllPost() async {
List<JsonItem> list = await _repository.getItem();
if (list != null) {
_streamOfJsonList.sink.add(list);
} else {
_streamOfJsonList.addError("ERROR");
}
}

Access other Class method in Flutter/dart

I was working on login with preference. Everything is working fine when I wrote all code in main.dart.
Problem:
When I create separate class on MySharePref then I am getting some error.
MySharePref.dart
import 'package:first_app/UserModel.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SharePrefClass {
void _saveData(UserModel model) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString("Username",model.userName);
await prefs.setString("Password", model.password);
}
Future<UserModel> _getData() async{
SharedPreferences preferences = await SharedPreferences.getInstance();
String username = preferences.getString("Username");
String password = preferences.getString("Password");
UserModel model = UserModel(username,password);
return model;
}
}
I want to access these both functions in main.dart:
_checkLogin() async {
UserModel userModel = new UserModel(
userNameEditText.text , passwordEditText.text);
SharePrefClass mySharedPref = new SharePrefClass();
final UserModel returnModel = mySharedPref._getData() ;
if(returnModel.userName == ""){
print("No data");
}else{
print("else executed");
}
}
I am getting error:
The prefix "_" means private field in dart.
Change the method name _getData() to getData() will let you can access this method in main.dart