I'm using the package image_picker on a flutter app to load a picture, and it works fine in the web when accessed by an Windows, MacOs, Android, but in the iOS (16.3) the pop up to choose the image won't show up.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import "package:image/image.dart" as img;
class ProgramScreen extends StatefulWidget {
#override
_ProgramScreenState createState() => _ProgramScreenState();
}
class _ProgramScreenState extends State<ProgramScreen> {
TextEditingController _destinationController = TextEditingController();
TextEditingController _subjectController = TextEditingController();
late Uint8List _clipboardImage;
bool hasImage = false;
bool hasText = false;
double heightImg = 1;
double widthImg = 1;
Future _getImageFromPicker() async {
final ImagePicker _picker = ImagePicker();
final XFile? image = await _picker.pickImage(
source: ImageSource.gallery, requestFullMetadata: false);
var bytes = await image!.readAsBytes();
var photoData = img.decodeImage(bytes);
heightImg = photoData!.height * 0.5;
widthImg = photoData.width * 0.5;
setState(() {
hasImage = true;
hasText = false;
_clipboardImage = bytes;
});
}
#override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).colorScheme.primaryContainer,
padding: EdgeInsets.all(16),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
color: Colors.white,
),
padding: EdgeInsets.all(16),
child: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(hintText: 'Destinatáio'),
controller: _destinationController,
),
TextField(
decoration: InputDecoration(hintText: 'Assunto'),
controller: _subjectController,
),
],
),
),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
ElevatedButton(
onPressed: () async {},
child: Text('Enviar Grupo'),
),
ElevatedButton(
onPressed: () async {},
child: Text('Enviar Todos'),
),
],
),
SizedBox(height: 100),
hasText
? Text(
"O conteúdo copiado não é uma imagem!",
style: TextStyle(
color: Colors.red, fontWeight: FontWeight.bold),
)
: SizedBox(height: 1),
!hasImage
? Column(children: [
ElevatedButton(
onPressed: () async {},
child: Text('Verificar área de transferência'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () async {
_getImageFromPicker(); // Here is the function call
},
child: Text('Escolher da galeria'),
),
])
: Column(
children: [
Container(
height: heightImg.toDouble(),
width: widthImg.toDouble(),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)),
image: DecorationImage(
image: MemoryImage(_clipboardImage),
fit: BoxFit.fill,
),
),
),
SizedBox(height: 20),
Column(children: [
ElevatedButton(
onPressed: () async {},
child: Text('Verificar área de transferência'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () async {
_getImageFromPicker(); // Here is the function call
},
child: Text('Escolher da galeria'),
),
])
],
),
],
),
),
);
}
}
here is my flutter doctor
[✓] Flutter (Channel stable, 3.3.10, on macOS 13.2 22D49 darwin-arm, locale pt-BR)
[!] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
✗ cmdline-tools component is missing
Run `path/to/sdkmanager --install "cmdline-tools;latest"`
See https://developer.android.com/studio/command-line for more details.
✗ Android license status unknown.
Run `flutter doctor --android-licenses` to accept the SDK licenses.
See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.
[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2021.2)
[✓] VS Code (version 1.74.3)
[✓] Connected device (3 available)
[✓] HTTP Host Availability
the pop up supposed to apper
I tried to use older versions of the packages, but still have the same issue. Also, setting the "NSPhotoLibraryUsageDescription" has no effect
Can't tell the reason why, but changing
onPressed: () async {
_getImageFromPicker(); // Here is the function call
}
to
onPressed: () { // removed the async modifier
_getImageFromPicker(); // Here is the function call
}
Solves the problem! Now the pop up shows up as expected
Related
I'm new to flutter and graphql
I'm trying to develop an app to consume backend api hosted on heroku
during development and while testing the app on my Samsung Note 5, the app connects successfully to the backend and I can fetch data from query and mutation
but after building the app-release.apk and installing it on the same mobile, the response is always null in both the query and mutation.
Also, I have REST api within the backend and I use Dio lib to send requests but I don't get any response from these requests.
I tried "flutter clean" but in vain
flutter doctor command shows no error:
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.0.3, on Microsoft Windows [Version 10.0.18363.1646], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[√] Chrome - develop for the web
[√] Android Studio
[√] VS Code (version 1.54.3)
[√] Connected device (2 available)
• No issues found!
I'm using android studio 4.2.2
main.dart
bool isAuth;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await initHiveForFlutter();
isAuth = await isAuthenticated();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GraphQLProvider(
client: client,
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter App',
theme: ThemeData(
primarySwatch: Colors.red,
),
initialRoute: isAuth ? 'HomeScreen' : 'LoginScreen',
routes: {
'HomeScreen': (context) => HomeScreen(),
'LoginScreen': (context) => LoginScreen()
}),
);
}
}
authentication.dart
// check if token is set using sharedPreferences lib
Future<bool> isAuthenticated() async {
final accessToken = await getAccessToken();
if (accessToken != null) {
return true;
}
return false;
}
GraphQLConfiguration.dart:
class GraphQLConfiguration {
HttpLink _httpLink;
AuthLink _authLink;
Link _link;
GraphQLConfiguration () {
_httpLink = new HttpLink('https://backendapi.herokuapp.com/graphql');
_authLink = new AuthLink(getToken: () async => 'Bearer ${await getAccessToken()}');
_link = _authLink.concat(_httpLink);
}
GraphQLClient myGQLClient() {
return GraphQLClient(
link: _link,
cache: GraphQLCache(store: HiveStore()),
);
}
}
ValueNotifier<GraphQLClient> client = ValueNotifier(GraphQLConfiguration().myGQLClient());
mutations.dart
String login() {
return '''
mutation login(\$data: LoginInput!){
login(data: \$data){
status
message
accessToken
}
}
''';
}
LoginScreen.dart
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
bool _hidePassword = true;
final TextEditingController _usernameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
children: [
Mutation(
options: MutationOptions(
document: gql(mutations.login()),
update: (GraphQLDataProxy cache, QueryResult result) {
String cookie;
final String cookieHeader = result.context
.entry<HttpLinkResponseContext>()
.headers['set-cookie'];
if (cookieHeader != null) {
cookie = cookieHeader.split(';')[0];
}
final LoginResponse loginResponse =
LoginResponse.from(result.data['login']);
if (loginResponse.status == true && cookie != null) {
setRefreshToken(cookie);
}
return cache;
},
onCompleted: (resultData) async {
final LoginResponse loginResponse =
LoginResponse.from(resultData['login']);
if (loginResponse.status == true) {
await setAccessToken(loginResponse.accessToken);
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => HomeScreen()));
}
Fluttertoast.showToast(
msg: loginResponse.message,
backgroundColor: Colors.grey,
gravity: ToastGravity.BOTTOM,
fontSize: 16.0,
timeInSecForIosWeb: 1,
textColor: Colors.white,
toastLength: Toast.LENGTH_LONG,
);
}),
builder: (RunMutation runMutation, QueryResult result) {
return Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
margin: EdgeInsets.only(top: 100),
child: Column(
children: [
Text(
'Welcome...',
style: TextStyle(
shadows: [
Shadow(
offset: Offset(0.5, 0.5),
blurRadius: 10.0,
color: Colors.grey,
),
],
fontSize: 45,
letterSpacing: 2,
fontWeight: FontWeight.bold,
),
),
Text(
'welcome,,,',
style: TextStyle(
fontSize: 20,
letterSpacing: 7,
),
)
],
),
),
Container(
child: Column(
children: [
Padding(
padding:
EdgeInsets.symmetric(vertical: 0, horizontal: 20),
child: TextField(
controller: _usernameController,
style: TextStyle(
fontSize: 22.0,
),
decoration: InputDecoration(
labelText: 'Username',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(50.5),
),
prefixIcon:
Icon(Icons.supervised_user_circle_outlined),
),
),
),
Padding(
padding: EdgeInsets.symmetric(
vertical: 10, horizontal: 20),
child: TextField(
controller: _passwordController,
obscureText: _hidePassword,
style: TextStyle(
fontSize: 22.0,
),
decoration: InputDecoration(
labelText: 'Password',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(50.5),
),
prefixIcon: Icon(Icons.lock),
suffixIcon: IconButton(
icon: Icon(_hidePassword
? Icons.visibility
: Icons.visibility_off),
onPressed: () => _togglePasswordVisibility(),
),
),
),
),
Padding(
padding: EdgeInsets.only(top: 30),
child: ElevatedButton(
style: ButtonStyle(
padding: MaterialStateProperty.all<EdgeInsets>(
EdgeInsets.all(15)),
minimumSize:
MaterialStateProperty.all<Size>(Size(370, 0)),
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
side: BorderSide(color: Colors.red),
),
),
backgroundColor:
MaterialStateProperty.all<Color>(Colors.red),
),
onPressed: () => runMutation(
{
'data': {
'username': _usernameController.text,
'password': _passwordController.text
}
},
),
child: Text(
'Login',
style: TextStyle(
fontSize: 30.0,
),
),
),
),
],
),
),
Container(
margin: EdgeInsets.only(top: 100),
padding: EdgeInsets.only(bottom: 20),
child: Center(
child: Text(
'BY XXX',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 10,
),
),
),
),
],
);
},
),
],
),
);
}
void _togglePasswordVisibility() {
setState(() {
_hidePassword = !_hidePassword;
});
}
pubspec.yaml
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
graphql_flutter: ^5.0.0
shared_preferences: ^2.0.6
http: ^0.13.3
fluttertoast: ^8.0.7
font_awesome_flutter: ^9.1.0
dio: ^4.0.0
flutter_datetime_picker: ^1.5.1
loading_overlay: ^0.3.0
cupertino_icons: ^1.0.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
assets:
- assets/images/male.png
- assets/images/female.png
fonts:
- family: Changa
fonts:
- asset: fonts/Changa-Regular.ttf
- asset: fonts/Changa-Bold.ttf
weight: 700
As I said, I'm new to flutter and mobile app development
and the solution was obtained from this thread
The problem wasn't related to flutter_graphql lib but to the manifest file of the android project.
internet permission should be declared.
I supposed flutter will auto-detect and configure the app permissions based on the used libraries, but I was wrong.
I have a ChewiePlayer inside a statefull widget which is being used inside another statefull widget. when I go to full screen mode the dispose function gets called which basically deletes the listeners and I can't get out of full screen mode.
I also get this error:
NoSuchMethodError: The method 'dispose' was called on null. Receiver: null Tried calling: dispose()
as well as
A ChewiePlayerController was used after being disposed. Once you have called dispose() on a ChewiePlayerController...
seems like a common issue, tried almost every solution out there but nothing seems to work.
Here is my flutter doctor output:
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.6, on Mac OS X 10.15.7 19H1217 darwin-x64,
locale en-GB)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 12.1)
[✓] Android Studio (version 4.1)
[✓] VS Code (version 1.57.0)
[✓] Connected device (1 available)
• No issues found!
and this is the code inside my statefull widget:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html/style.dart' as HtmlStyle;
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:ria/src/models/game_pebble.dart';
import 'package:ria/src/models/trail.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';
class VideoOutputMineral extends StatefulWidget {
#override
VideoOutputMineralState createState() => VideoOutputMineralState();
final Mineral mineral;
final List<GameStyle> styles;
final Function onChangeAnswer;
VideoOutputMineral(this.mineral, this.styles, this.onChangeAnswer, {Key key})
: super(key: key);
}
class VideoOutputMineralState extends State<VideoOutputMineral>
with TickerProviderStateMixin {
VideoPlayerController videoPlayerController;
ChewieController chewieController;
Color hexToColor(String code) {
return new Color(int.parse(code.substring(1, 7), radix: 16) + 0xFF000000);
}
Color getFontColor() {
if (widget.styles != null &&
widget.styles.first != null &&
widget.styles.first.attributes.fontColor != null) {
return hexToColor(widget.styles.first.attributes.fontColor);
} else {
return Colors.black;
}
}
Future<void> initializeVideoPlayer() async {
// the async function which is responsible to get the trail detail, then initialize the video player controller, once done rebuild the widget with new data.
if (widget.mineral.properties.first.media.url != null &&
widget.mineral.properties.first.media.url != "") {
videoPlayerController = VideoPlayerController.network(
widget.mineral.properties.first.media.url);
await videoPlayerController.initialize();
chewieController = ChewieController(
videoPlayerController: videoPlayerController,
looping: true,
aspectRatio: 16 / 9,
deviceOrientationsAfterFullScreen: [
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown
],
allowFullScreen: true,
fullScreenByDefault: false,
autoInitialize: true,
errorBuilder: (context, errorMessage) {
return Center(
child: Text(
errorMessage,
style: TextStyle(color: Colors.white),
),
);
},
);
}
setState(() {});
}
#override
void initState() {
this.initializeVideoPlayer();
super.initState();
}
#override
void dispose() {
super.dispose();
if (chewieController != null && chewieController.isFullScreen) {
chewieController?.dispose();
}
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 8, bottom: 8, left: 30, right: 30),
child: Column(
children: [
widget.mineral.properties.first.title != null &&
widget.mineral.properties.first.title != ""
? Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Linkify(
options: LinkifyOptions(
defaultToHttps: true, looseUrl: true),
onOpen: (link) async {
if (await canLaunch(link.url)) {
await launch(link.url);
} else {
throw 'Could not launch $link';
}
},
text:
"${widget.mineral.properties.first.title}${widget.mineral.properties?.first?.rulesInput?.rulesInputRequired == 'required' ? ' *' : ''}",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: hexToColor(
widget.styles.first.attributes.fontColor),
),
linkStyle: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: hexToColor(
widget.styles.first.attributes.fontColor),
),
textAlign: TextAlign.center,
),
),
],
),
SizedBox(
height: 12,
),
],
)
: Container(),
widget.mineral.properties.first.description != null &&
widget.mineral.properties.first.description != ""
? Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Linkify(
options: LinkifyOptions(
defaultToHttps: true, looseUrl: true),
onOpen: (link) async {
if (await canLaunch(link.url)) {
await launch(link.url);
} else {
throw 'Could not launch $link';
}
},
text:
"${widget.mineral.properties.first.description}",
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500,
color: hexToColor(
widget.styles.first.attributes.fontColor),
),
linkStyle: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500,
color: hexToColor(
widget.styles.first.attributes.fontColor),
),
textAlign: TextAlign.center,
),
),
],
),
SizedBox(
height: 12,
),
],
)
: Container(),
ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: RotatedBox(
quarterTurns: 0,
child: Container(
height: 200,
child: chewieController != null &&
chewieController.videoPlayerController.value.initialized
? Chewie(
controller: chewieController,
)
: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SpinKitFadingCircle(
color: Colors.black,
),
],
),
),
),
),
widget.mineral.properties.first.caption != null &&
widget.mineral.properties.first.caption != ""
? Column(
children: [
SizedBox(
height: 12,
),
Text(
widget.mineral.properties.first.caption,
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500,
color: getFontColor(),
),
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
maxLines: 2,
),
],
)
: Container(),
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: widget.mineral.properties.first.content != null
? Column(
children: [
Html(
data: widget.mineral.properties.first.content,
style: {
"html": HtmlStyle.Style(
fontSize: HtmlStyle.FontSize.large,
color: getFontColor()),
"p": HtmlStyle.Style(
lineHeight: 1,
display: HtmlStyle.Display.BLOCK,
margin: EdgeInsets.fromLTRB(0, 0, 0, 0),
),
}),
],
)
: Container(),
)
],
),
);
}
}
thanks in advance!
Finally after about a week struggling found the issue, the issue was because in the parent widget's AppBar I was using PreferedSize and giving some padding to the element inside of it, since the player was being rendered on top of it and because of the appBar it was not able to go fullScreen it would have disposed the controller.
The fix was to check if the child widget has a VideoPlayer inside ignore the padding and it works great.
My Image Picker Working Fine In Emulator 7 In Debug Mode in my Real Device But Not Working After Exporting App In my Real Device..
I am using this plugin
What's the problem see in this video:
Video in Google Drive:
In Debugging Where All things working fine:
video in google drive
as you can see every-thing is working fine in debug mode
This is my Image Picking Function
File userAvatar;
File get getUserAvatar => userAvatar;
Future pickUserAvatar(BuildContext context, ImageSource source) async {
final pickedUserAvatar = await picker.getImage(source: source);
BotToast.showText(text: 'my picked name is $source');
pickedUserAvatar == null
? BotToast.showText(text: 'Select Image')
: userAvatar = File(pickedUserAvatar.path);
userAvatar != null
? Provider.of<LandingService>(context, listen: false)
.showUserAvatar(context)
: BotToast.showText(text: 'Image Upload Error');
notifyListeners();
}
This is my show user Avatar Function Where i show after image Successfully picked
showUserAvatar(BuildContext context) {
return showModalBottomSheet(
context: context,
builder: (context) {
return Container(
height: MediaQuery.of(context).size.height * 0.45,
width: MediaQuery.of(context).size.width,
child: SingleChildScrollView(
child: Column(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 150.0),
child: Divider(
thickness: 4.0,
color: constantColors.whiteColor,
),
),
CircleAvatar(
radius: 80.0,
backgroundColor: constantColors.transperant,
backgroundImage: FileImage(
Provider.of<LandingUtils>(context, listen: false)
.userAvatar,
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
MaterialButton(
child: Text(
'Reselect',
style: TextStyle(
color: constantColors.whiteColor,
fontWeight: FontWeight.bold,
decoration: TextDecoration.underline,
decorationColor: constantColors.whiteColor,
),
),
onPressed: () {
Provider.of<LandingUtils>(context, listen: false)
.pickUserAvatar(context, ImageSource.gallery);
},
),
MaterialButton(
color: constantColors.blueColor,
child: Text(
'Confirm Image',
style: TextStyle(
color: constantColors.whiteColor,
fontWeight: FontWeight.bold,
),
),
onPressed: () {
Provider.of<FirebasessOperations>(context,
listen: false)
.uploadUserAvatar(context)
.whenComplete(() => {
signUpSheet(context),
});
},
)
],
),
)
],
),
),
decoration: BoxDecoration(
color: constantColors.blueGreyColor,
borderRadius: BorderRadius.circular(15.0),
),
);
});
}
I also add this line in my android manifest
android:requestLegacyExternalStorage="true"
the problem is your build Gradle version
go to android/build.grale
classpath 'com.android.tools.build:gradle:3.5.4'
hope it works,
you need to check and grant user permission first before executing the photo selection function
kindly take a look at this plugin: https://pub.dev/packages/permission_handler
example:
// request a user for permission first
Map<Permission, PermissionStatus> statuses = await [
Permission.storage,
Permission.camera,
].request();
if (await Permission.storage.request().isGranted) {
// Either the permission was already granted before or the user just granted it you
can now select photo.
}
When trying to upload an image on my social media app it always crashes. Its been 2 months trying to solve this issue.
Initially i was using an older flutter code which had Deprecation warnings. I have now migrated the App to AndroidX hoping to solve the issue but still it fails on opening Select image option before you even pic the image the app crashes.
Flutter Doctor
[√] Flutter (Channel dev, 1.24.0-10.2.pre, on Microsoft Windows [Version 10.0.19041.630], locale en-GB)
• Flutter version 1.24.0-10.2.pre at C:\Flutter
• Framework revision 022b333a08 (5 days ago), 2020-11-18 11:35:09 -0800
• Engine revision 07c1eed46b
• Dart version 2.12.0 (build 2.12.0-29.10.beta)
[√] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
• Android SDK at F:\Android\SDKs
• Platform android-30, build-tools 30.0.2
• ANDROID_HOME = F:\Android\SDKs
• Java binary at: C:\Program Files\Android\Android Studio1\jre\bin\java
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
• All Android licenses accepted.
[√] Android Studio (version 4.1.0)
• Android Studio at C:\Program Files\Android\Android Studio1
• Flutter plugin can be installed from:
https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
[√] VS Code (version 1.51.1)
• VS Code at C:\Users\ACEHOME\AppData\Local\Programs\Microsoft VS Code
• Flutter extension version 3.16.0
[√] Connected device (1 available)
• DRA LX5 (mobile) • VUY9K20409902290 • android-arm • Android 8.1.0 (API 27)
• No issues found!
Debug Console Errors: From the point where the App crashes
I/flutter (14332): Firebase Messaging Token: dI1-F5iKBVA:APA91bHJE6Yk91vcEv3BX0h2A2KaNZMWvEALwrqYRzZ-ZoihIste67XLiwnf72OPcbvWfLm7tm4ScD8c2CzOvsiqOG7IZMd5aPfOcULEDCLrUbgJ_rFxoSE0kIQhxdpXcqMFWMp4G4E0
I/flutter (14332): Firebase Messaging Token: dI1-F5iKBVA:APA91bHJE6Yk91vcEv3BX0h2A2KaNZMWvEALwrqYRzZ-ZoihIste67XLiwnf72OPcbvWfLm7tm4ScD8c2CzOvsiqOG7IZMd5aPfOcULEDCLrUbgJ_rFxoSE0kIQhxdpXcqMFWMp4G4E0
V/jhw (14332): call Intent.migrateExtraStreamToClipData(1)
D/Surface (14332): Surface::disconnect(this=0x903be000,api=1)
D/Surface (14332): Surface::disconnect(this=0x903be000,api=-1)
D/Surface (14332): Surface::disconnect(this=0x903a3000,api=1)
W/ThreadedRenderer(14332): ThreadedRenderer::detachAnimators pid = 14332 threadid = 14474
V/PhoneWindow(14332): DecorView setVisiblity: visibility = 4, Parent = ViewRoot{d76c32d com.finde.med/com.finde.med.MainActivity,ident = 0}, this = DecorView#8723b57[MainActivity]
W/ThreadedRenderer(14332): ThreadedRenderer::detachAnimators pid = 14332 threadid = 14474
W/ConnectionTracker(14332): Exception thrown while unbinding
W/ConnectionTracker(14332): java.lang.IllegalArgumentException: Service not registered: lp#5595c0d
W/ConnectionTracker(14332): at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1556)
W/ConnectionTracker(14332): at android.app.ContextImpl.unbindService(ContextImpl.java:1642)
W/ConnectionTracker(14332): at android.content.ContextWrapper.unbindService(ContextWrapper.java:703)
W/ConnectionTracker(14332): at ci.f(:com.google.android.gms.dynamite_measurementdynamite#204217128#20.42.17 (110306-0):1)
W/ConnectionTracker(14332): at ci.d(:com.google.android.gms.dynamite_measurementdynamite#204217128#20.42.17 (110306-0):2)
W/ConnectionTracker(14332): at lq.D(:com.google.android.gms.dynamite_measurementdynamite#204217128#20.42.17 (110306-0):10)
W/ConnectionTracker(14332): at lc.a(:com.google.android.gms.dynamite_measurementdynamite#204217128#20.42.17 (110306-0):2)
W/ConnectionTracker(14332): at ee.run(:com.google.android.gms.dynamite_measurementdynamite#204217128#20.42.17 (110306-0):3)
W/ConnectionTracker(14332): at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
W/ConnectionTracker(14332): at java.util.concurrent.FutureTask.run(FutureTask.java:266)
W/ConnectionTracker(14332): at ix.run(:com.google.android.gms.dynamite_measurementdynamite#204217128#20.42.17 (110306-0):6)
Lost connection to device.
Exited (sigterm)
Code for Upload Page
import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:findemed/models/user.dart';
import 'package:findemed/pages/home.dart';
import 'package:findemed/widgets/progress.dart';
import 'package:geolocator/geolocator.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:image/image.dart' as Im;
import 'package:uuid/uuid.dart';
class Upload extends StatefulWidget {
final User currentUser;
Upload({this.currentUser});
#override
_UploadState createState() => _UploadState();
}
class _UploadState extends State<Upload>
with AutomaticKeepAliveClientMixin<Upload> {
TextEditingController captionController = TextEditingController();
TextEditingController locationController = TextEditingController();
File file;
bool isUploading = false;
String postId = Uuid().v4();
handleTakePhoto() async {
final _picker = ImagePicker();
PickedFile image;
Navigator.pop(context);
// File file
image = await _picker.getImage(
source: ImageSource.camera,
maxHeight: 675,
maxWidth: 960,
);
setState(() {
this.file = File(image.path);
});
}
handleChooseFromGallery() async {
final _picker = ImagePicker();
PickedFile image;
Navigator.pop(context);
// File file (removed)
image = await _picker.getImage(
source: ImageSource.gallery,
);
setState(() {
this.file = File(image.path);
});
}
selectImage(parentContext) {
return showDialog(
context: parentContext,
builder: (context) {
return SimpleDialog(
title: Text("Create Post"),
children: <Widget>[
SimpleDialogOption(
child: Text("Photo with Camera"),
onPressed: handleTakePhoto
),
SimpleDialogOption(
child: Text("Image from Gallery"),
onPressed: handleChooseFromGallery
),
SimpleDialogOption(
child: Text("Cancel"),
onPressed: () => Navigator.pop(context),
)
],
);
},
);
}
Container buildSplashScreen() {
return Container(
color: Theme.of(context).primaryColor.withOpacity(0.6),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SvgPicture.asset('assets/images/upload.svg', height: 170.0),
Padding(
padding: EdgeInsets.only(top: 50.0),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Text(
"Upload Image",
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
),
),
color: Theme.of(context).accentColor,
onPressed: () => selectImage(context)),
),
],
),
);
}
clearImage() {
setState(() {
file = null;
});
}
compressImage() async {
final tempDir = await getTemporaryDirectory();
final path = tempDir.path;
Im.Image imageFile = Im.decodeImage(file.readAsBytesSync());
final compressedImageFile = File('$path/img_$postId.jpg')
..writeAsBytesSync(Im.encodeJpg(imageFile, quality: 85));
setState(() {
file = compressedImageFile;
});
}
Future<String> uploadImage(imageFile) async {
StorageUploadTask uploadTask =
storageRef
.child("post_$postId.jpg")
.putFile(imageFile);
StorageTaskSnapshot storageSnap = await uploadTask
.onComplete;
String downloadUrl = await storageSnap.ref
.getDownloadURL();
return downloadUrl;
}
createPostInFirestore(
{String mediaUrl, String location, String description}) {
postsRef
.doc(widget.currentUser.id)
.collection("userPosts")
.doc(postId)
.set({
"postId": postId,
"ownerId": widget.currentUser.id,
"username": widget.currentUser.username,
"mediaUrl": mediaUrl,
"description": description,
"location": location,
"timestamp": timestamp,
"likes": {},
});
}
handleSubmit() async {
setState(() {
isUploading = true;
});
await compressImage();
String mediaUrl = await uploadImage(file);
createPostInFirestore(
mediaUrl: mediaUrl,
location: locationController.text,
description: captionController.text,
);
captionController.clear();
locationController.clear();
setState(() {
file = null;
isUploading = false;
postId = Uuid().v4();
});
}
Scaffold buildUploadForm() {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white70,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.black),
onPressed: clearImage),
title: Text(
"Caption Post",
style: TextStyle(color: Colors.black),
),
actions: [
FlatButton(
onPressed: isUploading ? null : () => handleSubmit(),
child: Text(
"Post",
style: TextStyle(
color: Theme.of(context).accentColor,
fontWeight: FontWeight.bold,
fontSize: 20.0,
),
),
),
],
),
body: ListView(
children: <Widget>[
isUploading ? linearProgress(context) : Text(""),
Container(
height: 220.0,
width: MediaQuery.of(context).size.width * 0.8,
child: Center(
child: AspectRatio(
aspectRatio: 16 / 9,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: FileImage(file),
),
),
),
),
),
),
Padding(
padding: EdgeInsets.only(top: 10.0),
),
ListTile(
leading: CircleAvatar(
backgroundImage:
CachedNetworkImageProvider(widget.currentUser.photoUrl),
),
title: Container(
width: 250.0,
child: TextField(
controller: captionController,
decoration: InputDecoration(
hintText: "Write a caption...",
border: InputBorder.none,
),
),
),
),
Divider(),
ListTile(
leading: Icon(
Icons.pin_drop,
color: Theme.of(context).accentColor,
size: 35.0,
),
title: Container(
width: 250.0,
child: TextField(
controller: locationController,
decoration: InputDecoration(
hintText: "Where was this photo taken?",
border: InputBorder.none,
),
),
),
),
Container(
width: 200.0,
height: 100.0,
alignment: Alignment.center,
child: RaisedButton.icon(
label: Text(
"Use Current Location",
style: TextStyle(color: Colors.white),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
color: Theme.of(context).accentColor,
onPressed: getUserLocation,
icon: Icon(
Icons.my_location,
color: Colors.white,
),
),
),
],
),
);
}
getUserLocation() async {
Position position = await Geolocator()
.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
List<Placemark> placemarks = await Geolocator()
.placemarkFromCoordinates(position.latitude, position.longitude);
Placemark placemark = placemarks[0];
String completeAddress =
'${placemark.subThoroughfare} ${placemark.thoroughfare}, ${placemark.subLocality} ${placemark.locality}, ${placemark.subAdministrativeArea}, ${placemark.administrativeArea} ${placemark.postalCode}, ${placemark.country}';
print(completeAddress);
String formattedAddress = "${placemark.subLocality}, ${placemark.locality}, ${placemark.country}";
locationController.text = formattedAddress;
}
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
return file == null ? buildSplashScreen() : buildUploadForm();
}
}
In this (small part of a app I'm building) I have a row of buttons which uses streams to select a behaviour (namely a time range to display data), that's working without problem. Then I want to change the selected action by setting the button color to say Colors.red. For this I use a Stream that take a value for a pressed button to rebuild the row of buttons with the appropriate colour.
For an unknown reason the snapshot.data is equal to initialData: whatever button I pressed. I checked that the stream value is the added value, and in order to make the StreamController behaves correctly I then replace the snapshot.data test by a test on var data = stream.listen((x) => data = x) and that works.
I just do not understand what's happening
flutter doctor -v
[✓] Flutter (Channel stable, v1.17.2, on Mac OS X 10.15.4 19E287, locale en-FR)
• Flutter version 1.17.2 at /usr/local/flutter
• Framework revision 5f21edf8b6 (4 days ago), 2020-05-28 12:44:12 -0700
• Engine revision b851c71829
• Dart version 2.8.3
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
• Android SDK at /Users/jfb/Library/Android/sdk
• Platform android-29, build-tools 28.0.3
• Java binary at: /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_242-b08)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 11.4.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 11.4.1, Build version 11E503a
• CocoaPods version 1.9.1
[!] Android Studio (not installed)
• Android Studio not found; download from https://developer.android.com/studio/index.html
(or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
[✓] Connected device (1 available)
• iPhone 11 • 17CF5871-B9F8-4739-B8BB-607807AD0530 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-4 (simulator)
! Doctor found issues in 1 category.
Code of this part :
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:weight_trend/blocs/bloc_provider.dart';
import 'package:weight_trend/blocs/chart_bloc.dart';
var myStream = StreamController<int>.broadcast();
Stream stream = myStream.stream;
var data; // normally should use snapshot.data
class ChartRangeSelectionButtons extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: myStream.stream,
initialData: 2,
builder: (context, snapshot) {
myStream.stream.listen((x) => data = x);
print(snapshot.data);
if (data == 1) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ChartButton(title: '1W', buttonColor: Colors.red),
ChartButton(title: '2W'),
ChartButton(title: '3W'),
ChartButton(title: '4W'),
],
);
} else if (data == 2) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ChartButton(title: '1W'),
ChartButton(title: '2W', buttonColor: Colors.red),
ChartButton(title: '3W'),
ChartButton(title: '4W'),
],
);
} else if (data == 3) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ChartButton(title: '1W'),
ChartButton(title: '2W'),
ChartButton(title: '3W', buttonColor: Colors.red),
ChartButton(title: '4W'),
],
);
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ChartButton(
title: '1W',
),
ChartButton(
title: '2W',
),
ChartButton(title: '3W'),
ChartButton(title: '4W', buttonColor: Colors.red),
],
);
}
},
);
}
}
class ChartButton extends StatelessWidget {
const ChartButton({this.title, this.buttonColor = Colors.white});
final String title;
final buttonColor;
#override
Widget build(BuildContext context) {
return Container(
width: 60,
child: RaisedButton(
onPressed: () {
if (title == '1W') {
BlocProvider.of<ChartBloc>(context).inputEvent.add(ChartRange.one);
myStream.sink.add(1);
} else if (title == '2W') {
BlocProvider.of<ChartBloc>(context).inputEvent.add(ChartRange.two);
myStream.sink.add(2);
} else if (title == '3W') {
BlocProvider.of<ChartBloc>(context)
.inputEvent
.add(ChartRange.three);
myStream.sink.add(3);
} else if (title == '4W') {
BlocProvider.of<ChartBloc>(context).inputEvent.add(ChartRange.four);
myStream.sink.add(4);
}
},
color: buttonColor,
textColor: Colors.black,
splashColor: Colors.grey.shade400,
child: Text(title),
),
);
}
}
I have made a simple example using your code and it seems to work ok:
2
2
3
1
Why are You using Bloc? It seems to me overkill for this type of things.
Just start simple.
import 'package:flutter/material.dart';
import "dart:async";
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: ChartRangeSelectionButtons(),
),
),
);
}
}
var myStream = StreamController<int>.broadcast();
Stream stream = myStream.stream;
var data; // normally should use snapshot.data
class ChartRangeSelectionButtons extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: myStream.stream,
initialData: 2,
builder: (context, snapshot) {
//myStream.stream.listen((x) => data = x);
print(snapshot.data);
if (data == 1) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ChartButton(title: '1W', buttonColor: Colors.red),
ChartButton(title: '2W'),
ChartButton(title: '3W'),
ChartButton(title: '4W'),
],
);
} else if (data == 2) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ChartButton(title: '1W'),
ChartButton(title: '2W', buttonColor: Colors.red),
ChartButton(title: '3W'),
ChartButton(title: '4W'),
],
);
} else if (data == 3) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ChartButton(title: '1W'),
ChartButton(title: '2W'),
ChartButton(title: '3W', buttonColor: Colors.red),
ChartButton(title: '4W'),
],
);
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ChartButton(
title: '1W',
),
ChartButton(
title: '2W',
),
ChartButton(title: '3W'),
ChartButton(title: '4W', buttonColor: Colors.red),
],
);
}
},
);
}
}
class ChartButton extends StatelessWidget {
const ChartButton({this.title, this.buttonColor = Colors.white});
final String title;
final buttonColor;
#override
Widget build(BuildContext context) {
return Container(
width: 60,
child: RaisedButton(
onPressed: () {
if (title == '1W') {
//BlocProvider.of<ChartBloc>(context).inputEvent.add(ChartRange.one);
myStream.sink.add(1);
} else if (title == '2W') {
//BlocProvider.of<ChartBloc>(context).inputEvent.add(ChartRange.two);
myStream.sink.add(2);
} else if (title == '3W') {
//BlocProvider.of<ChartBloc>(context).inputEvent.add(ChartRange.three);
myStream.sink.add(3);
} else if (title == '4W') {
//BlocProvider.of<ChartBloc>(context).inputEvent.add(ChartRange.four);
myStream.sink.add(4);
}
},
color: buttonColor,
textColor: Colors.black,
splashColor: Colors.grey.shade400,
child: Text(title),
),
);
}
}