starter_kit_flutter 1.0.5
starter_kit_flutter: ^1.0.5 copied to clipboard
A batteries-included foundational Flutter package for networking, connectivity, storage, theming, app updates, and core utilities.
🚀 starter_kit_flutter #
A batteries-included Flutter package that sets up common app foundations from one place.

Ship features faster — stop re-wiring the same boilerplate in every project.
| 🌐 Networking | Dio + interceptors + sealed Result / AppError |
| 💾 Storage | SharedPreferences + Flutter Secure Storage |
| 🎨 Theming | Light / dark / system with persistence |
| 🧱 Design system | Spacing, radius, shadows, typography tokens |
| 🚩 Feature flags | Runtime flags + conditional UI (StarterKitSlot) |
| 🛡️ Safe JSON | Crash-proof parsing against API key drift |
| 🛠️ Dev Panel | Debug-only in-app inspector (kDebugMode) |
| 📡 Connectivity | Monitoring with optional offline banner |
| 🔄 Updater | Force-update & maintenance screens |
| ✨ Utilities | Extensions, validators, loader & toast overlays |
| 🖼️ App icons | CLI wrapper around flutter_launcher_icons |
Package:
starter_kit_flutteron pub.dev
Import:package:starter_kit_flutter/starter_kit_flutter.dart
Compat export:package:starter_kit_flutter/starter_kit.dart
📦 Installation #
dependencies:
starter_kit_flutter:
git:
url: https://gitlab.com/moin-quantana/starter_kit.git
ref: main
Or from pub.dev:
dependencies:
starter_kit_flutter: ^1.0.5
flutter pub get
⚡ One-Place Setup (Recommended) #
Use StarterKitApp as the single integration point. It initializes modules and wraps overlays for you.
import 'package:flutter/material.dart';
import 'package:starter_kit_flutter/starter_kit_flutter.dart';
void main() {
runApp(
StarterKitApp(
config: StarterKitConfig(
networkConfig: const NetworkConfig(
baseUrl: 'https://api.example.com',
authTokenKey: 'auth_token',
),
storageConfig: const StorageConfig(),
themeConfig: const ThemeConfig(
defaultThemeMode: ThemeMode.system,
),
updaterConfig: const UpdaterConfig(
versionCheckUrl: 'https://api.example.com/version',
enableAutoCheck: true,
enableMaintenanceMode: true,
),
modules: const StarterKitModulesConfig(
network: StarterKitModuleMode.enabled,
storage: StarterKitModuleMode.enabled,
theme: StarterKitModuleMode.enabled,
connectivity: StarterKitModuleMode.enabled,
updater: StarterKitModuleMode.enabled,
featureFlags: StarterKitModuleMode.enabled,
),
featureFlagConfig: const FeatureFlagConfig(
initialFlags: {'promo_banner': true},
),
ui: const StarterKitUiConfig(
showConnectivityBanner: true,
showForceUpdateScreen: true,
showMaintenanceScreen: true,
enableGlobalLoader: true,
enableDevPanel: true,
devPanelTrigger: DevPanelTrigger.floatingButton,
),
designSystemConfig: const DesignSystemConfig(
spacing: DesignSpacingConfig(
xxs: 4,
xs: 8,
sm: 12,
md: 16,
lg: 20,
xl: 24,
xxl: 32,
section: 40,
),
radius: DesignRadiusConfig(
sm: 8,
md: 12,
lg: 16,
xl: 24,
),
typography: DesignTypographyConfig(
titleLargeSize: 24,
bodyLargeSize: 16,
bodyMediumSize: 14,
),
),
),
appBuilder: (context, data) {
return MaterialApp(
navigatorKey: data.navigatorKey,
theme: data.lightTheme,
darkTheme: data.darkTheme,
themeMode: data.themeMode,
home: const HomePage(),
);
},
),
);
}
Access services anywhere after init:
StarterKit.I.storage
StarterKit.I.network
StarterKit.I.theme
StarterKit.I.connectivity
StarterKit.I.updater
StarterKit.I.featureFlags
🎛️ Module Toggles #
StarterKitModulesConfig controls each module explicitly:
| Mode | Behavior |
|---|---|
enabled |
Register the real implementation |
stub |
Register a stub (safe no-ops / controlled fallbacks) |
disabled |
Unregister; accessors still fall back to stubs if called |
const StarterKitModulesConfig(
network: StarterKitModuleMode.enabled,
storage: StarterKitModuleMode.enabled,
theme: StarterKitModuleMode.enabled,
connectivity: StarterKitModuleMode.enabled,
updater: StarterKitModuleMode.disabled,
featureFlags: StarterKitModuleMode.enabled,
)
Predictable behavior:
- Stub — calls succeed structurally with controlled fallbacks (e.g.
NETWORK_NOT_INITIALIZED) - Disabled — module not registered; accessor stubs prevent hard crashes
- Enabled + missing config —
initvalidation throws a clear configuration error
🖼️ UI Controls #
StarterKitUiConfig centralizes global UI behavior applied by StarterKitApp / StarterKit.builder:
const StarterKitUiConfig(
showConnectivityBanner: true,
showForceUpdateScreen: true,
showMaintenanceScreen: true,
enableGlobalLoader: true,
enableDevPanel: true, // only active when kDebugMode == true
devPanelTrigger: DevPanelTrigger.floatingButton, // or .tripleTap / .both
)
🚩 Feature Flags & Conditional UI #
Seed flags from config:
StarterKitConfig(
featureFlagConfig: const FeatureFlagConfig(
initialFlags: {
'new_checkout': false,
'promo_banner': true,
},
),
modules: const StarterKitModulesConfig(
featureFlags: StarterKitModuleMode.enabled,
),
)
Runtime access:
final enabled = StarterKit.I.featureFlags.isEnabled('new_checkout');
await StarterKit.I.featureFlags.setOverride('new_checkout', true);
await StarterKit.I.featureFlags.clearOverride('new_checkout');
await StarterKit.I.featureFlags.applyRemoteValues({'promo_banner': true});
Conditional rendering with StarterKitSlot:
StarterKitSlot(
featureFlag: 'promo_banner',
flaggedChild: const PromoBanner(),
fallback: const SizedBox.shrink(),
child: const SizedBox.shrink(),
)
🛡️ Safe JSON Parsing #
Tolerate backend key renames without crashing:
final json = response as Map<String, dynamic>;
final id = json.asString(['account_id', 'user_id', 'id'], fallback: '');
final total = json.asInt(['total', 'count'], fallback: 0);
final active = json.asBool(['is_active', 'active', 'enabled'], fallback: false);
final nested = json.asMap(['data', 'payload'], fallback: {});
// Or:
SafeJsonReader.asString(json, ['account_id', 'user_id', 'id']);
🛠️ In-App Dev Panel (Debug Only) #
Mounted only when kDebugMode == true and enableDevPanel: true.
| Tab | What it does |
|---|---|
| Network | Request logs, artificial delay, force 500 / 401 / offline |
| Storage | Search / edit / delete SharedPreferences (+ secure read helper) |
| Design | Live theme mode + spacing / radius token tweaks |
| Overlays | Simulate offline / maintenance / force-update + toast |
| Flags | Toggle feature flags + base URL / key remapper |
ui: const StarterKitUiConfig(
enableDevPanel: true,
devPanelTrigger: DevPanelTrigger.both, // FAB and/or triple-tap top-left
)
Release safety: Dev Panel host and Dio debug interceptor are gated by kDebugMode.
🎨 Centralized Design System #
DesignSystemConfig provides one-place visual tokens:
const DesignSystemConfig(
spacing: DesignSpacingConfig(
xxs: 4, xs: 8, sm: 12, md: 16,
lg: 20, xl: 24, xxl: 32, section: 40,
),
radius: DesignRadiusConfig(sm: 8, md: 12, lg: 16, xl: 24),
shadow: DesignShadowConfig(cardElevation: 2),
typography: DesignTypographyConfig(
fontFamily: null,
titleLargeSize: 24,
bodyLargeSize: 16,
bodyMediumSize: 14,
labelMediumSize: 12,
),
)
final spacing = context.dsSpacing;
final radius = context.dsRadius;
final shadows = context.dsShadow;
final typography = context.dsTypography;
const VSpace(DesignSpacingSize.md);
const HSpace(DesignSpacingSize.sm);
SKSizedBox.h16;
SKSizedBox.w8;
⚠️ Error Model #
Storage and network operations return sealed Result / AppError — no raw exceptions to the UI.
final result = await StarterKit.I.network.get<Map<String, dynamic>>(
'/users/1',
fromJson: (json) => json as Map<String, dynamic>,
);
result.fold(
(error) {
switch (error) {
case NetworkError(:final statusCode):
debugPrint('Network $statusCode: ${error.message}');
case ConnectionError():
debugPrint('Offline: ${error.message}');
case StorageError():
debugPrint('Storage: ${error.message}');
case ValidationError():
debugPrint('Validation: ${error.message}');
case ConfigurationError():
debugPrint('Config: ${error.message}');
case UnknownError():
debugPrint('Unknown: ${error.message}');
}
},
(data) => debugPrint('Success: $data'),
);
// Helpers: result.isSuccess, result.dataOrNull, result.errorOrNull
📚 Usage Examples #
🌐 Networking #
final getResult = await StarterKit.I.network.get<Map<String, dynamic>>(
'/users/123',
fromJson: (json) => json as Map<String, dynamic>,
);
final postResult = await StarterKit.I.network.post<Map<String, dynamic>>(
'/users',
data: {'name': 'John Doe', 'email': 'john@example.com'},
fromJson: (json) => json as Map<String, dynamic>,
);
// PUT, PATCH, DELETE are also available
💾 Storage #
await StarterKit.I.storage.setString('username', 'john_doe');
final username = await StarterKit.I.storage.getString('username');
await StarterKit.I.storage.setInt('count', 42);
await StarterKit.I.storage.setBool('isLoggedIn', true);
await StarterKit.I.storage.setDouble('rating', 4.5);
await StarterKit.I.storage.setStringList('tags', ['flutter', 'dart']);
🎨 Theme #
await StarterKit.I.theme.setThemeMode(ThemeMode.dark);
await StarterKit.I.theme.toggleTheme();
MaterialApp(
theme: StarterKit.I.theme.lightTheme,
darkTheme: StarterKit.I.theme.darkTheme,
themeMode: StarterKit.I.theme.currentThemeMode,
);
📡 Connectivity #
StarterKit.I.connectivity.connectionStream.listen((state) {
switch (state) {
case NetworkConnectionState.connected:
debugPrint('Online');
case NetworkConnectionState.disconnected:
debugPrint('Offline');
case NetworkConnectionState.unknown:
debugPrint('Unknown');
}
});
final current = StarterKit.I.connectivity.currentState;
🔄 Updater #
final status = await StarterKit.I.updater.checkForUpdates();
switch (status) {
case UpdateStatus.upToDate:
case UpdateStatus.updateAvailable:
case UpdateStatus.forceUpdateRequired:
case UpdateStatus.maintenanceMode:
case UpdateStatus.unknown:
debugPrint('$status');
}
StarterKit.I.updater.updateStatusStream.listen((status) {
// react to status changes
});
💬 Overlays #
GlobalLoader(
isLoading: _isLoading,
child: YourContent(),
);
ToastOverlay.show(context, 'Hello!');
ToastOverlay.showSuccess(context, 'Success!');
ToastOverlay.showError(context, 'Error!');
ToastOverlay.showWarning(context, 'Warning!');
ToastOverlay.showInfo(context, 'Info!');
final ctx = StarterKit.navigatorKey.currentContext;
if (ctx != null) {
ToastOverlay.showSuccess(ctx, 'Done');
}
✨ Utilities #
// Strings
'user@example.com'.isValidEmail;
'john doe'.capitalize();
'john doe'.capitalizeWords();
' '.isBlank;
// Context
context.screenWidth;
context.screenHeight;
context.showSnackBar('Hello!');
context.showSuccessSnackBar('OK');
context.showErrorSnackBar('Failed');
// Responsive
20.h(context); // % of height
50.w(context); // % of width
10.sp(context); // % of smaller dimension
// Dates
DateTime.now().toReadable();
DateTime.now().toShortReadable();
DateTime.now().isToday;
// Form validators
TextFormField(validator: emailValidator());
TextFormField(
validator: combineValidators([
requiredValidator('Password'),
minLengthValidator(8, 'Password'),
]),
);
TextFormField(validator: phoneValidator());
⚙️ Configuration Reference #
NetworkConfig #
NetworkConfig(
baseUrl: 'https://api.example.com',
connectTimeout: 30,
receiveTimeout: 30,
sendTimeout: 30,
enableLogging: true,
enableRetry: true,
maxRetries: 3,
authTokenKey: 'auth_token',
headers: {'X-API-Key': 'your-api-key'},
)
StorageConfig #
StorageConfig(
keyPrefix: 'my_app_',
enableSecureStorage: true,
enablePreferencesStorage: true,
)
ThemeConfig #
ThemeConfig(
defaultThemeMode: ThemeMode.system,
lightTheme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeStorageKey: 'theme_mode',
)
UpdaterConfig #
UpdaterConfig(
versionCheckUrl: 'https://api.example.com/version',
currentVersion: '1.0.0', // optional; auto from package_info if omitted
checkInterval: 3600,
enableAutoCheck: true,
enableMaintenanceMode: true,
headers: {'Authorization': 'Bearer token'},
)
FeatureFlagConfig #
FeatureFlagConfig(
initialFlags: {'promo_banner': true},
storageKey: 'starter_kit_feature_flags',
)
🧩 Manual / Advanced Path #
If you need explicit control over init order:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await StarterKit.init(
StarterKitConfig(
networkConfig: const NetworkConfig(baseUrl: 'https://api.example.com'),
storageConfig: const StorageConfig(),
themeConfig: const ThemeConfig(),
),
);
runApp(
MaterialApp(
navigatorKey: StarterKit.navigatorKey,
builder: (context, child) => StarterKit.builder(child: child!),
home: const HomePage(),
),
);
}
Re-initialize at runtime:
await StarterKit.init(newConfig, true);
🖼️ App Icon Generation (CLI) #
Wrapper around flutter_launcher_icons. Run from the consuming app root.
- Add to the app
pubspec.yaml:
dev_dependencies:
flutter_launcher_icons: ^0.14.4
- Generate:
flutter pub get
dart run starter_kit_flutter:starter_kit_icons --logo assets/logo/app_logo.png
Optional flags:
dart run starter_kit_flutter:starter_kit_icons --logo assets/logo/app_logo.png --no-ios
dart run starter_kit_flutter:starter_kit_icons --logo assets/logo/app_logo.png --no-android
dart run starter_kit_flutter:starter_kit_icons --logo assets/logo/app_logo.png \
--adaptive-bg "#FFFFFF" --adaptive-fg assets/logo/fg.png
A temporary launcher config is created and removed after the run.
🔑 Public API (Beginner First) #
Primary
StarterKitAppStarterKitConfig/StarterKitModulesConfig/StarterKitUiConfigDesignSystemConfig/FeatureFlagConfigStarterKit.Iservices (storage,network,theme,connectivity,updater,featureFlags)StarterKitSlotSafeJsonReader+ Map key-chain extensions- Sealed
Result/AppError
Advanced
StarterKit.init(...)/StarterKit.builder(...)/StarterKit.navigatorKey- Overlays:
GlobalLoader,ToastOverlay, connectivity / force-update / maintenance screens - Debug:
StarterKitDevPanel,DevPanelTrigger,StarterKitDebugController - Extensions, validators,
ResponsiveSizer
🏗️ Architecture #
- Facade — host apps talk to
StarterKit/StarterKit.Ionly - Modules —
enabled/stub/disabledregistration via GetIt - Interfaces —
INetworkClient,IStorageService,IConnectivityService,IUpdaterService,IFeatureFlagService - Errors — sealed
Result+ sealedAppErrorhierarchy
lib/
├── src/
│ ├── core/
│ │ ├── data/ # Network & storage implementations
│ │ ├── services/ # Connectivity, updater, feature flags
│ │ ├── design_system/ # Theme manager, spacing, responsive
│ │ ├── widgets/ # App, builder, slot, overlays, Dev Panel
│ │ ├── models/ # Configs & responses
│ │ ├── exceptions/ # Result & AppError
│ │ ├── utils/ # SafeJson, extensions, validators
│ │ ├── debug/ # Dev Panel controller
│ │ └── helpers/ # Service locator, logger, routing keys
│ └── facade/
│ └── starter_kit.dart
├── starter_kit_flutter.dart # Public export
└── starter_kit.dart # Compatibility re-export
✅ Requirements #
- Flutter SDK
>= 3.0.0 - Dart SDK
>= 3.0.0 < 4.0.0
📌 Dependencies #
| Package | Constraint |
|---|---|
dio |
^5.11.1 |
get_it |
^9.2.0 |
shared_preferences |
^2.5.3 |
flutter_secure_storage |
>=10.0.0 <12.0.0 |
connectivity_plus |
>=6.1.5 <8.0.0 |
package_info_plus |
>=9.0.0 <11.0.0 |
📄 License #
MIT — see LICENSE.
💬 Support #
Issues and contributions: GitLab.
👤 Authors #
- Md. Moinuddin / Developed at Quantana India