Commit 23fba931 authored by Thiago Nitschke's avatar Thiago Nitschke
Browse files

Merge branch 'release/agesPresentation'

parents a1846cd4 46128ec9
Showing with 423 additions and 105 deletions
+423 -105
assets/sinc_help.png

13.7 KB

......@@ -2,11 +2,15 @@ import 'package:flutter/material.dart';
class TextInputWidget extends StatefulWidget {
TextInputWidget(
{@required this.title, @required this.value, @required this.func});
{@required this.title,
@required this.value,
@required this.func,
this.hint});
final String title;
final Function func;
final String value;
final String hint;
@override
_TextInputWidgetState createState() => _TextInputWidgetState();
......@@ -85,7 +89,7 @@ class _TextInputWidgetState extends State<TextInputWidget> {
fillColor: Color(0xFF2F2F2F),
filled: true,
alignLabelWithHint: true,
hintText: widget.title + ' da disciplina',
hintText: widget.hint ?? widget.title + ' da disciplina',
hintStyle: TextStyle(
fontSize: 16, height: 1, color: Colors.white.withAlpha(0x99)),
border: UnderlineInputBorder(
......
import 'package:cupertino/pages/configuration_screen.dart';
import 'package:cupertino/pages/course_list.dart';
import 'package:cupertino/pages/login_screen.dart';
import 'package:cupertino/pages/synchronization_list.dart';
......@@ -39,18 +40,7 @@ class _MyAppState extends State<MyApp> {
break;
case 2:
showNavigationBar = true;
currentPage = Scaffold(
appBar: AppBar(
title: Text('Configurações'),
centerTitle: false,
),
body: Center(
child: Text(
'Em construção!',
style: TextStyle(fontSize: 40.0),
),
),
);
currentPage = ConfigurationScreen(update: update);
break;
}
if (Auth.loggedUserId == null) {
......@@ -64,6 +54,7 @@ class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark().copyWith(
primaryColor: Colors.deepPurple,
cursorColor: Colors.deepPurple,
......@@ -82,13 +73,12 @@ class _MyAppState extends State<MyApp> {
scaffoldBackgroundColor: Color(0xFF292929),
appBarTheme: AppBarTheme().copyWith(color: Color(0xFF121212))),
home: Scaffold(
body: getCurrentPage(currentIndex),
bottomNavigationBar: showNavigationBar ? myBottomNavBar() : null
),
body: getCurrentPage(currentIndex),
bottomNavigationBar: showNavigationBar ? myBottomNavBar() : null),
);
}
Widget myBottomNavBar(){
Widget myBottomNavBar() {
return BottomNavigationBar(
onTap: (index) {
setState(() {
......
import 'package:cupertino/services/auth.dart';
import 'package:flutter/material.dart';
class ConfigurationScreen extends StatefulWidget {
final VoidCallback update;
ConfigurationScreen({@required this.update});
@override
_ConfigurationScreenState createState() => _ConfigurationScreenState();
}
class _ConfigurationScreenState extends State<ConfigurationScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Configurações'),
centerTitle: false,
),
body: ListView(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.symmetric(vertical: 8.0),
children: [
ListTile(
contentPadding: EdgeInsets.all(16),
tileColor: Colors.black26,
dense: false,
visualDensity: VisualDensity.comfortable,
title: SizedBox(
height: 35,
child: Text(
'Conta de usuário',
style: TextStyle(
color: Colors.deepPurpleAccent.shade100,
fontSize: 19.0,
fontWeight: FontWeight.w500),
),
),
subtitle: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.all(8.0),
child: Icon(Icons.perm_identity_outlined,
color: Colors.grey),
),
Text(
Auth.loggedUserName ?? 'Não cadastrado',
maxLines: 1,
style: TextStyle(
fontSize: 17.0,
color: Colors.grey.shade300,
textBaseline: TextBaseline.alphabetic),
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.all(8.0),
child: Icon(
Icons.email_outlined,
color: Colors.grey,
),
),
Text(
Auth.loggedUserEmail ?? 'fulano@gmail.com',
maxLines: 1,
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 17.0,
color: Colors.grey.shade300,
textBaseline: TextBaseline.alphabetic),
),
],
),
],
),
trailing: Icon(
Icons.account_circle_rounded,
color: Colors.deepPurpleAccent,
size: 32,
),
)
],
),
backgroundColor: Colors.black26,
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: FloatingActionButton.extended(
elevation: 5,
backgroundColor: Colors.deepPurpleAccent.shade100,
icon: Icon(Icons.logout, color: Colors.black),
label: Text('LOGOUT'),
onPressed: () async {
await Auth().logout();
setState(() {
widget.update();
});
}),
);
}
}
......@@ -110,6 +110,12 @@ class _CoursesListState extends State<CoursesList> {
@override
Widget build(BuildContext context) {
// SchedulerBinding.instance.addPostFrameCallback((_) => setState(() {
// semestersSections.forEach((semester) {
// print(semester.expanded);
// semester.expanded = true;
// });
// }));
return Scaffold(
appBar: AppBar(
title: Text('Disciplinas'),
......@@ -177,12 +183,17 @@ class _CoursesListState extends State<CoursesList> {
});
SemesterSection newSection = SemesterSection(
expanded: true,
expanded: false,
header: newSemester.name,
items: newSemester.courses);
semestersSections.add(newSection);
}
// setState(() {
// });
}
return ExpandableListView(
builder:
SliverExpandableChildDelegate<Course, SemesterSection>(
......
......@@ -49,10 +49,9 @@ class _CourseRegistrationState extends State<CourseRegistration> {
name = widget.course.name;
code = widget.course.code;
schedule = widget.course.schedule;
print('SCHEDULE: $schedule');
selectedColor = widget.course.color;
semester = widget.semesters[
1]; //Por enquanto semestre esta hard coded pois essa informação não vem como parametro para a tela de edição
// Placeholder to avoid course edit from advancing
semester = Semester(name: null, startDate: null, endDate: null);
} else {
name = null;
code = null;
......@@ -62,20 +61,37 @@ class _CourseRegistrationState extends State<CourseRegistration> {
}
}
void _getAlertDialog() {
List<Widget> actions = [
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
)
];
void _getAlertDialog(bool confirmacao) async {
Text title;
Text content;
List<Widget> actions;
Text title = Text('Tentativa incorreta');
Text content = Text('Por favor, preencha todos os campos.');
if (confirmacao) {
actions = [
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
)
];
showDialog(
title = Text('Cadastro efetuado!');
content = Text('Cadastro foi confirmado com sucesso.');
} else {
actions = [
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
)
];
title = Text('Tentativa incorreta!');
content = Text('Por favor, preencha todos os campos corretamente.');
}
await showDialog(
context: context,
builder: (BuildContext context) {
if (Platform.isIOS)
......@@ -85,6 +101,7 @@ class _CourseRegistrationState extends State<CourseRegistration> {
return AlertDialog(
title: title, content: content, actions: actions);
});
if (confirmacao) Navigator.pop(context);
}
Future<void> checkAdd() async {
......@@ -99,7 +116,7 @@ class _CourseRegistrationState extends State<CourseRegistration> {
semester == '' ||
selectedColor == '' ||
code == '') {
_getAlertDialog();
_getAlertDialog(false);
} else {
Course disc;
if (widget.course != null) {
......@@ -126,7 +143,7 @@ class _CourseRegistrationState extends State<CourseRegistration> {
});
widget.update();
}
Navigator.pop(context);
_getAlertDialog(true);
}
}
......
......@@ -27,20 +27,37 @@ class _SemesterRegistrationState extends State<SemesterRegistration> {
end = null;
}
void _getAlertDialog() {
List<Widget> actions = [
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
)
];
void _getAlertDialog(bool confirmacao) async {
Text title;
Text content;
List<Widget> actions;
Text title = Text('Tentativa incorreta');
Text content = Text('Por favor, preencha todos os campos.');
if (confirmacao) {
actions = [
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
)
];
showDialog(
title = Text('Cadastro efetuado!');
content = Text('Cadastro foi confirmado com sucesso.');
} else {
actions = [
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
)
];
title = Text('Tentativa incorreta!');
content = Text('Por favor, preencha todos os campos corretamente.');
}
await showDialog(
context: context,
builder: (BuildContext context) {
if (Platform.isIOS)
......@@ -50,15 +67,16 @@ class _SemesterRegistrationState extends State<SemesterRegistration> {
return AlertDialog(
title: title, content: content, actions: actions);
});
if (confirmacao) Navigator.pop(context);
}
void checkAdd() {
if (name == null || begin == null || end == null || name == "") {
_getAlertDialog();
_getAlertDialog(false);
} else {
Semester semester = Semester(name: name, startDate: begin, endDate: end);
InsertData().insertSemester(semester);
Navigator.pop(context);
_getAlertDialog(true);
}
}
......@@ -81,6 +99,7 @@ class _SemesterRegistrationState extends State<SemesterRegistration> {
TextInputWidget(
title: 'Nome',
value: name,
hint: 'Nome do semestre',
func: (value) => {this.name = value}),
BasicDateField(
func: (value) => {
......
......@@ -41,6 +41,11 @@ class _SynchronizationListState extends State<SynchronizationList> {
appBar: AppBar(
title: Text("Sincronização"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.info, color: Colors.white),
onPressed: () {
Navigator.of(context).push(TutorialOverlay());
}),
IconButton(
icon: Icon(Icons.sync, color: Colors.white),
onPressed: () {
......@@ -55,24 +60,50 @@ class _SynchronizationListState extends State<SynchronizationList> {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(
Widget cancelButton = FlatButton(
child: Text("Ok"),
onPressed: () => Navigator.pop(context),
);
AlertDialog alert = AlertDialog(
title: Text("Erro ao buscar dados do banco"),
content: Text(
'Erro ao buscar dados do banco. Confira se sua conexão está ativa.',
style: TextStyle(fontSize: 32.0),
),
));
actions: [
cancelButton,
],
);
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return alert;
});
return _createBackground();
}
if (!snapshot.hasData) {
return Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(
Widget cancelButton = FlatButton(
child: Text("Ok"),
onPressed: () => Navigator.pop(context),
);
AlertDialog alert = AlertDialog(
title: Text("Erro ao buscar dados do banco"),
content: Text(
'Não existem dados cadastrados. Adicione um novo semestre e/ou disciplina.',
style: TextStyle(fontSize: 32.0),
),
));
actions: [
cancelButton,
],
);
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return alert;
});
return _createBackground();
}
if (semesters.length < snapshot.data.documents.length) {
for (DocumentSnapshot semesterData in snapshot.data.documents) {
......@@ -88,8 +119,7 @@ class _SynchronizationListState extends State<SynchronizationList> {
newCourse.schedule = [];
newCourse.scheduleReference.getDocuments().then((schedule) {
schedule.documents.forEach((scheduleData) {
Schedule newSchedule =
Schedule.fromSnapshot(scheduleData);
Schedule newSchedule = Schedule.fromSnapshot(scheduleData);
newCourse.schedule.add(newSchedule);
});
});
......@@ -102,6 +132,34 @@ class _SynchronizationListState extends State<SynchronizationList> {
);
}
_createBackground(){
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Padding(
padding: EdgeInsets.all(16),
child: Center(
child: Align(
alignment: Alignment.center,
child: Text(
'Para sincronizar suas fotos, clique no botão de sincronização',
style: TextStyle(color: Colors.white, fontSize: 20.0),
textAlign: TextAlign.center,
)),
),
),
Padding(
padding: EdgeInsets.all(10.0),
child: Center(child: Image(image: AssetImage('assets/sinc_help.png'))),
),
],
),
);
}
//Método dispardo pelo botão sync
_sync() {
int count = 0;
......@@ -127,10 +185,7 @@ class _SynchronizationListState extends State<SynchronizationList> {
print('curso valido: ' + course.toString());
print(!_checkDuplicate(file.path));
if (!_checkDuplicate(file.path)) {
_upload(file, createDateTime).then((url) => {
_addPhoto(url, file.path, createDateTime, course.reference),
_saveCache(file.path)
});
_upload(file, createDateTime).then((url) => {_addPhoto(url, file.path, createDateTime, course.reference), _saveCache(file.path)});
}
}
});
......@@ -150,8 +205,7 @@ class _SynchronizationListState extends State<SynchronizationList> {
//Valida se a data esta entre a data de inicio e fim do semestre
bool _validateSemester(Semester semester, DateTime date) {
if (date.compareTo(semester.startDate) > 0 &&
date.compareTo(semester.endDate) < 0) {
if (date.compareTo(semester.startDate) > 0 && date.compareTo(semester.endDate) < 0) {
return true;
}
return false;
......@@ -167,12 +221,8 @@ class _SynchronizationListState extends State<SynchronizationList> {
//}
//verificando somente a hora
if ((schedule.startTime.hour < date.hour ||
(schedule.startTime.hour == date.hour &&
schedule.startTime.minute <= date.minute)) &&
(schedule.endTime.hour > date.hour ||
(schedule.endTime.hour == date.hour &&
schedule.endTime.minute >= date.minute))) {
if ((schedule.startTime.hour < date.hour || (schedule.startTime.hour == date.hour && schedule.startTime.minute <= date.minute)) &&
(schedule.endTime.hour > date.hour || (schedule.endTime.hour == date.hour && schedule.endTime.minute >= date.minute))) {
List<String> weekdays = List.from(schedule.weekdays);
weekdays.forEach((weekday) {
print(weekday);
......@@ -233,19 +283,11 @@ class _SynchronizationListState extends State<SynchronizationList> {
List<AssetPathEntity> list = await PhotoManager.getAssetPathList();
list.forEach((assetPathEntity) {
print(assetPathEntity.name);
if (assetPathEntity.name == 'Pictures' ||
assetPathEntity.name == 'Camera' ||
assetPathEntity.name == 'Recent') {
assetPathEntity
.getAssetListPaged(0, 99)
.asStream()
.forEach((element) {
if (assetPathEntity.name == 'Pictures' || assetPathEntity.name == 'Camera' || assetPathEntity.name == 'Recent') {
assetPathEntity.getAssetListPaged(0, 99).asStream().forEach((element) {
element.asMap().forEach((key, image) {
print(image.id);
image.file.then((fileImage) => {
files.putIfAbsent(
File(fileImage.path), () => image.createDateTime)
});
image.file.then((fileImage) => {files.putIfAbsent(File(fileImage.path), () => image.createDateTime)});
});
});
}
......@@ -254,21 +296,47 @@ class _SynchronizationListState extends State<SynchronizationList> {
} else {}
}
String _buildPhotoTitle(DateTime createDatePhoto){
String day;
if(createDatePhoto.weekday == 1){
day = 'Segunda-feira';
}
if(createDatePhoto.weekday == 2 ){
day = 'Terça-feira';
}
if(createDatePhoto.weekday == 3 ){
day = 'Quarta-feira';
}
if(createDatePhoto.weekday == 4 ){
day = 'Quinta-feira';
}
if(createDatePhoto.weekday == 5 ){
day = 'Sexta-feira';
}
if(createDatePhoto.weekday == 6 ){
day = 'Sábado';
}
if(createDatePhoto.weekday == 7 ){
day = 'Domingo';
}
String data;
data = createDatePhoto.day.toString() + '/' + createDatePhoto.month.toString();
String title = data + " " + day + ' ' + createDatePhoto.hour.toString() + ':' + createDatePhoto.minute.toString();
return title;
}
//Insert no firebase
_addToSyncPhotos(String url, String path, DateTime createDatePhoto) {
InsertData()
.insertSyncPhoto(Photo(time: createDatePhoto, path: path, url: url));
InsertData().insertSyncPhoto(Photo(time: createDatePhoto, path: _buildPhotoTitle(createDatePhoto), url: url));
}
//Insere foto dentro do curso no firebase
_addToCourse(String url, String path, DateTime createDatePhoto,
DocumentReference course) {
InsertData().insertPhoto(
Photo(time: createDatePhoto, path: path, url: url), course);
_addToCourse(String url, String path, DateTime createDatePhoto, DocumentReference course) {
InsertData().insertPhoto(Photo(time: createDatePhoto, path: path, url: url), course);
}
_addPhoto(String url, String path, DateTime createDatePhoto,
DocumentReference course) {
_addPhoto(String url, String path, DateTime createDatePhoto, DocumentReference course) {
_addToSyncPhotos(url, path, createDatePhoto);
_addToCourse(url, path, createDatePhoto, course);
}
......@@ -288,13 +356,10 @@ class _SynchronizationListState extends State<SynchronizationList> {
//_addToFirebase(url, file.path, createDatePhoto);
} else if (storageUploadTask.isInProgress) {
storageUploadTask.events.listen((event) {
double percentage = 100 *
(event.snapshot.bytesTransferred.toDouble() /
event.snapshot.totalByteCount.toDouble());
double percentage = 100 * (event.snapshot.bytesTransferred.toDouble() / event.snapshot.totalByteCount.toDouble());
print("Upload: " + percentage.toString());
});
StorageTaskSnapshot storageTaskSnapshot =
await storageUploadTask.onComplete;
StorageTaskSnapshot storageTaskSnapshot = await storageUploadTask.onComplete;
var downloadUrl1 = await storageTaskSnapshot.ref.getDownloadURL();
print("Download URL " + downloadUrl1.toString());
print("add to photos: " + file.path);
......@@ -340,8 +405,93 @@ class _SynchronizationListState extends State<SynchronizationList> {
photos.add(newPhoto);
}
}
return _buildList(context, snapshot.data.documents);
return snapshot.data.documents.isEmpty ? _createBackground() : _buildList(context, snapshot.data.documents);
},
);
}
}
class TutorialOverlay extends ModalRoute<void> {
@override
Duration get transitionDuration => Duration(milliseconds: 200);
@override
bool get opaque => false;
@override
bool get barrierDismissible => false;
@override
Color get barrierColor => Colors.black.withOpacity(0.5);
@override
String get barrierLabel => null;
@override
bool get maintainState => true;
@override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
// This makes sure that text and other content follows the material style
return Material(
type: MaterialType.transparency,
// make sure that the overlay content is not cut off
child: SafeArea(
child: _buildOverlayContent(context),
),
);
}
Widget _buildOverlayContent(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Padding(
padding: EdgeInsets.all(16),
child: Center(
child: Align(
alignment: Alignment.centerRight,
child: Text(
'Para sincronizar suas fotos, clique no botão de sincronização',
style: TextStyle(color: Colors.white, fontSize: 20.0),
textAlign: TextAlign.center,
)),
),
),
Padding(
padding: EdgeInsets.all(10.0),
child: Center(child: Image(image: AssetImage('assets/sinc_help.png'))),
),
Padding(
padding: EdgeInsets.all(16.0),
child: Container(
alignment: Alignment.bottomRight,
child: RaisedButton(
color: Colors.deepPurpleAccent.shade200,
onPressed: () => Navigator.pop(context),
child: Text('Ok, entendi'),
)),
)
],
),
);
}
@override
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
// You can add your own animations for the overlay content
return FadeTransition(
opacity: animation,
child: ScaleTransition(
scale: animation,
child: child,
),
);
}
}
......@@ -7,6 +7,8 @@ class Auth {
final Firestore firestoreInstance = Firestore.instance;
final FirebaseStorage storage = FirebaseStorage.instance;
static String loggedUserId;
static String loggedUserName;
static String loggedUserEmail;
Future<FirebaseUser> auth(String email, String password) async {
FirebaseUser firebaseUser;
......@@ -15,6 +17,8 @@ class Auth {
.then((fbUser) {
firebaseUser = fbUser.user;
Auth.loggedUserId = firebaseUser.uid;
Auth.loggedUserName = firebaseUser.displayName;
Auth.loggedUserEmail = firebaseUser.email;
}).catchError((error) {
print(error.message);
print(error.code);
......@@ -36,9 +40,19 @@ class Auth {
});
await firestoreInstance
.collection("users")
.document(firebaseUser.uid).setData({
'name': name.first,
});
.document(firebaseUser.uid)
.setData({
'name': name.first,
});
return firebaseUser;
}
Future<void> logout() async {
await firebaseAuth.signOut().then((result) {
Auth.loggedUserId = null;
}).catchError((error) {
print(error.message);
print(error.code);
});
}
}
......@@ -12,6 +12,7 @@ class GetData {
.collection("users")
.document(uid)
.collection("semesters")
.orderBy('startDate', descending: true)
.snapshots();
}
......
......@@ -68,9 +68,8 @@ flutter:
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- assets/sinc_help.png
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment