更新番茄钟数值不会在Flutter Riverpod中触发警报声音。

huangapple go评论70阅读模式
英文:

Updating Pomodoro Timer Value Doesn't Trigger Alarm Sound in Flutter Riverpod

问题

我目前正在使用Flutter和Riverpod进行状态管理开发番茄钟计时器应用程序,遇到了一个问题,当我尝试从设置页面更新默认计时器值时。

以下是我的当前功能:

我有一个默认值为3的番茄钟计时器。当计时器结束时设置了一个警报声音播放。
当用户更新计时器值时,更新后的计时器能够正常工作,但计时器结束时不再播放警报声音。
我的初始番茄钟计时器状态提供程序声明如下:final pomodoroTimerProvider = StateProvider((ref) => 3);

我认为问题出在这一行,因为似乎只有在计时器值为3时才会条件性地播放警报声音。

以下是我想要实现的目标:

用户应能够更新计时器值。
更新后的计时器在结束时应触发警报声音,就像默认计时器一样。
用户还应能够从一组选项中选择警报声音。
以下是我的代码的相关部分:

// timer_provider.dart

import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:just_audio/just_audio.dart';
import 'package:pomoworkojunio2023/domain/entities/sound.dart';

final pomodoroTimerProvider = StateProvider<int>((ref) => 3);
// ... 其余代码

class TimerNotifier extends StateNotifier<int> {
  // ...

  Future<void> playSound() async {
    if (!_isDisposed) {
      final selectedSound = ref.watch(selectedSoundProvider.notifier).state;
      if (_audioPlayer.processingState != ProcessingState.idle) {
        await _audioPlayer.stop();
      }
      await _audioPlayer.setAsset(selectedSound.path);
      await _audioPlayer.load();
      _audioPlayer.play();
    }
  }
  
  void updateDuration(int newDuration) {
    // ...
  }
}

// settings_page.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../domain/entities/timer_provider.dart';

class SettingsPage extends ConsumerWidget {
  // ...

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      // ...
      body: ListView(
        // ...
        children: <Widget>[
          // ...
          ElevatedButton(
            onPressed: () {
              // ...
              ref.read(timerNotifierProvider.notifier).updateDuration(0);
            },
            child: const Text('Save'),
          )
        ],
      ),
    );
  }
}

class TimerSettingState extends ConsumerStatefulWidget {
  // ...
}

class _TimerSettingStateState extends ConsumerState<TimerSettingState> {
  // ...
}

如何修改我的代码,以便更新后的计时器值也能播放警报声音?非常感谢您提供的任何指导或建议!
请注意:我正在使用Riverpod v2.3.6和just_audio v0.9.34。有关这些包的更多信息,请参阅Riverpod文档pub.dev上的just_audio包

我还在GitHub上上传了完整的代码片段供参考:
https://github.com/codemotozu/stack-overflow-question-riverpod

非常感谢您的时间和专业知识。期待您的回复。

英文:

I am currently working on a Pomodoro timer app using Flutter and Riverpod for state management. I have encountered a problem when I tried to update the default timer value from the settings page.

Here is my current functionality:

I have a Pomodoro timer with a default value of 3. An alarm sound is set to play when the timer ends.
When the user updates the timer value, the updated timer works but the alarm sound doesn't play once the timer ends.
My initial Pomodoro timer state provider is declared as follows: final pomodoroTimerProvider = StateProvider<int>((ref) => 3);

I believe the problem arises from this line, as it seems the alarm sound is conditionally played only when the timer value is 3.

Here is what I want to achieve:

The user should be able to update the timer value.
The updated timer should trigger the alarm sound when it ends, just like the default timer.
The user should also be able to select an alarm sound from a set of options.
Here is the relevant part of my code:

// timer_provider.dart

import &#39;dart:async&#39;;
import &#39;package:flutter_riverpod/flutter_riverpod.dart&#39;;
import &#39;package:just_audio/just_audio.dart&#39;;
import &#39;package:pomoworkojunio2023/domain/entities/sound.dart&#39;;

final pomodoroTimerProvider = StateProvider&lt;int&gt;((ref) =&gt; 3);
// ... Rest of the code

class TimerNotifier extends StateNotifier&lt;int&gt; {
  // ...

  Future&lt;void&gt; playSound() async {
    if (!_isDisposed) {
      final selectedSound = ref.watch(selectedSoundProvider.notifier).state;
      if (_audioPlayer.processingState != ProcessingState.idle) {
        await _audioPlayer.stop();
      }
      await _audioPlayer.setAsset(selectedSound.path);
      await _audioPlayer.load();
      _audioPlayer.play();
    }
  }
  
  void updateDuration(int newDuration) {
    // ...
  }
}

// settings_page.dart

import &#39;package:flutter/material.dart&#39;;
import &#39;package:flutter/services.dart&#39;;
import &#39;package:flutter_riverpod/flutter_riverpod.dart&#39;;
import &#39;../../../domain/entities/timer_provider.dart&#39;;

class SettingsPage extends ConsumerWidget {
  // ...

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      // ...
      body: ListView(
        // ...
        children: &lt;Widget&gt;[
          // ...
          ElevatedButton(
            onPressed: () {
              // ...
              ref.read(timerNotifierProvider.notifier).updateDuration(0);
            },
            child: const Text(&#39;Save&#39;),
          )
        ],
      ),
    );
  }
}

class TimerSettingState extends ConsumerStatefulWidget {
  // ...
}

class _TimerSettingStateState extends ConsumerState&lt;TimerSettingState&gt; {
  // ...
}

How can I modify my code so that the alarm sound plays for updated timer values as well? Any step-by-step guide would be much appreciated!

Note: I am using Riverpod v2.3.6 and just_audio v0.9.34. For more information on these packages, please refer to the Riverpod documentation and the just_audio package on pub.dev.

I have also uploaded the full code snippet on GitHub for reference:
https://github.com/codemotozu/stack-overflow-question-riverpod

I greatly appreciate any guidance or suggestions you could provide to help me resolve this issue. Thank you very much for your time and expertise. I'm looking forward to your responses.

答案1

得分: 1

你的错误可能在于你在回调中使用了 ref.watch。只需使用 ref.read

Future<void> playSound() async {
    if (!_isDisposed) { //     ⬇这里⬇
      final selectedSound = ref.read(selectedSoundProvider.notifier).state;
      if (_audioPlayer.processingState != ProcessingState.idle) {
        await _audioPlayer.stop();
      }
      await _audioPlayer.setAsset(selectedSound.path);
      await _audioPlayer.load();
      _audioPlayer.play();
    }
  }
英文:

Your mistake is probably that you are using ref.watch in callbacks. Just use ref.read:

Future&lt;void&gt; playSound() async {
    if (!_isDisposed) { //     ⬇here⬇
      final selectedSound = ref.read(selectedSoundProvider.notifier).state;
      if (_audioPlayer.processingState != ProcessingState.idle) {
        await _audioPlayer.stop();
      }
      await _audioPlayer.setAsset(selectedSound.path);
      await _audioPlayer.load();
      _audioPlayer.play();
    }
  }

huangapple
  • 本文由 发表于 2023年7月13日 00:18:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76672615.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定