player_notification 0.0.1 copy "player_notification: ^0.0.1" to clipboard
player_notification: ^0.0.1 copied to clipboard

A Flutter plug-in for displaying the music player controller in the notification bar.

example/lib/main.dart

import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:player_notification/player_notification.dart';

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

  if (Platform.isAndroid) {
    // 请求通知权限
    await Permission.notification.request();

    // 如果需要系统级权限
    if (await Permission.systemAlertWindow.status.isDenied) {
      await Permission.systemAlertWindow.request();
    }
  }

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Player Notification Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const PlayerNotificationDemo(),
    );
  }
}

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

  @override
  State<PlayerNotificationDemo> createState() => _PlayerNotificationDemoState();
}

class _PlayerNotificationDemoState extends State<PlayerNotificationDemo> {
  final _playerNotification = PlayerNotification();
  bool _isPlaying = false;
  String _currentLyrics = '暂无歌词';
  int _currentSongIndex = 0;
  bool _isSticky = true; // 常驻状态控制
  Duration _position = Duration.zero;
  Duration _duration = const Duration(minutes: 3, seconds: 30); // 设置一个默认时长
  Timer? _progressTimer;

  // 模拟歌曲列表
  final List<Map<String, String>> _songs = [
    {
      'title': '起风了',
      'artist': '周深',
      'imageUrl':
          'https://onecms-res.cloudinary.com/image/upload/s--2Rbc2xc5--/f_auto,q_auto/c_fill,g_auto,h_622,w_830/v1/tdy-migration/19410372.JPG?itok=dEoez4y4',
      'lyrics': '这一路上走走停停...',
    },
    {
      'title': '我记得',
      'artist': '赵雷',
      'imageUrl': 'https://example.com/song2.jpg',
      'lyrics': '清晨从梦中醒来...',
    },
    {
      'title': '像我这样的人',
      'artist': '毛不易',
      'imageUrl': 'https://example.com/song3.jpg',
      'lyrics': '像我这样优秀的人...',
    },
  ];

  @override
  void initState() {
    super.initState();
    _setupNotificationListeners();
    _showCurrentSong();
    _startProgressTimer();
  }

  void _setupNotificationListeners() {
    _playerNotification.setPlaybackListener(
      onPlay: () {
        setState(() {
          _isPlaying = true;
          _updateNotificationPlayState();
        });
      },
      onPause: () {
        setState(() {
          _isPlaying = false;
          _updateNotificationPlayState();
        });
      },
      onNext: () {
        setState(() {
          _currentSongIndex = (_currentSongIndex + 1) % _songs.length;
          // 直接调用 show 更新所有信息
          _showCurrentSong();
        });
      },
      onPrevious: () {
        setState(() {
          _currentSongIndex =
              (_currentSongIndex - 1 + _songs.length) % _songs.length;
          // 直接调用 show 更新所有信息
          _showCurrentSong();
        });
      },
    );

    // 进度条拖动监听
    _playerNotification.setProgressListener((position, duration) {
      setState(() {
        _position = position;
        // 如果需要,也可以更新 duration
        // _duration = duration;
      });

      // 停止计时器,防止与拖动冲突
      _progressTimer?.cancel();

      // 重新启动计时器
      _startProgressTimer();
    });
  }

  void _showCurrentSong() {
    final song = _songs[_currentSongIndex];
    _playerNotification.show(
      title: song['title']!,
      artist: song['artist']!,
      imageUrl: song['imageUrl'],
      lyrics: song['lyrics']!,
      isPlaying: _isPlaying,
      position: _position,
      duration: _duration,
    );
    setState(() {
      _currentLyrics = song['lyrics']!;
      _position = Duration.zero; // 重置播放位置
      _duration = const Duration(minutes: 3, seconds: 30); // 设置新歌曲的时长
      _playerNotification.updateProgress(_position, _duration);
    });
  }

  void _startProgressTimer() {
    _progressTimer?.cancel();
    _progressTimer = Timer.periodic(const Duration(milliseconds: 500), (timer) {
      if (_isPlaying) {
        setState(() {
          _position += const Duration(milliseconds: 500);
          if (_position > _duration) {
            _position = Duration.zero;
          }
          _playerNotification.updateProgress(_position, _duration);
        });
      }
    });
  }

  void _updateNotificationPlayState() {
    _playerNotification.updatePlayState(_isPlaying);
  }

  void _playNextSong() {
    setState(() {
      _currentSongIndex = (_currentSongIndex + 1) % _songs.length;
      _showCurrentSong();
    });
  }

  void _playPreviousSong() {
    setState(() {
      _currentSongIndex =
          (_currentSongIndex - 1 + _songs.length) % _songs.length;
      _showCurrentSong();
    });
  }

  void _togglePlayPause() {
    setState(() {
      _isPlaying = !_isPlaying;
      _updateNotificationPlayState();
    });
  }

  void _updateLyrics(String lyrics) {
    setState(() {
      _currentLyrics = lyrics;
      _playerNotification.updateLyrics(lyrics);
    });
  }

  @override
  Widget build(BuildContext context) {
    final currentSong = _songs[_currentSongIndex];

    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('播放器通知示例'),
        actions: [
          // 常驻通知栏控制开关
          Switch(
            value: _isSticky,
            onChanged: (value) {
              setState(() {
                _isSticky = value;
                _playerNotification.setSticky(_isSticky);
              });
            },
          ),
        ],
      ),
      body: Column(
        children: [
          Center(
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  // 歌曲信息
                  Text(
                    currentSong['title']!,
                    style: Theme.of(context).textTheme.headlineMedium,
                  ),
                  const SizedBox(height: 8),
                  Text(
                    currentSong['artist']!,
                    style: Theme.of(context).textTheme.titleMedium,
                  ),
                  const SizedBox(height: 32),

                  // 歌词显示
                  Container(
                    padding: const EdgeInsets.all(16),
                    decoration: BoxDecoration(
                      color: Colors.grey[200],
                      borderRadius: BorderRadius.circular(8),
                    ),
                    child: Text(
                      _currentLyrics,
                      textAlign: TextAlign.center,
                      style: const TextStyle(fontSize: 16),
                    ),
                  ),
                  const SizedBox(height: 32),

                  // 播放控制
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      IconButton(
                        icon: const Icon(Icons.skip_previous),
                        iconSize: 48,
                        onPressed: _playPreviousSong,
                      ),
                      const SizedBox(width: 16),
                      IconButton(
                        icon: Icon(_isPlaying ? Icons.pause : Icons.play_arrow),
                        iconSize: 64,
                        onPressed: _togglePlayPause,
                      ),
                      const SizedBox(width: 16),
                      IconButton(
                        icon: const Icon(Icons.skip_next),
                        iconSize: 48,
                        onPressed: _playNextSong,
                      ),
                    ],
                  ),
                  const SizedBox(height: 32),

                  // 测试按钮
                  ElevatedButton(
                    onPressed: () {
                      _updateLyrics('测试更新歌词 - ${DateTime.now().toString()}');
                    },
                    child: const Text('更新歌词'),
                  ),
                ],
              ),
            ),
          ),
          // 进度条
          Slider(
            value: _position.inSeconds.toDouble(),
            max: _duration.inSeconds.toDouble(),
            onChanged: (value) {
              setState(() {
                _position = Duration(seconds: value.toInt());
                _playerNotification.updateProgress(_position, _duration);
              });
            },
          ),

          // 时间显示
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(_formatDuration(_position)),
              Text(_formatDuration(_duration)),
            ],
          ),
        ],
      ),
    );
  }

  // 格式化时间的方法
  String _formatDuration(Duration duration) {
    String twoDigits(int n) => n.toString().padLeft(2, '0');
    String minutes = twoDigits(duration.inMinutes.remainder(60));
    String seconds = twoDigits(duration.inSeconds.remainder(60));
    return "$minutes:$seconds";
  }

  @override
  void dispose() {
    _progressTimer?.cancel();
    _playerNotification.hide();
    super.dispose();
  }
}
2
likes
120
points
19
downloads

Publisher

verified publisherflutter-online.top

Weekly Downloads

A Flutter plug-in for displaying the music player controller in the notification bar.

Documentation

API reference

License

MPL-2.0 (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on player_notification