I/flutter (32524): type 'String' is not a subtype of type 'int' of 'index' - flutter

I have this error ("type 'String' is not a sub type of type 'int' of 'index'")
but i don't know where the problem is or which line, the compiler don't tell me which line the error is,
here is the code:
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<Auth>(
create: (_) =>
Auth(), //lezem nekten l auth abel l prodect li2an l prodect ya3tamed 3le
),
ChangeNotifierProxyProvider<Auth, Products>(
// 2 provider product ya3tamed 3ala auth
update: (ctx, value, previousProduct) => Products(value.token,
previousProduct==null? []: previousProduct.productsList),
),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<Auth>(
builder: (ctx, value, _) => MaterialApp(
theme: ThemeData(
primaryColor: Colors.orange,
canvasColor: Color.fromRGBO(255, 238, 219, 1)),
debugShowCheckedModeBanner: false,
home: value.isAuth? MyHomePage(): AuthScreen(),
),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isLoading = true;
#override
void initState() {
Provider.of<Products>(context, listen: false)
.fetchData()
.then((_) => _isLoading = false)
.catchError((onError) => print(onError));
super.initState();
}
Widget detailCard(id, tile, desc, price, imageUrl) {
return Builder(
builder: (innerContext) => FlatButton(
onPressed: () {
print(id);
Navigator.push(
innerContext,
MaterialPageRoute(builder: (_) => ProductDetails(id)),
).then(
(id) => Provider.of<Products>(context, listen: false).delete(id));
},
child: Column(
children: [
SizedBox(height: 5),
Card(
elevation: 10,
color: Color.fromRGBO(115, 138, 119, 1),
child: Row(
children: <Widget>[
Expanded(
flex: 3,
child: Container(
padding: EdgeInsets.only(right: 10),
width: 130,
child: Hero(
tag: id,
child: Image.network(imageUrl, fit: BoxFit.fill),
),
),
),
Expanded(
flex: 3,
child: Column(
//mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 10),
Text(
tile,
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold),
),
Divider(color: Colors.white),
Container(
width: 200,
child: Text(
desc,
style: TextStyle(color: Colors.white, fontSize: 14),
softWrap: true,
overflow: TextOverflow.fade,
textAlign: TextAlign.justify,
maxLines: 3,
),
),
Divider(color: Colors.white),
Text(
"\$$price",
style: TextStyle(color: Colors.black, fontSize: 18),
),
SizedBox(height: 13),
],
),
),
Expanded(flex: 1, child: Icon(Icons.arrow_forward_ios)),
],
),
),
],
),
),
);
}
#override
Widget build(BuildContext context) {
List<Product> prodList =
Provider.of<Products>(context, listen: true).productsList;
return Scaffold(
appBar: AppBar(title: Text('My Products')),
body: _isLoading
? Center(child: CircularProgressIndicator())
: (prodList.isEmpty
? Center(
child: Text('No Products Added.',
style: TextStyle(fontSize: 22)))
: RefreshIndicator(
onRefresh: () async =>
await Provider.of<Products>(context, listen: false)
.fetchData(),
child: ListView(
children: prodList
.map(
(item) => detailCard(item.id, item.title,
item.description, item.price, item.imageUrl),
)
.toList(),
),
)),
floatingActionButton: Container(
width: 180,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Theme.of(context).primaryColor,
),
child: FlatButton.icon(
label: Text("Add Product",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 19)),
icon: Icon(Icons.add),
onPressed: () => Navigator.push(
context, MaterialPageRoute(builder: (_) => AddProduct())),
),
),
);
}
}
product.dart
class Product {
final String id;
final String title;
final String description;
final double price;
final String imageUrl;
Product({
#required this.id,
#required this.title,
#required this.description,
#required this.price,
#required this.imageUrl,
});
}
class Products with ChangeNotifier {
List<Product> productsList = [];
final String authToken;
Products(this.authToken, this.productsList);
Future<void> fetchData() async {
final url = "https://flutter-app-568d3.firebaseio.com/product.json?auth=$authToken";
try {
final http.Response res = await http.get(url);
final extractedData = json.decode(res.body) as Map<String, dynamic>;
extractedData.forEach((prodId, prodData) {
final prodIndex =
productsList.indexWhere((element) => element.id == prodId);
if (prodIndex >= 0) {
productsList[prodIndex] = Product(
id: prodId,
title: prodData['title'],
description: prodData['description'],
price: prodData['price'],
imageUrl: prodData['imageUrl'],
);
} else {
productsList.add(Product(
id: prodId,
title: prodData['title'],
description: prodData['description'],
price: prodData['price'],
imageUrl: prodData['imageUrl'],
));
}
});
notifyListeners();
} catch (error) {
throw error;
}
}
Future<void> updateData(String id) async {
final url = "https://flutter-app-568d3.firebaseio.com/product/$id.json?auth=$authToken";
final prodIndex = productsList.indexWhere((element) => element.id == id);
if (prodIndex >= 0) {
await http.patch(url,
body: json.encode({
"title": "new title 4",
"description": "new description 2",
"price": 199.8,
"imageUrl":
"https://cdn.pixabay.com/photo/2015/06/19/21/24/the-road-815297__340.jpg",
}));
productsList[prodIndex] = Product(
id: id,
title: "new title 4",
description: "new description 2",
price: 199.8,
imageUrl:
"https://cdn.pixabay.com/photo/2015/06/19/21/24/the-road-815297__340.jpg",
);
notifyListeners();
} else {
print("...");
}
}
Future<void> add(
{String id,
String title,
String description,
double price,
String imageUrl}) async {
final url = "https://flutter-app-568d3.firebaseio.com/product.json?auth=$authToken";
try {
http.Response res = await http.post(url,
body: json.encode({
"title": title,
"description": description,
"price": price,
"imageUrl": imageUrl,
}));
print(json.decode(res.body));
productsList.add(Product(
id: json.decode(res.body)['name'],
title: title,
description: description,
price: price,
imageUrl: imageUrl,
));
notifyListeners();
} catch (error) {
throw error;
}
}
Future<void> delete(String id) async {
final url = "https://flutter-app-568d3.firebaseio.com/product/$id.json?auth=$authToken";
final prodIndex = productsList.indexWhere((element) => element.id == id);
var prodItem = productsList[prodIndex];
productsList.removeAt(prodIndex);
notifyListeners();
var res = await http.delete(url);
if (res.statusCode >= 400) {
productsList.insert(prodIndex, prodItem);
notifyListeners();
print("Could not deleted item");
} else {
prodItem = null;
print("Item deleted");
}
}
}
auth.dart
class Auth with ChangeNotifier {
String _token;
DateTime _expireDate;
String _userId;
bool get isAuth{
return token != null;
}
String get token{
if(_expireDate != null && _expireDate.isAfter(DateTime.now()) && _token != null){
return _token;
}return null;
}
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url =
"https://identitytoolkit.googleapis.com/v1/accounts:$urlSegment?key=AIzaSyAN1Z9ibJ9-HqBen65x5ALKiqsRTzFfhh8";
try {
final res = await http.post(url,
body: json.encode({
'email': email,
'password': password,
'returnSecureToken': true,
}));
print(json.decode(res.body));// byetba3 lma3lomat l rej3a ya3ni resalet l error
final resData = json.decode(res.body);
// to print the error
if(resData['error'] != null){
throw "${resData['error']['message']}";
}
_token = resData['idToken'];
_userId = resData['localId'];
_expireDate = DateTime.now().add(Duration(seconds: int.parse(resData['expiresIn'])));
notifyListeners();
} catch (e) {
throw e;
}
}
Future<void> signUp(String email, String password) async {
return _authenticate(email, password, "signUp");
}
Future<void> login(String email, String password) async {
return _authenticate(email, password, "signInWithPassword");
}
}
auth_screen.dart
enum AuthMode { SignUp, Login }
class AuthScreen extends StatelessWidget {
static const routeName = '/auth';
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return Scaffold(
// resizeToAvoidBottomInset: false,
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color.fromRGBO(215, 117, 255, 1).withOpacity(0.5),
Color.fromRGBO(255, 188, 117, 1).withOpacity(0.9),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
stops: [0, 1],
),
),
),
SingleChildScrollView(
child: Container(
height: deviceSize.height,
width: deviceSize.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
margin: EdgeInsets.only(bottom: 20.0),
padding:
EdgeInsets.symmetric(vertical: 8.0, horizontal: 94.0),
transform: Matrix4.rotationZ(-8 * pi / 180)
..translate(-10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.deepOrange.shade900,
boxShadow: [
BoxShadow(
blurRadius: 8,
color: Colors.black26,
offset: Offset(0, 2),
)
],
),
child: Text(
'MyShop',
style: TextStyle(
color: Colors.white,
fontSize: 40,
),
),
),
),
Flexible(
flex: deviceSize.width > 600 ? 2 : 1,
child: AuthCard(),
),
],
),
),
),
],
),
);
}
}
class AuthCard extends StatefulWidget {
const AuthCard({
Key key,
}) : super(key: key);
#override
_AuthCardState createState() => _AuthCardState();
}
class _AuthCardState extends State<AuthCard> {
final GlobalKey<FormState> _formKey = GlobalKey();
AuthMode _authMode = AuthMode.Login;
Map<String, String> _authData = {
'email': '',
'password': '',
};
var _isLoading = false;
final _passwordController = TextEditingController();
void _showErrorDialog(String message) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text("An Error Occurred"),
content: Text(message),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("OK")),
],
));
}
Future<void> _submit() async{
if (!_formKey.currentState.validate()) {
// Invalid!
return;
}
_formKey.currentState.save();
setState(() {
_isLoading = true;
});
try {
if (_authMode == AuthMode.Login) {
// Log user in
await Provider.of<Auth>(context, listen: false)
.login(
_authData['email'],
_authData['password'],
);
} else {
// Sign user up
await Provider.of<Auth>(context, listen: false)
.signUp(
_authData['email'],
_authData['password'],
);
}
} catch (error) {
var errorMessage = "Authentication failed";
if(error.toString().contains('EMAIL_EXISTS')){
errorMessage = 'This email address is already taken';
}else if(error.toString().contains('INVALID_EMAIL')){
errorMessage = 'This is not a valid email address';
}else if(error.toString().contains('WEAK_PASSWORD')){
errorMessage = 'This password is too weak';
} else if(error.toString().contains('EMAIL_NOT_FOUND')){
errorMessage = 'Could not find a user with that email';
} else if(error.toString().contains('INVALID_PASSWORD')){
errorMessage = 'Invalid password';
}
_showErrorDialog(errorMessage);
}
setState(() {
_isLoading = false;
});
}
void _switchAuthMode() {
if (_authMode == AuthMode.Login) {
setState(() {
_authMode = AuthMode.SignUp;
});
} else {
setState(() {
_authMode = AuthMode.Login;
});
}
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 8.0,
child: Container(
height: _authMode == AuthMode.SignUp ? 320 : 260,
constraints:
BoxConstraints(minHeight: _authMode == AuthMode.SignUp ? 320 : 260),
width: deviceSize.width * 0.75,
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'E-Mail'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Invalid email!';
}
return null;
},
onSaved: (value) {
_authData['email'] = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
validator: (value) {
if (value.isEmpty || value.length < 5) {
return 'Password is too short!';
}
return null;
},
onSaved: (value) {
_authData['password'] = value;
},
),
if (_authMode == AuthMode.SignUp)
TextFormField(
enabled: _authMode == AuthMode.SignUp,
decoration: InputDecoration(labelText: 'Confirm Password'),
obscureText: true,
validator: _authMode == AuthMode.SignUp
? (value) {
if (value != _passwordController.text) {
return 'Passwords do not match!';
}
return null;
}
: null,
),
SizedBox(
height: 20,
),
if (_isLoading)
CircularProgressIndicator()
else
RaisedButton(
child:
Text(_authMode == AuthMode.Login ? 'LOGIN' : 'SIGN UP'),
onPressed: _submit,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
padding:
EdgeInsets.symmetric(horizontal: 30.0, vertical: 8.0),
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).primaryTextTheme.button.color,
),
FlatButton(
child: Text(
'${_authMode == AuthMode.Login ? 'SIGN UP' : 'LOGIN'} INSTEAD'),
onPressed: _switchAuthMode,
padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 4),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Theme.of(context).primaryColor,
),
],
),
),
),
),
);
}
}
Compiler
Launching lib\main.dart on SM G610F in debug mode...
Running Gradle task 'assembleDebug'...
√ Built build\app\outputs\flutter-apk\app-debug.apk.
Installing build\app\outputs\flutter-apk\app.apk...
Waiting for SM G610F to report its views...
Debug service listening on ws://127.0.0.1:60889/J5CQX-fKfbs=/ws
Syncing files to device SM G610F...
I/zygote (32524): Do partial code cache collection, code=30KB, data=25KB
I/zygote (32524): After code cache collection, code=30KB, data=25KB
I/zygote (32524): Increasing code cache capacity to 128KB
D/libGLESv2(32524): STS_GLApi : DTS, ODTC are not allowed for Package : com.example.animation
D/ViewRootImpl#886418b[MainActivity](32524): ViewPostIme pointer 0
D/ViewRootImpl#886418b[MainActivity](32524): ViewPostIme pointer 1
D/InputMethodManager(32524): SSI - flag : 0 Pid : 32524 view : com.example.animation
V/InputMethodManager(32524): Starting input: tba=android.view.inputmethod.EditorInfo#9dca947 nm : com.example.animation ic=io.flutter.plugin.editing.InputConnectionAdaptor#271e574
D/InputMethodManager(32524): startInputInner - Id : 0
I/InputMethodManager(32524): startInputInner - mService.startInputOrWindowGainedFocus
D/InputTransport(32524): Input channel constructed: fd=100
D/InputTransport(32524): Input channel destroyed: fd=91
D/ViewRootImpl#886418b[MainActivity](32524): MSG_RESIZED: frame=Rect(0, 0 - 1080, 1920) ci=Rect(0, 72 - 0, 873) vi=Rect(0, 72 - 0, 873) or=1
D/ViewRootImpl#886418b[MainActivity](32524): Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x1 surface={valid=true 3430410240} changed=false
D/ViewRootImpl#886418b[MainActivity](32524): ViewPostIme pointer 0
D/ViewRootImpl#886418b[MainActivity](32524): ViewPostIme pointer 1
D/ViewRootImpl#886418b[MainActivity](32524): ViewPostIme pointer 0
I/zygote (32524): Do partial code cache collection, code=61KB, data=61KB
I/zygote (32524): After code cache collection, code=61KB, data=61KB
I/zygote (32524): Increasing code cache capacity to 256KB
D/ViewRootImpl#886418b[MainActivity](32524): ViewPostIme pointer 1
V/InputMethodManager(32524): Starting input: tba=android.view.inputmethod.EditorInfo#fb092e3 nm : com.example.animation ic=io.flutter.plugin.editing.InputConnectionAdaptor#981e4e0
D/InputMethodManager(32524): startInputInner - Id : 0
I/InputMethodManager(32524): startInputInner - mService.startInputOrWindowGainedFocus
D/InputTransport(32524): Input channel constructed: fd=94
D/InputTransport(32524): Input channel destroyed: fd=100
W/IInputConnectionWrapper(32524): getExtractedText on inactive InputConnection
D/ViewRootImpl#886418b[MainActivity](32524): ViewPostIme pointer 0
D/ViewRootImpl#886418b[MainActivity](32524): ViewPostIme pointer 1
D/InputMethodManager(32524): SSI - flag : 0 Pid : 32524 view : com.example.animation
V/InputMethodManager(32524): Starting input: tba=android.view.inputmethod.EditorInfo#391b65e nm : com.example.animation ic=io.flutter.plugin.editing.InputConnectionAdaptor#54f7a3f
D/InputMethodManager(32524): startInputInner - Id : 0
I/InputMethodManager(32524): startInputInner - mService.startInputOrWindowGainedFocus
D/InputTransport(32524): Input channel constructed: fd=97
D/InputTransport(32524): Input channel destroyed: fd=94
D/InputMethodManager(32524): HSIFW - flag : 0 Pid : 32524
D/ViewRootImpl#886418b[MainActivity](32524): MSG_RESIZED: frame=Rect(0, 0 - 1080, 1920) ci=Rect(0, 72 - 0, 0) vi=Rect(0, 72 - 0, 0) or=1
D/ViewRootImpl#886418b[MainActivity](32524): Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x1 surface={valid=true 3430410240} changed=false
D/ViewRootImpl#886418b[MainActivity](32524): ViewPostIme pointer 0
D/ViewRootImpl#886418b[MainActivity](32524): ViewPostIme pointer 1
I/flutter (32524): {kind: identitytoolkit#VerifyPasswordResponse, localId: urJPn2l2EBeHNGJ7MmcMMkCIJtf1, email: ali#gmail.com, displayName: , idToken: eyJhbGciOiJSUzI1NiIsImtpZCI6ImM0ZWFhZjkxM2VlNWY0MDY0YmE2NjUzN2M0Njk3YzY5OGE3NGYwODIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vZmx1dHRlci1hcHAtYjM0ZTAiLCJhdWQiOiJmbHV0dGVyLWFwcC1iMzRlMCIsImF1dGhfdGltZSI6MTYxNDg4MzQwMywidXNlcl9pZCI6InVySlBuMmwyRUJlSE5HSjdNbWNNTWtDSUp0ZjEiLCJzdWIiOiJ1ckpQbjJsMkVCZUhOR0o3TW1jTU1rQ0lKdGYxIiwiaWF0IjoxNjE0ODgzNDAzLCJleHAiOjE2MTQ4ODcwMDMsImVtYWlsIjoiYWxpQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJhbGlAZ21haWwuY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.XfeiI4-UqDcaugW1mQxaoQbrk-h_NclPANgKKt0w36H6Jj32mGdUV-pZ_WdXdfMRxnF9lJEt9nfe0FgQSVKyYk8oLxkEaqlNJME1BnF5wUvHEJsqpHsG89mFz77cYWw-jYcjvquvPlJYSiwIc-snEyinRPx5DZwpbIkWtGe-oqWzJyE23C5inh0yu0O52tLrEDtBHy5m9qBvCK-3HLHKJ1Phrz0Q06qdH8cxw_3-AdRPqZQ8w8F4FhVOyrB04NEqWIBs-uvjAkbjo6y3LlM5PqLebrhDSdKlUlbVYOVPotMp0UMkcDRqkuZDlFZoMRoU
D/ViewRootImpl#886418b[MainActivity](32524): Relayout returned: old=[0,0][1080,1920] new=[0,0][1080,1920] result=0x1 surface={valid=true 3430410240} changed=false
I/flutter (32524): type 'String' is not a subtype of type 'int' of 'index'
D/ViewRootImpl#886418b[MainActivity](32524): MSG_WINDOW_FOCUS_CHANGED 0
D/ViewRootImpl#886418b[MainActivity](32524): MSG_WINDOW_FOCUS_CHANGED 1
I need a help please:
what i need to know is where is the error and how to solve it.
thank you in advance

Related

Flutter application is not showing remote view while joining the Agora Channel for video calls

I am developing an application in which user can contact each other via video calls. I have setup my server on railway by following the Agora documentation. If anyone has any suggestions or know what I am doing wrong please do let me know. I have tried leaving the token empty ('') but it still gives invalid token error. The token is getting generated successfully but when users join the call. Remote view is not showing up even though the onUserJoined callback is getting triggered perfectly on both caller and receiver side.
This is the call screen code which will enable users to contact with each other
// ignore_for_file: prefer_typing_uninitialized_variables, use_build_context_synchronously
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../../constants/constants.dart';
import '../../global/firebase_ref.dart';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:wakelock/wakelock.dart';
import '../../methods/call_methods.dart';
import '../../models/call_model.dart';
import '../../services/app_services.dart';
import '../../services/connectivity_services.dart';
import '../../services/user_services.dart';
import '../../widgets/custom_images.dart';
import '../../widgets/custom_widgets.dart';
class VideoCallScreen extends StatefulWidget {
const VideoCallScreen(this.call, {Key? key}) : super(key: key);
final CallModel call;
#override
State<VideoCallScreen> createState() => _VideoCallScreenState();
}
class _VideoCallScreenState extends State<VideoCallScreen> {
final _users = <int>[];
final _infoStrings = <String>[];
bool muted = false;
RtcEngine? _engine;
bool isspeaker = true;
bool isalreadyendedcall = false;
String current = Get.find<UserServices>().adminid;
CollectionReference? reference;
String token = '';
Stream<DocumentSnapshot>? stream;
#override
void dispose() {
_users.clear();
_engine!.leaveChannel();
_engine!.release();
super.dispose();
}
getToken() async {
final url = Uri.parse(
'https://agora-token-service-production-59a1.up.railway.app/rtc/${widget.call.channelid}/1/uid/0',
);
Get.log('Token URL $url');
final response = await http.get(url);
debugPrint('Response: $response');
if (response.statusCode == 200) {
setState(() {
token = response.body;
token = jsonDecode(token)['rtcToken'];
Get.log('token: $token');
});
} else {
Get.log('Failed to fetch the token');
}
}
#override
void initState() {
initialize();
super.initState();
if (widget.call.by == current) {
reference = userRef.doc(widget.call.receiver!.id).collection('History');
stream = reference!.doc(widget.call.timeepoch.toString()).snapshots();
} else {
reference = adminRef.doc(widget.call.caller!.id).collection('History');
stream = reference!.doc(widget.call.timeepoch.toString()).snapshots();
}
}
Future<void> initialize() async {
try {
await [Permission.microphone, Permission.camera].request();
await getToken();
if (Get.find<AppServices>().appid.isEmpty) {
setState(() {
_infoStrings.add(
'Agora_APP_IDD missing, please provide your Agora_APP_IDD in app_constant.dart',
);
_infoStrings.add('Agora Engine is not starting');
});
return;
}
await _initAgoraRtcEngine();
_addAgoraEventHandlers();
VideoEncoderConfiguration configuration = const VideoEncoderConfiguration(
dimensions: VideoDimensions(height: 1920, width: 1080),
);
await _engine!.setVideoEncoderConfiguration(configuration);
Get.log('Channel id: ${widget.call.channelid}');
await _engine!.joinChannel(
token: token,
channelId: widget.call.channelid!,
uid: 0,
options: const ChannelMediaOptions(),
);
} catch (e) {
Get.log('Catch: $e');
}
}
Future<void> _initAgoraRtcEngine() async {
_engine = createAgoraRtcEngine();
await _engine!.initialize(
RtcEngineContext(
appId: Get.find<AppServices>().appid,
channelProfile: ChannelProfileType.channelProfileCommunication,
),
);
// _engine = await RtcEngine.create(Get.find<AppServices>().agoraid);
await _engine!.enableVideo();
await _engine!.enableAudio();
await _engine!.enableLocalVideo(true);
await _engine!.enableLocalAudio(true);
await _engine!.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
Get.log('---engine----');
}
var remoteid;
void _addAgoraEventHandlers() {
_engine!.registerEventHandler(
RtcEngineEventHandler(
onError: (code, value) {
setState(() {
final info = 'onErrorCode: $code';
_infoStrings.add(info);
Get.log(info);
final infp = 'onError: $value';
_infoStrings.add(infp);
Get.log(infp);
});
},
onJoinChannelSuccess: (channel, elapsed) {
setState(() {
final info = 'onJoinChannel: $channel';
_infoStrings.add(info);
Get.log(info);
});
if (widget.call.caller!.id == current) {
adminRef
.doc(widget.call.caller!.id!)
.collection('History')
.doc(widget.call.timeepoch.toString())
.set({
'TYPE': 'OUTGOING',
'ISVIDEOCALL': widget.call.video,
'PEER': widget.call.receiver!.id,
'TARGET': widget.call.receiver!.id,
'TIME': widget.call.timeepoch,
'DP': widget.call.receiver!.picture,
'ISMUTED': false,
'ISJOINEDEVER': false,
'STATUS': 'calling',
'STARTED': null,
'ENDED': null,
'CALLERNAME': widget.call.caller!.name,
'CHANNEL': channel.channelId,
'UID': channel.localUid,
}, SetOptions(merge: true)).then(
(value) => Get.log('added'),
);
userRef
.doc(widget.call.receiver!.id!)
.collection('History')
.doc(widget.call.timeepoch.toString())
.set({
'TYPE': 'INCOMING',
'ISVIDEOCALL': widget.call.video,
'PEER': widget.call.caller!.id,
'TARGET': widget.call.receiver!.id,
'TIME': widget.call.timeepoch,
'DP': widget.call.caller!.picture,
'ISMUTED': false,
'ISJOINEDEVER': true,
'STATUS': 'missedcall',
'STARTED': null,
'ENDED': null,
'CALLERNAME': widget.call.caller!.name,
'CHANNEL': channel.channelId,
'UID': channel.localUid,
}, SetOptions(merge: true));
}
Wakelock.enable();
},
onLeaveChannel: (connection, stats) {
// setState(() {
_infoStrings.add('onLeaveChannel');
_users.clear();
// });
if (isalreadyendedcall == false) {
adminRef
.doc(widget.call.caller!.id!)
.collection("History")
.doc(widget.call.timeepoch.toString())
.set({
'STATUS': 'ended',
'ENDED': DateTime.now(),
'ISMUTED': false,
'UID': -1,
}, SetOptions(merge: true));
userRef
.doc(widget.call.receiver!.id!)
.collection('History')
.doc(widget.call.timeepoch.toString())
.set({
'STATUS': 'ended',
'ENDED': DateTime.now(),
'ISMUTED': false,
'UID': -1,
}, SetOptions(merge: true));
// //----------
// userRef
// .doc(widget.call.receiver!.id)
// .collection('recent')
// .doc(widget.call.id)
// .set({
// 'id': widget.call.caller!.id,
// 'ENDED': DateTime.now().millisecondsSinceEpoch,
// 'CALLERNAME': widget.call.receiver!.name,
// }, SetOptions(merge: true));
}
Wakelock.disable();
},
onUserJoined: (connection, uid, elapsed) {
setState(() {
final info = 'userJoined: $uid';
_infoStrings.add(info);
_users.add(uid);
Get.log(info);
remoteid = uid;
Get.log(remoteid);
});
startTimerNow();
if (Get.find<UserServices>().adminid == widget.call.caller!.id) {
adminRef
.doc(widget.call.caller!.id!)
.collection('History')
.doc(widget.call.timeepoch.toString())
.set({
'STARTED': DateTime.now(),
'STATUS': 'pickedup',
'ISJOINEDEVER': true,
}, SetOptions(merge: true));
userRef
.doc(widget.call.receiver!.id!)
.collection('History')
.doc(widget.call.timeepoch.toString())
.set({
'STARTED': DateTime.now(),
'STATUS': 'pickedup',
}, SetOptions(merge: true));
}
Wakelock.enable();
},
onUserOffline: (connection, uid, elapsed) {
setState(() {
final info = 'userOffline: $uid';
_infoStrings.add(info);
_users.remove(uid);
Get.log(info);
remoteid = null;
});
if (isalreadyendedcall == false) {
adminRef
.doc(widget.call.caller!.id!)
.collection('History')
.doc(widget.call.timeepoch.toString())
.set({
'STATUS': 'ended',
'ENDED': DateTime.now(),
'ISMUTED': false,
'UID': -1,
}, SetOptions(merge: true));
userRef
.doc(widget.call.receiver!.id!)
.collection('History')
.doc(widget.call.timeepoch.toString())
.set({
'STATUS': 'ended',
'ENDED': DateTime.now(),
'ISMUTED': false,
'UID': -1,
}, SetOptions(merge: true));
//----------
// userRef
// .doc(widget.call.receiver!.id)
// .collection('recent')
// .doc(widget.call.id)
// .set({
// 'id': widget.call.caller!.id,
// 'ENDED': DateTime.now().millisecondsSinceEpoch,
// 'CALLERNAME': widget.call.receiver!.name,
// }, SetOptions(merge: true));
}
},
onFirstRemoteVideoFrame: (connection, uid, width, height, elapsed) {
setState(() {
final info = 'firstRemoteVideo: $uid ${width}x $height';
_infoStrings.add(info);
Get.log(info);
});
},
onTokenPrivilegeWillExpire: (connection, string) async {
await getToken();
await _engine!.renewToken(token);
},
),
);
}
void onCallEnd(BuildContext context) async {
await CallMethods.endCall(call: widget.call);
DateTime now = DateTime.now();
if (isalreadyendedcall == false) {
await adminRef
.doc(widget.call.caller!.id!)
.collection('History')
.doc(widget.call.timeepoch.toString())
.set({
'STATUS': 'ended',
'ENDED': now,
'ISMUTED': false,
"UID": -1,
}, SetOptions(merge: true));
await userRef
.doc(widget.call.receiver!.id!)
.collection('History')
.doc(widget.call.timeepoch.toString())
.set({
'STATUS': 'ended',
'ENDED': now,
'ISMUTED': false,
'UID': -1,
}, SetOptions(merge: true));
// //----------
// userRef
// .doc(widget.call.receiver!.id)
// .collection('recent')
// .doc(widget.call.id)
// .set({
// 'id': widget.call.caller!.id,
// 'ENDED': DateTime.now().millisecondsSinceEpoch,
// 'CALLERNAME': widget.call.receiver!.name,
// }, SetOptions(merge: true));
}
Wakelock.disable();
Navigator.pop(context);
}
Widget callView({
String status = 'calling',
bool muted = false,
int? remoteuid,
}) {
var w = MediaQuery.of(context).size.width;
var h = MediaQuery.of(context).size.height;
return Container(
alignment: Alignment.center,
decoration: status == 'pickedup'
? null
: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: providerImage(
widget.call.caller!.id == current
? widget.call.receiver!.picture ?? ''
: widget.call.caller!.picture ?? '',
),
),
),
child: Container(
color: status == 'pickedup' ? null : Colors.white.withOpacity(0.3),
child: Stack(
alignment: Alignment.center,
children: [
status != 'pickedup'
? Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: w,
height: h / 5,
alignment: Alignment.center,
margin: EdgeInsets.only(
top: MediaQuery.of(context).padding.top),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(
Icons.lock_rounded,
size: 17,
color: Colors.white38,
),
SizedBox(width: 6),
Text(
'End-to-end encrypted',
style: TextStyle(
color: Colors.white38,
fontWeight: FontWeight.w400,
fontFamily: AppStrings.opensans,
),
),
],
).marginOnly(top: 50, bottom: 7),
SizedBox(
width: w / 1.1,
child: Text(
widget.call.caller!.id ==
Get.find<UserServices>().adminid
? widget.call.receiver!.name!
: widget.call.caller!.name!,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 27,
fontFamily: AppStrings.opensans,
),
),
),
],
),
),
Text(
status == 'calling'
? widget.call.receiver!.id ==
Get.find<UserServices>().adminid
? 'Connecting...'
: 'Calling...'
: status == 'pickedup'
? '$hoursStr : $minutesStr: $secondsStr'
: status == 'ended'
? 'Call Ended'
: status == 'rejected'
? 'Rejected'
: 'Please wait...',
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 18,
fontFamily: AppStrings.opensans,
),
).marginOnly(bottom: 16, top: 10),
Stack(
children: [
widget.call.caller!.id ==
Get.find<UserServices>().adminid
? status == 'ended' || status == 'rejected'
? Container(
height: w + (w / 11),
width: w,
color: Colors.white12,
child: Icon(
status == 'ended'
? Icons.person_off
: status == 'rejected'
? Icons.call_end_rounded
: Icons.person,
size: 140,
),
)
: Container()
: status == 'ended' || status == 'rejected'
? Container(
height: w + (w / 11),
width: w,
color: Colors.white12,
child: Icon(
status == 'ended'
? Icons.person_off
: status == 'rejected'
? Icons.call_end_rounded
: Icons.person,
size: 140,
),
)
: Container(),
Positioned(
bottom: 20,
child: SizedBox(
width: w,
height: 20,
child: Center(
child: status == 'pickedup'
? muted == true
? const Text(
'Muted',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
fontFamily: AppStrings.opensans,
),
)
: const SizedBox(height: 0)
: const SizedBox(height: 0),
),
),
),
],
),
SizedBox(height: h / 6),
],
)
: _engine == null
? SizedBox()
: SizedBox(
child: AgoraVideoView(
controller: VideoViewController.remote(
rtcEngine: _engine!,
canvas: VideoCanvas(uid: remoteuid),
connection: RtcConnection(
channelId: widget.call.channelid!,
),
),
),
),
if (status == 'pickedup')
Positioned(
top: 150,
child: Text(
'$hoursStr: $minutesStr: $secondsStr',
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 18,
color: Colors.white,
fontFamily: AppStrings.opensans,
),
),
),
if (status != 'ended' || status != 'rejected')
_engine == null
? SizedBox()
: Align(
alignment: Alignment.bottomRight,
child: SizedBox(
width: 200,
height: 200,
child: AgoraVideoView(
controller: VideoViewController(
rtcEngine: _engine!,
canvas: const VideoCanvas(uid: 0),
),
),
),
),
],
),
),
);
}
onToggleMute() {
setState(() {
muted = !muted;
});
_engine!.muteLocalAudioStream(muted);
reference!
.doc(widget.call.timeepoch.toString())
.set({'ISMUTED': muted}, SetOptions(merge: true));
}
onSwitchCamera() => setState(() => _engine!.switchCamera());
Widget toolbar({String status = 'calling'}) {
return Container(
alignment: Alignment.bottomCenter,
padding: const EdgeInsets.symmetric(vertical: 35),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
status != 'ended' && status != 'rejected'
? SizedBox(
width: 65.67,
child: RawMaterialButton(
onPressed: onToggleMute,
shape: const CircleBorder(),
elevation: 2.0,
fillColor: muted ? Colors.blueAccent : Colors.white,
padding: const EdgeInsets.all(12.0),
child: Icon(
muted ? Icons.mic_off : Icons.mic,
color: muted ? Colors.white : Colors.blueAccent,
size: 22.0,
),
),
)
: const SizedBox(height: 42, width: 65.67),
SizedBox(
width: 65.67,
child: RawMaterialButton(
onPressed: () async {
Get.log('--on call end---');
setState(() {
isalreadyendedcall =
status == 'ended' || status == 'rejected' ? true : false;
onCallEnd(context);
});
},
shape: const CircleBorder(),
elevation: 2.0,
fillColor: status == 'ended' || status == 'rejected'
? Colors.black
: Colors.redAccent,
padding: const EdgeInsets.all(15.0),
child: Icon(
status == 'ended' || status == 'rejected'
? Icons.close
: Icons.call,
color: Colors.white,
size: 35.0,
),
),
),
status == 'ended' || status == 'rejected'
? const SizedBox(width: 65.67)
: SizedBox(
width: 65.67,
child: RawMaterialButton(
onPressed: onSwitchCamera,
shape: const CircleBorder(),
elevation: 2.0,
fillColor: Colors.white,
padding: const EdgeInsets.all(12.0),
child: const Icon(
Icons.switch_camera,
color: Colors.blueAccent,
size: 20.0,
),
),
),
],
),
);
}
Widget panel() {
return Container(
padding: const EdgeInsets.symmetric(vertical: 48),
alignment: Alignment.bottomCenter,
child: FractionallySizedBox(
heightFactor: 0.5,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 48),
child: ListView.builder(
reverse: true,
itemCount: _infoStrings.length,
itemBuilder: (BuildContext context, int index) {
if (_infoStrings.isEmpty) return const SizedBox();
return Padding(
padding:
const EdgeInsets.symmetric(vertical: 3, horizontal: 10),
child: Text(_infoStrings[index]),
);
},
),
),
),
);
}
#override
Widget build(BuildContext context) {
return Obx(
() => Get.find<ConnectivityService>().connectionStatus.value ==
ConnectivityResult.none
? const DisconnectedWidget()
: Scaffold(
body: Stack(
children: [
_engine == null
? Center(
child: Stack(
children: [callView(), panel(), toolbar()],
),
)
: StreamBuilder<DocumentSnapshot>(
stream: stream as Stream<DocumentSnapshot>,
builder: (context, snapshot) {
if (snapshot.hasData &&
snapshot.data!.data() != null &&
snapshot.data != null) {
var doc = snapshot.data!;
Get.log(doc.toString());
return Center(
child: Stack(
children: [
callView(
status: doc['STATUS'],
muted: doc['ISMUTED'],
remoteuid: doc['UID'],
),
panel(),
toolbar(status: doc['STATUS']),
],
),
);
}
return Center(
child: Stack(
children: [callView(), panel(), toolbar()],
),
);
},
),
],
),
),
);
}
}
I didn't set it up with a rails server but it should work the same. On the flutter side im calling a function at the very first point:
final token = await createToken(channelName, userId);
channel name to identify the channel for the users and a userId of my user who should be able to join the channel.
Future<dynamic> createToken(String channelName, int uid) async {
try {
//404
// final response = await dio.get('${url}/api/video/create-token?agChannelName=$channelName&agRole=$role&agUid=$uid&agExpireTime=$expireTime');
final response = await dio.get(
'${url}/api/video/create-token?agChannelName=$channelName&agUid=$uid');
print('res is ${response.data["token"]}');
return response.data["token"];
} on DioError catch (e) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx and is also not 304.
if (e.response != null) {
//print(HttpException(e.response!.data["message"]));
return e.response!.data;
//print(e.response!.headers);
//print(e.response!.requestOptions);
} else {
// Something happened in setting up or sending the request that triggered an Error
//print(e.requestOptions);
print('get events: ${e.message}');
}
}
}
On my server side where im using a javascript framework, im doing the following:
...
const token = RtcTokenBuilder.buildTokenWithUid(
process.env.AGORA_APP_ID,
process.env.AGORA_APP_CERTIFICATE,
channelName,
uid,
RtcRole.PUBLISHER,
privilegeExpireTime
);
console.log(token)
return res.status(201).json({ token: token });
For that im using the agora-access-token library on npm https://www.npmjs.com/package/agora-access-token

Translate chat message based on language that user picks from drop down list

I am trying to get messages translated in real-time in the chat portion of my app depending on the language that the user picks in real-time. For example, if the user only speaks Spanish but messages from the user that they are chatting with are in English, then the user can select 'Spanish' from the dropdown list and all messages that have already been received and all future messages that they will receive will be translated into Spanish. I am capturing the sent message and its translation in each language in firebase but not sure how to get the messages to actually translate on the frontend. Any help would be much appreciated. Thank you in advance!
chat.dart
class Chat extends StatelessWidget {
final String? peerId;
final String? peerAvatar;
final String? name;
Chat({Key? key, this.peerId, this.peerAvatar, this.name}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: SkapeColors.pageBackgroundFifth,
resizeToAvoidBottomInset: true,
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.white,
),
backgroundColor: SkapeColors.pageBackground,
title: Text(
name!,
textAlign: TextAlign.start,
style: TextStyle(fontFamily: 'Brand-Bold', fontWeight: FontWeight.bold, color: Colors.white, fontSize: 25),
),
centerTitle: true,
),
body: ChatScreen(
peerId: peerId,
peerAvatar: peerAvatar,
name: name,
),
);
}
}
class ChatScreen extends StatefulWidget {
final String? peerId;
final String? peerAvatar;
final String? name;
ChatScreen({Key? key, this.peerId, this.peerAvatar, this.name})
: super(key: key);
#override
State createState() =>
ChatScreenState(peerId: peerId, peerAvatar: peerAvatar);
}
class ChatScreenState extends State<ChatScreen> {
ChatScreenState({Key? key, this.peerId, this.peerAvatar, this.name});
String? peerId;
String? peerAvatar;
String? name;
String? id;
String? language1 = Translations.languages.first;
String? language2 = Translations.languages.first;
final translator = GoogleTranslator();
static final _apiKey = 'hidden';
List<QueryDocumentSnapshot> listMessage = new List.from([]);
int _limit = 20;
int _limitIncrement = 20;
String groupChatId = "";
SharedPreferences? prefs;
File? imageFile;
bool isLoading = false;
bool isShowSticker = false;
String imageUrl = "";
final TextEditingController textEditingController = TextEditingController();
final ScrollController listScrollController = ScrollController();
final FocusNode focusNode = FocusNode();
_scrollListener() {
if (listScrollController.offset >=
listScrollController.position.maxScrollExtent &&
!listScrollController.position.outOfRange) {
setState(() {
_limit += _limitIncrement;
});
}
}
#override
void initState() {
super.initState();
focusNode.addListener(onFocusChange);
listScrollController.addListener(_scrollListener);
readLocal();
}
readLocal() async {
prefs = await SharedPreferences.getInstance();
id = await getUserID();
if (id.hashCode <= peerId.hashCode) {
groupChatId = '$id-$peerId';
} else {
groupChatId = '$peerId-$id';
}
FirebaseFirestore.instance
.collection('users')
.doc(id)
.update({'chattingWith': peerId});
setState(() {});
}
static Future<String> translate(String message, String toLanguageCode) async {
final response = await http.post(
Uri.parse('https://translation.googleapis.com/language/translate/v2?target=$toLanguageCode&key=$_apiKey&q=$message'),
);
if (response.statusCode == 200) {
final body = json.decode(response.body);
final translations = body['data']['translations'] as List;
final translation = translations.first;
return HtmlUnescape().convert(translation['translatedText']);
} else {
throw Exception();
}
}
static Future<String> translate2(
String message, String fromLanguageCode, String toLanguageCode) async {
final translation = await GoogleTranslator().translate(
message,
from: fromLanguageCode,
to: toLanguageCode,
);
return translation.text;
}
Future<void> onSendMessage(String content, int type) async {
// type: 0 = text, 1 = image, 2 = sticker
if (content.trim() != '') {
textEditingController.clear();
var documentReference = FirebaseFirestore.instance
.collection('messages')
.doc(groupChatId)
.collection(groupChatId)
.doc(DateTime.now().millisecondsSinceEpoch.toString());
FirebaseFirestore.instance.runTransaction((transaction) async {
transaction.set(
documentReference,
{
'idFrom': id,
'idTo': peerId,
'timestamp': DateTime.now().millisecondsSinceEpoch.toString(),
'content': content,
'translated': {
'english': await translate(content, 'en'),
'spanish': await translate(content, 'es'),
'german': await translate(content, 'de'),
'french': await translate(content, 'fr'),
'russian': await translate(content, 'ru'),
'italian': await translate(content, 'it'),
'selectedTranslation': language1,
},
'type': type
},
);
});
listScrollController.animateTo(0.0,
duration: Duration(milliseconds: 300), curve: Curves.easeOut);
try {
String body = content;
if (content.contains("firebasestorage")) {
body = "Image";
}
var tempResp = await getUserInformation();
await sendNotificationToUser(
peerId, "New message from " + tempResp["fullName"], body);
} catch (e) {
print(e);
}
} else {
Fluttertoast.showToast(
msg: 'Nothing to send. Please insert your message',
backgroundColor: Colors.white24,
textColor: SkapeColors.colorPrimary);
}
}
Widget buildItem(int index, DocumentSnapshot document) {
String language1 = Translations.languages.first;
String language2 = Translations.languages.first;
if (document != null) {
if (document.get('idFrom') == id) {
// Right (my message)
return Row(
children: <Widget>[
document.get('type') == 0
// Text
? Container(
child: TranslationWidget(
message: document.get('content'),
fromLanguage: language1,
toLanguage: language1,
builder: (translatedMessage)=> MessageWidget(message: document.get('content'), translatedMessage: document.get('content'), isMe: true),
),
padding: EdgeInsets.fromLTRB(5.0, 5.0, 5.0, 5.0),
width: 215.0,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondary,
borderRadius: BorderRadius.circular(8.0)),
margin: EdgeInsets.only(
bottom: isLastMessageRight(index) ? 20.0 : 10.0,
right: 10.0),
)
: document.get('type') == 1
// Image
? Container(
child: OutlinedButton(
child: Material(
child: Image.network(
document.get("content"),
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) return child;
return Container(
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
),
width: 200.0,
height: 200.0,
child: Center(
child: CircularProgressIndicator(
color: SkapeColors.colorPrimary,
value: loadingProgress
.expectedTotalBytes !=
null &&
loadingProgress
.expectedTotalBytes !=
null
? loadingProgress
.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
),
);
},
width: 200.0,
height: 200.0,
fit: BoxFit.cover,
),
borderRadius:
BorderRadius.all(Radius.circular(8.0)),
clipBehavior: Clip.hardEdge,
),
onPressed: () {
print("here");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FullPhoto(
url: document.get('content'),
),
),
);
},
// Sticker
: Container(
child: Image.asset(
'images/${document.get('content')}.gif',
width: 100.0,
height: 100.0,
fit: BoxFit.cover,
),
margin: EdgeInsets.only(
bottom: isLastMessageRight(index) ? 20.0 : 10.0,
right: 10.0),
),
],
mainAxisAlignment: MainAxisAlignment.end,
);
} else {
// Left (peer message)
return Container(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
isLastMessageLeft(index)
? Material(
child: Image.network(
peerAvatar!,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: CircularProgressIndicator(
color: SkapeColors.colorPrimary,
value: loadingProgress.expectedTotalBytes !=
null &&
loadingProgress.expectedTotalBytes !=
null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
);
},
errorBuilder: (context, object, stackTrace) {
return Image.asset(
'images/user_icon.png',
height: 50,
width: 50,
);
},
width: 40,
height: 40,
fit: BoxFit.cover,
),
borderRadius: BorderRadius.all(
Radius.circular(35.0),
),
clipBehavior: Clip.hardEdge,
)
: Container(width: 35.0),
document.get('type') == 0
? Container(
child:
TranslationWidget(
message: document.get('content'),
fromLanguage: language1,
toLanguage: language1,
builder: (translatedMessage)=> MessageWidget(message: document.get('content'), translatedMessage: document.get('content'), isMe: false),
),
padding: EdgeInsets.fromLTRB(10.0, 5.0, 5.0, 5.0),
width: 215.0,
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.circular(8.0)),
margin: EdgeInsets.only(
bottom: isLastMessageRight(index) ? 20.0 : 10.0,
right: 10.0),
).paddingOnly(left: 12)
: document.get('type') == 1
? Container(
child: TextButton(
child: Material(
child: Image.network(
document.get('content'),
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) return child;
return Container(
decoration: BoxDecoration(
color: Colors.grey,
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
),
width: 200.0,
height: 200.0,
child: Center(
child: CircularProgressIndicator(
color: SkapeColors.colorPrimary,
value: loadingProgress
.expectedTotalBytes !=
null &&
loadingProgress
.expectedTotalBytes !=
null
? loadingProgress
.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes!
: null,
),
),
);
},
width: 200.0,
height: 200.0,
fit: BoxFit.cover,
),
borderRadius:
BorderRadius.all(Radius.circular(8.0)),
clipBehavior: Clip.hardEdge,
),
onPressed: () {
},
)
: Container(
),
],
),
)
],
crossAxisAlignment: CrossAxisAlignment.start,
),
margin: EdgeInsets.only(bottom: 2.0),
);
}
} else {
return SizedBox.shrink();
}
}
bool isLastMessageLeft(int index) {
if ((index > 0 && listMessage[index - 1].get('idFrom') == id) ||
index == 0) {
return true;
} else {
return false;
}
}
bool isLastMessageRight(int index) {
if ((index > 0 && listMessage[index - 1].get('idFrom') != id) ||
index == 0) {
return true;
} else {
return false;
}
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: ()=> Future.value(true),
child: Stack(
children: <Widget>[
Column(
children: <Widget>[
// List of messages
buildListMessage(),
// Input content
buildInput(),
],
),
// Loading
buildLoading()
],
),
// onWillPop: onBackPress,
);
}
Widget buildLoading() {
return Positioned(
child: isLoading ? const Loading() : Container(),
);
}
Widget buildInput() {
return Container(
child: SingleChildScrollView(
child: Column(
children: [
buildTitle().paddingBottom(10),
Row(
),
SizedBox(width: 10,),
Flexible(
child: Container(
child: TextField(
cursorColor: SkapeColors.colorPrimary,
autocorrect: true,
onSubmitted: (value) {
onSendMessage(textEditingController.text, 0);
},
style: TextStyle(color: Colors.white, fontSize: 18.0),
controller: textEditingController,
decoration: InputDecoration.collapsed(
hintText: 'Send Message....',
hintStyle: TextStyle(color: SkapeColors.colorTextSemiLight),
),
focusNode: focusNode,
),
),
),
// Button send message
color: SkapeColors.pageBackground,
),
],
),
],
),
),
width: double.infinity,
height: 155.0,
// height: 100,
);
}
Widget buildListMessage() {
return Flexible(
child: groupChatId.isNotEmpty
? StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('messages')
.doc(groupChatId)
.collection(groupChatId)
.orderBy('timestamp', descending: true)
.limit(_limit)
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
listMessage.addAll(snapshot.data!.docs);
return ListView.builder(
padding: EdgeInsets.all(10.0),
itemBuilder: (context, index) => buildItem(index, snapshot.data!.docs[index]),
itemCount: snapshot.data?.docs.length,
reverse: true,
controller: listScrollController,
);
} else {
return Center(
child: CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<Color>(SkapeColors.colorPrimary),
),
);
}
},
)
: Center(
child: CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<Color>(SkapeColors.colorPrimary),
),
),
);
}
Widget buildTitle() => TitleWidget(
language1: language1,
onChangedLanguage1: (newLanguage) => setState(() {
language1 = newLanguage;
}), key: ValueKey(DropDownWidget),
);
}
TitleWidget.dart
import 'package:flutter/material.dart';
import '../screens/messaging/chatWidgets/DropDownWidget.dart';
class TitleWidget extends StatelessWidget {
final String? language1;
final ValueChanged<String?> onChangedLanguage1;
const TitleWidget({
required this.language1,
required this.onChangedLanguage1,
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) => Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.translate, color: Colors.grey, size: 30,),
SizedBox(width: 12,),
DropDownWidget(
value: language1??"",
onChangedLanguage: onChangedLanguage1, key: key!,
),
],
);
}
translations.dart
class Translations {
static final languages = <String>[
'English',
'Spanish',
'French',
'German',
'Italian',
'Russian'
];
static String getLanguageCode(String language) {
switch (language) {
case 'English':
return 'en';
case 'French':
return 'fr';
case 'Italian':
return 'it';
case 'Russian':
return 'ru';
case 'Spanish':
return 'es';
case 'German':
return 'de';
default:
return 'en';
}
}
}
MessageWidget.dart
import 'package:flutter/material.dart';
class MessageWidget extends StatelessWidget {
final String? message;
final String? translatedMessage;
final bool isMe;
const MessageWidget({
required this.message,
required this.translatedMessage,
required this.isMe,
});
#override
Widget build(BuildContext context) {
final radius = Radius.circular(4);
final borderRadius = BorderRadius.all(radius);
return Row(
//To align at different positions based on if message is from the user or not
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
// padding: EdgeInsets.only(right: 10),
// margin: EdgeInsets.only(right: 10),
constraints: BoxConstraints(maxWidth: 190),
decoration: BoxDecoration(
color: isMe ? Theme.of(context).colorScheme.secondary : Colors.grey,
borderRadius: isMe
? borderRadius.subtract(BorderRadius.only(bottomRight: radius))
: borderRadius.subtract(BorderRadius.only(bottomLeft: radius)),
),
child: buildMessage(),
),
],
);
}
Widget buildMessage() => Column(
crossAxisAlignment:
isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: <Widget>[
// Text(
// message,
// style: TextStyle(
// color: isMe ? Colors.black54 : Colors.white70,
// fontSize: 14,
// ),
// textAlign: isMe ? TextAlign.end : TextAlign.start,
// ),
Text(
translatedMessage!,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.start,
),
],
);
}
TranslationWidget.dart
class TranslationWidget extends StatefulWidget {
final String? message;
final String? fromLanguage;
final String? toLanguage;
final Widget Function(String? translation) builder;
const TranslationWidget({
required this.message,
required this.fromLanguage,
required this.toLanguage,
required this.builder,
Key? key,
}) : super(key: key);
#override
_TranslationWidgetState createState() => _TranslationWidgetState();
}
class _TranslationWidgetState extends State<TranslationWidget> {
String? translation;
#override
Widget build(BuildContext context) {
// final fromLanguageCode = Translations.getLanguageCode(widget.fromLanguage);
final toLanguageCode = Translations.getLanguageCode(widget.toLanguage!);
return FutureBuilder(
future: TranslationApi.translate(widget.message!, toLanguageCode),
//future: TranslationApi.translate2(
// widget.message, fromLanguageCode, toLanguageCode),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return buildWaiting();
default:
if (snapshot.hasError) {
translation = 'Could not translate due to Network problems';
} else {
translation = snapshot.data!;
}
return widget.builder(translation??"");
}
},
);
}
Widget buildWaiting() =>
translation == null ? Container() : widget.builder(translation??"");
}

Why I can't see the result of "print()" statement in my Flutter code?

I am trying to write a simple signup/login page. The following codes are the main.dart, screen page for the view and the auth_controller for the control page of the project.
main.dart:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Auth(),
),
],
child: Consumer<Auth>(
builder: (ctx, auth, _) => MaterialApp(
title: 'MyShop',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.deepOrange,
fontFamily: 'Lato',
),
home: auth.isAuth
? MapScreen()
: FutureBuilder(
future: auth.tryAutoLogin(),
builder: (ctx, authResultSnapshot) =>
authResultSnapshot.connectionState ==
ConnectionState.waiting
? SplashScreen()
: AuthScreen(),
),
routes: {
MapScreen.routeName: (ctx) => MapScreen(),
},
),
),
);
}
}
auth_screen.dart:
enum AuthMode { Signup, Login }
class AuthScreen extends StatelessWidget {
static const routeName = '/auth';
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
// final transformConfig = Matrix4.rotationZ(-8 * pi / 180);
// transformConfig.translate(-10.0);
return Scaffold(
// resizeToAvoidBottomInset: false,
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
const Color.fromRGBO(215, 117, 255, 1).withOpacity(0.5),
const Color.fromRGBO(255, 188, 117, 1).withOpacity(0.9),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
stops: const [0, 1],
),
),
),
SingleChildScrollView(
child: Container(
height: deviceSize.height,
width: deviceSize.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
margin: const EdgeInsets.only(bottom: 20.0),
padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 94.0),
transform: Matrix4.rotationZ(-8 * pi / 180)
..translate(-10.0),
// ..translate(-10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.deepOrange.shade900,
boxShadow: const [
BoxShadow(
blurRadius: 8,
color: Colors.black26,
offset: Offset(0, 2),
)
],
),
child: Text(
'USmobile',
style: TextStyle(
color: Theme.of(context)
.textSelectionTheme
.selectionColor,
fontSize: 50,
fontFamily: 'Anton',
fontWeight: FontWeight.normal,
),
),
),
),
Flexible(
flex: deviceSize.width > 600 ? 2 : 1,
child: const AuthCard(),
),
],
),
),
),
],
),
);
}
}
class AuthCard extends StatefulWidget {
const AuthCard({
Key? key,
}) : super(key: key);
#override
_AuthCardState createState() => _AuthCardState();
}
class _AuthCardState extends State<AuthCard>
with SingleTickerProviderStateMixin {
final GlobalKey<FormState> _formKey = GlobalKey();
AuthMode _authMode = AuthMode.Login;
Map<String, String> _authData = {
'email': '',
'password': '',
};
var _isLoading = false;
final _passwordController = TextEditingController();
AnimationController? _controller;
Animation<Offset>? _slideAnimation;
Animation<double>? _opacityAnimation;
#override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(
milliseconds: 300,
),
);
_slideAnimation = Tween<Offset>(
begin: const Offset(0, -1.5),
end: const Offset(0, 0),
).animate(
CurvedAnimation(
parent: _controller as Animation<double>,
curve: Curves.fastOutSlowIn,
),
);
_opacityAnimation = Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _controller as Animation<double>,
curve: Curves.easeIn,
),
);
// _heightAnimation.addListener(() => setState(() {}));
}
#override
void dispose() {
super.dispose();
_controller!.dispose();
}
void _showErrorDialog(String message) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('An Error Occurred!'),
content: Text(message),
actions: <Widget>[
TextButton(
child: const Text('Okay'),
onPressed: () {
Navigator.of(ctx).pop();
},
)
],
),
);
}
Future<void> _submit() async {
if (!_formKey.currentState!.validate()) {
// Invalid!
return;
}
_formKey.currentState!.save();
setState(() {
_isLoading = true;
});
try {
if (_authMode == AuthMode.Login) {
// Log user in
await Provider.of<Auth>(context, listen: false).login(
_authData['email'] as String,
_authData['password'] as String,
);
} else {
// Sign user up
await Provider.of<Auth>(context, listen: false).signup(
_authData['email'] as String,
_authData['password'] as String,
);
}
// } on HttpException catch (error) {
// var errorMessage = 'Authentication failed';
// print("this is the auth data");
// print(_authData);
// if (error.toString().contains('EMAIL_EXISTS')) {
// errorMessage = 'This email address is already in use.';
// } else if (error.toString().contains('INVALID_EMAIL')) {
// errorMessage = 'This is not a valid email address';
// } else if (error.toString().contains('WEAK_PASSWORD')) {
// errorMessage = 'This password is too weak.';
// } else if (error.toString().contains('EMAIL_NOT_FOUND')) {
// errorMessage = 'Could not find a user with that email.';
// } else if (error.toString().contains('INVALID_PASSWORD')) {
// errorMessage = 'Invalid password.';
// }
// _showErrorDialog(errorMessage);
} catch (error) {
var errorMessage = 'Could not authenticate you. Please try again later.' +
error.toString();
_showErrorDialog(errorMessage);
}
setState(() {
_isLoading = false;
});
}
void _switchAuthMode() {
if (_authMode == AuthMode.Login) {
setState(() {
_authMode = AuthMode.Signup;
});
_controller!.forward();
} else {
setState(() {
_authMode = AuthMode.Login;
});
_controller!.reverse();
}
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 8.0,
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
height: _authMode == AuthMode.Signup ? 320 : 260,
// height: _heightAnimation.value.height,
constraints:
BoxConstraints(minHeight: _authMode == AuthMode.Signup ? 320 : 260),
width: deviceSize.width * 0.75,
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'E-Mail'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value!.isEmpty || !value.contains('#')) {
return 'Invalid email!';
}
},
onSaved: (value) {
_authData['email'] = value as String;
},
),
TextFormField(
decoration: const InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
validator: (value) {
if (value!.isEmpty || value.length < 5) {
return 'Password is too short!';
}
},
onSaved: (value) {
_authData['password'] = value as String;
},
),
AnimatedContainer(
constraints: BoxConstraints(
minHeight: _authMode == AuthMode.Signup ? 60 : 0,
maxHeight: _authMode == AuthMode.Signup ? 120 : 0,
),
duration: const Duration(milliseconds: 300),
curve: Curves.easeIn,
child: FadeTransition(
opacity: _opacityAnimation as Animation<double>,
child: SlideTransition(
position: _slideAnimation as Animation<Offset>,
child: TextFormField(
enabled: _authMode == AuthMode.Signup,
decoration: const InputDecoration(
labelText: 'Confirm Password'),
obscureText: true,
validator: _authMode == AuthMode.Signup
? (value) {
if (value != _passwordController.text) {
return 'Passwords do not match!';
}
}
: null,
),
),
),
),
const SizedBox(
height: 20,
),
if (_isLoading)
const CircularProgressIndicator()
else
ElevatedButton(
child:
Text(_authMode == AuthMode.Login ? 'LOGIN' : 'SIGN UP'),
onPressed: _submit,
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
primary: Theme.of(context).primaryColor,
padding: const EdgeInsets.symmetric(
horizontal: 30.0, vertical: 8.0),
onPrimary:
Theme.of(context).primaryTextTheme.button!.color,
),
),
TextButton(
child: Text(
'${_authMode == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} '),
onPressed: _switchAuthMode,
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 30.0, vertical: 4),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
textStyle: TextStyle(color: Theme.of(context).primaryColor),
),
),
],
),
),
),
),
);
}
}
auth_controller.dart:
class Auth with ChangeNotifier {
String? _token;
DateTime? _expiryDate;
String? _userId;
Timer? _authTimer;
bool get isAuth {
return token != null;
}
String? get token {
if (_expiryDate != null &&
_expiryDate!.isAfter(DateTime.now()) &&
_token != null) {
return _token;
}
return null;
}
String? get userId {
return _userId;
}
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url = Uri.parse('http://10.0.2.2:8000/api/$urlSegment');
try {
final http.Response response = await http.post(
url,
headers: {"Content-Type": "application/json"},
body: json.encode(
{
'email': email,
'password': password,
//'returnSecureToken': true,
},
),
);
print("This is response.body");
print(response.body);
print("This is response.body.runtimeType");
print(response.body.runtimeType);
final responseData = json.decode(response.body);
print("this is responseData");
print(responseData);
print("this is responseData['error']");
print(responseData['error']);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
} else {
print("There wasn't error here!");
}
_token = responseData['idToken'];
print("This is the token");
print(_token);
_userId = responseData['id'];
print("This is userId");
print(_userId);
print("This is expiryDate");
print(responseData['expiresIn']);
_expiryDate = DateTime.now().add(
Duration(
seconds: int.parse(
responseData['expiresIn'],
),
),
);
print("I can no see thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis");
_autoLogout();
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode(
{
'token': _token,
'userId': _userId,
'expiryDate': _expiryDate!.toIso8601String(),
},
);
prefs.setString('userData', userData);
} catch (error) {
throw error;
}
}
Future<void> signup(String email, String password) async {
return _authenticate(email, password, 'register');
}
Future<void> login(String email, String password) async {
return _authenticate(email, password, 'verifyPassword');
}
Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('userData')) {
return false;
}
final extractedUserData = json.decode(prefs.getString('userData') as String)
as Map<String, Object>;
final expiryDate =
DateTime.parse(extractedUserData['expiryDate'] as String);
if (expiryDate.isBefore(DateTime.now())) {
return false;
}
_token = extractedUserData['token'] as String;
_userId = extractedUserData['userId'] as String;
_expiryDate = expiryDate;
notifyListeners();
_autoLogout();
return true;
}
Future<void> logout() async {
_token = null;
_userId = null;
_expiryDate = null;
if (_authTimer != null) {
_authTimer!.cancel();
_authTimer = null;
}
notifyListeners();
final prefs = await SharedPreferences.getInstance();
// prefs.remove('userData');
prefs.clear();
}
void _autoLogout() {
if (_authTimer != null) {
_authTimer!.cancel();
}
final timeToExpiry = _expiryDate!.difference(DateTime.now()).inSeconds;
_authTimer = Timer(Duration(seconds: timeToExpiry), logout);
}
}
I know the backend part works fine and the following is the result I do get while running my app and try to register a new user through the Android Emulator:
I/flutter ( 6814): This is response.body
I/flutter ( 6814): {"id":"619c5141e08b15bf9173ab06","name":"","email":"test#testing.com","password":"$2a$10$yYUtDS1PrSAgpQBxoVm7Ae7O8ujR33ONz4gM5t7iHWt6e907pjFrq","idToken":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0ZXN0QHRlc3RpbmcuY29tIiwiZXhwIjoxNjM5Mjc1NjAzNzQzfQ.LgrlwFNrLhGr5UfHikL83e2tBjbqMyN4OKG6Fz816AeOs6ezfnhvQoXBDAsV2pIt4CWuBVf8qGbBYSXCQxgarw","expiresIn":1639275603743}
I/flutter ( 6814): This is response.body.runtimeType
I/flutter ( 6814): String
I/flutter ( 6814): this is responseData
I/flutter ( 6814): {id: 619c5141e08b15bf9173ab06, name: , email: test#testing.com, password: $2a$10$yYUtDS1PrSAgpQBxoVm7Ae7O8ujR33ONz4gM5t7iHWt6e907pjFrq, idToken: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0ZXN0QHRlc3RpbmcuY29tIiwiZXhwIjoxNjM5Mjc1NjAzNzQzfQ.LgrlwFNrLhGr5UfHikL83e2tBjbqMyN4OKG6Fz816AeOs6ezfnhvQoXBDAsV2pIt4CWuBVf8qGbBYSXCQxgarw, expiresIn: 1639275603743}
I/flutter ( 6814): this is responseData['error']
I/flutter ( 6814): null
I/flutter ( 6814): There wasn't error here!
I/flutter ( 6814): This is the token
I/flutter ( 6814): eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0ZXN0QHRlc3RpbmcuY29tIiwiZXhwIjoxNjM5Mjc1NjAzNzQzfQ.LgrlwFNrLhGr5UfHikL83e2tBjbqMyN4OKG6Fz816AeOs6ezfnhvQoXBDAsV2pIt4CWuBVf8qGbBYSXCQxgarw
I/flutter ( 6814): This is userId
I/flutter ( 6814): 619c5141e08b15bf9173ab06
I/flutter ( 6814): This is expiryDate
I/flutter ( 6814): 1639275603743
I see all the print() statements work except this:
print("I can no see thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis");
I don't know why? I also see the following error message in my Android Emulator that I can't understand the reason?
type 'int' is not a subtype of type 'String'
I also know the error occures in this part of the code in auth_controller.dart file:
} catch (error) {
print(error);
throw error;
}
int.parse(
responseData['expiresIn'],
)
For the above code to work responseData['expiresIn'] should be a String. But in the response, this comes as an int value. Make sure this is a String.
Or you can just use it like this,
Duration(
seconds: responseData['expiresIn'],
),

Is it possible to POST Data using localhost woocommerce rest api in flutter

Is it possible to POST data from flutter app to woocommerce localhost using woocommerce localhost server rest api.
i have GET & POST data with private domain but i want to POST & GET data with localhost woocommerce rest api. i have setup my wordpress and woocommerce on localhost I am trying to make flutter ecommerce app and trying to GET & POST data from woocommerce localhost. but its not working and i dont want to send from private domain rest api, i can get data on postman if i select OAuth 1.0 but if i dont use OAuth 1.0 i cant get data.
Config.dart
class Config {
static String key =
'ck_00000000000000000000000000';
static String sceret =
'cs_00000000000000000000000000';
static String url = 'http://10.0.2.2:80/wordpress_new/wp-json/wc/v3/';
static String customerURL = 'customers';
}
customer.dart
class CustomerModel {
String email;
String firstName;
String lastName;
String password;
CustomerModel({
this.email,
this.firstName,
this.lastName,
this.password,
});
Map<String, dynamic> toJson() {
Map<String, dynamic> map = {};
map.addAll({
'email': email,
'first_name': firstName,
'last_name': lastName,
'password': password,
'username': email,
});
return map;
}
}
apiservice.dart
class APIService {
Future<bool> createCustomer(CustomerModel model) async {
var authToken = base64.encode(
utf8.encode(Config.key + ':' + Config.sceret),
);
bool ret = false;
try {
var response = await Dio().post(
Config.url +
Config.customerURL,
data: model.toJson(),
options: new Options(headers: {
HttpHeaders.authorizationHeader: 'Basic $authToken',
HttpHeaders.contentTypeHeader: 'application/json',
}));
if (response.statusCode == 201) {
ret = true;
}
} on DioError catch (e) {
if (e.response.statusCode == 404) {
print(e.response.statusCode);
ret = false;
} else {
print(e.message);
print(e.request);
ret = false;
}
}
return ret;
}
Future<LoginResponseModel> loginCustomer(
String username,
String password,
) async {
LoginResponseModel model;
try {
var response = await Dio().post(Config.tokenURL,
data: {
'username': username,
'password': password,
},
options: new Options(headers: {
HttpHeaders.contentTypeHeader: 'application/x-www-form-urlencoded',
}));
if (response.statusCode == 200) {
model = LoginResponseModel.fromJson(response.data);
}
} on DioError catch (e) {
print(e.message);
}
return model;
}
}
signuppage.dart
class SignupPage extends StatefulWidget {
#override
_SignupPageState createState() => _SignupPageState();
}
class _SignupPageState extends State<SignupPage> {
APIService apiService;
CustomerModel model;
GlobalKey<FormState> globalKey = GlobalKey<FormState>();
bool hidePassword = true;
bool isApiCallProcess = false;
#override
void initState() {
apiService = new APIService();
model = new CustomerModel();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
automaticallyImplyLeading: true,
title: Text('Sign Up'),
),
body: ProgressHUD(
child: Form(
key: globalKey,
child: _formUI(),
),
inAsyncCall: isApiCallProcess,
opacity: 0.3),
);
}
Widget _formUI() {
return SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(10.00),
child: Container(
child: Align(
alignment: Alignment.topLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
FormHelper.fieldLabel('First Name'),
FormHelper.textInput(
context,
model.firstName,
(value) => {
this.model.firstName = value,
},
onValidate: (value) {
if (value.toString().isEmpty) {
return 'Please enter First Name.';
}
return null;
},
),
FormHelper.fieldLabel('Last Name'),
FormHelper.textInput(
context,
model.lastName,
(value) => {
this.model.lastName = value,
},
onValidate: (value) {
return null;
},
),
FormHelper.fieldLabel('Email Id'),
FormHelper.textInput(
context,
model.email,
(value) => {
this.model.email = value,
},
onValidate: (value) {
if (value.toString().isEmpty) {
return 'Please enter Email id.';
}
if (value.isNotEmpty && !value.toString().isValidEmail()) {
return 'Please enter valid email id';
}
},
),
FormHelper.fieldLabel('Password'),
FormHelper.textInput(
context,
model.password,
(value) => {
this.model.password = value,
},
onValidate: (value) {
if (value.toString().isEmpty) {
return 'Please enter Password.';
}
return null;
},
obscureText: hidePassword,
suffixIcon: IconButton(
onPressed: () {
setState(() {
hidePassword = !hidePassword;
});
},
color: Theme.of(context).accentColor.withOpacity(0.4),
icon: Icon(
hidePassword ? Icons.visibility_off : Icons.visibility,
),
),
),
SizedBox(
height: 20,
),
Center(
child: FormHelper.saveButton(
'Register',
() {
if (validateAndSave()) {
print(model.toJson());
setState(() {
isApiCallProcess = true;
});
apiService.createCustomer(model).then(
(ret) {
setState(() {
isApiCallProcess = false;
});
if (ret) {
FormHelper.showMessage(
context,
'WooCommerce App',
'Registration Successfull',
'Ok',
() {
Navigator.of(context).pop();
},
);
} else {
FormHelper.showMessage(
context,
'WooCommerce App',
'Email Id already registered.',
'Ok',
() {
Navigator.of(context).pop();
},
);
}
},
);
}
},
),
)
],
),
),
),
),
);
}
bool validateAndSave() {
final form = globalKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
}
form_helper.dart
class FormHelper {
static Widget textInput(
BuildContext context,
Object initialValue,
Function onChanged, {
bool isTextArea = false,
bool isNumberInput = false,
obscureText: false,
Function onValidate,
Widget prefixIcon,
Widget suffixIcon,
}) {
return TextFormField(
initialValue: initialValue != null ? initialValue.toString() : "",
decoration: fieldDecoration(
context,
"",
"",
suffixIcon: suffixIcon,
),
obscureText: obscureText,
maxLines: !isTextArea ? 1 : 3,
keyboardType: isNumberInput ? TextInputType.number : TextInputType.text,
onChanged: (String value) {
return onChanged(value);
},
validator: (value) {
return onValidate(value);
},
);
}
static InputDecoration fieldDecoration(
BuildContext context,
String hintText,
String helperText, {
Widget prefixIcon,
Widget suffixIcon,
}) {
return InputDecoration(
contentPadding: EdgeInsets.all(6),
hintText: hintText,
helperText: helperText,
prefixIcon: prefixIcon,
suffixIcon: suffixIcon,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
width: 1,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
width: 1,
),
),
);
}
static Widget fieldLabel(String labelName) {
return new Padding(
padding: EdgeInsets.fromLTRB(0, 5, 0, 10),
child: Text(
labelName,
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15.0,
),
),
);
}
static Widget saveButton(String buttonText, Function onTap,
{String color, String textColor, bool fullWidth}) {
return Container(
height: 50.0,
width: 150,
child: GestureDetector(
onTap: () {
onTap();
},
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.redAccent,
style: BorderStyle.solid,
width: 1.0,
),
color: Colors.redAccent,
borderRadius: BorderRadius.circular(30.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Text(
buttonText,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600,
letterSpacing: 1,
),
),
),
],
),
),
),
);
}
static void showMessage(
BuildContext context,
String title,
String message,
String buttonText,
Function onPressed,
) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(title),
content: new Text(message),
actions: [
new FlatButton(
onPressed: () {
return onPressed();
},
child: new Text(buttonText),
)
],
);
},
);
}
}
progressHUD.dart
class ProgressHUD extends StatelessWidget {
final Widget child;
final bool inAsyncCall;
final double opacity;
final Color color;
final Animation<Color> valueColor;
ProgressHUD({
Key key,
#required this.child,
#required this.inAsyncCall,
this.opacity = 0.3,
this.color = Colors.grey,
this.valueColor,
}) : super(key: key);
#override
Widget build(BuildContext context) {
List<Widget> widgetList = new List<Widget>();
widgetList.add(child);
if (inAsyncCall) {
final modal = new Stack(
children: [
new Opacity(
opacity: opacity,
child: ModalBarrier(dismissible: false, color: color),
),
new Center(child: new CircularProgressIndicator()),
],
);
widgetList.add(modal);
}
return Stack(
children: widgetList,
);
}
}

Unable to identify source of exception error: Flutter

Image of code that occurs with error
I am going through a udemy Flutter course and I do not understand why the try catch cannot handle the error with the if statement inside inside of the try{}. I have had this problem for this a couple of times and I have just avoided it by running error-free trials.
The code is as follows:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../models/http_exception.dart';
class Auth with ChangeNotifier {
String _token;
//tokens only last about an hour
DateTime _expiryDate;
String _userId;
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url = 'UrlIsCorrectInMyCode'; //changed on purpose
try {
final response = await http.post(
url,
body: json.encode(
{
'email': email,
'password': password,
'returnSecureToken': true,
},
),
);
final responseData = json.decode(response.body);
if(responseData['error'] != null){
throw HttpException(responseData['error']['message']);
}
} catch (error) {
throw error;
}
}
Future<void> signUp(String email, String password) async {
return _authenticate(email, password, 'signUp');
//in order for the progress indicator to be shown
//it must be returned so that it takes the future of
//_authenticate and not just any future
}
Future<void> login(String email, String password) async {
return _authenticate(email, password, 'signInWithPassword');
}
}
And the class that registers UI and uses Auth:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/auth.dart';
import '../models/http_exception.dart';
enum AuthMode { Signup, Login }
class AuthScreen extends StatelessWidget {
static const routeName = '/auth';
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
// final transformConfig = Matrix4.rotationZ(-8 * pi / 180);
// transformConfig.translate(-10.0);
return Scaffold(
// resizeToAvoidBottomInset: false,
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color.fromRGBO(215, 117, 255, 1).withOpacity(0.5),
Color.fromRGBO(255, 188, 117, 1).withOpacity(0.9),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
stops: [0, 1],
),
),
),
SingleChildScrollView(
child: Container(
height: deviceSize.height,
width: deviceSize.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
margin: EdgeInsets.only(bottom: 20.0),
padding:
EdgeInsets.symmetric(vertical: 8.0, horizontal: 94.0),
transform: Matrix4.rotationZ(-8 * pi / 180)
..translate(-10.0),
//transform allows to rotate or scale a box
//the '..' operator allows you to return the matrix4
//object that rotationZ provides instead of the void
//response that .translate provides
// ..translate(-10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.deepOrange.shade900,
boxShadow: [
BoxShadow(
blurRadius: 8,
color: Colors.black26,
offset: Offset(0, 2),
)
],
),
child: Text(
'MyShop',
style: TextStyle(
color:
Theme.of(context).accentTextTheme.headline6.color,
fontSize: 50,
fontFamily: 'Anton',
fontWeight: FontWeight.normal,
),
),
),
),
Flexible(
flex: deviceSize.width > 600 ? 2 : 1,
child: AuthCard(),
),
],
),
),
),
],
),
);
}
}
class AuthCard extends StatefulWidget {
const AuthCard({
Key key,
}) : super(key: key);
#override
_AuthCardState createState() => _AuthCardState();
}
class _AuthCardState extends State<AuthCard> {
final GlobalKey<FormState> _formKey = GlobalKey();
AuthMode _authMode = AuthMode.Login;
Map<String, String> _authData = {
'email': '',
'password': '',
};
var _isLoading = false;
final _passwordController = TextEditingController();
void _showErrorDialog(String message) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text("An error occured"),
content: Text(message),
actions: [
FlatButton(
child: Text("Okay"),
onPressed: () {
Navigator.of(ctx).pop();
},
),
],
),
);
}
Future<void> _submit() async {
if (!_formKey.currentState.validate()) {
// Invalid!
return;
}
_formKey.currentState.save();
setState(() {
_isLoading = true;
});
try {
if (_authMode == AuthMode.Login) {
await Provider.of<Auth>(context, listen: false).login(
_authData['email'],
_authData['password'],
);
} else {
await Provider.of<Auth>(context, listen: false).signUp(
_authData['email'],
_authData['password'],
);
}
} on HttpException catch (error) {
//this means a special type of error is thrown
//this acts as a filter for the type of error
var errorMessage = 'Authentication failed.';
if (error.toString().contains("EMAIL_EXISTS")) {
errorMessage = 'This email address is already in use';
} else if (error.toString().contains('INVALID_EMAIL')) {
errorMessage = 'This is not a valid email address.';
} else if (error.toString().contains('WEAK_PASSWORD')) {
errorMessage = 'This password is too weak.';
} else if (error.toString().contains('EMAIL_NOT_FOUND')) {
errorMessage = 'Could not find a user with that email.';
} else if (error.toString().contains('INVALID_PASSWORD')) {
errorMessage = 'Invalid password.';
}
_showErrorDialog(errorMessage);
} catch (error) {
const errorMessage = 'Could not authenticate. Please try again.';
_showErrorDialog(errorMessage);
}
setState(() {
_isLoading = false;
});
}
void _switchAuthMode() {
if (_authMode == AuthMode.Login) {
setState(() {
_authMode = AuthMode.Signup;
});
} else {
setState(() {
_authMode = AuthMode.Login;
});
}
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 8.0,
child: Container(
height: _authMode == AuthMode.Signup ? 320 : 260,
constraints:
BoxConstraints(minHeight: _authMode == AuthMode.Signup ? 320 : 260),
width: deviceSize.width * 0.75,
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'E-Mail'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Invalid email!';
} else {
return null;
}
},
onSaved: (value) {
_authData['email'] = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
validator: (value) {
if (value.isEmpty || value.length < 5) {
return 'Password is too short!';
} else {
return null;
}
},
onSaved: (value) {
_authData['password'] = value;
},
),
if (_authMode == AuthMode.Signup)
TextFormField(
enabled: _authMode == AuthMode.Signup,
decoration: InputDecoration(labelText: 'Confirm Password'),
obscureText: true,
//this allows stars to mask the input
validator: _authMode == AuthMode.Signup
? (value) {
if (value != _passwordController.text) {
return 'Passwords do not match!';
} else {
return null;
}
}
: null,
),
SizedBox(
height: 20,
),
if (_isLoading)
CircularProgressIndicator()
else
RaisedButton(
child:
Text(_authMode == AuthMode.Login ? 'LOGIN' : 'SIGN UP'),
onPressed: _submit,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
padding:
EdgeInsets.symmetric(horizontal: 30.0, vertical: 8.0),
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).primaryTextTheme.button.color,
),
FlatButton(
child: Text(
'${_authMode == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} INSTEAD'),
onPressed: _switchAuthMode,
padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 4),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
//reduces the amount of surface area that is tappable
textColor: Theme.of(context).primaryColor,
),
],
),
),
),
),
);
}
}