I want to change the height of the appbar using the value of json style file - flutter

I have a app_bar_base.dart file where i have an AppBar.
class AppBarBase extends StatelessWidget implements PreferredSizeWidget {
late double appBarHeight = LoadAppStyle().loadAppStyle();
AppBarBase({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return AppBar();
}
#override
Size get preferredSize => Size.fromHeight(appBarHeight);
}
I am calling the method LoadAppStyle().loadAppStyle() from the file load_app_style:
class LoadAppStyle {
loadAppStyle() async {
String jsonData =
await rootBundle.loadString('assets/config/app_style.json');
Map<String, dynamic> data = jsonDecode(jsonData);
var getHeight = double.parse(data["app_bar"]["app_bar_height"]);
return getHeight;
}
}
In the load_app_style.dart file i grab the value of app_bar_heigt from the app_style.json
in app_style.json i have key app_bar_height where i want to change the value manually to change the height of the App bar
{
"app_bar":
{
"app_bar_height": 78
},
}
But for some reason i get the error : type 'Future<dynamic>' is not a subtype of type 'double'

You can add the type to your loadAppStyle method. Since your method is async it returns a Future.
Future<double> loadAppStyle() async {
...
return getHeight;
}
Now your error should be
type 'Future<double>' is not a subtype of type 'double'
Since your method returns a Future you have to use await to get the value.
loadAppStyle() // Future<double>
await loadAppStyle() // double
If you want to use a value of a Future inside a Widget, have a look at FutureBuilder.
For your case you could e.g. use the FutureBuilder to retrieve the height and then pass it to AppBarBase
FutureBuilder<double>(
future: loadAppStyle(),
builder: (context, snapshot) {
if(snapshot.hasData) {
return AppBarBase(height: snapshot.data);
} else {
return const Center(child: CirclularProgressIndicator));
}
}
)
And change your AppBarBase to the following.
class AppBarBase extends StatelessWidget implements PreferredSizeWidget {
AppBarBase({
Key? key,
required this.height,
}) : super(key: key);
final double height;
#override
Widget build(BuildContext context) {
return AppBar();
}
#override
Size get preferredSize => Size.fromHeight(height);
}

In your example, loadAppStyle() has no defined return type (dynamic) and it is marked as async (Future), hence the return type of this function is Future<dynamic>. Size.fromHeight function requires the double value, hence you get this error - the expected type is double, but Future<dynamic> was found here.
To resolve the type differences, you should set the return type of a function:
class LoadAppStyle {
Future<double> loadAppStyle() async {
String jsonData =
await rootBundle.loadString('assets/config/app_style.json');
Map<String, dynamic> data = jsonDecode(jsonData);
var getHeight = double.parse(data["app_bar"]["app_bar_height"]);
return getHeight;
}
}
Now, since your function is async, you must wait for your Future to finish and only then you could retrieve the double value. It would look something like this:
class AppBarBase extends StatelessWidget implements PreferredSizeWidget {
late double appBarHeight = await LoadAppStyle().loadAppStyle(); // Throws error
AppBarBase({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return AppBar();
}
#override
Size get preferredSize => Size.fromHeight(appBarHeight);
}
However, this throws an error since you cannot use the asynchronous code when initialising a value this way. What could be a better way to do this is to wait for this value somewhere outside of your widget and pass the result via the constructor:
class AppBarBase extends StatelessWidget implements PreferredSizeWidget {
final double appBarHeight;
AppBarBase({
required this.appBarHeight,
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return AppBar();
}
#override
Size get preferredSize => Size.fromHeight(appBarHeight);
}
This way, you separate your UI code from the widget. Anyway, the way of keeping this UI-specific configuration inside the JSON file sounds way overengineered - consider just passing this value via constructor directly, like: AppBarBase(appBarHeight: 78).

Related

Generic Widget for listening Streams in Flutter

I would like to create a StatefulWidget which I'll use all over the app for listening streams of different types. Since I try to keep all the widgets Stateless I wanted to extract this functionality.
I've created this:
class StreamListener<T> extends StatefulWidget {
const StreamListener({
Key? key,
required this.stream,
required this.onNewData,
required this.child,
}) : super(key: key);
final Stream<T?> stream;
final void Function(T data) onNewData;
final Widget child;
#override
State<StreamListener> createState() => _StreamListenerState<T>();
}
class _StreamListenerState<T> extends State<StreamListener> {
late StreamSubscription<T?> streamSubscription;
#override
void initState() {
streamSubscription = (widget.stream as Stream<T?>).listen(
(T? data) {
if (data != null) {
widget.onNewData(data);
}
},
);
super.initState();
}
#override
Widget build(BuildContext context) {
return widget.child;
}
#override
void dispose() {
streamSubscription.cancel();
super.dispose();
}
}
Then somewhere in the Widgets tree I use:
return StreamListener<int>(
stream: context.read<MyCubit>().toastStream,
onNewData: (int data) {
print("Received: $data");
},
child: SomeStatelessWidget(),
}
Stream logic is added to the Cubit like that:
mixin ToastStreamForCubit<T> {
final StreamController<T> _toastStreamController = StreamController<T>();
get toastStream => _toastStreamController.stream;
void emitToastEvent(T event) {
_toastStreamController.add(event);
}
}
And when I call let's say emitToastEvent(1).
I receive type '(int) => void' is not a subtype of type '(dynamic) => void'.
on line widget.onNewData(data);.
I'm not sure what is going on. I thought I've mapped all the functions and classes to a particular generic type (T), but it still says something about dynamic.
You are missing T while extending State<StreamListener>. It should be
class _StreamListenerState<T> extends State<StreamListener<T>>

Take a Function from outside then run and take value

I just want to take from outside A function that like "Future<List?> Function(String userId)" then use it, but this error appear, this tell me I try to "equalize" (if this word don't fit please edit, and title is not fitted), No I dont want to equalize, I just want to run this function and take value. You can run this code on https://dartpad.dev/?
A value of type 'Future<List<String>?> Function(String)' can't be assigned to a variable of type 'List<String>?'.
Try changing the type of the variable, or casting the right-hand type to 'List<String>?'.
--
import 'package:flutter/material.dart';
typedef getAllProducts = Future<List<String>?> Function(String userId);
class AdanaView extends StatefulWidget {
const AdanaView({Key? key, required this.getProducts}) : super(key: key);
final getAllProducts getProducts;
#override
State<AdanaView> createState() => _AdanaViewState();
}
class _AdanaViewState extends State<AdanaView> {
List<String>? products;
#override
void initState() {
super.initState();
getAll();
}
Future<void> getAll() async {
products = await widget.getProducts;
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Adana'),
),
);
}
}

Initialize StateProvider in Widget

I just want initialize provider only one time with widget param. For some reason I can't use .family. I'm not sure if this is the right way. Can you check this? Thank you.
StateProvider<String> valueStateProvider;
class Widget extends HookWidget {
final String value;
Widget({#required this.value}) {
valueStateProvider = StateProvider<String>((ref) => this.value);
}
}
Finally I found the right way to do this. There is special provider type for this situation. ScopedProvider.
final scopedProvider = ScopedProvider<String>((_) => throw UnimplementedError());
class Widget extends HookWidget {
Widget({#required this.value});
final String value;
#override
Widget build(BuildContext context) {
return ProviderScope(
overrides: [scopedProvider.overrideWithValue(this.value)],
child: AnotherWidget()
);
}
}
So you can use scopedProvider in AnotherWidget. Yay!

The value of local variable isn't used

I am new to flutter and I was following a tutorial when this error popped up. The ancestorRenderObjectOfType has deprecated and been replaced by findAncestorRenderObjectOfType so dart is throwing me errors.
What the tutor did in his video of old dart:
static T of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context
.context.ancestorRenderObjectOfType(type);
return provider.bloc;
}
static Type _typeOf() => T;
}
What I did in my code
static T of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context
.findAncestorRenderObjectOfType();
return provider.bloc;
}
static Type _typeOf<T>() => T;
}
If I put
BlocProvider<T> provider = context
.findAncestorRenderObjectOfType(type);
I get an error saying
Too many positional arguements. 0 expected, but 1 found.
The ENTIRE code
abstract class BlocBase {
void dispose();
}
//Genric Bloc provider
class BlocProvider<T extends BlocBase> extends StatefulWidget {
BlocProvider({
Key key,
#required this.child,
#required this.bloc,
}) : super(key: key);
final T bloc;
final Widget child;
#override
_BlocProviderState<T> createState() => _BlocProviderState<T>();
static T of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context
.findAncestorRenderObjectOfType(); //context.ancestorRenderObjectOfType(type); GOTCHA
return provider.bloc;
}
static Type _typeOf<T>() => T;
}
class _BlocProviderState<T> extends State<BlocProvider<BlocBase>> {
#override
void dispose() {
widget.bloc.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return widget.child;
}
}
Thank you!
findAncestorRenderObjectOfType doesnt take the type as argument instead it is a generic method where you can provide the type while calling the method. So your code will be as below:
static T of<T>(BuildContext context) {
BlocProvider<T> provider = context
.findAncestorRenderObjectOfType<BlocProvider<T>>();
return provider.bloc;
}

I am getting this error styling my portfolio in flutter

import 'package:flutter/material.dart';
class ThemeSwitcher extends InheritedWidget {
final _ThemeSwitcherWidgetState data; // We'll use ThemeSwitcher to get access to the current state of ThemeSwitcherWidget
const ThemeSwitcher({
Key key,
#required this.data,
#required Widget child,
}) : assert(child != null),
super(key: key, child: child);
static _ThemeSwitcherWidgetState of(BuildContext context) { //This method returns the current state of the ThemeSwitcherWidget. This will be used down the tree
return (context.dependOnInheritedWidgetOfExactType(ThemeSwitcher)
as ThemeSwitcher)
.data;
}
#override
bool updateShouldNotify(ThemeSwitcher old) {
return this != old;
}
}
class ThemeSwitcherWidget extends StatefulWidget {
final bool initialDarkModeOn; // this is the initial state of the variable
final Widget child; // child to which this boolean variable should be propagated upon change. This will be our app in this case
ThemeSwitcherWidget({Key key, this.initialDarkModeOn, this.child})
: assert(initialDarkModeOn != null),
assert(child != null),
super(key: key);
#override
_ThemeSwitcherWidgetState createState() => _ThemeSwitcherWidgetState();
}
class _ThemeSwitcherWidgetState extends State<ThemeSwitcherWidget> {
bool isDarkModeOn;
void switchDarkMode() { //method used to toggle dark mode during the runtime of the app
setState(() {
isDarkModeOn = !isDarkModeOn;
});
}
#override
Widget build(BuildContext context) {
isDarkModeOn = isDarkModeOn ?? widget.initialDarkModeOn; // this is the build method which would build the widget tree with the above info
return ThemeSwitcher(
data: this,
child: widget.child,
);
}
}
Too many positional arguments: 0 expected, but 1 found.
Try removing the extra positional arguments, or specifying the name for named arguments.
This is the Error I am continuously facing the issue after trying many methods.
I would like to know how would this problem can be solved as I am not getting any good solution from searches.
Return the following statement in _ThemeSwitcherWidgetState of(BuildContext context) method of your code:
return (context.dependOnInheritedWidgetOfExactType<ThemeSwitcher>()).data;