I am a beginner in flutter development, I want to get filePath from the image that I choose in the app, but after I choose the image, the path is always emptied automatically
( value = null )
, I need the path to make a request to API, I hope there is someone that can help me to find the solution of this problem,
here is my code :
1
2 class AuthService {
3 static String? token;
4 static String? bioDateId;
5
6 final TokenManager tokenManager = TokenManager();
7 final BiodateIdManager biodateIdManager = BiodateIdManager();
8
9
10
11 Future<bool> updateBio({
12 required String firstName,
13 required String lastName,
14 required String birthDate,
15 required String gender,
16 required String phone,
17 required String address,
18 required String province,
19 required String regencies,
20 required String institutionName,
21 required String pupils,
22 required String field,
23 String? image,
24 String? proof,
25 }) async {
26 String? token = await tokenManager.getToken();
27 String? bioDateId = await biodateIdManager.getBiodateId();
28 try {
29
30 Map<String, dynamic> formDataMap = {
31 "firstName": firstName,
32 "lastName": lastName,
33 "birthDate": birthDate,
34 "gender": gender,
35 "phone": phone,
36 "address": address,
37 "province": province,
38 "regencies": regencies,
39 "institutionName": institutionName,
40 "field": field,
41 "pupils": pupils,
42 };
43
44
45 if (proof != null && proof.isNotEmpty) {
46 String? proofMimeType = lookupMimeType(proof);
47 if (proofMimeType != null) {
48 MultipartFile proofMultipartFile = await MultipartFile.fromFile(
49 proof,
50 filename: 'proof.png',
51 contentType: MediaType.parse(proofMimeType),
52 );
53 formDataMap["proof"] = proofMultipartFile;
54 } else {
55 debugPrint('Invalid proof MIME type');
56 }
57 }
58
59 if (image != null && image.isNotEmpty) {
60 String? imageMimeType = lookupMimeType(image);
61 if (imageMimeType != null) {
62 MultipartFile imageMultipartFile = await MultipartFile.fromFile(
63 image,
64 filename: 'image.png',
65 contentType: MediaType.parse(imageMimeType),
66 );
67 formDataMap["image"] = imageMultipartFile;
68 } else {
69 debugPrint('Invalid image MIME type');
70 }
71 }
72
73 var response = await Dio().put(
74 "http://myurl/update-biodate?id=$bioDateId",
75 data: FormData.fromMap(formDataMap),
76 options: Options(
77 headers: {
78 "Content-Type": "multipart/form-data",
79 "Authorization": "Bearer $token"
80 },
81 ),
82 );
83
84 if (response.statusCode == 200) {
85
86 return true;
87 } else {
88 throw Exception('Failed to Update Bio : ${response.data['message']}');
89 }
90 } on DioException catch (e) {
91 if (e.response?.statusCode == 400) {
92 debugPrint('Error 400: ${e.response?.data}');
93 throw Exception('Update Bio failed: ${e.response?.data['message']}');
94 } else {
95 debugPrint('Error: ${e.toString()}');
96 throw Exception('Failed to Update Bio');
97 }
98 }
99 }
1
2 class UpdateUserController {
3 final AuthService _authService = AuthService();
4 UpdateUserModel updateUserModel = UpdateUserModel();
5
6 TextEditingController firstNameController = TextEditingController();
7 TextEditingController lastNameController = TextEditingController();
8 TextEditingController birthDateController = TextEditingController();
9 TextEditingController genderController = TextEditingController();
10 TextEditingController phoneController = TextEditingController();
11 TextEditingController addressController = TextEditingController();
12 TextEditingController provinceController = TextEditingController();
13 TextEditingController regenciesController = TextEditingController();
14 TextEditingController imageController = TextEditingController();
15 TextEditingController institutionNameController = TextEditingController();
16 TextEditingController studyFieldController = TextEditingController();
17 TextEditingController uniqueIdController = TextEditingController();
18 TextEditingController proofController = TextEditingController();
19
20 String? _selectedImagePath;
21 String? _selectedProofPath;
22
23 void setImagePath(String filePath) {
24 _selectedImagePath = filePath;
25 debugPrint('Selected image path set: $_selectedImagePath');
26
27 }
28
29 void setProofPath(String filePath) {
30 _selectedProofPath = filePath;
31 debugPrint('Selected proof path set: $_selectedProofPath');
32
33 }
34
35 void reset() {
36 _selectedImagePath = null;
37 _selectedProofPath = null;
38 firstNameController.clear();
39 lastNameController.clear();
40 birthDateController.clear();
41 genderController.clear();
42 phoneController.clear();
43 addressController.clear();
44 provinceController.clear();
45 regenciesController.clear();
46 institutionNameController.clear();
47 studyFieldController.clear();
48 uniqueIdController.clear();
49 imageController.clear();
50 proofController.clear();
51 }
52
53 void dispose() {
54 firstNameController.dispose();
55 lastNameController.dispose();
56 birthDateController.dispose();
57 genderController.dispose();
58 phoneController.dispose();
59 addressController.dispose();
60 provinceController.dispose();
61 regenciesController.dispose();
62 addressController.dispose();
63 imageController.dispose();
64 institutionNameController.dispose();
65 studyFieldController.dispose();
66 uniqueIdController.dispose();
67 proofController.dispose();
68
69 }
70
71 bool fileExists(String path) {
72 return File(path).existsSync();
73 }
74
75 Future<void> updateBio(BuildContext context) async {
76
77 DialogHelper.showLoading(context);
78
79 String firstName = firstNameController.text.trim();
80 String lastName = lastNameController.text.trim();
81 String birthDate = birthDateController.text.trim();
82 String gender = genderController.text.trim();
83 String phone = phoneController.text.trim();
84 String address = addressController.text.trim();
85 String province = provinceController.text.trim();
86 String regencies = regenciesController.text.trim();
87 String institutionName = institutionNameController.text.trim();
88 String studyField = studyFieldController.text.trim();
89 String uniqueId = uniqueIdController.text.trim();
90 String? image = _selectedImagePath;
91 String? proof = _selectedProofPath;
92
93
94 if (proof != null && proof.isNotEmpty && !fileExists(proof)) {
95 throw Exception('Proof file does not exist or is inaccessible');
96 }
97
98 if (image != null && image.isNotEmpty && !fileExists(image)) {
99 throw Exception('Image file does not exist or is inaccessible');
100 }
101
102 try {
103 bool bioUpdated = await _authService.updateBio(
104 firstName: firstName,
105 lastName: lastName,
106 birthDate: birthDate,
107 gender: gender,
108 phone: phone,
109 address: address,
110 province: province,
111 regencies: regencies,
112 institutionName: institutionName,
113 field: studyField,
114 pupils: uniqueId,
115 image: image,
116 proof: proof,
117 );
118
119 DialogHelper.hideLoading(context);
120
121 if (bioUpdated) {
122
123 reset();
124
125 Navigator.push(
126 context,
127 MaterialPageRoute(
128 builder: (context) => const EduPassApp(
129 initialPageIndex: 4,
130 )));
131 ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
132 content: Text('UpdateBio successful'),
133 duration: Duration(seconds: 1),
134 ));
135 debugPrint('UpdateBio successful');
136 } else {
137
138 ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
139 content: Text('UpdateBio failed'),
140 duration: Duration(seconds: 2),
141 ));
142 debugPrint('UpdateBio failed');
143 }
144 } catch (e) {
145
146 DialogHelper.hideLoading(context);
147
148
149 ScaffoldMessenger.of(context).showSnackBar(SnackBar(
150 content: Text('Error: $e'),
151 duration: const Duration(seconds: 2),
152 ));
153
154 debugPrint('Error during UpdateBio: $e');
155 }
156 }
157 }
1
2 class ProfileDetailUser extends StatefulWidget {
3 const ProfileDetailUser({super.key});
4
5 @override
6 State<ProfileDetailUser> createState() => _ProfileDetailUserState();
7 }
8
9 class _ProfileDetailUserState extends State<ProfileDetailUser> {
10 String? _selectedImagePath;
11 String? _selectedBackgroundPath;
12 final UpdateUserController updateController = UpdateUserController();
13
14 void _handleImageSelected(String filePath) {
15 setState(() {
16 _selectedImagePath = filePath;
17 updateController.setImagePath(filePath);
18 });
19
20
21 debugPrint('File path: $filePath');
22 }
23
24 void _handleBackgroundSelected(String filePath) {
25 setState(() {
26 _selectedBackgroundPath = filePath;
27 updateController.setProofPath(filePath);
28 });
29
30
31 debugPrint('File path: $filePath');
32 }
33
34 @override
35 Widget build(BuildContext context) {
36 return ChangeNotifierProvider(
37 create: (context) => ProfileUserController(),
38 child: Consumer<ProfileUserController>(
39 builder: (context, profileController, child) {
40 if (profileController.isLoading) {
41 return const Center(child: CircularProgressIndicator());
42 }
43
44 if (profileController.userData == null) {
45 return ErrorScreen(onRetry: profileController.retryFetchUserData);
46 }
47
48
49 updateController.firstNameController.text =
50 profileController.userData!['biodate']['firstName'] ??
51 'First Name' ??
52 '';
53 updateController.lastNameController.text =
54 profileController.userData!['biodate']['lastName'] ?? '';
55 String birthDate =
56 profileController.userData!['biodate']['birthDate'] ?? '';
57 if (birthDate.isNotEmpty) {
58 updateController.birthDateController.text =
59 birthDate.substring(0, 10);
60 }
61
62 updateController.genderController.text =
63 profileController.userData!['biodate']['gender'] ?? '';
64 updateController.phoneController.text =
65 profileController.userData!['biodate']['phone'] ?? '';
66 updateController.addressController.text =
67 profileController.userData!['biodate']['address'] ?? '';
68 updateController.provinceController.text =
69 profileController.userData!['biodate']['province'] ?? '';
70 updateController.regenciesController.text =
71 profileController.userData!['biodate']['regencies'] ?? '';
72 updateController.institutionNameController.text =
73 profileController.userData!['biodate']['institutionName'] ?? '';
74 updateController.studyFieldController.text =
75 profileController.userData!['biodate']['field'] ?? '';
76 updateController.uniqueIdController.text =
77 profileController.userData!['biodate']['pupils'] ?? '';
78
79 updateController.setImagePath(
80 profileController.userData!['biodate']['image'] ?? '');
81 updateController.setProofPath(
82 profileController.userData!['biodate']['proof'] ?? '');
83
84 return Scaffold(
85 appBar: AppBar(
86 backgroundColor: Colors.white,
87 elevation: 0,
88 leading: IconButton(
89 icon: const Icon(Icons.arrow_back, color: Colors.black),
90 onPressed: () {
91 Navigator.pushReplacement(
92 context,
93 MaterialPageRoute(
94 builder: (context) =>
95 const EduPassApp(initialPageIndex: 4),
96 ),
97 );
98 },
99 ),
100 title: Text(
101 'Profile',
102 style: GoogleFonts.poppins(
103 color: Colors.black,
104 fontSize: 20,
105 fontWeight: FontWeight.bold,
106 ),
107 ),
108 ),
109 body: Container(
110 color: Colors.grey.shade100,
111 child: SingleChildScrollView(
112 padding: const EdgeInsets.only(
113 left: 16, right: 16, top: 16, bottom: 30),
114 child: Column(
115 children: [
116 UserAvatarField(onFileSelected: _handleImageSelected),
117 const SizedBox(height: 20),
118 if (_selectedImagePath != null) ...[
119 Text('Selected file: $_selectedImagePath'),
120
121 Image.file(
122 File(_selectedImagePath!),
123 height: 200,
124 ),
125 ],
126 const SizedBox(height: 16),
127 ProfileTextField(
128 label: 'Nama Depan',
129 placeholder: 'John',
130 controller: updateController.firstNameController,
131 ),
132 const SizedBox(height: 16),
133 ProfileTextField(
134 label: 'Nama Belakang',
135 placeholder: 'Doe',
136 controller: updateController.lastNameController,
137 ),
138 const SizedBox(height: 16),
139 ProfileTextField(
140 label: 'Email',
141 placeholder: 'stevejobs@gmail.com',
142 enabled: false,
143 controller: TextEditingController(
144 text: profileController.userData!['email'] ?? '',
145 ),
146 ),
147 const SizedBox(height: 16),
148 ProfileDateField(
149 label: 'Select Date',
150 placeholder: 'YYYY-MM-DD',
151 controller: updateController.birthDateController,
152 ),
153 const SizedBox(height: 16),
154 ElevatedButton(
155 onPressed: () {
156 debugPrint(
157 'Selected Date: ${updateController.birthDateController.text}');
158 },
159 child: const Text('Print Selected Date'),
160 ),
161 const SizedBox(height: 16),
162 DropdownField(
163 label: 'Jenis Kelamin',
164 items: const ['Pria', 'Wanita', ''],
165 controller: updateController.genderController,
166 onChanged: (value) {
167 debugPrint(
168 'Selected Gender: ${updateController.genderController.text}');
169 },
170 ),
171 const SizedBox(height: 16),
172 UploadImageField(onFileSelected: _handleBackgroundSelected),
173 const SizedBox(height: 20),
174 if (_selectedBackgroundPath != null) ...[
175 Text('Selected file: $_selectedBackgroundPath'),
176
177 Image.file(
178 File(_selectedBackgroundPath!),
179 height: 200,
180 ),
181 ],
182 const SizedBox(height: 16),
183 ProfileTextField(
184 label: 'Provinsi',
185 placeholder: 'California',
186 controller: updateController.provinceController,
187 ),
188 const SizedBox(height: 16),
189 ProfileTextField(
190 label: 'Regencies',
191 placeholder: 'San Francisco',
192 controller: updateController.regenciesController,
193 ),
194 const SizedBox(height: 16),
195 ProfileTextField(
196 label: 'Nomor HP',
197 placeholder: '08123456789',
198 controller: updateController.phoneController,
199 ),
200 const SizedBox(height: 16),
201 ProfileTextField(
202 label: 'Alamat',
203 placeholder: 'Jalan Jendral Sudirman No 1',
204 controller: updateController.addressController,
205 ),
206 const SizedBox(height: 16),
207 ProfileTextField(
208 label: 'Nama Instansi',
209 placeholder: 'Harvard University',
210 controller: updateController.institutionNameController,
211 ),
212 const SizedBox(height: 16),
213 ProfileTextField(
214 label: 'Bidang Studi/Jurusan',
215 placeholder: 'Teknik Informatika',
216 controller: updateController.studyFieldController,
217 ),
218 const SizedBox(height: 16),
219 ProfileTextField(
220 label: 'NIM/NISN',
221 placeholder: '123123123',
222 controller: updateController.uniqueIdController,
223 ),
224 const SizedBox(height: 32),
225 ElevatedButton(
226 onPressed: () {
227 updateController.updateBio(context);
228 updateController.reset();
229
230
231
232
233 },
234 style: ElevatedButton.styleFrom(
235 backgroundColor: Colors.indigo,
236 padding: const EdgeInsets.symmetric(
237 horizontal: 40, vertical: 16),
238 shape: RoundedRectangleBorder(
239 borderRadius: BorderRadius.circular(8),
240 ),
241 ),
242 child: Text(
243 'Edit',
244 style: GoogleFonts.poppins(
245 fontSize: 16,
246 fontWeight: FontWeight.bold,
247 color: Colors.white,
248 ),
249 ),
250 ),
251 ],
252 ),
253 ),
254 ),
255 );
256 },
257 ),
258 );
259 }
260 }
and here is the image of my debugging for imagePath, i hope you can get the picture of the problem
https://i.sstatic.net/8Lw0pyTK.png[
^]
What I have tried:
I have tried to change the nullable type but it still not work