InkWell(
onTap: () {
Get.put<DetailsPaymentHistoryController>(
DetailsPaymentHistoryController(
paymentHistoryApi: PaymentHistoryApi(),
invoiceId: payment.invoiceId!.toString()));
Get.toNamed(Routes.detailsHistoryPayment);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
'More Details',
style: getSemiBoldStyle(
color: Colormanager.primary,
fontSize: FontSize.s15),
),
const SizedBox(
width: AppSize.s4,
),
Icon(
Icons.read_more,
color: Colormanager.darkPrimary,
)
],
),
),
Suppose there some card and those card has their own ivoiceId "yxz123"
when i press "More Details" button it route me to the "detailsHistoryPayment" page acording to invoiceId where has some property.but whene i go back and press another "More Details" button it route me the same previous InvoiceId page. it is not showing the new invoiceId's page.
class DetailsPaymentHistoryController extends GetxController
with StateMixin<DetailsHistoryPaymentResponse> {
PaymentHistoryApi paymentHistoryApi;
String invoiceId;
DetailsPaymentHistoryController({
required this.paymentHistoryApi,
required this.invoiceId,
});
#override
void onInit() {
if (kDebugMode) {
print('--------------------------');
print(invoiceId);
}
getPaymentHistoryDetails();
super.onInit();
}
//Get Dashboard Data
getPaymentHistoryDetails() async {
change(null, status: RxStatus.loading());
try {
paymentHistoryApi
.getPaymentHistoryDetails(invoiceId: invoiceId)
.then((value) {
var body = json.decode(value);
print(invoiceId);
change(DetailsHistoryPaymentResponse.fromJson(body),
status: RxStatus.success());
if (kDebugMode) {
print(value);
}
}).onError((error, stackTrace) {
change(null, status: RxStatus.error(AppStrings.somthingWentWrong));
if (kDebugMode) {
print(value);
}
});
} catch (error) {
change(null, status: RxStatus.error(error.toString()));
if (kDebugMode) {
print(value);
}
}
}
}
............................
Future<dynamic> getPaymentHistoryDetails({
required String? invoiceId,
}) =>
http
.get(
Uri.parse(
'${BaseUrl.baseUrl}/payment-history-details-merchant?invoice_id=$invoiceId'),
headers: <String, String>{
'Accept': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ${StorageHelper.getString(key: 'token')}'
},
)
.then((value) => value.body)
.onError((error, stackTrace) => Future.error(error.toString()));
}
I tried Get.toNamed(Routes.detailsHistoryPayment); to Get.offNamed(Routes.detailsHistoryPayment); and it work but it route me to two previous page. But i want to go back just previous page. Is there any way to go back to previous page and previous page got reload automaticly???
To go previous page, execute below.
Get.back();
And you could refresh previous page after await Get.toNamed('...');
onTap: () async {
...
await Get.toNamed(Routes.detailsHistoryPayment);
// TODO: yourController.yourRefreshMethod();
},
The main problem happens with my Get.put method. Just writing Get.putAsync method and all goes well.
onTap: () {
Get.putAsync<DetailsPaymentHistoryController>(
await DetailsPaymentHistoryController(
paymentHistoryApi: PaymentHistoryApi(),
invoiceId: payment.invoiceId!.toString()));
Get.toNamed(Routes.detailsHistoryPayment);
},
Related
I want to call and show the data '800000.00' which is coming from an api, just below of the IconButton text 'ক্যাশ'
I have created a widget to click and show data from an api which uses get request. I want to show the api data just below of the Text('ক্যাশ') of this button:
Widget _buildCashDetailsBtn() {
return Column(
children: <Widget>[
IconButton(
iconSize: 50,
icon: const Icon(
Icons.directions_bike,
color: Color.fromARGB(255, 4, 219, 93),
),
onPressed: () {
setState(
() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CashDetailsAPI()),
);
},
);
},
),
Text('ক্যাশ'),
],
);
}
The Future I have created for loading the data from the api is below:
Future<List<Welcome>> getData() async {
final response = await http.get(
Uri.parse('http://202.191.120.42:5000/api/ReportData/GetCashAmount'));
var data = jsonDecode(response.body.toString());
if (response.statusCode == 200) {
for (Map<String, dynamic> index in data) {
welcome.add(Welcome.fromJson(index));
}
return welcome;
} else {
return welcome;
}
}
I am developing a voice/video-calling app using Flutter and Agora rtc engine (v 5.3.1). I have followed all the necessary steps for generating token and joining a channel. But, I can't see the local camera view in the UI and the logs gives me warning saying: "onWarning warn 8 msg invalid view for local video". Any leads would be big help, thanks in advance.
Logs:
W/spdlog (30579): [2023-01-04 21:02:33.375] [0] [warning] /tmp/jenkins/IRIS-SDK/rtc/cxx/src/internal/rtc_engine_event_handler.cc:43 onWarning warn 8 msg invalid view for local video
W/spdlog (30579): [2023-01-04 21:02:33.375] [0] [warning] /tmp/jenkins/IRIS-SDK/rtc/cxx/src/internal/rtc_engine_event_handler.cc:43 onWarning warn 16
msg nullptr
I/spdlog (30579): [2023-01-04 21:02:33.375] [0] [info] /tmp/jenkins/IRIS-SDK/rtc/cxx/src/internal/rtc_engine_event_handler.cc:72 onJoinChannelSuccess
channel b8667da0-8c6a-11ed-a9fb-578e8ad35bd6 uid 1
W/spdlog (30579): [2023-01-04 21:02:33.377] [0] [warning] /tmp/jenkins/IRIS-SDK/rtc/cxx/src/internal/rtc_engine_event_handler.cc:43 onWarning warn 16
msg nullptr
Call Screen Widget:
imports...
String baseUrl = 'https://...';
class CallScreen extends ConsumerStatefulWidget {
final Call call;
const CallScreen({Key? key, required this.call, }) : super(key: key);
#override
_CallScreenState createState() => _CallScreenState();
}
class _CallScreenState extends ConsumerState<CallScreen> {
int uid = 1;
List<int> _remoteUids = [];
bool isJoined = false,
switchCamera = true,
openMicrophone = true,
enableSpeakerphone = false;
late bool openCamera;
late RtcEngine _engine;
#override
void initState() {
initAgora();
openCamera = widget.call.isVideoCall;
super.initState();
}
Future<String?> _getToken() async {
String url = baseUrl + "/rtc/" + widget.call.callId + "/publisher/uid/" + uid.toString() + "/";;
String? token;
try{
var resp = await http.get(Uri.parse(url));
if(resp.statusCode == 200){
token = jsonDecode(resp.body)['rtcToken'];
return token;
}
else{
showMySnackBar(context: context, content: "Token Status ERR: "+jsonDecode(resp.body)['message']);
return null;
}
}
catch(e){
showMySnackBar(context: context, content: "Token Err: "+e.toString());
return null;
}
}
void _joinChannel() async {
String? token = await _getToken();
if(token != null){
await _engine.joinChannel(token, widget.call.callId, null, uid);
}
else{
showMySnackBar(context: context, content: 'Token is null!');
}
}
void _leaveChannel() async {
ref.read(callControllerProvider).endCall(
widget.call.callerId,
widget.call.receiverId,
context,
widget.call.isGroupChat
);
if(widget.call.isVideoCall) await _engine.stopPreview();
await _engine.leaveChannel();
}
void _switchCamera() {
_engine.switchCamera()
.then((value) {
setState(() {
switchCamera = !switchCamera;
});
})
.catchError((err) {
//print('switchCamera $err');
});
}
void _switchMicrophone() async {
// await _engine.muteLocalAudioStream(!openMicrophone);
await _engine.enableLocalAudio(!openMicrophone)
.then((value) {
setState(() {
openMicrophone = !openMicrophone;
});
})
.catchError((err) {
// print('enableLocalAudio $err');
});
}
void _switchSpeakerphone() {
_engine.setEnableSpeakerphone(!enableSpeakerphone)
.then((value) {
setState(() {
enableSpeakerphone = !enableSpeakerphone;
});
})
.catchError((err) {
//print('setEnableSpeakerphone $err');
});
}
void initAgora() async {
try{
await [Permission.microphone, Permission.camera].request();
_engine = await RtcEngine.createWithContext(RtcEngineContext(AgoraConfig.appId));
_engine.setEventHandler(
RtcEngineEventHandler(
warning: (warn) {
showMySnackBar(context: context, content: "Warn: "+warn.name);
},
error: (err) {
showMySnackBar(context: context, content: 'OnErr event: '+err.name);
},
joinChannelSuccess: (String channel, int userId, int elapsed) {
// print("local user ${connection.localUid} joined");
if(mounted){
setState(() {
isJoined = true;
uid = userId;
});
}
showMySnackBar(context: context, content: 'You ($userId) have joined the call!');
},
userJoined: (int remoteUid, int elapsed) {
//debugPrint("remote user $remoteUid joined");
if(mounted){
setState(() {
_remoteUids.add(remoteUid);
});
}
},
userOffline: (int remoteUid, UserOfflineReason reason) {
//debugPrint("remote user $remoteUid left channel");
if(mounted){
setState(() {
_remoteUids.removeWhere((element) => element == remoteUid);
});
}
},
leaveChannel: (stats) {
if(mounted){
setState(() {
isJoined = false;
if(!widget.call.isGroupChat || _remoteUids.length == 1){
_remoteUids.clear();
}
});
}
},
// onTokenPrivilegeWillExpire: (RtcConnection connection, String token) {
// debugPrint('[onTokenPrivilegeWillExpire] connection: ${connection.toJson()}, token: $token');
// },
),
);
await _engine.setChannelProfile(ChannelProfile.LiveBroadcasting);
//await _engine.setClientRole(ClientRole.Broadcaster);
await _engine.enableVideo();
if(widget.call.isVideoCall){
await _engine.startPreview();
}
else{
await _engine.muteLocalVideoStream(true);
await _engine.muteAllRemoteVideoStreams(true);
}
_joinChannel();
}
catch(e){
showMySnackBar(context: context, content: "Init Err: "+e.toString());
}
}
#override
void dispose() {
_leaveChannel();
_engine.destroy();
super.dispose();
}
// Display remote user's video
Widget _remoteVideo() {
if (_remoteUids.isNotEmpty) {
//TODO check for video on or off or if video call:
return rtc_remote_view.SurfaceView(
uid: _remoteUids[0],
channelId: widget.call.callId,
);
}
else {
return const Text(
'Please wait for others to join',
textAlign: TextAlign.center,
);
}
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async { _leaveChannel(); return true; },
child: Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: [
Center(
child: _remoteVideo(),
),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(right: 18.0, bottom: 12),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: ColoredBox(
color: Colors.grey.shade200,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 125, maxHeight: 175),
child: AspectRatio(
aspectRatio: 9/16,
child: Center(
child: isJoined
?
( //TODO: check for video on or off or if video call:
openCamera
? rtc_local_view.SurfaceView(
channelId: widget.call.callId,
)
: const Icon(
Icons.videocam_off_rounded,
color: Colors.black,
size: appActionsIconsSize,
)
)
: const CircularProgressIndicator(),
),
),
),
),
),
),
),
],
),
),
);
}
}
I found the issue: I was not setting the ClientRoleType correctly and that caused error in finding local view. One needs to define ClientRoleType (based on your logic) and ChannelProfileType.broadcast and everything seems to work.
I am fetching the user data through the fetchUser() method on the home screen but when I update the income, it is not updated on the home screen when I navigate back. How can I make the method fetchUser be called each time I navigate to the home screen?
Or what else I can do so I can achieve this?
import 'dart:async';
import 'dart:convert';
import 'package:fin_app/apiservice/variables.dart';
import 'package:month_year_picker/month_year_picker.dart';
// import 'dart:developer';
import 'package:http/http.dart' as http;
import 'package:fin_app/screens/login_screen/components/overview_screen/top_card.dart';
import 'package:flutter/material.dart';
import '../../models/user.dart';
import '../monthly_expense/expense_app_theme.dart';
import 'input_form.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String dropdownValue = list.first;
List userData = [];
#override
void initState() {
super.initState();
fetchUser();
}
Future<User> fetchUser() async {
Map<String, String> requestHeaders = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
};
final response = await http.get(
Uri.parse('https://10.0.2.2:7014/api/user/me'),
headers: requestHeaders,
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
// income=jsonDecode(response.body)['income'];
income=jsonDecode(response.body)['profile']['income'];
return User.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
print(response.statusCode.toString());
throw Exception('Failed to load user');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ExpenseAppTheme.background,
body: Column(
children: [
SizedBox(height: 15),
TopNeuCard(balance: '\ 20,000', expense: '100'),
Expanded(
child: Container(
child: Center(
child: Column(
children: [
Container(
padding: EdgeInsets.only(left: 30.00),
alignment: Alignment.topLeft,
child: DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 100,
style: const TextStyle(
color: Color.fromARGB(255, 44, 121, 244)),
underline: Container(
height: 2,
color: Color.fromARGB(255, 44, 121, 244),
),
onChanged: (String? value) {
// This is called when the user selects an item.
setState(() {
dropdownValue = value!;
});
_fetchData();
},
items: list.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
Container(height: 275, child: _buildListView(context))
],
)),
)),
],
),
floatingActionButton: FloatingActionButton(
onPressed: navigate,
backgroundColor: Color.fromARGB(255, 121, 146, 237),
child: const Icon(Icons.add_rounded),
),
);
}
Future<void> _fetchData() async {
var apiUrl2 =
'https://10.0.2.2:7014/api/expense/me/month?month=2022%20$dropdownValue';
Map<String, String> requestHeaders = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
};
final response = await http.get(
Uri.parse(apiUrl2),
headers: requestHeaders,
);
final data = json.decode(response.body);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
setState(() {
userData = data;
});
} else if (response.statusCode == 404) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("No expenses present")));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
print(response.statusCode.toString());
throw Exception('Failed to load expenses');
}
}
Future deletePost(String id) async {
var apiUrl = 'https://10.0.2.2:7014/api/expense/me/$id';
// final res = await http.delete(Uri.parse(apiUrl));
// if (res.statusCode == 200) {
// print("Deleted");
// } else {
// throw "Sorry! Unable to delete this post.";
// }
Map<String, String> requestHeaders = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token'
};
final response = await http.delete(
Uri.parse(apiUrl),
headers: requestHeaders,
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Deleted succesfully")));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
print(response.statusCode.toString());
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Expense could not be deleted ")));
throw Exception('Failed to load expenses');
}
}
void navigate() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const FormInput()),
);
}
ListView _buildListView(BuildContext context) {
return ListView.builder(
itemCount: userData.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(userData[index]["category"]),
subtitle: Text(userData[index]["date"]),
leading: IconButton(
icon: Icon(Icons.delete),
color: Colors.red,
onPressed: () {
setState(() {
deletePost(userData[index]["id"]);
userData.removeAt(index);
});
},
),
trailing: Text(
'-' '\$' + userData[index]["amount"].toString(),
style: TextStyle(
//fontWeight: FontWeight.bold,
fontSize: 16,
color: Colors.red,
),
),
onTap: () {},
));
},
);
}
}
Change this:
void navigate() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const FormInput()),
);
}
to this:
void navigate() async {
bool result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const FormInput()),
);
if(result != null && result){
fetchUser();
}
}
then inside FormInput, pop like this:
Navigator.pop(context, true);
I need help regrading the scan using qr_code_scanner, the scanner successful but don't know how to call response either success or not. here example.
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
controller.scannedDataStream.listen((scanData) async {
controller.pauseCamera();
var response = await ScanApi.scan(scanData.code);
print(response);
result = scanData;
setState(() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("check"),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text('Data: ${scanData.code}'),
],
),
),
actions: <Widget>[
TextButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
).then((value) => controller.resumeCamera());
and my example api post to get reponse.
static Future<dynamic> scan() async {
final url = Uri.parse(url);
final response = await http.post(url);
if (response.statusCode == 200) {
final String msg = json.decode(response.body)["status"];
print(msg);
return msg;
} else {
throw Exception();
}}
code like this and calling this class into widget.
class ScanResponse {
String status;
ScanResponse({this.status});
factory ScanResponse.fromJson(Map<String, dynamic> jsonData) {
return ScanResponse(
status: jsonData['status'],
);
}
}
Here is the ProviderModel:
class UserModel extends ChangeNotifier {
User user = new User(
name: 'Loading name...',
avatarUrl:
'https://i.pinimg.com/564x/10/b2/f6/10b2f6d95195994fca386842dae53bb2.jpg',
email: 'as',
id: 'asfd',
createdAt: 'as',
jwt: 'asfe',
tasks: [
Task(
title: "Loading data..",
description: "loading data..",
isCompleted: true),
],
);
Future<String> getMyTasks() async {
final String token = user.jwt;
try {
final response = await http.get(
Uri.parse('$serverUrl/tasks?sortBy=createdAt:asc'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
},
);
var res = response.body;
return res;
} catch (e) {
print('Got an Error : $e');
}
}
void updateTasks() async {
try {
var myTasks = jsonDecode(await getMyTasks());
myTasks.forEach((task) {
Task tempTask = Task(
title: task["description"],
isCompleted: task["completed"],
description: "No description");
user.tasks.add(tempTask);
notifyListeners();
});
} catch (e) {
print('Encountered an Error while retriving tasks from the server');
print(e);
}
}
And here is the Widget that uses data from this Provider:
class AllTasks extends StatelessWidget {
#override
Widget build(BuildContext context) {
context.watch<UserModel>().updateProfile();
context.watch<UserModel>().updateTasks();
print('AllTask Widget Builded...');
return ListView.separated(
itemCount: context.watch<UserModel>().user.tasks.length,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Text((index + 1).toString()),
title: Text(context.watch<UserModel>().user.tasks[index].title,
style: GoogleFonts.ubuntu()),
subtitle: Text(
context.watch<UserModel>().user.tasks[index].description,
style: GoogleFonts.ubuntu()),
trailing: Checkbox(
value: context.watch<UserModel>().user.tasks[index].isCompleted,
onChanged: (value) {},
),
);
},
separatorBuilder: (BuildContext context, int index) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 50.0),
child: const Divider(
thickness: 1.0,
),
),
);
}
}
Can Anyone Please help me ? The build method of AllTask Widget gets rebuilded everytime Because of Which the same data from the API gets Added to the taskList Of user...And the ListView shows the same data continuously without stopping.
Is there any solution?
remove these from inside the build otherwise update tasks will get called continuously during the build resulting in a loop. you can place them in initState.
context.watch<UserModel>().updateProfile();
context.watch<UserModel>().updateTasks();
Because you're calling your functions in the build method. And build method is being called again and again, hence adding the same data in your list that you provided your ListView.builder. Remove these lines of code from the build method.
context.watch<UserModel>().updateProfile();
context.watch<UserModel>().updateTasks();