Explorar o código

feat: albums list

Fela Maslen %!s(int64=4) %!d(string=hai) anos
pai
achega
0f4b20fe00

+ 88 - 0
gmus-mobile/lib/components/albums.dart

@@ -0,0 +1,88 @@
+import 'dart:convert';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:http/http.dart' as http;
+
+import '../config.dart';
+
+import './spinner.dart';
+
+class Albums extends StatefulWidget {
+  final String artist;
+  final void Function(String, String) onSelect;
+
+  Albums({
+    @required this.artist,
+    @required this.onSelect,
+  });
+
+  @override
+  _AlbumsWidgetState createState() => _AlbumsWidgetState(artist: this.artist, onSelect: this.onSelect);
+}
+
+Future<List<String>> fetchAlbums(String artist) async {
+  final response = await http.get(Uri.https(config['apiUrl'], '/albums', {
+    'artist': artist,
+  }));
+
+  if (response.statusCode == 200) {
+    return List<String>.from(jsonDecode(response.body)['albums']);
+  } else {
+    throw Exception('Failed to load albums');
+  }
+}
+
+class _AlbumsWidgetState extends State<Albums> {
+  final String artist;
+  Future<List<String>> albums;
+
+  final void Function(String, String) onSelect;
+
+  _AlbumsWidgetState({
+    @required this.artist,
+    @required this.onSelect,
+  });
+
+  @override
+  void initState() {
+    super.initState();
+    albums = fetchAlbums(this.artist);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return FutureBuilder<List<String>>(
+      future: albums,
+      builder: (context, snapshot) {
+        if (snapshot.hasData) {
+          return ListView(
+            padding: EdgeInsets.only(left: 8, right: 8),
+            children: snapshot.data.map((album) => Container(
+              height: 40,
+              color: Colors.white,
+              child: Align(
+                alignment: Alignment.centerLeft,
+                child: TextButton(
+                  child: Text(album.length == 0 ? 'Unknown album' : album),
+                  onPressed: () {
+                    onSelect(artist, album);
+                  },
+                  style: TextButton.styleFrom(
+                    textStyle: TextStyle(fontSize: 18, fontStyle: FontStyle.normal),
+                    primary: Colors.black,
+                  ),
+                ),
+              ),
+            )).toList(),
+          );
+        }
+        if (snapshot.hasError) {
+          return Text("${snapshot.error}");
+        }
+
+        return CenterSpinner();
+      },
+    );
+  }
+}

+ 33 - 8
gmus-mobile/lib/components/artists.dart

@@ -4,10 +4,17 @@ import 'package:flutter/material.dart';
 import 'package:http/http.dart' as http;
 
 import '../config.dart';
+import './spinner.dart';
 
 class Artists extends StatefulWidget {
+  final void Function(String) onSelect;
+
+  Artists({
+    @required this.onSelect,
+  });
+
   @override
-  _ArtistsWidgetState createState() => _ArtistsWidgetState();
+  _ArtistsWidgetState createState() => _ArtistsWidgetState(onSelect: this.onSelect);
 }
 
 Future<List<String>> fetchArtists() async {
@@ -23,6 +30,12 @@ Future<List<String>> fetchArtists() async {
 class _ArtistsWidgetState extends State<Artists> {
   Future<List<String>> artists;
 
+  final void Function(String) onSelect;
+
+  _ArtistsWidgetState({
+    @required this.onSelect,
+  });
+
   @override
   void initState() {
     super.initState();
@@ -37,12 +50,24 @@ class _ArtistsWidgetState extends State<Artists> {
         if (snapshot.hasData) {
           return ListView(
             padding: EdgeInsets.only(left: 8, right: 8),
-            children: snapshot.data.map((artist) => Container(
-              height: 32,
-              color: Colors.white,
-              child: Align(
-                alignment: Alignment.centerLeft,
-                child: Text(artist.length == 0 ? 'Unknown artist' : artist),
+            children: snapshot.data.map((artist) => InkWell(
+              onTap: () {
+                onSelect(artist);
+              },
+              child: SizedBox(
+                height: 40,
+                width: MediaQuery.of(context).size.width,
+                child: Container(
+                  child: Align(
+                    alignment: Alignment.centerLeft,
+                    child: Text(
+                      artist.length == 0 ? 'Unknown artist' : artist,
+                      style: TextStyle(
+                        fontSize: 18,
+                      ),
+                    ),
+                  ),
+                ),
               ),
             )).toList(),
           );
@@ -51,7 +76,7 @@ class _ArtistsWidgetState extends State<Artists> {
           return Text("${snapshot.error}");
         }
 
-        return CircularProgressIndicator();
+        return CenterSpinner();
       },
     );
   }

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

@@ -0,0 +1,50 @@
+import 'package:flutter/widgets.dart';
+import 'package:get/get.dart';
+import 'package:gmus_mobile/components/albums.dart';
+
+import './artists.dart';
+
+class Browser extends StatefulWidget {
+  @override
+  _BrowserWidgetState createState() => _BrowserWidgetState();
+}
+
+class _BrowserWidgetState extends State<Browser> {
+  PageController pageController = PageController();
+
+  void _jumpToPage(int page) {
+    pageController.animateToPage(page, duration: Duration(milliseconds: 500), curve: Curves.ease);
+  }
+  void _jumpToAlbums() {
+    this._jumpToPage(1);
+  }
+  void _jumpToSongs() {
+    this._jumpToPage(2);
+  }
+
+  RxString selectedArtist;
+  RxString selectedAlbum;
+
+  void onSelectArtist(String artist) {
+    print("onSelectArtist called $artist");
+    this.selectedArtist = artist.obs;
+    this._jumpToAlbums();
+  }
+
+  void onSelectAlbum(String artist, String album) {
+    this.selectedAlbum = album.obs;
+    this._jumpToSongs();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return PageView(
+      controller: pageController,
+      children: <Widget>[
+        Artists(onSelect: this.onSelectArtist),
+        Obx(() => Albums(artist: this.selectedArtist.value, onSelect: this.onSelectAlbum)),
+      ],
+      pageSnapping: true,
+    );
+  }
+}

+ 15 - 0
gmus-mobile/lib/components/spinner.dart

@@ -0,0 +1,15 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+
+class CenterSpinner extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return Center(
+      child: SizedBox(
+        child: CircularProgressIndicator(),
+        height: 64,
+        width: 64,
+      ),
+    );
+  }
+}

+ 2 - 2
gmus-mobile/lib/components/ui.dart

@@ -3,7 +3,7 @@ import 'package:get/get.dart';
 
 import '../controller.dart';
 
-import './artists.dart';
+import './browser.dart';
 import './player.dart';
 
 // Main UI once identified
@@ -13,7 +13,7 @@ class UI extends StatelessWidget {
   Widget build(BuildContext context) {
     return Column(
       children: [
-        Expanded(child: Artists()),
+        Expanded(child: Browser()),
         GmusPlayer(),
       ],
     );

+ 5 - 4
gmus-mobile/lib/main.dart

@@ -3,11 +3,12 @@ import 'dart:io';
 import 'package:flutter_dotenv/flutter_dotenv.dart' as DotEnv;
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
-import 'package:gmus_mobile/components/content.dart';
-import 'package:gmus_mobile/components/status.dart';
 
-import 'config.dart';
-import 'controller.dart';
+import './config.dart';
+import './controller.dart';
+
+import './components/content.dart';
+import './components/status.dart';
 
 class Gmus extends StatelessWidget {
   @override