I'm using Injectable and I have two classes. WebImageDownloader and MobileImageDownloader. Both are implementing ImageDownloader which is an abstract class. I'm registering web and mobile image downloaders as ImageDownloader with Injectable, one registered under web, one under mobile environment.
But since WebImageDownloader has dart:js and dart:html imports, I can't run my code. Because these libraries are not found.
I see on some answers that people do conditional imports between dart:io and dart:html but it doesn't work for me.
Also, the question is under issues for Injectable.
import 'MobileFileDownloader.dart'
if (dart.library.html) 'WebFileDownloadService.dart';
abstract class NativeFileDownloader {
void downloadFile(List<int> bytes, String downloadName);
factory NativeFileDownloader() =>getDownloader();
}
import 'NativeFileDownloader.dart';
class WebFileDownloadService implements NativeFileDownloader{
void downloadFile(List<int> bytes, String downloadName) {
// Encode our file in base64
final _base64 = base64Encode(bytes);
// Create the link with the file
final anchor = AnchorElement(href: 'data:application/octet-stream;base64,$_base64')
..target = 'blank'
..setAttribute('download', downloadName);
// add the name
//anchor.download = downloadName;
// trigger download
document.body?.append(anchor);
anchor.click();
anchor.remove();
return;
}
}
NativeFileDownloader getDownloader()=>WebFileDownloadService();
import 'package:flovo/Services/FileDownloadService/Native/NativeFileDownloader.dart';
class MobileFileDownloader implements NativeFileDownloader{
#override
void downloadFile(List<int> bytes, String downloadName) {
}
}
NativeFileDownloader getDownloader()=>MobileFileDownloader();
use => NativeFileDownloader().downloadFile(list, 'image.jpeg');
Related
This is less about a specific implementation, but more about good practice.
I have the following structure in a flutter desktop project:
DataProviders: read data from one of two different fileformats (locally)
Repository: parses the data and instantiates my Model
ProjectCubit: takes a path from a FilePicker and gets the Project from the upper 2 layers
ProjectCubit.dart:
class ProjectCubit extends Cubit<ProjectState> {
ProjectCubit() : super(ProjectState.Closed);
Project? loadedProject;
Project? getProject() {
// return loaded instance of Project if loaded
if(loadedProject != null)
return loadedProject;
}
// creates Project instance from csv file
void importProject(String filePath) async {
emit(ProjectState.Importing);
loadedProject = await ProjectRepository().loadData(loadType: ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
emit(ProjectState.Open);
}
// open json-Project file
void openProject(String filePath) async {
emit(ProjectState.Opening);
try {
loadedProject = await ProjectRepository().loadData(loadType: ProjectLoadType.OPEN_PROJECT_FILE, filePath: filePath);
} catch (e) {
emit(ProjectState.Closed);
Log().l.e("Opening file failed with ${e.toString()}");
}
emit(ProjectState.Open);
}
}
where the states are:
enum ProjectState {
Closed,
Importing,
Opening,
Open
}
The Project instance in the ProjectCubit needs to be accessed and changed from multiple screens in multiple settings (DataTable, simple Inputs etc.). For example, Project has a Customer, which has a customerName, customerId etc. which have to be changed from a Customer-Settings screen.
I thought of two ways:
creating a ProjectSettingsCubit, CustomerDataCubit, ProjectDataCubit etc. which take the ProjectCubit as an argument and modify the Project from there
just using the ProjectCubit the entire time and making the changes from the Presentation layer
What would be the best way to accomplish this? And if the whole structure or Cubit is bad, why?
Would appreciate any help, thanks
The best practice depends on what you want to accomplish.
If you want your application to scale in future, have several people work on it, facilitate better reusability and better testability, it is recommended to separate business logic & UI as much as you can. So it would not make sense to have logic in your presentation layer directly. As you are using cubit, you would want to be consistent in your program & try to have UI and logic decoupled as much as you can.
This comes at a cost ofcourse. You need to put more time & make your code more complicated than before.
As for your answer, I suggest using a ProjectCubit and implement several events as for your requirements, like CustomerChangeEvent for changing customer.
If you have any special requirements that need to be implemented differently in two pages, then I suggest inheriting from a base class or just using a mixin and extending that class in different cubits.
class BaseProjectCubit extends Cubit<ProjectState> {
void importProject(String filePath) async {
emit(ProjectState.Importing);
loadedProject = await ProjectRepository().loadData(loadType:
ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
emit(ProjectState.Open);
}
...
}
class ProjectCubitA extends BaseProjectCubit {
#override
void importProject(String filePath) async {
...
}
}
class ProjectCubitB extends BaseProjectCubit {
importProject(String filePath) async {
...
}
}
Or for using mixins, it would be something like this:
mixin ProjectModifier {
void importProject(String filePath) async {
emit(ProjectState.Importing);
loadedProject = await ProjectRepository().loadData(loadType:
ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
emit(ProjectState.Open);
}
...
}
class CustomerTypeOneProjectCubit extends Cubit<ProjectState> with ProjectModifier {
changeName(String newName) {
...
}
}
class CustomerTypeTwoProjectCubit extends Cubit<ProjectState> with ProjectModifier {
changeName(String newName) {
...
}
}
Dart allows to use the standard library names for conditional import/export, like this:
export 'src/hw_none.dart' // Stub implementation
if (dart.library.io) 'src/hw_io.dart' // dart:io implementation
if (dart.library.html) 'src/hw_html.dart'; // dart:html implementation
Is it possible to define a custom property/condition? For example, pass it when compiling.
I have a project that I would like to split into two variants: Flutter variant and pure Dart variant. The choice of the variant depends at compile time, and the necessary implements of abstract classes defines at compile time.
Custom properties where an experimental feature in Dart 1. With Dart 2 there is no longer any support for user defined custom conditions in compile time.
Here is the discussion referencing your question.
All you can do is, switch between implementations on run time:
abstract class SomeFactory {
String get message;
factory SomeFactory() {
if(Platform.environment['SOME_VAR'] != null)
return new _SomeImplementation();
return new _SomeOtherImplementation();
}
}
class _SomeImplementation implements SomeFactory {
#override
String get message => 'SomeImplementation';
}
class _SomeOtherImplementation implements SomeFactory {
#override
String get message => "OtherImplementation";
}
Check this blog entry for more details.
I am trying to create a dart package and use it in my few flutter projects. The package is not public it’s a private package. I am trying to understand how to create a package with working on an example. The documentation wasn’t so difficult, but it confuses me, because I am new to this type project.
So, I create private dart package project. My package name is socket_conn. The socket_conn.dart has single export line as export 'src/socket_conn_base.dart'; My socket_conn_base.dart has 1 class and 1 Future method.
My intention is to import this package to my flutter app, send data to EncrptedSocketCommunication and wait EncrptedSocketCommunication returns data from getQuery. It didn’t work.
I am not sure if I am doing right but calling EncrptedSocketCommunication how do I fire getQuery method, so it goes another class under my src folder (getQueryA100) and gets the data. The getQueryA100 has a working and tested code. But when I import this package to my flutter app
İt doesn’t call Future>> getQuery.
My question is how to call dart package method from Flutter app?
import 'csbins_socket/getQueryA100.dart';
List<List<dynamic>> _returnData;
class EncrptedSocketCommunication {
String connectionText;
String queryText;
String parameterText;
EncrptedSocketCommunication(
this.connectionText,
this.queryText,
this.parameterText
);
Future<List<List<dynamic>>> getQuery(String connectionText, String queryText, String parameterText) async {
switch (queryText){
case "QA100": {
_returnData = await getQueryA100(queryText, parameterText);
return _returnData;
}
break;
}
}
}
I'm making an example with flutter and I've come across a question mark. In my project I have implemented dependency injection and I have two classes to get data one for production and testing with local data (Mock). The problem is that the local data I have stored in a json file and when I implement the functionality "fetchProducts" I do not know how to get the Context to load the json... I hope you can help me, thanks.
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:graphqllapp/data/product_data.dart';
import 'package:path/path.dart';
class MockProductRepository implements ProductRepository {
#override
Future<List<Product>> fetchProducts() async {
// TODO: implement fetchUsers
String data = await
DefaultAssetBundle.of(????).loadString("mockdata/data.json");
var jsonResult = json.decode(data);
return new Future.value(products);
}
}
You can instead use rootBundle which is the default value of DefaultAssetBundle
rootBundle.loadString("mockdata/data.json");
My Dart app project structure:
myapp/
pubspec.yaml
pubspec.lock
asset/
...assets
build/
packages/
web/
lookups/
AjaxLookups.dart
requests/
RESTClient.dart
AjaxRESTClient.dart
The AjaxLookups file:
library myapp;
abstract class AjaxLookups {
static final String BASE_URL = "/myapp";
static final String DO_S0METHING_SERVICE_URL = BASE_URL + "/doSomething";
}
The RESTClient file:
library myapp;
typedef void Callback(String json);
abstract class RESTClient {
void get(String url, Callback onFail, Callback onSuccess);
void post(String url, String dataJSON, Callback onFail, Callback onSuccess);
}
The AjaxRESTClient file:
library myapp;
import "RESTClient.dart";
import "../lookups/AjaxLookups.dart";
import "dart:html";
import "dart:convert" show JSON;
class AjaxRESTClient implements RESTClient, AjaxLookups {
// ...
}
Above, the import statement for AjaxLookups is causing a compiler error:
Target of URI does not exist: '../request/AjaxLookups.dart'
Why am I getting this? Why can't Dart find ../request/AjaxLookups.dart? What do I need to do to fix it?
It looks like the file AjaxLookups.dart is in the lookups folder, so your import should be:
import "../lookups/AjaxLookups.dart";
I figured it out. I was declaring a new myapp library inside each source file. Instead I added a main/driver Dart file, declared a library in it called myapp, and then changed all the other source files to be part of myapp;.