parent
5a0540924d
commit
91386b243f
After Width: | Height: | Size: 749 B |
After Width: | Height: | Size: 356 B |
@ -0,0 +1,3 @@
|
|||||||
|
description: This file stores settings for Dart & Flutter DevTools.
|
||||||
|
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||||
|
extensions:
|
@ -0,0 +1,201 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import '../api/api_download.dart';
|
||||||
|
import '../common_widget/Song_widegt.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
class DownloadItem {
|
||||||
|
final Song song;
|
||||||
|
double progress;
|
||||||
|
bool isCompleted;
|
||||||
|
bool isDownloading;
|
||||||
|
|
||||||
|
DownloadItem({
|
||||||
|
required this.song,
|
||||||
|
this.progress = 0.0,
|
||||||
|
this.isCompleted = false,
|
||||||
|
this.isDownloading = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'song': {
|
||||||
|
'pic': song.pic,
|
||||||
|
'artistPic': song.artistPic,
|
||||||
|
'title': song.title,
|
||||||
|
'artist': song.artist,
|
||||||
|
'musicurl': song.musicurl,
|
||||||
|
'id': song.id,
|
||||||
|
'likes': song.likes,
|
||||||
|
'collection': song.collection
|
||||||
|
},
|
||||||
|
'progress': progress,
|
||||||
|
'isCompleted': isCompleted,
|
||||||
|
'isDownloading': isDownloading,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从JSON创建DownloadItem
|
||||||
|
factory DownloadItem.fromJson(Map<String, dynamic> json) {
|
||||||
|
return DownloadItem(
|
||||||
|
song: Song(
|
||||||
|
pic: json['song']['pic'],
|
||||||
|
artistPic: json['song']['artistPic'],
|
||||||
|
title: json['song']['title'],
|
||||||
|
artist: json['song']['artist'],
|
||||||
|
musicurl: json['song']['musicurl'],
|
||||||
|
id: json['song']['id'],
|
||||||
|
likes: json['song']['likes'],
|
||||||
|
collection: json['song']['collection'],
|
||||||
|
),
|
||||||
|
progress: json['progress'],
|
||||||
|
isCompleted: json['isCompleted'],
|
||||||
|
isDownloading: json['isDownloading'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DownloadManager extends GetxController {
|
||||||
|
static const String PREFS_KEY = 'downloads_data';
|
||||||
|
final _downloads = <String, DownloadItem>{}.obs;
|
||||||
|
final downloadApi = DownloadApi();
|
||||||
|
late SharedPreferences _prefs;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() async {
|
||||||
|
super.onInit();
|
||||||
|
await _initPrefs();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initPrefs() async {
|
||||||
|
_prefs = await SharedPreferences.getInstance();
|
||||||
|
await _loadDownloadsFromPrefs();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从SharedPreferences加载数据
|
||||||
|
Future<void> _loadDownloadsFromPrefs() async {
|
||||||
|
final String? downloadsJson = _prefs.getString(PREFS_KEY);
|
||||||
|
if (downloadsJson != null) {
|
||||||
|
final Map<String, dynamic> downloadsMap = json.decode(downloadsJson);
|
||||||
|
downloadsMap.forEach((key, value) {
|
||||||
|
_downloads[key] = DownloadItem.fromJson(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存数据到SharedPreferences
|
||||||
|
Future<void> _saveDownloadsToPrefs() async {
|
||||||
|
final Map<String, dynamic> downloadsMap = {};
|
||||||
|
_downloads.forEach((key, value) {
|
||||||
|
downloadsMap[key] = value.toJson();
|
||||||
|
});
|
||||||
|
await _prefs.setString(PREFS_KEY, json.encode(downloadsMap));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Song> getLocalSongs() {
|
||||||
|
final localSongs = <Song>[];
|
||||||
|
_downloads.forEach((key, value) {
|
||||||
|
if (value.isCompleted) {
|
||||||
|
localSongs.add(value.song);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return localSongs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, DownloadItem> get downloads => _downloads;
|
||||||
|
|
||||||
|
bool isDownloading(int id) => _downloads[id.toString()]?.isDownloading ?? false;
|
||||||
|
bool isCompleted(int id) => _downloads[id.toString()]?.isCompleted ?? false;
|
||||||
|
double getProgress(int id) => _downloads[id.toString()]?.progress ?? 0.0;
|
||||||
|
|
||||||
|
Song? getLocalSong(int id) {
|
||||||
|
final downloadItem = _downloads[id.toString()];
|
||||||
|
if (downloadItem?.isCompleted ?? false) {
|
||||||
|
return downloadItem!.song;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool removeSong(int id) {
|
||||||
|
if (_downloads[id.toString()]?.isCompleted ?? false) {
|
||||||
|
File file = File.fromUri(Uri.parse(_downloads[id.toString()]!.song.musicurl));
|
||||||
|
file.deleteSync();
|
||||||
|
_downloads.remove(id.toString());
|
||||||
|
_saveDownloadsToPrefs();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int completedNumber() {
|
||||||
|
int count = 0;
|
||||||
|
_downloads.forEach((key, value) {
|
||||||
|
if (value.isCompleted) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> startDownload({
|
||||||
|
required Song song,
|
||||||
|
required context,
|
||||||
|
}) async {
|
||||||
|
if (_downloads[song.id.toString()]?.isDownloading ?? false) return;
|
||||||
|
|
||||||
|
final fileName = '${song.id}_${song.title}_${song.artist}';
|
||||||
|
|
||||||
|
final downloadItem = DownloadItem(
|
||||||
|
song: song,
|
||||||
|
isDownloading: true,
|
||||||
|
);
|
||||||
|
_downloads[song.id.toString()] = downloadItem;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final filePath = await downloadApi.downloadMusic(
|
||||||
|
musicUrl: song.musicurl,
|
||||||
|
name: fileName,
|
||||||
|
context: context,
|
||||||
|
onProgress: (progress) {
|
||||||
|
downloadItem.progress = progress;
|
||||||
|
_downloads[song.id.toString()] = downloadItem;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (filePath != null) {
|
||||||
|
downloadItem.isCompleted = true;
|
||||||
|
downloadItem.isDownloading = false;
|
||||||
|
downloadItem.progress = 1.0;
|
||||||
|
song.musicurl = _getLocalAudioPath(fileName, song.musicurl);
|
||||||
|
print(song.musicurl);
|
||||||
|
} else {
|
||||||
|
downloadItem.isDownloading = false;
|
||||||
|
downloadItem.progress = 0.0;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Download error: $e');
|
||||||
|
downloadItem.isDownloading = false;
|
||||||
|
downloadItem.progress = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_downloads[song.id.toString()] = downloadItem;
|
||||||
|
await _saveDownloadsToPrefs();
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getFileExtension(String url) {
|
||||||
|
// Remove query parameters
|
||||||
|
final urlWithoutQuery = url.split('?').first;
|
||||||
|
// Get the extension including the dot
|
||||||
|
final extension = path.extension(urlWithoutQuery);
|
||||||
|
return extension.isNotEmpty ? extension : '.mp3'; // Default to .mp3 if no extension found
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getLocalAudioPath(String fileName, String url) {
|
||||||
|
final extension = _getFileExtension(url);
|
||||||
|
final fullFileName = '$fileName$extension';
|
||||||
|
return path.join('/storage/emulated/0/MTMusic', fullFileName);
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,20 @@
|
|||||||
class Song {
|
class Song {
|
||||||
final String pic;
|
String pic;
|
||||||
final String artistPic;
|
String artistPic;
|
||||||
final String title;
|
String title;
|
||||||
final String artist;
|
String artist;
|
||||||
final String musicurl;
|
String musicurl;
|
||||||
final int id;
|
int id;
|
||||||
final bool likes;
|
bool likes;
|
||||||
final bool collection;
|
bool collection;
|
||||||
|
|
||||||
Song({required this.pic,required this.artistPic,required this.title, required this.artist, required this.musicurl,required this.id,required this.likes,required this.collection});
|
Song(
|
||||||
|
{required this.pic,
|
||||||
|
required this.artistPic,
|
||||||
|
required this.title,
|
||||||
|
required this.artist,
|
||||||
|
required this.musicurl,
|
||||||
|
required this.id,
|
||||||
|
required this.likes,
|
||||||
|
required this.collection});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue