like_devtool 1.2.0
like_devtool: ^1.2.0 copied to clipboard
A developer tooling panel for the LIKE networking package. Provides an inspectable bottom sheet with logs, traffic inspector, and feature flags.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:like/like.dart';
import 'package:like_devtool/like_devtool.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const LikeDevToolExampleApp());
}
/// The root application widget demonstrating the LIKE DevTool panel.
class LikeDevToolExampleApp extends StatelessWidget {
/// Creates the [LikeDevToolExampleApp].
const LikeDevToolExampleApp({super.key});
@override
Widget build(BuildContext context) {
return Like(
baseUrl: 'https://jsonplaceholder.typicode.com',
// Injects the LIKE DevTool overlay. The overlay FAB appears automatically
// in debug builds and is stripped in release builds.
devTool: (child) => LikeDevTool(child: child),
child: MaterialApp(
title: 'LIKE DevTool Example',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF14B8A6),
brightness: Brightness.dark,
),
scaffoldBackgroundColor: const Color(0xFF0F1115),
appBarTheme: const AppBarTheme(
backgroundColor: Color(0xFF16181D),
elevation: 0,
centerTitle: true,
),
),
home: const DevToolDemoScreen(),
),
);
}
}
/// The main demo screen showing various actions to trigger traffic and inspect details.
class DevToolDemoScreen extends StatefulWidget {
/// Creates a [DevToolDemoScreen] widget.
const DevToolDemoScreen({super.key});
@override
State<DevToolDemoScreen> createState() => _DevToolDemoScreenState();
}
class _DevToolDemoScreenState extends State<DevToolDemoScreen> {
final ValueNotifier<LikeStateResponse<List<dynamic>>> _postsNotifier =
ValueNotifier(LikeStateResponse.idle());
@override
void initState() {
super.initState();
_fetchDemoPosts();
}
@override
void dispose() {
_postsNotifier.dispose();
super.dispose();
}
Future<void> _fetchDemoPosts() async {
_postsNotifier.value = LikeStateResponse.loading();
final result = await LikeClient().get(
'/posts',
ars: const ARS(staleWhileRevalidate: true),
);
_postsNotifier.value = LikeStateResponse.fromResult(result);
}
Future<void> _triggerPostRequest() async {
// Generate a POST request to show up in the devtool traffic inspector
await LikeClient().post(
'/posts',
body: {
'title': 'Testing LIKE DevTool',
'body': 'This request was captured by the traffic inspector!',
'userId': 1,
},
);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('POST request triggered! Open DevTool to inspect.'),
backgroundColor: Color(0xFF14B8A6),
),
);
}
Future<void> _triggerErrorRequest() async {
// Generate a failing request to demonstrate error handling and red indicators
await LikeClient().get('/invalid-endpoint-for-error-testing');
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Failed GET request triggered! Open DevTool to inspect.'),
backgroundColor: Colors.redAccent,
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'LIKE DEVTOOL DEMO',
style: TextStyle(
fontWeight: FontWeight.bold,
letterSpacing: 1.2,
fontSize: 16,
),
),
),
body: Column(
children: [
// Control Actions Panel
Container(
padding: const EdgeInsets.all(16.0),
color: const Color(0xFF16181D),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'INTERACT & GENERATE TRAFFIC',
textAlign: TextAlign.center,
style: TextStyle(
color: Color(0xFF14B8A6),
fontSize: 11,
fontWeight: FontWeight.bold,
letterSpacing: 1.5,
),
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF1E2128),
foregroundColor: Colors.white,
),
onPressed: _triggerPostRequest,
icon: const Icon(Icons.send_rounded, size: 16),
label: const Text('POST Req'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF1E2128),
foregroundColor: Colors.white,
),
onPressed: _triggerErrorRequest,
icon: const Icon(Icons.error_outline_rounded, size: 16),
label: const Text('Fail Req'),
),
),
],
),
],
),
),
// List of posts from jsonplaceholder
Expanded(
child: ValueListenableBuilder<LikeStateResponse<List<dynamic>>>(
valueListenable: _postsNotifier,
builder: (context, state, _) {
return LikeBuilder<List<dynamic>>(
observe: () => state,
onLoading: () => const Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(Color(0xFF14B8A6)),
),
),
onSuccess: (posts, isRefreshing, isFromSWR) {
final displayPosts = posts.take(10).toList();
return Stack(
children: [
RefreshIndicator(
onRefresh: _fetchDemoPosts,
color: const Color(0xFF14B8A6),
child: ListView.builder(
padding: const EdgeInsets.all(12),
itemCount: displayPosts.length,
itemBuilder: (context, index) {
final post = displayPosts[index];
return Card(
color: const Color(0xFF16181D),
margin: const EdgeInsets.only(bottom: 10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: ListTile(
leading: CircleAvatar(
backgroundColor: const Color(0xFF1E2128),
foregroundColor: const Color(0xFF14B8A6),
child: Text(post['id'].toString()),
),
title: Text(
post['title'],
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
subtitle: Text(
post['body'],
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.white.withValues(
alpha: 0.7,
),
),
),
),
);
},
),
),
if (isRefreshing)
const Positioned(
top: 0,
left: 0,
right: 0,
child: LinearProgressIndicator(
minHeight: 2,
valueColor: AlwaysStoppedAnimation(
Color(0xFF14B8A6),
),
backgroundColor: Colors.transparent,
),
),
],
);
},
onError: (error) => Center(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.cloud_off_rounded,
size: 48,
color: Colors.redAccent,
),
const SizedBox(height: 12),
Text(
'Failed to fetch posts: ${error.message}',
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.white70),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _fetchDemoPosts,
child: const Text('Retry'),
),
],
),
),
),
);
},
),
),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: const Color(0xFF14B8A6),
foregroundColor: Colors.white,
onPressed: _fetchDemoPosts,
child: const Icon(Icons.refresh_rounded),
),
);
}
}