Tải bản đầy đủ

Bao cao java , javafx file doc phần mềm nghe nhạc

ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN

BÁO CÁO ĐỒ ÁN

NGÔN NGỮ LẬP TRÌNH JAVA

ĐỀ TÀI

MEDIA PLAYER
TP. Hồ Chí Minh, 13 tháng 06 năm 2018

Giảng viên hướng dẫn:

ThS. Lê Thanh Trọng

Sinh viên 1

:

Lê Đức Tiến – 15520881


Sinh viên 2
15520851

:

Dương Phước Hải Thọ -

Sinh viên 3
15520787

:

Đỗ Thành Thắng -


NHẬN XÉT CỦA GIÁO VIÊN HƯỚNG DẪN
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
.................................................................................................................................
…..........................., ngày..........tháng..........năm 2018
Người nhận xét
(Ký tên)



LỜI CẢM ƠN
Để có được sự thành công trong môn học và hoàn thành tốt đồ án
cuôi kỳ - ứng dụng “Music Player” chúng em đã nhận được rất nhiều sự
giúp đỡ của các quý thầy cô và bạn bè. Tỏ lòng biết ơn sâu sắc, chúng em
xin chân thành cảm ơn những giảng viên ở khoa Công nghệ phần mềm –
Đại học Công Nghệ Thông Tin đã cùng với tri thức và tâm huyết của mình
truyền đạt vốn kiến thức quý báu cho chúng em trong suốt thời gian học
tập tại trường. Trong học kỳ này, chúng em được tiếp cận với môn học
“Công nghệ phần mềm chuyên sâu” – môn học rất hữu ích đối với sinh
viên khoa Công nghệ phần mềm. Và đặc biệt, quá trình thực hiện đồ án
môn học đã giúp chúng em nâng cao kiến thức, trải nghiệm thực tế việc
xây dựng một website đơn giản và một phần nào có thể giúp đỡ được
nhiều người khi sử dụng sản phẩm của nhóm.
Chúng em xin chân thành cảm ơn thầy Lê Thanh Trọng đã tận tâm
hướng dẫn chúng em qua từng buổi học trên lớp. Nếu không có những lời
hướng dẫn, chỉ bảo của thầy thì chúng em nghĩ quá trình hoàn thiện bài
báo cáo này của chúng em sẽ gặp nhiều vấn đề và khó khăn hơn.
Do kiến thức và khả năng của chúng em còn nhiều hạn chế, vì vậy
không tránh khỏi những thiếu sót, yếu kém. Chúng em rất mong nhận
được những ý kiến đóng góp quý báu của thầy để kiến thức của chúng em
được hoàn thiện hơn.
Sau cùng, chúng em xin kính chúc quý thầy cô ở khoa Công nghệ
phần mềm và thầy Lê Thanh Trọng thật dồi dào sức khỏe, niềm tin để tiếp
tục thực hiện sứ mệnh cao đẹp của mình là truyền đạt kiến thức cho thế
hệ mai sau.
Trân trọng.


MỤC LỤC
MỤC LỤC......................................................................................................i
1.1 Trình chạy nhạc Media Player......................................................ii
1.2 Các chức năng.................................................................................ii
2. PHÂN TÍCH VÀ THIẾT KẾ.........................................................................iii
2.1 Phân tích chức năng.....................................................................iii
2.1.1 Initialize MusicPlayer...................................................................iii
2.1.2 Artists...........................................................................................iii
2.1.3 Album..........................................................................................vii
2.1.4 Songs.........................................................................................viii
2.1.5 Tìm kiếm theo artist, album, tên bài hát......................................x
2.1.6 Pause, Skip, Previous Songs........................................................xi
2.1.7 Playlist, Recently Played Playlist, Most Played Playlist..............xiii
2.1.8 Loop, shuffle, volume của bài hát...............................................xv
2.2 Thiết kế phần mềm.....................................................................xvi
2.2.1 Artists.........................................................................................xvi
2.2.2 Album.......................................................................................xviii
2.2.3 Songs..........................................................................................xx
2.2.4 Tìm kiếm theo artist, album, tên bài hát...................................xxi
2.2.5 Pause, Skip, Previous Songs.....................................................xxii
2.2.6 Playlist, Recently Played Playlist, Most Played Playlist.............xxiii
2.2.7 Loop, shuffle, volume của bài hát.............................................xxv
4.CÀI ĐẶT...............................................................................................xxvi
4.1 Nền tảng công nghệ..................................................................xxvi
5. KẾT LUẬN............................................................................................xxvi
5.1 Kết quả đạt được.......................................................................xxvi
5.2 Hạn chế.......................................................................................xxvi
5.3 Hướng phát triển.......................................................................xxvi
6. PHÂN CÔNG CÔNG VIỆC....................................................................xxvii
7. TÀI LIỆU THAM KHẢO.........................................................................xxvii

1


1. GIỚI THIỆU

1.1 Trình chạy nhạc Media Player
Trong thời đại ngày nay, âm nhạc là một thứ gần như không thể thiếu
đối với con người, thậm chí là động vật. Các ca sĩ, nhạc sĩ … ngày càng có
nhiều cơ hội dễ trình diễn sản phẩm của họ.
Việc quản lí nhiều bài hát, nhiều ca khúc, album của ca sĩ, nhạc sĩ trở
nên cần thiết hơn. Người dùng có thể quản lí một cách thỏa mái và dễ
dàng toàn bộ những bài hát, album hay ca sĩ mà mình yêu thích. Bật phát
nhạc ở desktop offline và tận hưởng cuộc sống.
Từ đó chúng tôi quyết định cho ra phần mềm quản lí media player,
quản lí theo album, bài hát, ca sĩ và playlist. Giúp người dùng dễ dàng
thao tác, giao diện dễ sử dụng và hiệu ứng sống động cùng âm thanh
chất lượng.
1.2 Các chức năng









Phát, dừng và skip bài hát.
Quản lí bài hát dựa vào album, artist, songs.
Quản lí danh sách phát nhạc
Phát nhạc theo tuần tự playlist, lặp bài, suffle playlist nhạc.
Drag bài hát vào phần mềm.
Search theo bài hát, artists, album.
Dựng playlist đã nghe gần đây, playlist được nghe nhiều nhất.
Tự động tải hình ảnh album dựa vào tên album có sẵn.

2


2. PHÂN TÍCH VÀ THIẾT KẾ
2.1 Phân tích chức năng
2.1.1 Initialize MusicPlayer
Bước 1: Kiểm tra file XML có tồn tại, nếu không thì thì khởi tạo nó dựa vào
đường dẫn người dùng đưa vào. Và xuất ra các bài hát được quản lí theo
album, artist, songs, playlist.
Bước 2: checkLibraryXML()
 Tìm đường dẫn đến file library.xml
 Kiểm tra giá trị file trong folder thực và library.xml có giống nhau
không để cập nhật
 Cập nhật library(sử dụng util.XMLEditor)
 Nếu đường dẫn không có file âm nhạc, yêu cầu người dùng import
đường dẫn khác
Bước 3: Nhập danh sách bài hát -> album -> artist, playlist vào class
Library để quản lí.
Bước 4: Khởi tạo danh sách chơi hiện tại để cập nhật bài hát đầu tiên.
Bước 5: Kiểm tra bài hát có tồn tại các hình ảnh ca sĩ, album. Nếu không,
tự động download image từ cloud xuống.
Bước 6: Sau khi đã đưa dữ liệu vào library class. Khởi tạo giao diện fxml
và Main Controller để quản lí event.
2.1.2 Artists
2.1.2.1 selectView(Event e)
Khi người dùng click vào HBox Artists thì sự kiện selectView(Event e)
được gọi.
Hàm HBox eventSource = ((HBox)e.getSource()); Sẽ bắt sự kiện click vào
HBox Artists và tiến hành thêm CSS cho lớp Control trước đó.

3


Hàm loadView(eventSource.getId()); sẽ load SubView tương ứng với HBox
Artists, tạo ra file Aritists.fxml tương ứng.
2.1.2.2 VBox createCell(Artist artist)
Tạo ra các artist-cell dựa vào thông tin như Title, Artist Image,
artistImageProperty của đối tượng artist. Tạo ra VBox dựa vào các thông
tin trên và hiển thị trên TableView.
2.1.2.3 class Artist implements Comparable
class Aritist gồm các thuộc tính như:
private String title;
private ArrayList albums;
private Image artistImage;
private SimpleObjectProperty artistImageProperty;
Tạo constructor cho class Aritist
public Artist(String title, ArrayList albums) {
this.title = title;
this.albums = albums;
this.artistImageProperty = new
SimpleObjectProperty<>(getArtistImage());
}
Trong đó aritistImageProperty sẽ được gán giá trị bằng
getArtistImage();
public Image getArtistImage() {
if (artistImage == null) {
try {
File file = new File(Resources.JAR + "/img/" + this.title + ".jpg");
artistImage = new Image(file.toURI().toURL().toString());
if (artistImage.isError()) {
file.delete();
artistImage = new Image(Resources.IMG + "artistsIcon.png");
}
4


} catch (Exception ex) {
File file = new File(Resources.JAR + "/img/" + this.title + ".jpg");
file.delete();
artistImage = new Image(Resources.IMG + "artistsIcon.png");
}
}
return artistImage;
}
2.1.2.4 Dùng API để download Artist Image
public void downloadArtistImage()
Nếu thư mục imgFolder không tồn tại thì chương trình sẽ tạo ra một
Thread gọi đến hàm downloadArtistImage để dowload AristImage đó.
Thread thread1 = new Thread(() -> {
Library.getArtists().forEach(Artist::downloadArtistImage);
});
2.1.2.5 void showAllSongs(Artist artist, boolean fromMainController)
Duyệt qua tất cả các album của artist, thêm tất cả các bài hát của
album đó vào danh sách bài hát
Thực hiện sắp xếp danh sách các bài hát đó theo thứ tự alphabet.
Hiển thị danh sách bài hát vào khung tableView bài hát.
2.1.2.6 public void play()
Kiểm tra nếu Album đã được chọn thì đưa tất cả các bài hát đó vào
danh sách phát.
Ngược lại nếu chưa có lựa chọn Album thì sẽ lấy tất cả các bài hát
trong tất cả các album của Artist đó.
Play nhạc nếu thuộc tính MusicPlayer.isShuffleActive()==true thì
nhạc sẽ được play ngẫu nhiên, ngược lại sẽ được play theo thứ tự
alphabet.

5


2.1.2.7 Animation
Scroll danh sách Artist:
Animation scrollAnimation = new Transition() {
{
setCycleDuration(Duration.millis(500));

}

protected void interpolate(double frac) {
double vValue = startVvalue + ((finalVvalue - startVvalue) *
frac);
artistListScrollPane.setVvalue(vValue);
}
};
Animation Load danh sách Artist
private Animation albumLoadAnimation = new Transition() {
{
setCycleDuration(Duration.millis(250));
setInterpolator(Interpolator.EASE_BOTH);
}
protected void interpolate(double frac) {
double curHeight = collapsedHeight + (expandedHeight collapsedHeight) * (frac);
songTable.setTranslateY(expandedHeight - curHeight);
songTable.setOpacity(frac);
}
};
Animation Unload danh sách Artist
private Animation albumUnloadAnimation = new Transition() {
{
setCycleDuration(Duration.millis(250));
6


setInterpolator(Interpolator.EASE_BOTH);
}
protected void interpolate(double frac) {
double curHeight = collapsedHeight + (expandedHeight collapsedHeight) * (1 - frac);
songTable.setTranslateY(expandedHeight - curHeight);
songTable.setOpacity(1 - frac);
songTable.setMinHeight(1 - frac);
songTable.setPrefHeight(1 - frac);
}
};
2.1.3 Album
2.1.3.1 selectView(Event e)
Khi người dùng click vào HBox Album thì sự kiện selectView(Event e)
được gọi.
Hàm HBox eventSource = ((HBox)e.getSource()); Sẽ bắt sự kiện
click và tiến hành thêm CSS cho lớp Control trước đó.
Hàm loadView(eventSource.getId()); sẽ load SubView tương ứng với
HBox Albums, tạo ra file Albums.fxml tương ứng.
2.1.3.2 VBox createCell(Album album, int index)
Tạo ra các ô album dựa vào thông tin như Title, artwork của đối
tượng album.
Hiện thị các thông tin trên trên TableView
2.1.3.3 Class Album trong package Model
- Implement interface Comparable
- Gồm các thuộc tính
private int id;
private String title;
7


private String artist;
private Image artwork;
private ArrayList songs;
private SimpleObjectProperty artworkProperty
Constructor
public Album(int id, String title, String artist, ArrayList
songs) {
this.id = id;
this.title = title;
this.artist = artist;
this.songs = songs;
this.artworkProperty = new
SimpleObjectProperty(getArtwork());
}
2.1.3.4 void downloadArtwork()
Tải artwork cho album từ internet theo tên ca sĩ và tên album sử
dụng API audioscrobler.
2.1.3.5 Animation void populateSongTable(VBox cell, Album
selectedAlbum)
Hiện danh sách bài hát (expandAnimation)
Ẩn danh sách bài hát (collapseAnimation)
2.1.4 Songs
2.1.4.1 Song data
Cấu trúc class một bài hát
private int id;

//ID bài hát

private SimpleStringProperty title; //Tên bài hát
private SimpleStringProperty artist; //Tên ca sĩ
private SimpleStringProperty album; //Tên album
private SimpleStringProperty length; //Độ dài bài hát string
private long lengthInSeconds; //Độ dài tính bằng giây
8


private int trackNumber;

//Số track trong album

private int discNumber;

// Số đĩa

private SimpleIntegerProperty playCount; //Số lượng được chơi
private LocalDateTime playDate;

//Ngày chơi

private String location; //Vị trí lưu file
private SimpleBooleanProperty playing; //Có đang chơi
private SimpleBooleanProperty selected; //Bài hát có đang được lựa
chọn
2.1.4.1 SongsController
// Initializes table view scroll bar.
private ScrollBar scrollBar;
// Keeps track of which column is being used to sort table view and in
what order (ascending or descending)
private String currentSortColumn = "titleColumn";
private String currentSortOrder = null;
private Song selectedSong;

Các sự kiện trong TableView ScrollBar
Click Row: Double click row song để bật bài hát được chọn
ControlDown Row: Cho phép chọn nhiều bài hát bằng cách nhấn ctrl, có
thể kéo vào playlist
isShiftDown Row: Cho phép chọn nhiều bài hát bằng phím shift, có thể
kéo vào playlist để chơi nhạc
EnterPress: Chơi bài hát, hàng đang được chọn
2.2.4.3 Chơi bài hát được chọn
public void play() {
Song song = selectedSong;

//Bài hát được chọn

ObservableList songList = tableView.getItems();
9


if (MusicPlayer.isShuffleActive()) { //Kiểm tra có xáo bài
Collections.shuffle(songList);
songList.remove(song);
songList.add(0, song);
}
MusicPlayer.setNowPlayingList(songList);
MusicPlayer.setNowPlaying(song);
MusicPlayer.play();
}

2.1.4.4 Animation Scroll click leter
Override lại interface scroll để có thể thực hiện chức năng sort theo chữ
cái. Thêm hiệu ứng
/**
* Hàm sắp xếp theo ký tự click, sắp xếp và tạo hiệu ứng giữa các row
table
* @param letter
*/
@Override
public void scroll(char letter)
Thêm animation khi nhấn letter
Animation scrollAnimation = new Transition() {
{
setCycleDuration(Duration.millis(500));
}
protected void interpolate(double frac) {
double vValue = startVvalue + ((finalVvalue - startVvalue) *
10


frac);
scrollBar.setValue(vValue);
}
};
2.1.5 Tìm kiếm theo artist, album, tên bài hát
2.1.5.1 search( String searchText)
Khi người dùng nhập kí tự vào searchTextField, hàm này sẽ trả về giá trị
Boolean cho biết có tìm được kết quả nào không và lưu danh sách kết quả
(giới hạn 3 phần tử mỗi mục) vào thuộc tính Search.result.
2.1.5.2 showSearchResults(SearchResult result)
Hiện kết quả tìm kiếm theo từng mục Artist, Album, Song kèm theo
artwork (nếu có). Khi người dụng thay đổi thông tin trên searchTexField,
kết quả sẽ thay đổi. Khi click vào kết quả tìm kiếm sẽ hiện ra view
ArtistMain với các thông tin đang được chọn là kết quả tìm kiếm.
2.1.5.3 Animation
Ô tìm kiếm có 2 animation là hiện khung tìm kiếm
(searchShowAnimation) và ẩn khung tìm kiếm (searchHideAnimation)
2.1.6 Pause, Skip, Previous Songs
2.1.6.1 Pause
Gọi về Application MusicPlayer và kiểm tra nếu đang chơi thì dừng, nếu
dừng thì thì chơi nhạc
public void playPause() {
sideBar.requestFocus();
if (MusicPlayer.isPlaying()) {
MusicPlayer.pause();
} else {
11


MusicPlayer.play();
}
}
2.1.6.1 Skip
Gọi về Application MusicPlayer và nhảy bài.
@FXML
private void skip() {
sideBar.requestFocus();
MusicPlayer.skip();
}
Hàm MusicPlayer.skip()
Nếu bài hát hiện tại nằm trong size của playlist thì chơi bài tiếp theo.
Nếu index không nằm trong size playlist thì kiểm tra có lặp bài hay không.
Nếu không lặp thì quay lại bài đầu tiên trong danh sách.
public static void skip() {
//Nếu nằm bài hát hiện tại nằm trong size của playlist thì chơi bài
tiếp theo
if (nowPlayingIndex < nowPlayingList.size() - 1) {
boolean isPlaying = isPlaying();
mainController.updatePlayPauseIcon(isPlaying);
setNowPlaying(nowPlayingList.get(nowPlayingIndex + 1));
if (isPlaying) {
play();
}
}
//Nếu index không nằm trong size playlist
else if (isLoopActive) {
12


//Kiểm tra có lặp bài hát đang chơi, nếu có chơi lại
boolean isPlaying = isPlaying();
mainController.updatePlayPauseIcon(isPlaying);
nowPlayingIndex = 0;
setNowPlaying(nowPlayingList.get(nowPlayingIndex));
if (isPlaying) {
play();
}
} else {
//Nếu không lặp thì quay lại bài đầu tiên trong ds
mainController.updatePlayPauseIcon(false);
nowPlayingIndex = 0;
setNowPlaying(nowPlayingList.get(nowPlayingIndex));
}
}
2.1.6.3 Previous
Bắt sự kiện khi nhấn nút Previous
Kiểm tra xem timerCouter đã vượt qua bài hát mới hoặc chỉ số bài hát
đang chơi hiện tại bằng 0 hay không. Nếu có thì chơi lại bài hát, seek(0),
ngược lại chơi bài hát tiếp theo.
public static void back() {
if (timerCounter > 20 || nowPlayingIndex == 0) {
mainController.initializeTimeSlider();
seek(0);
} else {
boolean isPlaying = isPlaying();
setNowPlaying(nowPlayingList.get(nowPlayingIndex - 1));
if (isPlaying) {
play();
}
}
13


}
2.1.7 Playlist, Recently Played Playlist, Most Played Playlist
2.1.7.1 Tạo Playlist
Sự kiện click New Playlist
private void newPlaylist()






Khởi tạo và tạo Hbox Playlist có các sự kiện đi kèm:
Kéo bài hát hoặc album vào playlist
Click vào album để truy cập vào Playlist layout
Press Enter để truy cập Playlist layout
Hiệu ứng khi hover vào HBox

2.1.7.1 Playing Playlist
Danh sách những bài hát được lấy từ MusicPlayer.getNowPlayingList() và
hiển thị ra theo kiểu dữ liệu Song

public class NowPlayingController implements Initializable, SubView {
@FXML private TableView tableView;
@FXML private TableColumn playingColumn;
@FXML private TableColumn titleColumn;
@FXML private TableColumn artistColumn;
@FXML private TableColumn albumColumn;
@FXML private TableColumn lengthColumn;
@FXML private TableColumn playsColumn;
private Song selectedSong;
 Khởi tạo và tạo Hbox Playlist có các sự kiện đi kèm:
 Kéo bài hát hoặc album vào playlist
14


 Click vào album để truy cập vào Playlist layout
 Press Enter để truy cập Playlist layout
 Hiệu ứng khi hover vào HBox

2.1.7.3 Recently Played, Most Played Playlist & another Playlist
Hàm khởi tạo toàn bộ playlist và đổ dữ liệu vào controller các playlist.
private void initializePlaylists()







Khởi tạo và tạo Hbox Playlist có các sự kiện đi kèm:
Kéo bài hát hoặc album vào playlist
Click vào album để truy cập vào Playlist layout
Press Enter để truy cập Playlist layout
Hiệu ứng khi hover vào HBox

2.1.8 Loop, shuffle, volume của bài hát
2.1.8.1 Lặp bài
//Sự kiện click nút loop thì thêm css màu và chuyển cờ loop ở
MusicPlayer
PseudoClass active = PseudoClass.getPseudoClass("active");
loopButton.setOnMouseClicked(x -> {
sideBar.requestFocus();
MusicPlayer.toggleLoop();
loopButton.pseudoClassStateChanged(active,
MusicPlayer.isLoopActive());
});
2.1.8.2 Xáo trộn bài
//Sự kiện click nút shuffle thì thêm css màu và chuyển cờ shuffle ở
MusicPlayer
shuffleButton.setOnMouseClicked(x -> {
sideBar.requestFocus();
MusicPlayer.toggleShuffle();
shuffleButton.pseudoClassStateChanged(active,
15


MusicPlayer.isShuffleActive());
});
2.1.8.3 Volume
Tạo VolumePopup
private void createVolumePopup()
Animation khi mở volumePopup
popup.focusedProperty().addListener((x, wasFocused, isFocused)
-> {
if (wasFocused && !isFocused) {
volumeHideAnimation.play();
}
});

Xử lí sao khi hiệu ứng kết thúc
volumeHideAnimation.setOnFinished(x -> popup.hide());
popup.show();
popup.hide();
volumePopup = popup;

2.2 Thiết kế phần mềm

16


2.2.1 Artists
2.1.1.1 Giao diện Artists

2.1.1.2 Giao diện Artist Main

17


STT Tên biến
1
HboxArtist

Kiểu biến
customize từ

Mô tả
Load viewLoad Artist

2

Pane và lable
subViewRo BroderPane

Chứa listView để chức các

3
4

ot
artistList
albumList

ListView
ListView

ArtistCell
Hiện danh sách các Artist
Hiện danh sách các Album tương

TableView

ứng với Artist
Hiện danh sách các bài hát

5

songTable

2.2.2 Album

STT Tên biến

Loại controller

Chức năng
Khi người dung bấm
vào HBox Album,

1

Chọn xem theo
album

HBox

layout bên phải sẽ
hiển thị danh sách các
album.

2

albumImageView

ImageView

Khi người dung bấm
18


hình của album, bên
dưới sẽ hiển thị chi tiết
các bài hát của album,
nếu người dung bấm
lần nữa sẽ tắt hiện thị
chi tiết album.
3

STT
4

Tên album

Tên biến
X

Label

Loại controller
Album Controller

Hiển thị tên album

Chức năng
Hiển thị
Artwork và

5
6

Tên ca sĩ
Tên album

Label

tên album
Hiển thị tên

Label

ca sĩ
Hiển thị tên
album
19


7

titleColumn

ControlPanelTableCell

Tên bài hát

8

lengthColumn

ClippedTableCell

Độ dài bài

9

playsColumn

ClippedTableCell

hát
Số lần chơi

10

playingColumn

PlayingTableCell

Cờ bài đang
được phát

20


2.2.3 Songs

STT
1

Tên biến
letterBox

Loại controller
Hbox + Label

Chức năng
Hiển thị và
search theo

2

playingColumn

PlayingTableCell

ký tự
Cờ bài đang

3

titleColumn

ControlPanelTableCell

được phát
Tên bài hát

4

artistColumn

ClippedTableCell

Tên ca sỹ

5

albumColumn

ClippedTableCell

Tên album

6

lengthColumn

ClippedTableCell

Độ dài bài

7

playsColumn

ClippedTableCell

hát
Số lần chơi

21


2.2.4 Tìm kiếm theo artist, album, tên bài hát

Sau khi nhập vào ô tìm kiếm

22


Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay

×