diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 3e01d5e..ac14084 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -4,12 +4,15 @@ import 'package:capstone_hungry_hippos/screens/standing.dart'; import 'package:flutter/material.dart'; import 'package:capstone_hungry_hippos/screens/home_widget.dart'; import 'package:capstone_hungry_hippos/screens/sport.dart'; +import 'package:capstone_hungry_hippos/screens/twitter_widget.dart'; +import 'package:capstone_hungry_hippos/screens/favorites_reorder.dart'; class RouteGenerator { - static Route generateRoute(RouteSettings settings){ - final args = settings.arguments; //This is how we pass arguments and can be used in case + static Route generateRoute(RouteSettings settings) { + final args = settings + .arguments; //This is how we pass arguments and can be used in case - switch (settings.name){ + switch (settings.name) { case '/': return MaterialPageRoute(builder: (_) => Home()); case '/Sport': @@ -21,13 +24,17 @@ class RouteGenerator { return MaterialPageRoute(builder: (_) => Standing()); case '/Chat': return MaterialPageRoute(builder: (_) => Chat()); + case '/Favorites': + return MaterialPageRoute(builder: (_) => FavoritesManager()); + case '/Twitter': + return MaterialPageRoute(builder: (_) => TwitterFeed()); default: return _errorRoute(); } } static Route _errorRoute() { - return MaterialPageRoute(builder: (_){ + return MaterialPageRoute(builder: (_) { return Scaffold( appBar: AppBar( title: Text("Error Page"), diff --git a/lib/screens/favorites_reorder.dart b/lib/screens/favorites_reorder.dart new file mode 100644 index 0000000..3c6ad9a --- /dev/null +++ b/lib/screens/favorites_reorder.dart @@ -0,0 +1,82 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class Favorites { + Future _prefs = SharedPreferences.getInstance(); + + static const List DEFAULT_FAVORITES = [ + 'Football', + 'Basketball', + 'Baseball', + 'Soccer', + 'Tennis', + 'Volleyball' + ]; + + Future> get_favorites() async { + final prefs = await _prefs; + return prefs.getStringList('favorites') ?? DEFAULT_FAVORITES; + } + + Future set_favorites(final List favorites) async { + final prefs = await _prefs; + return await prefs.setStringList('favorites', favorites); + } +} + +class FavoritesManager extends StatefulWidget { + FavoritesManager({Key key}) : super(key: key); + + @override + _FavoritesManagerState createState() => _FavoritesManagerState(); +} + +class _FavoritesManagerState extends State { + Favorites _mgr = Favorites(); + Future> _order; + + @override + void initState() { + _order = _mgr.get_favorites(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: false, + title: Text('Manage Favorites'), + backgroundColor: Colors.green, + ), + body: FutureBuilder>( + future: _order, + builder: (ctx, snap) { + if (snap.connectionState == ConnectionState.waiting) { + return CircularProgressIndicator(); + } else { + var order = snap.data.toList(); + return ReorderableListView( + onReorder: (int oldIdx, int newIdx) { + if (newIdx > oldIdx) newIdx--; + order.insert(newIdx, order.removeAt(oldIdx)); + + setState(() { + _mgr.set_favorites(order); + _order = Future.value(order); + }); + }, + children: order.map((sport) { + return ListTile( + key: Key(sport), + title: Text(sport), + trailing: Icon(Icons.drag_handle), + ); + }).toList(), + ); + } + }, + ), + ); + } +} diff --git a/lib/screens/home_widget.dart b/lib/screens/home_widget.dart index 6c0488d..8af1840 100644 --- a/lib/screens/home_widget.dart +++ b/lib/screens/home_widget.dart @@ -1,15 +1,31 @@ +import 'package:capstone_hungry_hippos/screens/favorites_reorder.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../news/feed.dart'; -class Home extends StatelessWidget { +class Home extends StatefulWidget { + @override + _HomeState createState() => _HomeState(); +} + +class _HomeState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: CustomScrollView( - slivers: [ - _AppBar(), - SliverList(delegate: SliverChildListDelegate(_buildList())), - ], + body: FutureBuilder( + future: _buildList(), + builder: (ctx, snap) { + if (snap.hasData) { + return CustomScrollView( + slivers: [ + _AppBar(), + SliverList(delegate: SliverChildListDelegate(snap.data)), + ], + ); + } else { + return CircularProgressIndicator(); + } + }, ), drawer: Drawer( child: ListView( @@ -32,6 +48,21 @@ class Home extends StatelessWidget { onPressed: () => Navigator.pushNamed(context, '/Chat'), ), ), + ListTile( + title: IconButton( + icon: Icon(Icons.voice_chat), + onPressed: () => Navigator.pushNamed(context, '/Twitter'), + ), + ), + ListTile( + title: IconButton( + icon: Icon(Icons.settings), + onPressed: () => + Navigator.pushNamed(context, '/Favorites').then((e) { + setState(() {}); + }), + ), + ) ], ), ), @@ -50,15 +81,15 @@ class _AppBar extends StatelessWidget { } } -List _buildList() { +Future> _buildList() async { final feed = Feed(); - List listItems = List(); - listItems.add(HorizontalNewsFeed(newsFeed: feed, title: Text("Football"))); - listItems.add(HorizontalNewsFeed(newsFeed: feed, title: Text("Soccer"))); - listItems.add(HorizontalNewsFeed(newsFeed: feed, title: Text("Basketball"))); - listItems.add(HorizontalNewsFeed(newsFeed: feed, title: Text("Volleyball"))); - listItems.add(HorizontalNewsFeed(newsFeed: feed, title: Text("Baseball"))); - listItems.add(HorizontalNewsFeed(newsFeed: feed, title: Text("Softball"))); - listItems.add(HorizontalNewsFeed(newsFeed: feed, title: Text("Tennis"))); - return listItems; + final mgr = Favorites(); + final sports = await mgr.get_favorites(); + + return sports.map((sport) { + return HorizontalNewsFeed( + newsFeed: feed, + title: Text(sport), + ); + }).toList(); } diff --git a/lib/screens/twitter_widget.dart b/lib/screens/twitter_widget.dart new file mode 100644 index 0000000..593cb73 --- /dev/null +++ b/lib/screens/twitter_widget.dart @@ -0,0 +1,65 @@ +import 'package:capstone_hungry_hippos/twitter_assets/twitterFeed.dart'; +import 'package:flutter/material.dart'; +import '../twitter_assets/tweet.dart'; + +class TwitterFeed extends StatelessWidget{ + List fuck = []; + final test = new Tweet(1, "We'll get through this together, Niner Nation. #WeAreAllNiners", "@unccharlotte", "https://pbs.twimg.com/profile_images/1175214096280629249/QC79Xju2_400x400.jpg", "test"); + final test2 = new Tweet(2, "Let's test your UNC Charlotte knowledge...do you know why we became the 49ers? Here's the full history on the pioneering spirit that shaped our trajectory http://bit.ly/UNCC-1949", "@unccharlotte", "https://pbs.twimg.com/profile_images/1175214096280629249/QC79Xju2_400x400.jpg", "test"); + final test3 = new Tweet(3, "Niner Nation means uplifting each other. This 4/9 Day, let's show our students why #WeAreAllNiners by supporting the Student Emergency Relief Fund ️ http://bit.ly/UNCC-SER", "@unccharlotte", "https://pbs.twimg.com/profile_images/1175214096280629249/QC79Xju2_400x400.jpg", "test"); + final test4 = new Tweet(4, "Niner Nation: Chancellor Dubois shares that UNC Charlotte will be able to apply our established parking refund procedures with special considerations for the impact of COVID-19.", "@unccharlotte", "https://pbs.twimg.com/profile_images/1175214096280629249/QC79Xju2_400x400.jpg", "test"); + final test5 = new Tweet(5, "4/9 Day is just for us, Niner Nation. From wherever you are, you're family #WeAreAllNiners", "@unccharlotte", "https://pbs.twimg.com/profile_images/1175214096280629249/QC79Xju2_400x400.jpg", "test"); + final test6= new Tweet(6, "Niner Nation, #49erAlumni Gene Johnson ’73 is getting us excited for 4/9 Day tomorrow! Put on your Niner gear, call your friends and let’s celebrate together virtually \n We’re all in this together! ", "@unccharlotte", "https://pbs.twimg.com/profile_images/1175214096280629249/QC79Xju2_400x400.jpg", "test"); + final test7 = new Tweet(7, "From virtual events to one-on-one sessions with counselors, it's easy to stay connected with @UNCCAdmissions", "@unccharlotte", "https://pbs.twimg.com/profile_images/1175214096280629249/QC79Xju2_400x400.jpg", "test"); + + + @override + Widget build(BuildContext context) { + fuck.add(test); + fuck.add(test2); + fuck.add(test3); + fuck.add(test4); + fuck.add(test5); + fuck.add(test6); + fuck.add(test7); + + return StatefulBuilder( + builder: (context, StateSetter setState) => Scaffold( + appBar: AppBar( + centerTitle: false, + title: Text("49ers Tweets"), + backgroundColor: Colors.green, + ), + body: Container( + color: Colors.black12, + child: + VerticalTwitterFeed(twitterFeed: fuck), + ), + 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, '/'), + ), + ), + ], + ), + ) + )); + } +} + diff --git a/lib/twitter_assets/tweet.dart b/lib/twitter_assets/tweet.dart new file mode 100644 index 0000000..31b571c --- /dev/null +++ b/lib/twitter_assets/tweet.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; + +class Tweet { + final int id; + final String text; + final String userName; + final String userImgUrl; + final String url; + + Tweet( + this.id, + this.text, + this.userName, + this.userImgUrl, + this.url, + ); + + /*factory Tweet.fromJson(Map json) { + return Tweet( + json['id_str'], + text: json['text'], + userName: json['user']['name'], + userImgUrl: json['user']['profile_image_url_https'], + url: json['urls']['expanded_url'], + ); + } + Commenting out till we figure out the API + */ + + + +} + +class TwitterCard extends StatelessWidget{ + + const TwitterCard({ + Key key, + @required this.tweet, + }) : super(key: key); + + final Tweet tweet; + + @override + Widget build(BuildContext context) { + return Card( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 10, horizontal: 0), + child: ListTile( + leading: SizedBox( + height: 150, + width: 75, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + fit: BoxFit.fill, + image: NetworkImage('${tweet.userImgUrl}'), + ), + ), + ), + ), + title: Text('${tweet.userName}'), + subtitle: Text('${tweet.text}'), + ), + ), + ); + } +} + diff --git a/lib/twitter_assets/twitterFeed.dart b/lib/twitter_assets/twitterFeed.dart new file mode 100644 index 0000000..4fdc735 --- /dev/null +++ b/lib/twitter_assets/twitterFeed.dart @@ -0,0 +1,78 @@ +import 'dart:io'; + +import 'package:capstone_hungry_hippos/screens/twitter_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; + +import 'dart:convert'; + +import 'tweet.dart'; + +class TwitterFeedCreation { + static final twitterBase = 'https://api.twitter.com/1.1/search'; + + static final apiKey = 'AFBfOqx8uXIUBZMxAFoQyO3zA'; + static final apiSecret = '48Gp7nczz9SqExorwYuWpA6Nmviuox6Beq83kjH1XtYtunorym'; + + getToken() async { + http.Response response = await http.get('https://api.twitter.com/oauth2/token',); +} + + /*Future> getPage({int size = 10}) async { + var url = '$twitterBase/tweets.json?q=from%3ACharlotteFTBL&result_type=mixed&count=$size'; + http.Response response = await http.get(url, + headers: {'authorization': apiKey,} + ); + Iterable tweets = json.decode(response.body); + return tweets.map((e) => Tweet.fromJson(e)).toList(); + } */ +} + + +class VerticalTwitterFeed extends StatelessWidget{ + + final List twitterFeed; + + const VerticalTwitterFeed({ + Key key, + @required this.twitterFeed, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + + return Container( + child: ListView.builder( + scrollDirection: Axis.vertical, + itemCount: twitterFeed.length, + itemBuilder: (ctx, idx){ + return TwitterCard( + tweet: twitterFeed[idx], + ); + }, + ), + ); + + /* return Container( + child: FutureBuilder( + future: twitterFeed.getPage(), + builder: (ctx, snapshot){ + if(!snapshot.hasData){ + return Center(child: CircularProgressIndicator()); + }else{ + List tweets = snapshot.data; + return ListView.builder( + scrollDirection: Axis.vertical, + itemCount: tweets.length, + itemBuilder: (ctx, idx) { + return TwitterCard( + tweet: tweets[idx], + ); + }, + ); + } + }, + ), + ); */ + } +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index b0162bd..dd1117d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,21 +7,21 @@ packages: name: archive url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.13" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "1.5.2" + version: "1.6.0" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.0" + version: "2.4.1" bloc: dependency: transitive description: @@ -35,21 +35,21 @@ packages: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "2.0.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.3" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.14.11" + version: "1.14.12" convert: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "2.1.4" cupertino_icons: dependency: "direct main" description: @@ -88,6 +88,11 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" http: dependency: "direct main" description: @@ -101,14 +106,14 @@ packages: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.3" + version: "3.1.4" image: dependency: transitive description: name: image url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.12" intl: dependency: transitive description: @@ -171,7 +176,7 @@ packages: name: quiver url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.1.3" rxdart: dependency: transitive description: @@ -179,6 +184,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.23.1" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.6+3" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+6" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2+4" simple_gesture_detector: dependency: transitive description: @@ -197,7 +230,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.5.5" + version: "1.7.0" stack_trace: dependency: transitive description: @@ -239,7 +272,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.11" + version: "0.2.15" typed_data: dependency: transitive description: @@ -260,7 +293,7 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "3.5.0" + version: "3.6.1" sdks: dart: ">=2.6.0 <3.0.0" - flutter: ">=1.12.1" + flutter: ">=1.12.13+hotfix.4 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index e100b59..9f02971 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,7 @@ dependencies: flutter_bloc: ^3.2.0 http: ^0.12.0+4 + shared_preferences: ^0.5.6+3 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons.