Попытка составить формулу для расчета времени между 2 датами и временем, чтобы активировать Темную тему в флаттере - PullRequest
0 голосов
/ 09 марта 2020

Это не вопрос флаттера, а вопрос дротика и математики.

Я пытаюсь создать тему для своего приложения, когда пользователь включает автоматическую темную тему. переключиться, или когда он вернется в приложение.

Я уже установил опцию для пользователя, чтобы изменить начальное время и время окончания автоматического Темная тема дает нам DateTime () переменные, которые содержат данные год, месяц, день, час, минуты, секунды и т. д. c. (часы в 24-часовом формате)

Пока у меня есть эта формула:

if ((now.hour >= _startTime.hour && now.minute >= _startTime.minute) || (now.hour <= _endTime.hour && now.minute <= _endTime.minute)) {
      setTheme('dark');
} else {
      setTheme('light');
}

Я думал, что это работало нормально, но, как вы можете видеть на этой картинке и в настройках. Это не сработало должным образом ... enter image description here

Это переменные:

_startTime = 1:00 AM = 1
now = 10:40PM = 22:40
_endTime = 8:00 AM = 8

по моей формуле: ((now.hour >= _startTime.hour && now.minute >= _startTime.minute) || (now.hour <= _endTime.hour && now.minute <= _endTime.minute)) это создает True и False , что соответствует True и активирует Темную тему.

Как я могу усовершенствовать эту формулу? кажется, что это легко сделать, но на самом деле это очень запутанно.

Редактировать: для тех, кто любит иметь дело с числами

Давайте начнем со сборщиков (виджетов, которые позволяют пользователю вводить дату или время )

class HourPickers extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    CustomAppThemeProvider themeProvider =
        Provider.of<CustomAppThemeProvider>(context, listen: false);
    DateTime startTime = themeProvider.getStartTime;
    DateTime endTime = themeProvider.getEndTime;
    print('from provider:\n$startTime & $endTime');
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Switch(
                value: themeProvider.getIsAutoThemeSwitchOn,
                activeColor: Colors.green,
                onChanged: (boolean) {
                  themeProvider.setIsAutoThemeSwitchOn(boolean);
                },
              ),
              Text(
                'Tema Oscuro Automático',
                style: Theme.of(context).textTheme.subtitle,
              ),
            ],
          ),
          Text(
            'Inicio',
            style: Theme.of(context).textTheme.subtitle,
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 5),
            child: SizedBox(
              height: 100,
              child: Card(
                child: CupertinoDatePicker(
                  mode: CupertinoDatePickerMode.time,
                  initialDateTime: DateTime(startTime.year, startTime.month,
                      startTime.day, startTime.hour, startTime.minute),
                  onDateTimeChanged: (DateTime pickedTime) {
                    Provider.of<CustomAppThemeProvider>(context, listen: false)
                        .setStartTime(pickedTime);
                  },
                  use24hFormat: false,
                  backgroundColor: Theme.of(context).colorScheme.primary,
                ),
              ),
            ),
          ),
          Text(
            'Final',
            style: Theme.of(context).textTheme.subtitle,
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 5),
            child: SizedBox(
              height: 100,
              child: Card(
                child: CupertinoDatePicker(
                  mode: CupertinoDatePickerMode.time,
                  initialDateTime: DateTime(endTime.year, endTime.month,
                      endTime.day, endTime.hour, endTime.minute),
                  onDateTimeChanged: (DateTime pickedTime) {
                    Provider.of<CustomAppThemeProvider>(context, listen: false)
                        .setEndTime(pickedTime);
                  },
                  use24hFormat: false,
                  backgroundColor: Theme.of(context).colorScheme.primary,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

и вот куда уходит провайдер (я только что вынул часть темы)

bool get getIsAutoThemeSwitchOn => _isAutoThemeSwitchOn;

  Future<bool> getPrefIsAutoThemeSwitchOn() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool _prefAutoTheme = prefs.getBool('AutoTheme') ?? false;
    _isAutoThemeSwitchOn = _prefAutoTheme;
    return _prefAutoTheme;
  }

  Future<void> setIsAutoThemeSwitchOn(boolean) async {
    _isAutoThemeSwitchOn = boolean;
    // print(_isAutoThemeSwitchOn);
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setBool('AutoTheme', boolean);
    if (boolean == true) {
      autoThemeSetter();
    } else {
      notifyListeners();
    }
  }

  void autoThemeSetter() {
    // only if switch is ON
    DateTime now = DateTime.now();

    if (_startTime.isAfter(_endTime)) _endTime = _endTime.add(Duration(days: 1));

    print('start: $_startTime');
    print('now: $now');
    print('end: $_endTime');
    print('now >= start? ${now.isAfter(_startTime)}');
    print('now <= end? ${now.isBefore(_endTime)}');

    if (now.isAfter(_startTime) && now.isBefore(_endTime)) {
      // print('auto dark theme');
      setTheme('dark');
    } else {
      // print('auto light theme');
      setTheme('light');
    }
    // had add notify even if switch != true because the switch value needs to update
    notifyListeners();
  }

  getPrefTimes() async {
    await getPrefsStartTime();
    await getPrefsEndTime();
  }

  getPrefsStartTime() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    if (prefs.getInt('startTime') != null) {
      DateTime now = DateTime.now();
      _startTime =
          DateTime.fromMillisecondsSinceEpoch(prefs.getInt('startTime'));

      print('start pref: $_startTime');

      // set the day equal to now.day
      if (now.day != _startTime.day) {
        _startTime = DateTime(now.year, now.month, now.day, _startTime.hour, _startTime.minute);
      }
      // sub -1 day if needed
      if (_startTime.isAfter(now)) _startTime = _startTime.subtract(Duration(days: 1));

      // update SharedPref because why not
      // setStartTime(_startTime);
    }
  }

  getPrefsEndTime() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    if (prefs.getInt('endTime') != null) {
      DateTime now = DateTime.now();
      _endTime = DateTime.fromMillisecondsSinceEpoch(prefs.getInt('endTime'));

      print('end pref: $_endTime');

      // set the day equal to now.day
      if (now.day != _endTime.day) {
        _endTime = DateTime(now.year, now.month, now.day, _endTime.hour, _endTime.minute);
      }
      // add +1 day if needed
      if (_startTime.isAfter(_endTime)) _endTime = _endTime.add(Duration(days: 1));

      // update SharedPref because why not
      // setStartTime(_endTime);
    }
  }

  get getStartTime => _startTime;
  get getEndTime => _endTime;

  Future<void> setStartTime(DateTime pickedTime) async {
    // print(pickedTime);
    SharedPreferences prefs = await SharedPreferences.getInstance();
    DateTime now = DateTime.now();
    _startTime = pickedTime;
    // sub -1 day if needed
      if (_startTime.isAfter(now)) _startTime = _startTime.subtract(Duration(days: 1));
    int epoch = _startTime.millisecondsSinceEpoch;
    prefs.setInt('startTime', epoch);
    // print(prefs.getInt('startTime'));
  }

  Future<void> setEndTime(DateTime pickedTime) async {
    // print(pickedTime);
    SharedPreferences prefs = await SharedPreferences.getInstance();
    DateTime now = DateTime.now();
    _endTime = pickedTime;
    // sub -1 day if needed
      if (_startTime.isAfter(now)) _startTime = _startTime.subtract(Duration(days: 1));
    int epoch = _endTime.millisecondsSinceEpoch;
    prefs.setInt('endTime', epoch);
  }
}

вы уже можете видеть, что это не так просто, как кажется, там в фоновом режиме много всего для автоматического переключения тем.

Кстати, autoThemeSetter () вызывается каждый раз, когда приложение возобновляет работу из фона.

1 Ответ

0 голосов
/ 09 марта 2020

Формула, которую вы используете, имеет некоторые логики c fl aws. В основном, он не проверяет, что сейчас находится между _startTime и _endTime (ИЛИ должно быть И ..., но есть еще проблемы)

Просто для объяснения, логика c, которую вы используются: «Сделать тему темной, если текущее время - после времени начала ИЛИ, если текущее время - до времени окончания»

Допустим, текущее время - 9:00, а время начала - 1:00 и время окончания это 8 утра. Это установило бы темную тему, потому что вы использовали ИЛИ, а 9:00 - после 1:00. Таким образом, это проходит, поскольку OR не относится к тому факту, что это после endTime. Итак, вы хотите использовать && для проверки обоих, потому что вы хотите проверить, что текущее время идет после _startTime и до _endTime.

К сожалению, вы не можете просто сделать это && и назвать его день, потому что часы и минуты разделены. Итак, предположим, что время 6:01 утра ... и начало и конец те же, что и раньше. В этом случае первая часть имеет значение true (текущее время минут и часов больше, чем _startTime минут и часов, но для темы будет установлено значение LIGHT, поскольку текущие минуты (01) не меньше _endTime минут, несмотря на то, что оно явно в диапазоне.

Итак, одним из вариантов будет преобразование всего в минуты, например:

  if ((now.hour * 60 + now.minute) >=
          (_startTime.hour * 60 + _startTime.minute) &&
      ((now.hour * 60 + now.minute) <=
          (_endTime.hour * 60 + _endTime.minute))) {
    print('dark');
  } else {
    print('light');
  }

Но у этого есть недостаток - не проверять дату. Например, он не будет работать, если вы хотите, чтобы время начала 2300 и время окончания 0800.

Еще один (гораздо лучший) метод - использовать методы .isBefore () и .isAfter (). ОДНАКО вам нужно убедитесь, что они используют правильную дату, так как вы используете объект DateTime (). Это может выглядеть примерно так:

    var stringDate = DateTime.now().year.toString() + "-" +    DateTime.now().month.toString().padLeft(2, '0') + "-" + DateTime.now().day.toString().padLeft(2, '0'); 
//I'm assuming that all dates are the same, but you should use the correct dates.

      print(stringDate);
      var now_2 = DateTime.now();

      var _startTime_2 = DateTime.parse(stringDate + " 01:00:00Z");
      var _endTime_2 = DateTime.parse(stringDate+" 08:00:00Z");

      print("now_2="+now_2.toString());
      print("_startTime_2="+_startTime_2.toString());
      print("_endTime_2="+_endTime_2.toString());

        print("inBefore method");
      print("---------------------------------");
      if (_startTime_2.isBefore(now_2) && now_2.isBefore(_endTime_2)) {
        print('dark');
      } else {
        print('light');
      }

Я сделал файл dartpad, чтобы вы могли поиграть с кодом здесь: https://dartpad.dev/1f978458eabcaf588c872fa4f6bfdaf0

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...