How can I apply dart extension methods in the Flutter Logging library? - flutter

I am trying logging library in my flutter project. They have some good record messages (e.g. record.name, record.message, etc.) For my project, I want to extend by using dart extension methods this package to add some more record message (e.g. record.version, record.eventName, etc.). As a beginner in dart, I am not sure completely how to do that?
Here is an example that I tried but failed.
extension CustomLog on LogRecord {
String version(LogRecord version) => "1.0";
String eventName(LogRecord eventName) => "userNameChangedEvent";
}
Please provide me some suggestions/examples how can I extend any package and use it on my own.

Logging does not support extending (with extension) the LogRecord to add custom fields.
You can pass all your custom info as an class object in object param and retrieve it later.
Something like
class CustomLogAttributes {
final String version;
final String eventName;
CustomLogAttributes(this.version, this.eventName);
}
then
log.fine("example log message", object: CustomLogAttributes("1.1.0", "example_event");

Related

How to setup different firebase environments(Flavors) in Flutter Web

I am trying to set up different firebase environments(for example :qa,prod) in a flutter project.
I created two projects in firebase, one for production, one for the qa. Then, in an iOS or Android project, I using separate google-services.json or GoogleServices-Info.plist files.
but,how to do it in Flutter web?
If you need this dynamic config in dart code, you can create an interface that represents your configs and create implementations for each environment, so you can change the implementation passing a parameter when run flutter app (using --dart-define).
Imagine the case that you have a prod and an homolog environment, you can create three files:
The first one is the contract of your configs, that all environments must have implemented.
abstract class AppConfig {
String get baseUrl;
}
And we create a class for each environment, with the implementation of the configs defined in AppConfig.
class ProdConfig implements AppConfig {
#override
String get baseUrl => 'https://my-prod-url.com';
}
class HomologConfig implements AppConfig {
#override
String get baseUrl => 'https://my-homolog-url.com';
}
When we need to get the config class, we instantiate based on parameter passed by --dart-define
AppConfig getConfig() {
const environmentParameter = String.fromEnvironment('ENV');
switch (environmentParameter) {
case 'prod': return ProdConfig();
case 'homolog': return HomologConfig();
default: throw Error(); // You can set a default environment
}
}
And when you run your app, you just need to pass this parameter, like the example below:
flutter run --dart-define ENV=prod
Or in homolog:
flutter run --dart-define ENV=homolog
BUT, if you need to set configs like firebase, you should check this answer

passing dynamic strings to AppLocalizations.of(context)! in Flutter

right now Im working in App using Flutter and I have 4 different languages, I use json (arb files) for localization (translation)
I need to pass different string values which app fetch them using API's as shown in example below
AppLocalizations.of(context)!snapshot.data![index].state_pickup[0]
however "AppLocalizations.of(context)!" doesn't fetch the return data from snapshot.data![index].state_pickup[0] and instead it looks for it as string and tries to search for match string name in AppLocalization.dart class?
Any idea how I can pass dynamic string arguments to AppLocalizations.of(context)!?
What you are trying to do, invoking a method by its name at runtime, is called reflection, and this is not supported by Flutter natively (though there are packages that try to emulate this, but I have no experience with them).
What will work for you, even though it might be tedious, is manually mapping your value from the API to the corresponding method from AppLocalizations.of(context).
String localizedString = getLocalizedString(snapshot.data![index].state_pickup[0], context);
String getLocalizedString(String key, BuildContext context) {
switch (key) {
case "possible_api_value_1":
return AppLocalizations.of(context)!.possibleApiValue1;
case "possible_api_value_2":
return AppLocalizations.of(context)!.possibleApiValue2;
...
}

How to ignore package when building flutter project for web?

I have a project which uses flutter_libserialport library on macOS.
I am modifying it to work on web however this library does not work on web.
I am building a web implementation using navigator.serial in javascript which works fine.
However when I attempt to build the project for web I get the following error
/opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/libserialport-0.2.0+3/lib/src/config.dart:25:8: Error: Not found: 'dart:ffi'
import 'dart:ffi' as ffi;
This makes sense since FFI is not available on web.
But I don't even need the libserialport library on web any way.
How can I get flutter to ignore it?
I tried this however it doesn't contain information on how to exclude a package.
It also does not contain information on how to ignore it specifically for web. It seems to just ignore it in general.
Maybe you should guard your usages of libserialport with the kIsWeb predicate like following:
if(!kIsWeb){
// libserialport code execution here
}
I searched a lot as well and didn't find a way you can do that, I think this should be handled by the package itself not the package's users like in path_provider for instance.
As a workaround I have created a dummy libserialport's SerialPort class for web only as follows:
dummy_serialport.dart:
class SerialPort {
final String name;
static List<String> availablePorts = ['dummy'];
static SerialPortError? lastError;
SerialPort(this.name);
bool openReadWrite() {
return false;
}
}
class SerialPortError {}
// add more properties and functions as needed
main.dart:
import 'package:libserialport/libserialport.dart'
if (dart.library.html) './dummy_serialport.dart'
if (dart.library.io) 'package:libserialport/libserialport.dart';
....
if (!kIsWeb) {
final name = SerialPort.availablePorts.first;
final port = SerialPort(name);
if (!port.openReadWrite()) {
print(SerialPort.lastError);
exit(-1);
}
}
....
....
It's bad, I know :( but it works! maybe you can contact the package author to get more insight and if opening a PR where the interfaces are separated from the FFI implementation so that importing the classes wouldn't break web or something.

How to use Strings to access class members in Flutter

I want to set use Strings from an API as Fontawesome icons. I have added the font_awesome_flutter plugin.
I need to store the icon name in a variable and then create an object from it. I would imagine it to like this:
String iconfromApi = 'suitcase';
Icon(FontAwesomeIcons.iconfromApi);
As described here, you would need have access to the dart:mirrors pacakage, which is not avaible in Flutter.
A solution that would work in Flutter is creating a helper method. This means that you will have to code in cases for all icon names you want to use. If you do not want to write all of that by hand, you can take a look at a package like reflectable as mentioned in the GitHub comment or potentially source_gen or build_runner, however, I am not sure if the latter two are well suited.
Anyways, what you could also write by hand is a helper function like this:
IconData fontAwesomeIconFromString(String name) {
switch (name) {
case 'suitecase':
return FontAwesomeIcons.suitecase;
case 'gamepad':
return FontAwesomeIcons.gamepad;
// ...
}
}
In your code, you can now use it like this:
String iconfromApi = 'suitcase';
Icon(fontAwesomeIconFromString(iconFromApi));

How to use classes like RegistryRoot correctly in custom actions?

I have to implement a custom action to search the windows registry for the installed version of the dotnet framework. Therefore I thought to extend the ReadRegistryValueAction to integrate my individual search algorithm. But the custom action will not be found at the IDE. So I extends the action from the AbstractInstallAction and included the RegistryRoot class to configure the action inside the IDE the same way as with provided registry actions of install4j framework.
public class CheckDotNetInstallationAction extends AbstractInstallAction {
private RegistryRoot registryRoot;
public RegistryRoot getRegistryRoot() {
return registryRoot;
}
public void setRegistryRoot(RegistryRoot registryRoot) {
this.registryRoot = registryRoot;
}
#Override
public boolean install(InstallerContext paramInstallerContext)
throws UserCanceledException {
// do custom search
return false;
}
}
But instead to get a dropdown list, there is only a blank field. I expected also a dropdown list the same way as in the present registry action. Now there are two questions:
Is it possible to extends existing actions/screens/forms and to use and configure it in the IDE or is it necessary to extends from the AbstractInstallAction?
How can I use classes like RegistryRoot for my custom components the same way as they are used in the actions provided by the install4j framework? Specifically the way to configure these components inside the IDE.
You have to add add a BeanInfo class and set an enumeration mapper. See the source file
samples/customCode/SampleActionBeanInfo.java
in your install4j install4j Installation and and look for the the call to setEnumerationMappers.