Merge branch 'refs/heads/dev2'

# Conflicts:
#	lib/common_widget/Song_widegt.dart
#	lib/view/home_view.dart
#	lib/view/main_tab_view/main_tab_view.dart
#	pubspec.lock
#	pubspec.yaml
master
Spark 1 week ago
commit 08a374f864

@ -0,0 +1,2 @@
#Mon Oct 28 21:45:22 CST 2024
java.home=C\:\\Program Files\\Android\\Android Studio\\jbr

@ -0,0 +1,8 @@
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Mon Oct 28 21:45:22 CST 2024
sdk.dir=C\:\\Users\\zxp\\AppData\\Local\\Android\\Sdk

@ -1,3 +1,4 @@
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
systemProp.org.gradle.wrapper.timeout=300000

@ -1,7 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import '../models/universal_bean.dart'; import '../models/universal_bean.dart';
const String _changeNameURL = 'http://flyingpig.fun:10010/users/username'; const String _changeNameURL = 'http://flyingpig.fun:10010/users/username';
@ -9,6 +8,7 @@ const String _changeHeaderURL = 'http://flyingpig.fun:10010/users/avatar';
class ChangeApiClient { class ChangeApiClient {
final Dio dio = Dio(); final Dio dio = Dio();
final ValueNotifier<String> avatarUrlNotifier = ValueNotifier<String>("");
/// ///
Future<UniversalBean> changeName({ Future<UniversalBean> changeName({
required String Authorization, required String Authorization,
@ -16,13 +16,19 @@ class ChangeApiClient {
}) async { }) async {
Response response = await dio.put( Response response = await dio.put(
_changeNameURL, _changeNameURL,
data: { // data: {
'Authorization': Authorization, // 'Authorization': Authorization,
}, // },
queryParameters: {'userName':userName}, queryParameters: {'userName':userName},
options: Options(headers:{'Authorization':Authorization,'Content-Type':'application/json;charset=UTF-8'}) options: Options(
headers:{
'Authorization':Authorization,
'Content-Type':'application/json;charset=UTF-8'
}
)
); );
print(response.data); print(response.data);
return UniversalBean.formMap(response.data); return UniversalBean.formMap(response.data);
} }
/// ///
@ -32,7 +38,7 @@ class ChangeApiClient {
required File avatar, required File avatar,
}) async { }) async {
FormData formData = FormData.fromMap({ FormData formData = FormData.fromMap({
'Authorization': Authorization, // 'Authorization': Authorization,
'avatar': await MultipartFile.fromFile(avatar.path, filename: 'avatar.jpg'), 'avatar': await MultipartFile.fromFile(avatar.path, filename: 'avatar.jpg'),
}); });
@ -46,8 +52,8 @@ class ChangeApiClient {
}, },
), ),
); );
print(response.data); print(response.data);
avatarUrlNotifier.value = avatar.path;
return UniversalBean.formMap(response.data); return UniversalBean.formMap(response.data);
} }

@ -1,13 +1,15 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import '../common_widget/Song_widegt.dart';
import '../models/getMusicList_bean.dart'; import '../models/getMusicList_bean.dart';
import '../models/getRank_bean.dart'; import '../models/getRank_bean.dart';
const String _getMusic1 = 'http://flyingpig.fun:10010/musics/1'; const String _getMusic1 = 'http://flyingpig.fun:10010/musics/1';
const String _getMusic2 = 'http://flyingpig.fun:10010/musics/2'; const String _getMusic2 = 'http://flyingpig.fun:10010/musics/2';
const String _getMusic3 = 'http://flyingpig.fun:10010/musics/3'; const String _getMusic3 = 'http://flyingpig.fun:10010/musics/3';
const String _getSongDetail = 'http://flyingpig.fun:10010/musics';
/// ///
class GetMusic { class GetMusic {
final Dio dio = Dio(); final Dio dio = Dio();
@ -51,3 +53,40 @@ class GetMusic {
return MusicListBean.formMap(response.data); return MusicListBean.formMap(response.data);
} }
} }
//
class GetMusicDetail {
final Dio dio = Dio();
// ID
Future<Song> getMusicDetail({required int songId, required String Authorization}) async {
try {
// songId URL
final String url = 'http://flyingpig.fun:10010/musics/$songId'; // API
// GET
Response response = await dio.get(
url,
options: Options(
headers: {
'Authorization': Authorization,
'Content-Type': 'application/json;charset=UTF-8',
},
),
);
print("Song detail response: ${response.data}");
//
if (response.statusCode == 200) {
// Song
return Song.fromMap(response.data['data']);
} else {
throw Exception("Failed to load song details");
}
} catch (e) {
print("Error occurred while fetching song details: $e");
rethrow; //
}
}
}

@ -9,18 +9,27 @@ import '../models/search_bean.dart';
const String _SearchURL = 'http://flyingpig.fun:10010/musics/search'; const String _SearchURL = 'http://flyingpig.fun:10010/musics/search';
const String _postComment = 'http://flyingpig.fun:10010/comments'; const String _postComment = 'http://flyingpig.fun:10010/comments';
/// ///
class SearchMusic{ class SearchMusic {
final Dio dio = Dio(); final Dio dio = Dio();
Future<SearchBean> search({required String keyword,}) async {
Future<SearchBean> search({
required String keyword,
required String Authorization,
}) async {
Response response = await dio.get( Response response = await dio.get(
_SearchURL, _SearchURL,
queryParameters: {'keyword':keyword} queryParameters: {'keyword': keyword},
options: Options(headers: {
'Authorization': Authorization,
'Content-Type': 'application/json;charset=UTF-8',
}),
); );
print(response.data); print(response.data);
return SearchBean.formMap(response.data); return SearchBean.formMap(response.data);
} }
} }
/// ///
class commentMusic { class commentMusic {
final Dio dio = Dio(); final Dio dio = Dio();

@ -8,13 +8,29 @@ class Song {
bool likes; bool likes;
bool collection; bool collection;
Song( //
{required this.pic, Song({
required this.artistPic, required this.pic,
required this.title, required this.artistPic,
required this.artist, required this.title,
required this.musicurl, required this.artist,
required this.id, required this.musicurl,
required this.likes, required this.id,
required this.collection}); required this.likes,
required this.collection,
});
// 使 Map Song
factory Song.fromMap(Map<String, dynamic> map) {
return Song(
pic: map['coverPath'] ?? '', // coverPath
artistPic: map['coverPath'] ?? '', // artistPic
title: map['name'] ?? '', // name
artist: map['singerName'] ?? '', // singerName
musicurl: map['musicPath'] ?? '', // musicPath
id: map['id'] ?? 0, // ID id
likes: map['likeOrNot'] ?? false, // likeOrNot
collection: map['collectOrNot'] ?? false, // collectOrNot
);
}
} }

@ -21,17 +21,25 @@ class HomeView extends StatefulWidget {
} }
class _HomeViewState extends State<HomeView> { class _HomeViewState extends State<HomeView> {
// 使 GetX HomeViewModel homeVM
// Get.put() HomeViewModel GetX 便使
final homeVM = Get.put(HomeViewModel()); final homeVM = Get.put(HomeViewModel());
// TextEditingController
//
final TextEditingController _controller = TextEditingController(); final TextEditingController _controller = TextEditingController();
// _isSearching
// _isSearching true_isSearching false
bool _isSearching = false; bool _isSearching = false;
final downloadManager = Get.put(DownloadManager()); final downloadManager = Get.put(DownloadManager());
void initState() { void initState() {
super.initState(); super.initState();
_fetchSonglistData(); _fetchSonglistData();
} }
List<Song> songs = []; List<Song> selectedSongs = [];
Future<void> _fetchSonglistData() async { Future<void> _fetchSonglistData() async {
MusicListBean bean1 = MusicListBean bean1 =
await GetMusic().getMusic1(Authorization: AppData().currentToken); await GetMusic().getMusic1(Authorization: AppData().currentToken);
@ -41,7 +49,7 @@ class _HomeViewState extends State<HomeView> {
await GetMusic().getMusic3(Authorization: AppData().currentToken); await GetMusic().getMusic3(Authorization: AppData().currentToken);
setState(() { setState(() {
songs = [ selectedSongs = [
Song( Song(
artistPic: bean1.coverPath!, artistPic: bean1.coverPath!,
title: bean1.name!, title: bean1.name!,
@ -81,23 +89,85 @@ class _HomeViewState extends State<HomeView> {
{"image": "assets/img/banner.png"}, {"image": "assets/img/banner.png"},
]; ];
List<String> _filteredData = []; List<Song> _filteredData = [];
Future<void> _filterData(String query) async { Future<void> _filterData(String query) async {
if (query.isNotEmpty) { if (query.isNotEmpty) {
SearchBean bean = await SearchMusic().search(keyword: query); try {
if (bean.code == 200) { //
SearchBean bean = await SearchMusic().search(
keyword: query,
Authorization: AppData().currentToken,
);
//
if (bean.code == 200 && bean.data != null) {
//
List<Future<Song?>> songDetailsFutures = [];
// id
for (var data in bean.data!) {
if (data.id != null) { // id null
// 使 id Future
songDetailsFutures.add(
GetMusicDetail().getMusicDetail(
songId: data.id!,
Authorization: AppData().currentToken,
).then((details) {
if (details != null) {
// Song
return Song(
artistPic: details.artistPic ?? '', //
title: data.name ?? '', //
artist: details.artist ?? '', //
musicurl: details.musicurl ?? '', //
pic: details.pic ?? '', //
id: details.id, // ID
likes: details.likes, //
collection: details.collection, //
);
}
return null; // null
}).catchError((error) {
print("Error occurred while fetching song details: $error");
return null; // null
})
);
} else {
print("Song ID is null for song: ${data.name}");
}
}
// 使 Future.wait
List<Song?> songDetailsList = await Future.wait(songDetailsFutures);
// null
List<Song> validSongDetails = songDetailsList.where((song) => song != null).cast<Song>().toList();
// UI _filteredData
setState(() {
_filteredData = validSongDetails; //
_isSearching = true; //
});
//
print("Filtered Data: $_filteredData");
} else {
setState(() {
_filteredData = [];
_isSearching = false;
});
}
} catch (error) {
print("Error occurred during search: $error");
setState(() { setState(() {
_filteredData = bean.data _filteredData = [];
?.map((data) => _isSearching = false;
"${data.name} ") // Adjust this based on your data structure
.toList() ??
[];
_isSearching = true;
}); });
} }
} else { } else {
setState(() { setState(() {
_filteredData = [];
_isSearching = false; _isSearching = false;
}); });
} }
@ -226,7 +296,21 @@ class _HomeViewState extends State<HomeView> {
itemCount: _filteredData.length, itemCount: _filteredData.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return ListTile( return ListTile(
title: Text(_filteredData[index]), title: Text(_filteredData[index].title),
onTap: () {
//
Navigator.push(
// 使 Navigator
context,
MaterialPageRoute(
// MusicView
builder: (context) => MusicView(
songList: _filteredData, //
initialSongIndex: index, //
),
),
);
},
); );
}, },
), ),
@ -261,18 +345,18 @@ class _HomeViewState extends State<HomeView> {
), ),
ListView.builder( ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemCount: songs.length, itemCount: selectedSongs.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return ListTile( return ListTile(
leading: Image.network(songs[index].pic), leading: Image.network(selectedSongs[index].pic),
title: Text( title: Text(
songs[index].title, selectedSongs[index].title,
style: const TextStyle(fontSize: 18, color: Colors.black), style: const TextStyle(fontSize: 18, color: Colors.black),
), ),
subtitle: Text( subtitle: Text(
songs[index].artist, selectedSongs[index].artist,
style: const TextStyle(fontSize: 16, color: Colors.black), style: const TextStyle(fontSize: 16, color: Colors.black),
), ),
trailing: InkWell( trailing: InkWell(
@ -286,14 +370,14 @@ class _HomeViewState extends State<HomeView> {
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => MusicView( builder: (context) => MusicView(
songList: songs, songList: selectedSongs,
initialSongIndex: index, initialSongIndex: index,
onSongStatusChanged: (index, isCollected, isLiked) { onSongStatusChanged: (index, isCollected, isLiked) {
setState(() { setState(() {
// //
songs[index].collection = isCollected; selectedSongs[index].collection = isCollected;
songs[index].likes = isLiked; selectedSongs[index].likes = isLiked;
downloadManager.updateSongInfo(songs[index].id, isCollected, isLiked); downloadManager.updateSongInfo(selectedSongs[index].id, isCollected, isLiked);
}); });
}, },
), ),

@ -1,17 +1,12 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:music_player_miao/widget/text_field.dart'; import 'package:image_picker/image_picker.dart';
import '../../api/api_client.dart'; import '../../api/api_client.dart';
import '../../api/api_client_info.dart'; import '../../api/api_client_info.dart';
import '../../common_widget/app_data.dart'; import '../../common_widget/app_data.dart';
import '../../models/getInfo_bean.dart';
import '../../models/universal_bean.dart';
import '../../view_model/home_view_model.dart'; import '../../view_model/home_view_model.dart';
import 'package:image_picker/image_picker.dart'; import '../../view/main_tab_view/main_tab_view.dart';
class UserInfo extends StatefulWidget { class UserInfo extends StatefulWidget {
const UserInfo({super.key}); const UserInfo({super.key});
@ -23,7 +18,7 @@ class UserInfo extends StatefulWidget {
class _UserInfoState extends State<UserInfo> { class _UserInfoState extends State<UserInfo> {
final listVM = Get.put(HomeViewModel()); final listVM = Get.put(HomeViewModel());
final TextEditingController _controller = TextEditingController(); final TextEditingController _controller = TextEditingController();
late File _selectedImage; File? _selectedImage;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -42,7 +37,17 @@ class _UserInfoState extends State<UserInfo> {
elevation: 0, elevation: 0,
leading: IconButton( leading: IconButton(
onPressed: () { onPressed: () {
Get.back(); // MainTabView
Get.back(); //
//
Future.delayed(Duration(milliseconds: 100), () {
// MainTabView TabController
final mainTabController = Get.find<MainTabView>().getController(context);
if (mainTabController != null) {
mainTabController.index = 3; //
}
});
}, },
icon: Image.asset( icon: Image.asset(
"assets/img/back.png", "assets/img/back.png",
@ -60,77 +65,8 @@ class _UserInfoState extends State<UserInfo> {
body: SingleChildScrollView( body: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
Container( _buildAvatarRow(),
height: 80, _buildNicknameRow(),
color: Colors.white.withOpacity(0.6),
padding: const EdgeInsets.only(left: 48, right: 25),
child: InkWell(
onTap: () {
_bottomSheet(context);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"头像",
style: TextStyle(fontSize: 20),
),
Row(
children: [
Image.network(
AppData().currentAvatar,
width: 64,
height: 64,
),
const SizedBox(
width: 20,
),
Image.asset(
"assets/img/user_next.png",
width: 25,
height: 25,
)
],
)
],
),
),
),
Container(
height: 80,
color: Colors.white.withOpacity(0.6),
padding: const EdgeInsets.only(left: 48, right: 25),
child: InkWell(
onTap: () {
_showNicknameDialog();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"昵称",
style: TextStyle(fontSize: 20),
),
Row(
children: [
Text(
AppData().currentUsername,
style: const TextStyle(fontSize: 20),
),
const SizedBox(
width: 15,
),
Image.asset(
"assets/img/user_next.png",
width: 25,
height: 25,
)
],
)
],
),
),
)
], ],
), ),
), ),
@ -138,68 +74,159 @@ class _UserInfoState extends State<UserInfo> {
); );
} }
//
Widget _buildAvatarRow() {
return Container(
height: 80,
color: Colors.white.withOpacity(0.6),
padding: const EdgeInsets.only(left: 48, right: 25),
child: InkWell(
onTap: () {
_bottomSheet(context);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"头像",
style: TextStyle(fontSize: 20),
),
Row(
children: [
_buildAvatarImage(),
const SizedBox(width: 20),
Image.asset(
"assets/img/user_next.png",
width: 25,
height: 25,
),
],
),
],
),
),
);
}
//
Widget _buildNicknameRow() {
return Container(
height: 80,
color: Colors.white.withOpacity(0.6),
padding: const EdgeInsets.only(left: 48, right: 25),
child: InkWell(
onTap: () {
_showNicknameDialog();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"昵称",
style: TextStyle(fontSize: 20),
),
Row(
children: [
Text(
AppData().currentUsername,
style: const TextStyle(fontSize: 20),
),
const SizedBox(width: 15),
Image.asset(
"assets/img/user_next.png",
width: 25,
height: 25,
),
],
),
],
),
),
);
}
// Widget URL
Widget _buildAvatarImage() {
final avatarPath = AppData().currentAvatar;
if (avatarPath.startsWith('http')) {
return Image.network(
avatarPath,
width: 64,
height: 64,
);
} else {
return Image.file(
File(avatarPath),
width: 64,
height: 64,
);
}
}
Future _bottomSheet(BuildContext context) async { Future _bottomSheet(BuildContext context) async {
final picker = ImagePicker(); final picker = ImagePicker();
await showModalBottomSheet( await showModalBottomSheet(
context: context, context: context,
backgroundColor: Colors.white, backgroundColor: Colors.white,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(30))), borderRadius: BorderRadius.vertical(top: Radius.circular(30))),
builder: (context) => Container( builder: (context) => Container(
height: 132, height: 132,
padding: const EdgeInsets.only(top: 20), padding: const EdgeInsets.only(top: 20),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () async {
Navigator.pop(context); Navigator.pop(context);
final pickedFile = final pickedFile =
await picker.pickImage(source: ImageSource.gallery); await picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) { if (pickedFile != null) {
_selectedImage=File('assets/images/bg.png'); _selectedImage = File(pickedFile.path);
setState(() { setState(() {}); // UI
_selectedImage = File(pickedFile.path);
print(_selectedImage); //
}); await ChangeApiClient().changeHeader(
UniversalBean bean = await ChangeApiClient().changeHeader( Authorization: AppData().currentToken,
Authorization: AppData().currentToken, avatar: _selectedImage!);
avatar: _selectedImage);
GetInfoBean bean1 = await GetInfoApiClient().getInfo( //
Authorization: AppData().currentToken); _updatetouxiang(_selectedImage!.path);
AppData appData = AppData(); //
appData.box.write('currentAvatar', AppData().currentAvatar); await GetInfoApiClient().getInfo(
} Authorization: AppData().currentToken);
}, }
style: ElevatedButton.styleFrom( },
backgroundColor: Colors.transparent, style: ElevatedButton.styleFrom(
elevation: 0, backgroundColor: Colors.transparent,
padding: const EdgeInsets.symmetric(vertical: 12), elevation: 0,
tapTargetSize: MaterialTapTargetSize.shrinkWrap, padding: const EdgeInsets.symmetric(vertical: 12),
), tapTargetSize: MaterialTapTargetSize.shrinkWrap,
child: const Text(
"从相册上传头像",
style: TextStyle(color: Colors.black, fontSize: 18),
),
),
ElevatedButton(
onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xff429482),
padding: const EdgeInsets.symmetric(vertical: 18),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero,
),
),
child: const Text(
"取消",
style: TextStyle(color: Colors.black, fontSize: 18),
),
),
],
), ),
)); child: const Text(
"从相册上传头像",
style: TextStyle(color: Colors.black, fontSize: 18),
),
),
ElevatedButton(
onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xff429482),
padding: const EdgeInsets.symmetric(vertical: 18),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero,
),
),
child: const Text(
"取消",
style: TextStyle(color: Colors.black, fontSize: 18),
),
),
],
),
),
);
} }
void _showNicknameDialog() { void _showNicknameDialog() {
@ -209,12 +236,12 @@ class _UserInfoState extends State<UserInfo> {
return AlertDialog( return AlertDialog(
title: const Center( title: const Center(
child: Text( child: Text(
"修改昵称", "修改昵称",
style: TextStyle(fontSize: 20), style: TextStyle(fontSize: 20),
)), )),
content: TextFieldColor( content: TextField(
controller: _controller, controller: _controller,
hintText: '请输入新昵称', decoration: const InputDecoration(hintText: '请输入新昵称'),
), ),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
@ -225,8 +252,7 @@ class _UserInfoState extends State<UserInfo> {
backgroundColor: const Color(0xff429482), backgroundColor: const Color(0xff429482),
minimumSize: const Size(130, 50), minimumSize: const Size(130, 50),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: borderRadius: BorderRadius.circular(5.0),
BorderRadius.circular(5.0), // Adjust the radius as needed
), ),
), ),
child: const Text( child: const Text(
@ -237,7 +263,7 @@ class _UserInfoState extends State<UserInfo> {
TextButton( TextButton(
onPressed: () async { onPressed: () async {
_updateNickname(); _updateNickname();
UniversalBean bean = await ChangeApiClient().changeName( await ChangeApiClient().changeName(
Authorization: AppData().currentToken, Authorization: AppData().currentToken,
userName: AppData().currentUsername); userName: AppData().currentUsername);
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -246,8 +272,7 @@ class _UserInfoState extends State<UserInfo> {
backgroundColor: const Color(0xff429482), backgroundColor: const Color(0xff429482),
minimumSize: const Size(130, 50), minimumSize: const Size(130, 50),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: borderRadius: BorderRadius.circular(5.0),
BorderRadius.circular(5.0), // Adjust the radius as needed
), ),
), ),
child: const Text( child: const Text(
@ -267,4 +292,14 @@ class _UserInfoState extends State<UserInfo> {
appData.box.write('currentUsername', _controller.text); appData.box.write('currentUsername', _controller.text);
}); });
} }
void _updatetouxiang(String path) {
setState(() {
AppData appData = AppData();
appData.box.write('currentAvatar', path); //
});
}
} }

@ -30,7 +30,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
win32: ^5.1.0 win32: ^5.7.1
flutter_swiper_view: 1.1.8 flutter_swiper_view: 1.1.8
audioplayers: ^5.2.1 audioplayers: ^5.2.1
permission_handler: ^11.0.1 permission_handler: ^11.0.1

Loading…
Cancel
Save