Skip to content

Instantly share code, notes, and snippets.

@rodydavis
Last active August 8, 2018 20:08
Show Gist options
  • Save rodydavis/60184750d00077ff59f275d0bbbbd2df to your computer and use it in GitHub Desktop.
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
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