-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
๐ Feat/#4 UI,๊ธฐ๋ฅ ๊ตฌํ ์๋ฃ
- Loading branch information
Showing
6 changed files
with
264 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:tj_musical_number_book/models/song.dart'; | ||
import 'package:tj_musical_number_book/services/song_service.dart'; | ||
import 'package:tj_musical_number_book/theme/colors.dart'; | ||
import 'package:tj_musical_number_book/widgets/song_card.dart'; | ||
|
||
class SavedSongsPage extends StatefulWidget { | ||
const SavedSongsPage({super.key}); | ||
|
||
@override | ||
_SavedSongsPageState createState() => _SavedSongsPageState(); | ||
} | ||
|
||
class _SavedSongsPageState extends State<SavedSongsPage> { | ||
late List<Song> savedSongs; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
loadSavedSongs(); | ||
} | ||
|
||
Future<void> loadSavedSongs() async { | ||
savedSongs = await getSavedSongs(); | ||
setState(() {}); | ||
} | ||
|
||
void _onReorder(int oldIndex, int newIndex) { | ||
setState(() { | ||
if (newIndex > oldIndex) { | ||
newIndex -= 1; // ์ธ๋ฑ์ค๊ฐ ํ๋์ฉ ๋ฐ๋ฆฌ๋ ๋ฌธ์ ํด๊ฒฐ | ||
} | ||
final Song movedSong = savedSongs.removeAt(oldIndex); | ||
savedSongs.insert(newIndex, movedSong); | ||
}); | ||
updateSongs(savedSongs); // ์๋ก์ด ์์ ์ ์ฅ | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Scaffold( | ||
appBar: AppBar( | ||
title: const Text('์ค๋ ๋ถ๋ฅผ ๋๋ฒ', | ||
style: TextStyle(color: AppColors.blackMain)), | ||
backgroundColor: AppColors.white, | ||
), | ||
body: FutureBuilder<List<Song>>( | ||
future: getSavedSongs(), // ์ ์ฅ๋ ๋ ธ๋๋ค ๋ถ๋ฌ์ค๊ธฐ | ||
builder: (context, snapshot) { | ||
if (snapshot.connectionState == ConnectionState.waiting) { | ||
return const Center(child: CircularProgressIndicator()); | ||
} | ||
|
||
if (snapshot.hasError) { | ||
return const Center(child: Text('์๋ฌ๊ฐ ๋ฐ์ํ์ต๋๋ค.')); | ||
} | ||
|
||
if (!snapshot.hasData || snapshot.data!.isEmpty) { | ||
return const Center(child: Text('์ ์ฅ๋ ๋ ธ๋๊ฐ ์์ต๋๋ค.')); | ||
} | ||
|
||
savedSongs = snapshot.data!; | ||
|
||
return ReorderableListView( | ||
onReorder: _onReorder, | ||
children: savedSongs | ||
.asMap() | ||
.map((index, song) { | ||
return MapEntry( | ||
index, | ||
SongCard( | ||
key: ValueKey(index), // ์ฌ๊ธฐ์ key๋ฅผ ์ค์ | ||
song: song, | ||
index: index, | ||
onDelete: () async { | ||
await deleteSong(song); | ||
ScaffoldMessenger.of(context).showSnackBar( | ||
SnackBar( | ||
content: Text('"${song.title}" ๋ฒํธ๊ฐ ์ญ์ ๋์์ต๋๋ค.')), | ||
); | ||
loadSavedSongs(); | ||
}, | ||
), | ||
); | ||
}) | ||
.values | ||
.toList(), | ||
); | ||
}, | ||
), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import 'dart:convert'; | ||
import 'package:shared_preferences/shared_preferences.dart'; | ||
import 'package:tj_musical_number_book/models/song.dart'; | ||
|
||
// Song ๊ฐ์ฒด๋ฅผ SharedPreferences์ ์ ์ฅํ๋ ํจ์ | ||
Future<void> saveSong(Song song) async { | ||
final prefs = await SharedPreferences.getInstance(); | ||
List<String> savedSongsJson = prefs.getStringList('saved_songs') ?? []; | ||
|
||
// Song ๊ฐ์ฒด๋ฅผ JSON ๋ฌธ์์ด๋ก ๋ณํ | ||
String songJson = json.encode(song.toJson()); | ||
|
||
savedSongsJson.add(songJson); | ||
await prefs.setStringList('saved_songs', savedSongsJson); | ||
} | ||
|
||
// SharedPreferences์์ ์ ์ฅ๋ Song ๊ฐ์ฒด๋ฅผ ๋ถ๋ฌ์ค๋ ํจ์ | ||
Future<List<Song>> getSavedSongs() async { | ||
final prefs = await SharedPreferences.getInstance(); | ||
|
||
// SharedPreferences์์ ์ ์ฅ๋ ๋ ธ๋ ๋ชฉ๋ก์ ๊ฐ์ ธ์ด | ||
List<String>? songsJson = prefs.getStringList('saved_songs'); | ||
|
||
if (songsJson != null) { | ||
// JSON ๋ฌธ์์ด์ Song ๊ฐ์ฒด ๋ฆฌ์คํธ๋ก ๋ณํ | ||
return songsJson.map((songJson) { | ||
return Song.fromJson(jsonDecode(songJson)); | ||
}).toList(); | ||
} | ||
|
||
return []; | ||
} | ||
|
||
// ๋ ธ๋ ์ญ์ ํ๊ธฐ | ||
Future<void> deleteSong(Song song) async { | ||
SharedPreferences prefs = await SharedPreferences.getInstance(); | ||
List<String>? songsJson = prefs.getStringList('saved_songs'); | ||
|
||
if (songsJson != null) { | ||
// ๋ ธ๋ ๋ฆฌ์คํธ์์ ์ญ์ ํ ๋ ธ๋๋ฅผ ์ ๊ฑฐ | ||
songsJson.removeWhere((songData) { | ||
Song s = Song.fromJson(json.decode(songData)); | ||
return s.tjNumber == song.tjNumber; // tjNumber๋ฅผ ๊ธฐ์ค์ผ๋ก ์ญ์ | ||
}); | ||
|
||
// ์ญ์ ๋ ๋ฆฌ์คํธ๋ฅผ ๋ค์ ์ ์ฅ | ||
await prefs.setStringList('saved_songs', songsJson); | ||
} | ||
} | ||
|
||
// ๋ ธ๋ ์์ ์ ๋ฐ์ดํธ | ||
Future<void> updateSongs(List<Song> songs) async { | ||
// SharedPreferences ์ธ์คํด์ค ๊ฐ์ ธ์ค๊ธฐ | ||
final prefs = await SharedPreferences.getInstance(); | ||
|
||
// Song ๊ฐ์ฒด๋ฅผ JSON ๋ฌธ์์ด๋ก ๋ณํ | ||
List<String> songsJson = | ||
songs.map((song) => jsonEncode(song.toJson())).toList(); | ||
|
||
// SharedPreferences์ ์ ์ฅ | ||
await prefs.setStringList('saved_songs', songsJson); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:tj_musical_number_book/models/song.dart'; | ||
import 'package:tj_musical_number_book/theme/colors.dart'; | ||
|
||
class SongCard extends StatelessWidget { | ||
final Song song; | ||
final int index; | ||
final VoidCallback onDelete; | ||
|
||
const SongCard({ | ||
Key? key, | ||
required this.song, | ||
required this.index, | ||
required this.onDelete, | ||
}) : super(key: key); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Card( | ||
key: ValueKey(index.toString()), | ||
margin: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0), | ||
child: ListTile( | ||
leading: Row( | ||
mainAxisSize: MainAxisSize.min, | ||
children: [ | ||
Text( | ||
'${index + 1}', | ||
style: const TextStyle( | ||
color: AppColors.primary, | ||
fontWeight: FontWeight.bold, | ||
fontSize: 16.0, | ||
), | ||
), | ||
const SizedBox(width: 8.0), | ||
Container( | ||
width: 50.0, | ||
height: 50.0, | ||
decoration: BoxDecoration( | ||
borderRadius: BorderRadius.circular(8.0), | ||
), | ||
child: Stack( | ||
alignment: Alignment.center, | ||
children: [ | ||
ClipRRect( | ||
borderRadius: BorderRadius.circular(8.0), | ||
child: Image.asset( | ||
'./assets/imgs/logo/${song.img.isNotEmpty ? song.img : 'default.png'}', | ||
fit: BoxFit.cover, | ||
), | ||
), | ||
ClipRRect( | ||
borderRadius: BorderRadius.circular(8.0), | ||
child: Container( | ||
color: Colors.black.withOpacity(0.43), | ||
), | ||
), | ||
Text( | ||
song.tjNumber, | ||
style: const TextStyle( | ||
color: AppColors.white, | ||
fontWeight: FontWeight.bold, | ||
fontSize: 11.0, | ||
), | ||
), | ||
], | ||
), | ||
), | ||
], | ||
), | ||
title: Text(song.title, style: const TextStyle(fontWeight: FontWeight.bold)), | ||
subtitle: Text(song.singer), | ||
trailing: IconButton( | ||
icon: const Icon(Icons.remove_circle_outline, color: AppColors.circleBorder), | ||
onPressed: onDelete, | ||
), | ||
), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters