island_snack 0.1.0 copy "island_snack: ^0.1.0" to clipboard
island_snack: ^0.1.0 copied to clipboard

PlatformiOS

Dynamic Island-style notifications for Flutter iOS apps. Spring physics animations that expand from the island position.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:island_snack/island_snack.dart';

void main() => runApp(const App());

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

  @override
  Widget build(BuildContext context) {
    return IslandSnackTheme(
      successColor: const Color(0xFF7E9B72), // sage
      errorColor: const Color(0xFFB87068), // rose
      warningColor: const Color(0xFFC9834E), // terracotta
      infoColor: const Color(0xFFC8B9A0), // sand
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          brightness: Brightness.light,
          scaffoldBackgroundColor: const Color(0xFFF5F5EF),
          useMaterial3: true,
        ),
        home: const DemoScreen(),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 24),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              const SizedBox(height: 48),
              const Text(
                'Island Snack',
                style: TextStyle(
                  fontSize: 28,
                  fontWeight: FontWeight.w700,
                  color: Color(0xFF141310),
                ),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 6),
              const Text(
                'Notifications from the Dynamic Island',
                style: TextStyle(fontSize: 14, color: Color(0xFF7A7568)),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 36),
              _Btn(
                label: 'Success',
                accent: const Color(0xFF7E9B72),
                onTap: () => IslandSnack.success(
                  context,
                  title: 'Photo kept',
                  subtitle: 'Added to your favorites',
                ),
              ),
              _Btn(
                label: 'Error',
                accent: const Color(0xFFB87068),
                onTap: () => IslandSnack.error(
                  context,
                  title: 'Failed to delete',
                  subtitle: 'Please try again later',
                ),
              ),
              _Btn(
                label: 'Warning',
                accent: const Color(0xFFC9834E),
                onTap: () => IslandSnack.warning(
                  context,
                  title: 'You are offline',
                  subtitle: 'Changes will sync when connected',
                ),
              ),
              _Btn(
                label: 'Info',
                accent: const Color(0xFFC8B9A0),
                onTap: () => IslandSnack.info(
                  context,
                  title: '12 photos archived',
                  subtitle: 'Tap to review',
                ),
              ),
              _Btn(
                label: 'Loading  ->  Success',
                accent: const Color(0xFF8E8E93),
                onTap: () {
                  IslandSnack.loading(
                    context,
                    id: 'scan',
                    title: 'Scanning photos...',
                    subtitle: 'Analyzing your library',
                  );
                  Future.delayed(const Duration(seconds: 2), () {
                    if (!context.mounted) return;
                    IslandSnack.success(
                      context,
                      id: 'scan',
                      title: 'Scan complete!',
                      subtitle: '42 blurry photos found',
                    );
                  });
                },
              ),
              _Btn(
                label: 'With Undo Action',
                accent: const Color(0xFF7E9B72),
                onTap: () => IslandSnack.success(
                  context,
                  title: '5 photos deleted',
                  duration: IslandSnackDuration.action,
                  action: IslandSnackAction(
                    label: 'Undo',
                    onPressed: () {
                      if (!context.mounted) return;
                      IslandSnack.info(context, title: 'Restored!');
                    },
                  ),
                ),
              ),
              _Btn(
                label: 'With Progress Bar',
                accent: const Color(0xFFC9834E),
                onTap: () => IslandSnack.show(
                  context,
                  title: 'Scanning for blurry photos...',
                  subtitle: '128 / 342',
                  progress: 0.37,
                  style: const IslandSnackStyle(
                    accentColor: Color(0xFFC9834E),
                    iconData: Icons.blur_on_rounded,
                  ),
                  duration: IslandSnackDuration.action,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class _Btn extends StatelessWidget {
  const _Btn({
    required this.label,
    required this.accent,
    required this.onTap,
  });

  final String label;
  final Color accent;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 10),
      child: GestureDetector(
        onTap: onTap,
        child: Container(
          padding: const EdgeInsets.symmetric(vertical: 15),
          decoration: BoxDecoration(
            color: Colors.black,
            borderRadius: BorderRadius.circular(16),
            border: Border.all(
              color: accent.withValues(alpha: 0.3),
              width: 1,
            ),
          ),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                width: 8,
                height: 8,
                decoration: BoxDecoration(
                  color: accent,
                  shape: BoxShape.circle,
                ),
              ),
              const SizedBox(width: 10),
              Text(
                label,
                style: const TextStyle(
                  color: Colors.white,
                  fontSize: 15,
                  fontWeight: FontWeight.w600,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
1
likes
150
points
9
downloads

Documentation

API reference

Publisher

verified publisheralejandrogarcia.io

Weekly Downloads

Dynamic Island-style notifications for Flutter iOS apps. Spring physics animations that expand from the island position.

Repository (GitHub)

Topics

#notification #snackbar #dynamic-island #ios #animation

License

MIT (license)

Dependencies

device_info_plus, figma_squircle, flutter

More

Packages that depend on island_snack