Related
im new to flutter and i got a problem on my app,
firstly i was creating a button on my "ReminderPage" to navigate to a different page "AddReminder". it works before, so i try to add BottomNavigator in my "MainPage", but when i add a bottom navigatation from "HomePage" to "ReminderPage" all of the sudden the button didnt work, i also have an icon to change the theme, but the button didnt work and the background all of the sudden become blue, i dont know how this error happen so i need help from all of you guys, thank you
here is my "ReminderPage" code
import 'package:date_picker_timeline/date_picker_timeline.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:medreminder/Reminder/services/notification_services.dart';
import 'package:medreminder/Reminder/services/theme_services.dart';
import 'package:intl/intl.dart';
import 'package:medreminder/Reminder/ui/theme.dart';
import 'package:medreminder/Reminder/ui/widgets/add_remindbar.dart';
import 'package:medreminder/Reminder/ui/widgets/button.dart';
import 'package:medreminder/Reminder/ui/widgets/add_remindbar.dart';
class ReminderHomePage extends StatefulWidget {
const ReminderHomePage({super.key});
#override
State<ReminderHomePage> createState() => _ReminderHomePageState();
}
class _ReminderHomePageState extends State<ReminderHomePage> {
DateTime _selectedDate = DateTime.now();
var notifyHelper;
#override
void initState() {
// TODO: implement initState
super.initState();
notifyHelper=NotifyHelper();
notifyHelper.initializeNotification();
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: _appBar(),
backgroundColor: context.theme.backgroundColor,
body: Column(
children: [
_addTaskBar(),
_addDateBar(),
],
),
);
}
_addDateBar(){
return Container(
margin: const EdgeInsets.only(top: 20, left: 20),
child: DatePicker(
DateTime.now(),
height: 100,
width: 80,
initialSelectedDate: DateTime.now(),
selectionColor: Color(0xFFAAB6FB),
selectedTextColor: Colors.white,
dateTextStyle: GoogleFonts.lato(
textStyle: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color:Colors.grey
),
),
dayTextStyle: GoogleFonts.lato(
textStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color:Colors.grey
),
),
monthTextStyle: GoogleFonts.lato(
textStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color:Colors.grey
),
),
onDateChange: (date){
_selectedDate=date;
},
),
);
}
_addTaskBar(){
return Container(
margin: const EdgeInsets.only(left: 20, right: 20, top: 5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
margin: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(DateFormat.yMMMMd().format(DateTime.now()),
style: subHeadingStyle,
),
Text("Today",
style: headingStyle,
)
],
),
),
MyButton(label: "Add Reminder", onTap: ()=>Get.to(AddReminderPage()))
],
),
);
}
_appBar(){
return AppBar(
elevation: 0,
backgroundColor: context.theme.backgroundColor,
leading: GestureDetector(
onTap: (){
ThemeService().switchTheme();
notifyHelper.displayNotification(
title:"Theme Changed!",
body: Get.isDarkMode?"Activated Light Theme!":"Activated Dark Theme!"
);
notifyHelper.scheduledNotification();
},
child: Icon(Get.isDarkMode ?Icons.wb_sunny_outlined:Icons.nightlight_round,
size: 20,
color:Get.isDarkMode ? Colors.white:Colors.black
),
),
actions: [
CircleAvatar(
backgroundImage: AssetImage(
"images/profile.png"
),
),
// Icon(Icons.person,
// size: 20,),
SizedBox(width: 20,),
],
);
}
}
here is my BottomNavigator code
import 'package:flutter/material.dart';
import 'package:medreminder/Reminder/ui/home_reminder.dart';
import 'package:medreminder/Reminder/ui/widgets/add_remindbar.dart';
import 'package:medreminder/home_page.dart';
import 'package:medreminder/profile_page.dart';
import 'package:medreminder/settings_page.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:medreminder/Reminder/ui/theme.dart';
void main() => runApp(MaterialApp(home: MainPage()));
class MainPage extends StatefulWidget {
const MainPage({super.key});
#override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
List <Widget> pages = [
HomePage(),
SettingPage(),
ProfilePage()
];
int currentIndex = 0;
void onTap(int index){
setState(() {
currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
//height: MediaQuery.of(context).size.height * 0.4,
child: pages[currentIndex]
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.shifting,
onTap: onTap,
currentIndex: currentIndex,
selectedItemColor: bluishClr,
unselectedItemColor: Colors.black,
showUnselectedLabels: false,
showSelectedLabels: false,
items: [
BottomNavigationBarItem(label: "Home", icon: Icon(Icons.home)),
BottomNavigationBarItem(label: "Settings", icon: Icon(Icons.settings)),
BottomNavigationBarItem(label: "Profile", icon: Icon(Icons.account_circle)),
],
),
);
}
}
and lastly here is my HomePage code
import 'package:flutter/material.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:get/get_navigation/get_navigation.dart';
import 'Reminder/ui/home_reminder.dart';
import 'Reminder/ui/widgets/button.dart';
void main() {
// debugPaintSizeEnabled = true;
runApp(const HomePage());
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
#override
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Medicine Reminder App'),
),
body: Column(children: [
Stack(
children: [
Image.asset(
'images/MenuImg.jpg',
width: 600,
height: 200,
fit: BoxFit.cover,
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black)),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ReminderHomePage()),
);
},
child: Text("Button1"),
),
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black)),
onPressed: () {},
child: Text("Button2"),
),
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.black)),
onPressed: () {},
child: Text("Button3"),
),
],
)
]),
),
);
}
}
i really need a help, so every help would mean so much to me, thankyou guys
here is my app working perfectly when i run only the ReminderPage
https://i.stack.imgur.com/JqcZp.png
and here's how it look if i run it with BottomNavigationBar (the add reminder button and moon icon cant be clicked)
https://i.stack.imgur.com/9hVr8.png
Try the following code:
Navigator.of(context, rootNavigator: true).push(
MaterialPageRoute(builder: (context) => const ReminderHomePage())
);
try this
Navigator.of(context, rootNavigator: true).push(
context,
MaterialPageRoute(builder: (context) => const ReminderHomePage()),
);
everyone, I am having an issue with the release version of the flutter app where I do get everything perfect when the apps load for the first time after installing but after exiting it and re-opening the app gives an issue with the Ui build.
This is the expected result and as I get it for the first time.
This is what I get from the second time.
Key points I noticed:
I think it has something to do with getX and get controller as I didn't get any errors before using get and recent apps I have to build using getx throwing similar errors.
When I reopen the app after some time it works then again after exiting it won't, it is a continuous process.
I am using get and separating the view, controller and bindings.
Here is my main.dart file, login_binding.dart file, login_controller.dart file and login_view.dart file respectively.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:sizer/sizer.dart';
import 'package:travel_mate/app/utils/my_translations.dart';
import 'package:travel_mate/app/utils/themes.dart';
import 'app/modules/Bindings/login_binding.dart';
import 'app/routes/app_pages.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await GetStorage().initStorage;
runApp(
Sizer(
builder: (BuildContext context, Orientation orientation,
DeviceType deviceType) {
var isDark = GetStorage().read('isDark');
return GetMaterialApp(
defaultTransition: Transition.cupertino,
translations: MyTranslations(),
locale: Locale('en'),
fallbackLocale: Locale('np'),
themeMode: isDark != null
? isDark
? ThemeMode.dark
: ThemeMode.light
: ThemeMode.system,
debugShowCheckedModeBanner: false,
title: "Application",
getPages: AppPages.routes,
initialRoute: GetStorage().read('token') != null
? AppPages.INITIAL
: AppPages.SECONDARY,
theme: lightTheme,
darkTheme: darkTheme,
initialBinding: LoginBinding(),
);
},
),
);
}
import 'package:get/get.dart';
import 'package:travel_mate/app/modules/Controller/auth_controller.dart';
import 'package:travel_mate/app/modules/Controller/login_controller.dart';
class LoginBinding extends Bindings {
#override
void dependencies() {
Get.put(LoginController());
Get.put(AuthController());
}
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:travel_mate/app/models/user.dart';
import 'package:travel_mate/app/modules/Controller/auth_controller.dart';
import 'package:travel_mate/app/modules/views/tab/tab_view.dart';
class LoginController extends GetxController {
GlobalKey<FormState> formKey = GlobalKey();
TextEditingController emailOrUsernameController = TextEditingController();
TextEditingController passwordController = TextEditingController();
var isLoading = false.obs;
Rx<User?>? user;
#override
void dispose() {
super.dispose();
emailOrUsernameController.dispose();
passwordController.dispose();
}
final count = 0.obs;
void increment() => count.value++;
void login() async {
if (formKey.currentState!.validate()) {
isLoading.value = true;
Rx<User?> response = (await AuthController.instance
.login(emailOrUsernameController.text, passwordController.text))
.obs;
if (response.value != null) {
GetStorage().write('token', response.value!.token);
Get.offAndToNamed('/tab');
}
isLoading.value = false;
}
}
void clearFields() {
emailOrUsernameController.clear();
passwordController.clear();
}
String? validateEmailOrUsername(String? value) {
{
if (value!.isEmpty) {
return "Email or username can't be empty!";
} else if (!GetUtils.isEmail(value)) {
return "Not a valid email address!";
}
return null;
}
}
String? validatePassword(String? value) {
{
if (value!.isEmpty) {
return "Password can't be empty!";
} else if (value.length < 8) {
return "Password can't be less than 8 characters!";
}
return null;
}
}
}
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:sizer/sizer.dart';
import 'package:travel_mate/app/global_components/my_text_field.dart';
import 'package:travel_mate/app/modules/views/components/custom_button.dart';
import 'package:travel_mate/app/utils/colors.dart';
import '../Controller/login_controller.dart';
class LoginView extends GetView<LoginController> {
const LoginView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
child: Column(
children: [
Container(
margin: EdgeInsets.symmetric(horizontal: 5.w, vertical: 5.w),
//FORMS START FROM HERE
child: Form(
key: controller.formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//Main art and logo
Center(
child: SvgPicture.asset(
'assets/images/login_art.svg',
width: 75.w,
),
),
SizedBox(
height: 1.h,
),
Center(
child: Text(
'TravelMate',
style: TextStyle(
fontFamily: 'Comic Sans Ms',
fontSize: 22.5.sp,
color: primaryColor,
),
),
),
SizedBox(
height: 2.h,
),
Text(
'login'.tr,
style: TextStyle(
fontFamily:
GoogleFonts.poppins(fontWeight: FontWeight.bold)
.fontFamily,
fontSize: 15.sp,
color: primaryColor,
),
),
SizedBox(
height: 2.h,
),
//Username Field
MyTextField(
textEditingController:
controller.emailOrUsernameController,
validator: controller.validateEmailOrUsername,
textInputAction: TextInputAction.next,
labelText: 'emailLabel'.tr,
),
SizedBox(
height: 3.h,
),
//Password Field
MyTextField(
validator: controller.validatePassword,
textEditingController: controller.passwordController,
textInputAction: TextInputAction.done,
labelText: 'passwordLabel'.tr,
isPassword: true,
),
SizedBox(
height: 3.h,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
InkWell(
onTap: () {},
child: Text(
'forgot'.tr,
style: TextStyle(
fontFamily: GoogleFonts.poppins().fontFamily),
),
)
],
),
SizedBox(
height: 4.h,
),
//Login button
Obx(
() => CustomButton(
onTap: controller.login,
isLoading: controller.isLoading.value,
title: 'login'.tr),
),
SizedBox(
height: 4.h,
),
//Sign in with google button
SizedBox(
height: 4.h,
),
//Not registered yet button
Center(
child: Text.rich(
TextSpan(
style: TextStyle(
fontFamily: GoogleFonts.poppins().fontFamily,
fontSize: 12.sp,
// color: const Color(0xff000000),
),
children: [
TextSpan(
text: 'registerText'.tr,
),
TextSpan(
recognizer: TapGestureRecognizer()
..onTap = (() {
Get.toNamed('/sign-up');
}),
text: 'signup'.tr,
style: TextStyle(
color: const Color(0xff0189e2),
),
),
],
),
textHeightBehavior: TextHeightBehavior(
applyHeightToFirstAscent: false),
textAlign: TextAlign.center,
softWrap: false,
),
),
],
),
),
),
],
),
),
),
);
}
}
Update: after trying out some possible reasons, and delaying the call of the run app function by around 500ms I was able to resolve this issue but still not sure what is causing such an error.
am trying to pass song details from the following file Songs_list.dart to home_screen.dart but i get an error that type 'Song' is not a subtype of type 'song' where Song is from .......Songs_list.dart
import 'package:flutter/material.dart';
import 'package:nyimbo_cia_ngai/models/Songs_All.dart';
import 'package:nyimbo_cia_ngai/screens/home_screen.dart';
class SongsList extends StatefulWidget {
//static String tag = 'Songlist-page';
#override State<StatefulWidget> createState() {
return new _SongsListState();
}
}
class _SongsListState extends State<SongsList> {
TextEditingController searchController = new TextEditingController();
String filter;
#override initState() {
searchController.addListener(() {
setState(() {
filter = searchController.text;
});
});
}
#override void dispose() {
searchController.dispose();
super.dispose();
}
#override Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColor,
appBar: AppBar( leading: IconButton(
icon: Icon(Icons.menu),
iconSize: 30.0,
color: Colors.white,
onPressed: (){},
),
title: Text('Nyimbo Cia Kuinira Ngai', style: TextStyle(fontSize: 20.0,
),),
elevation: 0.0,
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
iconSize: 30.0,
color: Colors.white,
onPressed: (){},
),
],
),
body: new Column(
children: <Widget>[
//Search box
new Padding(
padding: new EdgeInsets.all(8.0),
child: new TextField(
controller: searchController,
decoration: InputDecoration(
hintText: 'Search Song',
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0),
borderSide: BorderSide(color: Colors.white)
),
),
),
//search Box end
),
new Expanded(
child: Container(
decoration: BoxDecoration(color: Theme.of(context).accentColor,
borderRadius: BorderRadius.only(topLeft: Radius.circular(30.0),topRight: Radius.circular(30.0),
),
),
///////////////////////////////////////////////////////////////////
child: new ListView.builder(
itemCount: Songs.length,
itemBuilder: (context, index) {
// if filter is null or empty returns all data
return filter == null || filter == "" ? ListTile(
title: Text(
'${Songs[index].SongName}',
),
subtitle: Text('${Songs[index].SongNumber}'),
leading: new CircleAvatar(
backgroundColor: Theme.of(context).primaryColor,
child: Text(
'${Songs[index].SongNumber.substring(0, 3)}')),
onTap: () =>
Navigator.push(context, MaterialPageRoute(builder: (context)=>HomeScreen(Songs[index] ?? '')))
//_onTapItem(context, Songs[index] ?? ''),
)
: '${Songs[index].SongNumber}'.toLowerCase()//search using the song number
.contains(filter.toLowerCase())
? ListTile(
title: Text(
'${Songs[index].SongName}',
),
subtitle: Text('${Songs[index].SongNumber}'),
leading: new CircleAvatar(
backgroundColor: Theme.of(context).primaryColor,
child: Text(
'${Songs[index].SongNumber.substring(0, 3)}')),
onTap: () =>
Navigator.push(context, MaterialPageRoute(builder: (context)=>HomeScreen(Songs[index]?? '')))
//_onTapItem(context, Songs[index]?? ''),
)
: new Container();
},
),
//////////////////////////////////////////////////////////////////
),
),
],
));
}
void _onTapItem(BuildContext context, Song post) {
}
}
class Song {
final String SongNumber;
final String SongName;
const Song({this.SongNumber, this.SongName});
}
Songs_list.dart is getting its data from Songs_all.dart which is happening correctly
import 'package:flutter/material.dart';
class Song{
String SongName;
String SongNumber;
String verses;
Song(
{
#required this.SongName,
#required this.SongNumber,
#required this.verses});
}
List<Song> Songs =[
Song(
SongNumber:'002',
SongName:'HE NYUMBA NJEGA THIINI WA ANDU',
verses:'1 . He nyumba njega thiini wa andu'
But when user taps on the song to open its details it brings up an error. the ontap is supposed to open in the following page home_screen.dart
import 'package:flutter/material.dart';
import 'package:nyimbo_cia_ngai/screens/Songs_list.dart';
class HomeScreen extends StatelessWidget {
final Song song;
HomeScreen(this.song);
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text(''),
),
);
}
}
where could i be going wrong when passing the details using ontap?
You are using diffrent class "Song"
SongsList : import 'package:nyimbo_cia_ngai/models/Songs_All.dart';
HomeScreen : import 'package:nyimbo_cia_ngai/screens/Songs_list.dart';
Its not big issue just make sure you are importing the same class.
I am working on an application to set wallpapers, which comes to the application through the link "imgUrl", but when I want to set a specific image as wallpaper it gives me this error,
[ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: MissingPluginException(No implementation found for method requestPermissions on channel flutter.baseflow.com/permissions/methods)
I hope you will give me an easy way to set an image as a wallpaper and also a way to save the image inside the device,
Note: I am using flutter for Android only
import 'package:flutter/material.dart';
import 'package:gallery_saver/gallery_saver.dart';
import 'package:get/get.dart';
import 'package:image_downloader/image_downloader.dart';
import 'package:flutter/services.dart';
import 'dart:async';
import 'dart:io';
import 'dart:async';
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:wallpaper/wallpaper.dart';
class ImgDetails extends StatefulWidget {
#override
_ImgDetailsState createState() => _ImgDetailsState();
}
class _ImgDetailsState extends State<ImgDetails> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
var imgPath ;
String home = "Home Screen",
lock = "Lock Screen",
both = "Both Screen",
system = "System";
String _title = Get.arguments['title'];
String _imgUrl = Get.arguments['url'];
#override
Widget build(BuildContext context) {
final snackBar = SnackBar(
content: Text(_title),
duration: const Duration(seconds:3),
);
return Scaffold(
appBar: AppBar(
title: Text(_title),
centerTitle: true,
),
key: _scaffoldKey,
body: Stack(
alignment: Alignment.bottomCenter,
children: [
Container(
height: double.infinity,
child: InteractiveViewer(
maxScale: 6,
child: FadeInImage(
image: NetworkImage(_imgUrl),
placeholder: AssetImage('assets/img/img_ot_found.jpg'),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: MediaQuery.of(context).size.width*0.8,
height: MediaQuery.of(context).size.height*0.08,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Colors.purple , Colors.purpleAccent]
)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(icon: Icon(Icons.save_alt_rounded , color: Colors.white,size: 32), onPressed: (){
}),
IconButton(icon: Icon(Icons.imagesearch_roller, color: Colors.white,size: 32), onPressed: (){
_modal();
}),
IconButton(icon: Icon(Icons.info_outline, color: Colors.white,size: 32,), onPressed: (){
_scaffoldKey.currentState.showSnackBar(snackBar);
}),
],
),
),
),
],
),
);
}
_askPermission() async {
if (Platform.isAndroid) {
await PermissionHandler().requestPermissions([
PermissionGroup.storage,
PermissionGroup.camera,
PermissionGroup.location,
]);
} else {
await PermissionHandler()
.checkPermissionStatus(PermissionGroup.storage);
}
}
_modal() {
showModalBottomSheet(
backgroundColor: Colors.white.withOpacity(0.2),
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30,)),
context: context,
builder: (BuildContext context) {
return Container(
height: 130,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.8),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
)
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_createTile(context, 'Home Screen', Icons.home, _action1),
SizedBox(height: 10,),
_createTile(context, 'Lock Screen', Icons.lock, _action2),
],
),
);
}
);
}
ListTile _createTile(BuildContext context, String name, IconData icon,
Function action) {
return ListTile(
leading: Icon(icon,
color: Colors.blueAccent,),
title: Text(name,
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.w500, fontSize: 20),),
onTap: () {
Navigator.pop(context);
action();
},
);
}
_action1() async {
if (Platform.isAndroid) {
await _askPermission();
}
var response = await Dio()
.get(_imgUrl, options: Options(responseType: ResponseType.bytes));
//await ImageGallerySaver.saveImage(Uint8List.fromList(response.data));
home = await Wallpaper.homeScreen(_imgUrl);
final result = home = home;
print(result);
}
_action2() async {
if (Platform.isAndroid) {
await _askPermission();
}
var response = await Dio()
.get(_imgUrl, options: Options(responseType: ResponseType.bytes));
//await ImageGallerySaver.saveImage(Uint8List.fromList(response.data));
home = await Wallpaper.lockScreen(_imgUrl);
final result = home = lock;
print(result);
}
}
You are having a problem with the permission. You need to add a permission code to the AndroidManifest file. Can you send me all the error logs so I can figure out what privilege is missing?
I hope you all are doing well today. I have another flutter issue that I have been stuck on for the past few days now. I'm attempting to upload this data to my firestore instance, but my post button never seems to be triggering. I have attempted to print a statement from the method that it evokes, but I can't seem to get that to work either. I'm attempting to create a social media app, and any and all help would be appreciated.
My main goal is to get the post button to execute in upload.dart.
I have also included home.dart since the two classes are connected in terms of performance.
upload.dart
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/flutter_svg.dart';
import 'package:fluttermedia/models/user.dart';
import 'package:fluttermedia/pages/home.dart';
import 'package:fluttermedia/widgets/progress.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> {
TextEditingController locationController = TextEditingController();
TextEditingController captionController = TextEditingController();
File file;
bool isUploading = false;
String postId = Uuid().v4();
handleChooseFromGallery() async{
Navigator.pop(context);
File file = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
this.file = file;
});
}
handleTakePhoto() async {
Navigator.pop(context);
File file = await ImagePicker.pickImage(source: ImageSource.camera,maxHeight: 675,maxWidth: 960);
setState(() {
this.file = file;
});
}
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).accentColor.withOpacity(0.6),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SvgPicture.asset('assets/images/upload.svg',height: 260.0,),
Padding(
padding: EdgeInsets.only(top:20.0),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
child: Text(
"Upload Image",
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
),
),
color: Colors.deepOrange,
onPressed: () => selectImage(context),
),
)
],
),
);
}
clearImage(){
setState(() {
file = null;
});
}
//This compresses images for firebase
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;
}
//upload new info to firestore that creates a new collection
createPostInFirestore({String mediaUrl, String location, String description}){
postsRef.document(widget.currentUser.id)
.collection("userPosts")
.document(postId)
.setData({
"postId": postId,
"ownerId": widget.currentUser.id,
"username": widget.currentUser.username,
"mediaUrl": mediaUrl,
"description": description,
"location": location,
"timestamp": timeStamp,
"likes":{}
});
}
//Getting the info from the caption, location and pic
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;
});
}
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: <Widget>[
FlatButton(
onPressed: () => isUploading ? null : () => handleSubmit(),
child: Text(
"Post",
style: TextStyle(
color: Colors.blueAccent,
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),
),
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: Colors.orange,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: Colors.blue,
onPressed: () => print("Get user location"),
icon: Icon(
Icons.my_location,
color: Colors.white,
),
),
)
],
),
);
}
#override
Widget build(BuildContext context) {
return file == null ? buildSplashScreen() : buildUploadForm();
}
}
home.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttermedia/models/user.dart';
import 'package:fluttermedia/pages/activity_feed.dart';
import 'package:fluttermedia/pages/create_account.dart';
import 'package:fluttermedia/pages/profile.dart';
import 'package:fluttermedia/pages/search.dart';
import 'package:fluttermedia/pages/upload.dart';
import 'package:google_sign_in/google_sign_in.dart';
final GoogleSignIn googleSignIn = GoogleSignIn();
final StorageReference storageRef = FirebaseStorage.instance.ref();
final usersRef = Firestore.instance.collection('users');
final postsRef = Firestore.instance.collection('posts');
final DateTime timeStamp = DateTime.now();
User currentUser;
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool isAuth = false;
PageController pageController;
int pageIndex = 0;
#override
void initState() {
super.initState();
pageController = PageController();
// Detects if user signs in
googleSignIn.onCurrentUserChanged.listen((account) {
handleSignIn(account);
}, onError: (err){
print('Error sigining in: $err');
});
//Reauthenticate user when app is opened
googleSignIn.signInSilently(suppressErrors: false)
.then((account) =>
handleSignIn(account)).catchError((err){
print('Error signing in on retry: $err');
});
}
#override
Widget build(BuildContext context) {
return isAuth ? buildAuthScreen() : buildUnAuthScreen();
}
#override
void dispose(){
pageController.dispose();
super.dispose();
}
//Helper Functions
//The sign in section of the code
handleSignIn(GoogleSignInAccount account){
if(account != null){
createUserInFirestore();
setState(() {
isAuth = true;
});
}else{
setState(() {
isAuth = false;
});
}
}
login(){
googleSignIn.signIn();
}
logout(){
googleSignIn.signOut();
}
onPageChanged(int pageIndex){
setState(() {
this.pageIndex = pageIndex;
});
}
createUserInFirestore() async{
// 1) Check if user exists in users collection in database (According to id)
final GoogleSignInAccount user = googleSignIn.currentUser;
DocumentSnapshot doc = await usersRef.document(user.id).get();
if(!doc.exists){
// 2) If the user doesn't exist, take them to create account page
final username = await Navigator.push(context, MaterialPageRoute(builder: (context) => CreateAccount()));
// 3) get username from create account, use it to make new user document in users collection
usersRef.document(user.id).setData({
"id":user.id,
"username":username,
"photoUrl": user.photoUrl,
"email":user.email,
"displayName": user.displayName,
"bio":"",
"timeStamp": timeStamp,
});
doc = await usersRef.document(user.id).get();
}
currentUser = User.fromDocument(doc);
//print(currentUser);
//print(currentUser.username);
}
onTap(int pageIndex){
//This what you would use to animate in between the different screens
pageController.animateToPage(
pageIndex,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut
);
}
//UI Code
Widget buildAuthScreen() {
return Scaffold(
body: PageView(
children: <Widget>[
//Timeline(),
RaisedButton(
child: Text('Logout'),
onPressed: logout,
),
ActivityFeed(),
Upload(currentUser: currentUser),
Search(),
Profile(),
],
controller: pageController,
onPageChanged: onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: CupertinoTabBar(
currentIndex: pageIndex,
onTap: onTap,
activeColor: Theme.of(context).primaryColor,
items: [
BottomNavigationBarItem(icon: Icon(Icons.whatshot),),
BottomNavigationBarItem(icon: Icon(Icons.notifications_active),),
BottomNavigationBarItem(icon: Icon(Icons.photo_camera, size: 34.0,),),
BottomNavigationBarItem(icon: Icon(Icons.search),),
BottomNavigationBarItem(icon: Icon(Icons.account_circle),),
],
),
);
/*return RaisedButton(
child: Text('Logout'),
onPressed: logout,
);*/
}
Scaffold buildUnAuthScreen() {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Theme.of(context).primaryColor,
Theme.of(context).accentColor,
]
)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text('FlutterMedia',
style: TextStyle(
fontFamily: "Signatra",
fontSize: 90.0,
color: Colors.white
),
),
GestureDetector(
onTap:() => login(),
child: Container(
width: 260,
height: 60,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/google_signin_button.png'),
fit: BoxFit.cover,
),
),
),
)
],
),
),
);
}
}
onPressed: () => isUploading ? null : () => handleSubmit(),
Well, there's your problem. You meant to have a tertiary condition that makes onPressed call handleSubmit when isUploading is false. Instead, you have made onPressed into a function that returns a function.
To hopefully make that more clear, let's blow this function up into proper non-lambda functions and if/else blocks:
onPressed: () {
if (isUploading) {
return null;
} else {
return () {
handleUpload();
}
}
}
So consider what happens when the button is pressed. It calls the outer function, which checks isUploading. If true, the function returns null, and if false, it returns another function that, if called, calls handleUpload. So how this plays out is that onPressed will never be null (it just returns null sometimes) and handleUpload never gets called (since the inner function that is returned is never then called itself).
Remove the outer lambda and it will work:
onPressed: isUploading ? null : () => handleSubmit(),