ソースを参照

feat: songs list

Fela Maslen 4 年 前
コミット
63dac1a492

+ 7 - 2
gmus-mobile/lib/components/albums.dart

@@ -33,6 +33,8 @@ Future<List<String>> fetchAlbums(String artist) async {
   }
 }
 
+const allAlbums = 'All albums';
+
 class _AlbumsWidgetState extends State<Albums> {
   final String artist;
   Future<List<String>> albums;
@@ -56,9 +58,12 @@ class _AlbumsWidgetState extends State<Albums> {
       future: albums,
       builder: (context, snapshot) {
         if (snapshot.hasData) {
+          List<String> albumsWithAll = snapshot.data.sublist(0);
+          albumsWithAll.insert(0, allAlbums);
+          
           return ListView(
             padding: EdgeInsets.only(left: 8, right: 8),
-            children: snapshot.data.map((album) => Container(
+            children: albumsWithAll.map((album) => Container(
               height: 40,
               color: Colors.white,
               child: Align(
@@ -66,7 +71,7 @@ class _AlbumsWidgetState extends State<Albums> {
                 child: TextButton(
                   child: Text(album.length == 0 ? 'Unknown album' : album),
                   onPressed: () {
-                    onSelect(artist, album);
+                    onSelect(artist, album == allAlbums ? null : album);
                   },
                   style: TextButton.styleFrom(
                     textStyle: TextStyle(fontSize: 18, fontStyle: FontStyle.normal),

+ 10 - 0
gmus-mobile/lib/components/browser.dart

@@ -1,6 +1,7 @@
 import 'package:flutter/widgets.dart';
 import 'package:get/get.dart';
 import 'package:gmus_mobile/components/albums.dart';
+import 'package:gmus_mobile/components/songs.dart';
 
 import './artists.dart';
 
@@ -36,6 +37,10 @@ class _BrowserWidgetState extends State<Browser> {
     this._jumpToSongs();
   }
 
+  void onSelectSong(int songId) {
+    print("Selecting song ID $songId");
+  }
+
   @override
   Widget build(BuildContext context) {
     return PageView(
@@ -43,6 +48,11 @@ class _BrowserWidgetState extends State<Browser> {
       children: <Widget>[
         Artists(onSelect: this.onSelectArtist),
         Obx(() => Albums(artist: this.selectedArtist.value, onSelect: this.onSelectAlbum)),
+        Obx(() => Songs(
+          artist: this.selectedArtist.value,
+          album: this.selectedAlbum.value,
+          onSelect: this.onSelectSong,
+        )),
       ],
       pageSnapping: true,
     );

+ 106 - 0
gmus-mobile/lib/components/songs.dart

@@ -0,0 +1,106 @@
+import 'dart:convert';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:http/http.dart' as http;
+
+import '../config.dart';
+import '../types/song.dart';
+
+import './spinner.dart';
+
+class Songs extends StatefulWidget {
+  final String artist;
+  final String album;
+  final void Function(int) onSelect;
+
+  Songs({
+    @required this.artist, // can be an empty string
+    @required this.album, // can be an empty string
+    @required this.onSelect,
+  });
+
+  @override
+  _SongsWidgetState createState() => _SongsWidgetState(
+      artist: this.artist,
+      album: this.album,
+      onSelect: this.onSelect,
+    );
+}
+
+Future<List<Song>> fetchSongs(String artist) async {
+  final response = await http.get(Uri.https(config['apiUrl'], '/songs', {
+    'artist': artist,
+  }));
+
+  if (response.statusCode != 200) {
+    throw Exception('Failed to load songs');
+  }
+
+  List<Song> songs = [];
+  var responseJson = jsonDecode(response.body)['songs'];
+  for (var i = 0; i < responseJson.length; i++) {
+    songs.add(Song.fromJson(responseJson[i]));
+  }
+  return songs;
+}
+
+class _SongsWidgetState extends State<Songs> {
+  final String artist;
+  final String album;
+  Future<List<Song>> songs;
+
+  final void Function(int) onSelect;
+
+  _SongsWidgetState({
+    @required this.artist,
+    @required this.album,
+    @required this.onSelect,
+  });
+
+  @override
+  void initState() {
+    super.initState();
+    songs = fetchSongs(this.artist);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return FutureBuilder<List<Song>>(
+      future: songs,
+      builder: (context, snapshot) {
+        if (snapshot.hasData) {
+          var filteredAlbums = this.album == null
+            ? snapshot.data
+            : snapshot.data.where((song) => song.album == this.album);
+
+          return ListView(
+            padding: EdgeInsets.only(left: 8, right: 8),
+            children: filteredAlbums.map<Widget>((song) => Container(
+              height: 40,
+              color: Colors.white,
+              child: Align(
+                alignment: Alignment.centerLeft,
+                child: TextButton(
+                  child: Text("${song.track} - ${song.title.length == 0 ? 'Untitled Track' : song.title}"),
+                  onPressed: () {
+                    onSelect(song.id);
+                  },
+                  style: TextButton.styleFrom(
+                    textStyle: TextStyle(fontSize: 18, fontStyle: FontStyle.normal),
+                    primary: Colors.black,
+                  ),
+                ),
+              ),
+            )).toList(),
+          );
+        }
+        if (snapshot.hasError) {
+          return Text("${snapshot.error}");
+        }
+
+        return CenterSpinner();
+      },
+    );
+  }
+}

+ 21 - 0
gmus-mobile/lib/types/song.dart

@@ -0,0 +1,21 @@
+class Song {
+  int id;
+  int track;
+  String title;
+  String artist;
+  String album;
+  int time;
+
+  Song({this.id, this.track, this.title, this.artist, this.album, this.time});
+
+  factory Song.fromJson(Map<String, dynamic> json) {
+    return Song(
+        id: json['id'],
+        track: json['track'],
+        title: json['title'],
+        artist: json['artist'],
+        album: json['album'],
+        time: json['time'],
+      );
+  }
+}