Just getting started with Flutter/dart, transitioning for PHP, and struggling to figure out how to pass classes into widgets.
I am working on creating my first android and iOS applications using flutter.
I am working with internationalization and everything works fine at my initial build page using the internationalization class I have. However, when passing it on to another widget I get:
NoSuchMethodError: The getter textTitle was called on null.
Receiver: null
tried calling: textTitle
What is the best way of handling this?
Flutter Doctor
[✓] Flutter (Channel beta, v0.1.5, on Mac OS X 10.13.3 17D47, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK 27.0.1)
[✓] Android Studio (version 3.0)
[✓] Connected devices (1 available)
Localization dart
class HnLocalizations{
HnLocalizations(this.locale);
final Locale locale;
static HnLocalizations of(BuildContext context){
return Localizations.of<HnLocalizations>(context, HnLocalizations);
}
static Map<String, Map<String, String>> _localizedValues = {
'en': {
'btnLabelLoginS1': 'Login',
'btnLabelRegisterS1': 'Sign Up'
},
;
String get s1ButtonLabelLogin =>
_localizedValues[locale.languageCode]['btnLabelLoginS1'];
class HnLocalizationsDelegate extends LocalizationsDelegate<HnLocalizations> {
const HnLocalizationsDelegate();
#override
bool isSupported(Locale locale) => ['en', 'es'].contains(locale.languageCode);
#override
Future<HnLocalizations> load(Locale locale) =>
new SynchronousFuture<HnLocalizations>(new HnLocalizations(locale)); //HnLocalizations.load(locale);
#override
bool shouldReload(HnLocalizationsDelegate old) => false;
}
Main Dart
void main() {
runApp(new MaterialApp(
localizationsDelegates: [
const HnLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'), /// Americans
const Locale('en', 'GB') /// Brits
],
title: 'HN',
home: new EntryPage(),
));
}
class EntryPage extends StatelessWidget {
final HnColors _hnColors = new HnColors();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
// !!!**** THIS WORKS AS EXPECTED ****!!!!
title: new Text(HnLocalizations.of(context).s1ButtonLabelLogin),
backgroundColor: _hnColors.transparent(),
elevation: 0.0,
),
backgroundColor: _hnColors.accent(),
body: new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage("assets/Background_World.png"),
fit: BoxFit.fitWidth,
),
),
child: new PanelArea(),
)
);
}
}
class PanelArea extends StatelessWidget {
#override
Widget build(BuildContext context) {
HnColors _hnColors = new HnColors();
return new Container(
child: new Center(
child: new Container(
decoration: new BoxDecoration(
borderRadius: new BorderRadius.circular(15.0),
color: _hnColors.transparent()
),
child: new Column(
children: [
new Image.asset('assets/Icon_Intro_login'),
new Text(
// !!!**** ERROR IS HERE ****!!!!
HnLocalizations.of(context).s1M1HeaderTitle,
style: new TextStyle(
color: _haillioColors.white()
),
),
What is the best way of handling this?
Update: Mar 11 2018
I've discovered that if I move all of the code into the main.dart file. All localization works fine. However, when I move my widgets into a separate dart file, the errors come back, even though all of the code is the same.
Update: Mar 12 2018
nicolás-carrasco pointed in the right direction by a reference in this post (Thank you). The problem had to do with imports which is addressed in this post here which ended up being the solution that worked for me. The example is added below in answers.
Nicolás Carrasco pointed towards a solution which was related to what was causing the problem for me by way of link to this post.
In the localization.dart file imports I had:
import 'package:hn/hnLocalization.dart';
While in the main.dart file imports I had:
import 'hnLocalization.dart';
These are not the same thing as described here
Making sure that all files are imported using relative paths vs packages resolved the problem. The distinction is that my files, not the dependencies use relative path. That part stumped at first.
Now my localization.dart file has the following.
import 'hnLocalization.dart'; // <--- Using relative Path
class PanelArea extends StatelessWidget {
#override
Widget build(BuildContext context) { ...
child: new Column(
children: [
new Image.asset('assets/Icon_Intro_login'),
// This Now Works --->
new Text(HnLocalizations.of(context).s1M1HeaderTitle,
]
...
and all is right now.
Related
I want to load image in my app
in stack
but image not load
I don't have an error
I've add image in pubspec and pub it .
this is part of my code :
InkWell(
child: Stack(
children: <Widget>[
new Image.asset('assets/Images/b.jpg',fit: BoxFit.cover,),
Center(child: Text("something",textAlign: TextAlign.center,)),
]
),
onTap: () {
ListOfEpisode();
print("am");
},
),
I've try it with network image but still not work.
anyone know that why i can't loaded ?
Change it towercase i:
new Image.asset('assets/images/b.jpg',fit: BoxFit.cover,),
In your pubespec you have it assets/images, in your code it's Images. Fix one of them.
Path in your directory and pubsec is:
assets/images/b.jpg
But in your code its:
assets/Images/b.jpg
change path in code to:
assets/images/b.jpg
In my project I have some JSON files that are used to get environment configurations at runtime through an entrypoint to the main dart file, they hold sensitive data so I put their containing folder in the .gitignore file.
I have written a test that passes when I run it locally, but fails when triggered by the github action because of this error:
The following assertion was thrown running a test:
Unable to load asset: assets/config/dev.json
Is there a way to somehow inject this JSON while performing the action? Any help is much appreciated, my only concern is having private data not stored in the github repository and having the action pass.
This is my code:
custom entry point
dev_run.dart
import 'package:gitgo/main.dart' as App;
void main() {
App.main('dev');
}
The class that has access to the JSON:
EnvironmentConfig
import 'dart:convert';
import 'package:flutter/services.dart';
class EnvironmentConfig {
final Map<String, String> environment;
EnvironmentConfig({this.environment});
static Future<EnvironmentConfig> forEnvironment(String env) async {
env = env ?? 'dev';
final contents = await rootBundle.loadString(
'assets/config/$env.json',
);
final Map<String, String> json = Map.castFrom(jsonDecode(contents));
return EnvironmentConfig(environment: json);
}
}
Dependencies
pubspec.yaml
name: gitgo
description: Git on the go.
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
http: ^0.12.1
oauth2: ^1.6.1
url_launcher: ^5.4.10
flutter_config: ^1.0.8
gql: ^0.12.3
gql_exec: ^0.2.4
gql_link: ^0.3.0
gql_http_link: ^0.3.2
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.11.1
gql_build: ^0.0.11
pedantic: ^1.9.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- assets/config/
Main file
main.dart
import 'package:flutter/material.dart';
import 'package:gitgo/inbound/configuration/config_environment_widget.dart';
import 'package:gitgo/outbound/api/viewer.req.gql.dart';
import 'package:gql_exec/gql_exec.dart';
import 'package:gql_link/gql_link.dart';
import 'package:gitgo/outbound/api/viewer.data.gql.dart';
import 'package:gitgo/outbound/auth.dart';
import 'package:gql_http_link/gql_http_link.dart';
import 'inbound/configuration/environment_config.dart';
Future main(String env) async {
WidgetsFlutterBinding.ensureInitialized();
final config = await EnvironmentConfig.forEnvironment(env);
print("starting app in $env mode");
runApp(MyApp(config));
}
class MyApp extends StatelessWidget {
final EnvironmentConfig config;
MyApp(this.config);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'GitGo Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: EnvironmentConfigWidget(
config: config, child: MyHomePage(title: 'GitGo Demo Home Page')),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState(title: "GitHub login");
}
class _MyHomePageState extends State<MyHomePage> {
_MyHomePageState({this.title});
EnvironmentConfigWidget environmentConfigWidget;
String title;
#override
Widget build(BuildContext context) {
return GithubLoginWidget(
builder: (context, httpClient) {
final link = HttpLink(
'https://api.github.com/graphql',
httpClient: httpClient,
);
return FutureBuilder<$ViewerDetail$viewer>(
future: viewerDetail(link),
builder: (context, snapshot) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text(
snapshot.hasData
? 'Hello ${snapshot.data?.login}!'
: 'Retrieving viewer login details...',
),
),
);
},
);
},
githubClientId: EnvironmentConfigWidget.of(context)
.config
.environment['githubClientId'],
githubClientSecret: EnvironmentConfigWidget.of(context)
.config
.environment['githubClientSecret'],
githubScopes: EnvironmentConfigWidget.of(context)
.config
.environment['githubScopes']
.split(","));
}
}
Future<$ViewerDetail$viewer> viewerDetail(Link link) async {
var result = await link.request(ViewerDetail((b) => b)).first;
if (result.errors != null && result.errors.isNotEmpty) {
throw QueryException(result.errors);
}
return $ViewerDetail(result.data).viewer;
}
class QueryException implements Exception {
QueryException(this.errors);
List<GraphQLError> errors;
#override
String toString() {
return 'Query Exception: ${errors.map((err) => '$err').join(',')}';
}
}
Failing test in github actions but not locally
widget_dart.test
import 'package:flutter_test/flutter_test.dart';
import 'package:gitgo/inbound/configuration/environment_config.dart';
import 'package:gitgo/main.dart';
void main() {
testWidgets('Smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
var env = await EnvironmentConfig.forEnvironment('dev');
await tester.pumpWidget(MyApp(env));
// Verify that our counter starts at 0.
expect(find.text('Log into Github'), findsOneWidget);
expect(find.text('1'), findsNothing);
});
}
Github action
ci.yml
name: ci
jobs:
ci:
name: ci
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout#v2
- name: Flutter test
uses: subosito/flutter-action#v1.4.0
with:
flutter-version: '1.26.0-17.2.pre'
channel: dev
- run: flutter pub get
- run: flutter analyze
- run: flutter test --no-sound-null-safety
- name : Clean merged branches
run: |
git fetch -p && for branch in $(git branch -vv | grep ': gone]' | awk '{print $1}'); do git branch -D $branch; done
echo "Finished cleaning"
You can use GitHub Action secrets.
Put your dev.json contents in a secret (for example, DEV_JSON_CONTENTS), and write it to the correct location with a command.
- name: Write dev.json
run: echo '{{ secrets.DEV_JSON_CONTENTS }}' > assets/config/dev.json
The proposed solution didn't work for me, but as hacker1024 pointed out:
Put your dev.json contents in a secret (for example, DEV_JSON_CONTENTS), and write it to the correct location with a command.
So what worked in my case, was adding the github secret DEV_JSON with the contents of the original file, then
I modified the workflow file by adding the secret as an env variable in the workflow:
env:
DEV_JSON : ${{ secrets.DEV_JSON }}
And I added this step to write the contents to a new file:
- name: Write dev.json
run: |
touch assets/config/dev.json
echo $DEV_JSON >> assets/config/dev.json
cat assets/config/dev.json
I am developing a desktop UI in Flutter and I need to create buttons to execute shell commands.
I already can execute some commands simple such as ls -l and it shows its results nicely in the console.
However I need a way to show the results in the main app and not in the console, I have tried the snackbar but it is not so nice and it does not get the outputs from other commands that gives dynamic outputs.
I would like to watch dynamic outputs such as tail -f and top.
How could I open a new window in the flutter app to show the execution of a command?
For now, I have this:
class LsButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
onPressed: () {
Process.run('ls', ['-l']).then((ProcessResult results) {
Flushbar(
title: "Output",
message: results.stdout,
duration: Duration(seconds: 15),
)..show(context);
});
},
child: Text('Show dir contents!',
style: TextStyle(
fontSize: 10,
),)
),
);
}}
Flutter doesn't yet support multiple windows, so currently if you want to do that you'd have to do it via native code, controlled via platform channels.
i made one demo in flutter its work fine in Android, iphone, linux desktop and mac desktop but in windows desktop it give me error
[ERROR:c:\b\s\w\ir\cache\builder\src\flutter\lib\ui\ui_dart_state.cc(157)] Unhandled Exception: MissingPluginException(No implementation found for method stop on channel xyz.luan/audioplayers)
can any one help me to resolve this error?
in this demo i used audioplayers 0.14.2 to play local audio file in flutter.
here is my code:-
void main() {
debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
runApp(new MaterialApp(home: new ExampleApp()));
}
class ExampleApp extends StatefulWidget {
#override
_ExampleAppState createState() => new _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
AudioPlayer advancedPlayer;
AudioCache audioCache;
#override
void initState() {
super.initState();
initPlayer();
}
void initPlayer() {
advancedPlayer = new AudioPlayer();
audioCache = new AudioCache(fixedPlayer: advancedPlayer);
}
void playfirst() {
audioCache.play('audio1.mp3');
}
void stop() {
advancedPlayer.stop();
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 1,
child: Scaffold(
appBar: AppBar(
title: Text('Audio file demo'),
),
body: Center(
child: Column(
children: <Widget>[
ButtonTheme(
minWidth: 48.0,
child: RaisedButton(child: Text("play"), onPressed: playfirst)),
ButtonTheme(
minWidth: 48.0,
child: RaisedButton(child: Text("stop"), onPressed: stop))
],
),
)
),
);
}
}
can any one help me to resolve this error?
The only way to resolve the error would be to write an implementation of that plugin for Windows; the reason it's telling you that the plugin is missing is that the plugin doesn't have Windows support (which you can tell because there's no windows folder in the plugin repository, or windows: entry in the pubspec.yaml).
its work fine in [...] linux desktop
That's surprising, given that the plugin you are using doesn't support Linux either.
It's unlikely that you're going to find a plugin that has Windows support at the moment given that the official documentation currently says:
Note: Windows and Linux plugin APIs and tooling are not yet stable, so any plugin written now will need frequent updates for breaking changes. Because of this, publishing Windows and/or Linux plugins to pub.dev at this stage is strongly discouraged.
I'm developing an application in flutter which is showing videos in a list (like Instagram). Videos must be streamed so I can't download them first and then play them.
I want to cache them while they are being streamed. I've seen CacheManager class but it will download the whole file and then pass it to video player to play it.
How can I implement a cache manager to show the video file while it is being downloaded to cache folder?
I might be writing this a bit late but just in case anybody looking for a solution soon.
By the moment the official video_player plugin doesn't support video caching over network yet.
But fortunately, there been some attempts by contributors to add caching feature to the video_player plugin
You can track updates and find another PRs here: https://github.com/flutter/flutter/issues/28094
Replace video_player in your pubspec.yaml with
video_player:
git:
url: https://github.com/sanekyy/plugins.git
ref: caching
path: packages/video_player/video_player
In case of you are using chewie or other libraries that depend on video_player plugin add:
dependency_overrides:
video_player:
git:
url: https://github.com/sanekyy/plugins.git
ref: caching
path: packages/video_player/video_player
And now to cache the video pass useCache : true to
_videoPlayerController = VideoPlayerController.network(videoURL, useCache: true);
By default both maxFileSize and maxCacheSize is set to 10 * 1024 * 1024 bytes.
To adjust the cache size:
VideoPlayerController.setCacheSize(100 * 1024 * 1024, 200 * 1024 * 1024);
Another Solution:
Is to stream the video normally using the official plugin and to cache the video file using flutter_cache_manager simultaneously.
But this will lead to fetch the video twice the first time (Once for streaming through the video_player, Another for downloading the video through the cachemanager)
Here how the scenario would goes:
1- Check with flutter_cache_manager if the video_url is already downloaded and cached.
2- if the video is cached, pass the file path to video_player VideoPlayerController.file(path), if not download the file using cachemanager and stream the video using VideoPlayerController.network(videoURL) (at this moment video is being fetched twice... by videoplayer and cachemanager).
Visit https://github.com/elgsylvain85/cachedflickvideoplayer.git
It is a video player for flutter. It combines both: The flick_video_player plugin for the base architecture, own set of UI and The cached_video_player plugin for cache supporting.
In your pubspec.yaml file :
cachedflickvideoplayer:
git:
url: https://github.com/elgsylvain85/cachedflickvideoplayer.git
a demo of code :
import 'package:cached_video_player/cached_video_player.dart';
import 'package:cachedflickvideoplayer/cachedflickvideoplayer.dart';
import 'package:cachedflickvideoplayer/controls/flick_landscape_controls.dart';
import 'package:cachedflickvideoplayer/controls/flick_video_with_controls.dart';
import 'package:cachedflickvideoplayer/manager/flick_manager.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class ViewPage extends StatefulWidget {
FlickManager flickManager;
ViewPage() {
flickManager = initVideo();
}
#override
_ViewPageState createState() => _ViewPageState();
FlickManager initVideo() {
return FlickManager(
cachedVideoPlayerController:
CachedVideoPlayerController.network('https://media.istockphoto.com/videos/blurred-motion-of-people-in-restaurant-blur-background-video-id1190840021'),
);
}
}
class _ViewPageState extends State<ViewPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
Card(
margin: const EdgeInsets.fromLTRB(20, 20, 20, 100),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: const EdgeInsets.all(8),
height: 300,
child: FlickVideoPlayer(
flickManager: widget.flickManager,
flickVideoWithControlsFullscreen:
FlickVideoWithControls(
videoFit: BoxFit.contain,
controls: FlickLandscapeControls(),
),
)),,
]),
),
],
));
}
#override
void dispose() {
super.dispose();
widget.flickManager.dispose();
}
}
You can mix video_player with flutter_cache_manager.
/// Get a file from the cache or download and insert it into the memory.
final url = 'link-to-the-file';
final file = await DefaultCacheManager().getSingleFile(url, key: url);
_videoController = VideoPlayerController.file(file)
..initialize().then(
(_) => initialize(),
);
As the result, if the manager does not find a file in the cache by url, it will download it, insert it into the memory and return the file object.
This solution is only effective if you work with small sizes video.