[Newbie] Chapter 5. Basic tickets

[Newbie] Chapter 1. Flutter overview

[Newbie] Chapter 2. Flutter getting started

[Newbie] Chapter 3. Flutter initial setup

[Newbie] Chapter 4. Widget’s state

Content

  1. Work with asset files (image, font, files)
  2. Work with i18n
  3. Work with rest API
  4. Work with cache
  5. Work with dialog
  6. Work with app navigation
  7. Work with list
  8. Work with animation
  9. Work app version and env
  10. Testing
  11. Deal with performance, memory

Work with asset files

https://flutter.dev/docs/development/ui/assets-and-images

Work with i18n

https://flutter.dev/docs/development/accessibility-and-localization/internationalization

https://medium.com/flutter-community/flutter-internationalization-the-easy-way-using-provider-and-json-c47caa4212b2

Create i18n directory at <root project>/assets/ and update pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter

flutter:
  uses-material-design: true
  assets:
    - assets/i18n/

Create 2 JSON File en.json and vi.json and put all to i118n created above

# en.json
{
  "title": "Hello!"
}

# vi.json
{
  "title": "Xin chào!"
}

Create DemoLocalizations Class And Delegate Class


import 'dart:convert';

import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';

class AppLocalizations {
  final Locale locale;

  AppLocalizations(this.locale);

  // Helper method to keep the code in the widgets concise
  // Localizations are accessed using an InheritedWidget "of" syntax
  static AppLocalizations of(BuildContext context) {
    return Localizations.of<AppLocalizations>(context, AppLocalizations);
  }

  // Static member to have a simple access to the delegate from the MaterialApp
  static const LocalizationsDelegate<AppLocalizations> delegate =
  _AppLocalizationsDelegate();

  Map<String, String> _localizedStrings;

  Future<bool> load() async {
    // Load the language JSON file from the "lang" folder
    String jsonString =
    await rootBundle.loadString('assets/i18n/${locale.languageCode}.json');
    Map<String, dynamic> jsonMap = json.decode(jsonString);

    _localizedStrings = jsonMap.map((key, value) {
      return MapEntry(key, value.toString());
    });

    return true;
  }

  // This method will be called from every widget which needs a localized text
  String translate(String key) {
    return _localizedStrings[key];
  }
}

class _AppLocalizationsDelegate
    extends LocalizationsDelegate<AppLocalizations> {
  // This delegate instance will never change (it doesn't even have fields!)
  // It can provide a constant constructor.
  const _AppLocalizationsDelegate();

  @override
  bool isSupported(Locale locale) {
    // Include all of your supported language codes here
    return ['en', 'vi'].contains(locale.languageCode);
  }

  @override
  Future<AppLocalizations> load(Locale locale) async {
    // AppLocalizations class is where the JSON loading actually runs
    AppLocalizations localizations = new AppLocalizations(locale);
    await localizations.load();
    return localizations;
  }

  @override
  bool shouldReload(_AppLocalizationsDelegate old) => false;
}

Make the MaterialApp localized

import 'package:flutter_localizations/flutter_localizations.dart';
import 'provider/app_localizations.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      supportedLocales: [
        const Locale('en'),
        const Locale('vi'),
      ],
      localizationsDelegates: [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: AppContent(),
    );
  }
}

How to use it?

AppLocalizations.of(context).translate('title')

How to get Locale from the global setting?

import 'dart:ui' as ui;
Locale(ui.window.locale.languageCode, ui.window.locale.countryCode);

How to load Locale manually?

  • First, install bflutter
  • Sample

import 'dart:ui' as ui;

class MyApp extends StatelessWidget {
  static final localeBloc = BlocDefault<Locale>();

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: localeBloc.stream,
        builder: (context, snapshot) {
          print(snapshot);
          return MaterialApp(
            locale: (snapshot.hasData
                ? snapshot.data
                : Locale(ui.window.locale.languageCode,
                    ui.window.locale.countryCode)),
            supportedLocales: [
              const Locale('en'),
              const Locale('vi'),
            ],
            localizationsDelegates: [
              AppLocalizations.delegate,
              GlobalMaterialLocalizations.delegate,
              GlobalWidgetsLocalizations.delegate,
            ],
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: AppContent(),
          );
        });
  }
}

class AppContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            centerTitle: true,
            title: Text(AppLocalizations.of(context).translate('title'))),
        body: Center(
          child: Column(
            children: <Widget>[
              RaisedButton(
                child: Text('en'),
                onPressed: () {
                  MyApp.localeBloc.push(Locale('en'));
                },
              ),
              RaisedButton(
                child: Text('vi'),
                onPressed: () {
                  MyApp.localeBloc.push(Locale('vi'));
                },
              ),
            ],
          ),
        ));
  }
}

** Use the way above, may you have to face the issue that black screen in first start app, because that approach needs time to load JSON language file and parsing, it takes a bit time. To avoid that, following below

  • Install bflutter and flutter_localizations
# pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  bflutter: ^0.1.8+2
  • Create languages file at lib\provider\i18n
# lib\provider\i18n\en.dart
const en = {
  'title': 'Hello'
};

# lib\provider\i18n\vi.dart
const vi = {
  'title': 'Xin chào'
};
  • Create AppLocalizations
import 'package:flutter/widgets.dart';
import 'package:bflutter/provider/base_localizations.dart';
import 'package:cxi_pos/provider/i18n/en.dart';
import 'package:cxi_pos/provider/i18n/vi.dart';

class AppLocalizations extends BaseLocalizations {
  AppLocalizations(locale) : super(locale);

  // Helper method to keep the code in the widgets concise
  // Localizations are accessed using an InheritedWidget "of" syntax
  static AppLocalizations of(BuildContext context) {
    return Localizations.of<AppLocalizations>(context, AppLocalizations);
  }

  // Static member to have a simple access to the delegate from the MaterialApp
  static LocalizationsDelegate<AppLocalizations> delegate =
      AppLocalizationsDelegate(
          ['en', 'vi'], (locale) => AppLocalizations(locale));

  @override
  Map<String, String> load(Locale locale) {
    switch (locale.languageCode) {
      case 'vi':
        return vi;
    }
    return en;
  }
}
  • Using

import 'dart:ui' as ui;

class MyApp extends StatelessWidget {
  static final bloc = MainBloc.instance;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: bloc.localeBloc.stream,
        builder: (context, snapshot) {
          return MaterialApp(
            locale: (snapshot.hasData
                ? snapshot.data
                : Locale(ui.window.locale.languageCode,
                    ui.window.locale.countryCode)),
            supportedLocales: [
              const Locale('en'),
              const Locale('vi'),
            ],
            localizationsDelegates: [
              AppLocalizations.delegate,
              GlobalMaterialLocalizations.delegate,
              GlobalWidgetsLocalizations.delegate,
            ],
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: AppContent(),
          );
        });
  }
}

class AppContent extends StatelessWidget {

  static final bloc = MainBloc.instance;
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            centerTitle: true,
            title: Text(AppLocalizations.of(context).translate('title'))),
        body: Center(
          child: Column(
            children: <Widget>[
              RaisedButton(
                child: Text('en'),
                onPressed: () {
                  bloc.localeBloc.push(Locale('en'));
                },
              ),
              RaisedButton(
                child: Text('vi'),
                onPressed: () {
                  bloc.localeBloc.push(Locale('vi'));
                },
              ),
            ],
          ),
        ));
  }
}

Work with rest API

https://flutter.dev/docs/cookbook/networking/fetch-data

Work with cache

Work with dialog

https://api.flutter.dev/flutter/material/AlertDialog-class.html

https://api.flutter.dev/flutter/material/Dialog-class.html

Work with app navigation

Doc: https://flutter.dev/docs/development/ui/navigation

Example: https://flutter.dev/docs/cookbook/navigation/navigation-basics

Work with list

Doc: https://flutter.dev/docs/cookbook/lists

API: https://api.flutter.dev/flutter/widgets/ListView-class.html

Work with animation

Topic: https://flutter.dev/docs/development/ui/animations

Widget: https://flutter.dev/docs/development/ui/widgets/animation

Tutorial: https://flutter.dev/docs/development/ui/animations/tutorial

Work with app version and env

  • Updating the app’s version number

The default version number of the app is 1.0.0. To update it, navigate to the pubspec.yaml file and update the following line:

version: 1.0.0+1

The version number is three numbers separated by dots, such as 1.0.0 in the example above, followed by an optional build number such as 1 in the example above, separated by a +.

Both the version and the build number may be overridden in Flutter’s build by specifying –build-name and –build-number, respectively.

In Android, build-name is used as versionName while build-number used as versionCode. For more information, see Version your app in the Android documentation.

If you want to build with a specific version, just run

flutter build apk --build-name=1.0.3
flutter build apk --build-number=3
flutter build apk --build-name=1.0.3 --build-number=3
  • App environment
flutter run -t lib/Main/main_staging.dart

# Update FLUTTER_TARGET at ios/Flutter/Generated.xcconfig 
FLUTTER_TARGET=lib/Main/main_staging.dart

Testing

https://flutter.dev/docs/testing

https://medium.com/stuart-engineering/flutter-ui-testing-7f7df932edf6

https://medium.com/flutter-community/testing-flutter-ui-with-flutter-driver-c1583681e337

https://blog.codemagic.io/flutter-ui-testing/

Deal with performance, memory

Cookbook

https://flutter.dev/docs/cookbook

Leave a Reply

Your email address will not be published.Required fields are marked *