dinkar1708/flutter_riverpod_template
Flutter riverpod tempalte.
flutter_riverpod_template
A new Flutter template project using the Riverpod library for state management.
Table of Contents
- Setup
- Guide to Run Code
- API Used
- Features
- Run Configuration Guide
- Coding Guide
- Release Guide
- APIs
- Riverpod Library Guide
- FAQ
- DO/DON'T
- TODOs
Setup
Prerequisites
- Flutter SDK installed - Current tested flutter SDK 3.19.6
- Android Studio / VS Code installed
- Emulator / Simulator / Physical device for testing
Installation
- Clone project
- Run
flutter pub get - Generating Code - To generate the necessary code, use the following commands:
One-time generation:
dart run build_runner build --delete-conflicting-outputsContinuous watch:
dart run build_runner watch --delete-conflicting-outputsGuide to Run Code
Run configuration configuration using .launch.json file
Mock data
- Guide: Mocking Providers
- Use mock run configuration to use mock/hard-coded data TODO
- Use actual configuration run actual API data
Final after running the app
API Used in the project
GitHub API:
- Base URL:
https://api.github.com/
Repositories by User Name
- Users:
- User Repositories:
https://api.github.com/users/:username/repos
- User Repositories:
- Endpoint:
users/dinkar1708/repos?per_page=3
Latest screen shots
Features
Home Page
Feature: Navigation
Feature: Counter without API
API-TYPE: No API
Requirement: Maintain widget local state only without network operation
How to Use Riverpod in This Case: Use flutter hooks HookWidget widget
- Define parent class:
// see parent class
@RoutePage()
class CounterPage extends HookWidget {- Use notifier provider on UI
// define
final counterState = useState(0);
// use variable
Text(
'Value ${counterState.value}',
style: AppTextStyle.labelMedium
.copyWith(color: context.color.textPrimary),
),
// modify variable
onPressed: () {
counterState.value = counterState.value + 1;
},Feature: User GitHub Repository List
API-TYPE: GET
Requirement: Fetch Data from Network
How to Use Riverpod in This Case: User Future Provider - https://riverpod.dev/docs/providers/future_provider
- Define a future and perform a network call:
@riverpod
class RepositoryListNotifier extends _$RepositoryListNotifier {
// below is the future provider
@override
Future<List<RepositoryListModel>> build() async => await ref
.read(userRepositoryProvider)
.getRepositories(userName, pageSize);
}- Define parent class:
// see parent class
class RepositoryListPage extends ConsumerStatefulWidget {- Use notifier provider on UI
final repositoryListAsync = ref.watch(repositoryListNotifierProvider);
return switch (repositoryListAsync) {
AsyncError(:final error) =>
SliverToBoxAdapter(child: Text('Error $error')),
AsyncData(:final value) => _buildListView(value),
_ => const SliverToBoxAdapter(child: Center(child: Text('Loading...'))),
};Feature: Search Users and Handle widget local state
API-TYPE: GET
Requirement: Fetch Data from Network and handle widget local state(clear button in search box)
How to Use Riverpod in This Case: User Future Provider with hooks - https://riverpod.dev/docs/essentials/side_effects#going-further-showing-a-spinner--error-handling
- Define a future and perform a network call:
// TODO later- Define parent class:
// see parent class is StatefulHookConsumerWidget which is special using via 'hooks_riverpod' library
// task 1 can use useState final isSearchingNotifier = useState(false);
// task 2 can do read and watch - final usersListAsync = ref.watch(usersNotifierProviderProvider);
class UsersPage extends StatefulHookConsumerWidget {- Use notifier provider on UI
// use widget local state variable
final isSearchingNotifier = useState(false);
// Change the value
onChanged: (value) {
isSearchingNotifier.value = true;
},// load user list data
final usersListAsync = ref.watch(usersNotifierProviderProvider);
return switch (usersListAsync) {
AsyncError(:final error) => SliverToBoxAdapter(
child: SliverToBoxAdapter(child: Text('Error $error'))),
AsyncData(:final value) => _buildListView(value),
_ => const SliverToBoxAdapter(child: Center(child: Text('Loading...'))),
};Feature: Login
API-TYPE: POST
Requirement: Send data to network
How to Use Riverpod in This Case:
To use the Flutter Future Notifier Provider, we can follow the guidelines provided in the Riverpod documentation. For a more comprehensive guide on handling side effects, such as showing a spinner and error handling, refer to this section of the Riverpod documentation.
However, for simplicity and to maintain clean code, you can handle error messages and loading states using the FutureProvider in Riverpod.
- Define a future and perform a network call:
@riverpod
class LoginNotifier extends _$LoginNotifier {
@override
Future<LoginStateModel> build() async {
debugPrint('login initial state....');
return Future.value(const LoginStateModel());
}- Define parent class:
// see parent class
class LoginPage extends ConsumerStatefulWidget {
- Use notifier provider on UI
// use to handle progress indicator
// watch all the times
final loginState = ref.watch(loginNotifierProvider);
// use on UI with condition
child: loginState.value?.apiResultState == APIResultState.loading
? const CircularProgressIndicator()
: const Text('Login'),// use to show error message
// use error message on UI
const SizedBox(
height: 100,
),
if (loginState.value?.errorMessage != null)
Text(loginState.value!.errorMessage),// use to do network request
// call api and handle error such as snack bar or alert etc.
loginNotifier.login(loginRequestModel).then((loginStateModel) => {
if (loginStateModel.apiResultState == APIResultState.result &&
loginStateModel.loginResponseModel != null)
{
showSnackBar(context,
'Login success ${loginStateModel.loginResponseModel!.userName}'),
context.router.replaceAll([HomeRoute(title: 'Home')]),
}
else
{
// show error message as snack bar or dailog anything
showSnackBar(
context, 'Login failed ${loginStateModel.errorMessage}'),
}
});
Loading State after the button is clicked
Loaded State after the API call is done
Feature TODO: Complex Widget local state
API-TYPE: No api
Requirement: Manage complext widget local state
How to Use Riverpod in This Case: State notifier provider https://riverpod.dev/docs/providers/state_notifier_provider
- Define state model class
StateModel {
}
- Define a state notifier and define initial state:
@riverpod
class ABCNotifier extends _$ABCNotifier {
@override
// note here not using future
StateModel build() async {
return StateModel();
}- Use notifier provider on UI
//Feature TODO: Combination of POST, GET, or Widget Local State
Define the parent StatefulHookConsumerWidget, which allows you to use useState and ref to access the provider in the desired manner.
Examples:
-
POST + Local State: Follow the login example, but define the parent
StatefulHookConsumerWidgetto useuseState. -
POST + GET: Follow the login example and the repository list example.
-
POST + GET + Widget Local State: Follow the login example, the repository list example, and define the parent as
StatefulHookConsumerWidgetto useuseState.
Run Configuration Guide
Guide link
This section provides guidance on setting up flavors, run configurations, and build modes for iOS.
Flavors/ Run Configuration and Build Mode Guide
Reference flavors guide - YouTube Video
Only the "dev" and "prod" environments follow the same steps to create a staging environment if needed. Additionally, update the same code in the main folder. Here, too, in the app_config.dart, add a new variable named staging to the AppEnvironment
A. iOS - Add Flavor (Schema) using Xcode
- **Add/Edit Schema:
-
Configuration:
In the image below, all build modes (Debug, Profile, and Release) have been shown fordevandprodflavors (Flavors).

-
Fix Main File Path:
Go to Runner -> Target -> Build Settings -> All, search forflutter_target, specify value for each main file.

-
Fix Display App Name:
Go to Runner -> Target -> Build Settings -> All, search forproduct name, specify value for each main file.

-
Fix Bundle Identifier:
Go to Runner -> Signing & Capability -> Build Settings -> All.

B. Android - Add Flavor (Schema)
C. Use Flavor
Run Configuration Setting Using VS Code
Using "dev" and "prod" flavors as examples, with "Debug" and "Release" modes:
Coding Guide
Riverpod Guide
For detailed information on how Riverpod is used in this project, please refer to the Features section, where each feature is accompanied by a guide based on Riverpod's functionality and requirements.
App navigation
- follow official documentation Auto Route
- must run Generating Code to generate route
Package used
This Flutter project utilizes the following packages:
- Riverpod - State management
- Retrofit - API call
- Dio - HTTP client
- Build Runner - Code generation
- Freezed - Code generation for models
- Freezed Annotations - Annotations for code generation
Guide to inspect widget
Start widget inspection. See below picture
Select mode -> Click button 'Toggle select widget mode'. See below picture
Select widgets - Explore the widget tree to view details. Refer to the following information about the tree:. See below picture
End widget inspection. See below picture
Release Guide
Guide CI/CD For detailed guidance
refer to: GitHub Actions Quickstart
Github Actions (CI/CD)
First-time User? Follow these steps:
-
Visit flutter-actions/setup-flutter and copy the provided basic version. Paste it into any file, give it a name, commit, push, and create a pull request. This action will automatically begin running.
-
If you have an extra step, add it to the .yml file:
- name: Generate code run: dart run build_runner build --delete-conflicting-outputs
-
Now, check if the automatic CI running has passed.
How to Use This Repository's .yml File:
- Simply copy and paste the
build.ymlfile into your repository under.github/workflows/build.yml, ensuring to specify the correct version of the Flutter SDK, and it will automatically start building.
Riverpod Library Guide
- Main library
flutter_riverpod: ^2.2.0
riverpod_annotation: ^2.3.3
- Use flutter hooks to manage state of variables
flutter_hooks
- StatefulHookConsumerWidget which offers HookWidget and ConsumerStatefulWidget both features.
hooks_riverpod
APIs
For example API usage, refer to the list below:
For example API usage, refer to the API List.
FAQ
-
Can use the
hooks_riverpodpackage, StatefulHookConsumerWidget which offers HookWidget and ConsumerStatefulWidget both features. -
All pages must be suffixed by 'Page' to generate auto router automatically
Example
Correct - HomePage // at the end must add Page
Wrong - HomeView, HomeWidget, HomeStatefullWidget -
To resolve compile errors, follow these steps:
- Ensure that generator dependencies are added to
pubspec.yaml(retrofit_generator, riverpod_generator). - Manually delete generated files (
.gand.freezed.dart) before running the build runner commands. - Fix compile issues (except for generated syntax) before running build runner commands again.
DO/DON'T
- Use hooks for storing widget local state
TODOs
- Fix command line run ->
flutter run --flavor development- Target file "lib/main.dart" not found.
- Run using Android Studio configurations
- Able to run using Android Studio
- Implement GitHub APIs using different Riverpod library usages

















