save_points_background_service_builder 0.0.5 copy "save_points_background_service_builder: ^0.0.5" to clipboard
save_points_background_service_builder: ^0.0.5 copied to clipboard

A Flutter package to easily build and manage background services and notifications, optimized for Save Points.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:save_points_background_service_builder/save_points_background_service_builder.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize SharedPreferences for persistence
  final prefs = await SharedPreferences.getInstance();

  runApp(
    ProviderScope(
      overrides: [
        // Required for the package to access local storage
        sharedPreferencesProvider.overrideWithValue(prefs),
      ],
      child: const NotificationExampleApp(),
    ),
  );
}

class NotificationExampleApp extends StatelessWidget {
  const NotificationExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Background Service Example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF673AB7),
        ),
        useMaterial3: true,
        fontFamily: 'Inter',
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF673AB7),
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
        fontFamily: 'Inter',
      ),
      home: const ExampleDashboard(),
    );
  }
}

class ExampleDashboard extends ConsumerWidget {
  const ExampleDashboard({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final notifications = ref.watch(notificationsProvider);

    // Listen to notification taps globally
    ref.listen(notificationTapProvider, (previous, next) {
      next.whenData((response) {
        if (!context.mounted) return;
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Notification Tapped: ${response.payload}'),
            backgroundColor: Colors.green,
            behavior: SnackBarBehavior.floating,
          ),
        );
      });
    });

    return Scaffold(
      appBar: AppBar(
        title: const Text('Notification Center'),
        centerTitle: true,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _buildQuickActionCard(
              context,
              title: 'Schedule New Notification',
              subtitle: 'Create a one-time or recurring reminder',
              icon: Icons.add_alarm_rounded,
              color: Theme.of(context).colorScheme.primaryContainer,
              onTap: () => NotificationSchedulerSheet.show(context),
            ),
            const SizedBox(height: 16),
            _buildQuickActionCard(
              context,
              title: 'View Active Notifications',
              subtitle: 'Manage and cancel your scheduled alerts',
              icon: Icons.list_alt_rounded,
              color: Theme.of(context).colorScheme.secondaryContainer,
              onTap: () => Navigator.of(context).push(
                MaterialPageRoute(
                  builder: (_) => NotificationListScreen(
                    itemBuilder: (context, notification) {
                      return Card(
                        margin: const EdgeInsets.symmetric(
                          horizontal: 16,
                          vertical: 6,
                        ),
                        child: ListTile(
                          title: Text(
                            notification.title,
                            style: const TextStyle(fontWeight: FontWeight.bold),
                          ),
                          subtitle: Text(
                            '${notification.body}\nType: ${notification.type.name.toUpperCase()}',
                          ),
                          isThreeLine: true,
                          trailing: IconButton(
                            icon: const Icon(
                              Icons.delete_outline,
                              color: Colors.redAccent,
                            ),
                            onPressed: () {
                              ref
                                  .read(notificationsProvider.notifier)
                                  .removeNotification(notification.id);
                            },
                          ),
                        ),
                      );
                    },
                  ),
                ),
              ),
            ),
            const SizedBox(height: 32),
            Text(
              'Quick Status',
              style: Theme.of(
                context,
              ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 16),
            notifications.when(
              data: (list) => _buildStatusGrid(context, list.length),
              loading: () => const Center(child: CircularProgressIndicator()),
              error: (e, _) => Text('Error: $e'),
            ),
            const SizedBox(height: 32),
            _buildTestSection(context, ref),
          ],
        ),
      ),
    );
  }

  Widget _buildQuickActionCard(
    BuildContext context, {
    required String title,
    required String subtitle,
    required IconData icon,
    required Color color,
    required VoidCallback onTap,
  }) {
    return InkWell(
      onTap: onTap,
      borderRadius: BorderRadius.circular(20),
      child: Container(
        padding: const EdgeInsets.all(24),
        decoration: BoxDecoration(
          color: color,
          borderRadius: BorderRadius.circular(20),
          boxShadow: [
            BoxShadow(
              color: color.withValues(alpha: 0.3),
              blurRadius: 10,
              offset: const Offset(0, 4),
            ),
          ],
        ),
        child: Row(
          children: [
            Container(
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Colors.white24,
                borderRadius: BorderRadius.circular(12),
              ),
              child: Icon(icon, size: 32),
            ),
            const SizedBox(width: 20),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    title,
                    style: Theme.of(context).textTheme.titleMedium?.copyWith(
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  Text(subtitle, style: Theme.of(context).textTheme.bodySmall),
                ],
              ),
            ),
            const Icon(Icons.chevron_right_rounded),
          ],
        ),
      ),
    );
  }

  Widget _buildStatusGrid(BuildContext context, int count) {
    return GridView.count(
      shrinkWrap: true,
      crossAxisCount: 2,
      crossAxisSpacing: 16,
      mainAxisSpacing: 16,
      childAspectRatio: 1.5,
      physics: const NeverScrollableScrollPhysics(),
      children: [
        _buildStatItem(
          context,
          'Active Notifications',
          count.toString(),
          Icons.notifications_active_outlined,
        ),
        _buildStatItem(
          context,
          'System Status',
          'Healthy',
          Icons.check_circle_outline_rounded,
        ),
      ],
    );
  }

  Widget _buildStatItem(
    BuildContext context,
    String label,
    String value,
    IconData icon,
  ) {
    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        border: Border.all(color: Theme.of(context).dividerColor),
        borderRadius: BorderRadius.circular(16),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(icon, size: 20, color: Theme.of(context).colorScheme.primary),
          const SizedBox(height: 8),
          Text(
            value,
            style: Theme.of(
              context,
            ).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold),
          ),
          Text(label, style: Theme.of(context).textTheme.labelSmall),
        ],
      ),
    );
  }

  Widget _buildTestSection(BuildContext context, WidgetRef ref) {
    return Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.15),
        borderRadius: BorderRadius.circular(20),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Row(
            children: [
              const Icon(Icons.bug_report_outlined),
              const SizedBox(width: 12),
              Text(
                'Developer Tools',
                style: Theme.of(context).textTheme.titleMedium,
              ),
            ],
          ),
          const SizedBox(height: 16),
          FilledButton.icon(
            onPressed: () async {
              final service = ref.read(notificationServiceProvider);
              await service.showImmediateNotification(
                title: 'Instant Test',
                body: 'The notification system is working perfectly!',
              );
            },
            icon: const Icon(Icons.flash_on_rounded),
            label: const Text('Test Immediate Notification'),
          ),
          const SizedBox(height: 8),
          OutlinedButton.icon(
            onPressed: () {
              ref.read(notificationsProvider.notifier).initializeSystem();
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(content: Text('Permissions re-requested')),
              );
            },
            icon: const Icon(Icons.security_rounded),
            label: const Text('Re-initialize Permissions'),
          ),
        ],
      ),
    );
  }
}
1
likes
150
points
--
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter package to easily build and manage background services and notifications, optimized for Save Points.

Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

cupertino_icons, flutter, flutter_local_notifications, flutter_riverpod, flutter_timezone, shared_preferences, timezone, uuid

More

Packages that depend on save_points_background_service_builder