diff --git a/.gitignore b/.gitignore index ae1f183..07e7c4e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,10 @@ .pub/ /build/ +gen/ +bin/ +out/ + # Web related lib/generated_plugin_registrant.dart diff --git a/lib/news/article.dart b/lib/news/article.dart new file mode 100644 index 0000000..4acc3a5 --- /dev/null +++ b/lib/news/article.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; + +class Article { + final int id; + final String type; + final String sport; + final String title; + final String mediumHeadline; + final String url; + final String summary; + final String thumbUrl; + + Article( + this.id, { + this.type, + this.sport, + this.title, + this.mediumHeadline, + this.url, + this.summary, + this.thumbUrl, + }); + + factory Article.fromJson(Map json) { + return Article( + json['id'], + type: json['type'], + sport: json['sport'], + title: json['title'], + mediumHeadline: json['medium_headline'], + url: json['url'], + summary: json['summary'], + thumbUrl: json['thumb']['url'], + ); + } +} + +class ArticleCard extends StatelessWidget { + const ArticleCard({ + Key key, + @required this.article, + this.numCards = 1.25, + }) : super(key: key); + + final Article article; + final double numCards; + + double widthIn(BuildContext context) { + return MediaQuery.of(context).size.width / numCards; + } + + @override + Widget build(BuildContext context) { + var decoration = BoxDecoration( + image: DecorationImage( + image: NetworkImage( + article.thumbUrl, + ), + fit: BoxFit.cover, + ), + ); + + var body = Column( + verticalDirection: VerticalDirection.up, + children: [ + Container( + color: Colors.white, + child: ListTile( + title: Text( + article.mediumHeadline, + overflow: TextOverflow.ellipsis, + maxLines: 2, + ), + ), + ), + ], + ); + + return SizedBox( + width: widthIn(context), + child: Card( + semanticContainer: true, + clipBehavior: Clip.antiAliasWithSaveLayer, + child: Container( + decoration: decoration, + child: body, + ), + ), + ); + } +} diff --git a/lib/news/feed.dart b/lib/news/feed.dart new file mode 100644 index 0000000..3592029 --- /dev/null +++ b/lib/news/feed.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; + +import 'dart:convert'; + +import 'article.dart'; + +class Feed { + static final cobraBase = "https://www.ncaa.com/ncaa/cobra"; + + Future> getPage(int page, {int size = 10}) async { + var url = '$cobraBase/school-content/charlotte,$page,$size'; + http.Response response = await http.get(url); + Iterable articles = json.decode(response.body); + return articles.map((e) => Article.fromJson(e)).toList(); + } +} + +class HorizontalNewsFeed extends StatelessWidget { + final Feed newsFeed; + final Widget title; + final double numCards; + + const HorizontalNewsFeed({ + Key key, + @required this.newsFeed, + @required this.title, + this.numCards = 3.25, + }) : super(key: key); + + double heightIn(BuildContext context) { + return MediaQuery.of(context).size.height / numCards; + } + + @override + Widget build(BuildContext context) { + return SizedBox( + height: heightIn(context), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ListTile( + title: title, + trailing: IconButton( + icon: Icon(Icons.navigate_next), + onPressed: () => Navigator.pushNamed(context, '/Sport'), + ), + ), + Expanded( + child: FutureBuilder( + future: newsFeed.getPage(1), + builder: (ctx, snapshot) { + if (!snapshot.hasData) { + return Center(child: CircularProgressIndicator()); + } else { + List
articles = snapshot.data; + return ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: articles.length, + itemBuilder: (ctx, idx) { + return ArticleCard( + article: articles[idx], + ); + }, + ); + } + }, + ), + ), + ], + ), + ); + } +} diff --git a/lib/placeholder_widget.dart b/lib/placeholder_widget.dart deleted file mode 100644 index 64e35a2..0000000 --- a/lib/placeholder_widget.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter/material.dart'; - -class PlaceholderWidget extends StatelessWidget{ - final Color color; - PlaceholderWidget(this.color,); - - @override - Widget build(BuildContext context) { - return Container( - color: color, - ); - } -} diff --git a/lib/screens/home_widget.dart b/lib/screens/home_widget.dart index efedd67..9a7946d 100644 --- a/lib/screens/home_widget.dart +++ b/lib/screens/home_widget.dart @@ -1,14 +1,10 @@ import 'package:flutter/material.dart'; -import '../placeholder_widget.dart'; +import '../news/feed.dart'; + class Home extends StatelessWidget { - final List _children = [ - PlaceholderWidget(Colors.white), - PlaceholderWidget(Colors.orange), - PlaceholderWidget(Colors.blue), - PlaceholderWidget(Colors.red), - PlaceholderWidget(Colors.black38), - ]; + + final feed = Feed(); //was var not final @override Widget build(BuildContext context) { @@ -17,12 +13,15 @@ class Home extends StatelessWidget { appBar: AppBar( centerTitle: false, title: Text("49ers"), - ), - body: _children[4], - floatingActionButton: FloatingActionButton( backgroundColor: Colors.green, - child: Icon(Icons.arrow_forward_ios), - onPressed: () => Navigator.pushNamed(context, '/Sport'), + ), + body: ListView( + children: [ + HorizontalNewsFeed(newsFeed: feed, title: Text("Basketball")), + HorizontalNewsFeed(newsFeed: feed, title: Text("Soccer")), + HorizontalNewsFeed(newsFeed: feed, title: Text("Football")), + HorizontalNewsFeed(newsFeed: feed, title: Text("Volleyball")), + ], ), drawer: Drawer( child: ListView( @@ -32,7 +31,7 @@ class Home extends StatelessWidget { 'Drawer Header', style: TextStyle( color: Colors.white, - fontSize: 24, + fontSize: 28, ), ), decoration: BoxDecoration( diff --git a/lib/screens/sport.dart b/lib/screens/sport.dart index a56e759..ed6e248 100644 --- a/lib/screens/sport.dart +++ b/lib/screens/sport.dart @@ -1,14 +1,18 @@ import 'package:flutter/material.dart'; +import '../news/feed.dart'; class Sport extends StatelessWidget { final List _curSport = ['FootBall', Colors.green]; final List colorList = [ - const Item("FootBall", Colors.red), + const Item('FootBall', Colors.green), + const Item("BasketBall", Colors.red), const Item("Soccer", Colors.pinkAccent), - const Item('Baseball', Colors.yellow), + const Item('Baseball', Colors.orange), ]; + final feed = Feed(); // was var not final + @override Widget build(BuildContext context) { Item selectedSport; @@ -16,34 +20,76 @@ class Sport extends StatelessWidget { return StatefulBuilder( builder: (context, StateSetter setState) => Scaffold( appBar: AppBar( - title: DropdownButton( - value: selectedSport, - icon: Icon(Icons.arrow_drop_down), - iconSize: 24, - style: TextStyle(color: Colors.black), - iconEnabledColor: Colors.white, - onChanged: (Item value) { - setState(() { - selectedSport = value; - _curSport[0] = selectedSport.name; - _curSport[1] = selectedSport.color; - }); - }, - items: colorList.map>((Item item) { - return DropdownMenuItem( - value: item, - child: SizedBox( - width: 100, - child: Text(item.name), - ), - ); - }).toList(), - ), + centerTitle: false, + title: buildDropdownButton(selectedSport, setState), backgroundColor: _curSport[1], ), - body: Center( - child: Text("Sports Page Body"), + body: ListView( + children: [ + HorizontalNewsFeed(newsFeed: feed, title: Text(_curSport[0])), + HorizontalNewsFeed(newsFeed: feed, title: Text(_curSport[0])), + HorizontalNewsFeed(newsFeed: feed, title: Text(_curSport[0])), + HorizontalNewsFeed(newsFeed: feed, title: Text(_curSport[0])), + ], ), + drawer: Drawer( + child: ListView( + children: [ + DrawerHeader( + child: Text( + 'Drawer Header', + style: TextStyle( + color: Colors.white, + fontSize: 24, + ), + ), + decoration: BoxDecoration( + color: Colors.green, + ), + ), + ListTile( + title: IconButton( + icon: Icon(Icons.home), + onPressed: () => Navigator.pushNamed(context, '/'), + ), + ), + ], + ), + ), + ), + ); + } + + DropdownButtonHideUnderline buildDropdownButton( + Item selectedSport, StateSetter setState) { + return DropdownButtonHideUnderline( + child: DropdownButton( + value: selectedSport, + icon: Icon(Icons.arrow_drop_down), + iconSize: 28, + style: TextStyle(color: Colors.black, fontSize: 28), + iconEnabledColor: Colors.white, + hint: Text( + _curSport[0], + style: TextStyle( + color: Colors.white, fontSize: 28, fontWeight: FontWeight.bold), + ), + onChanged: (Item value) { + setState(() { + selectedSport = value; + _curSport[0] = selectedSport.name; + _curSport[1] = selectedSport.color; + }); + }, + items: colorList.map>((Item item) { + return DropdownMenuItem( + value: item, + child: SizedBox( + child: Text(item.name), + width: 110, + ), + ); + }).toList(), ), ); } diff --git a/pubspec.lock b/pubspec.lock index fcf6763..dd132b2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -74,6 +74,20 @@ packages: description: flutter source: sdk version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.0+4" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.3" image: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 958dc91..5d4a329 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,6 +20,8 @@ dependencies: flutter: sdk: flutter + http: ^0.12.0+4 + # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2