ソースコード source code

下記アプリの主要なソースコードを公開しています。アプリ開発の参考になれば幸いです。

画像等が別途必要ですので下記情報のみでアプリが完成するものではありません。 アプリは少しずつ機能拡張していますのでストア公開されているアプリと内容が異なる場合があります。 コードはコピーして自由にお使いいただけます。ただし著作権は放棄しておりませんので全部の再掲載はご遠慮ください。部分的に再掲載したり、改変して再掲載するのは構いません。 自身のアプリ作成の参考として個人使用・商用問わず自由にお使いいただけます。 コード記述のお手本を示すものではありません。ミニアプリですので変数名などさほど気遣いしていない部分も有りますし間違いも有るかと思いますので参考程度にお考え下さい。 他の賢者の皆様が公開されているコードを参考にした箇所も含まれます。Flutter開発の熟練者が書いたコードではありません。 エンジニア向け技術情報共有サービスではありませんので説明は省いています。 GitHubなどへの公開は予定しておりません。

下記コードの最終ビルド日: 2023-11-26

pubspec.yaml

name: spiritlevel
description: "Spirit Level"
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev

# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1

environment:
  sdk: '>=3.3.0-152.0.dev <4.0.0'

# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.6
  package_info_plus: ^5.0.1
  shared_preferences: ^2.0.17
  flutter_localizations:    #多言語ライブラリの本体    # .arbファイルを更新したら flutter gen-l10n
    sdk: flutter
  intl: ^0.18.1     #多言語やフォーマッタなどの関連ライブラリ
  google_mobile_ads: ^3.1.0
  sensors_plus: ^3.1.0

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_launcher_icons: ^0.13.1    #flutter pub run flutter_launcher_icons
  flutter_native_splash: ^2.3.6     #flutter pub run flutter_native_splash:create

  # The "flutter_lints" package below contains a set of recommended lints to
  # encourage good coding practices. The lint set provided by the package is
  # activated in the `analysis_options.yaml` file located at the root of your
  # package. See that file for information about deactivating specific lint
  # rules and activating additional ones.
  flutter_lints: ^3.0.1

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

flutter_launcher_icons:
  android: "launcher_icon"
  ios: true
  image_path: "assets/icon/icon.png"
  adaptive_icon_background: "assets/icon/icon_back.png"
  adaptive_icon_foreground: "assets/icon/icon_fore.png"

flutter_native_splash:
  color: '#d4ff48'
  image: 'assets/image/splash.png'
  color_dark: '#d4ff48'
  image_dark: 'assets/image/splash.png'
  fullscreen: true
  android_12:
    icon_background_color: '#d4ff48'
    image: 'assets/image/splash.png'
    icon_background_color_dark: '#d4ff48'
    image_dark: 'assets/image/splash.png'

# The following section is specific to Flutter packages.
flutter:
  generate: true    #自動生成フラグの有効化

  # 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:
  #   - images/a_dot_burr.jpeg
  #   - images/a_dot_ham.jpeg
  assets:
    - assets/image/

  # An image asset can refer to one or more resolution-specific "variants", see
  # https://flutter.dev/assets-and-images/#resolution-aware

  # For details regarding adding assets from package dependencies, see
  # https://flutter.dev/assets-and-images/#from-packages

  # To add custom fonts to your application, add a fonts section here,
  # in this "flutter" section. Each entry in this list should have a
  # "family" key with the font family name, and a "fonts" key with a
  # list giving the asset and other descriptors for the font. For
  # example:
  # fonts:
  #   - family: Schyler
  #     fonts:
  #       - asset: fonts/Schyler-Regular.ttf
  #       - asset: fonts/Schyler-Italic.ttf
  #         style: italic
  #   - family: Trajan Pro
  #     fonts:
  #       - asset: fonts/TrajanPro.ttf
  #       - asset: fonts/TrajanPro_Bold.ttf
  #         weight: 700
  #
  # For details regarding fonts from package dependencies,
  # see https://flutter.dev/custom-fonts/#from-packages

lib/ad_mob.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-02-06
///
library;

import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'dart:io';

class AdMob {
  late BannerAd _adMobBanner;
  bool _isAdMob = false;
  AdMob() { //constructor
    String adBannerUnitId = '';
    if (!kIsWeb && Platform.isAndroid) {
      //adBannerUnitId = 'ca-app-pub-3940256099942544/6300978111';  //test
      adBannerUnitId = 'ca-app-pub-0000000000000000/0000000000';
      _isAdMob = true;
    } else if (!kIsWeb && Platform.isIOS) {
      //adBannerUnitId = 'ca-app-pub-3940256099942544/6300978111';  //test
      adBannerUnitId = 'ca-app-pub-0000000000000000/0000000000';
      _isAdMob = true;
    }
    if (_isAdMob) {
      _adMobBanner = BannerAd(
        adUnitId: adBannerUnitId,
        size: AdSize.banner,
        request: const AdRequest(),
        listener: const BannerAdListener(),
      );
    }
  }
  void load() {
    if (_isAdMob) {
      _adMobBanner.load();
    }
  }
  void dispose() {
    if (_isAdMob) {
      _adMobBanner.dispose();
    }
  }
  Widget getAdBannerWidget() {
    if (_isAdMob) {
      return Container(
        alignment: Alignment.center,
        width: _adMobBanner.size.width.toDouble(),
        height: _adMobBanner.size.height.toDouble(),
        child: AdWidget(ad: _adMobBanner),
      );
    } else {
      return Container();
    }
  }
  double getAdBannerHeight() {
    if (_isAdMob) {
      return _adMobBanner.size.height.toDouble();
    } else {
      return 150;  //for web
    }
  }
}

lib/const_value.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-10-15
///
library;

import 'package:flutter/material.dart';

class ConstValue {
  //pref
  static const String prefLanguageCode = 'languageCode';
  static const String prefSensitivity = 'sensitivity';
  static const String prefScaleType = 'scaleType';
  static const String prefTweakX = 'tweakX';
  static const String prefTweakY = 'tweakY';
  //image
  static const List<String> imageStages = [
    'assets/image/stage06.webp',
    'assets/image/stage07.webp',
    'assets/image/stage08.webp',
    'assets/image/stage09.webp',
    'assets/image/stage04.webp',
    'assets/image/stage05.webp',
    'assets/image/stage03.webp',
    'assets/image/stage01.webp',
    'assets/image/stage02.webp',
  ];
  static const String imageNeedleX = 'assets/image/needle_x.webp';
  static const String imageNeedleY = 'assets/image/needle_y.webp';
  static const String imageNeedleXY = 'assets/image/needle_xy.webp';
  //color
  static const Color colorBack = Color.fromRGBO(21, 52, 0, 1.0);
  static const Color colorHeader = Color.fromRGBO(34, 87, 0, 1);
  static const Color colorSettingAccent = Color.fromRGBO(59, 145, 0, 1.0);
  static const Color colorUiActiveColor = Color.fromRGBO(59, 145, 0,1);
  static const Color colorUiInactiveColor = Color.fromRGBO(50,50,50,1);
  //double
  static const double sensitivityMin = 0.03;
  static const double sensitivityMax = 0.3;
  static const double needleLimit = 0.28;
  //string
  static const Map<String,String> languageCode = {
    'en': 'English',
    'bg': 'български език',
    'cs': 'Čeština',
    'da': 'dansk',
    'de': 'Deutsch',
    'el': 'Ελληνικά',
    'es': 'Español',
    'et': 'eesti keel',
    'fi': 'Suomen kieli',
    'fr': 'Français',
    'hu': 'magyar nyelv',
    'it': 'Italiano',
    'ja': '日本語',
    'lt': 'lietuvių kalba',
    'lv': 'Latviešu',
    'nl': 'Nederlands',
    'pl': 'Polski',
    'pt': 'Português',
    'ro': 'limba română',
    'ru': 'русский',
    'sk': 'Slovenčina',
    'sv': 'svenska',
    'th': 'ภาษาไทย',
    'zh': '中文',
  };

}

lib/empty.dart

lib/language_state.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-01-27
///
library;

import 'package:spiritlevel/preferences.dart';

class LanguageState {

  static String _languageCode = 'en';

  //言語コードを記録
  static Future<void> setLanguageCode(String str) async {
    _languageCode = str;
    await Preferences.setLanguageCode(_languageCode);
  }
  //言語コードを返す
  static Future<String> getLanguageCode() async {
    _languageCode = await Preferences.getLanguageCode() ?? 'en';
    return _languageCode;
  }

}

lib/main.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-10-02
///
library;

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart' if (dart.library.html) 'empty.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:sensors_plus/sensors_plus.dart';

//自身で作成したclassを読み込む
import 'package:spiritlevel/const_value.dart';
import 'package:spiritlevel/language_state.dart';
import 'package:spiritlevel/version_state.dart';
import 'package:spiritlevel/setting.dart';
import 'package:spiritlevel/ad_mob.dart';
import 'package:spiritlevel/page_state.dart';
import 'package:spiritlevel/preferences.dart';

void main() {
  runApp(const MainApp());
}

class MainApp extends StatefulWidget {    //statefulに変更して言語変更に対応
  const MainApp({super.key});
  @override
  State<MainApp> createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  Locale localeLanguage = const Locale('en');
  @override
  Widget build(BuildContext context) {
    if (kIsWeb == false) {
      MobileAds.instance.initialize();
    }
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      localizationsDelegates: AppLocalizations.localizationsDelegates,   //多言語化
      supportedLocales: AppLocalizations.supportedLocales,  //自動で言語リストを生成
      locale: localeLanguage,
      home: const MainHomePage(),
    );
  }
}

class MainHomePage extends StatefulWidget {
  const MainHomePage({super.key});
  @override
  State<MainHomePage> createState() => _MainHomePageState();
}

class _MainHomePageState extends State<MainHomePage> with SingleTickerProviderStateMixin {
  final GlobalKey _aspectRatioKey = GlobalKey();  //_stageのサイズ取得用
  final AdMob _adMob = AdMob(); //広告表示
  double _accelerometerEventX = 0;
  double _accelerometerEventY = 0;
  double _stageWidth = 0;
  double _needleOffsetX = 0;
  double _needleOffsetY = 0;

  //アプリのバージョン取得
  void _getVersion() async {
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    setState(() {
      VersionState.versionSave(packageInfo.version);
    });
  }
  //言語準備
  void _getCurrentLocale() async {
    Locale locale = Locale(await LanguageState.getLanguageCode());
    if (mounted) {  //Widgetが存在する。Widgetが存在しない時の実行によるエラーを回避する為。
      context.findAncestorStateOfType<_MainAppState>()!
        ..localeLanguage = locale
        ..setState(() {});
    }
  }
  //ページ起動開始時に一度だけ呼ばれる
  @override
  void initState() {
    super.initState();
    _getVersion();
    _getCurrentLocale();
    LanguageState.getLanguageCode();
    _adMob.load();
    //
    accelerometerEvents.listen((AccelerometerEvent event) {
      setState(() {
        _accelerometerEventX = event.x + (Preferences.tweakX * 0.1);
        _accelerometerEventY = event.y + (Preferences.tweakY * 0.1);
        _needleOffsetX = _stageWidth * Preferences.sensitivity * _accelerometerEventX;
        _needleOffsetY = _stageWidth * Preferences.sensitivity * _accelerometerEventY * -1;
        if (_needleOffsetX < - _stageWidth * ConstValue.needleLimit) {
          _needleOffsetX = - _stageWidth * ConstValue.needleLimit;
        } else if (_needleOffsetX > _stageWidth * ConstValue.needleLimit) {
          _needleOffsetX = _stageWidth * ConstValue.needleLimit;
        }
        if (_needleOffsetY < - _stageWidth * ConstValue.needleLimit) {
          _needleOffsetY = - _stageWidth * ConstValue.needleLimit;
        } else if (_needleOffsetY > _stageWidth * ConstValue.needleLimit) {
          _needleOffsetY = _stageWidth * ConstValue.needleLimit;
        }
      });
    });
    //
    (() async {
      await Preferences.initial();
      setState(() {});
    })();
  }
  //ページ終了時に一度だけ呼ばれる
  @override
  void dispose() {
    PageState.setCurrentPage('');
    _adMob.dispose();
    super.dispose();
  }
  //画面全体
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
      },
      child: Container(
        decoration: const BoxDecoration(
          color: ConstValue.colorBack,
        ),
        child: Scaffold(
          backgroundColor: Colors.transparent, //ここは透明
          appBar: AppBar(
            backgroundColor: ConstValue.colorHeader,
            //タイトル表示
            title: const Text('Spirit level',
              style: TextStyle(
                color: Colors.white,
                fontSize: 15.0,
              )
            ),
            //設定ボタン
            actions: <Widget>[
              TextButton(
                onPressed: () async {
                  bool? ret = await Navigator.of(context).push(
                    MaterialPageRoute<bool>(builder:(context) => const SettingPage()),
                  );
                  //awaitで呼び出しているので、settingから戻ったら以下が実行される。
                  if (ret!) { //設定で適用だった場合
                    _getCurrentLocale();
                    setState(() {});
                  }
                },
                child: Text(
                  AppLocalizations.of(context)!.setting,
                  style: const TextStyle(
                    color: Colors.white,
                  )
                )
              )
            ]
          ),
          body: SafeArea(
            child: Column(children: [
              Expanded(
                child: Stack(children:[
                  _preStageArea(),
                  _stage(),
                  _needleX(),
                  _needleY(),
                  _needleXY(),
                  _textXY(),
                ]),
              ),
              //広告
              Padding(
                padding: const EdgeInsets.only(top: 10, left: 0, right: 0, bottom: 0),
                child: SizedBox(
                  width: double.infinity,
                  child: _adMob.getAdBannerWidget(),
                )
              )
            ])
          )
        )
      )
    );
  }
  //_stageAreaのサイズ取得用
  Widget _preStageArea() {
    return AspectRatio(
      key: _aspectRatioKey,
      aspectRatio: 1,
    );
  }
  Widget _stage() {
    try {
      RenderBox renderBox = _aspectRatioKey.currentContext?.findRenderObject() as RenderBox;
      _stageWidth = renderBox.size.width;
    } catch (_) {
      return Container();
    }
    return Center(
      child: Image.asset(ConstValue.imageStages[Preferences.scaleType],
        width: _stageWidth,
        height: _stageWidth,
      ),
    );
  }
  Widget _needleX() {
    return Center(
      child: Transform.translate(
        offset: Offset(_needleOffsetX,0),
        child: Image.asset(ConstValue.imageNeedleX,
          width: _stageWidth,
          height: _stageWidth,
        ),
      ),
    );
  }
  Widget _needleY() {
    return Center(
      child: Transform.translate(
        offset: Offset(0,_needleOffsetY),
        child: Image.asset(ConstValue.imageNeedleY,
          width: _stageWidth,
          height: _stageWidth,
        ),
      ),
    );
  }
  Widget _needleXY() {
    double offsetX = _needleOffsetX;
    double offsetY = _needleOffsetY;
    double length = sqrt(_needleOffsetX * _needleOffsetX + _needleOffsetY * _needleOffsetY);
    if (length > _stageWidth * ConstValue.needleLimit) {
      double scaleFactor = _stageWidth * ConstValue.needleLimit / length;
      offsetX = _needleOffsetX * scaleFactor;
      offsetY = _needleOffsetY * scaleFactor;
    }
    return Center(
      child: Transform.translate(
        offset: Offset(offsetX,offsetY),
        child: Image.asset(ConstValue.imageNeedleXY,
          width: _stageWidth,
          height: _stageWidth,
        ),
      ),
    );
  }
  Widget _textXY() {
    double angleX = double.parse((_accelerometerEventX * 9).toStringAsFixed(1));
    double angleY = double.parse((_accelerometerEventY * 9).toStringAsFixed(1));
    return Center(
      child: Column(children:[
        const Spacer(),
        Text('X: $angleX °',
            style: TextStyle(
              fontSize: _stageWidth * 0.06,
            )
        ),
        SizedBox(height: _stageWidth * 0.2),
        Text('Y: $angleY °',
            style: TextStyle(
              fontSize: _stageWidth * 0.06,
            )
        ),
        const Spacer(),
      ])
    );
  }
}

lib/page_state.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-10-05
///
library;

//現在のページを記録。initStateでタイミングが合わない時にbuild内で一度だけ実行させるために使用。
class PageState {

  static String _currentPage = '';

  static void setCurrentPage(String str) {
    _currentPage = str;
  }

  static String getCurrentPage() {
    return _currentPage;
  }

}

lib/preferences.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-10-26
///
library;

import 'package:shared_preferences/shared_preferences.dart';

import 'package:spiritlevel/const_value.dart';

//デバイスに情報を保存
class Preferences {

  static bool ready = false;
  //この値は常に最新にしておく
  static String _languageCode = '';
  static double _sensitivity = ConstValue.sensitivityMin;
  static int _scaleType = 0;
  static double _tweakX = 0;
  static double _tweakY = 0;

  static String get languageCode {
    return _languageCode;
  }
  static double get sensitivity {
    return _sensitivity;
  }
  static int get scaleType {
    return _scaleType;
  }
  static double get tweakX {
    return _tweakX;
  }
  static double get tweakY {
    return _tweakY;
  }

  static Future<void> initial() async {
    _languageCode = await getLanguageCode();
    _sensitivity = await getSensitivity();
    _scaleType = await getScaleType();
    _tweakX = await getTweakX();
    _tweakY = await getTweakY();
    ready = true;
  }

  //----------------------------

  //言語コード
  static Future<void> setLanguageCode(String str) async {
    _languageCode = str;
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString(ConstValue.prefLanguageCode, str);
  }
  static Future<String> getLanguageCode() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    final String str = prefs.getString(ConstValue.prefLanguageCode) ?? 'en';
    return str;
  }

  //----------------------------

  //感度
  static Future<void> setSensitivity(double num) async {
    _sensitivity = num;
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setDouble(ConstValue.prefSensitivity, num);
  }
  static Future<double> getSensitivity() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    final double num = prefs.getDouble(ConstValue.prefSensitivity) ?? ConstValue.sensitivityMin;
    return num;
  }

  //----------------------------

  //スケールタイプ
  static Future<void> setScaleType(int num) async {
    _scaleType = num;
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setInt(ConstValue.prefScaleType, num);
  }
  static Future<int> getScaleType() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    final int num = prefs.getInt(ConstValue.prefScaleType) ?? 0;
    return num;
  }

  //----------------------------

  //微調整X
  static Future<void> setTweakX(double num) async {
    _tweakX = num;
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setDouble(ConstValue.prefTweakX, num);
  }
  static Future<double> getTweakX() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    final double num = prefs.getDouble(ConstValue.prefTweakX) ?? 0;
    return num;
  }

  //----------------------------

  //微調整Y
  static Future<void> setTweakY(double num) async {
    _tweakY = num;
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setDouble(ConstValue.prefTweakY, num);
  }
  static Future<double> getTweakY() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    final double num = prefs.getDouble(ConstValue.prefTweakY) ?? 0;
    return num;
  }

//----------------------------

}

lib/setting.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-10-15
///
library;

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

import 'package:spiritlevel/const_value.dart';
import 'package:spiritlevel/preferences.dart';
import 'package:spiritlevel/language_state.dart';
import 'package:spiritlevel/version_state.dart';
import 'package:spiritlevel/ad_mob.dart';
import 'package:spiritlevel/page_state.dart';

class SettingPage extends StatefulWidget {
  const SettingPage({super.key});

  @override
  State<SettingPage> createState() => _SettingPageState();
}

class _SettingPageState extends State<SettingPage> {
  final AdMob _adMob = AdMob(); //広告
  //これら変数はUIへの表示や入力の為に一時的に使用される。
  String _languageKey = ''; //言語コード 'en'
  String _languageValue = '';
  double _sensitivity = ConstValue.sensitivityMin;
  int _scaleType = 0;
  double _tweakX = 0;
  double _tweakY = 0;

  //ページ起動時に一度だけ実行される
  @override
  void initState() {
    super.initState();
    _adMob.load();
  }
  //ページ終了時に一度だけ実行される
  @override
  void dispose() {
    PageState.setCurrentPage('');
    _adMob.dispose();
    super.dispose();
  }
  //ページ描画
  @override
  Widget build(BuildContext context) {
    //このページが開いたときに一度だけ実行される処理を記述。initStateではタイミングが合わない為。
    if (PageState.getCurrentPage() != 'setting') {
      PageState.setCurrentPage('setting');
      (() async {
        _languageKey = await LanguageState.getLanguageCode();
        _languageValue = ConstValue.languageCode[_languageKey] ?? '';
        await Preferences.initial();
        _sensitivity = Preferences.sensitivity;
        _scaleType = Preferences.scaleType;
        _tweakX = Preferences.tweakX;
        _tweakY = Preferences.tweakY;
        setState((){});
      })();
    }
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        elevation: 0,
        //設定キャンセルボタン
        leading: IconButton(
          icon: const Icon(Icons.close),
          onPressed: () {
            Navigator.of(context).pop(false); //falseを返す
          },
        ),
        title: Text(AppLocalizations.of(context)!.setting),
        foregroundColor: const Color.fromRGBO(255,255,255,1),
        backgroundColor: ConstValue.colorSettingAccent,
        actions: [
          //設定OKボタン
          IconButton(
            icon: const Icon(Icons.check),
            onPressed: () async {
              await LanguageState.setLanguageCode(_languageKey);
              await Preferences.setSensitivity(_sensitivity);
              await Preferences.setScaleType(_scaleType);
              await Preferences.setTweakX(_tweakX);
              await Preferences.setTweakY(_tweakY);
              if (!mounted) {
                return;
              }
              Navigator.of(context).pop(true);  //trueを返す
            },
          ),
        ],
      ),
      body: Column(children:[
        Expanded(
          child: GestureDetector(
            onTap: () => FocusScope.of(context).unfocus(),  //背景タップでキーボードを仕舞う
            child: SingleChildScrollView(
              child: Padding(
                padding: const EdgeInsets.all(20),
                child: Column(children: [
                  Padding(
                      padding: const EdgeInsets.only(top: 18, left: 16, right: 16, bottom: 0),
                      child: Row(children: [
                        Text(AppLocalizations.of(context)!.sensitivity,style: const TextStyle(fontSize: 16)),
                        const Spacer(),
                      ])
                  ),
                  Padding(
                      padding: const EdgeInsets.only(top: 0, left: 16, right: 16, bottom: 6),
                      child: Row(children: <Widget>[
                        Text(_sensitivity.toStringAsFixed(2)),
                        Expanded(
                            child: Slider(
                              value: _sensitivity,
                              min: ConstValue.sensitivityMin,
                              max: ConstValue.sensitivityMax,
                              divisions: 27,
                              onChanged: (double value) {
                                setState(() {
                                  _sensitivity = double.parse(value.toStringAsFixed(2));
                                });
                              },
                              activeColor: ConstValue.colorUiActiveColor,
                              inactiveColor: ConstValue.colorUiInactiveColor,
                            )
                        )
                      ])
                  ),
                  _border(),
                  Padding(
                      padding: const EdgeInsets.only(top: 18, left: 16, right: 16, bottom: 0),
                      child: Row(children: [
                        Text(AppLocalizations.of(context)!.scaleType,style: const TextStyle(fontSize: 16)),
                        const Spacer(),
                      ])
                  ),
                  Padding(
                      padding: const EdgeInsets.only(top: 0, left: 16, right: 16, bottom: 6),
                      child: Row(children: <Widget>[
                        Text(_scaleType.toString()),
                        Expanded(
                            child: Slider(
                              value: _scaleType.toDouble(),
                              min: 0,
                              max: ConstValue.imageStages.length - 1,
                              divisions: ConstValue.imageStages.length - 1,
                              onChanged: (double value) {
                                setState(() {
                                  _scaleType = value.toInt();
                                });
                              },
                              activeColor: ConstValue.colorUiActiveColor,
                              inactiveColor: ConstValue.colorUiInactiveColor,
                            )
                        )
                      ])
                  ),
                  _border(),
                  Padding(
                      padding: const EdgeInsets.only(top: 18, left: 16, right: 16, bottom: 0),
                      child: Row(children: [
                        Text(AppLocalizations.of(context)!.tweakX,style: const TextStyle(fontSize: 16)),
                        const Spacer(),
                      ])
                  ),
                  Padding(
                      padding: const EdgeInsets.only(top: 0, left: 16, right: 16, bottom: 6),
                      child: Row(children: <Widget>[
                        Text(_tweakX.toString()),
                        Expanded(
                            child: Slider(
                              value: _tweakX,
                              min: -5,
                              max: 5,
                              divisions: 20,
                              onChanged: (double value) {
                                setState(() {
                                  _tweakX = value;
                                });
                              },
                              activeColor: ConstValue.colorUiActiveColor,
                              inactiveColor: ConstValue.colorUiInactiveColor,
                            )
                        )
                      ])
                  ),
                  Padding(
                      padding: const EdgeInsets.only(top: 18, left: 16, right: 16, bottom: 0),
                      child: Row(children: [
                        Text(AppLocalizations.of(context)!.tweakY,style: const TextStyle(fontSize: 16)),
                        const Spacer(),
                      ])
                  ),
                  Padding(
                      padding: const EdgeInsets.only(top: 0, left: 16, right: 16, bottom: 6),
                      child: Row(children: <Widget>[
                        Text(_tweakY.toString()),
                        Expanded(
                            child: Slider(
                              value: _tweakY,
                              min: -5,
                              max: 5,
                              divisions: 20,
                              onChanged: (double value) {
                                setState(() {
                                  _tweakY = value;
                                });
                              },
                              activeColor: ConstValue.colorUiActiveColor,
                              inactiveColor: ConstValue.colorUiInactiveColor,
                            )
                        )
                      ])
                  ),
                  _border(),
                  Padding(
                    padding: const EdgeInsets.only(top: 18, left: 0, right: 0, bottom: 0),
                    child: Row(children:[
                      const SizedBox(width:16),
                      Text(AppLocalizations.of(context)!.language,
                        style: const TextStyle(
                          fontSize: 16,
                        )
                      ),
                      const Spacer(),
                    ])
                  ),
                  Padding(
                    padding: const EdgeInsets.only(top: 12, left: 0, right: 0, bottom: 18),
                    child: Table(
                      children: <TableRow>[
                        TableRow(children: <Widget>[
                          _languageTableCell(0),
                          _languageTableCell(1),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(2),
                          _languageTableCell(3),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(4),
                          _languageTableCell(5),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(6),
                          _languageTableCell(7),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(8),
                          _languageTableCell(9),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(10),
                          _languageTableCell(11),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(12),
                          _languageTableCell(13),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(14),
                          _languageTableCell(15),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(16),
                          _languageTableCell(17),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(18),
                          _languageTableCell(19),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(20),
                          _languageTableCell(21),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(22),
                          _languageTableCell(23),
                        ]),
                      ]
                    ),
                  ),
                  _border(),
                  Padding(
                    padding: const EdgeInsets.only(top: 24, left: 0, right: 0, bottom: 24),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children:[
                        Text(AppLocalizations.of(context)!.usage1),
                        const SizedBox(height:15),
                        Text(AppLocalizations.of(context)!.usage2),
                        const SizedBox(height:15),
                        Text(AppLocalizations.of(context)!.usage3),
                        const SizedBox(height:15),
                        Text(AppLocalizations.of(context)!.usage4),
                      ]
                    ),
                  ),
                  _border(),
                  Padding(
                    padding: const EdgeInsets.only(top: 24, left: 0, right: 0, bottom: 36),
                    child: SizedBox(
                      child: Text('version  ${VersionState.versionLoad()}',
                        style: const TextStyle(
                          fontSize: 10,
                        ),
                      ),
                    ),
                  ),
                ]),
              ),
            ),
          ),
        ),
        Padding(
          padding: const EdgeInsets.only(top: 10, left: 0, right: 0, bottom: 0),
          child: SizedBox(
            width: double.infinity,
            child: _adMob.getAdBannerWidget(),
          ),
        ),
      ]),
    );
  }
  //UIの仕切り用ボーダーライン
  Widget _border() {
    return Container(
      decoration: BoxDecoration(
        border: Border(
          top: BorderSide(
            color: Colors.grey.shade300,
            width: 1,
          ),
        ),
      ),
    );
  }
  //言語一覧表示
  TableCell _languageTableCell(int index) {
    return TableCell(
      child: RadioListTile(
        visualDensity: const VisualDensity(horizontal: VisualDensity.minimumDensity,vertical: VisualDensity.minimumDensity),
        contentPadding: EdgeInsets.zero,
        title: Text(ConstValue.languageCode.values.elementAt(index)),
        value: ConstValue.languageCode.values.elementAt(index),
        groupValue: _languageValue,
        onChanged: (String? value) {
          setState(() {
            _languageValue = value ?? '';
            _languageKey = ConstValue.languageCode.keys.elementAt(index);
          });
        },
        activeColor: ConstValue.colorUiActiveColor,
      ),
    );
  }

}

lib/version_state.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-01-27
///
library;

class VersionState {

  static String _version = '';

  //バージョンを記録
  static void versionSave(String str) {
    _version = str;
  }
  //バージョンを返す
  static String versionLoad() {
    return _version;
  }

}

lib/l10n/app_bg.arb

{
	"@@locale":"bg",
	"@locale": {
		"description": "ブルガリア"
	},
	"setting": "Настройка",
	"sensitivity": "Чувствителност",
	"scaleType": "Изображение в мащаб",
	"tweakX": "Ощипвам X",
	"tweakY": "Ощипвам Y",
	"language": "език",
	"usage1": "Нивелир.",
	"usage2": "Дръжте устройството хоризонтално и го притиснете към предмет. Показва ъгъла на наклон.",
	"usage3": "Направете малки корекции предварително, за да се съобразите с уникалния наклон, причинен от издатините и корпуса на устройството.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_cs.arb

{
	"@@locale":"cs",
	"@locale": {
		"description": "チェコ"
	},
	"setting": "Nastavení",
	"sensitivity": "Citlivost",
	"scaleType": "Měřítko obrázku",
	"tweakX": "Tweak X",
	"tweakY": "Tweak Y",
	"language": "Jazyk",
	"usage1": "Duchovní úroveň.",
	"usage2": "Držte zařízení vodorovně a přitlačte jej k předmětu. Zobrazuje úhel sklonu.",
	"usage3": "Proveďte drobné úpravy předem, abyste se přizpůsobili jedinečnému náklonu způsobenému výstupky a pouzdrem zařízení.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_da.arb

{
	"@@locale":"da",
	"@locale": {
		"description": "デンマーク"
	},
	"setting": "Indstilling",
	"sensitivity": "Følsomhed",
	"scaleType": "Skala billede",
	"tweakX": "Tweak X",
	"tweakY": "Tweak Y",
	"language": "Sprog",
	"usage1": "vaterpas.",
	"usage2": "Hold enheden vandret, og tryk den mod en genstand. Viser hældningsvinklen.",
	"usage3": "Foretag mindre justeringer på forhånd for at imødekomme den unikke hældning forårsaget af enhedens fremspring og etui.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_de.arb

{
	"@@locale":"de",
	"@locale": {
		"description": "ドイツ"
	},
	"setting": "Einstellung",
	"sensitivity": "Empfindlichkeit",
	"scaleType": "Bild skalieren",
	"tweakX": "X optimieren",
	"tweakY": "Y optimieren",
	"language": "Sprache",
	"usage1": "Wasserwaage.",
	"usage2": "Halten Sie das Gerät horizontal und drücken Sie es gegen einen Gegenstand. Zeigt den Neigungswinkel an.",
	"usage3": "Nehmen Sie vorab geringfügige Anpassungen vor, um der besonderen Neigung Rechnung zu tragen, die durch die Vorsprünge und das Gehäuse des Geräts verursacht wird.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_el.arb

{
	"@@locale":"el",
	"@locale": {
		"description": "ギリシャ"
	},
	"setting": "Σύνθεση",
	"sensitivity": "Ευαισθησία",
	"scaleType": "Κλίμακα εικόνας",
	"tweakX": "Tweak X",
	"tweakY": "Tweak Y",
	"language": "Γλώσσα",
	"usage1": "Πνευματικό επίπεδο.",
	"usage2": "Κρατήστε τη συσκευή οριζόντια και πιέστε την πάνω σε ένα αντικείμενο. Εμφανίζει τη γωνία κλίσης.",
	"usage3": "Κάντε εκ των προτέρων μικρές ρυθμίσεις για να προσαρμόσετε τη μοναδική κλίση που προκαλείται από τις προεξοχές και τη θήκη της συσκευής.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_en.arb

{
	"@@locale":"en",
	"@locale": {
		"description": "英語"
	},
	"setting": "Setting",
	"sensitivity": "Sensitivity",
	"scaleType": "Scale image",
	"tweakX": "Tweak X",
	"tweakY": "Tweak Y",
	"language": "Language",
	"usage1": "Spirit level.",
	"usage2": "Hold the device horizontally and press it against an object. Displays the angle of inclination.",
	"usage3": "Make minor adjustments in advance to accommodate the unique tilt caused by the device's protrusions and case.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_es.arb

{
	"@@locale":"es",
	"@locale": {
		"description": "スペイン"
	},
	"setting": "Configuración",
	"sensitivity": "Sensibilidad",
	"scaleType": "Imagen a escala",
	"tweakX": "Ajustar X",
	"tweakY": "Ajustar Y",
	"language": "Idioma",
	"usage1": "Nivel espiritual.",
	"usage2": "Sostenga el dispositivo horizontalmente y presiónelo contra un objeto. Muestra el ángulo de inclinación.",
	"usage3": "Realice pequeños ajustes con anticipación para adaptarse a la inclinación única causada por las protuberancias y la carcasa del dispositivo.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_et.arb

{
	"@@locale":"et",
	"@locale": {
		"description": "エストニア"
	},
	"setting": "Seadistamine",
	"sensitivity": "Tundlikkus",
	"scaleType": "Skaala kujutis",
	"tweakX": "Näpista X",
	"tweakY": "Näpistada Y",
	"language": "Keel",
	"usage1": "Vaimutase.",
	"usage2": "Hoidke seadet horisontaalselt ja vajutage seda vastu objekti. Näitab kaldenurka.",
	"usage3": "Tehke eelnevalt väiksemaid muudatusi, et kohandada seadme eenditest ja korpusest põhjustatud ainulaadset kaldenurka.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_fi.arb

{
	"@@locale":"fi",
	"@locale": {
		"description": "フィンランド"
	},
	"setting": "Asetus",
	"sensitivity": "Herkkyys",
	"scaleType": "Skaalaa kuva",
	"tweakX": "Säädä X",
	"tweakY": "Säädä Y",
	"language": "Kieli",
	"usage1": "Henkinen taso.",
	"usage2": "Pidä laitetta vaakasuorassa ja paina sitä esinettä vasten. Näyttää kaltevuuskulman.",
	"usage3": "Tee pieniä säätöjä etukäteen mukautuaksesi laitteen ulkonemien ja kotelon aiheuttamaan ainutlaatuiseen kallistukseen.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_fr.arb

{
	"@@locale":"fr",
	"@locale": {
		"description": "フランス"
	},
	"setting": "Paramètre",
	"sensitivity": "Sensibilité",
	"scaleType": "Image à l'échelle",
	"tweakX": "Ajuster X",
	"tweakY": "Ajuster Y",
	"language": "Langue",
	"usage1": "Niveau à bulle.",
	"usage2": "Tenez l'appareil horizontalement et appuyez-le contre un objet. Affiche l'angle d'inclinaison.",
	"usage3": "Effectuez des ajustements mineurs à l'avance pour tenir compte de l'inclinaison unique provoquée par les saillies et le boîtier de l'appareil.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_hu.arb

{
	"@@locale":"hu",
	"@locale": {
		"description": "ハンガリー"
	},
	"setting": "Beállítás",
	"sensitivity": "Érzékenység",
	"scaleType": "Méretezési kép",
	"tweakX": "Csíp X",
	"tweakY": "Csíp Y",
	"language": "Nyelv",
	"usage1": "Vízmérték.",
	"usage2": "Tartsa a készüléket vízszintesen, és nyomja egy tárgyhoz. Megjeleníti a dőlésszöget.",
	"usage3": "Előzetesen végezzen kisebb módosításokat, hogy alkalmazkodjon a készülék kiemelkedései és tokja által okozott egyedi dőléshez.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_it.arb

{
	"@@locale":"it",
	"@locale": {
		"description": "イタリア"
	},
	"setting": "Collocamento",
	"sensitivity": "Sensibilità",
	"scaleType": "Immagine in scala",
	"tweakX": "Modifica X",
	"tweakY": "Modifica Y",
	"language": "Lingua",
	"usage1": "Livello di spirito.",
	"usage2": "Tenere il dispositivo in posizione orizzontale e premerlo contro un oggetto. Visualizza l'angolo di inclinazione.",
	"usage3": "Effettuare piccole modifiche in anticipo per adattarsi all'inclinazione unica causata dalle sporgenze e dalla custodia del dispositivo.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_ja.arb

{
	"@@locale":"ja",
	"@locale": {
		"description": "日本"
	},
	"setting": "設定",
	"sensitivity": "感度",
	"scaleType": "目盛画像",
	"tweakX": "微調整X",
	"tweakY": "微調整Y",
	"language": "言語",
	"usage1": "水準器",
	"usage2": "デバイスを水平にして物体に押し当てます。傾きの角度を表示します。",
	"usage3": "デバイスの突起物やケースによる固有の傾きに対応する為、事前に微調整を行っておきます。",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_lt.arb

{
	"@@locale":"lt",
	"@locale": {
		"description": "リトアニア"
	},
	"setting": "Nustatymas",
	"sensitivity": "Jautrumas",
	"scaleType": "Mastelio vaizdas",
	"tweakX": "Pataisykite X",
	"tweakY": "Pataisykite Y",
	"language": "Kalba",
	"usage1": "Dvasios lygis.",
	"usage2": "Laikykite įrenginį horizontaliai ir prispauskite prie objekto. Rodo pasvirimo kampą.",
	"usage3": "Iš anksto atlikite nedidelius pakeitimus, kad atitiktumėte unikalų pakreipimą, kurį sukelia įrenginio iškyšos ir korpusas.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_lv.arb

{
	"@@locale":"lv",
	"@locale": {
		"description": "ラトビア"
	},
	"setting": "Iestatījums",
	"sensitivity": "Jutīgums",
	"scaleType": "Mēroga attēls",
	"tweakX": "Kniebiet X",
	"tweakY": "Kniebiet Y",
	"language": "Valoda",
	"usage1": "Gara līmenis.",
	"usage2": "Turiet ierīci horizontāli un piespiediet to pret kādu priekšmetu. Parāda slīpuma leņķi.",
	"usage3": "Iepriekš veiciet nelielus pielāgojumus, lai pielāgotos unikālajam sasvērumam, ko izraisa ierīces izvirzījumi un korpuss.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_nl.arb

{
	"@@locale":"nl",
	"@locale": {
		"description": "オランダ"
	},
	"setting": "Instelling",
	"sensitivity": "Gevoeligheid",
	"scaleType": "Schaal afbeelding",
	"tweakX": "Pas X aan",
	"tweakY": "Pas Y aan",
	"language": "Taal",
	"usage1": "Waterpas.",
	"usage2": "Houd het apparaat horizontaal en druk het tegen een voorwerp. Geeft de hellingshoek weer.",
	"usage3": "Voer van tevoren kleine aanpassingen uit om tegemoet te komen aan de unieke kanteling die wordt veroorzaakt door de uitsteeksels en de behuizing van het apparaat.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_pl.arb

{
	"@@locale":"pl",
	"@locale": {
		"description": "ポーランド"
	},
	"setting": "Ustawienie",
	"sensitivity": "Wrażliwość",
	"scaleType": "Skaluj obraz",
	"tweakX": "Popraw X",
	"tweakY": "Popraw Y",
	"language": "Język",
	"usage1": "Poziom duchowy.",
	"usage2": "Trzymaj urządzenie poziomo i dociśnij je do przedmiotu. Wyświetla kąt nachylenia.",
	"usage3": "Dokonaj z wyprzedzeniem drobnych regulacji, aby dostosować się do wyjątkowego pochylenia spowodowanego występami urządzenia i obudową.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_pt.arb

{
	"@@locale":"pt",
	"@locale": {
		"description": "ポルトガル"
	},
	"setting": "Contexto",
	"sensitivity": "Sensibilidade",
	"scaleType": "Escalar imagem",
	"tweakX": "Ajuste X",
	"tweakY": "Ajustar Y",
	"language": "Linguagem",
	"usage1": "Nivel espiritual.",
	"usage2": "Segure o dispositivo horizontalmente e pressione-o contra um objeto. Exibe o ângulo de inclinação.",
	"usage3": "Faça pequenos ajustes com antecedência para acomodar a inclinação única causada pelas saliências e pela caixa do dispositivo.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_ro.arb

{
	"@@locale":"ro",
	"@locale": {
		"description": "ルーマニア"
	},
	"setting": "Setare",
	"sensitivity": "Sensibilitate",
	"scaleType": "Scala imaginea",
	"tweakX": "Ajustați X",
	"tweakY": "Ajustați Y",
	"language": "Limba",
	"usage1": "Nivel de spirit.",
	"usage2": "Țineți dispozitivul orizontal și apăsați-l pe un obiect. Afișează unghiul de înclinare.",
	"usage3": "Faceți ajustări minore în avans pentru a se adapta înclinării unice cauzate de proeminențele și carcasa dispozitivului.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_ru.arb

{
	"@@locale":"ru",
	"@locale": {
		"description": "ロシア"
	},
	"setting": "Параметр",
	"sensitivity": "Чувствительность",
	"scaleType": "Масштабировать изображение",
	"tweakX": "Твик X",
	"tweakY": "Изменить Y",
	"language": "Язык",
	"usage1": "Духовный уровень.",
	"usage2": "Держите устройство горизонтально и прижмите его к какому-либо предмету. Отображает угол наклона.",
	"usage3": "Заранее внесите небольшие изменения, чтобы учесть уникальный наклон, вызванный выступами устройства и корпусом.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_sk.arb

{
	"@@locale":"sk",
	"@locale": {
		"description": "スロバキア"
	},
	"setting": "Nastavenie",
	"sensitivity": "Citlivosť",
	"scaleType": "Mierka obrázka",
	"tweakX": "Tweak X",
	"tweakY": "Tweak Y",
	"language": "Jazyk",
	"usage1": "Vodováha.",
	"usage2": "Držte zariadenie vodorovne a pritlačte ho k predmetu. Zobrazuje uhol sklonu.",
	"usage3": "Vopred vykonajte menšie úpravy, aby ste sa prispôsobili jedinečnému sklonu spôsobenému výstupkami a puzdrom zariadenia.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_sv.arb

{
	"@@locale":"sv",
	"@locale": {
		"description": "スウェーデン"
	},
	"setting": "Miljö",
	"sensitivity": "Känslighet",
	"scaleType": "Skala bild",
	"tweakX": "Tweak X",
	"tweakY": "Tweaka Y",
	"language": "Språk",
	"usage1": "Andenivå.",
	"usage2": "Håll enheten horisontellt och tryck den mot ett föremål. Visar lutningsvinkeln.",
	"usage3": "Gör mindre justeringar i förväg för att tillgodose den unika lutningen som orsakas av enhetens utsprång och fodral.",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_th.arb

{
	"@@locale":"th",
	"@locale": {
		"description": "タイ"
	},
	"setting": "การตั้งค่า",
	"sensitivity": "ความไว",
	"scaleType": "ภาพมาตราส่วน",
	"tweakX": "ปรับแต่ง X",
	"tweakY": "ปรับแต่ง Y",
	"language": "ภาษา",
	"usage1": "ระดับจิตวิญญาณ.",
	"usage2": "ถืออุปกรณ์ในแนวนอนแล้วกดเข้ากับวัตถุ แสดงมุมเอียง",
	"usage3": "ทำการปรับเปลี่ยนเล็กน้อยล่วงหน้าเพื่อรองรับความเอียงอันเนื่องมาจากส่วนที่ยื่นออกมาและตัวเครื่องของอุปกรณ์",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_zh.arb

{
	"@@locale":"zh",
	"@locale": {
		"description": "中国"
	},
	"setting": "环境",
	"sensitivity": "灵敏度",
	"scaleType": "缩放图像",
	"tweakX": "调整X",
	"tweakY": "调整Y",
	"language": "语言",
	"usage1": "精神层面。",
	"usage2": "水平握住设备并将其压在物体上。 显示倾斜角度。",
	"usage3": "提前进行细微调整,以适应设备突出部分和外壳造成的独特倾斜。",
	"usage4": "",

	"dummy": "dummy"
}