wt_framework 1.1.0
wt_framework: ^1.1.0 copied to clipboard
WondTech Flutter MVC framework — controllers, models, views, routing, sessions, and enveloped token-auth API helpers for building structured Flutter apps.
WT Framework — Flutter Edition #
WT Framework - Flutter Edition v1.1
Inspired by the original WondTech PHP MVC Framework
Overview #
A lightweight MVC framework that brings the simplicity and structure of the WT Framework — PHP Edition to Flutter mobile development.
It enforces a clean Model → Controller → View separation, built-in security helpers, session management, and a centralized router — so your Flutter app feels as organized as a well-structured PHP backend.
Features #
- MVC Architecture — Clear separation of Model, Controller, and View
- Centralized Router — Define all routes in one place, with dynamic segments (e.g.
/users/:id) - Base Model — HTTP GET / POST / PUT / DELETE with automatic JSON parsing
- Base View — Synchronous and async views with built-in loading/error/empty states
- WtSecurity — Input sanitization, XSS protection, encryption with secret key, secure token generation
- WtSession — Persistent session management using SharedPreferences
- WtHelper — Common utilities: date formatting, string manipulation, flash messages, dialogs
- WtConfig — Centralized app configuration (base URL, secret key, theme)
What's new in v1.1 #
WtModel is now ready for real, authenticated, enveloped backends — not just bare REST:
- Bearer auth, automatic — the token saved with
WtSession.set('token', ...)is injected asAuthorization: Bearer <token>on every request. - Response envelopes — set
WtConfig.envelopeKey: 'data'and models transparently read{ "state": true, "data": {...} }. - Real error messages — a failed response raises
WtModelExceptioncarrying the server'smsg(key configurable viaWtConfig.messageKey); optionalsuccessKeytreats200 + {state:false}as a failure too. - Low-level client —
getJson / postJson / putJson / deleteJson / postMultipartfor action-style endpoints (/api/login,/api/ad/5) and file uploads (WtUpload). - Safer defaults — client-side body sanitisation is now opt-in (
WtConfig.sanitizeRequests) so it no longer mangles legitimate content; add per-model headers via theextraHeadersgetter.
WtConfig.init(const WtConfig(
appName: 'Findlly',
baseUrl: 'https://findlly.co',
secretKey: '...',
envelopeKey: 'data', // unwrap { state, data }
successKey: 'state', // 200 + state:false => error
tokenKey: 'token', // WtSession key holding the bearer token
));
// action endpoint + upload, all token- & envelope-aware:
class AdsModel extends WtModel<Ad> {
@override String get endpoint => '/api/ads';
@override Ad fromJson(Map<String, dynamic> j) => Ad.fromJson(j);
Future<List<Ad>> search(String q) async =>
fromJsonList((await getJson('/api/ads', query: {'q': q}))['items']);
Future<Ad> createWithPhotos(Map<String, String> fields, List<int> jpg) async =>
fromJson(await postMultipart('/api/createad',
fields: fields,
files: [WtUpload(field: 'images[]', bytes: jpg, filename: 'p.jpg', contentType: 'image/jpeg')],
));
}
Project Structure #
wt_framework/
├── lib/
│ ├── wt.dart ← Package entry point
│ └── libs/
│ ├── core/
│ │ ├── wt_app.dart ← App root widget
│ │ └── wt_router.dart ← Route dispatcher
│ ├── config/
│ │ └── wt_config.dart ← Global config
│ ├── mvc/
│ │ ├── wt_controller.dart ← Base Controller
│ │ ├── wt_model.dart ← Base Model + HTTP
│ │ └── wt_view.dart ← Base View
│ └── helpers/
│ ├── wt_security.dart ← Security utilities
│ ├── wt_session.dart ← Session manager
│ └── wt_helper.dart ← General helpers
│
example/
├── main.dart
└── lib/
├── controllers/
├── models/
└── views/
Installation #
Add to your pubspec.yaml:
dependencies:
wt_framework:
git:
url: https://github.com/mogbil/WT_Flutter_FrameWork.git
Then run:
flutter pub get
Then import in your Dart files:
import 'package:wt_framework/wt.dart';
Usage #
1. Initialize the App — main.dart #
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await WtSession.init(); // equivalent to session_start()
WtConfig.init(const WtConfig(
appName: 'My App',
baseUrl: 'https://api.example.com',
secretKey: 'your_secret_key',
));
runApp(WtApp(
config: WtConfig.instance,
router: WtRouter(
initialRoute: '/',
routes: [
WtRoute(path: '/', builder: (s) => HomeController(s)),
WtRoute(path: '/login', builder: (s) => LoginController(s)),
WtRoute(path: '/users', builder: (s) => UsersController(s)),
WtRoute(path: '/users/:id', builder: (s) => UserDetailController(s)),
],
),
));
}
2. Define a Model #
class UserModel extends WtModel<User> {
@override
String get endpoint => '/users';
@override
User fromJson(Map<String, dynamic> json) => User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
// Fetch all users
final users = await UserModel().fetchAll();
// Fetch one
final user = await UserModel().fetch(params: {'id': '1'});
// Create
await UserModel().create({'name': 'Ali', 'email': 'ali@example.com'});
// Update
await UserModel().update('1', {'name': 'Ali Updated'});
// Delete
await UserModel().delete('1');
3. Define a Controller #
class UsersController extends WtController {
UsersController(super.settings);
@override
WtView view(BuildContext context) {
final v = UsersView();
v.assign('title', 'All Users');
v.assign('onTap', (int id) {
navigate(context, '/users/:id', args: {'id': id.toString()});
});
return v;
}
}
4. Define a View #
Synchronous:
class HomeView extends WtView {
@override
Widget build(BuildContext context) {
return scaffold(
context: context,
body: Center(child: Text(title)),
);
}
}
Async (loads data before rendering):
class UsersView extends WtAsyncView<List<User>> {
@override
Future<List<User>> loadData() => UserModel().fetchAll();
@override
Widget buildData(BuildContext context, List<User> users) {
return Scaffold(
appBar: AppBar(title: Text(title)),
body: ListView(
children: users.map((u) => ListTile(title: Text(u.name))).toList(),
),
);
}
}
5. Security #
// Sanitize input — protection against XSS and SQL injection
final safe = WtSecurity.sanitize(formData);
// Hash data with your secret key
final hash = WtSecurity.hashWithKey(data, WtConfig.instance.secretKey);
// Encode / Decode
final encoded = WtSecurity.encode(data, secretKey);
final decoded = WtSecurity.decode(encoded, secretKey);
// Validate
WtSecurity.isValidEmail('user@example.com'); // true/false
WtSecurity.isValidInput(userInput);
// Generate secure token
final token = WtSecurity.generateToken(); // 32-char random string
6. Session Management #
// Login — saves user to session
await WtSession.login({'id': 1, 'name': 'Ali', 'email': 'ali@example.com'});
// Check login state
WtSession.isLoggedIn(); // true/false
// Get logged-in user data
final user = WtSession.getUser();
// Store and retrieve custom values
await WtSession.set('cart_count', 5);
final count = WtSession.get<int>('cart_count');
// Logout — clears session
await WtSession.logout();
7. Helpers #
// Flash messages (success / error)
WtHelper.flash(context, 'Saved successfully!');
WtHelper.flash(context, 'Something went wrong', isError: true);
// Loading dialog
WtHelper.showLoading(context);
WtHelper.hideLoading(context);
// Confirm dialog
final confirmed = await WtHelper.confirm(context,
title: 'Delete',
message: 'Are you sure?',
);
// Format date
WtHelper.formatDate(DateTime.now()); // "2024-01-15"
WtHelper.timeAgo(someDate); // "3h ago"
// Format number
WtHelper.currency(1999.5); // "$1999.50"
WtHelper.formatNumber(1000000); // "1,000,000"
// String utilities
WtHelper.truncate('Long text...', 20);
WtHelper.ucFirst('hello world'); // "Hello world"
WtHelper.slug('My Page Title'); // "my-page-title"
License #
MIT License © 2026 WT Framework — Flutter Edition v1.1 — Built by WondTech. All rights reserved.