flutter_homescreen_widget 0.1.5 copy "flutter_homescreen_widget: ^0.1.5" to clipboard
flutter_homescreen_widget: ^0.1.5 copied to clipboard

Update iOS WidgetKit and Android Glance widgets using Flutter as the UI. Pure Dart — no Swift or Kotlin required. Supports tap actions and multiple sizes.

example/lib/main.dart

import 'dart:async';

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

final _navigatorKey = GlobalKey<NavigatorState>();

void main() {
  FlutterHomescreenWidget.init(_navigatorKey);
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: _navigatorKey,
      title: 'flutter_homescreen_widget example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark(),
      home: const ClockPage(),
    );
  }
}

class ClockPage extends StatefulWidget {
  const ClockPage({super.key});

  @override
  State<ClockPage> createState() => _ClockPageState();
}

class _ClockPageState extends State<ClockPage> {
  DateTime _now = DateTime.now();
  Timer? _timer;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) async {
      await Future.delayed(const Duration(milliseconds: 300));
      _updateWidgets();
    });
    _timer = Timer.periodic(const Duration(minutes: 1), (_) {
      setState(() => _now = DateTime.now());
      _updateWidgets();
    });
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  Future<void> _updateWidgets() async {
    final now = DateTime.now();
    setState(() => _now = now);
    try {
      await FlutterHomescreenWidget.update(
        widgetName: 'ClockWidget',
        size: const Size(329, 155),
        content: ClockWidgetMedium(now: now),
      );
      await FlutterHomescreenWidget.update(
        widgetName: 'ClockWidgetSmall',
        size: const Size(155, 155),
        content: ClockWidgetSmall(now: now),
      );
    } catch (e) {
      debugPrint('Widget update error: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: const BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            colors: [Color(0xFF1a1a2e), Color(0xFF16213e), Color(0xFF0f3460)],
          ),
        ),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Text('Widget Preview',
                  style: TextStyle(color: Colors.white54, fontSize: 13)),
              const SizedBox(height: 24),
              ClipRRect(
                borderRadius: BorderRadius.circular(20),
                child: SizedBox(
                  width: 329,
                  height: 155,
                  child: ClockWidgetMedium(now: _now),
                ),
              ),
              const SizedBox(height: 16),
              ClipRRect(
                borderRadius: BorderRadius.circular(20),
                child: SizedBox(
                  width: 155,
                  height: 155,
                  child: ClockWidgetSmall(now: _now),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

/// Medium clock widget — landscape layout with date and AM/PM indicator.
class ClockWidgetMedium extends StatelessWidget {
  final DateTime now;
  const ClockWidgetMedium({super.key, required this.now});

  @override
  Widget build(BuildContext context) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(24),
      child: Stack(fit: StackFit.expand, children: [
      _Background(),
      Positioned(top: -40, right: -20, child: _GlowCircle(160, Colors.purpleAccent.withOpacity(0.25))),
      Positioned(bottom: -30, left: 60, child: _GlowCircle(100, Colors.blueAccent.withOpacity(0.2))),
      Padding(
        padding: const EdgeInsets.all(16),
        child: _GlassCard(
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
            child: Row(children: [
              Expanded(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(_formatTime(now),
                        style: const TextStyle(
                            color: Colors.white, fontSize: 52,
                            fontWeight: FontWeight.w200, letterSpacing: -2, height: 1)),
                    const SizedBox(height: 6),
                    Text(_formatDate(now),
                        style: TextStyle(color: Colors.white.withOpacity(0.55), fontSize: 13)),
                  ],
                ),
              ),
              Container(
                  width: 1, height: 60,
                  color: Colors.white.withOpacity(0.15),
                  margin: const EdgeInsets.symmetric(horizontal: 20)),
              Column(mainAxisAlignment: MainAxisAlignment.center, children: [
                Text(_dayOfWeek(now),
                    style: TextStyle(
                        color: Colors.white.withOpacity(0.5),
                        fontSize: 11, letterSpacing: 2, fontWeight: FontWeight.w500)),
                const SizedBox(height: 8),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
                  decoration: BoxDecoration(
                    color: Colors.white.withOpacity(0.12),
                    borderRadius: BorderRadius.circular(20),
                    border: Border.all(color: Colors.white.withOpacity(0.2)),
                  ),
                  child: Text(now.hour < 12 ? 'AM' : 'PM',
                      style: const TextStyle(
                          color: Colors.white, fontSize: 12,
                          fontWeight: FontWeight.w600, letterSpacing: 1)),
                ),
              ]),
            ]),
          ),
        ),
      ),
    ]));
  }
}

/// Small clock widget — compact square layout.
class ClockWidgetSmall extends StatelessWidget {
  final DateTime now;
  const ClockWidgetSmall({super.key, required this.now});

  @override
  Widget build(BuildContext context) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(24),
      child: Stack(fit: StackFit.expand, children: [
        _Background(),
        Positioned(top: -30, right: -20, child: _GlowCircle(110, Colors.purpleAccent.withOpacity(0.25))),
        Positioned(bottom: -20, left: -10, child: _GlowCircle(80, Colors.blueAccent.withOpacity(0.2))),
        Padding(
          padding: const EdgeInsets.all(12),
          child: _GlassCard(
            child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
              Text(_formatTime(now),
                  style: const TextStyle(
                      color: Colors.white, fontSize: 36,
                      fontWeight: FontWeight.w200, letterSpacing: -1.5, height: 1)),
              const SizedBox(height: 6),
              Text(_dayOfWeek(now),
                  style: TextStyle(color: Colors.white.withOpacity(0.45), fontSize: 10, letterSpacing: 2)),
              const SizedBox(height: 6),
              Text(_formatDateShort(now),
                  style: TextStyle(color: Colors.white.withOpacity(0.6), fontSize: 12)),
            ]),
          ),
        ),
      ]),
    );
  }
}

String _formatTime(DateTime t) {
  final h = t.hour % 12 == 0 ? 12 : t.hour % 12;
  return '$h:${t.minute.toString().padLeft(2, '0')}';
}

String _formatDate(DateTime t) {
  const months = ['January','February','March','April','May','June',
                  'July','August','September','October','November','December'];
  return '${months[t.month - 1]} ${t.day}, ${t.year}';
}

String _formatDateShort(DateTime t) {
  const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
  return '${months[t.month - 1]} ${t.day}';
}

String _dayOfWeek(DateTime t) {
  const days = ['MON','TUE','WED','THU','FRI','SAT','SUN'];
  return days[t.weekday - 1];
}

class _Background extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: const BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
          colors: [Color(0xFF1a1a2e), Color(0xFF16213e), Color(0xFF0f3460)],
        ),
      ),
    );
  }
}

class _GlowCircle extends StatelessWidget {
  final double size;
  final Color color;
  const _GlowCircle(this.size, this.color);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: size, height: size,
      decoration: BoxDecoration(
        shape: BoxShape.circle, color: color,
        boxShadow: [BoxShadow(color: color, blurRadius: 40, spreadRadius: 10)],
      ),
    );
  }
}

class _GlassCard extends StatelessWidget {
  final Widget child;
  const _GlassCard({required this.child});

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(16),
        color: Colors.white.withOpacity(0.08),
        border: Border.all(color: Colors.white.withOpacity(0.18)),
        boxShadow: [BoxShadow(
            color: Colors.black.withOpacity(0.2),
            blurRadius: 20, offset: const Offset(0, 4))],
      ),
      child: child,
    );
  }
}
3
likes
150
points
0
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Update iOS WidgetKit and Android Glance widgets using Flutter as the UI. Pure Dart — no Swift or Kotlin required. Supports tap actions and multiple sizes.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_homescreen_widget

Packages that implement flutter_homescreen_widget