Freezed class with generic callback - flutter

I would like to define a freezed class [https://pub.dev/packages/freezed] with a generic callback.
Freezed class:
import 'package:freezed_annotation/freezed_annotation.dart';
part 'foo.freezed.dart';
#freezed
abstract class Foo<T> with _$Foo {
factory Foo({
// String Function() callBackOne,
String Function(T) callBackTwo,
}) = _Foo;
}
Widget using the Freezed class:
class MyHomePage extends StatelessWidget {
// final fooOne = Foo<int>(callBackOne: () => 'Result: 42');
final fooTwo = Foo<int>(callBackTwo: (value) => 'Result: ${value * 3}');
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(fooTwo.callBackTwo(14)),
),
);
}
}
Error:
lib/foo.freezed.dart:128:26: Error: The return type of the method '_Foo.callBackTwo' is 'String Function(T)', which does not match the return type, 'String Function(dynamic)', of the overridden method, '_$Foo.callBackTwo'.
Change to a subtype of 'String Function(dynamic)'.
String Function(T) get callBackTwo;
^
lib/foo.freezed.dart:31:26: Context: This is the overridden method ('callBackTwo').
String Function(T) get callBackTwo;
^
Do you know what is wrong with my code? Is it a limitation of Freezed? Do you know a workaround?
Thank you!!!

It looks like a flaw in Dart type system. I've encouraged something like that either. I don't know a clean workaround. You can specify not a direct function but a function wrapped into a class with a "strong" method signature. Something like that should work:
#freezed
abstract class Foo<T> with _$Foo {
factory Foo({
Func<T> callBackTwo,
}) = _Foo;
}
class Func<T> {
final String Function(T) _apply;
Func(this._apply) : assert(_apply != null);
String call(T value) {
return _apply(value);
}
}
class MyHomePage extends StatelessWidget {
final fooTwo = Foo<int>(Func<int>((value) => 'Result: ${value * 3}'));
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(fooTwo.callBackTwo(14)),
),
);
}
}
It's not so good, because you are to type more. But we can minimize typing a bit:
#freezed
abstract class Foo<T> with _$Foo {
factory Foo({
Func<T> callBackTwo,
}) = _Foo;
factory Foo.from(String Function(T) arg) {
return Foo<T>(callBackTwo: Func<T>(arg));
}
}
class MyHomePage extends StatelessWidget {
final fooTwo = Foo<int>.from((value) => 'Result: ${value * 3}');
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(fooTwo.callBackTwo(14)),
),
);
}
}

Related

Error: Type argument 'RoutesBloc' doesn't conform to the bound 'BlocBase<S>' of the type variable 'B' on 'BlocBuilder'

I'm getting this error and I have no clue where it's coming from.
class Routes extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocBuilder<RoutesBloc, RoutesEvent>( // <-- It occurs here
builder: (context, state) {
return Text('...');
},
);
}
}
Full error:
lib/screens/home_screen.dart:86:12: Error: Type argument 'RoutesBloc' doesn't conform to the bound 'BlocBase' of the type variable 'B' on 'BlocBuilder'.
'RoutesBloc' is from '/blocs/routes/routes_bloc.dart' ('lib/blocs/routes/routes_bloc.dart').
'BlocBase' is from 'package:bloc/src/bloc.dart' ('../../AppData/Local/Pub/Cache/hosted/pub.dartlang.org/bloc-7.0.0/lib/src/bloc.dart').
Try changing type arguments so that they conform to the bounds.
return BlocBuilder<RoutesBloc, RoutesEvent>(
^
I use a multiplocprovider in my main.dart like this:
MultiBlocProvider(
providers: [
...,
BlocProvider<RoutesBloc>(
create: (_) => RoutesBloc(
apiRepository: ApiRepository.create(),
)..add(RoutesLoaded()),
),
],
child: AppView(),
)
routes_state.dart:
abstract class RoutesState extends Equatable {
const RoutesState();
#override
List<Object> get props => [];
}
class RoutesLoadInProgress extends RoutesState {}
class RoutesLoadSuccess extends RoutesState {
final List<BoulderingRoute> routes;
const RoutesLoadSuccess([this.routes = const []]);
#override
List<Object> get props => [routes];
}
class RoutesLoadFailure extends RoutesState {}
routes_event.dart:
abstract class RoutesEvent extends Equatable {
const RoutesEvent();
#override
List<Object> get props => [];
}
class RoutesLoaded extends RoutesEvent {}
class RouteAdded extends RoutesEvent {
final BoulderingRoute route;
const RouteAdded({this.route}) : assert(route != null);
#override
List<Object> get props => [route];
}
class RouteUpdated extends RoutesEvent {
final BoulderingRoute route;
const RouteUpdated({this.route}) : assert(route != null);
#override
List<Object> get props => [route];
}
class RouteDeleted extends RoutesEvent {
final BoulderingRoute route;
const RouteDeleted({this.route}) : assert(route != null);
#override
List<Object> get props => [route];
}
routes_bloc.dart:
class RoutesBloc extends Bloc<RoutesEvent, RoutesState> {
final ApiRepository _apiRepository;
RoutesBloc({ApiRepository apiRepository})
: assert(apiRepository != null),
this._apiRepository = apiRepository,
super(RoutesLoadInProgress());
#override
Stream<RoutesState> mapEventToState(
RoutesEvent event,
) async* {
print(event);
if (event is RoutesLoaded) {
yield* _mapRoutesLoadedToState();
}
}
Stream<RoutesState> _mapRoutesLoadedToState() async* {
try {
print('start');
final List<BoulderingRoute> routes =
await _apiRepository.fetchBoulderingRoutes();
yield RoutesLoadSuccess(routes);
} catch (_) {
yield RoutesLoadFailure();
}
}
}
I firstly thought that there must be something wrong with my RoutesBloc but changing the blocbuilder to a bloc that I'm successfully using at another place ends up with the same error.
Does someone know where this is coming from?
It should be return BlocBuilder<RoutesBloc, RoutesState>
Check this: https://pub.dev/packages/flutter_bloc#blocbuilder
BlocBuilder<BlocA, BlocAState>(
builder: (context, state) {
// return widget here based on BlocA's state
}
)

Error: Type argument 'T' doesn't conform to the bound 'Object' of the type variable 'T' on 'GetIt.call'. After migrating to Null Safety

I'm in the process of migrating over a large project to null safety and I'm coming across a strange error I'm not entirely sure how to fix.
"Error: Type argument 'T' doesn't conform to the bound 'Object' of the type variable 'T' on 'GetIt.call'."
class BaseView<T extends BaseProvider?> extends StatefulWidget {
final Widget Function(BuildContext context, T value, Widget? child)? builder;
final Function(T)? onModelReady;
BaseView({this.builder, this.onModelReady});
#override
_BaseViewState<T> createState() => _BaseViewState<T>();
}
class _BaseViewState<T extends BaseProvider?> extends State<BaseView<T?>> {
T model = locator<T>(); <---- This is throwing it
#override
void initState() {
if (widget.onModelReady != null) {
widget.onModelReady!(model);
}
super.initState();
}
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<T?>(
create: (context) => model,
child: Consumer<T>(builder: widget.builder!),
);
}
}
I can't find much info on this error and so far any method I've tried hasn't worked out. Can anyone be of assistance?
I'm using Provider for state management and BaseView is what wraps all my other views during build; e.g.:
class EquipmentMainView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BaseView<EquipmentProvider>(
onModelReady: (model) async {
model.getAllFunctions();
},..
Posting here for anyone else that might eventually run across this in the future, just changed the nullability of BaseProvider suggested by jamesdlin by changing
class BaseView<T extends BaseProvider?>
to
class BaseView<T extends BaseProvider>
I had similar issues when I upgraded to flutter 2.0 I made the generic methods in Generic class to explicitly extends Base class Object i.e
from:
import 'package:get_it/get_it.dart';
class PoultryBabaRegistry<T> {
static GetIt _getIt = GetIt.instance;
static void register<T>(T model) {
_getIt.registerSingleton<T extends Object >(model, signalsReady: true);
}
static void remove<T>(T model) {
_getIt.unregister<T extends Object>(instance:model);
}
static T getIt<T>() {
return _getIt.get<T>();
}
}
to:
class PoultryBabaRegistry<T extends Object> {
static GetIt _getIt = GetIt.instance;
static void register<T extends Object>(T model) {
_getIt.registerSingleton<T >(model, signalsReady: true);
}
static void remove<T extends Object>(T model) {
_getIt.unregister<T>(instance:model);
}
static T getIt<T extends Object>() {
return _getIt.get<T>();
}
}

Can you use a class name in a conditional statement?

I have a custom widget that uses a ListTile. I would like to set the Leading: property to a Checkbox if the Class A is building the widget, but set the Leading property to Null if Class B is building the widget.
Is it possible for the ListTile to know the name of the class that is building it?
Or is there a better way to approach this type of problem?
You can either use the is operator or use obj.runtimeType to check the type of object.
Refer to this link to understand the difference between them.
Here's an example snippet.
class CustomListTile{
var obj;
CustomListTile(this.obj);
void isSameClass(){
// if(obj.runtimeType == Truck)
if(obj is Truck){
print("Building checkbox");
}else{
print("returning Null");
}
}
}
class Chopper{
void test(){
CustomListTile obj = CustomListTile(this);
obj.isSameClass();
}
}
class Truck{
void test(){
CustomListTile obj = CustomListTile(this);
obj.isSameClass();
}
}
void main(){
Chopper objChop = Chopper();
objChop.test();
Truck objTruck = Truck();
objTruck.test();
}
Would passing a boolean like this do the job for you?
class CustomListTile extends StatelessWidget {
const CustomListTile({Key? key, this.hasLeading = false}) : super(key: key);
final bool hasLeading;
#override
Widget build(BuildContext context) {
return ListTile(
leading: hasLeading ? const Icon(Icons.person) : null,
);
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ListView(
children: [
CustomListTile(hasLeading: true), // This one has leading
CustomListTile(), // This one does not
],
);
}
}

How to integrate native_pdf_view into my app (flutter)?

I want to show a PDF file with the package native_pdf_view (https://pub.dev/packages/native_pdf_view) in my app.
I tried it like this:
class OStundenplan extends StatelessWidget {
final pdfController = PdfController(
document: PdfDocument.openAsset('assets/stundenplan.pdf'),
);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Offline Stundenplan'),
),
body: Builder(builder: (BuildContext context) {
return PdfView(controller: _pdfController);
}));
}
}
ostundenplan() {
Navigator.push(
context,
MaterialPageRoute(
Widget pdfView() => PdfView(
controller: pdfController,
);
}
later in the app:
RaisedButton.icon(onPressed: ostundenplan, icon: Icon(Icons.signal_wifi_off), label: Text('Offline Stundenplan'),),
but it doesn't work. Can anyone help me?
EDIT:
When I try it like pradyot1996 says, I get this:
Compiler message:
lib/main.dart:315:37: Error: Type 'PDFReader' not found.
class _PDFReaderState extends State<PDFReader> {
^^^^^^^^^
lib/main.dart:315:7: Error: Type argument 'invalid-type' doesn't conform to the bound 'StatefulWidget' of the type variable 'T' on 'State' in the supertype 'State' of class '_PDFReaderState'.
- 'StatefulWidget' is from 'package:flutter/src/widgets/framework.dart' ('/C:/flutter/packages/flutter/lib/src/widgets/framework.dart').
Try changing type arguments so that they conform to the bounds.
class _PDFReaderState extends State<PDFReader> {
^
/C:/flutter/packages/flutter/lib/src/widgets/framework.dart:1029:22: Context: This is the type variable whose bound isn't conformed to.
abstract class State<T extends StatefulWidget> with Diagnosticable {
^
Compiler message:
lib/main.dart:315:37: Error: Type 'PDFReader' not found.
class _PDFReaderState extends State<PDFReader> {
^^^^^^^^^
lib/main.dart:315:7: Error: Type argument 'invalid-type' doesn't conform to the bound 'StatefulWidget' of the type variable 'T' on 'State' in the supertype 'State' of class '_PDFReaderState'.
- 'StatefulWidget' is from 'package:flutter/src/widgets/framework.dart' ('/C:/flutter/packages/flutter/lib/src/widgets/framework.dart').
Try changing type arguments so that they conform to the bounds.
class _PDFReaderState extends State<PDFReader> {
^
/C:/flutter/packages/flutter/lib/src/widgets/framework.dart:1029:22: Context: This is the type variable whose bound isn't conformed to.
abstract class State<T extends StatefulWidget> with Diagnosticable {
^
Target kernel_snapshot failed: Exception: Errors during snapshot creation: null
build failed.
^^^^^^^^^^
Looks like it didn't find the PDFReader.
What can I do?
EDIT 2:
That's the red screen I get:
btw, this is my navigator:
ostundenplan() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PDFReader()));
}
EDIT 3:
class PDFReader extends StatefulWidget {
static const route_name = 'pdf_reader';
#override
_PDFReaderState createState() => _PDFReaderState();
}
class _PDFReaderState extends State<PDFReader> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Offline Stundenplan'),
),
body: FutureBuilder(
future: PDFDocument.fromAsset('assets/stundenplan.pdf'),
builder: (_, pdfData) {},
),
);
}
}
Try this package flutter_plugin_pdf_viewer .
This works perfectly fine for me. I had the PDF file saved in firebase storage and open it through the URL.
PDFDocument doc = await PDFDocument.fromURL(LINK);
PDFViewer(document: doc)
EDIT:
Below class shows the implementation. You can even use a StatelessWidget class if you don't need to refresh the state.
class PDFReader extends StatefulWidget {
static const route_name = 'pdf_reader';
#override
_PDFReaderState createState() => _PDFReaderState();
}
class _PDFReaderState extends State<PDFReader> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Document'),
),
body: FutureBuilder(
future: PDFDocument.fromURL('http://www.africau.edu/images/default/sample.pdf'),
builder: (_, pdfData) {
if (pdfData.connectionState == ConnectionState.waiting) {
return CenterCircularProgressBar();
} else if (pdfData.data == null) {
return CenterText('Not able to open PDF file');
} else {
return PDFViewer(document: pdfData.data);
}
},
),
);
}
}
Now you just need to Navigate to PDFReader widget. If you want to pass the PDF data from one screen to another you can also do that instead of hard coding it in the PDFReader screen.
CenterCircularProgressBar() is a custom widget which shows a Circular
progress bar in the center of the screen till the PDF is loaded
and,
CenterText is a custom widget which shows an error if we don't get the
data back from the PDFDocument.fromURL. Code is given below.
So in this line
PDFDocument.fromURL('http://www.africau.edu/images/default/sample.pdf')
You can use the fromAsset, fromURL and fromFile methods provide by the PDFDocument to show the PDF. PDFViewer is custom class provided by the package which will handle the PDF view.
class CenterCircularProgressBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const Center(
child: CircularProgressIndicator(),
);
}
}
class CenterText extends StatelessWidget {
final String stringValue;
CenterText(this.stringValue);
#override
Widget build(BuildContext context) {
return Center(
child: Text(
stringValue,
),
);
}
}
If you wish to do it with the original library "(https://pub.dev/packages/native_pdf_view)" you can do this:
You need to use a Stateful widget if you want to interact with the PDF. (let say your PDF have more than 1 page)
When you call the PdfView remember to include the document and the controller.
(You were missing the asset path in the constructor of PdfView).
PdfView(
controller: _pdfController,
onDocumentLoaded: (document) {
setState(() {
_allPagesCount = document.pagesCount;
});
},
onPageChanged: (page) {
setState(() {
_actualPageNumber = page;
});
},
),
The above code is an extract from the original library example: https://pub.dev/packages/native_pdf_view/example
So your code should look something like this:
ostundenplan() {
Navigator.push(
context,
MaterialPageRoute(
Widget pdfView() => PdfView(
controller: pdfController,
onDocumentLoaded: (document) {
setState(() {
_allPagesCount = document.pagesCount;
});
},
onPageChanged: (page) {
setState(() {
_actualPageNumber = page;
});
},
),
);
}
adding these variables at the top of your class as well:
int _actualPageNumber = _initialPage, _allPagesCount = 0;
This help you without changing your initial library.

How can I access a public static variable from a different class in dart?

I am unable to access a public static boolean from a different class, eg. I have a boolean isFull in my StudyjiosListviewScreen class as shown:
class StudyjiosListviewScreen extends StatefulWidget {
#override
_StudyjiosListviewScreenState createState() => _StudyjiosListviewScreenState();
}
class _StudyjiosListviewScreenState extends State<StudyjiosListviewScreen> {
static bool isFull = false;
...
I want to use this boolean isFull in another class JoinStudyjio.
I created an instance of the StudyjiosListviewScreen class in the JoinStudyjio class like this:
StudyjiosListviewScreen listviewScreen = StudyjiosListviewScreen();
But when I try to use the boolean isFull like this:
if (listviewScreen.isFull) {
...
I get an error. I have already imported the file for the StudyjiosListviewScreen class inside the file for the JoinStudyjio class.
This is because StudyjiosListviewScreen and _StudyjiosListviewScreenState are 2 different classes.
The static variable isFull which you are trying to access is of the later one and you are trying to access it by creating an instance of the first one. If it had been a static variable of the class StudyjiosListviewScreen, you could have accessed it without even creating an instance of that class like this StudyjiosListviewScreen.isFull
If I understood your issue correctly, and following the suggestion I made in my comment, here is a code example of sharing a variable and a method to change it's value, down to two classes from a parent class:
class VariableSharing62951032 extends StatefulWidget {
#override
_VariableSharing62951032State createState() => _VariableSharing62951032State();
}
class _VariableSharing62951032State extends State<VariableSharing62951032> {
bool isFull = false;
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ClassA62951032(isFull: isFull, swapIsFull: swapIsFull,),
ClassB62951032(isFull: isFull, swapIsFull: swapIsFull,),
],
);
}
void swapIsFull(){
setState(() {
isFull = !isFull;
});
}
}
class ClassA62951032 extends StatefulWidget {
final bool isFull;
final Function swapIsFull;
ClassA62951032({
this.isFull,
this.swapIsFull
});
#override
_ClassA62951032State createState() => _ClassA62951032State();
}
class _ClassA62951032State extends State<ClassA62951032> {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Text('Class A'),
Text(widget.isFull.toString()),
RaisedButton(
child: Text('Swap isFull'),
onPressed: () => widget.swapIsFull(),
),
],
);
}
}
class ClassB62951032 extends StatefulWidget {
final bool isFull;
final Function swapIsFull;
ClassB62951032({
this.isFull,
this.swapIsFull
});
#override
_ClassB62951032State createState() => _ClassB62951032State();
}
class _ClassB62951032State extends State<ClassB62951032> {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Text('Class B'),
Text(widget.isFull.toString()),
RaisedButton(
child: Text('Swap isFull'),
onPressed: () => widget.swapIsFull(),
),
],
);
}
}
Sharing variables and methods between classes it's a huge deal in Flutter.
First of all, you are passing it in the wrong way. That variable is saved in your state widget, which is defined as private.
So, or you define it as public and than you pass a key associated with your state, or you change complitelly approach. I don't like passing keys and it is not good for production, so I will give you a better example using providers:
add provider library to your pubspec.yaml:
provider: ^4.3.1 // Or latest version
Create a class where you can save that value:
class valuesHelper {
//In this class we are storing global, dynamic values
bool _isSeen;
valuesHelper() {
this._isSeen = false;
}
void setValue(bool value) {
this._isSeen = value;
}
bool getValue(){
return this._isSeen;
}
}
Now wrap your main with the provider and pass the valuesHelper();
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return Provider(
create: (_) => valuesHelper(),
child: MaterialApp(
home: MyHomePage(),
),
);
}
}
Now call the Provider.of(context) wherever you want.
//Somwhere in your code when you have access to context:
ValueHelper helper = Provider.of<valueHelper>(context);
helper.setValue(true);
//Somwhereelse in your code when you have access to context:
ValueHelper helper = Provider.of<valueHelper>(context);
bool theValueIWant = helper.getValue();
If you have asynchronous stuff and huge state managment Blocs are even better and fancier, but for this kind of things Providers are more than enough.