IDHT (I Don’t Have Time) is a Flutter library offering practical tools to accelerate and streamline app development.
- Event: Stay updated with changes in events, states, or values across your app.
- Store: A lightweight, in-memory database to streamline model management.
- Localization: Easily add multilingual support to your app.
- Dependency Injection (DI): Effortlessly manage and inject dependencies throughout your app.
Add to your pubspec.yaml:
dependencies:
idht: ^<latest_version>Import in your Dart/Flutter files:
import 'package:idht/idht.dart';The Event class allows you to notify other parts of your app when a change occurs. For example, when the app's theme changes in the settings, all dependent screens can be updated automatically.
The following example demonstrates how to listen to changes in a counter value and print the updated value:
final counterEvent = Event<int>(value: 0);
counterEvent.addListener((count) => print('Count: $count'));
counterEvent.send(1); // Prints: Count: 1To automatically rebuild a part of your UI when an Event value changes, use the EventBuilder widget:
EventBuilder(
events: [counterEvent], // List the events that trigger a rebuild when changed.
builder: (context) => Text('Count: ${counterEvent.value}'),
);The Store class provides a simple in-memory database for managing models in RAM. It supports basic CRUD operations and querying for efficient data handling.
// Add an object
store.put<Todo>(todo);
// Retrieve all added objects
store.getAll<Todo>();
// Retrieve objects matching a condition
store.where<Todo>((t) => t.isDone);
// Check if an object exists
store.exists<Todo>(todo);
// Update an object by ID
store.update<Todo>(id, todo);
// Remove an object
store.remove<Todo>(todo);
// Iterate over objects and perform an action
store.forEach<Todo>((t) => print(t.title));The Localization class simplifies adding multilingual support to your app.
Create a Localization instance with supported languages:
enum AppLanguage { en, es }
final localization = Localization<AppLanguage>(langs: AppLanguage.values);You can add translations in two ways, depending on your preference:
-
By Language:
localization.byLanguage({ AppLanguage.en: { "hello": "Hello", "greeting": "Hi {name}!", // Use variables in translations and replace them at runtime }, AppLanguage.es: { "hello": "Hola", "greeting": "Hola {name}!", }, });
-
By Key:
localization.byKey({ "hello": { AppLanguage.en: "Hello", AppLanguage.es: "Hola", }, "greeting": { AppLanguage.en: "Hi {name}!", AppLanguage.es: "Hola {name}!", }, });
You can access translations in two ways:
-
Using the Localization Object:
Text(localization.get("hello")) // Output: Hello
-
Using the String Extension:
Text("hello".tr); // Output: Hello Text( "greeting".trWith(values: {"name": "Adam"}) ); // Output: Hi Adam!
Switch the app's language with the changeLanguage method:
localization.changeLanguage(AppLanguage.es);To automatically update the UI when the language changes, pair Localization with an Event:
final languageEvent = Event<AppLanguage>(value: AppLanguage.en);
final localization = Localization<AppLanguage>(
langs: AppLanguage.values,
event: languageEvent,
);
// Use EventBuilder to rebuild parts of your UI when the language changes
EventBuilder(
events: [languageEvent],
builder: (context) => Text("hello".tr),
);The DI class simplifies dependency management by allowing you to define objects globally and access them from any part of your app. Without DI, passing an object from Screen A to Screen D through Screens B and C can lead to messy and error-prone code. With DI, you can register dependencies once and retrieve them anywhere.
Dependencies are typically registered before the app starts:
void setup() {
// Register dependencies here
}
void main() {
setup();
runApp(...);
}You can register dependencies as either Singleton or Factory:
- Singleton: A single instance of the object is shared across the app.
- Factory: A function that creates a new instance each time it’s called (e.g., fetching an object from a database).
void setup() {
final user = User();
di.registerSingleton<User>(user); // Register a singleton
di.registerFactory<User>(() => User()); // Register a factory
}Access registered dependencies from any part of your app:
final user = di.get<User>();Verify if a dependency is registered:
di.contains<User>(); // Returns true if registeredRemove a registered dependency when no longer needed:
di.remove<User>();You can also store and retrieve events in DI using a unique key:
Event<int>.register(value: 0, key: "counter"); // Register an event
final counterEvent = Event.get<int>("counter"); // Retrieve the eventIDHT provides a default DI instance (DI.instance) for convenience, accessible via the di getter. However, if you're using IDHT in your own package, avoid using DI.instance to prevent conflicts with the main app's dependencies. Instead, create your own DI instance and pass it to Localization, Event, and other components.
Create a custom DI instance and use it:
final myDi = DI();
void setup() {
final user = User();
myDi.registerSingleton<User>(user);
Event<int>.register(value: 0, key: "counter", di: myDi);
final counterEvent = Event.get<int>(key: "counter", di: myDi);
}final localization = Localization(langs: AppLanguage.values, di: myDi);
print("hello".trWith(di: myDi));Similarly, the store getter uses Store.instance by default. To avoid conflicts, create your own Store instance:
final myStore = Store();Contributions, issues, and feature requests are welcome!