From flutter-skills-33
Uses Flutter's http package for GET, POST, PUT, DELETE requests to REST APIs. Includes permissions setup, headers, error handling, JSON deserialization, and isolate-based parsing.
npx claudepluginhub joshuarweaver/cascade-code-languages-misc-1 --plugin flutter-skills-33This skill uses the workspace's default tool permissions.
- [Configuration & Permissions](#configuration--permissions)
Conducts multi-round deep research on GitHub repos via API and web searches, generating markdown reports with executive summaries, timelines, metrics, and Mermaid diagrams.
Dynamically discovers and combines enabled skills into cohesive, unexpected delightful experiences like interactive HTML or themed artifacts. Activates on 'surprise me', inspiration, or boredom cues.
Generates images from structured JSON prompts via Python script execution. Supports reference images and aspect ratios for characters, scenes, products, visuals.
Configure the environment and platform-specific permissions required for network access.
http package dependency via the terminal:
flutter pub add http
import 'package:http/http.dart' as http;
android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements:
<key>com.apple.security.network.client</key>
<true/>
Execute HTTP operations and map responses to strongly typed Dart objects.
Uri.parse('your_url').headers parameter map. Use HttpHeaders.authorizationHeader for auth tokens.jsonEncode() from dart:convert.response.statusCode. Treat 200 OK (GET/PUT/DELETE) and 201 CREATED (POST) as success.null on failure, as this prevents FutureBuilder from triggering its error state and causes infinite loading indicators.jsonDecode(response.body) and map it to a custom Dart object using a factory constructor (e.g., fromJson).Offload expensive JSON parsing to a separate Isolate to prevent UI jank (frame drops).
package:flutter/foundation.dart.compute() function to run the parsing logic in a background isolate.compute() is a top-level function or a static method, as closures or instance methods cannot be passed across isolates.Use the following checklist to implement and validate network operations.
Task Progress:
fromJson factory constructor.Future<Model>.'Content-Type': 'application/json; charset=UTF-8' and attach the jsonEncode body.200 OK).statusCode and throw an Exception on failure.Future into the UI using FutureBuilder.snapshot.hasData, snapshot.hasError, and default to a CircularProgressIndicator.import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
// 1. Top-level parsing function for Isolate
List<Photo> parsePhotos(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<Object?>)
.cast<Map<String, Object?>>();
return parsed.map<Photo>(Photo.fromJson).toList();
}
// 2. Network execution with background parsing
Future<List<Photo>> fetchPhotos() async {
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/photos'),
headers: {
HttpHeaders.authorizationHeader: 'Bearer your_token_here',
HttpHeaders.acceptHeader: 'application/json',
},
);
if (response.statusCode == 200) {
// Offload heavy parsing to a background isolate
return compute(parsePhotos, response.body);
} else {
throw Exception('Failed to load photos. Status: ${response.statusCode}');
}
}
}
// 3. Strongly typed model
class Photo {
final int id;
final String title;
final String thumbnailUrl;
const Photo({
required this.id,
required this.title,
required this.thumbnailUrl,
});
factory Photo.fromJson(Map<String, dynamic> json) {
return Photo(
id: json['id'] as int,
title: json['title'] as String,
thumbnailUrl: json['thumbnailUrl'] as String,
);
}
}
// 4. UI Integration
class PhotoGallery extends StatefulWidget {
const PhotoGallery({super.key});
@override
State<PhotoGallery> createState() => _PhotoGalleryState();
}
class _PhotoGalleryState extends State<PhotoGallery> {
late Future<List<Photo>> _futurePhotos;
@override
void initState() {
super.initState();
// Initialize Future once to prevent re-fetching on rebuilds
_futurePhotos = fetchPhotos();
}
@override
Widget build(BuildContext context) {
return FutureBuilder<List<Photo>>(
future: _futurePhotos,
builder: (context, snapshot) {
if (snapshot.hasData) {
final photos = snapshot.data!;
return ListView.builder(
itemCount: photos.length,
itemBuilder: (context, index) => ListTile(
leading: Image.network(photos[index].thumbnailUrl),
title: Text(photos[index].title),
),
);
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
// Default loading state
return const Center(child: CircularProgressIndicator());
},
);
}
}