flutter:How to persist enum in shared preference? - flutter

I'm working with Enums through my application and I noticed that it resets every time I leave the page or of course when I close the app, I know about shared_preferences but I don't know if it's the right way or actually how to implement it with an enum. Any information on this would be much appreciated
here is a sample from my application:
`enum Gender {
male,
female,
}
class InputPage extends StatefulWidget {
#override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
Gender selectedGender;
int height = 180;
int weight = 60;
int age = 20;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.male;
});
},
colour: selectedGender == Gender.male
? kActiveCardColour
: kInactiveCardColour,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
),
),
),
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.female;
});
},
colour: selectedGender == Gender.female
? kActiveCardColour
: kInactiveCardColour,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
),
),
),
],
))
,`

You can copy paste run full code below
You can use package https://pub.dev/packages/enum_to_string to save and get enum as String
Step 1: init selectedGender in initState() with EnumToString.fromString
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
initGender();
});
super.initState();
}
void initGender() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
selectedGender =
EnumToString.fromString(Gender.values, prefs.getString("gender"));
setState(() {});
}
Step 2: Save selectedGender with prefs.setString("gender", enumToString.parse(Gender.male));
onPress: () async {
setState(() {
selectedGender = Gender.male;
});
SharedPreferences prefs =
await SharedPreferences.getInstance();
prefs.setString(
"gender", EnumToString.parse(Gender.male));
}
working demo
full code
import 'package:flutter/material.dart';
import 'package:enum_to_string/enum_to_string.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
const kBottomContainerHeight = 80.0;
const kActiveCardColour = Color(0xFF1D1E33);
const kInactiveCardColour = Color(0xFF111328);
const kBottomContainerColour = Color(0xFFEB1555);
const kLabelTextStyle = TextStyle(
fontSize: 18.0,
color: Color(0xFF8D8E98),
);
const kNumberTextStyle = TextStyle(
fontSize: 50.0,
fontWeight: FontWeight.w900,
);
const kLargeButtonTextStyle = TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.bold,
);
const kTitleTextStyle = TextStyle(
fontSize: 50.0,
fontWeight: FontWeight.bold,
);
const kResultTextStyle = TextStyle(
color: Color(0xFF24D876),
fontSize: 22.0,
fontWeight: FontWeight.bold,
);
const kBMITextStyle = TextStyle(
fontSize: 100.0,
fontWeight: FontWeight.bold,
);
const kBodyTextStyle = TextStyle(
fontSize: 22.0,
);
class IconContent extends StatelessWidget {
IconContent({this.icon, this.label});
final IconData icon;
final String label;
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
icon,
size: 80.0,
),
SizedBox(
height: 15.0,
),
Text(
label,
style: kLabelTextStyle,
)
],
);
}
}
enum Gender {
male,
female,
}
class ReusableCard extends StatelessWidget {
ReusableCard({#required this.colour, this.cardChild, this.onPress});
final Color colour;
final Widget cardChild;
final Function onPress;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress,
child: Container(
child: cardChild,
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0),
),
),
);
}
}
class InputPage extends StatefulWidget {
#override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
Gender selectedGender;
int height = 180;
int weight = 60;
int age = 20;
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
initGender();
});
super.initState();
}
void initGender() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
selectedGender =
EnumToString.fromString(Gender.values, prefs.getString("gender"));
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
onPress: () async {
setState(() {
selectedGender = Gender.male;
});
SharedPreferences prefs =
await SharedPreferences.getInstance();
prefs.setString(
"gender", EnumToString.parse(Gender.male));
},
colour: selectedGender == Gender.male
? kActiveCardColour
: kInactiveCardColour,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
),
),
),
Expanded(
child: ReusableCard(
onPress: () async {
setState(() {
selectedGender = Gender.female;
});
SharedPreferences prefs =
await SharedPreferences.getInstance();
prefs.setString(
"gender", EnumToString.parse(Gender.female));
},
colour: selectedGender == Gender.female
? kActiveCardColour
: kInactiveCardColour,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
),
),
),
],
))
]));
}
}
Future<void> main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: InputPage(),
);
}
}

I think shared prefs only stores simple types. You could copy what json_serializable does and just decode a string value with a simple function and a mapping. This is their implementation but I'll add comments.
// _$CategoryEnumMap is a Map<dynamic, String> mapping from enum entry to string
const _$CategoryEnumMap = {
Category.action: 'action',
Category.drama: 'drama',
};
T _$enumDecode<T>(
// enumValues would be _$CategoryEnumMap in this case
Map<T, dynamic> enumValues,
// source is the string value you would get from shared prefs
dynamic source, {
T unknownValue,
}) {
if (source == null) {
throw ArgumentError('A value must be provided. Supported values: '
'${enumValues.values.join(', ')}');
}
final value = enumValues.entries
.singleWhere((e) => e.value == source, orElse: () => null)
?.key;
if (value == null && unknownValue == null) {
throw ArgumentError('`$source` is not one of the supported values: '
'${enumValues.values.join(', ')}');
}
return value ?? unknownValue;
}
You could get rid of the _$ stuff to make the function publicly accessible and I'm sure you could automatically create the EnumMap using a function like this.
enum Category {
action,
drama,
}
final Map<dynamic, String> CategoryEnumMap = Map.fromIterable(
Category.values.map((e) => MapEntry(e, describeEnum(e))),
);

Related

Viewing pdf from url in Flutter using the package advance_pdf_viewer

I can successfully view pdfs however any state changes in my page, such uploading new pdfs, thereafter, I can only view the pdfs that have been cached. All the others hang on the function:
document = await PDFDocument.fromURL(file);
I am using the package advance_pdf_viewer, is this a bug within the package? I am fetching the url from the rails api all with the similar url prefix.
import 'dart:async';
import 'package:advance_pdf_viewer/advance_pdf_viewer.dart';
import 'package:fl_downloader/fl_downloader.dart';
import 'package:flutter/material.dart';
class PdfViewer extends StatefulWidget {
final String file;
final String counter;
const PdfViewer({Key? key, required this.file, required this.counter}) : super(key: key);
#override
State<PdfViewer> createState() => _PdfViewerState(file, counter);
}
class _PdfViewerState extends State<PdfViewer> {
String file;
String counter;
_PdfViewerState(this.file, this.counter);
bool _isLoading = true;
bool _isDownloading = false;
PDFDocument? document;
int progress = 0;
late StreamSubscription progressStream;
#override
void initState() {
loadDoc();
FlDownloader.initialize();
progressStream = FlDownloader.progressStream.listen((event) {
print(event.status);
if (event.status == DownloadStatus.successful) {
setState(() {
progress = event.progress;
_isDownloading = false;
});
FlDownloader.openFile(
filePath: event.filePath,
);
} else if (event.status == DownloadStatus.running) {
setState(() {
_isDownloading = true;
progress = event.progress;
});
}
});
}
void dispose(){
progressStream.cancel();
super.dispose();
//...
}
loadDoc() async {
try {
document = await PDFDocument.fromURL(file);
} catch (e) {
Navigator.pop(context);
}
setState(() => _isLoading = false);
}
download() async {
await FlDownloader.download(file, fileName: 'Report-${counter}.pdf');
setState(() {
_isDownloading = false;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(
Icons.cancel,
color: Color(0xff5C449A),
),
onPressed: () => {Navigator.pop(context)},
),
actions: [
IconButton(
icon: Icon(
Icons.save,
color: Color(0xff5C449A),
),
onPressed: download,
),
],
title: Text(
"Report",
style: TextStyle(color: Color(0xff383636)),
),
backgroundColor: Colors.white,
),
body: Center(
child: _isLoading
? const Center(child: CircularProgressIndicator())
: Stack(children: [
PDFViewer(document: document!),
(_isDownloading == true)
? Container(
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.7)),
child: Align(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(
color: Color(0xff5C449A)),
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Text(
"DOWNLOADING ($progress%)",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
)
],
)),
)
: Text("")
])),
);
}
}
I am not sure what else to do other than programatically force a hot restart.

Can't read the arguments on a second screen using PushNamed in Flutter

I have the following code that is passing an object as an Argument to another screen using Push named:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter_nsd/flutter_nsd.dart';
import 'package:australremote/screens/screen5.dart';
import 'package:australremote/screens/screen6.dart';
void main() {
runApp(const Screen1());
}
class Screen1 extends StatefulWidget {
const Screen1({Key? key}) : super(key: key);
#override
State createState() => _Screen1State();
}
class _Screen1State extends State<Screen1> {
final flutterNsd = FlutterNsd();
final services = <NsdServiceInfo>[];
bool initialStart = true;
bool _scanning = false;
//List<String> _deviceIPAddresses = [];
_Screen1State();
#override
void initState() {
super.initState();
// Try one restart if initial start fails, which happens on hot-restart of
// the flutter app.
flutterNsd.stream.listen(
(NsdServiceInfo service) {
setState(() {
services.add(service);
});
},
onError: (e) async {
if (e is NsdError) {
if (e.errorCode == NsdErrorCode.startDiscoveryFailed &&
initialStart) {
await stopDiscovery();
} else if (e.errorCode == NsdErrorCode.discoveryStopped &&
initialStart) {
initialStart = false;
await startDiscovery();
}
}
},
);
startDiscovery();
}
Future<void> startDiscovery() async {
if (_scanning) return;
setState(() {
services.clear();
_scanning = true;
});
await flutterNsd.discoverServices('_http._tcp.');
/*List<InternetAddress> addresses = await services.resolve();
setState(() {
_deviceIPAddresses.add(addresses[0].address);
});*/
}
Future<void> stopDiscovery() async {
if (!_scanning) return;
setState(() {
services.clear();
_scanning = false;
});
flutterNsd.stopDiscovery();
}
#override
Widget build(BuildContext context) {
//return MaterialApp(
return Scaffold(
appBar: AppBar(
title: const Text('Your devices',style: TextStyle(color: Colors.black87),),
titleSpacing: 00.0,
centerTitle: true,
toolbarHeight: 60.2,
toolbarOpacity: 0.6,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(25),
bottomLeft: Radius.circular(25)),
),
elevation: 0.00,
backgroundColor: Colors.transparent,
),
body:
Column(
children: <Widget>[
Expanded(
child: _buildMainWidget(context),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SafeArea(
child: IconButton(
iconSize: 32.0,
icon: const Icon(Icons.add),
tooltip: 'Add a new device',
onPressed: () {
// Navigate to the second screen using a named route.
Navigator.pushNamed(context, '/second');
},
),
),
],
),
],
),
);
// );
}
Widget _buildMainWidget(BuildContext context) {
if (services.isEmpty && _scanning) {
return const Center(
child: CircularProgressIndicator(),
);
} else if (services.isEmpty && !_scanning) {
return const SizedBox.shrink();
} else {
print(services);
return ListView.builder(
itemBuilder: (context, index) => ListTile(
leading: Icon(
Icons.speaker,
color: Colors.grey[500],
),
title: Text(services[index].name ?? 'Invalid service name',textAlign: TextAlign.left,style: TextStyle(color: Colors.black,fontWeight: FontWeight.w500,
fontSize: 20,)
),
subtitle: Text(services[index].hostname ?? 'Invalid service name',textAlign: TextAlign.left,style: TextStyle(color: Colors.grey,fontWeight: FontWeight.w500,
fontSize: 10,)
),
trailing: Icon(
Icons.arrow_forward_ios,
),
onTap: ()
{
Navigator.of(context).pushNamed(
'/sixth',
arguments:services,
);
},
),
itemCount: services.length,
);
}
}
}
Second screen:
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:australremote/screens/screen1.dart';
import 'package:convert/convert.dart';
void main() {
runApp(MyHomePage6());
}
class MyHomePage6 extends StatefulWidget {
const MyHomePage6({Key? key}) : super(key: key);
#override
_MyHomePage6State createState() => _MyHomePage6State();
}
class _MyHomePage6State extends State<MyHomePage6> {
// final String args = "";
#override
Widget build(BuildContext context) {
//final services args = ModalRoute.of(context)?.settings?.arguments;
//String hostname = args[0];
final args = ModalRoute.of(context)?.settings?.arguments as List<String>;
final String services = '';
final int index;
final String hostname ='';
final String service = '';
return Scaffold(
appBar: AppBar(
title: const Text('Connect your DAC to your network',
style: TextStyle(color: Colors.black87)),
titleSpacing: 00.0,
centerTitle: true,
toolbarHeight: 60.2,
toolbarOpacity: 0.6,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(25),
bottomLeft: Radius.circular(25)),
),
elevation: 0.00,
backgroundColor: Colors.transparent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(service),
//Text("Your name is :$name"),
/*SizedBox(height: 20),
Text("HEX value: $_hexValue"),
SizedBox(height: 20),
Text("API response: $_apiResponse"),
SizedBox(height: 20),
Text("SSID Hex: $_ssidHexValue"),*/
SizedBox(height: 20),
TextButton(
onPressed:() async{
// Send an API request with the HEX value
var response = await http.get(Uri.parse(
"http://10.10.10.254/httpapi.asp?command=getStatusEx"),);
if (response.statusCode == 200) {
print(response);
// Navigator.pushNamed(context, '/');
} else {
print("There is something wrong here");
}
},
child: Text("Next", style: TextStyle(color: Colors.grey)),
),
],
),
),
);
}
}
I tried to define the getters, but I'm not quite sure I can extract the content from the arguments I've sent from the previous screen.Also, I'm receiving the following error:
type 'List' is not a subtype of type 'List' in type cast
Problem:
At first screen you defined services with generic NsdServiceInfo like:
final services = <NsdServiceInfo>[];
but on second screen , at modalRoute you used String as generic like:
final args = ModalRoute.of(context)?.settings?.arguments as List<String>;
Solution:
so make String to NsdServiceInfo in route arg defining variable like:
final args = ModalRoute.of(context)?.settings?.arguments as List<NsdServiceInfo>;

How to change text in textformfield in flutter conatct picker

I have fluttercontactpicker as suffix in my textformfield.
while selecting the contact it is not showing in textformfield.
EditTextField(
onChanged: (text) {
setState(() => _phn = text);
},
input: [FilteringTextInputFormatter.digitsOnly],
isPassword: false,
inputType: TextInputType.number,
decoration: country_code,
isSuffix: InkWell(
onTap: () async {
final PhoneContact contact =
await FlutterContactPicker
.pickPhoneContact();
if (contact != null) {
setState(() {
_phn = contact.phoneNumber!.number
.removeAllWhiteSpace()
.replaceFirst('+91', '')
.toString();
print("this is $_phn");
});
}
},
child: const Icon(
Icons.contacts,
color: t5DarkNavy,
),
),
),
You need to make use of controller for TextForm Field here is an example, you can update controller text with setState
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:fluttercontactpicker/fluttercontactpicker.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) => MaterialApp(
home: MainWidget(),
);
}
class MainWidget extends StatefulWidget {
#override
_MainWidgetState createState() => _MainWidgetState();
}
class _MainWidgetState extends State<MainWidget> {
PhoneContact? _phoneContact;
EmailContact? _emailContact;
String? _contact;
Image? _contactPhoto;
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Column(
children: kIsWeb && !FlutterContactPicker.available
? [_buildError(context)]
: _buildChildren(context),
),
);
Widget _buildError(BuildContext context) {
return RichText(
text: TextSpan(
text:
'Your browser does not support contact pickers for more information see: ',
children: [
TextSpan(
text: 'https://web.dev/contact-picker/',
style: TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () => launch('https://web.dev/contact-picker/')),
TextSpan(text: ' and '),
TextSpan(
text:
'https://developer.mozilla.org/en-US/docs/Web/API/Contact_Picker_API#Browser_compatibility/',
style: TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () => launch(
'https://developer.mozilla.org/en-US/docs/Web/API/Contact_Picker_API#Browser_compatibility'))
]),
);
}
List<Widget> _buildChildren(BuildContext context) {
return <Widget>[
if (_emailContact != null)
Column(
children: <Widget>[
const Text("Email contact:"),
Text("Name: ${_emailContact!.fullName}"),
Text(
"Email: ${_emailContact!.email!.email} (${_emailContact!.email!.label})")
],
),
if (_phoneContact != null)
Column(
children: <Widget>[
const Text("Phone contact:"),
TextFormField(
controller: TextEditingController()..text = '${_phoneContact!.fullName}',
onSaved: (String? value) {
debugPrint("Value Set To Be : ${_phoneContact!.fullName}");
},
),
Text(
"Phone: ${_phoneContact!.phoneNumber!.number} (${_phoneContact!.phoneNumber!.label})")
],
),
if (_contactPhoto != null) _contactPhoto!,
if (_contact != null) Text(_contact!),
ElevatedButton(
child: const Text("pick phone contact"),
onPressed: () async {
final PhoneContact contact =
await FlutterContactPicker.pickPhoneContact();
print(contact);
setState(() {
_phoneContact = contact;
});
},
),
ElevatedButton(
child: const Text("pick email contact"),
onPressed: () async {
final EmailContact contact =
await FlutterContactPicker.pickEmailContact();
print(contact);
setState(() {
_emailContact = contact;
});
},
),
ElevatedButton(
child: const Text("pick full contact"),
onPressed: () async {
final FullContact contact =
(await FlutterContactPicker.pickFullContact());
setState(() {
_contact = contact.toString();
_contactPhoto = contact.photo?.asWidget();
});
},
),
ElevatedButton(
child: const Text('Check permission'),
onPressed: () async {
final granted = await FlutterContactPicker.hasPermission();
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Granted: '), content: Text('$granted')));
},
),
ElevatedButton(
child: const Text('Request permission'),
onPressed: () async {
final granted = await FlutterContactPicker.requestPermission();
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Granted: '), content: Text('$granted')));
},
),
];
}
}
/// your code
TextEditingController _phn = TextEditingController();
_phn = contact.phoneNumber!.number
.removeAllWhiteSpace()
.replaceFirst('+91', '')
.toString();
/// Modify as
_phn.text = contact.phoneNumber!.number
.removeAllWhiteSpace()
.replaceFirst('+91', '')
.toString();

Update the navigation menu when changing the display conditions of icons in BottomNavigationBarItem in the flutter

I have a navigation menu that I made for a test application, there are some tabs that I want to hide if I am not logged into the application. After logging in, these tabs should appear. The problem is that after logging in, I go to the desired page and I don't see all the navigation menu icons. For them to appear, I need to click on one of the available icons (only 2 icons are available for authorization) and only then the navigation menu will be updated and everything will be as it should be. All 6 icons will be visible! Can someone help me with this? Here I described the problem with the code that I am using. I would be grateful for any help.
import 'package:flutter/material.dart';
import 'package:flutter_app_seals/model/object_main/Status.dart';
import 'package:flutter_app_seals/model/seals/Seals_List.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_app_seals/Setting_glob.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:flutter_app_seals/model/add_seals/JsonAddSeals.dart';
import 'package:flutter_app_seals/model/user_page/page.dart';
import 'package:flutter_app_seals/model/setting/globalvar.dart' as global;
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:io';
import 'package:flutter_aes_ecb_pkcs5/flutter_aes_ecb_pkcs5.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter/foundation.dart';
void main() => runApp(Main_Page());
class Main_Page extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage());
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
var test;
class _HomePageState extends State<HomePage> {
Future<bool> _onBackPressed() {
return showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Ви впевнині?'),
content: new Text('Ви хочете вийти з додатку',
style: TextStyle(
fontSize: 20,
),
),
actions: <Widget>[
new GestureDetector(
onTap: () => Navigator.of(context).pop(false),
child:
Text("Ні",
style: TextStyle(
fontSize: 25,
),
),
),
SizedBox(height: 40),
new GestureDetector(
onTap: () => Navigator.of(context).pop(true),
child: Text("Так",
style: TextStyle(
fontSize: 25,
),
),
),
],
),
) ??
false;
}
int _pageIndex = 0;
PageController _pageController;
List<Widget> tabPages = [
Login(),
Setting(),
UserPage(),
Status_Obj(),
Status_Seals(),
Add_Seals(),
] ;
#override
void initState(){
super.initState();
_pageController = PageController(initialPage: _pageIndex);
}
#override
void dispose() {
_pageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onBackPressed,
child: new Scaffold(
resizeToAvoidBottomInset: false,
bottomNavigationBar: BottomNavigationBar(
showSelectedLabels: true, // <-- HERE
showUnselectedLabels: true, // <-- AND
currentIndex: _pageIndex,
onTap: onTabTapped,
backgroundColor: Colors.blue,
items: <BottomNavigationBarItem>[
new BottomNavigationBarItem( icon: Icon(Icons.admin_panel_settings_outlined), title: Text(" Вхід"),backgroundColor: Colors.lightBlue),
new BottomNavigationBarItem(icon: Icon(Icons.settings), title: Text("Налаштування"),backgroundColor: Colors.lightBlue),
if( global.nameUser ?.isNotEmpty == true)...[
new BottomNavigationBarItem(icon: Icon(Icons.person_pin), title: Text("Користувач"),backgroundColor: Colors.lightBlue),
new BottomNavigationBarItem(icon: Icon(Icons.home), title: Text("Пломбування"),backgroundColor: Colors.lightBlue),
new BottomNavigationBarItem(icon: Icon(Icons.qr_code), title: Text("Пломби"),backgroundColor: Colors.lightBlue),
new BottomNavigationBarItem(icon: Icon(Icons.add_outlined), title: Text("Акт приймання"),backgroundColor: Colors.lightBlue),
]
],
),
body: PageView(
children: tabPages,
onPageChanged: onPageChanged,
controller: _pageController,
),
),
);
}
void onPageChanged(int page) {
setState(() {
this._pageIndex = page;
});
}
void onTabTapped(int index) {
this._pageController.animateToPage(index,duration: const Duration(milliseconds: 500),curve: Curves.easeInOut);
}
}
class Login extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new LoginPage(
storage: Storage()
)
);
}
}
class LoginPage extends StatefulWidget {
final Storage storage;
LoginPage({Key key, #required this.storage}) : super(key: key);
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
//Info about users
String state;
#override
void initState() {
super.initState();
widget.storage.readData().then((String value) {
setState(() {
global.urlVar = value;
});
});
}
bool _isLoading = false;
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light.copyWith(statusBarColor: Colors.transparent));
return Scaffold(
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue, Colors.white],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
),
child: _isLoading ? Center(child: CircularProgressIndicator()) : ListView(
children: <Widget>[
headerSection(),
textSection(),
buttonSection(),
],
),
),
);
}
signIn(String login, pass) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
var AESLogin = login;
var AESpass = pass;
//generate a 16-byte random key
var key = '11111';
print(key);
//encrypt
var encryptLogin = await FlutterAesEcbPkcs5.encryptString(AESLogin, key);
var encryptPass = await FlutterAesEcbPkcs5.encryptString(AESpass, key);
HttpClient client = new HttpClient();
client.badCertificateCallback = ((X509Certificate cert, String host, int port) => true);
String url = global.urlVar + "/auth_user";
Map map = {
"login": encryptLogin,
"pass": encryptPass
};
HttpClientRequest request = await client.postUrl(Uri.parse(url));
request.headers.set('content-type', 'application/json');
request.add(utf8.encode(json.encode(map)));
HttpClientResponse response = await request.close();
var responseBody = await response.transform(utf8.decoder).join();
Map jsonResponse = json.decode(responseBody);
print(jsonResponse);
if (response.statusCode == 200) {
if (jsonResponse['message'] ==
'200') { //if( jsonResponse['message'] == '200') {
setState(() {
_isLoading = false;
});
global.nameUser = jsonResponse['name'];
global.dataArea = jsonResponse['data_area'];
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => UserPage()),
);
}
else {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Error_Auth()),
);
}
}
else {
setState(() {
_isLoading = false;
});
}
}
Container buttonSection() {
return Container(
width: MediaQuery.of(context).size.width,
height: 40.0,
padding: EdgeInsets.symmetric(horizontal: 15.0),
margin: EdgeInsets.only(top: 15.0),
child: RaisedButton(
onPressed: emailController.text == "" || passwordController.text == "" ? null : () {
setState(() {
_isLoading = true;
});
signIn(emailController.text, passwordController.text);
},
elevation: 0.0,
color: Colors.purple,
child: Text("Авторизація", style: TextStyle(color: Colors.white70)),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
),
);
}
final TextEditingController emailController = new TextEditingController();
final TextEditingController passwordController = new TextEditingController();
Container textSection() {
return Container(
padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
child: Column(
children: <Widget>[
TextFormField(
controller: emailController,
cursorColor: Colors.white,
style: TextStyle(color: Colors.white70),
decoration: InputDecoration(
icon: Icon(Icons.login, color: Colors.white70),
hintText: "Логін",
border: UnderlineInputBorder(borderSide: BorderSide(color: Colors.white70)),
hintStyle: TextStyle(color: Colors.white70),
),
),
SizedBox(height: 30.0),
TextFormField(
controller: passwordController,
cursorColor: Colors.white,
obscureText: true,
style: TextStyle(color: Colors.white70),
decoration: InputDecoration(
icon: Icon(Icons.lock, color: Colors.white70),
hintText: "Пароль",
border: UnderlineInputBorder(borderSide: BorderSide(color: Colors.white70)),
hintStyle: TextStyle(color: Colors.white70),
),
),
],
),
);
}
Container headerSection() {
return Container(
alignment: Alignment.topCenter,
margin: EdgeInsets.only(top: 50.0),
child: Text("Пломби",
style: TextStyle(
color: Colors.white70,
fontSize: 40.0,
fontWeight: FontWeight.bold)),
);
}
}
class Error_Auth extends StatelessWidget {
#override
Widget build(BuildContext context) {
final AlertDialog dialog = AlertDialog(
title: Text('Помилка при авторизації'),
content:
Text('Повторити спробу авторизації'),
actions: [
FlatButton(
textColor: Color(0xFF6200EE),
onPressed: () => SystemNavigator.pop(),
child: Text('Ні'),
),
FlatButton(
textColor: Color(0xFF6200EE),
onPressed: () { Navigator.push(
context,MaterialPageRoute(builder: (context) => Login()),
);
},
child: Text('Так'),
),
],
);
return Scaffold(
body:dialog
);
}
}
class Storage {
Future<String> get localPath async {
final dir = await getApplicationDocumentsDirectory();
return dir.path;
}
Future<File> get localFile async {
final path = await localPath;
return File('$path/db.txt');
}
Future<String> readData() async {
try {
final file = await localFile;
String body = await file.readAsString();
return body;
} catch (e) {
return e.toString();
}
}
Future<File> writeData(String data) async {
final file = await localFile;
return file.writeAsString("$data");
}
}
In this part of the code I am automated and if the status code is 200, then I parse the Jason and add a name for the variable global.nameUser. And in the navigation menu I check if it is not zero then show all the icons of the navigation menu. But the first time it doesn't work. I have clicked on this menu again and only then it will work.
if (response.statusCode == 200) {
if (jsonResponse['message'] ==
'200') { //if( jsonResponse['message'] == '200') {
setState(() {
_isLoading = false;
});
global.nameUser = jsonResponse['name'];
global.dataArea = jsonResponse['data_area'];
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => UserPage()),
);
}
Check the navigation menu which icons to display!
items: <BottomNavigationBarItem>[
new BottomNavigationBarItem( icon: Icon(Icons.admin_panel_settings_outlined), title: Text(" Вхід"),backgroundColor: Colors.lightBlue),
new BottomNavigationBarItem(icon: Icon(Icons.settings), title: Text("Налаштування"),backgroundColor: Colors.lightBlue),
if( global.nameUser ?.isNotEmpty == true)...[
new BottomNavigationBarItem(icon: Icon(Icons.person_pin), title: Text("Користувач"),backgroundColor: Colors.lightBlue),
new BottomNavigationBarItem(icon: Icon(Icons.home), title: Text("Пломбування"),backgroundColor: Colors.lightBlue),
new BottomNavigationBarItem(icon: Icon(Icons.qr_code), title: Text("Пломби"),backgroundColor: Colors.lightBlue),
new BottomNavigationBarItem(icon: Icon(Icons.add_outlined), title: Text("Акт приймання"),backgroundColor: Colors.lightBlue),
]
],
Your page is not re built after logging in the user, that is why your nav bar is not updated. When you click on the button it refreshes and correctly displays the new elements.
Instead of using a global variable you could look into a state management package in order to make the logged-in user available throughout your app. (article for getx the simplest one out there)
If this is simply a prototype and you want some quick and dirty, I guess you could trigger a reload of your app once a user logs in by wrapping your app with a widget that exposes a rebuild method. (article)
EDIT: Example with Getx:
class UserController extends GetxController {
var nameUser = "".obs;
void setName(String str) => nameUser = str;
}
class Home extends StatelessWidget {
final UserController c = Get.put(UserController());
#override
Widget build(context)
...
Obx(() => /// You are watching your controller
...
items: <BottomNavigationBarItem>[
if( c.nameUser.isNotEmpty)...[
...
]
)))
...
class LoginPage extends StatelessWidget {
// You can ask Get to find a Controller that is being used by another page and redirect you to it.
final UserController c = Get.find();
#override
Widget build(context){
...
onPressed: () => c.setName(username);
}
}

How to show a text after onPressed function

I want to show a text after onPressed function happened, this function is a recording function and wants to show a text 'recording' when the function happening
voiceCreate.dart
import 'package:flutter/material.dart';
class VoiceCreate extends StatelessWidget {
final VoidCallback onPressed;
VoiceCreate({this.onPressed});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: onPressed),
),
),
);
}
}
**main.dart**
import 'dart:io';
import 'package:audioplayer/audioplayer.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:record_mp3/record_mp3.dart';
import 'package:permission_handler/permission_handler.dart';
import 'regitration.dart';
import 'voiceCreate.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String statusText = "";
bool isComplete = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) => Scaffold(
drawer: Drawer(
elevation: 2.0,
child: ListView(
children: <Widget>[
ListTile(
title: Text('Home'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return MyApp();
},
),
);
},
),
ListTile(
title: Text('Sign up'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
},
),
ListTile(
title: Text('Sign in'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
// add sign in page
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return VoiceCreate(onPressed: startRecord);
}),
);
},
// Add your onPressed code here!
child: Icon(Icons.add),
backgroundColor: Colors.tealAccent.shade700,
),
backgroundColor: Colors.grey.shade900,
appBar: AppBar(
title: Text('Myvo'),
centerTitle: true,
backgroundColor: Colors.tealAccent.shade700,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 40,
onPressed: () async {
startRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.pause),
color: Colors.white,
iconSize: 40,
onPressed: () async {
pauseRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.stop),
color: Colors.white,
iconSize: 40,
onPressed: () async {
stopRecord();
}),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Text(
statusText,
style: TextStyle(color: Colors.red, fontSize: 20),
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
play();
},
child: Container(
margin: EdgeInsets.only(top: 30),
alignment: AlignmentDirectional.center,
width: 100,
height: 50,
child: isComplete && recordFilePath != null
? Text(
"play",
style: TextStyle(color: Colors.red, fontSize: 20),
)
: Container(),
),
),
]),
),
),
);
}
Future<bool> checkPermission() async {
if (!await Permission.microphone.isGranted) {
PermissionStatus status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
return false;
}
}
return true;
}
void startRecord() async {
bool hasPermission = await checkPermission();
if (hasPermission) {
statusText = "Recording...";
recordFilePath = await getFilePath();
isComplete = false;
RecordMp3.instance.start(recordFilePath, (type) {
statusText = "Record error--->$type";
setState(() {});
});
} else {
statusText = "No microphone permission";
}
setState(() {});
}
void pauseRecord() {
if (RecordMp3.instance.status == RecordStatus.PAUSE) {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
} else {
bool s = RecordMp3.instance.pause();
if (s) {
statusText = "Recording pause...";
setState(() {});
}
}
}
void stopRecord() {
bool s = RecordMp3.instance.stop();
if (s) {
statusText = "Record complete";
isComplete = true;
setState(() {});
}
}
void resumeRecord() {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
}
String recordFilePath;
void play() {
if (recordFilePath != null && File(recordFilePath).existsSync()) {
AudioPlayer audioPlayer = AudioPlayer();
audioPlayer.play(recordFilePath, isLocal: true);
}
}
int i = 0;
Future<String> getFilePath() async {
Directory storageDirectory = await getApplicationDocumentsDirectory();
String sdPath = storageDirectory.path + "/record";
var d = Directory(sdPath);
if (!d.existsSync()) {
d.createSync(recursive: true);
}
return sdPath + "/test_${i++}.mp3";
}
}
VoiceCreate function will happen on a new page when clicking on the Floating button in main.dart and recording will happen when click on mic Icon, want show the text 'recording' whine the fuction happening.
First of all, you need to have StatefulWidget to manage changes in state, then you can use two functions startRecording and stopRecording to toggle the isRecording variable. Then based on the value of isRecording you can make changes in the view, e.g., displaying a text. For displaying the text you can use a Visibility widget and set its visible parameter to isRecording.
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _isRecording = false;
_startRecording() {
this.setState(() {
_isRecording = true;
});
}
_stopRecording() {
this.setState(() {
_isRecording = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: () => _startRecording(),
),
IconButton(
icon: Icon(Icons.stop),
color: Colors.white,
iconSize: 70,
onPressed: () => _stopRecording(),
),
Visibility(
visible: _isRecording,
child: Text(
'recording',
style: TextStyle(
color: Colors.red
),
),
)
],
),
),
),
);
}
}
Maybe a snackbar could be useful here, something like:
class VoiceCreate extends StatefulWidget {
VoiceCreate({Key key, this.title}) : super(key: key);
final String title;
#override
_VoiceCreateState createState() => _VoiceCreateState();
}
class _VoiceCreateState extends State<VoiceCreate> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
var isRecording = false;
void showRecordingMessage(String message, [Color color = Colors.red]) {
_scaffoldKey.currentState.showSnackBar(
new SnackBar(backgroundColor: color, content: new Text(message)));
}
void setRecordingState() {
this.setState(() {
isRecording = true;
});
print("isRecording is set to $isRecording");
showRecordingMessage('Recording now!');
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.blueGrey,
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: () {
setRecordingState();
},
),
],
),
),
);
}
}