Last active
August 8, 2018 20:08
-
-
Save rodydavis/60184750d00077ff59f275d0bbbbd2df to your computer and use it in GitHub Desktop.
flutter_slidable and flutter_list_drag_and_drop using cloud_firestore in Flutter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:cloud_firestore/cloud_firestore.dart'; | |
import 'package:firebase_analytics/firebase_analytics.dart'; | |
import 'package:firebase_analytics/observer.dart'; | |
import 'package:firebase_auth/firebase_auth.dart'; | |
import 'package:firebase_core/firebase_core.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter/rendering.dart'; | |
import 'package:flutter_firebase_ui/flutter_firebase_ui.dart'; | |
import 'package:flutter_list_drag_and_drop/drag_and_drop_list.dart'; | |
import 'package:flutter_slidable/flutter_slidable.dart'; | |
import 'package:native_widgets/native_widgets.dart'; | |
import 'package:share/share.dart'; | |
import 'package:shared_preferences/shared_preferences.dart'; | |
import 'package:songlist_pro/globals.dart' as globals; | |
import '../models/song.dart'; | |
import '../settings.dart'; | |
import 'song_edit.dart'; | |
import 'song_view.dart'; | |
final FirebaseAuth _auth = FirebaseAuth.instance; | |
// final GoogleSignIn _googleSignIn = new GoogleSignIn(); | |
class SongListPage extends StatefulWidget { | |
SongListPage({ | |
@required this.observer, | |
@required this.analytics, | |
@required this.name, | |
this.songs, | |
this.library, | |
@required this.prefs, | |
this.app, | |
}); | |
final FirebaseApp app; | |
final FirebaseAnalytics analytics; | |
final FirebaseAnalyticsObserver observer; | |
final String name; | |
final CollectionReference songs; | |
final bool library; | |
final SharedPreferences prefs; | |
@override | |
SongListPageState createState() => SongListPageState(songs: songs); | |
} | |
class SongListPageState extends State<SongListPage> { | |
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); | |
StreamSubscription<FirebaseUser> _listener; | |
CollectionReference songs; | |
SongListPageState({this.songs}); | |
// FirebaseUser _currentUser; | |
@override | |
void initState() { | |
super.initState(); | |
_checkCurrentUser(); | |
} | |
@override | |
void dispose() { | |
_listener.cancel(); | |
super.dispose(); | |
} | |
List<DocumentSnapshot> _songs; | |
void initPlatformState() async { | |
try { | |
QuerySnapshot querySnapshot = await songs.orderBy('index').getDocuments(); | |
var list = querySnapshot.documents; | |
setState(() => _songs = list); | |
} catch (e) { | |
setState(() => _songs = []); | |
} | |
_updateIndex(); | |
} | |
Widget buildAppBar(BuildContext context) { | |
return NativeAppBar( | |
title: Text( | |
widget.name, | |
textScaleFactor: widget.library ? 0.8 : 1.0, | |
style: TextStyle( | |
color: globals.isDark ? Colors.white : Colors.black, | |
), | |
), | |
foregroundColor: globals.isDark ? Colors.white : Colors.black, | |
backgroundColor: globals.isDark ? null : Colors.white, | |
leading: widget.library | |
? null | |
: IconButton( | |
icon: Icon(Icons.settings), | |
onPressed: () { | |
// Navigator.pushNamed(context, '/settings'); | |
Navigator | |
.push( | |
context, | |
MaterialPageRoute( | |
builder: (context) => SettingsPage( | |
prefs: widget.prefs, | |
firestore: Firestore.instance, | |
analytics: widget.analytics, | |
observer: widget.observer, | |
), | |
fullscreenDialog: true, | |
), | |
) | |
.then((value) => value != null | |
? setState(() => globals.user = null) | |
: null); | |
}, | |
), | |
// : IconButton( | |
// icon: Icon(Icons.menu), | |
// onPressed: () => _logout(context), | |
// ), | |
actions: widget.library | |
? null | |
: <Widget>[ | |
// _search, | |
IconButton( | |
icon: Icon(Icons.delete_sweep), | |
onPressed: _songs == null || _songs.length == 0 | |
? null | |
: () => _deleteSongs(context), | |
), | |
// IconButton( | |
// icon: Icon(Icons.import_export), | |
// onPressed: null, | |
// ), | |
IconButton( | |
icon: Icon(Icons.share), | |
onPressed: _songs == null || _songs.isEmpty | |
? null | |
: () => _shareSongs(context), | |
), | |
], | |
); | |
} | |
void _shareSongs(BuildContext context) { | |
String _share = ""; | |
for (var document in _songs) { | |
final Song song = Song.fromSnapshot(document); | |
_share += song.toString() + "\n"; | |
} | |
final RenderBox box = context.findRenderObject(); | |
Share.share(_share.trim(), | |
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size); | |
} | |
void _deleteSongs(BuildContext context) { | |
showDialog<Null>( | |
context: context, | |
builder: (BuildContext context) => NativeDialog( | |
title: 'Warning', | |
content: 'Do you want to delete all songs?', | |
actions: <NativeDialogAction>[ | |
NativeDialogAction( | |
text: 'Delete', | |
isDestructive: true, | |
onPressed: () { | |
for (var doc in _songs) | |
songs | |
.document(doc.documentID) | |
.delete() | |
.then((_) => initPlatformState()); | |
Navigator.pop(context); | |
}), | |
NativeDialogAction( | |
text: 'Cancel', | |
isDestructive: false, | |
onPressed: () { | |
Navigator.pop(context); | |
}), | |
], | |
)); | |
} | |
void _updateIndex() { | |
int index = 0; | |
for (var document in _songs) { | |
final DocumentReference doc = songs.document(document.documentID); | |
doc.updateData(<String, dynamic>{'index': index}); | |
index++; | |
} | |
for (int i = 0; i < _songs.length - 1; i++) { | |
final DocumentReference document = songs.document(_songs[i].documentID); | |
document.updateData(<String, dynamic>{'index': i}); | |
} | |
} | |
bool isNumeric(String s) { | |
if (s == null) { | |
return false; | |
} | |
return (double.tryParse(s) ?? null) != null; | |
} | |
@override | |
Widget build(BuildContext context) { | |
if (globals.user == null) { | |
return new SignInScreen( | |
title: "Sign In", | |
// backgroundColor: globals.isDark ? Colors.black : Colors.white, | |
header: new Padding( | |
padding: const EdgeInsets.symmetric(vertical: 16.0), | |
child: new Padding( | |
padding: const EdgeInsets.all(16.0), | |
child: new Text("Choose an Option Below"), | |
), | |
), | |
providers: [ | |
ProvidersTypes.google, | |
ProvidersTypes.facebook, | |
// ProvidersTypes.twitter, | |
// ProvidersTypes.email, | |
// ProvidersTypes.phone, | |
], | |
); | |
} else { | |
return Scaffold( | |
key: _scaffoldKey, | |
appBar: buildAppBar(context), | |
body: Padding( | |
padding: const EdgeInsets.only(top: 0.0), | |
child: _songs == null | |
? NativeLoadingIndicator( | |
text: Text('Loading...'), | |
) | |
: _songs.length == 0 | |
? Center( | |
child: Text('No Songs Found'), | |
) | |
: DragAndDropList<DocumentSnapshot>( | |
_songs, | |
itemBuilder: (BuildContext context, item) { | |
final DocumentSnapshot document = item; | |
final Song song = Song.fromSnapshot(document); | |
var _notation = song?.notation?.toString() ?? ""; | |
if (_notation.contains("--")) _notation = ""; | |
List<Widget> _items = []; | |
if (widget.library && !globals.admin) { | |
_items = null; // Not Admin | |
} else { | |
_items.add(IconSlideAction( | |
caption: 'Edit', | |
color: Colors.black45, | |
icon: Icons.edit, | |
onTap: () => Navigator.push( | |
context, | |
MaterialPageRoute( | |
builder: (context) => SongEditPage( | |
songs: songs, | |
isEditing: true, | |
song: song, | |
title: 'Edit Song', | |
analytics: widget.analytics, | |
observer: widget.observer, | |
firestore: Firestore.instance, | |
prefs: widget.prefs, | |
count: _songs.length, | |
), | |
), | |
), | |
)); | |
_items.add(IconSlideAction( | |
caption: 'Delete', | |
color: Colors.red, | |
icon: Icons.delete, | |
onTap: () { | |
final DocumentReference document = | |
songs.document(song.id); | |
document.delete(); | |
initPlatformState(); | |
}, | |
)); | |
} | |
return Slidable( | |
delegate: SlidableDrawerDelegate(), | |
actionExtentRatio: 0.25, | |
closeOnScroll: true, | |
child: Container( | |
decoration: BoxDecoration( | |
border: Border( | |
bottom: | |
BorderSide(color: Colors.grey[300]))), | |
child: ListTile( | |
title: Text(song.name), | |
subtitle: | |
_notation.isEmpty ? null : Text(_notation), | |
leading: song.number.toString().isEmpty | |
? null | |
: Text(song.number), | |
onTap: () => Navigator.push( | |
context, | |
MaterialPageRoute( | |
builder: (context) => SongDetailsPage( | |
songs: songs, | |
song: song, | |
title: 'Song Details', | |
prefs: widget.prefs, | |
), | |
), | |
)), | |
), | |
actions: <Widget>[ | |
IconSlideAction( | |
caption: 'Share', | |
color: Colors.indigo, | |
icon: Icons.share, | |
onTap: () { | |
String _share = ""; | |
_share = song.toString(); | |
final RenderBox box = | |
context.findRenderObject(); | |
Share.share(_share, | |
sharePositionOrigin: | |
box.localToGlobal(Offset.zero) & | |
box.size); | |
}, | |
), | |
], | |
secondaryActions: _items, | |
); | |
}, | |
onDragFinish: (before, after) { | |
var data = _songs[before]; | |
_songs.removeAt(before); | |
_songs.insert(after, data); | |
_updateIndex(); | |
}, | |
canBeDraggedTo: (one, two) => true, | |
dragElevation: 8.0, | |
), | |
), | |
floatingActionButton: widget.library && !globals.admin | |
? null | |
: FloatingActionButton( | |
heroTag: 'Add Song', | |
onPressed: () { | |
Navigator | |
.push( | |
context, | |
MaterialPageRoute( | |
builder: (context) => SongEditPage( | |
songs: songs, | |
isEditing: false, | |
title: 'New Song', | |
analytics: widget.analytics, | |
observer: widget.observer, | |
firestore: Firestore.instance, | |
prefs: widget.prefs, | |
), | |
fullscreenDialog: true, | |
), | |
) | |
.then((_) => initPlatformState()); | |
}, | |
tooltip: 'Add Song', | |
child: const Icon(Icons.add), | |
), | |
); | |
} | |
} | |
bool checkAdmin() { | |
List _admins = []; //Add Admin UIDs Here | |
for (var item in _admins) { | |
if (globals.user.uid.contains(item)) { | |
globals.admin = true; | |
return true; | |
} | |
} | |
globals.admin = false; | |
return false; | |
} | |
void _checkCurrentUser() async { | |
globals.user = await _auth.currentUser(); | |
globals.user?.getIdToken(refresh: true); | |
_listener = _auth.onAuthStateChanged.listen((FirebaseUser user) { | |
setState(() { | |
globals.user = user; | |
if (globals.user != null) { | |
songs = Firestore.instance | |
.collection('users') | |
.document(globals.user.uid) | |
.collection('songs'); | |
initPlatformState(); | |
} | |
}); | |
}); | |
} | |
// void _logout(BuildContext context) { | |
// setState(() { | |
// FirebaseAuth.instance | |
// .signOut() | |
// .then((_) => Navigator.pushReplacementNamed(context, '/login')); | |
// }); | |
// } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment