Troubleshooting Radio Button Implementation that can play sounds

Actions & Logic
Resolved

SOLUTION (see below for original post) :

I managed to get what I wanted with the help of ChatGPT.

You first need to create an AppState element. It can be string, integer, whatever you need to be returned after the user selected the radio element. In my case, it's the id of the sound.

Secondly, you need to create a custom widget :

import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:just_audio/just_audio.dart';

class SoundsListView extends StatefulWidget {
  const SoundsListView({super.key, this.width, this.height});
  final double? width;
  final double? height;

  @override
  State<SoundsListView> createState() => _SoundsListViewState();
}

class _SoundsListViewState extends State<SoundsListView> {
  final AudioPlayer player = AudioPlayer();
  List<dynamic> sounds = [];
  int? _selectedIndex;
  int?
      soundID; // Init the local appstate variable

  @override
  void initState() {
    super.initState();
    print("initState: fetchSounds is being called.");
    fetchSounds();
  }

  fetchSounds() async {
    try {
      final response = await Supabase.instance.client
          .from('sounds')
          .select()
          .order('id', ascending: true)
          .execute();
      final data = response.data;
      if (data != null) {
        print("fetchSounds: Data fetched - $data");
        setState(() {
          sounds = data;
          _selectedIndex = null;
          soundID = null; // Reset the ID of the sound
          print("fetchSounds: setState called.");
        });
      } else {
        print("fetchSounds: No data collected.");
      }
    } catch (e) {
      print("fetchSounds: Exception: - $e");
    }
  }

  @override
  void dispose() {
    player.dispose();
    super.dispose();
    print("dispose: SoundListView was disposed.");
  }

  @override
  Widget build(BuildContext context) {
    print(
        "build: Building SoundsListView with ${sounds.length} sounds.");
    return Container(
      width: widget.width,
      height: widget.height,
      child: ListView.builder(
        itemCount: sounds.length,
        itemBuilder: (context, index) {
          var sound = sounds[index];
          print("ListView.builder: Building the element: $index");
          return RadioListTile(
            title: Text(sound['name']),
            value: index,
            groupValue: _selectedIndex,
            onChanged: (value) async {
              setState(() {
                _selectedIndex = value;
                FFAppState().update(() {
                  FFAppState().soundID =
                      sound['id']; // Store the soundID selected
                });
              });
              print("RadioListTile: Playing the following sound ${sound['name']}");
              await player.setUrl(sound['sound_url']);
              player.play();
            },
          );
        },
      ),
    );
  }
}

The important part here is

  int?
      soundID; // Init the local appstate variable

that you need to change for your appstate variable type and name and

                FFAppState().update(() {
                  FFAppState().soundID =
                      sound['id']; // Store the soundID selected
                });

That you need to change as well.

Note that I'm using Supabase to collect the list of my sounds so you will need to modify this part to make it work

      final response = await Supabase.instance.client
          .from('sounds')
          .select()
          .order('id', ascending: true)
          .execute();
      final data = response.data;
      if (data != null) {
        print("fetchSounds: Data fetched - $data");
        setState(() {
          sounds = data;
          _selectedIndex = null;
          soundID = null; // Reset the ID of the sound
          print("fetchSounds: setState called.");
        });
      } else {
        print("fetchSounds: No data collected.");
      }
    } catch (e) {
      print("fetchSounds: Exception: - $e");
    }
  }

Once you select the sound (or anything) you want from the radiobuttion, it will automatically update the appstate variable. You can then use this value to do any actions you want to.

Voilà ! Hope it can help!

ORIGINAL THREAD

Hi everyone,

As the title implies, I'm trying to display a list of sounds that users can choose from, with a little speaker icon next to each sound. If the user clicks on the speaker, it plays the correct sound. Since I want them to be able to select only one, I went with the radio button widget.

The issue is that I cannot get it to work. I cannot generate a list of radio buttons like I can do with a listview, where each radio button has its own state.


What have you tried so far?

I tried encapsulating the radio widget inside a column that would generate individual radio buttons, where each radio button is a component. The problem is, the user can select virtually every button with this method.

I also tried to generate only one sound widget, and map the options respective to the list of sound names. It works, but then I cannot play the sound respective to its name.

Did you check FlutterFlow's Documentation for this topic?
Yes
2 replies