how can I compound getters in dart to avoid duplication - flutter

I have lots of getters for localizations (they are coming from the json file for example) such as:
String get start {
return localizedValues[locale.languageCode]!['start']!;
}
String get hours {
return localizedValues[locale.languageCode]!['hours']!;
}
String get minutes {
return localizedValues[locale.languageCode]!['minutes']!;
}
String get seconds {
return localizedValues[locale.languageCode]!['seconds']!;
}
So I want to compound them since they use some common codes (I tried to create final someWord = commonCode; but It did not work, so I wanted to ask)
Now, If I want to reach them, I use myClass.of(context).start for example. So, in the end, I will reach using the same way but in the class which is above, I will not do any duplication If you help me. So, I need your help to avoid duplication.

I would recommend using a data class to hold localisation data instead of just a Map, or using a package such as i10n to do the translations for you.
There are a couple of ways you can shorten this code. For starters, you can extract localizedValues[locale.languageCode]! to its own getter, like this:
Map<String, String> get localeValues => localizedValues[locale.languageCode]!;
Then all your methods become a bit shorter:
String get seconds {
return localeValues['seconds']!;
}
Additionally, you can shorten your getters by removing the function body and using an arrow function instead, like I did above for the localeValues:
String get seconds => localeValues['seconds']!;
Do this for all your getters, and your code is now shorter.

You can use this method, and shorten the code:
String getTime(String languageCode, String time) {
return localizedValues[languageCode]![time]!;
}
getTime("1529", "seconds");
getTime("859", "mitutes");
getTime("9632", "hours");

Related

How to avoid typing incorrect serialization name when updating a property from a database?

I'm using Firestore database and i want to update some fields from a document.
var updateFields = {
"completedByUid": authRepo.getUID(),
"completed": currentTime,
};
return await docRef.update(updateFields);
Instead of typing the properyName manually how can i get the name directly from an object Object, and by this avoiding typing it incorrectly or outdated.
Let's say i have an object like:
#JsonSerializable()
class OrderModel {
String? completedByUid;
String? completed;
}
and i want to get the serialization name something like:
var updateFields = {
OrderModel.completedByUid: authRepo.getUID(),
or
var updateFields = {
order.completedByUid.properyName: authRepo.getUID(),
Normally this would be a use for reflection but that might be overkill.
I think the design pattern you could use is a constant that you use to both set and read the values, like so:
const String ORDER_MODEL_COMPLETED_BY_UID_PROPERTY = "completedByUid";
This doesn't exactly guarantee a match if, for example, some existing data is present and may have a name mismatch.
For an answer based on reflection, see this answer.

Why use setter when you can assign massively using a method?

I found out that I can assign data to a property using set or a method.
class Human {
String name, address;
set rewriteName(String name) {
this.name = name;
}
set rewriteAddress(String address) {
this.address = address;
}
void rewrite(String name, String address) {
this.name = name;
this.address = address;
}
String introduction() => "Name is $name. I live in $address";
Human(this.name, this.address);
}
I tried to assign some data using both way, and method looks more efficient than using setter, since its only need just one call to change everything:
Human human = Human('stacker', 'baghdad');
// using method
human.rewrite('overflow', 'new york');
// using setter
human.rewriteName = "Hooman";
human.rewriteAddress = "jakarta";
my question is why using a setter instead of method?
Typically, the targets of getters and setters are made private so they're not directly accessible from outside of the file or library.
class Business {
String name, _address;
double lat, long;
bool coordsCalculated = false;
Map propertyRecords = {};
get address {
return _address;
}
set address(String address) {
if (address == _address) return; // Nothing changed;
_address = address;
// API call to calculate lat/log
APICall(onSuccess: (data) {
lat = data.lat;
long = data.long;
coordsCalculated = true;
});
}
void rewrite(String name, String address) {
this.name = name;
this.address = address;
}
String summary() {
if (coordsCalculated) return "Business name is $name, here's a link to the map!";
return "Business name is $name, at $_address.";
}
Human(this.name, String address) {
this.address = address;
}
}
The user of the class feels like they're using a normal property, but it does other silent things.
Methods can do this too, yes, but this can feel cleaner.
Importantly, getters and setters cannot be asynchronous which definitely can give methods an advantage, but there are plenty of valid uses.
Getters and setters are also easier to read, when being used. Less parentheses are always a good thing.
You certainly don't need to always use them, or use them when they do nothing but set the variable, but they can be nice.
In one of my Widgets, I have a getter that looks something like
FileState get fileState => FileUploaderKey.currentState!. widget.file.state;
It's so much easier to read this way. It gets the current state of the file, always, whereas
FileState fileState = FileUploaderKey.currentState!.widget.file.state;
Only saves the current state, but doesn't change with it.
It's basically about what the usage looks like, a method call with a parameter vs. what looks like an assignment to a property. From Dart.dev's Effective Dart: Design
DO use setters for operations that conceptually change properties.
Linter rule: use_setters_to_change_properties
Deciding between a setter versus a method is similar to deciding between a getter versus a method. In both cases, the operation should be “field-like”.
For a setter, “field-like” means:
The operation takes a single argument and does not produce a result value.
The operation changes some state in the object.
The operation is idempotent. Calling the same setter twice with the same value should do nothing the second time as far as the caller is concerned. Internally, maybe you’ve got some cache invalidation or logging going on. That’s fine. But from the caller’s perspective, it appears that the second call does nothing.
In your example you're comparing a method that changes two properties with two separate setters. You'd use the method if it's essential that the two properties both be updated at the same time, as a single conceptual operation. If the properties are independent (and otherwise meet the criteria above), you might use setters instead (if you need to do something when they're set; otherwise, simple data fields might make more sense).

Flutter 1.22 Internationalization with variable as key

I implemented the new (official) localization for Flutter (https://pascalw.me/blog/2020/10/02/flutter-1.22-internationalization.html) and everything is working fine, except that I don't know how to get the translation for a variable key.
The translation is in the ARB file, but how can I access it?
Normally I access translations using Translations.of(context).formsBack, but now I would like to get the translation of value["labels"]["label"].
Something like Translations.of(context).(value["labels"]["label"]) does not work of course.
I don't think this is possible with gen_l10n. The code that is generated by gen_l10n looks like this (somewhat abbreviated):
/// The translations for English (`en`).
class TranslationsEn extends Translations {
TranslationsEn([String locale = 'en']) : super(locale);
#override
String get confirmDialogBtnOk => 'Yes';
#override
String get confirmDialogBtnCancel => 'No';
}
As you can see it doesn't generate any code to perform a dynamic lookup.
For most cases code generation like this is a nice advantage since you get auto completion and type safety, but it does mean it's more difficult to accommodate these kinds of dynamic use cases.
The only thing you can do is manually write a lookup table, or choose another i18n solution that does support dynamic lookups.
A lookup table could look something like this. Just make sure you always pass in the current build context, so the l10n code can lookup the current locale.
class DynamicTranslations {
String get(BuildContext context, String messageId) {
switch(messageId) {
case 'confirmDialogBtnOk':
return Translations.of(context).confirmDialogBtnOk;
case 'confirmDialogBtnCancel':
return Translations.of(context).confirmDialogBtnCancel;
default:
throw Exception('Unknown message: $messageId');
}
}
}
To provide an example for https://stackoverflow.com/users/5638943/kristi-jorgji 's answer (which works fine):
app_en.arb ->
{
"languages": "{\"en\": \"English\", \"ro\": \"Romanian\"}"
}
localization_controller.dart ->
String getLocaleName(BuildContext ctx, String languageCode) {
return jsonDecode(AppLocalizations.of(ctx)!.languages)[languageCode];
}
getLocaleName(context, 'ro') -> "Romanian"
You can store a key in translation as json string.
Then you read it, parse it to Map<string,string> and access dynamically what you need.
Been using this approach with great success

A way to read a String as dart code inside flutter?

I want to build a method to dynamically save attributes on a specific object
given the attribute name and the value to save I call the "save()" function to update the global targetObj
var targetObj = targetClass();
save(String attribute, String value){
targetObj.attribute = value;
print(targetObj.attribute);
}
But I'm getting the following error:
Class 'targetClass' has no instance setter 'attribute='.
Receiver: Instance of 'targetClass'
Tried calling: attribute="Foo"
The only thing that I can think of is that "attribute" due to being type String results in an error.
That lead me to think if there is a way to read a String as code, something like eval for php.
As #Randal mentioned, you cannot create class..method at runtime. Still, you can try something like this.
A certain class
class Foo {
dynamic bar1;
dynamic bar2;
// ...
}
Your save method
save(Foo fooObject, String attribute, dynamic value) {
if ("bar1" == attribute) fooObject.bar1 = value;
else if ("bar2" == attribute) fooObject.bar2 == value;
// ...
}
Dart (and thus flutter) does not have a way to compile and execute code at runtime (other than dart:mirrors, which is deprecated). You can build additional code that derives from other code using the various builder mechanisms, although it can be rather complicated to implement (and use!).

NTriplesParser extract textual value from string

I am using dotnetrdf and trying to parse some triples with NTriplesParser. I have my own handler RobHandler in which I process each triple in turn.
public class RobHandler : BaseRdfHandler
{
protected override bool HandleTripleInternal(Triple t)
{
string predicateUrl = ((BaseUriNode)(t.Predicate)).Uri.AbsoluteUri;
string value = t.Object.ToString();
}
}
This works fine but I want to get the object minus the language. My objects look like "Lincoln"#en. I could obviously write some code to remove the #en bit, but I'd rather use some library code rather than my own that hard-coded strings like #en. To do this I think I need to create a LiteralNode but there doesn't seem to be a way to get from a string which is what I have (my variable value) to a LiteralNode.
How can I extract just the textual value from an object string?
Actually I think I have the answer myself:
if (t.Object.NodeType == NodeType.Literal)
{
var node = (ILiteralNode)t.Object;
}