📆

【Flutter】オフライン環境でも日付変更を感知する方法

2022/02/14に公開約3,100字

経緯

現在開発中の個人開発アプリで、1日に投稿数を制限する仕様にしたいと考えていました。
とすると、次の日にはまた投稿できるように特定の変数をリセットする必要があります。

今回は、サンプルとしてカウンターアプリを少しカスタマイズしました。
10までしかカウントアップできないようにし、翌日にカウンターが0になるといった具合です。

環境

//zshrc, macOS 12.2, M1 2020
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.10.1, on macOS 12.2.1 21D62 darwin-arm, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 32.0.0-rc1)
[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2021.1)
[✓] VS Code (version 1.64.0)
[✓] Connected device (2 available)
[✓] HTTP Host Availability

• No issues found!

説明

intlとshared_preferencesを用いて、実装しました。

  • intl→日付を20220214のようなint型にするため
  • shared_preferences→FABを押すたびにint型にした日付を保存するため

流れ
1.年月日のint型をFABを押すたびに_lastPostDayとして保存する
2.アプリ起動時に、initStateで_lastPostdayより_todayが大きかった場合にリセットする

パッケージ

pubspec.yaml
intl: ^0.17.0
shared_preferences: ^2.0.13

コード

main.dart
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:intl/intl.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(title: '日付変更を感知'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late SharedPreferences _prefs;
  late int _lastPostDay;
  late int _today;
  int _counter = 0;
  Future<void> setInstance() async {
    _prefs = await SharedPreferences.getInstance();
    getDay();
    setState(() {});
  }

  void setDay(int lastPostDay) {
    _prefs.setInt('lastPostDay', lastPostDay);
    getDay();
  }

  void getDay() {
    _lastPostDay = _prefs.getInt('lastPostDay') ?? 20220214;
  }

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
     setDay(_today);
  }

  
  void initState() {
    setInstance();
    _today = int.parse(DateFormat('yyyyMMdd').format(DateTime.now()));
    if (_today > _lastPostDay) {
      _counter = 0;
    }

    super.initState();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Center(
        child: Text(
          _counter < 9
	  ? '日付が変わっていたら、\nゼロにする↓\n\n$_counter'
	  : '今日はここまで\n$_counter',
          style: Theme.of(context).textTheme.headline5,
          textAlign: TextAlign.center,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _counter < 9 ? _incrementCounter : print('今日はここまで'),
        child: const Icon(Icons.add),
      ),
    );
  }
}

弱点

shared_preferencesで保存しているため、アプリをアンインストールされると対応できなくなるので、制限していても無限に投稿されたりもしてしまいます。

ですが、この点は、_lastPostDayをFireabaseに保存すれば解決できます。
完全オフラインアプリでなければ、日付変更を感知できそうですね。

最後に

最後までお読み頂き、ありがとうざいます。
至らない点、より良くできる点などありましたら、ご指摘頂けると幸いです。

Discussion

ログインするとコメントできます