0

I am trying to use Flutter Riverpod together with the Date Range Picker.

  • I have a list of Trips which when clicked on, open up the Trip Page.

Home page

  • On the trip page, the user can view the start / end dates

Trip page

  • They can then click on a button, which brings up the Date Range Picker widget

Date Range Picker

  • I want the user to be able to change the date range, and this be reflected on the screen (and eventually saved back against the Trip object)
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart';

void main() {
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Riverpod DateRange Picker',
      home: HomeScreen(),
    );
  }
}

class Trip {
  final String name;
  final DateTimeRange dateTimeRange;
  Trip(this.name, this.dateTimeRange);
}

class HomeScreen extends ConsumerWidget {
  const HomeScreen({super.key});
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    Set<Trip> trips = {
      Trip('Test 1',
          DateTimeRange(start: DateTime(2023, 1, 3), end: DateTime(2023, 1, 6)))
    };
    return Scaffold(
      appBar: AppBar(title: const Text('Riverpod DateRange Picker')),
      body: ListView(
        children: [
          for (final trip in trips)
            ListTile(
              title: Text(trip.name),
              onTap: () {
                Navigator.push(
                    context,
                    MaterialPageRoute<void>(
                        builder: (BuildContext context) =>
                            TripScreen(trip: trip)));
              },
            ),
        ],
      ),
    );
  }
}

class TripScreen extends ConsumerWidget {
  const TripScreen({Key? key, required this.trip}) : super(key: key);

  final Trip trip;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    void _showDateRangePicker() async {
      final DateTimeRange? result = await showDateRangePicker(
        context: context,
        locale: const Locale('en', 'GB'),
        initialDateRange: trip.dateTimeRange,
        saveText: 'Done',
        firstDate: DateTime(2022, 1, 1),
        lastDate: DateTime(2030, 12, 31),
      );

      if (result != null) {
        print(result);
      }
    }

    return WillPopScope(
        onWillPop: () {
          Navigator.pop(context);
          return Future.value(false);
        },
        child: Scaffold(
            backgroundColor: Colors.white,
            appBar: AppBar(
              title: Text(trip.name),
            ),
            body: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    IconButton(
                      icon: const Icon(Icons.calendar_month),
                      onPressed: () {
                        _showDateRangePicker();
                      },
                    ),
                    Text(
                        'Start: ${DateFormat('dd/MM/yyyy').format(trip.dateTimeRange.start)}'),
                    Text(
                        'End: ${DateFormat('dd/MM/yyyy').format(trip.dateTimeRange.end)}'),
                  ],
                ))));
  }
}

Any help would be much appriciated.

Thanks.

I've created this using Provider but I would like to use Riverpod.

1 Answer 1

1

I created "tripsProvider" instance of StateProvider that holds all trip data, like in your case only one value. Home screen watching that provider and displaying data in ListView, when user select item in list I pass index of item and watch that single item on new screen (copy of yours TripScreen). When user update the data of single item I update that list, so update is available on TripScreen and HomeScreen. I also still learning riverpod but hope my answer can help you.

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart';

void main() {
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

final tripsProvider = StateProvider<List<Trip>>(
  (ref) => [
    Trip(
      'Test 1',
      DateTimeRange(start: DateTime(2023, 1, 3), end: DateTime(2023, 1, 6)),
    ),
  ],
);

class Trip {
  final String name;
  final DateTimeRange dateTimeRange;

  const Trip(this.name, this.dateTimeRange);
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Riverpod DateRange Picker',
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends ConsumerWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final trips = ref.watch(tripsProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('Riverpod DateRange Picker')),
      body: ListView.builder(
        itemCount: trips.length,
        itemBuilder: (context, index) {
          Trip trip = trips[index];

          return ListTile(
            title: Text(trip.name),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute<void>(
                  builder: (BuildContext context) => TripScreen(index: index),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

class TripScreen extends ConsumerWidget {
  int index;

  TripScreen({Key? key, required this.index}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final trip = ref.watch(tripsProvider)[index];

    void _showDateRangePicker() async {
      final DateTimeRange? result = await showDateRangePicker(
        context: context,
        locale: const Locale('en', 'GB'),
        initialDateRange: trip.dateTimeRange,
        saveText: 'Done',
        firstDate: DateTime(2022, 1, 1),
        lastDate: DateTime(2030, 12, 31),
      );

      if (result != null) {
        print(result);
        Trip updatedTrip = Trip(trip.name, DateTimeRange(start: result.start, end: result.end));

        ref.read(tripsProvider.notifier).update(
          (state) {
            List<Trip> updatedList = [];
            for (int i = 0; i < state.length; i++) {
              if (i == index) {
                updatedList.add(updatedTrip);
              } else {
                updatedList.add(state[i]);
              }
            }
            return updatedList;
          },
        );
      }
    }

    return WillPopScope(
      onWillPop: () {
        Navigator.pop(context);
        return Future.value(false);
      },
      child: Scaffold(
        backgroundColor: Colors.white,
        appBar: AppBar(
          title: Text(trip.name),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              IconButton(
                icon: const Icon(Icons.calendar_month),
                onPressed: () {
                  _showDateRangePicker();
                },
              ),
              Text('Start: ${DateFormat('dd/MM/yyyy').format(trip.dateTimeRange.start)}'),
              Text('End: ${DateFormat('dd/MM/yyyy').format(trip.dateTimeRange.end)}'),
            ],
          ),
        ),
      ),
    );
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Wow, you are a genius. Thanks a lot. I've been trying to fix this problem for days. I couldn't find a good example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.