Flutter - How to persist selected language? - android

I folowed this video to implement localization in my app :- https://youtu.be/Zw4KoorVxgg
Everything works fine but when the app is relaunched the language gets set to default. How can I persiste the data.
[Note:- I am already using shared preference to persist some other data in my app, but I have no clue about persisting selected Locale]
This class below is called to set the locale:
class LocaleProvider extends ChangeNotifier {
Locale? _locale;
Locale? get locale => _locale;
void setLocale(Locale locale) {
if (!L10n.all.contains(locale)) return;
_locale = locale;
notifyListeners();
}
void clearLocale() {
_locale = null;
notifyListeners();
}
}
And this is the screen where I set the language:
class SelectLanguage extends StatefulWidget {
const SelectLanguage({Key? key}) : super(key: key);
#override
_SelectLanguageState createState() => _SelectLanguageState();
}
class _SelectLanguageState extends State<SelectLanguage> {
void setLocale(String selectedLocale) {
final provider = Provider.of<LocaleProvider>(context, listen: false);
provider.setLocale(
Locale(selectedLocale),
);
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.black,
body: Padding(
padding:
EdgeInsets.all(MediaQuery.of(context).size.width / 41.1),
child: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2.75,
crossAxisSpacing: MediaQuery.of(context).size.width / 41.1,
mainAxisSpacing: MediaQuery.of(context).size.width / 41.1,
),
children: [
LanguageTile(
tileTitle: 'English',
titleOnTap: () => setLocale('en'),
),
LanguageTile(
tileTitle: 'हिन्दी',
titleOnTap: () => setLocale('hi'),
),
],
),
),
),
);
}
}

using shared preference
static Future<Locale> setLocale(String langCode) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString(languageCode, langCode);
return locale(langCode);
}
static Locale locale(String languageCode) {
Locale _temp;
if (languageCode == 'hi') {
_temp = Locale('hi');
}
else {
_temp = Locale('en');
}
return _temp;
}
static Future<Locale> getLocale() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String code = prefs.getString(languageCode);
print('language code:$code');
return locale(code);
}

create a class
import 'dart:ui';
import 'package:shared_preferences/shared_preferences.dart';
const String LAGUAGE_CODE = 'languageCode';
//languages code
const String ENGLISH = 'en';
const String FRENCH = 'fr';
const String ARABIC = 'ar';
const String KINYARWANDA = 'rw';
const String SWAHILLI ="sw";
Future<Locale> storeLocale(String languageCode) async {
SharedPreferences _prefs = await SharedPreferences.getInstance();
await _prefs.setString(LAGUAGE_CODE, languageCode);
return _locale(languageCode);
}
Future<Locale> getLocale() async {
SharedPreferences _prefs = await SharedPreferences.getInstance();
String languageCode = _prefs.getString(LAGUAGE_CODE) ?? ENGLISH;
return _locale(languageCode);
}
Locale _locale(String languageCode) {
switch (languageCode) {
case ENGLISH:
return const Locale(ENGLISH, '');
case FRENCH:
return const Locale(FRENCH, "");
case ARABIC:
return const Locale(ARABIC, "");
case KINYARWANDA:
return const Locale(KINYARWANDA, "");
case SWAHILLI:
return const Locale(SWAHILLI, "");
default:
return const Locale(ENGLISH, '');
}
}
then in your provider class add
Future<void> setLocale(Locale locale) async{
if(!L10n.all.contains(locale)) return;
_locale =locale;
storeLocale(locale.languageCode);//add this important
// storelocal(locale.languageCode);
notifyListeners();
}
where or widget you are implementing it e.g dropdown
Widget build(BuildContext context) {
final provider = Provider.of<LocaleProvider>(context,);
final locale = provider.locale ?? const Locale('en');
return DropdownButtonHideUnderline(
child: DropdownButton(
value: locale,
icon: const Icon(Icons.language,color:Colors.white,),
items: L10n.all.map((locale) {
final flag = L10n.getFlag(locale.languageCode);
return DropdownMenuItem(
value: locale,
onTap: ()async {
//await storeLocale(locale.languageCode);//may uncomment this
final provider =
Provider.of<LocaleProvider>(context,listen: false );
provider.setLocale(locale);
},
and in the main.dart change to stateful and override
#override
void didChangeDependencies() {
super.didChangeDependencies();
getLocale().then(
(locale) => Provider.of<LocaleProvider>(context,listen: false).setLocale(locale));
}
hope this helps

Related

the flutter audio wiveforms package does not display waveforms

I hope you are well, I have a big problem with the flutter audio waveforms package, indeed I want to display the waveforms of my voice files in a folder, but they are not displayed and when I display the value of playerController.bufferData I get a null, please how can I manage this problem, I have already spent days on it.
Sincerely
below are my classes
import 'dart:async';
import 'dart:io';
import 'package:audio_recorder/AudioWaveFormsWidget.dart';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:record/record.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Audio Recorder',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Audio Recorder'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
//late final PlayerController playerController1;
final record = Record();
int _recordDuration = 0;
Timer? _timer;
RecordState _recordState = RecordState.stop;
StreamSubscription<RecordState>? _recordSub;
final List<File> _audioFile = [];
#override
void initState() {
super.initState();
//Listening record state
_recordSub = record.onStateChanged().listen((recordState) {
setState(() => _recordState = recordState);
});
initCheckPermission();
setState(() {
initFileInDir();
});
}
#override
void dispose() {
_timer?.cancel();
_recordSub?.cancel();
record.dispose();
super.dispose();
}
Future initCheckPermission() async {
final statusMicrophone = await Permission.microphone.request();
final statusStorage = await Permission.storage.request();
if (statusMicrophone != PermissionStatus.granted ||
statusStorage != PermissionStatus.granted) {
await Permission.microphone.request();
await Permission.storage.request();
}
}
void _startTimer() {
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 1), (Timer t) {
setState(() => _recordDuration++);
});
}
Widget _buildText() {
if (_recordState != RecordState.stop) {
return _buildTimer();
}
return const Text("Waiting to record");
}
String _formatNumber(int number) {
String numberStr = number.toString();
if (number < 10) {
numberStr = '0$numberStr';
}
return numberStr;
}
Widget _buildTimer() {
final String minutes = _formatNumber(_recordDuration ~/ 60);
final String seconds = _formatNumber(_recordDuration % 60);
return Text(
'$minutes : $seconds',
style: const TextStyle(color: Colors.red),
);
}
Future<Directory> _getDir() async {
//Check platform and adjust settings
final tempDir = Platform.isAndroid
? await getExternalStorageDirectory()
: await getApplicationDocumentsDirectory();
Directory finalPath;
if (Platform.isAndroid) {
String buildDir =
tempDir!.path.replaceFirst("/data/", "/media/").split("files").first;
buildDir += "AudioRecorder"; // Plus ajout du nom de l'application
return finalPath = await Directory(buildDir).create(recursive: true);
} else {
return finalPath = await Directory(tempDir!.path).create(recursive: true);
}
}
void initFileInDir() async {
Directory finalPath = await _getDir();
var exists = await finalPath.exists();
if (exists) {
finalPath.list(recursive: false).forEach((element) {
File file = File(element.path);
_audioFile.add(file);
});
}
}
Widget _buildStopAndPlayIcon() {
if (_recordState != RecordState.stop) {
return const Icon(Icons.stop);
} else {
return const Icon(Icons.mic);
}
}
Future<void> _start() async {
Directory finalPath = await _getDir();
//Start recording
await record.start(
path: '${finalPath.path}/${DateTime.now().millisecondsSinceEpoch}.m4a',
encoder: AudioEncoder.aacLc, // by default
bitRate: 128000, // by default
samplingRate: 44100);
_recordDuration = 0;
_startTimer();
}
Future<File?> _stop() async {
_timer?.cancel();
_recordDuration = 0;
final path = await record.stop();
File? file;
if (path != null) {
file = File(path);
if (kDebugMode) {
print("--------------------------$path");
}
}
return file;
}
Future<void> _pause() async {
_timer?.cancel();
await record.pause();
}
Future<void> _resume() async {
_startTimer();
await record.resume();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
LimitedBox(
maxHeight: 650,
child: ListView.builder(
shrinkWrap: true,
itemCount: _audioFile.length,
itemBuilder: (context, index) {
var data = _audioFile[index];
return AudioWaveFormsWidget(path: data);
},
),
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_buildText(),
ElevatedButton(
onPressed: () async {
if (_recordState == RecordState.stop) {
_start();
} else {
File? newFile = await _stop();
setState((){ _audioFile.add(newFile!);});
}
},
style: ButtonStyle(
elevation: MaterialStateProperty.all(0),
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100),
side: BorderSide.none))),
child: _buildStopAndPlayIcon(),
)
],
),
],
),
),
// This trailing comma makes auto-formatting nicer for build methods.
);
}
}
import 'dart:io';
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class AudioWaveFormsWidget extends StatefulWidget {
final File path;
//final PlayerController playerController1;
const AudioWaveFormsWidget({Key? key, required this.path}) : super(key: key);
#override
State<AudioWaveFormsWidget> createState() => _AudioWaveFormsWidgetState();
}
class _AudioWaveFormsWidgetState extends State<AudioWaveFormsWidget> {
late final PlayerController playerController1;
#override
void initState() {
playerController1 = PlayerController()
..addListener(() {
if (mounted) setState(() {});
});
_preparePlayer();
super.initState();
}
void _preparePlayer() async {
bool exist = await widget.path.exists();
if (exist) {
playerController1.preparePlayer(widget.path.path);
}
print("--------------------------------${playerController1.bufferData}");
}
void _playOrPausePlayer(PlayerController controller) async {
debugPrint(
'****************************************${controller.playerState.toString()}');
controller.playerState == PlayerState.playing
? await controller.pausePlayer()
: await controller.startPlayer(finishMode: FinishMode.pause);
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
shape: BoxShape.rectangle,
color: Colors.lightGreenAccent,
),
child: Row(
children: [
IconButton(
onPressed: () {
_playOrPausePlayer(playerController1);
},
icon: playerController1.playerState == PlayerState.playing
? const Icon(Icons.pause)
: const Icon(Icons.play_arrow)),
AudioFileWaveforms(
density: 1.0,
enableSeekGesture: true,
size: const Size(100.0, 70.0),
playerController: playerController1),
],
)),
);
}
}
if you're trying to record, try setting the bitRate to 48000 (worked for me on iOS when it wasn't showing the waveforms when recording).
final RecorderController recorderController = RecorderController()
..androidEncoder = AndroidEncoder.aac
..androidOutputFormat = AndroidOutputFormat.mpeg4
..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC
..sampleRate = 44100
..bitRate = 48000;

Flutter Shared Preferences

Guys how to transfer data when I login.. For example when I login the transfer data are User ID, email and password.. So if I want to add something that requires the user id how do I call it?
This is my login method
void login() async {
if(passController.text.isNotEmpty && emailController.text.isNotEmpty) {
var response = await http.post(
Uri.parse("url"),
body: ({
'email': emailController.text,
'password': passController.text,
}));
if (response.statusCode == 200) {
final body = jsonDecode(response.body);
print(body.toString());
List<dynamic> data = body["Details"];
print(data[0]['email']);
pageRoute(data[0]['name']);
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Wrong password")));
}
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Sila isi tempat kosong")));
}
}
void pageRoute(data) async {
//STORE VALUE IN SHARED PREFERENCES
SharedPreferences pref = await SharedPreferences.getInstance();
await pref.setString("login", data);
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => nav()),
(route) => false);
This is where I want to take the user id without put it on the textfield.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
import '../Utils/lib.dart';
class CarList extends StatefulWidget {
const CarList({Key? key}) : super(key: key);
#override
State<CarList> createState() => _CarListState();
}
class _CarListState extends State<CarList> {
var userController = TextEditingController();
// late SharedPreferences logindata;
// String? Email;
final pref = Pref();
// late String name;
// late String registeration_no;
#override
void initState() {
// TODO: implement initState
super.initState();
initial();
}
void initial() async {
if (pref.isLogin()) {
final body = jsonDecode(pref.getLogin());
print(body['Details']['user_id'].toString());
}
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
Container(
padding: const EdgeInsets.all(10),
child: TextField(
controller: userController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
suffixIcon: Icon(Icons.email),
labelText: 'User ID',
),
),
),
Container(
margin: EdgeInsets.all(25),
child: TextButton(
child: Text('test',
style: TextStyle(fontSize: 20.0,
color: Colors.blueAccent,
backgroundColor: Colors.white),
),
onPressed: () {
list();
},
),
)
]
)
);
}
void list() async {
{
var response = await http.post(
Uri.parse("url"),
body: ({
'user_id': userController.text,
}));
if (response.statusCode == 200) {
final body = jsonDecode(response.body);
// final SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
// sharedPreferences.setString('email', emailController.text);
pref.saveLogin(true, response.body);
print(body.toString());
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Successfully Login")));
}
}
}
}
Im kinda new with this flutter so might thankful with your help
You can do something like this:
This is store data in pageRoute.
void login() async {
if (passController.text.isNotEmpty && emailController.text.isNotEmpty) {
var response = await http.post(
Uri.parse("http://servisjer.me-tech.com.my/api/Login"),
body: ({
'email': emailController.text,
'password': passController.text,
}));
if (response.statusCode == 200) {
final body = jsonDecode(response.body);
print(body.toString());
List<dynamic> data = body["Details"];
print(data[0]['email']);
pageRoute(Data(data[0]['email'], data[0]['user_id']));
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Wrong password")));
}
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Sila isi tempat kosong")));
}
}
void pageRoute(Data data) async {
MySharedPreferences().storeUser(data);
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => nav()), (route) => false);
}
MySharedPreferences
class MySharedPreferences {
Future<void> storeUser(Data data) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString("email", data.email);
prefs.setInt("user_id", data.userId);
}
Future getUserId() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var userId = prefs.getInt("user_id");
return userId;
}
}
In CarList, retrieve data using this way
#override
void initState() {
MySharedPreferences().getUserId().then((value) {
setState(() {
userController.text = value.toString();
});
});
//TODO: IMPLEMENT INITSTATE
super.initState();
}
Data
class Data {
var email;
var userId;
Data(this.email,this.userId);
}

how to call dbhelper insert or update or delete

import 'dart:async';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import '../models/product.dart';
class DbHelper {
late Database ?_db;
static final DbHelper instance=DbHelper();
Future<Database> get db async{
if(_db==null){
_db=await initializedb();
}
return _db!;
}
static Future<Database> initializedb()async {
String dbPath = join(await getDatabasesPath(),"etrade.db");
var etradeDB = await openDatabase(dbPath,version: 1,onCreate: createDb);
return etradeDB;
}
void createDb(Database db, int version)async {
await db.execute("Create table products(id integer primary key, name text, description
text, unitPrice integer)");
}
Future<List<Product>> getProducts() async{
Database db = await this.db;
var result = await db.query("products");
return List.generate(result.length, (i){
return Product.fromObject(result[i]);
});
}
Future<int> insert(Product product) async {
Database db = await this.db;
var result = await db.insert("products",product.toMap());
return result;
}
Future<int> delete(int id) async {
var db = await this.db;
var result = await db.rawDelete("delete from products where id=$id");
return result;
}
Future<int> update(Product product) async {
var db = await this.db;
var result = await db.update("product", product.toMap(), where: "id=?",whereArgs:
[product.id]);
return result;
}
}
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:sqflite_demo/data/dbHelper.dart';
class ProductAdd extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return ProductAddState();
}
}
class ProductAddState extends State with DbHelper{
initState() {
myAsyncInit();
}
myAsyncInit() async {
//do async stuff
}
var Dbhelper = DbHelper;
final txtName = TextEditingController();
final txtDescription = TextEditingController();
var txtUnitPrice = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text("Yeni Ürün ekle"),
),
body: Padding(
padding: EdgeInsets.all(30.0),
child: Column(
children: <Widget>[
buildNameField(),
buildDescriptionField(),
buildUnitPriceField(),
buildSaveButton()
],
),
),
);
}
buildUnitPriceField() {
return TextField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
decoration: InputDecoration(labelText: "Birim fiyatı", hintText: "20"),
controller: txtName,
);
}
buildNameField() {
return TextField(
decoration: InputDecoration(labelText: "Ürün adı", hintText: "Tohum"),
controller: txtDescription,
);
}
buildDescriptionField() {
return TextField(
decoration: const InputDecoration(
labelText: "Ürün açıklaması", hintText: "Domates"),
controller: txtUnitPrice,
);
}
buildSaveButton() {
return FlatButton(
onPressed: () {
addProduct();
},
child: const Text("Ekle"),
);
}
void addProduct() async {
await Dbhelper.insert;
}
}
I want to call insert from the db helper below, the error it gives is as follows
The getter 'insert' isn't defined for the type 'Type'. (Documentation) Try importing the library that defines 'insert', correcting the name to the name of an existing getter, or defining a getter or field named 'insert'.
First if you want to create a singleton class do it like this,
class DbHelper {
static final DbHelper instance= DbHelper._();//change to this
...
}
second,
When using singleton no need to create it's instance,
initialise that class in main or some root widget.
like this,
void main()async{
await DbHelper.init();
...
}
third, now where you want to use this functions,
class ProductAdd extends StatefulWidget {
const ProductAdd({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _ ProductAddState();
}
class _ ProductAddState extends State< ProductAdd> {
// you actually don't need "mixin" just directly use it.
...
void addProduct() async {
await Dbhelper.insert();
}
}
}
more about singleton,
How do you build a Singleton in Dart?

Error: Could not find the correct Provider<AuthState> above this AuthPage Widget

ERROR:
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following ProviderNotFoundException was thrown building AuthPage(dirty, state:
_AuthPageState#7ac1c):
Error: Could not find the correct Provider above this AuthPage Widget
This happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:
You added a new provider in your main.dart and performed a hot-reload.
To fix, perform a hot-restart.
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that AuthPage is under your MultiProvider/Provider.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
consider using builder like so:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
My Code:
AuthPage.dart:-
import 'package:first_app/pages/auth/bloc/auth_state.dart';
import 'package:first_app/pages/auth/widgets/auth_button.dart';
import 'package:first_app/pages/auth/widgets/otp_page.dart';
import 'package:first_app/pages/auth/widgets/phone_page.dart';
import 'package:first_app/pages/auth/widgets/set_up_account.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
class AuthPage extends StatefulWidget {
final int page;
final String? uid;
const AuthPage({
Key? key,
this.page = 0,
this.uid,
}) : super(key: key);
#override
_AuthPageState createState() => _AuthPageState();
}
class _AuthPageState extends State<AuthPage> {
#override
Widget build(BuildContext context) {
final state = Provider.of<AuthState>(context);
final screenSize = MediaQuery.of(context).size;
return
Builder(builder: (context) {
return Stack(
children: [
Container(
height: screenSize.height,
width: screenSize.width,
color: Colors.white,
child: PageView(
controller: state.controller,
onPageChanged: state.onPageChanged,
physics: NeverScrollableScrollPhysics(),
children: [
PhonePage(),
OtpPage(),
SetUpAccount(),
],
),
),
AuthButton(),
],
);
});
}
}
class AuthPageWidget extends StatelessWidget {
final int page;
final String? uid;
const AuthPageWidget({
Key? key,
required this.page,
this.uid,
}) : super(key: key);
#override
Widget build(BuildContext context) {
final state = AuthState(page, uid ?? '');
return ChangeNotifierProvider(
create: (_) => state,
child: ChangeNotifierProvider.value(
value: state,
child: AuthPage(page: page, uid: uid),
),
);
}
}
AuthState.dart
import 'dart:async';
import 'package:first_app/models/user.dart';
import 'package:first_app/repositories/user_repository.dart';
import 'package:first_app/services/auth.dart';
import 'package:first_app/services/map_services.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
enum PhoneAuthState { initial, success, loading, codeSent, error }
/*part of 'auth_bloc.dart';
abstract class AuthState extends Equatable {
const AuthState();
#override
List<Object> get props => [];
}*/
class AuthState extends ChangeNotifier {
final authService = AuthService.instance;
final userRepo = UserRepository.instance;
PhoneAuthState _phoneAuthState = PhoneAuthState.initial;
String verificationId = '';
TextEditingController phoneController = TextEditingController();
TextEditingController otpController = TextEditingController();
TextEditingController firstNameController = TextEditingController();
TextEditingController lastNameController = TextEditingController();
TextEditingController emailController = TextEditingController();
TextEditingController licensePlateController = TextEditingController();
TextEditingController vehicleColorController = TextEditingController();
TextEditingController vehicleTypeController = TextEditingController();
TextEditingController vehicleManufacturersController = TextEditingController();
Roles role = Roles.passenger;
PageController? controller;
int pageIndex = 0;
String uid = '';
int timeOut = 30;
bool get isRoleDriver => role == Roles.driver;
AuthState(int page, String uid) {
this.uid = uid;
controller = PageController(initialPage: page);
pageIndex = page;
notifyListeners();
siginCurrentUser();
}
PhoneAuthState get phoneAuthState => _phoneAuthState;
set changeRoleState(int value) {
role = Roles.values[value];
notifyListeners();
}
set phoneAuthStateChange(PhoneAuthState phoneAuthState) {
_phoneAuthState = phoneAuthState;
notifyListeners();
}
void animateToNextPage(int page) {
controller!.animateToPage(page, duration: Duration(milliseconds: 400), curve: Curves.easeIn);
pageIndex = page;
notifyListeners();
}
void onPageChanged(int value) {
pageIndex = value;
notifyListeners();
}
Future<void> signUp() async {
phoneAuthStateChange = PhoneAuthState.loading;
final address = await MapService.instance?.getCurrentPosition();
try {
final user = User(
uid: uid,
isActive: true,
firstname: firstNameController.text,
lastname: lastNameController.text,
email: emailController.text,
createdAt: DateTime.now(),
isVerified: true,
licensePlate: licensePlateController.text,
phone: "234${phoneController.text}",
vehicleType: vehicleTypeController.text,
vehicleColor: vehicleColorController.text,
vehicleManufacturer: vehicleManufacturersController.text,
role: role,
latlng: address?.latLng,
);
await userRepo.setUpAccount(user);
phoneAuthStateChange = PhoneAuthState.success;
} on FirebaseException catch (e) {
print(e.message);
phoneAuthStateChange = PhoneAuthState.error;
}
}
Future<void> phoneNumberVerification(String phone) async {
await AuthService.instance!.verifyPhoneSendOtp(phone, completed: (credential) async {
if (credential.smsCode != null && credential.verificationId != null) {
verificationId = credential.verificationId ?? '';
notifyListeners();
await verifyAndLogin(credential.verificationId!, credential.smsCode!, phoneController.text);
}
}, failed: (error) {
phoneAuthStateChange = PhoneAuthState.error;
}, codeSent: (String id, int? token) {
verificationId = id;
notifyListeners();
phoneAuthStateChange = PhoneAuthState.codeSent;
codeSentEvent();
print('code sent $id');
}, codeAutoRetrievalTimeout: (id) {
verificationId = id;
notifyListeners();
phoneAuthStateChange = PhoneAuthState.codeSent;
animateToNextPage(1);
print('timeout $id');
});
animateToNextPage(1);
notifyListeners();
}
Future<void> verifyAndLogin(String verificationId, String smsCode, String phone) async {
phoneAuthStateChange = PhoneAuthState.loading;
final uid = await authService?.verifyAndLogin(verificationId, smsCode, phone);
await userRepo.getUser(uid);
this.uid = uid ?? '';
animateToNextPage(2);
notifyListeners();
phoneAuthStateChange = PhoneAuthState.success;
print('completed');
}
Future<void> siginCurrentUser() async {
await userRepo.signInCurrentUser();
}
Future<void> codeSentEvent() async {
animateToNextPage(1);
_startCountDown();
}
void _startCountDown() {
Timer.periodic(Duration(seconds: 1), (timer) {
if (timer.tick > 30) {
timer.cancel();
} else {
--timeOut;
}
notifyListeners();
});
}
}
main.dart
import 'package:first_app/pages/home/home.dart';
import 'package:first_app/repositories/user_repository.dart';
import 'package:first_app/ui/theme.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
UserRepository.instance.signInCurrentUser();
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'BrilliantDrive',
theme: CityTheme.theme,
home: HomePage(),
);
}
}
Initialize your provider 1st. Refer this https://stackoverflow.com/a/68418866/16467763.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<AuthState>(
create: (context) => AuthState(),
),
],
child: MyApp(),
),
);
}
class AuthPageWidget extends StatelessWidget {
final int page;
final String? uid;
const AuthPageWidget({
Key? key,
required this.page,
this.uid,
}) : super(key: key);
#override
Widget build(BuildContext context) {
final state = AuthState(page, uid ?? '');
return ChangeNotifierProvider(
create: (_) => state,
child: ChangeNotifierProvider.value(
value: state,
child: AuthPage(page: page, uid: uid),
),
);
}
}
You should move the ChangeNotifierProvider to your main.dart like this
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
final state = AuthState(page, uid ?? '');
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home: ChangeNotifierProvider(
create: (_) => state,
child: AuthPage(page: page, uid: uid),
),
),
);
}
OR
class SomeWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: ChangeNotifierProvider(
create: (_) => state,
child: ChangeNotifierProvider.value(
value: state,
child: AuthPage(page: page, uid: uid),
),
)
),
);
}
}

Flutter switch toggles off on its own

I have created a flutter starter kit that allowes me to switch between themes in-app.
Now this works great but there is a small issue.
I have placed the switch button in the settings screen,
but when I go to another screen and then back to the settings screen
- it would seem that the switch button goes to Off mode on its own.
I'm attaching an image and my code on github so that you guys can see what I mean.
class ThemeSwitchState extends State {
bool switchControl = false;
Future<bool> darkMode() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return sharedPreferences.getBool("isDark");
}
#override
Widget build(BuildContext context) {
return FutureBuilder<bool>(
future: darkMode(),
builder: (context, _snapshot) {
return Transform.scale(
scale: 1.5,
child: Switch(
value: _snapshot.data ?? false,
onChanged: (value) {
save(value);
setState(() {
});
},
activeColor: CustomColors().duskBlue,
activeTrackColor: CustomColors().noroGrey,
inactiveThumbColor: CustomColors().lureGrey,
inactiveTrackColor: CustomColors().noroGrey,
),
);
},
);
}
void save(bool value) async{
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
await sharedPreferences.setBool("isDark", value);
}
void toggleSwitch(bool value) {
ThemeChanger _themeChanger =
Provider.of<ThemeChanger>(context, listen: false);
if (switchControl == false) {
setState(() {
switchControl = true;
});
print('Theme is Dark');
_themeChanger.setTheme(CustomThemes.darkTheme.copyWith(
textTheme:
CustomThemes.darkTextTheme(CustomThemes.darkTheme.textTheme)));
} else {
setState(() {
switchControl = false;
});
print('Theme is Light');
_themeChanger.setTheme(CustomThemes.lightTheme.copyWith(
textTheme:
CustomThemes.lightTextTheme(CustomThemes.lightTheme.textTheme)));
}
}
}
You can use SharedPreferences from https://pub.dev/packages/shared_preferences
to save the last value of the CheckBox
I wrote an example
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Settings extends StatefulWidget {
#override
_SettingsState createState() => _SettingsState();
}
class _SettingsState extends State<Settings> {
Future<bool> darkMode() async{
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return sharedPreferences.getBool("isNight");
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: <Widget>[
Text("Night Mode"),
FutureBuilder<bool>(
future: darkMode(),
builder: (context, _snapshot){
return Checkbox(
value: _snapshot.data ?? false,
onChanged: (value){
save(value);
setState(() {
toggleSwitch(value);
});
},
);
},
)
],
),
),
);
}
void save(bool value) async{
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
await sharedPreferences.setBool("isNight", value);
}
}
EDIT: WITH SWITCH
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Settings extends StatefulWidget {
#override
_SettingsState createState() => _SettingsState();
}
class _SettingsState extends State<Settings> {
Future<bool> darkMode() async{
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
return sharedPreferences.getBool("isNight");
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: <Widget>[
Text("Night Mode"),
FutureBuilder<bool>(
future: darkMode(),
builder: (context, _snapshot){
return Switch(
value: _snapshot.data ?? false,
onChanged: (value){
save(value);
setState(() {
});
},
);
},
)
],
),
),
);
}
void save(bool value) async{
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
await sharedPreferences.setBool("isNight", value);
}
}
UPDATE use value instead of switchControl
void toggleSwitch(bool value) {
ThemeChanger _themeChanger =
Provider.of<ThemeChanger>(context, listen: false);
if (value) {
setState(() {
switchControl = true;
});
print('Theme is Dark');
_themeChanger.setTheme(CustomThemes.darkTheme.copyWith(
textTheme:
CustomThemes.darkTextTheme(CustomThemes.darkTheme.textTheme)));
} else {
setState(() {
switchControl = false;
});
print('Theme is Light');
_themeChanger.setTheme(CustomThemes.lightTheme.copyWith(
textTheme:
CustomThemes.lightTextTheme(CustomThemes.lightTheme.textTheme)));
}
}
}

Categories

Resources