I have an article search feature on my application by implementing BLOC and RX Dart. I have succeeded in searching the article based on the "title" that became the key in the search, but when I filled in the "title" incorrectly, the results did not issue an error such as "Article does not exist / anything else" and the results were not real-time according to the key " title "is meant and instead gets an error in LogCat as below:
E/flutter (25135): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: Class 'String' has no instance method 'forEach'.
E/flutter (25135): Receiver: "Data not found"
E/flutter (25135): Tried calling: forEach(Closure: (dynamic) => Null)
E/flutter (25135): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:50:5)
E/flutter (25135): #1 new Articles.fromJson (package:vallery/src/models/articles/articles.dart:11:22)
E/flutter (25135): #2 ApiProvider.searchArticle (package:vallery/src/resources/api/api_provider.dart:65:23)
E/flutter (25135): <asynchronous suspension>
E/flutter (25135): #3 Repository.searchArticlesRepository (package:vallery/src/resources/repository/repository.dart:19:74)
E/flutter (25135): #4 SearchArticleBloc.searchArticleBloc (package:vallery/src/blocs/article/articles_search_bloc.dart:12:42)
E/flutter (25135): <asynchronous suspension>
E/flutter (25135): #5 EditableTextState._formatAndSetValue (package:flutter/src/widgets/editable_text.dart:1335:14)
E/flutter (25135): #6 EditableTextState.updateEditingValue (package:flutter/src/widgets/editable_text.dart:971:5)
E/flutter (25135): #7 _TextInputClientHandler._handleTextInputInvocation (package:flutter/src/services/text_input.dart:743:36)
E/flutter (25135): <asynchronous suspension>
E/flutter (25135): #8 MethodChannel._handleAsMethodCall (package:flutter/src/services/platform_channel.dart:397:55)
E/flutter (25135): <asynchronous suspension>
E/flutter (25135): #9 MethodChannel.setMethodCallHandler.<anonymous closure> (package:flutter/src/services/platform_channel.dart:365:54)
E/flutter (25135): #10 _DefaultBinaryMessenger.handlePlatformMessage (package:flutter/src/services/binary_messenger.dart:110:33)
E/flutter (25135): <asynchronous suspension>
E/flutter (25135): #11 _invoke3.<anonymous closure> (dart:ui/hooks.dart:280:15)
E/flutter (25135): #12 _rootRun (dart:async/zone.dart:1124:13)
E/flutter (25135): #13 _CustomZone.run (dart:async/zone.dart:1021:19)
E/flutter (25135): #14 _CustomZone.runGuarded (dart:async/zone.dart:923:7)
E/flutter (25135): #15 _invoke3 (dart:ui/hooks.dart:279:10)
E/flutter (25135): #16 _dispatchPlatformMessage (dart:ui/hooks.dart:141:5)
This is the model:
class Articles {
int status;
List<Result> result;
Articles({this.status, this.result});
Articles.fromJson(Map<String, dynamic> json) {
status = json['status'];
if (json['result'] != null) {
result = new List<Result>();
json['result'].forEach((v) {
result.add(new Result.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
if (this.result != null) {
data['result'] = this.result.map((v) => v.toJson()).toList();
}
return data;
}
}
class Result {
String idArtikel;
String title;
String sinopsis;
String content;
String createdDate;
String thumbnail;
Result(
{this.idArtikel,
this.title,
this.sinopsis,
this.content,
this.createdDate,
this.thumbnail});
Result.fromJson(Map<String, dynamic> json) {
idArtikel = json['id_artikel'];
title = json['title'];
sinopsis = json['sinopsis'];
content = json['content'];
createdDate = json['created_date'];
thumbnail = json['thumbnail'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id_artikel'] = this.idArtikel;
data['title'] = this.title;
data['sinopsis'] = this.sinopsis;
data['content'] = this.content;
data['created_date'] = this.createdDate;
data['thumbnail'] = this.thumbnail;
return data;
}
}
This is the API:
class ApiProvider {
Client client = Client();
static final String baseUrl = 'link_api';
Future<Articles> searchArticle(String title) async {
final response = await client.post(baseUrl + 'search-artikel', body: {
"title" : title
});
if (response.statusCode == 200) {
return Articles.fromJson(json.decode(response.body));
} else {
throw Exception('Gagal ambil data article');
}
}
}
This is the repository:
class Repository {
final apiProvider = ApiProvider();
Future<Articles> searchArticlesRepository(String title) => apiProvider.searchArticle(title);
}
This is the BLoC:
class SearchArticleBloc {
final repository = Repository();
final articleSearchFetcher = PublishSubject<Articles>();
Observable<Articles> get allSearchArticle => articleSearchFetcher.stream;
searchArticleBloc(String title) async {
Articles articles = await repository.searchArticlesRepository(title);
articleSearchFetcher.sink.add(articles);
}
dispose() {
articleSearchFetcher.close();
}
}
And this is the UI:
class SearchArticlePage extends StatefulWidget {
#override
_SearchArticlePageState createState() => _SearchArticlePageState();
}
class _SearchArticlePageState extends State<SearchArticlePage> {
final blocSearchArticle = SearchArticleBloc();
#override
void dispose() {
blocSearchArticle.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: color_white,
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
backgroundColor: color_white,
iconTheme: IconThemeData(
color: color_blue_bg, //change your color here
),
centerTitle: true,
floating: true,
pinned: true,
title: TextField(
autofocus: true,
style: TextStyle(fontSize: 17, color: color_blue_bg),
decoration: InputDecoration.collapsed(
hintText: "Article Name...",
hintStyle: TextStyle(fontSize: 17, color: color_blue_bg),
),
onChanged: blocSearchArticle.searchArticleBloc,
),
)
];
},
body: getListResult(),
),
);
}
Widget getListResult() {
return StreamBuilder(
stream: blocSearchArticle.allSearchArticle,
builder: (BuildContext context, AsyncSnapshot<Articles> snapshot) {
if(snapshot.hasData) {
return showListResult(snapshot);
} else if (!snapshot.hasData) {
return Center(
child: Text('Data not found'),
);
} else if(snapshot.hasError) {
return Text(snapshot.error.toString());
}
return Center(
child: CircularProgressIndicator(),
);
},
);
}
Widget showListResult(AsyncSnapshot<Articles> snapshot) {
return Container(
margin: EdgeInsets.only(top: 10.0),
child: ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: snapshot.data.result == null ? Center(child: Text('Data not found')) : snapshot?.data?.result?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
child: Container(
height: MediaQuery.of(context).size.height / 7.0,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
child: FadeInImage.assetNetwork(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width / 3,
placeholder: 'assets/images/img_default_bg.png',
image: '${snapshot.data.result[0].thumbnail}',
fit: BoxFit.cover,
),
),
),
Expanded(
child: Container(
margin: EdgeInsets.only(
left: MediaQuery.of(context).size.width / 41,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.only(
right: MediaQuery.of(context).size.width/41,
bottom: MediaQuery.of(context).size.width/ 80,
),
child: Text(
snapshot.data.result[index].title,
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(
color: Colors.black,
fontSize: MediaQuery.of(context).size.width / 25,
fontWeight: FontWeight.bold,
),
),
),
Padding(
padding: EdgeInsets.only(
right: MediaQuery.of(context).size.width/41,
bottom: MediaQuery.of(context).size.width/ 80,
),
child: Text(
snapshot.data.result[index].sinopsis,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.black,
fontSize: MediaQuery.of(context).size.width / 35,
fontWeight: FontWeight.normal,
),
),
),
SizedBox(height: MediaQuery.of(context).size.height / 50,
),
Padding(
padding: EdgeInsets.only(
right: MediaQuery.of(context).size.width/41,
bottom: MediaQuery.of(context).size.width/ 80,
),
child: Text(
snapshot.data.result[index].createdDate,
style: TextStyle(
color: Colors.black,
fontSize: MediaQuery.of(context).size.width / 35,
fontWeight: FontWeight.normal,
),
),
),
],
),
),
),
],
),
),
),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context){
return ArticleDetailPage(
id: snapshot.data.result[index].idArtikel,
title: snapshot.data.result[index].title,
thumbnail: '${snapshot.data.result[index].thumbnail}',
);
}),
);
},
);
},
),
);
}
}
Can someone help me? Because I was dizzy to find a solution to this error :)
The problem is here:
if (json['result'] != null) {
result = new List<Result>();
json['result'].forEach((v) {
result.add(new Result.fromJson(v));
});
}
You are expecting the "result" part of the JSON to be a list, but it's apparently a string. Check the actual JSON text and you will probably find "result": "some result", not "result": [ ... Consider editing the question to show the actual JSON.
As an aside there's a simpler syntax to do what you are doing in the snippet above. (Naturally that will give the same error until you solve the JSON array vs string problem.)
result = json['result'].map<Result>((j) => Result.fromJson(j).toList();
Solve this problem if (json['result'] != '' && json['result'] != null) { result = new List<Result>(); json['result'].forEach((v) { result.add(new Result.fromJson(v));});}
Related
i'm learning to use Cubit, Initially the application runs without any errors when I do the likeArticle, but when I do the like method continuously or too often an Unhandled Exception will occur. This my code:
//article_cubit.dart
class ArticleCubit extends Cubit<ArticleState> {
final CreateArticleUseCase createArticleUseCase;
final ReadArticlesUseCase readArticlesUseCase;
final LikeArticleUseCase likeArticleUseCase;
ArticleCubit({
required this.createArticleUseCase,
required this.readArticlesUseCase,
required this.likeArticleUseCase,
}) : super(ArticleInitial());
Future<void> createArticle({required ArticleEntity articleEntity}) async {
try {
await createArticleUseCase.call(articleEntity);
} on SocketException catch (_) {
emit(ArticleFailure());
} catch (_) {
emit(ArticleFailure());
}
}
Future<void> getArticles({required ArticleEntity articleEntity}) async {
emit(ArticleLoading());
try {
final streamResponse = readArticlesUseCase.call(articleEntity);
streamResponse.listen(
(articles) {
debugPrint("ArticleCubit[getArticles]: emit(ArticleLoaded())");
emit(ArticleLoaded(articles: articles));
},
);
} on SocketException catch (_) {
emit(ArticleFailure());
} catch (_) {
emit(ArticleFailure());
}
}
Future<void> likeArticle({required ArticleEntity articleEntity}) async {
try {
await likeArticleUseCase.call(articleEntity);
} on SocketException catch (_) {
emit(ArticleFailure());
} catch (_) {
emit(ArticleFailure());
}
}
}
This my ArticlePage:
class ArticlePage extends StatelessWidget {
final UserEntity currentUser;
const ArticlePage({super.key, required this.currentUser});
#override
Widget build(BuildContext context) {
debugPrint("ArticlePage[build]: Building!!");
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
title: Text(
"Article",
style: TextStyle(color: AppColor.primaryColor, fontSize: 25),
),
actions: [
currentUser.role == "admin"
? Padding(
padding: const EdgeInsets.only(right: 10.0),
child: InkWell(
onTap: () {
Navigator.pushNamed(
context,
PageConst.uploadArticlePage,
arguments: currentUser,
);
},
child: Icon(Icons.create, color: AppColor.primaryColor),
),
)
: const SizedBox(),
],
),
body: BlocProvider<ArticleCubit>(
create: (context) => di.sl<ArticleCubit>()
..getArticles(articleEntity: const ArticleEntity()),
child: BlocBuilder<ArticleCubit, ArticleState>(
builder: (context, articleState) {
if (articleState is ArticleLoading) {
return const Center(
child: CircularProgressIndicator(
color: Colors.black,
));
}
if (articleState is ArticleFailure) {
toast("Some failure occured while creating the article");
}
if (articleState is ArticleLoaded) {
return articleState.articles.isEmpty
? _noPostsWidget()
: ListView.builder(
itemCount: articleState.articles.length,
itemBuilder: (context, index) {
final article = articleState.articles[index];
return BlocProvider(
create: (context) => di.sl<ArticleCubit>(),
child: SingleArticleWidget(articleEntity: article),
);
},
);
}
return const Center(
child: CircularProgressIndicator(
color: Colors.black,
));
},
),
),
);
}
Center _noPostsWidget() {
return Center(
child: Text(
"No Posts",
style: TextStyle(
color: AppColor.primaryColor,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
);
}
}
and this my SingleArticleWidget (like Card widget);
class SingleArticleWidget extends StatefulWidget {
final ArticleEntity articleEntity;
const SingleArticleWidget({
Key? key,
required this.articleEntity,
}) : super(key: key);
#override
State<SingleArticleWidget> createState() => _SingleArticleWidgetState();
}
class _SingleArticleWidgetState extends State<SingleArticleWidget> {
String _currentUid = "";
#override
void initState() {
di.sl<GetCurrentUidUseCase>().call().then((uid) {
setState(() {
_currentUid = uid;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
offset: const Offset(5, 10),
blurRadius: 10,
color: AppColor.gradientSecond.withOpacity(0.3),
),
],
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// [TopSection]: Image and title
Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
Navigator.pushNamed(
context,
PageConst.detailArticlePage,
arguments: AppEntity(
uid: _currentUid,
articleId: widget.articleEntity.articleId,
creatorUid: widget.articleEntity.creatorUid,
),
);
},
child: Ink(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Image
Container(
width: double.infinity,
height: size.height * 0.25,
decoration: BoxDecoration(
// color: Colors.red,
borderRadius: BorderRadius.circular(10),
),
child: imageBoxWidget(
imageUrl: widget.articleEntity.articleImageUrl),
),
AppSize.sizeVer(10),
// Title
Text(
widget.articleEntity.title!.length > 63
? "${widget.articleEntity.title!.substring(0, 63)}..."
: widget.articleEntity.title!,
style: AppTextStyle.kTitleTextStyle
.copyWith(fontSize: 19),
),
],
),
),
),
),
AppSize.sizeVer(10),
// User Tag
// [BottomSection]: Include Usertag, like button, total like.
Row(
children: [
// [Container]: User tag
Container(
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(20.0),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 7.0,
vertical: 3.0,
),
child: FittedBox(
child: Row(
children: [
SizedBox(
width: 25,
height: 25,
child: ClipRRect(
borderRadius: BorderRadius.circular(15),
child: profileWidget(
imageUrl:
widget.articleEntity.userProfileUrl),
),
),
AppSize.sizeHor(8),
Text(
widget.articleEntity.username!,
style: AppTextStyle.kTitleTextStyle.copyWith(
fontSize: 15,
color: Colors.white,
),
)
],
),
),
),
),
const Spacer(),
// [Text]: Total Likes.
Text(
'${widget.articleEntity.totalLikes} likes',
style: TextStyle(
color: AppColor.primaryColor,
fontWeight: FontWeight.bold,
),
),
AppSize.sizeHor(5),
// [Button]: Like Button.
InkWell(
onTap: _likeArticle,
child: Icon(
widget.articleEntity.likes!.contains(_currentUid)
? Icons.favorite
: Icons.favorite_outline,
color: widget.articleEntity.likes!.contains(_currentUid)
? Colors.red
: AppColor.primaryColor,
),
)
],
),
AppSize.sizeVer(10),
],
),
),
),
);
}
void _likeArticle() {
BlocProvider.of<ArticleCubit>(context).likeArticle(
articleEntity: ArticleEntity(
articleId: widget.articleEntity.articleId,
),
);
}
}
for ArticleCubit.getArticles.<anonymous closure> this line reffer to emit(ArticleLoaded(articles: articles));. This my problem from Debug Console:
E/flutter (14310): #0 BlocBase.emit
E/flutter (14310): #1 ArticleCubit.getArticles.<anonymous closure>
E/flutter (14310): #2 _RootZone.runUnaryGuarded (dart:async/zone.dart:1586:10)
E/flutter ( 7916): #3 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11)
E/flutter ( 7916): #4 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter ( 7916): #5 _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
E/flutter ( 7916): #6 _MapStream._handleData (dart:async/stream_pipe.dart:218:10)
E/flutter ( 7916): #7 _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
E/flutter ( 7916): #8 _RootZone.runUnaryGuarded (dart:async/zone.dart:1586:10)
E/flutter ( 7916): #9 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11)
E/flutter ( 7916): #10 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
E/flutter ( 7916): #11 _ForwardingStreamSubscription._add (dart:async/stream_pipe.dart:123:11)
E/flutter ( 7916): #12 _MapStream._handleData (dart:async/stream_pipe.dart:218:10)
E/flutter ( 7916): #13 _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
E/flutter ( 7916): #14 _RootZone.runUnaryGuarded (dart:async/zone.dart:1586:10)
E/flutter ( 7916): #15 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11)
E/flutter ( 7916): #16 _DelayedData.perform (dart:async/stream_impl.dart:515:14)
E/flutter ( 7916): #17 _PendingEvents.handleNext (dart:async/stream_impl.dart:620:11)
E/flutter ( 7916): #18 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:591:7)
E/flutter ( 7916): #19 _microtaskLoop (dart:async/schedule_microtask.dart:40:21)
E/flutter ( 7916): #20 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)
NOTE: I can still do likes even though there are Unhandled Exception and im using firebase as database.
Whenever I try to clear the TextField by clicking on the IconButton I get an Unhandled Exception warning in the debug console although my TextField is cleared.
Also when I try to add a new value to the TextField my previous value is automatically displayed in the TextField.
Here's my code for the Search_location UI
import 'package:flutter/material.dart';
import 'package:geoflutterfire/geoflutterfire.dart';
import 'package:geolocator/geolocator.dart';
import 'package:maps_app/models/place.dart';
import 'package:maps_app/services/location_api.dart';
import 'package:provider/provider.dart';
class SearchView extends StatefulWidget {
#override
_SearchViewState createState() => _SearchViewState();
}
class _SearchViewState extends State<SearchView> {
final _scrollController = ScrollController();
var latitude, longitude;
var con_width = 0.0;
var list_height = 0.0;
GeoFirePoint point;
Geoflutterfire geo = Geoflutterfire();
bool serviceEnabled;
LocationPermission permission;
#override
void initState() {
super.initState();
getCurrentLocation();
}
getCurrentLocation() async {
try {
final pos = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
setState(() {
latitude = pos.latitude;
longitude = pos.longitude;
});
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SearchInjector(
child: SafeArea(
child: Consumer<LocationApi>(
builder: (_, api, child) => SingleChildScrollView(
child: Container(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Container(
child: TextField(
onTap: () {
setState(() {
list_height = 56;
});
},
controller: api.addressController,
decoration: InputDecoration(
prefixIcon: IconButton(
icon: Icon(Icons.my_location),
onPressed: () {
// getCurrentLocation();
}),
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () {
setState(() {
api.addressController.clear();
con_width = 0.0;
list_height = 0.0;
});
}),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.red,
),
borderRadius: BorderRadius.circular(50.0),
),
labelText: 'Search Location',
fillColor: Colors.grey[20],
filled: true),
onChanged: (value) {
setState(() {
con_width = 300.0;
});
api.places.clear();
api.handleSearch(value);
},
),
),
AnimatedContainer(
duration: Duration(milliseconds: 20),
height: list_height,
color: Colors.blue[100].withOpacity(.3),
width: MediaQuery.of(context).size.width,
child: Column(
children: List.generate(1, (i) {
return ListTile(
onTap: () {
setState(() {
api.addressController.text = 'Your Location';
list_height = 0.0;
con_width = 0.0;
});
},
title: Row(
children: [
Icon(Icons.my_location),
SizedBox(
width: 5,
),
Text(
'Your Location',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
],
),
);
}))),
AnimatedContainer(
duration: Duration(milliseconds: 20),
color: Colors.blue[100].withOpacity(.3),
width: MediaQuery.of(context).size.width,
height: con_width,
child: StreamBuilder<List<Place>>(
stream: api.controllerOut,
builder: (context, snapshot) {
if (snapshot.data == null) {
return Center(
child: Text('No data address found'));
}
final data = snapshot.data;
return Scrollbar(
controller: _scrollController,
child: SingleChildScrollView(
controller: _scrollController,
child: Container(
child: Builder(builder: (context) {
return Column(
children: [
Column(
children: List.generate(data.length,
(index) {
final place = data[index];
return ListTile(
leading: Icon(Icons.home),
onTap: () {
point = geo.point(
latitude: place.latitude,
longitude: place.longitude);
setState(() {
api.addressController.text =
'${place.name}, ${place.subLocality}, ${place.country}, ${place.postalCode}';
con_width = 0.0;
list_height = 0.0;
});
},
title: Text(
'${place.name}, ${place.subLocality}, ${place.locality}, ${place.postalCode} '),
subtitle: Text(
'${place.adminArea}, ${place.country}'),
);
})),
],
);
}),
),
),
);
}),
)
],
),
),
),
),
),
),
);
}
}
class SearchInjector extends StatelessWidget {
final Widget child;
const SearchInjector({Key key, this.child}) : super(key: key);
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => LocationApi(),
child: child,
);
}
}
This is the Exception I am getting in the debug Console
Restarted application in 1,268ms.
E/MethodChannel#flutter/textinput(29061): Failed to handle method call
E/MethodChannel#flutter/textinput(29061): java.lang.IndexOutOfBoundsException: invalid selection start: 13
E/MethodChannel#flutter/textinput(29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$TextEditState.<init>(TextInputChannel.java:724)
E/MethodChannel#flutter/textinput(29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$TextEditState.fromJson(TextInputChannel.java:680)
E/MethodChannel#flutter/textinput(29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$1.onMethodCall(TextInputChannel.java:91)
E/MethodChannel#flutter/textinput(29061): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/MethodChannel#flutter/textinput(29061): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/MethodChannel#flutter/textinput(29061): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:818)
E/MethodChannel#flutter/textinput(29061): at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#flutter/textinput(29061): at android.os.MessageQueue.next(MessageQueue.java:336)
E/MethodChannel#flutter/textinput(29061): at android.os.Looper.loop(Looper.java:174)
E/MethodChannel#flutter/textinput(29061): at android.app.ActivityThread.main(ActivityThread.java:7697)
E/MethodChannel#flutter/textinput(29061): at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#flutter/textinput(29061): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
E/MethodChannel#flutter/textinput(29061): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
E/flutter (29061): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: PlatformException(error, invalid selection start: 13, null, java.lang.IndexOutOfBoundsException: invalid selection start: 13
E/flutter (29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$TextEditState.<init>(TextInputChannel.java:724)
E/flutter (29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$TextEditState.fromJson(TextInputChannel.java:680)
E/flutter (29061): at io.flutter.embedding.engine.systemchannels.TextInputChannel$1.onMethodCall(TextInputChannel.java:91)
E/flutter (29061): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/flutter (29061): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/flutter (29061): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:818)
E/flutter (29061): at android.os.MessageQueue.nativePollOnce(Native Method)
E/flutter (29061): at android.os.MessageQueue.next(MessageQueue.java:336)
E/flutter (29061): at android.os.Looper.loop(Looper.java:174)
E/flutter (29061): at android.app.ActivityThread.main(ActivityThread.java:7697)
E/flutter (29061): at java.lang.reflect.Method.invoke(Native Method)
E/flutter (29061): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
E/flutter (29061): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
E/flutter (29061): )
[38;5;244mE/flutter (29061): #0 JSONMethodCodec.decodeEnvelope[39;49m
[38;5;244mE/flutter (29061): #1 MethodChannel._invokeMethod[39;49m
E/flutter (29061): <asynchronous suspension>
E/flutter (29061):
The problem is the clearing of the controller.
Instead of
api.addressController.clear();
try:
WidgetsBinding.instance.addPostFrameCallback((_) => api.addressController.clear());
I think you are trying to access index which does not exists, please try to check your list size.
I am new in flutter but I tried to make an app but I have many problem in the login & register page connect with sqlite I tried many ways I don't know the how to solve it please help regard my problem I appreciate any suggestion in advance.
the error:
E/flutter ( 4024): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
E/flutter ( 4024): #1 _ChangePassPage._submitForm.<anonymous closure>
package:future_uni/…/login/change_pass_page.dart:80
E/flutter ( 4024): #2 State.setState
package:flutter/…/widgets/framework.dart:1233
E/flutter ( 4024): #3 _ChangePassPage._submitForm
package:future_uni/…/login/change_pass_page.dart:77
E/flutter ( 4024): #4 _InkResponseState._handleTap
package:flutter/…/material/ink_well.dart:705
E/flutter ( 4024): #5 _InkResponseState.build.<anonymous closure>
package:flutter/…/material/ink_well.dart:788
E/flutter ( 4024): #6 GestureRecognizer.invokeCallback
package:flutter/…/gestures/recognizer.dart:182
E/flutter ( 4024): #7 TapGestureRecognizer.handleTapUp
package:flutter/…/gestures/tap.dart:486
E/flutter ( 4024): #8 BaseTapGestureRecognizer._checkUp
package:flutter/…/gestures/tap.dart:264
E/flutter ( 4024): #9 BaseTapGestureRecognizer.handlePrimaryPointer
package:flutter/…/gestures/tap.dart:199
E/flutter ( 4024): #10 PrimaryPointerGestureRecognizer.handleEvent
package:flutter/…/gestures/recognizer.dart:470
E/flutter ( 4024): #11 PointerRouter._dispatch
package:flutter/…/gestures/pointer_router.dart:76
E/flutter ( 4024): #12 PointerRouter._dispatchEventToRoutes.<anonymous closure>
package:flutter/…/gestures/pointer_router.dart:117
E/flutter ( 4024): #13 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:379:8)
E/flutter ( 4024): #14 PointerRouter._dispatchEventToRoutes
package:flutter/…/gestures/pointer_router.dart:115
E/flutter ( 4024): #15 PointerRouter.route
package:flutter/…/gestures/pointer_router.dart:101
E/flutter ( 4024): #16 GestureBinding.handleEvent
package:flutter/…/gestures/binding.dart:218
E/flutter ( 4024): #17 GestureBinding.dispatchEvent
package:flutter/…/gestures/binding.dart:198
E/flutter ( 4024): #18 GestureBinding._handlePointerEvent
package:flutter/…/gestures/binding.dart:156
E/flutter ( 4024): #19 GestureBinding._flushPointerEventQueue
package:flutter/…/gestures/binding.dart:102
E/flutter ( 4024): #20 GestureBinding._handlePointerDataPacket
package:flutter/…/gestures/binding.dart:86
E/flutter ( 4024): #21 _rootRunUnary (dart:async/zone.dart:1138:13)
E/flutter ( 4024): #22 _CustomZone.runUnary (dart:async/zone.dart:1031:19)
E/flutter ( 4024): #23 _CustomZone.runUnaryGuarded (dart:async/zone.dart:933:7)
E/flutter ( 4024): #24 _invoke1 (dart:ui/hooks.dart:274:10)
E/flutter ( 4024): #25 _dispatchPointerDataPacket (dart:ui/hooks.dart:183:5)
E/flutter ( 4024):
this is the register page to add your password:
class ChangePassPage extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return _ChangePassPage();
}
}
class _ChangePassPage extends State<ChangePassPage> {
bool isLoading = false;
String _password ;
int _index;
LoginResponse _response;
User user;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _passwordTextController = TextEditingController();
Widget _buildPasswordTextField() {
return TextFormField(
decoration: InputDecoration(
labelText: 'Password',
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(25.0),
borderSide: new BorderSide(
),), ),
obscureText: true,
controller: _passwordTextController,
validator: (String value) {
if (value.isEmpty || value.length < 6) {
return 'Password invalid';
}
},
onSaved: (String value) {
_password = value;
},
);
}
Widget _buildPasswordConfirmTextField() {
return TextFormField(
decoration: InputDecoration(
labelText: 'Confirm Password',
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(25.0),
borderSide: new BorderSide(
),), ),
obscureText: true,
validator: (String value) {
if (_passwordTextController.text != value) {
return 'Password not match';
}
},
);
}
void _submitForm() async {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
final form =_formKey.currentState;
if (form.validate() ) {
setState(() {
isLoading= true;
form.save();
_response.doregister(user);
Navigator.pushReplacementNamed(context, '/');
});
}
}
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child:Container(
padding: EdgeInsets.all(40.0),
child: Column(
children: <Widget>[
Align(
alignment: Alignment.topCenter,
child:Container(
padding: EdgeInsets.only(top:1),
child: Center(
child: Card(
child:Column(
children: <Widget>[
Image.asset('assets/Logo_of_future_university_sudan.png',
height: 130,
),
],)
),),
decoration: BoxDecoration(border: Border(
bottom: BorderSide(color:Color(0xffe46b10)),
))
),),
Container(
padding: EdgeInsets.only(top:60),
child:Center(
child: SingleChildScrollView(
child: Container(
child: Form(
key: _formKey,
child: Column(children: <Widget>[
_title(),
SizedBox(height: 40,),
_buildPasswordTextField(),
SizedBox(height: 40,),
_buildPasswordConfirmTextField(),
SizedBox(height: 50,),
ScopedModelDescendant<MainModel>(
builder: (BuildContext context, Widget child,MainModel model) {
return model.isLoading
? CircularProgressIndicator
: RaisedButton(
color:Color(0xffe46b10),
shape: new RoundedRectangleBorder(
side: BorderSide(color:Colors.black,width: 2),
borderRadius: new BorderRadius.circular(30.0),
),
textColor: Colors.black,
child: Text('SUBMIT'),
onPressed: _submitForm
);
}
)
],) ,
)
)
)
)
)
],)
)
)
);
}
}
the Request file:
class LoginRequest {
DatabaseHelper con = new DatabaseHelper();
Future<User> getLogin(int index , String password ) {
var result = con.getLogin(index, password);
return result;
}
Future <int> saveUser (User user) async {
var result = con.saveUser(user);
return result;
}
}
the Response file:
abstract class LoginCallBack {
void onLoginSuccess(User user);
void onLoginError(String error);
}
class LoginResponse {
LoginCallBack _callBack;
LoginRequest loginRequest = new LoginRequest();
LoginResponse(this._callBack);
doLogin(int index, String password) {
loginRequest.getLogin(index, password)
.then((user) => _callBack.onLoginSuccess(user))
.catchError((onError) => _callBack.onLoginError(onError.toString()));
}
doregister(User user) {
loginRequest.saveUser(user);
}
}
and Login page:
class LoginPage extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return _LoginPage();
}
}
enum LoginStatus {notSignIn, signIn}
class _LoginPage extends State<LoginPage> implements LoginCallBack {
LoginStatus _loginStatus = LoginStatus.notSignIn;
BuildContext _ctx;
bool _isLoading = false;
String password ;
int index;
LoginResponse _response;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final scaffoldKey = new GlobalKey<ScaffoldState>();
final TextEditingController _indexTextController = TextEditingController();
final TextEditingController _passTextController = TextEditingController();
_LoginPage(){
_response= new LoginResponse(this);
}
var value;
getPref() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
setState(() {
value = preferences.getInt("value");
_loginStatus = value == 1 ? LoginStatus.signIn : LoginStatus.notSignIn;
});
}
signOut() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
setState(() {
preferences.setInt("value", null);
_loginStatus = LoginStatus.notSignIn;
});
}
void initState() {
super.initState();
getPref();
}
Widget _buildIndexTextField() {
var textFormField = TextFormField(
decoration: InputDecoration(
labelText: 'Index Number',
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(25.0),
borderSide: new BorderSide(
),), ),
keyboardType: TextInputType.number,
controller: _indexTextController,
validator: (String value) {
if (value.isEmpty || value.length > 11) {
return 'Please enter a valid index';
}
},
onSaved: (value) => index = num.tryParse(value)
);
return textFormField;
}
Widget _buildPasswordTextField() {
return TextFormField(
decoration: InputDecoration(
labelText: 'Password',
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(25.0),
borderSide: new BorderSide(
),), ),
obscureText: true,
controller: _passTextController,
validator: (String value) {
if (value.isEmpty || value.length < 6) {
return 'Password invalid';
}
},
onSaved: (String value) {
password = value;
},
);
}
void _submitForm() async {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
final form =_formKey.currentState;
if (form.validate() && _indexTextController.text != _passTextController.text ) {
setState(() {
_isLoading= true;
form.save();
_response.doLogin(index, password);
Navigator.pushReplacementNamed(context, '/home');
});
}
if (form.validate() && _indexTextController.text == _passTextController.text) {
setState(() {
Navigator.pushReplacementNamed(context, '/passconfirm');
});
};
}
Widget build(BuildContext context) {
switch (_loginStatus) {
case LoginStatus.notSignIn:
_ctx = context;
var loginForm = new
SingleChildScrollView(
child:Container(
padding: EdgeInsets.all(40.0),
child: Column(
children: <Widget>[
Align(
alignment: Alignment.topCenter,
child:Container(
padding: EdgeInsets.only(top:1),
child: Center(
child: Card(
child:Column(
children: <Widget>[
Image.asset('assets/Logo_of_future_university_sudan.png',
height: 130,
),
],)
),),
decoration: BoxDecoration(border: Border(
bottom: BorderSide( color:Color(0xffe46b10)),
))
),),
Container(
padding: EdgeInsets.only(top:30),
child:Center(
child: Container(
child: Form(
key: _formKey,
child: Column(children: <Widget>[
_title(),
SizedBox(height: 50,),
_buildIndexTextField(),
SizedBox(height: 30,),
_buildPasswordTextField(),
SizedBox(height: 80,),
Padding(
padding: const EdgeInsets.only(left: 180.0),
child: ScopedModelDescendant<MainModel>(
builder: (BuildContext context, Widget child,MainModel model) {
return model.isLoading
? CircularProgressIndicator
: RaisedButton(
color:Color(0xffe46b10),
shape: new RoundedRectangleBorder(
side: BorderSide(color:Colors.black,width: 2),
borderRadius: new BorderRadius.circular(30.0),
),
textColor: Colors.black,
child: Text('LOGIN'),
onPressed: _submitForm
);
}
)
)
],) ,
)
)
)
)
]),
)
);
return Scaffold(
key: scaffoldKey,
body: Container(
child: loginForm,
),);
break;
case LoginStatus.signIn:
return HomePage(signOut());
break;
}
}
savePref(int value,int index, String password) async {
SharedPreferences preferences = await SharedPreferences.getInstance();
setState(() {
preferences.setInt("value", value);
preferences.setInt("index", index);
preferences.setString("password", password);
});
}
You never implement onLoginSuccess or onLoginError in _LoginPage.
I tried to make a compass for a flutter app.
This idea was to put an image of the compass on the camera preview.
The result seems to be ok:
First, the user has a camera preview with the compass :
The name of the room can be added.
When the user takes a picture, it makes a screenshot that can be shared:
Even it seems to work fine, I have the following error message on Android Studio:
E/flutter (29454): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: setState() called after dispose(): _CompassState#46249(lifecycle state: defunct, not mounted)
E/flutter (29454): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
E/flutter (29454): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter (29454): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
E/flutter (29454): #0 State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1204:9)
E/flutter (29454): #1 State.setState (package:flutter/src/widgets/framework.dart:1239:6)
E/flutter (29454): #2 _CompassState._onData (package:franck_ehrhart/seller/compass.dart:28:29)
E/flutter (29454): #3 _rootRunUnary (dart:async/zone.dart:1198:47)
E/flutter (29454): #4 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter (29454): #5 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter (29454): #6 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:357:11)
E/flutter (29454): #7 _DelayedData.perform (dart:async/stream_impl.dart:611:14)
E/flutter (29454): #8 _StreamImplEvents.handleNext (dart:async/stream_impl.dart:730:11)
E/flutter (29454): #9 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:687:7)
E/flutter (29454): #10 _rootRun (dart:async/zone.dart:1182:47)
E/flutter (29454): #11 _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (29454): #12 _CustomZone.runGuarded (dart:async/zone.dart:997:7)
E/flutter (29454): #13 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1037:23)
E/flutter (29454): #14 _rootRun (dart:async/zone.dart:1190:13)
E/flutter (29454): #15 _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (29454): #16 _CustomZone.runGuarded (dart:async/zone.dart:997:7)
E/flutter (29454): #17 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1037:23)
E/flutter (29454): #18 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
E/flutter (29454): #19 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
E/flutter (29454):
Here is the source code for the compass:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_compass/flutter_compass.dart';
class Compass extends StatefulWidget {
Compass({Key key}) : super(key: key);
#override
_CompassState createState() => _CompassState();
}
class _CompassState extends State<Compass> {
double _heading = 0;
String get _readout => _heading.toStringAsFixed(0) + '°';
#override
void initState() {
super.initState();
FlutterCompass.events.listen(_onData);
}
void _onData(double x) => setState(() { _heading = x; });
final TextStyle _style = TextStyle(
color: Colors.red,
fontSize: 32,
fontWeight: FontWeight.bold,
backgroundColor: Colors.white.withOpacity(0.5) ,
);
#override
Widget build(BuildContext context) {
return CustomPaint(
foregroundPainter: CompassPainter(angle: _heading),
child: Center(child: Text(_readout, style: _style))
);
}
}
class CompassPainter extends CustomPainter {
CompassPainter({ #required this.angle }) : super();
final double angle;
double get rotation => -2 * pi * (angle / 360);
Paint get _brush => new Paint()
..style = PaintingStyle.stroke
..strokeWidth = 4.0;
#override
void paint(Canvas canvas, Size size) {
Paint circle = _brush
..color = Colors.blue.shade800.withOpacity(0.6);
Paint needle = _brush
..color = Colors.lightBlueAccent;
double radius = min(size.width / 2.2, size.height / 2.2);
Offset center = Offset(size.width / 2, size.height / 2);
Offset start = Offset.lerp(Offset(center.dx, radius), center, .4);
Offset end = Offset.lerp(Offset(center.dx, radius), center, -2);
canvas.translate(center.dx, center.dy);
canvas.rotate(rotation);
canvas.translate(-center.dx, -center.dy);
canvas.drawLine(start, end, needle);
canvas.drawCircle(center, radius, circle);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Here is the code for the page displaying both camera preview and compass:
import 'package:camera/camera.dart';
import 'package:flutter/cupertino.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';
import'package:franck_ehrhart/camera/preview_compass.dart';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/rendering.dart';
import 'package:image_picker_saver/image_picker_saver.dart';
import 'package:flutter/services.dart';
class CompassTool extends StatefulWidget {
// Screenshot
CompassTool({Key key}) : super(key: key);
#override
_CompassToolState createState() => _CompassToolState();
}
class _CompassToolState extends State<CompassTool> {
// Screenshot
static GlobalKey screen = new GlobalKey();
// Camera
CameraController controller;
List cameras;
int selectedCameraIndex;
String imgPath;
String compassPath;
// Textinput name of room
TextEditingController nameController = TextEditingController();
String roomName = '';
#override
void initState() {
super.initState();
// Camera
availableCameras().then((availableCameras) {
cameras = availableCameras;
if (cameras.length > 0) {
setState(() {
selectedCameraIndex = 0;
});
_initCameraController(cameras[selectedCameraIndex]).then((void v) {});
} else {
print('No camera available');
}
}).catchError((err) {
print('Error :${err.code}Error message : ${err.message}');
});
}
Future _initCameraController(CameraDescription cameraDescription) async {
if (controller != null) {
await controller.dispose();
}
controller = CameraController(cameraDescription, ResolutionPreset.medium);
controller.addListener(() {
if (mounted) {
setState(() {});
}
if (controller.value.hasError) {
print('Camera error ${controller.value.errorDescription}');
}
});
try {
await controller.initialize();
} on CameraException catch (e) {
_showCameraException(e);
}
if (mounted) {
setState(() {});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blueAccent,
appBar: AppBar(
title: Text("ORIENTATION PIECES"),
centerTitle: true,
backgroundColor: Colors.blueAccent.shade700,
),
// body: Compass()
body:
Container(
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 1,
child:
_cameraPreviewWidget(),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 80,
width: double.infinity,
padding: EdgeInsets.all(15),
color: Colors.blueAccent,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
_cameraToggleRowWidget(),
_cameraControlWidget(context),
Spacer()
],
),
),
),
Card(
margin: EdgeInsets.symmetric( horizontal: 10.0, vertical :5.0),
child: TextField(
controller: nameController,
decoration: InputDecoration(
hintText: 'Nom de la pièce',
border: OutlineInputBorder(),
labelText: 'Nom de la pièce',
),
onChanged: (text) {
setState(() {
roomName = text;
//you can access nameController in its scope to get
// the value of text entered as shown below
//fullName = nameController.text;
}
);
},
),
),
]
),
),
),
);
}
/// Display the control bar with buttons to take pictures
Widget _cameraControlWidget(context) {
return Expanded(
child: Align(
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
FloatingActionButton(
child: Icon(
Icons.camera,
color: Colors.black,
),
backgroundColor: Colors.white,
onPressed: () {
_onCapturePressed(context);
},
),
],
),
),
);
}
/// Display Camera preview.
Widget _cameraPreviewWidget() {
if (controller == null || !controller.value.isInitialized) {
return const Text(
'Loading',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w900,
),
);
}
return
//screenshot
RepaintBoundary(
key: screen,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
new Positioned.fill(
child: new AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: new CameraPreview(controller)),
),
new Positioned.fill(
child: Compass(
)
),
],
),
);
}
/// Display a row of toggle to select the camera (or a message if no camera is available).
Widget _cameraToggleRowWidget() {
if (cameras == null || cameras.isEmpty) {
return Spacer();
}
CameraDescription selectedCamera = cameras[selectedCameraIndex];
CameraLensDirection lensDirection = selectedCamera.lensDirection;
return Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: FlatButton.icon(
onPressed: _onSwitchCamera,
icon: Icon(
_getCameraLensIcon(lensDirection),
color: Colors.white,
size: 24,
),
label: Text(
'${lensDirection.toString().substring(lensDirection.toString().indexOf('.') + 1).toUpperCase()}',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500
),),
),
),
);
}
// Camera
IconData _getCameraLensIcon(CameraLensDirection direction) {
switch (direction) {
case CameraLensDirection.back:
return CupertinoIcons.switch_camera;
case CameraLensDirection.front:
return CupertinoIcons.switch_camera_solid;
case CameraLensDirection.external:
return Icons.camera;
default:
return Icons.device_unknown;
}
}
void _showCameraException(CameraException e) {
String errorText = 'Error:${e.code}\nError message : ${e.description}';
print(errorText);
}
void _onCapturePressed(context) async {
try {
// Compass
RenderRepaintBoundary boundary = screen.currentContext.findRenderObject();
ui.Image image = await boundary.toImage();
ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
final compassPath =
await ImagePickerSaver.saveFile(
fileData:byteData.buffer.asUint8List() );
// Camera
final path =
join((await getTemporaryDirectory()).path, '${DateTime.now()}.png');
await controller.takePicture(path);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PreviewCompass(
imgPath: path,
compassPath: compassPath,
roomName: roomName,
)
),
);
} catch (e) {
_showCameraException(e);
}
}
void _onSwitchCamera() {
selectedCameraIndex =
selectedCameraIndex < cameras.length - 1 ? selectedCameraIndex + 1 : 0;
CameraDescription selectedCamera = cameras[selectedCameraIndex];
_initCameraController(selectedCamera);
}
}
And here is the code for the page displaying the screenshot of the previous screen:
import 'dart:io';
import 'dart:typed_data';
import 'package:esys_flutter_share/esys_flutter_share.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
// packages screenshot
import 'package:flutter/rendering.dart';
import 'package:screenshot/screenshot.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_icons/flutter_icons.dart';
// Compass
class PreviewCompass extends StatefulWidget{
final String imgPath;
final String compassPath;
final String roomName;
const PreviewCompass({Key key, this.imgPath, this.compassPath, this.roomName}) : super(key: key);
//PreviewCompass({this.imgPath,this.roomName});
#override
_PreviewCompassState createState() => _PreviewCompassState();
}
class _PreviewCompassState extends State<PreviewCompass>{
// Screenshot
File _imageFile;
ScreenshotController screenshotController = ScreenshotController();
#override
Widget build(BuildContext context) {
return Screenshot(
controller: screenshotController,
child:
Scaffold(
backgroundColor: Colors.blueAccent,
appBar: AppBar(
automaticallyImplyLeading: true,
title: Text("ORIENTATION PIECE"),
centerTitle: true,
backgroundColor: Colors.blueAccent.shade700,
),
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 2,
child: Stack(
alignment: FractionalOffset.center,
children: <Widget>[
new Positioned.fill(child:
Image.file(File(widget.imgPath),fit: BoxFit.fill,),),
new Positioned.fill(child:
Image.file(File(widget.compassPath),fit: BoxFit.fill,),),
/*
Expanded(
// flex: 1,
child:
Image.file(File(widget.imgPath),fit: BoxFit.fill,),
),
Align(
// alignment: Alignment.bottomCenter,
child: Image.file(File(widget.compassPath),fit: BoxFit.fill,),
),*/
],
),
),
Card(
margin: EdgeInsets.symmetric( horizontal: 10.0, vertical :5.0),
child: ListTile (
leading: Icon(
FontAwesome.compass,
color: Colors.blue.shade900,
),
title: (
Text (widget?.roomName,
style: TextStyle(
fontSize: 15.0,
fontFamily: 'Source Sans Pro',
color: Colors.blue.shade900,
)
)
),
)
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
width: double.infinity,
height: 60.0,
color: Colors.black,
child: Center(
child: IconButton(
icon: Icon(Icons.share,color: Colors.white,),
onPressed: () async {
_takeScreenshotandShare();
},
),
),
),
),
],
),
),
),
);
}
// Screenshot
_takeScreenshotandShare() async {
_imageFile = null;
screenshotController
.capture(delay: Duration(milliseconds: 10), pixelRatio: 2.0)
.then((File image) async {
setState(() {
_imageFile = image;
});
final directory = (await getApplicationDocumentsDirectory()).path;
Uint8List pngBytes = _imageFile.readAsBytesSync();
File imgFile = new File('$directory/screenshot.png');
imgFile.writeAsBytes(pngBytes);
print("File Saved to Gallery");
await Share.file('Screenshot', 'screenshot.png', pngBytes, 'image/png');
})
.catchError((onError) {
print(onError);
});
}
}
Can you please help me with this error ?
Many thanks.
Your error comes from here:
FlutterCompass.events.listen(_onData);
You should store that stream subscription in a variable and cancel it in the dispose method:
StreamSubscription<double> stream;
#override
void initState() {
super.initState();
stream = FlutterCompass.events.listen(_onData);
}
#override
void dispose() {
stream.cancel();
super.dispose();
}
I am trying to make a slider to enlarge and reduce the font but I am facing this error.
E/flutter (11441): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)]
Unhandled Exception: NoSuchMethodError: The method 'setString' was
called on null.
E/flutter (11441): Receiver: null
E/flutter (11441): Tried calling: setString("fontSizeArabic",
"23.99652777777778")
E/flutter (11441): #0 Object.noSuchMethod
(dart:core-patch/object_patch.dart:53:5)
E/flutter (11441): #1 SettingsHelpers.fontSizeArabic
(package:alquranalkareem/helper/settings_helpers.dart:20:17)
E/flutter (11441): #2 _QuranShowState._showTafseer..
(package:alquranalkareem/module/quran/show.dart:881:32)
E/flutter (11441): #3 _SliderState._handleChanged
(package:flutter/src/material/slider.dart:453:14)
E/flutter (11441): #4 _RenderSlider._startInteraction
(package:flutter/src/material/slider.dart:982:7)
E/flutter (11441): #5 _RenderSlider._handleTapDown
(package:flutter/src/material/slider.dart:1031:50)
E/flutter (11441): #6
TapGestureRecognizer.handleTapDown.
(package:flutter/src/gestures/tap.dart:463:51)
E/flutter (11441): #7 GestureRecognizer.invokeCallback
(package:flutter/src/gestures/recognizer.dart:182:24)
E/flutter (11441): #8 TapGestureRecognizer.handleTapDown
(package:flutter/src/gestures/tap.dart:463:11)
E/flutter (11441): #9 BaseTapGestureRecognizer._checkDown
(package:flutter/src/gestures/tap.dart:256:5)
E/flutter (11441): #10 BaseTapGestureRecognizer.didExceedDeadline
(package:flutter/src/gestures/tap.dart:227:5)
E/flutter (11441): #11
PrimaryPointerGestureRecognizer.didExceedDeadlineWithEvent
(package:flutter/src/gestures/recognizer.dart:496:5)
E/flutter (11441): #12
PrimaryPointerGestureRecognizer.addAllowedPointer.
(package:flutter/src/gestures/recognizer.dart:449:40)
E/flutter (11441): #13 _rootRun (dart:async/zone.dart:1122:38)
E/flutter (11441): #14 _CustomZone.run
(dart:async/zone.dart:1023:19)
E/flutter (11441): #15 _CustomZone.runGuarded
(dart:async/zone.dart:925:7)
E/flutter (11441): #16 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:965:23)
E/flutter (11441): #17 _rootRun (dart:async/zone.dart:1126:13)
E/flutter (11441): #18 _CustomZone.run
(dart:async/zone.dart:1023:19)
E/flutter (11441): #19 _CustomZone.bindCallback. (dart:async/zone.dart:949:23)
E/flutter (11441): #20 Timer._createTimer.
(dart:async-patch/timer_patch.dart:23:15)
E/flutter (11441): #21 _Timer._runTimers
(dart:isolate-patch/timer_impl.dart:384:19)
E/flutter (11441): #22 _Timer._handleMessage
(dart:isolate-patch/timer_impl.dart:418:5)
E/flutter (11441): #23 _RawReceivePortImpl._handleMessage
(dart:isolate-patch/isolate_patch.dart:174:12)
Do you have a solution to the problem?
settings_helpers
import 'dart:convert';
import 'dart:ui';
import 'package:quiver/strings.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SettingsHelpers {
static SettingsHelpers _instance;
static SettingsHelpers get instance {
if (_instance == null) {
_instance = SettingsHelpers();
}
return _instance;
}
SharedPreferences prefs;
Future fontSizeArabic(double fontSize) async {
await prefs.setString('fontSizeArabic', fontSize.toString());
}
static const double minFontSizeArabic = 22;
double get getFontSizeArabic {
String fontSizeString = prefs.getString('fontSizeArabic');
return double.tryParse(fontSizeString ?? minFontSizeArabic.toString());
}
Future setLocale(Locale locale) async {
var map = {
'languageCode': locale.languageCode,
};
var json = jsonEncode(map);
await prefs.setString('locale', json);
}
Locale getLocale() {
var json = prefs.getString('locale');
if (isBlank(json)) {
return Locale('en');
}
var mapJson = jsonDecode(json);
var locale = Locale(mapJson["languageCode"]);
return locale;
}
Future init() async {
prefs = await SharedPreferences.getInstance();
}
}
_showTafseer
Widget _showTafseer(int pageNum) {
TafseerRepository tafseerRepository = new TafseerRepository();
return FutureBuilder<List<Ayat>>(
future: tafseerRepository.getPageTafseer(pageNum),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
List<Ayat> ayat = snapshot.data;
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
children: <Widget>[
Container(
color: Theme.of(context).primaryColorLight,
child: Row(
children: <Widget>[
Slider(
min: SettingsHelpers.minFontSizeArabic,
max: maxFontSizeArabic,
value: fontSizeArabic,
activeColor: Theme.of(context).hoverColor,
inactiveColor: Theme.of(context).primaryColorDark,
onChanged: (double value) async {
await SettingsHelpers.instance
.fontSizeArabic(value);
setState(
() {
fontSizeArabic = value;
},
);
_myEventBus.eventBus.fire(
FontSizeEvent()
..arabicFontSize = value
);
},
),
Container(
decoration: BoxDecoration(
color: Theme.of(context).hoverColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5.0),
topRight: Radius.circular(5.0),
bottomLeft: Radius.circular(5.0),
bottomRight: Radius.circular(5.0),
)
),
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text('${fontSizeArabic.toInt()}',
style: TextStyle(
fontSize: 20,
color: Theme.of(context).primaryColorLight)),
),
),
],
),
),
Container(
// width: 300.0,
height: 500.0,
child: ListView.builder(
itemCount: ayat.length,
itemBuilder: (context, position) {
Ayat aya = ayat[position];
List<String> tafseer = aya.tafsser.split("))");
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Theme.of(context).backgroundColor,
borderRadius: BorderRadius.only(
topRight: Radius.circular(8.0),
topLeft: Radius.circular(8.0)
)
),
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
"﴿${tafseer.first}﴾",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "Uthmanic",
fontWeight: FontWeight.w500,
fontSize: fontSizeArabic
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0, bottom: 8.0),
child: Text(
"${tafseer.last.trim()}",
textAlign: TextAlign.justify,
style: TextStyle(
color: Theme.of(context).hoverColor,
fontFamily: 'naskh',
fontWeight: FontWeight.w100,
fontSize: fontSizeArabic
),
),
),
Divider()
],
);
}),
),
],
),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
);
}
I think the issue is with prefs not being properly initialized. Just try making your initialization simpler as below
I have used the factory design pattern. See this article to learn more about it.
Note that I used a simple floating button to trigger the action rather than the slider
class SettingsHelpers {
SharedPreferences prefs;
static final SettingsHelpers _instance = SettingsHelpers._internal();
SettingsHelpers._internal(){
_init();
}
factory SettingsHelpers() => _instance;
void _init() async {
prefs = await SharedPreferences.getInstance();
}
void fontSizeArabic(double fontSize) async {
prefs.setString('fontSizeArabic', fontSize.toString());
}
static const double minFontSizeArabic = 22;
double get getFontSizeArabic {
String fontSizeString = prefs.getString('fontSizeArabic');
return double.tryParse(fontSizeString ?? minFontSizeArabic.toString());
}
Future setLocale(Locale locale) async {
var map = {
'languageCode': locale.languageCode,
};
var json = jsonEncode(map);
await prefs.setString('locale', json);
}
Locale getLocale() {
var json = prefs.getString('locale');
if (isBlank(json)) {
return Locale('en');
}
var mapJson = jsonDecode(json);
var locale = Locale(mapJson["languageCode"]);
return locale;
}
}
class SampleTest extends StatefulWidget {
#override
_SampleTestState createState() => _SampleTestState();
}
class _SampleTestState extends State<SampleTest> {
double fontSizeArabic;
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: _onPressed),
);
}
void _onPressed() async {
double value = 18.0;
SettingsHelpers().fontSizeArabic(value);
}
}