diff --git a/assets/images/logo.png b/assets/images/logo.png
new file mode 100644
index 0000000..b32c93a
Binary files /dev/null and b/assets/images/logo.png differ
diff --git a/assets/maps/c1/c1PavimentoSuperior.svg b/assets/maps/c1/c1PavimentoSuperior.svg
new file mode 100644
index 0000000..96c176a
--- /dev/null
+++ b/assets/maps/c1/c1PavimentoSuperior.svg
@@ -0,0 +1,6544 @@
+
+
diff --git a/assets/maps/c1/c1PavimentoTerreo.svg b/assets/maps/c1/c1PavimentoTerreo.svg
new file mode 100644
index 0000000..fd538c3
--- /dev/null
+++ b/assets/maps/c1/c1PavimentoTerreo.svg
@@ -0,0 +1,12023 @@
+
+
diff --git a/lib/app/app.color.dart b/lib/app/app.color.dart
new file mode 100644
index 0000000..b45a38a
--- /dev/null
+++ b/lib/app/app.color.dart
@@ -0,0 +1,8 @@
+import 'package:flutter/material.dart';
+
+class AppColors {
+ // static const Color primary = Color(0xff003E1F);
+ // static const Color secondary = Color(0xff01110A);
+ static const Color primary = Colors.deepOrange;
+ static const Color secondary = Colors.orange;
+}
diff --git a/lib/app/app.constant.dart b/lib/app/app.constant.dart
index 5b8a0a2..9ebfcbf 100644
--- a/lib/app/app.constant.dart
+++ b/lib/app/app.constant.dart
@@ -1,4 +1,8 @@
+/// Valid types:
+///
+/// common, initial, intermediary.
enum TypePoint {
- path,
- goal,
+ common,
+ entrance,
+ passage,
}
diff --git a/lib/app/app.repository.dart b/lib/app/app.repository.dart
new file mode 100644
index 0000000..d02903e
--- /dev/null
+++ b/lib/app/app.repository.dart
@@ -0,0 +1,71 @@
+import 'dart:convert';
+
+import 'package:dio/dio.dart';
+import 'package:flutter/foundation.dart';
+
+class AppRepository {
+ static const String path = 'https://api-proex.onrender.com';
+ static const String queryLogin = '/login';
+ static const String queryUser = '/user';
+ static const String queryAllUsers = '/users';
+ static const String queryMap = '/maps';
+ static const String queryBuilder = '/api/accounts';
+ static const String queryOrganization = '/api/accounts';
+ static const String queryPoints = '/points';
+
+ Dio dio = Dio();
+
+ Future post(
+ {required dynamic model, required String query, Options? options}) async {
+ const String erroMessage = "Erro na consulta";
+ //print(model.toJson());
+ try {
+ return await dio
+ .post(
+ AppRepository.path + query,
+ data: model.toJson(),
+ options: options,
+ )
+ .then(
+ (res) {
+ return res.data.toString();
+ },
+ );
+ } catch (e) {
+ if (kDebugMode) {
+ print("Erro em post:\n");
+ print(e);
+ }
+ return erroMessage;
+ }
+ }
+
+ Future get(
+ {required String id, required String query, Options? options}) async {
+ const String erroMessage = "Erro na consulta";
+ if (kDebugMode) {
+ print("GET...\n");
+ print(AppRepository.path + query + '/' + id);
+ }
+ try {
+ return await dio
+ .get(
+ AppRepository.path + query + '/' + id,
+ options: options,
+ )
+ .then(
+ (res) {
+ return res.data["id"] == null
+ ? res.data.toString()
+ : jsonEncode(res.data);
+ },
+ );
+ } catch (e) {
+ if (kDebugMode) {
+ print("Erro em post:\n");
+ print(e);
+ }
+ return erroMessage;
+ }
+ }
+}
diff --git a/lib/app/app.widget.dart b/lib/app/app.widget.dart
index e877074..0f17a4a 100644
--- a/lib/app/app.widget.dart
+++ b/lib/app/app.widget.dart
@@ -1,23 +1,32 @@
import 'package:flutter/material.dart';
+import 'package:mvp_proex/app/app.color.dart';
+import 'package:mvp_proex/features/login/login.view.dart';
import 'package:mvp_proex/features/map/map.view.dart';
+import 'package:mvp_proex/features/mapselection/mapselection.view.dart';
+import 'package:mvp_proex/features/user/user.model.dart';
+import 'package:provider/provider.dart';
class AppWidget extends StatelessWidget {
const AppWidget({Key? key}) : super(key: key);
- // This widget is the root of your application.
@override
Widget build(BuildContext context) {
- return MaterialApp(
- debugShowCheckedModeBanner: false,
- title: 'MVP Demo',
- theme: ThemeData(
- primarySwatch: Colors.deepOrange,
- scaffoldBackgroundColor: Colors.black26,
+ return Provider(
+ create: (_) => UserModel(),
+ child: MaterialApp(
+ debugShowCheckedModeBanner: false,
+ title: 'MVP Demo',
+ theme: ThemeData(
+ primarySwatch: AppColors.primary as MaterialColor,
+ scaffoldBackgroundColor: Colors.black,
+ ),
+ initialRoute: '/login',
+ routes: {
+ '/map': (context) => const MapView(),
+ '/login': (context) => const LoginView(),
+ '/mapselection':(context) => const MapselectionView(),
+ },
),
- initialRoute: '/map',
- routes: {
- '/map': (context) => const MapView(),
- },
);
}
}
diff --git a/lib/features/login/login.controller.dart b/lib/features/login/login.controller.dart
new file mode 100644
index 0000000..082294f
--- /dev/null
+++ b/lib/features/login/login.controller.dart
@@ -0,0 +1,13 @@
+import 'package:flutter/cupertino.dart';
+import 'package:rx_notifier/rx_notifier.dart';
+
+class LoginController {
+ TextEditingController emailEditingController = TextEditingController();
+ TextEditingController passwordEditingController = TextEditingController();
+
+ RxNotifier isVisible = RxNotifier(false);
+ bool get getIsVisible => isVisible.value;
+
+ RxNotifier isLoading = RxNotifier(false);
+ bool get getIsLoading => isLoading.value;
+}
diff --git a/lib/features/login/login.view.dart b/lib/features/login/login.view.dart
new file mode 100644
index 0000000..0b4951b
--- /dev/null
+++ b/lib/features/login/login.view.dart
@@ -0,0 +1,219 @@
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:rx_notifier/rx_notifier.dart';
+import 'package:mvp_proex/app/app.color.dart';
+import 'package:mvp_proex/features/login/login.controller.dart';
+import 'package:mvp_proex/features/user/user.model.dart';
+import 'package:mvp_proex/features/user/user.repository.dart';
+import 'package:mvp_proex/features/widgets/shared/button_submit.widget.dart';
+import 'package:mvp_proex/features/widgets/shared/form_field.widget.dart';
+import 'package:mvp_proex/features/widgets/shared/snackbar.message.dart';
+
+class LoginView extends StatefulWidget {
+ const LoginView({Key? key}) : super(key: key);
+
+ @override
+ _LoginViewState createState() => _LoginViewState();
+}
+
+class _LoginViewState extends State {
+ late UserModel userModel;
+ LoginController controller = LoginController();
+ final _formKey = GlobalKey();
+
+ @override
+ void initState() {
+ super.initState();
+ userModel = Provider.of(context, listen: false);
+ if (userModel.token != "") {
+ Navigator.of(context).pushReplacementNamed('/mapselection');
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ Size size = MediaQuery.of(context).size;
+ return Scaffold(
+ body: Center(
+ child: SingleChildScrollView(
+ child: Container(
+ width: size.width < 320 ? size.width * 0.8 : 280,
+ height: size.height,
+ alignment: Alignment.center,
+ child: Form(
+ key: _formKey,
+ child: Column(
+ children: [
+ const Spacer(
+ flex: 4,
+ ),
+ const Text(
+ "Módulo\n1",
+ style: TextStyle(
+ fontSize: 36,
+ fontWeight: FontWeight.w700,
+ color: AppColors.primary,
+ ),
+ textAlign: TextAlign.center,
+ ),
+ const Spacer(
+ flex: 2,
+ ),
+ FormFieldWidget(
+ title: "E-mail",
+ description: "Entre com seu email",
+ validator: (String value) {
+ if (value.isEmpty) return "Campo vazio";
+ if (value.length < 10) return "Campo muito pequeno";
+ if (!value.contains("@")) return "Falta @";
+ if (!value.contains("@")) return "Falta .";
+ return null;
+ },
+ controller: controller.emailEditingController,
+ onChanged: (value) {
+ userModel.email = value;
+ },
+ icon: const SizedBox(),
+ keyboardType: TextInputType.emailAddress,
+ ),
+ RxBuilder(
+ builder: (context) {
+ return FormFieldWidget(
+ title: "Senha",
+ description: "Senha do sistema",
+ validator: (value) {
+ if (value.isEmpty) return "Campo vazio";
+ return null;
+ },
+ controller: controller.passwordEditingController,
+ onChanged: (value) {
+ userModel.password = value;
+ },
+ keyboardType: TextInputType.text,
+ obscure: !controller.getIsVisible,
+ icon: IconButton(
+ icon: !controller.getIsVisible == true
+ ? const Icon(Icons.visibility)
+ : const Icon(Icons.visibility_off),
+ onPressed: () {
+ controller.isVisible.value =
+ !controller.getIsVisible;
+ },
+ ),
+ );
+ },
+ ),
+ const Spacer(
+ flex: 2,
+ ),
+ RxBuilder(
+ builder: (context) {
+ return controller.getIsLoading
+ ? const CircularProgressIndicator()
+ : ButtonSubmitWidget(
+ textButton: "Entrar",
+ onPressed: () async {
+ if (_formKey.currentState!.validate()) {
+ controller.isLoading.value = true;
+ await UserRepository()
+ .login(
+ userModel: userModel,
+ )
+ .then(
+ (value) async {
+ if (value.contains("Erro")) {
+ showMessageError(
+ context: context, text: value);
+ } else {
+ userModel.token = value;
+ //TODO: tratar possíveis erros de requisição
+ await UserRepository()
+ .getUser(value)
+ .then((othervalue) {
+ userModel.permission =
+ othervalue["role"];
+ });
+ Navigator.of(context)
+ .pushReplacementNamed(
+ '/mapselection');
+ }
+ },
+ ).whenComplete(() =>
+ controller.isLoading.value = false);
+ }
+ },
+ );
+ },
+ ),
+ RxBuilder(
+ builder: ((context) {
+ return controller.getIsLoading
+ ? const CircularProgressIndicator()
+ : TextButton(
+ onPressed: () async {
+ userModel.email = "gabriel@gmail.com";
+ userModel.password = "123456";
+ await UserRepository()
+ .login(
+ userModel: userModel,
+ )
+ .then(
+ (value) async {
+ if (value.contains("Erro")) {
+ showMessageError(
+ context: context, text: value);
+ } else {
+ userModel.token = value;
+ //TODO: tratar possíveis erros de requisição
+ await UserRepository()
+ .getUser(value)
+ .then((othervalue) {
+ userModel.permission =
+ othervalue["role"];
+ });
+ Navigator.of(context)
+ .pushReplacementNamed(
+ '/mapselection');
+ }
+ },
+ ).whenComplete(() =>
+ controller.isLoading.value = false);
+ },
+ child: const Text(
+ "Automático",
+ style: TextStyle(color: Colors.white),
+ ));
+ }),
+ ),
+ const Spacer(
+ flex: 4,
+ ),
+ TextButton(
+ onPressed: () {
+ Navigator.of(context).pushNamed("/recovery-password");
+ },
+ child: const Padding(
+ padding: EdgeInsets.all(8.0),
+ child: Text(
+ "Recuperar Senha",
+ style: TextStyle(
+ fontSize: 12,
+ fontWeight: FontWeight.w400,
+ color: Colors.grey,
+ ),
+ textAlign: TextAlign.center,
+ ),
+ ),
+ ),
+ const Spacer(
+ flex: 1,
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/features/map/map.view.dart b/lib/features/map/map.view.dart
index 3fa90bf..8b749a3 100644
--- a/lib/features/map/map.view.dart
+++ b/lib/features/map/map.view.dart
@@ -1,27 +1,33 @@
import 'package:flutter/material.dart';
-import 'package:mvp_proex/features/model/person.model.dart';
-import 'package:mvp_proex/features/widgets/svg_map.widget.dart';
+import 'package:mvp_proex/features/svg_map/svg_map.view.dart';
class MapView extends StatefulWidget {
- const MapView({Key? key}) : super(key: key);
+ final String? mysvgPath;
+ final String? mapId;
+ final String? mapName;
+ const MapView({
+ Key? key,
+ this.mysvgPath,
+ this.mapId,
+ this.mapName,
+ }) : super(key: key);
@override
State createState() => _MapViewState();
}
class _MapViewState extends State {
- PersonModel person = PersonModel(639, 274, 0, -22.2467586, -45.0171148, 0);
-
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SVGMap(
- svgPath: "assets/maps/reitoria/mapaTeste.svg",
+ svgPath: widget.mysvgPath ?? "assets/maps/c1/c1PavimentoSuperior.svg",
svgWidth: 800,
svgHeight: 600,
svgScale: 1.3,
- person: person,
+ mapID: widget.mapId,
+ mapName: widget.mapName,
),
),
);
diff --git a/lib/features/mapselection/mapselection.repository.dart b/lib/features/mapselection/mapselection.repository.dart
new file mode 100644
index 0000000..3f8e38a
--- /dev/null
+++ b/lib/features/mapselection/mapselection.repository.dart
@@ -0,0 +1,28 @@
+import 'package:dio/dio.dart';
+import 'package:flutter/foundation.dart';
+import 'package:mvp_proex/app/app.repository.dart';
+
+class MapselectionRepository extends AppRepository {
+ Future getMapList({required String token}) async {
+ if (kDebugMode) {
+ print("Get maps...");
+ }
+ try {
+ return await dio
+ .get(
+ AppRepository.path + AppRepository.queryMap,
+ options: Options(
+ headers: {
+ "Authorization": "Bearer $token",
+ },
+ responseType: ResponseType.json,
+ ),
+ )
+ .then((res) {
+ return res.data;
+ });
+ } on DioError {
+ rethrow;
+ }
+ }
+}
diff --git a/lib/features/mapselection/mapselection.view.dart b/lib/features/mapselection/mapselection.view.dart
new file mode 100644
index 0000000..895bf91
--- /dev/null
+++ b/lib/features/mapselection/mapselection.view.dart
@@ -0,0 +1,150 @@
+import 'dart:async';
+
+import 'package:dio/dio.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:mvp_proex/app/app.color.dart';
+import 'package:mvp_proex/features/map/map.view.dart';
+import 'package:mvp_proex/features/mapselection/mapselection.repository.dart';
+import 'package:mvp_proex/features/user/user.model.dart';
+import 'package:mvp_proex/features/user/user.repository.dart';
+import 'package:provider/provider.dart';
+
+class MapselectionView extends StatefulWidget {
+ const MapselectionView({Key? key}) : super(key: key);
+
+ @override
+ State createState() => _MapselectionViewState();
+}
+
+class _MapselectionViewState extends State {
+ late UserModel userModel;
+ UserRepository repository = UserRepository();
+ final _formKey = GlobalKey();
+
+ StreamController _streamController = StreamController();
+ List listOfMaps = [];
+ void getAllMaps() {
+ _streamController = StreamController(onListen: () async {
+ try {
+ listOfMaps = await MapselectionRepository().getMapList(
+ token: userModel.token,
+ );
+ _streamController.sink.add("event");
+ _streamController.close();
+ } on DioError catch (e) {
+ switch (e.response!.statusCode) {
+ case 404:
+ if (kDebugMode) {
+ print("Not found");
+ }
+ break;
+ case 401:
+ if (kDebugMode) {
+ print("Unauthorized");
+ }
+ break;
+ default:
+ break;
+ }
+ _streamController.addError("error");
+ }
+ });
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ userModel = Provider.of(context, listen: false);
+ if (userModel.token == "") {
+ Navigator.of(context).pushReplacementNamed('/login');
+ }
+ getAllMaps();
+ }
+
+ @override
+ void dispose() {
+ _streamController.close();
+ super.dispose();
+ }
+
+ Map mapa = {};
+
+ @override
+ Widget build(BuildContext context) {
+ return StreamBuilder