import 'package:flutter/material.dart'; import 'package:wayland_layer_shell/types.dart'; import 'package:wayland_layer_shell/wayland_layer_shell.dart'; import 'dart:io'; void main(List args) async { WidgetsFlutterBinding.ensureInitialized(); // Parse command line arguments: x y xp_value duration_seconds if (args.length < 4) { print('Usage: xp_overlay_app '); exit(1); } final x = int.tryParse(args[0]) ?? 0; final y = int.tryParse(args[1]) ?? 0; final xpValue = int.tryParse(args[2]) ?? 0; final duration = int.tryParse(args[3]) ?? 3; final shell = WaylandLayerShell(); final success = await shell.initialize(50, 200); if (!success) { print('wayland layer shell could not initialize'); exit(1); } await shell.setLayer(ShellLayer.layerBackground); await shell.setExclusiveZone(0); await shell.setKeyboardMode(ShellKeyboardMode.keyboardModeNone); await shell.setAnchor(ShellEdge.edgeLeft, true); // shell.setAnchor(ShellEdge.edgeRight, true); await shell.setAnchor(ShellEdge.edgeTop, true); // shell.setAnchor(ShellEdge.edgeBottom, true); await shell.setMargin(ShellEdge.edgeLeft, x); await shell.setMargin(ShellEdge.edgeTop, y); runApp( XPOverlayScreen( xpValue: xpValue, duration: Duration(seconds: duration), shell: shell, ), ); } class XPOverlayScreen extends StatefulWidget { final int xpValue; final Duration duration; final WaylandLayerShell shell; const XPOverlayScreen({super.key, required this.xpValue, required this.duration, required this.shell}); @override State createState() => _XPOverlayScreenState(); } class _XPOverlayScreenState extends State { @override void initState() { super.initState(); _scheduleExit(); widget.shell.setLayer(ShellLayer.layerOverlay); } void _scheduleExit() { Future.delayed(widget.duration, () { exit(0); }); } @override Widget build(BuildContext context) { return MaterialApp( color: Colors.transparent, home: Scaffold( backgroundColor: Colors.transparent, body: Center( child: XPNumberWidget(xpValue: widget.xpValue, duration: widget.duration), ), ), ); } } class XPNumberWidget extends StatefulWidget { final int xpValue; final Duration duration; const XPNumberWidget({super.key, required this.xpValue, required this.duration}); @override State createState() => _XPNumberWidgetState(); } class _XPNumberWidgetState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _slideAnimation; late Animation _fadeAnimation; late Animation _scaleAnimation; @override void initState() { super.initState(); _controller = AnimationController(duration: widget.duration, vsync: this); // Slide up animation _slideAnimation = Tween( begin: 0.0, end: -100.0, ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut)); // Fade out animation _fadeAnimation = Tween(begin: 1.0, end: 0.0).animate( CurvedAnimation( parent: _controller, curve: const Interval(0.7, 1.0, curve: Curves.easeIn), ), ); // Scale bounce animation _scaleAnimation = Tween(begin: 0.8, end: 1.0).animate( CurvedAnimation( parent: _controller, curve: const Interval(0.0, 0.3, curve: Curves.elasticOut), ), ); _controller.forward(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _controller, builder: (context, child) { return Transform.translate( offset: Offset(0, _slideAnimation.value), child: Transform.scale( scale: _scaleAnimation.value, child: Opacity( opacity: _fadeAnimation.value, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: _getXPColor().withOpacity(0.9), borderRadius: BorderRadius.circular(16), border: Border.all(color: _getXPColor(), width: 2), boxShadow: [BoxShadow(color: _getXPColor().withOpacity(0.3), blurRadius: 8, spreadRadius: 2)], ), child: Text( '+${widget.xpValue}', style: TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, shadows: [Shadow(color: Colors.black.withOpacity(0.7), offset: const Offset(1, 1), blurRadius: 2)], ), ), ), ), ), ); }, ); } Color _getXPColor() { if (widget.xpValue >= 100) { return Colors.amber; // Gold for bonus XP } else if (widget.xpValue >= 50) { return Colors.orange; // Orange for high XP } else { return Colors.green; // Green for regular XP } } }