Skip to content

CaglarKullu/virtual_food_storage

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Flutter Food Vault Application

Overview

The Flutter Food Vault Application is a testament to modern Flutter development practices, emphasizing clean architecture, immutability, and efficient state management. Purposefully I avoid to use external packages such as freezed or equaltable for showcasing the principles behind it.

Key Development Principles

DRY with Generics

Generics play a crucial role in reducing redundancy. Our DataController<T> is a prime example:

abstract class DataController<T> extends StateNotifier<DataState<T>> {
  DataController() : super(const DataState());

  Future<void> loadData();

  // Shared logic for updating data
  void updateData(T newData) {
    state = state.copyWith(status: DataStatus.success, data: newData);
  }

  // Shared error handling
  void setError(String errorMessage) {
    state = state.copyWith(status: DataStatus.error, errorMessage: errorMessage);
  }
}

This generic controller handles common data manipulation logic, applicable across various data types (e.g., User, FoodItem).

Clean Architecture with BaseData

The BaseData<T> class encapsulates serialization, equality, and debugging functionalities, fostering a clean and maintainable codebase:

abstract class BaseData<T> {
  const BaseData();

  Map<String, dynamic> toJson();
  T fromJson(Map<String, dynamic> json);

  @override
  String toString() {
    return '${runtimeType}(${toJson().entries.map((e) => '${e.key}: ${e.value}').join(', ')})';
  }
}

Models like User, FoodItem, and Vault extend BaseData, inheriting these essential traits.

Effective State Management

I use StateNotifier along with Riverpod for state management. The switch statement in UI components reacts to different states:

class FoodItemsView extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final state = ref.watch(foodItemControllerProvider);

    switch (state.status) {
      case DataStatus.loading:
        return CircularProgressIndicator();
      // Other cases...
    }
  }
}

This approach ensures that the UI responds dynamically to state changes, enhancing user experience.

Immutability

Immutability is key for predictable state management. The models are designed to be immutable, ensuring reliability and simplicity in state changes:

@immutable
class User extends BaseData<User> {
  final String id;
  // Other fields...

  // Immutable copyWith method
  @override
  User copyWith({String? id /* other fields */}) {
    return User(id: id ?? this.id /* other fields */);
  }
}

Immutable models prevent unintended side-effects and make the app's behavior easier to understand and debug.

Conclusion

The Flutter Food Vault Application is not just a project but a reflection of best practices in Flutter development. It's built with a focus on clean code, reusability, and efficient state management, demonstrating advanced concepts in a practical, real-world application.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors