app_alerts 0.1.0
app_alerts: ^0.1.0 copied to clipboard
App-wide, prioritized alert delivery for Flutter. Polls (or receives pushed) alerts from a configurable backend source, tracks what has already been presented, and shows urgent pop-up alerts above eve [...]
import 'package:flutter/material.dart';
import 'package:app_alerts/app_alerts.dart';
/// Demonstrates the full app_alerts integration:
///
/// 1. Initialize once before runApp — here with the bundled sample feed
/// (`useSampleData: true`). Point [AppAlertsConfig.source] at an
/// `HttpAlertSource` for a real backend.
/// 2. Mount the app-wide urgent overlay with `MaterialApp.builder`.
/// 3. Render inline alerts in the app's own style with
/// `InlineAlertsBuilder`.
/// 4. Handle alert URLs (deep links or external sites) with `onOpenUrl` —
/// this example just shows a SnackBar; a real app would route custom
/// schemes through its navigator and hand web URLs to `url_launcher`.
///
/// Run it: the sample urgent alerts pop up in priority order (each with the
/// 2-second dismiss lock; the first carries a URL, so it shows View status +
/// Dismiss), and the home screen lists the sample inline alerts as
/// dismissible cards — the survey one has a URL, so it also offers Open.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await AppAlerts.initialize(
AppAlertsConfig(
useSampleData: true,
// For production, replace useSampleData with e.g.:
// source: HttpAlertSource(
// Uri.parse('https://netstorage.example.com/alerts/feed.json'),
// ),
pollInterval: const Duration(seconds: 60),
onOpenUrl: (Uri url, Alert alert) {
// Deep-link interception point. A real app might do:
// if (url.scheme == 'myapp') router.go(url.path);
// else launchUrl(url); // url_launcher
final ScaffoldMessengerState? messenger = _messengerKey.currentState;
messenger?.showSnackBar(
SnackBar(content: Text('Would open: $url (from "${alert.title}")')),
);
},
),
);
runApp(const ExampleApp());
}
final GlobalKey<ScaffoldMessengerState> _messengerKey =
GlobalKey<ScaffoldMessengerState>();
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'app_alerts example',
scaffoldMessengerKey: _messengerKey,
// One line makes urgent alerts appear above every route in the app.
builder: AppAlerts.builder,
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('app_alerts example')),
body: ListView(
padding: const EdgeInsets.all(16),
children: <Widget>[
// Inline alerts: the package hands over raw content and the app
// presents it in its own style. See _buildInlineAlerts.
InlineAlertsBuilder(builder: _buildInlineAlerts),
const SizedBox(height: 24),
FilledButton(
onPressed: () => AppAlerts.instance.refresh(),
child: const Text('Refresh feed now'),
),
],
),
);
}
// Rendered here as Material cards; alerts with a URL get an Open action
// that reuses the app-wide onOpenUrl handler.
Widget _buildInlineAlerts(
BuildContext context,
List<Alert> alerts,
Future<void> Function(String) acknowledge,
) {
if (alerts.isEmpty) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 24),
child: Text('No inline alerts pending.'),
);
}
return Column(
children: <Widget>[
for (final Alert alert in alerts)
Card(
child: ListTile(
key: ValueKey<String>(alert.id),
leading: const Icon(Icons.campaign_outlined),
title: Text(alert.title),
subtitle: Text(alert.message),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (alert.url != null)
IconButton(
icon: const Icon(Icons.open_in_new),
tooltip: 'Open',
onPressed: () => AppAlerts.instance.openUrl(alert),
),
IconButton(
icon: const Icon(Icons.close),
tooltip: 'Dismiss',
onPressed: () => acknowledge(alert.id),
),
],
),
),
),
],
);
}
}