Related
I'm sorry if my question was ambiguous.
I'll slowly explain what I want.
I declared the variables to be used in the app using the provider. This is the code I wrote.
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class CountPage extends ChangeNotifier {
int _page = 150;
int get page => _page;
bool _visible = false;
bool get visible => _visible;
double _font = 40;
double get font => _font;
TextAlign align = TextAlign.center;
Color selection = Colors.red[200]!;
change_align_left(){
align = TextAlign.left;
notifyListeners();
}
change_align_center(){
align = TextAlign.center;
notifyListeners();
}
change_align_right(){
align = TextAlign.right;
notifyListeners();
}
change_color_1() {
selection = Colors.green[200]!;
notifyListeners();
}
change_color_2() {
selection = Colors.blue[200]!;
notifyListeners();
}
change_color_3() {
selection = Colors.deepOrange[200]!;
notifyListeners();
}
change_color_4() {
selection = Colors.pink[200]!;
notifyListeners();
}
change_color_5() {
selection = Colors.red[200]!;
notifyListeners();
}
change_color_6() {
selection = Colors.brown[200]!;
notifyListeners();
}
change_color_7() {
selection = Colors.deepPurple[200]!;
notifyListeners();
}
change_font_1() async {
_font = 30;
notifyListeners();
}
change_font_2() async {
_font = 35;
notifyListeners();
}
change_font_3() async {
_font = 40;
notifyListeners();
}
copy_on() {
_visible = !_visible;
notifyListeners();
}
page_down() {
if (_page == 0) {
_page = 0;
notifyListeners();
} else {
_page--;
notifyListeners();
}
}
page_up() {
if (_page == 152) {
_page = 152;
notifyListeners();
} else {
_page++;
notifyListeners();
}
}
}
And then I created a button for the user to choose background color, text size, and text alignment, which is part of the code I created.
class _Option_pageState extends State<Option_page> {
#override
Widget build(BuildContext context) {
void initState() {
super.initState();
}
final countPage = Provider.of<CountPage>(context);
CountPage _countPage = Provider.of<CountPage>(context, listen: true);
return Scaffold(
appBar: AppBar(
backgroundColor: countPage.selection,
centerTitle: true,
title: Text("설정"),
),
body: Center(
child: Container(
child: Column(children: [
Text(
"글자 크기 ",
style: TextStyle(
fontSize: countPage.font,
),
),
Container(
height: 50,
child: Row(
children: [
Container(child: Text('글자크기')),
Container(
width: 300,
color: Colors.green[200],
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButton(
onPressed: () {
_countPage.change_font_1();
},
icon: Icon(Icons.looks_one_outlined)),
IconButton(
onPressed: () {
_countPage.change_font_2();
},
icon: Icon(Icons.looks_two_outlined)),
IconButton(
onPressed: () {
_countPage.change_font_3();
},
icon: Icon(Icons.looks_3_outlined)),
],
),
)
],
),
),
Container(
color: _countPage.selection,
height: 50,
child: Row(
children: [
TextButton(onPressed:()
{
Navigator.push(context, MaterialPageRoute(builder: (context) => const Color_choic()));
},
child: Text("색깔변경 "),
style: TextButton.styleFrom(primary: Colors.white),
),
],
),
),
Container(
color: Colors.white,
height: 50,
child: Row(
children: [
Text('글자정렬'),
Container(
width: 300,
color: Colors.lightGreen,
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButton(
onPressed: () {countPage.change_align_left();},
icon: Icon(Icons.format_align_left)),
IconButton(
onPressed: () {countPage.change_align_center();},
icon: Icon(Icons.format_align_center)),
IconButton(
onPressed: () {countPage.change_align_right();},
icon: Icon(Icons.format_align_right)),
],
),
),
),
],
),
),
]),
),
),
);;
}
}
This code changes the font size, background color, and text alignment while the app is running, but when you run the app again, it returns to the first value.
I want to change the size, color, and alignment values when I press the button, and I want the changed values to remain changed even when I run the app again.
I looked up a function called Shared Preference, but I don't know how to apply it to my code.
I'd appreciate it if you could suggest a way to solve my problem.
Don't hesitate to comment on my questioning method or code.
Yes, shared preferences can be a right approach: add the shared_preferences library to pubspec.yaml.
SharedPreferences needs an instance across and a string key to store the value in device storage:
Adding static late SharedPreferences _prefs; to your ChangeNotifier
Adding the instance to the initializer:
static Future init() async {
_prefs = await SharedPreferences.getInstance();
}
So then your getters and setters would be something like this:
double _font = 40; //variable
double get font {
return _prefs.getDouble("prefsFont") ?? _font; //return value of variable when there's nothing on preferences
}
set font(double font) {
_font = font;
_prefs.setDouble("prefsFont", _font); //saving variable to preferences when setting a value
}
If you want to "reset" values you just need to remove it from preferences:
void resetFont {
_prefs.remove("prefsFont");
}
And if you want to remove all preferences:
static void clearAll() async {
_prefs.clear();
}
Full class should look something like this: ( I haven't tested it)
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class CountPage extends ChangeNotifier {
static late SharedPreferences _prefs;
static const String prefsFont = "prefs_font";
static const String prefsPage = "prefs_page";
static const String prefsVisible = "prefs_visible";
static const String prefsColor = "prefs_color";
static const String prefsAlign = "prefs_align";
int _page = 150;
int get page {
return _prefs.getInt(prefsPage) ?? _page;
}
set page(int page) {
_page = page;
_prefs.setInt(prefsPage, _page);
}
bool _visible = false;
bool get visible {
return _prefs.getBool(prefsFont) ?? _visible;
}
set visible(bool visible) {
_visible = visible;
_prefs.setBool(prefsFont, _visible);
}
double _font = 40;
double get font {
return _prefs.getDouble(prefsFont) ?? _font;
}
set font(double font) {
_font = font;
_prefs.setDouble(prefsFont, _font);
}
TextAlign _align = TextAlign.center;
TextAlign get align {
final alignValue = _prefs.getInt(prefsAlign) ?? _align.index;
switch (alignValue) {
case 0:
return TextAlign.left;
case 1:
return TextAlign.center;
case 2:
return TextAlign.right;
default:
return TextAlign.center;
}
}
set align(TextAlign align) {
_align = align;
_prefs.setInt(prefsAlign, _align.index);
}
Color _selection = Colors.red[200]!;
Color get selection {
Color color = Color(_prefs.getInt(prefsColor) ?? _selection.value);
return color;
}
set selection(Color selection) {
_selection = selection;
_prefs.setInt(prefsColor, _selection.value);
}
static Future init() async {
_prefs = await SharedPreferences.getInstance();
}
change_align_left() {
align = TextAlign.left;
notifyListeners();
}
change_align_center() {
align = TextAlign.center;
notifyListeners();
}
change_align_right() {
align = TextAlign.right;
notifyListeners();
}
change_color_1() {
selection = Colors.green[200]!;
notifyListeners();
}
change_color_2() {
selection = Colors.blue[200]!;
notifyListeners();
}
change_color_3() {
selection = Colors.deepOrange[200]!;
notifyListeners();
}
change_color_4() {
selection = Colors.pink[200]!;
notifyListeners();
}
change_color_5() {
selection = Colors.red[200]!;
notifyListeners();
}
change_color_6() {
selection = Colors.brown[200]!;
notifyListeners();
}
change_color_7() {
selection = Colors.deepPurple[200]!;
notifyListeners();
}
change_font_1() async {
_font = 30;
notifyListeners();
}
change_font_2() async {
_font = 35;
notifyListeners();
}
change_font_3() async {
_font = 40;
notifyListeners();
}
copy_on() {
_visible = !_visible;
notifyListeners();
}
page_down() {
if (_page == 0) {
_page = 0;
notifyListeners();
} else {
_page--;
notifyListeners();
}
}
page_up() {
if (_page == 152) {
_page = 152;
notifyListeners();
} else {
_page++;
notifyListeners();
}
}
}
I tried to do give a command to the flutter application using voice commands and in the application there was a text to voice function. so when i tried to give read command using voice there was a repeat on that function. how to avoid the repeat.
I have tried to terminate the Listening function after getting one input but it dosen't work.
Tried to terminate the Listening function.
but same error
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:newsapp/screens/News_Screen.dart';
import 'package:newsapp/utils/app_colors.dart';
import 'package:newsapp/utils/assets_constants.dart';
import 'package:webfeed/webfeed.dart';
import 'package:flutter_tts/flutter_tts.dart';
import 'package:url_launcher/url_launcher.dart';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter_speech/flutter_speech.dart';
const languages = const [
// const Language('Francais', 'fr_FR'),
const Language('English', 'en_US'),
const Language('Pусский', 'ru_RU'),
const Language('Italiano', 'it_IT'),
const Language('Español', 'es_ES'),
];
class Language {
final String name;
final String code;
const Language(this.name, this.code);
}
class BBCNews extends StatefulWidget {
#override
_BBCNewsState createState() => _BBCNewsState();
}
class _BBCNewsState extends State<BBCNews> {
late SpeechRecognition _speech;
FlutterTts flutterTts = FlutterTts();
bool _speechRecognitionAvailable = false;
bool _isListening = false;
String transcription = '';
String _currentLocale = 'en_US';
//Language selectedLang = languages.first;
#override
initState() {
super.initState();
activateSpeechRecognizer();
}
void activateSpeechRecognizer() {
//print('_MyAppState.activateSpeechRecognizer... ');
_speech = SpeechRecognition();
_speech.setAvailabilityHandler(onSpeechAvailability);
_speech.setRecognitionStartedHandler(onRecognitionStarted);
_speech.setRecognitionResultHandler(onRecognitionResult);
_speech.setRecognitionCompleteHandler(onRecognitionComplete);
_speech.setErrorHandler(errorHandler);
_speech.activate('en_US').then((res) {
setState(() => _speechRecognitionAvailable = res);
});
}
var client = http.Client();
Future myDevBlog() async {
var response = await client
.get(Uri.parse('http://feeds.bbci.co.uk/news/world/rss.xml'));
var channel = RssFeed.parse(response.body);
final item = channel.items;
return item;
}
Future<void> openFeed(String url) async {
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: true,
forceWebView: false,
);
return;
}
}
rightIcon() {
return const Icon(
Icons.keyboard_arrow_right,
color: Colors.grey,
size: 30,
);
}
#override
Widget build(BuildContext context) {
var currentIndex;
return Scaffold(
appBar: AppBar(
backgroundColor: AppColors.primaryColor,
//title: const Text('VoiceNews'),
title: Image.asset(
AssetConstants.iconPath,
width: 150,
),
elevation: 10.0,
actions: [
IconButton(
onPressed: _speechRecognitionAvailable && !_isListening
? () => start()
: null,
icon: const Icon(Icons.play_arrow_rounded)),
IconButton(
onPressed: _isListening ? () => stop() : null,
icon: const Icon(Icons.stop_circle))
],
),
body: StreamBuilder(
stream: myDevBlog().asStream(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, int index) {
if (transcription.toLowerCase() == "play") {
// _isListening = false;
//stop();
print(transcription);
speak(snapshot.data[1].title);
var currentIndex = 0;
} else if (transcription.toLowerCase() == "next") {
// _isListening = false;
speak(snapshot.data[2].title);
print(transcription);
} else if (transcription.toLowerCase() == "all") {
// _isListening = false;
errorHandler();
//speak("Wrong Input");
//cancel();
}
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: ListTile(
title: Text(snapshot.data[index].title),
subtitle:
Text(snapshot.data[index].description),
//onTap: () =>
speak(snapshot.data[index].title),
// onTap: () =>
openFeed(snapshot.data[index].link),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
newsScreen(snapshot.data[index].link),
// Pass the arguments as part of the
RouteSettings. The
// DetailScreen reads the arguments
from these settings.
// settings: RouteSettings(
// arguments: todos[index],
// ),
),
);
print(snapshot.data[index].link);
},
onLongPress: () =>
speak(snapshot.data[index].description),
leading: Text((1 + index).toString()),
trailing: rightIcon(),
),
),
);
},
);
} else if (snapshot.hasError ||
snapshot.connectionState == ConnectionState.none) {
return Center(
child: Text(snapshot.error.toString()),
);
}
return const Center(
child: CircularProgressIndicator(),
);
},
),
);
}
// List<CheckedPopupMenuItem<Language>> get
_buildLanguagesWidgets => languages
void start() => _speech.activate(_currentLocale).then((_) {
return _speech.listen().then((result) {
print('_MyAppState.start => result $result');
setState(() {
_isListening = result;
});
});
});
void cancel() =>
_speech.cancel().then((_) => setState(() => _isListening =
false));
void stop() => _speech.stop().then((_) {
setState(() => _isListening = false);
});
void onSpeechAvailability(bool result) =>
setState(() => _speechRecognitionAvailable = result);
// void onCurrentLocale(String locale) {
// // print('_MyAppState.onCurrentLocale... $locale');
// setState(
// () => _currentLocale = languages.firstWhere((l) =>
l.code == locale));
// }
void onRecognitionStarted() {
setState(() => _isListening = true);
}
void onRecognitionResult(String text) {
// print('_MyAppState.onRecognitionResult... $text');
setState(() => transcription = text);
}
void onRecognitionComplete(String text) {
//print('_MyAppState.onRecognitionComplete... $text');
setState(() => _isListening = false);
}
void errorHandler() => activateSpeechRecognizer();
void speak(String text) async {
await flutterTts.speak(text);
await flutterTts.setLanguage("en-US");
await flutterTts.setPitch(1);
await flutterTts.setSpeechRate(0.6);
}
}
I'm building a simple flutter app, which needs to takes pictures. For that i'm using ImagePicker.
When built into an APK, an error is returned when _getImage is called:
"Pick image error.PlatformException(error,null,null)[...]"
When executed through flutter run on the same device, it works as expected.
Relevant part of the code:
class _BodyState extends State<Body> {
final ImagePicker _picker = ImagePicker();
XFile? _imageFile;
dynamic _pickImageError;
String? _retrieveDataError;
void _getImage(ImageSource source) async {
try {
final pickedFile = await _picker.pickImage(
source: source,
maxWidth: 720,
maxHeight: 1280,
imageQuality: 80,
// preferredCameraDevice: CameraDevice.rear,
);
setState(() {
_imageFile = pickedFile;
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
}
Widget _previewImages() {
final Text? retrieveError = _getRetrieveErrorWidget();
Size size = MediaQuery.of(context).size;
if (retrieveError != null) {
return retrieveError;
}
if (_imageFile != null) {
return CircleAvatar(
backgroundColor: Colors.transparent,
radius: 150,
backgroundImage: FileImage(File(_imageFile!.path)),
);
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return CircleAvatar(
backgroundColor: Colors.transparent,
radius: 150,
child: Image.asset(
"assets/images/user.png",
width: size.width,
),
);
}
}
Text? _getRetrieveErrorWidget() {
if (_retrieveDataError != null) {
final Text result = Text(_retrieveDataError!);
_retrieveDataError = null;
return result;
}
return null;
}
Future<void> retrieveLostData() async {
final LostDataResponse response = await _picker.retrieveLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
setState(() {
_imageFile = response.file;
});
} else {
_retrieveDataError = response.exception!.code;
}
}
#override
Widget build(BuildContext context) {
return Background(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: FutureBuilder<void>(
future: retrieveLostData(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
case ConnectionState.done:
return _previewImages();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
},
)
//: _previewImages(),
),
Error log (couldn't copy it)
How it should look like
I want to search for a short sentence inside a long sentence ...
it is working fine with this demo:
String a = 'from first day i was very good';
String b = 'from first day';
print(a.contains(b));
result : true
but when I use TextField to enter a short sentence and check it if is exciting in a long sentence ...
TextField when I enter space between words doesn't show any result
Note: this app in the Arabic language and doesn't work on an android and IOS ... in English worked well in the IOS simulator but doesn't work on an android phone.
my all code:
import 'dart:convert';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:egyptian_ads_app/constant/constant.dart';
import 'package:egyptian_ads_app/pages/business_man_pages/business_man_page.dart';
import 'package:egyptian_ads_app/pages/starting_page/landing_service_page.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:share/share.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
class ItemModel {
ItemModel(
{this.id,
this.title,
this.imagePath,
this.about,
this.phoneNumber,
this.traderId,
this.type,
this.city});
int id;
String title;
String imagePath;
String about;
String phoneNumber;
int traderId;
String type;
String city;
factory ItemModel.fromJson(Map<String, dynamic> json) {
return new ItemModel(
id: json['id'],
title: json['name'],
imagePath: json["logo"]['url'],
about: json['about'],
phoneNumber: json['phone_number'],
traderId: json['trader_id'],
type: json['category']['type'],
// city: json['city'],
);
}
}
class InstantSearchPage extends StatefulWidget {
#override
_InstantSearchPageState createState() => _InstantSearchPageState();
}
class _InstantSearchPageState extends State<InstantSearchPage> {
TextEditingController _searchController = TextEditingController();
Future resultsLoaded;
List<ItemModel> _allResults = [];
List<ItemModel> _resultsList = [];
#override
void initState() {
super.initState();
_searchController.addListener(_onSearchChanged);
}
#override
void dispose() {
_searchController.removeListener(_onSearchChanged);
_searchController.dispose();
super.dispose();
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
resultsLoaded = getUserDetails();
}
getUserDetails() async {
final String url = 'https://yallservice.com/api/v1/departments';
final response = await http.get(url);
final responseJson = json.decode(response.body);
var data = responseJson['data'];
setState(() {
for (Map user in data) {
_allResults.add(ItemModel.fromJson(user));
}
});
searchResultsList();
return "complete";
}
_onSearchChanged() {
searchResultsList();
}
searchResultsList() {
List<ItemModel> showResults = [];
if (_searchController.text != "") {
for (var tripSnapshot in _allResults) {
String title = tripSnapshot.about;
print(title + title);
if (title.contains(_searchController.text)) {
showResults.add(tripSnapshot);
}
}
} else {
showResults = List.from(_allResults);
}
setState(() {
_resultsList = showResults;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: BackButton(),
title: Container(
color: Colors.white,
child: TextField(
controller: _searchController,
decoration: InputDecoration(prefixIcon: Icon(Icons.search)),
),
),
),
body: Container(
color: Colors.grey.shade300,
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: _resultsList.length,
itemBuilder: (BuildContext context, int index) {
return Container(
color: Colors.white,
child: ListTile(
subtitle: Text(_resultsList[index].about),
));
// return Card(
// index: index,
// data: _resultsList,
// );
},
)),
],
),
),
);
}
}
This is due to the encoding of white spaces in RTL strings.
Try to trim the TextField text before you search for it.
Special trim method
String trim(String string) {
assert(string != null);
final stringList = string.characters.toList();
final whitespaces = ['8206', '8207', '32'];
while (whitespaces.contains(stringList.last.runes.join()))
stringList.removeLast();
while (whitespaces.contains(stringList.first.runes.join()))
stringList.remove(stringList.first);
return stringList.join();
}
Updated searchResultsList
searchResultsList() {
List<ItemModel> showResults = [];
if (_searchController.text != "") {
for (var tripSnapshot in _allResults) {
String title = tripSnapshot.about;
if (title.contains(trim(_searchController.text))) {
showResults.add(tripSnapshot);
}
}
} else {
showResults = List.from(_allResults);
}
setState(() {
_resultsList = showResults;
});
}
Ref: Text fields' values do not get trimmed correctly when textDirection: TextDirection.rtl #68093
Improvement
Your search is currently case-sensitive. Maybe you should make it case-insensitive?
searchResultsList() {
setState(() {
_resultsList = _searchController.text.isNotEmpty
? _allResults
.where((tripSnapshot) => tripSnapshot.about
.toLowerCase()
.contains(trim(_searchController.text).toLowerCase()))
.toList()
: List.from(_allResults);
});
}
I fixed the problem just by putting textDirection: TextDirection.rtl, to my TextField
I'm trying to read file from a known path get base64 string from the image. I still don't understand why base64 is broken. This happens only in flutter code.
I did try doing the same conversion using a simple dart program i got the desired base64 string. This issue is happening in flutter.
onPressed: () async {
File imageFile =
await ImagePicker.pickImage(source: ImageSource.camera);
if (imageFile != null) {
Uint8List bytes = await imageFile.readAsBytes();
String base64data = base64.encode(bytes);
print(base64data);
}
}
Following is my console output.
W/ExifInterface(15331): Skip the tag entry since tag number is not defined: 2
W/ExifInterface(15331): Stop reading file since a wrong offset may cause an infinite loop: 0
I/chatty (15331): uid=10271(com.crowdanalytix.datax_app) Binder:15331_5 identical 2 lines
W/ExifInterface(15331): Stop reading file since a wrong offset may cause an infinite loop: 0
I/flutter (15331): /9j/4QGLRXhpZgAATU0AKgAAAAgACAEAAAQAAAABAAAKMgEQAAIAAAAOAAAAbgEBAAQAAAABAAASIAEPAAIAAAAIAAAAfIdpAAQAAAABAAAAmAESAAMAAAABAAAAAAEyAAIAAAAUAAAAhIglAAQAAAABAAABCgAAAABPTkVQTFVTIEEzMDAzAE9uZVBsdXMAMjAxOTowOTowMiAxOTo0MDo1MgAAB6QDAAMAAAABAAAAAIgnAAMAAAABD6AAAJIKAAUAAAABAAAA8oKaAAUAAAABAAAA+pIJAAMAAAABABAAAJIIAAQAAAABAAAAAIKdAAUAAAABAAABAgAAAAAAAAGqAAAAZAAAAkwAACcQAABOIAAAJxAAAQAFAAEAAAAHAAABHAAAAAAyMDAvMTAwAAQBEAACAAAADgAAAVkBDwACAAAACAAAAWcBEgADAAAAAQAAAAABMgACAAAAFAAAAW8AAAAAT05FUExVUyBBMzAwMwBPbmVQbHVzADIwMTk6MDk6MDIgMTk6NDA6NTIA/+AAEEpGSUYAAQEAAAEAAQAA/9sAQwABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/9sAQwEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/8AAEQgSIAoyAwEiAAIRAQMRAf/EAB8AAAIDAQEBAQEBAQAAAAAAAAQFAwYHAggAAQkKC//EAF0QAAEBBAYHCAIBAwMDAQECHwIBAAMREgQhIjFBUQUyYXGBkfAGE0KhscHR4VLxIwcUYjNDchVTgghjkhYkc4OiNJOjF0RUstIlZISzwsPilMTTGHSkNVW01PP0/8QAHAEAAwEBAQEBAQAAAAAAAAAAAgMEAAEFBgcI/8QAQhEAAAQDBgUFAQEAAQQBAgENAAECEQMhMRJBUWFx8IG
Base64 string which i'm getting is invalid. Can someone try this?
I'm using a OnePlus3t (ONEPLUS A3003).
print function did not print everything.
you can see full result with debug mode
code snippet
List<int> imageBytes = await _imageFile.readAsBytes();
String base64Image = base64Encode(imageBytes);
print(base64Image);
Copy base64 string from debug mode and paste to online converter, you can see result is correct.
full code from offical demo and add base64 convert
// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:video_player/video_player.dart';
import 'dart:typed_data';
import 'package:image/image.dart' as ImageProcess;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Picker Demo',
home: MyHomePage(title: 'Image Picker Example'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File _imageFile;
dynamic _pickImageError;
bool isVideo = false;
VideoPlayerController _controller;
String _retrieveDataError;
Future<void> _playVideo(File file) async {
if (file != null && mounted) {
await _disposeVideoController();
_controller = VideoPlayerController.file(file);
await _controller.setVolume(1.0);
await _controller.initialize();
await _controller.setLooping(true);
await _controller.play();
setState(() {});
}
}
void _onImageButtonPressed(ImageSource source) async {
if (_controller != null) {
await _controller.setVolume(0.0);
}
if (isVideo) {
final File file = await ImagePicker.pickVideo(source: source);
await _playVideo(file);
} else {
try {
_imageFile = await ImagePicker.pickImage(source: source);
List<int> imageBytes = await _imageFile.readAsBytes();
String base64Image = base64Encode(imageBytes);
print(base64Image);
setState(() {});
} catch (e) {
_pickImageError = e;
}
}
}
#override
void deactivate() {
if (_controller != null) {
_controller.setVolume(0.0);
_controller.pause();
}
super.deactivate();
}
#override
void dispose() {
_disposeVideoController();
super.dispose();
}
Future<void> _disposeVideoController() async {
if (_controller != null) {
await _controller.dispose();
_controller = null;
}
}
Widget _previewVideo() {
final Text retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_controller == null) {
return const Text(
'You have not yet picked a video',
textAlign: TextAlign.center,
);
}
return Padding(
padding: const EdgeInsets.all(10.0),
child: AspectRatioVideo(_controller),
);
}
Widget _previewImage() {
final Text retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_imageFile != null) {
return Image.file(_imageFile);
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
Future<void> retrieveLostData() async {
final LostDataResponse response = await ImagePicker.retrieveLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
if (response.type == RetrieveType.video) {
isVideo = true;
await _playVideo(response.file);
} else {
isVideo = false;
setState(() {
_imageFile = response.file;
});
}
} else {
_retrieveDataError = response.exception.code;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Platform.isAndroid
? FutureBuilder<void>(
future: retrieveLostData(),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
case ConnectionState.done:
return isVideo ? _previewVideo() : _previewImage();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
},
)
: (isVideo ? _previewVideo() : _previewImage()),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(ImageSource.gallery);
},
heroTag: 'image0',
tooltip: 'Pick Image from gallery',
child: const Icon(Icons.photo_library),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(ImageSource.camera);
},
heroTag: 'image1',
tooltip: 'Take a Photo',
child: const Icon(Icons.camera_alt),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
isVideo = true;
_onImageButtonPressed(ImageSource.gallery);
},
heroTag: 'video0',
tooltip: 'Pick Video from gallery',
child: const Icon(Icons.video_library),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
isVideo = true;
_onImageButtonPressed(ImageSource.camera);
},
heroTag: 'video1',
tooltip: 'Take a Video',
child: const Icon(Icons.videocam),
),
),
],
),
);
}
Text _getRetrieveErrorWidget() {
if (_retrieveDataError != null) {
final Text result = Text(_retrieveDataError);
_retrieveDataError = null;
return result;
}
return null;
}
}
class AspectRatioVideo extends StatefulWidget {
AspectRatioVideo(this.controller);
final VideoPlayerController controller;
#override
AspectRatioVideoState createState() => AspectRatioVideoState();
}
class AspectRatioVideoState extends State<AspectRatioVideo> {
VideoPlayerController get controller => widget.controller;
bool initialized = false;
void _onVideoControllerUpdate() {
if (!mounted) {
return;
}
if (initialized != controller.value.initialized) {
initialized = controller.value.initialized;
setState(() {});
}
}
#override
void initState() {
super.initState();
controller.addListener(_onVideoControllerUpdate);
}
#override
void dispose() {
controller.removeListener(_onVideoControllerUpdate);
super.dispose();
}
#override
Widget build(BuildContext context) {
if (initialized) {
return Center(
child: AspectRatio(
aspectRatio: controller.value?.aspectRatio,
child: VideoPlayer(controller),
),
);
} else {
return Container();
}
}
}