Migrate to flutter_bloc

This commit is contained in:
Supan Adit Pratama 2020-07-29 01:11:47 +07:00
parent 64511fb1f7
commit cc0fd1cd84
34 changed files with 886 additions and 473 deletions

7
android/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java

View File

@ -0,0 +1,6 @@
package com.example.geosmart
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}

32
ios/.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,3 @@
export 'authentication_bloc.dart';
export 'authentication_event.dart';
export 'authentication_state.dart';

View File

@ -0,0 +1,38 @@
import 'package:alice/alice.dart';
import 'package:dio/dio.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:geosmart/bloc/authentication/authentication_event.dart';
import 'package:geosmart/bloc/authentication/authentication_state.dart';
import 'package:geosmart/service/setting_service.dart';
import 'package:meta/meta.dart';
class AuthenticationBloc
extends Bloc<AuthenticationEvent, AuthenticationState> {
final Alice alice;
final Dio dio;
AuthenticationBloc({
@required this.alice,
@required this.dio,
}) : super(AuthenticationInitial());
@override
Stream<AuthenticationState> mapEventToState(
AuthenticationEvent event,
) async* {
if (event is AuthenticationStarted) {
yield AuthenticationProgress();
final s = await SettingService().getSetting();
if (s.isValid()) {
yield AuthenticationSuccess();
} else {
yield AuthenticationFailed();
}
}
if (event is AuthenticationClear) {
await SettingService().clearSetting();
yield AuthenticationFailed();
}
}
}

View File

@ -0,0 +1,12 @@
import 'package:equatable/equatable.dart';
class AuthenticationEvent extends Equatable {
const AuthenticationEvent();
@override
List<Object> get props => [];
}
class AuthenticationStarted extends AuthenticationEvent {}
class AuthenticationClear extends AuthenticationEvent {}

View File

@ -0,0 +1,16 @@
import 'package:equatable/equatable.dart';
class AuthenticationState extends Equatable {
const AuthenticationState();
@override
List<Object> get props => [];
}
class AuthenticationInitial extends AuthenticationState {}
class AuthenticationProgress extends AuthenticationState {}
class AuthenticationSuccess extends AuthenticationState {}
class AuthenticationFailed extends AuthenticationState {}

3
lib/bloc/bloc.dart Normal file
View File

@ -0,0 +1,3 @@
export 'authentication/authentication.dart';
export 'position/position.dart';
export 'setting/setting.dart';

View File

@ -0,0 +1,3 @@
export 'position_bloc.dart';
export 'position_event.dart';
export 'position_state.dart';

View File

@ -0,0 +1,45 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:geosmart/bloc/authentication/authentication.dart';
import 'package:geosmart/bloc/position/position_event.dart';
import 'package:geosmart/bloc/position/position_state.dart';
import 'package:geosmart/service/position_service.dart';
import 'package:meta/meta.dart';
class PositionBloc extends Bloc<PositionEvent, PositionState> {
final AuthenticationBloc authenticationBloc;
PositionBloc({@required this.authenticationBloc})
: super(PositionTrackingIdle());
@override
Stream<PositionState> mapEventToState(PositionEvent event) async* {
if (event is PositionStartTracking) {
yield PositionTrackingStarted();
}
if (event is PositionStopTracking) {
try {
await PositionService(
dio: authenticationBloc.dio,
).stopTracking();
yield PositionTrackingIdle();
} catch (e) {
yield PositionTrackingFailed();
}
}
if (event is PositionSend) {
try {
PositionService(
dio: authenticationBloc.dio,
).sendPosition(
event.lat,
event.lng,
);
} catch (_) {
await PositionService(
dio: authenticationBloc.dio,
).stopTracking();
yield PositionTrackingFailed();
}
}
}
}

View File

@ -0,0 +1,25 @@
import 'package:equatable/equatable.dart';
class PositionEvent extends Equatable {
const PositionEvent();
@override
List<Object> get props => [];
}
class PositionStartTracking extends PositionEvent {}
class PositionSend extends PositionEvent {
final String lat;
final String lng;
const PositionSend({this.lat, this.lng});
@override
List<Object> get props => [this.lat, this.lng];
@override
String toString() => "PositionSend { lat: $lat, lng: $lng }";
}
class PositionStopTracking extends PositionEvent {}

View File

@ -0,0 +1,14 @@
import 'package:equatable/equatable.dart';
class PositionState extends Equatable {
const PositionState();
@override
List<Object> get props => [];
}
class PositionTrackingIdle extends PositionState {}
class PositionTrackingFailed extends PositionState {}
class PositionTrackingStarted extends PositionState {}

View File

@ -0,0 +1,3 @@
export 'setting_bloc.dart';
export 'setting_event.dart';
export 'setting_state.dart';

View File

@ -0,0 +1,40 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:geosmart/bloc/authentication/authentication.dart';
import 'package:geosmart/bloc/setting/setting_event.dart';
import 'package:geosmart/bloc/setting/setting_state.dart';
import 'package:geosmart/model/setting.dart';
import 'package:geosmart/service/setting_service.dart';
import 'package:geosmart/service/unique_id_service.dart';
import 'package:meta/meta.dart';
class SettingBloc extends Bloc<SettingEvent, SettingState> {
final AuthenticationBloc authenticationBloc;
SettingBloc({@required this.authenticationBloc}) : super(SettingInitial());
@override
Stream<SettingState> mapEventToState(SettingEvent event) async* {
if (event is SettingSet) {
yield SettingProgress();
if (event.host != null && event.host != "") {
try {
final s = await UniqueIDService().getUniqueID(
event.host,
authenticationBloc.dio,
);
SettingService().setSetting(SettingModel(
event.host,
s.id,
));
yield SettingSuccess();
} catch (_) {
yield SettingFailed(
message: "Make sure your host is correct and alive.",
);
}
} else {
yield SettingFailed(message: "Host cannot null or empty.");
}
}
}
}

View File

@ -0,0 +1,23 @@
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
class SettingEvent extends Equatable {
const SettingEvent();
@override
List<Object> get props => [];
}
class SettingSet extends SettingEvent {
final String host;
const SettingSet({@required this.host}) : assert(host != null && host != "");
@override
List<Object> get props => [];
@override
String toString() => "SettingSet { host: $host }";
}
class SettingClear extends SettingEvent {}

View File

@ -0,0 +1,26 @@
import 'package:equatable/equatable.dart';
class SettingState extends Equatable {
const SettingState();
@override
List<Object> get props => [];
}
class SettingInitial extends SettingState {}
class SettingProgress extends SettingState {}
class SettingSuccess extends SettingState {}
class SettingFailed extends SettingState {
final String message;
const SettingFailed({this.message});
@override
List<Object> get props => [this.message];
@override
String toString() => "SettingFailed { message: $message }";
}

View File

@ -1,4 +1,5 @@
class Config { class Config {
static const String api = "http://192.168.1.7:8080"; static const String api = "http://192.168.1.7:8080";
static const bool dynamicHostSetting = true; static const bool dynamicHostSetting = true;
static const bool showInterceptor = true;
} }

View File

@ -1,19 +1,71 @@
import 'package:alice/alice.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:geosmart/page/startup.dart'; import 'package:geosmart/config.dart';
import 'package:geosmart/page/map_page.dart';
import 'package:geosmart/page/setting_page.dart';
import 'package:geosmart/page/startup_page.dart';
void main() => runApp(MyApp()); import 'bloc/bloc.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final Alice alice = Alice(showNotification: Config.showInterceptor);
final Dio dio = Dio();
dio.interceptors.add(alice.getDioInterceptor());
runApp(
MultiBlocProvider(
providers: [
BlocProvider<AuthenticationBloc>(
create: (context) => AuthenticationBloc(
alice: alice,
dio: dio,
)..add(AuthenticationStarted()),
),
BlocProvider<SettingBloc>(
create: (context) => SettingBloc(
authenticationBloc: BlocProvider.of<AuthenticationBloc>(
context,
),
),
),
BlocProvider<PositionBloc>(
create: (context) => PositionBloc(
authenticationBloc: BlocProvider.of<AuthenticationBloc>(
context,
),
),
),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIOverlays([]);
return MaterialApp( return MaterialApp(
title: 'Geo Smart App', title: 'Geo Smart App',
navigatorKey: BlocProvider.of<AuthenticationBloc>(
context,
).alice.getNavigatorKey(),
theme: ThemeData( theme: ThemeData(
primarySwatch: Colors.blue, primarySwatch: Colors.blue,
), ),
home: Startup(), home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (ctx, state) {
if (state is AuthenticationSuccess) {
return MapPage();
}
if (state is AuthenticationFailed) {
return SettingPage();
}
return StartupPage();
},
),
); );
} }
} }

View File

@ -12,9 +12,7 @@ class SettingModel {
return (this.id == "" || this.id == null); return (this.id == "" || this.id == null);
} }
bool isNullHostId(String operator) { bool isValid() {
return (operator == "and") return (!isNullHost() && !isNullId());
? isNullHost() && isNullId()
: isNullHost() || isNullId();
} }
} }

View File

@ -1,208 +0,0 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:geolocator/geolocator.dart' as geo;
import 'package:geosmart/model/position.dart';
import 'package:geosmart/model/setting.dart';
import 'package:geosmart/page/setting.dart';
import 'package:geosmart/service/position_service.dart';
import 'package:geosmart/service/setting_service.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class Map extends StatefulWidget {
Map({Key key, this.title}) : super(key: key);
final String title;
@override
_MapState createState() => _MapState();
}
class _MapState extends State<Map> {
Completer<GoogleMapController> _controller = Completer();
double latitude = 0.0;
double longitude = 0.0;
double altitude = 0.0;
double accuracy = 0.0;
double bearing = 0.0;
double speed = 0.0;
PositionService _positionService;
SettingService _settingService;
bool isChecking = true;
Position _position;
String id;
String host;
bool isGranted = false;
bool isTracking = false;
@override
void initState() {
super.initState();
setState(() {
isChecking = true;
});
_settingService = new SettingService();
_positionService = new PositionService();
// geo.Geolocator()..forceAndroidLocationManager = true;
geo.Geolocator().checkGeolocationPermissionStatus().then(
(v) {
setState(() {
isGranted = true;
});
var geolocator = geo.Geolocator();
var locationOptions = geo.LocationOptions(
accuracy: geo.LocationAccuracy.high,
);
geolocator
.getPositionStream(locationOptions)
.listen((geo.Position position) {
if (this.id != null) {
setState(() {
this._position = Position(
id: this.id,
lat: position.latitude.toString(),
lng: position.longitude.toString(),
type: "user",
);
});
} else {
stopLocationService();
settingPage();
}
print(
"New position detected with lat ${position.latitude} and lng ${position.longitude}");
sendLastPosition();
});
_settingService.getSetting().then((v) {
this.id = v.id;
this.host = v.host;
if (v.isNullId()) {
settingPage();
}
});
},
).catchError((e) {
setState(() {
isGranted = false;
});
}).whenComplete(() {
setState(() {
isChecking = false;
});
});
}
static final CameraPosition _kGooglePlex = CameraPosition(
target: LatLng(-6.914744, 107.609810),
zoom: 14.4746,
);
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Stack(
children: <Widget>[
GoogleMap(
mapType: MapType.normal,
initialCameraPosition: _kGooglePlex,
myLocationEnabled: true,
myLocationButtonEnabled: true,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
Container(
child: Image.asset("assets/images/logo.png"),
width: 70,
height: 70,
alignment: Alignment.topLeft,
margin: EdgeInsets.only(left: 10.0),
),
Container(
child: FlatButton(
color: (isTracking) ? Colors.redAccent : Colors.green,
onPressed: toggleTracking,
child: Text(
(isChecking)
? "Please wait"
: ((isTracking) ? "Stop Tracking" : "Start Tracking"),
style: TextStyle(color: Colors.white),
),
),
margin: EdgeInsets.only(bottom: 50.0),
alignment: Alignment.bottomCenter,
)
],
),
);
}
toggleTracking() {
if (!isChecking) {
if (isGranted) {
if (isTracking) {
stopLocationService();
} else {
sendLastPosition();
}
setState(() {
isTracking = !isTracking;
});
} else {
FlutterToast.showToast(
msg: "Make sure you have turn on location services",
);
}
}
}
stopLocationService() {
if (_positionService != null) {
_positionService.stopTracking();
}
}
settingPage() {
Navigator.of(context).pushReplacement(new MaterialPageRoute(
builder: (BuildContext context) => Setting(),
));
}
sendLastPosition() async {
SettingModel m = await _settingService.getSetting();
print("Prepare to Send last location with ID : ${m.id} to ${m.host}");
if (this._position != null) {
if (this._position.isValid()) {
if (_positionService != null) {
print("Lat ${_position.lat}, Lng ${_position.lng}");
if (isTracking) {
print("Send tracking location");
_positionService.sendPosition(
this._position.lat.toString(),
this._position.lng.toString(),
);
}
} else {
FlutterToast.showToast(
msg: "Failed to start position service",
);
settingPage();
}
} else {
print("Invalid Position");
}
}
}
@override
void dispose() {
super.dispose();
stopLocationService();
}
}

139
lib/page/map_page.dart Normal file
View File

@ -0,0 +1,139 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:geolocator/geolocator.dart' as geo;
import 'package:geosmart/bloc/bloc.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class MapPage extends StatefulWidget {
MapPage({Key key, this.title}) : super(key: key);
final String title;
@override
_MapPageState createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
Completer<GoogleMapController> _controller = Completer();
bool isChecking = true;
bool isGranted = false;
bool isTracking = false;
@override
void initState() {
super.initState();
setState(() {
isChecking = true;
});
// geo.Geolocator()..forceAndroidLocationManager = true;
geo.Geolocator().checkGeolocationPermissionStatus().then(
(v) {
isGranted = true;
var geolocator = geo.Geolocator();
var locationOptions = geo.LocationOptions(
accuracy: geo.LocationAccuracy.high,
);
geolocator.getPositionStream(locationOptions).listen(
(geo.Position position) {
if (isTracking && isGranted) {
BlocProvider.of<PositionBloc>(context).add(
PositionSend(
lat: position.latitude.toString(),
lng: position.longitude.toString(),
),
);
}
},
);
},
).catchError((e) {
isGranted = false;
}).whenComplete(() {
setState(() {
isChecking = false;
});
});
}
static final CameraPosition _kGooglePlex = CameraPosition(
target: LatLng(-6.914744, 107.609810),
zoom: 14.4746,
);
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocListener<PositionBloc, PositionState>(
listener: (ctx, state) {
if (state is PositionTrackingFailed) {
BlocProvider.of<AuthenticationBloc>(ctx).add(
AuthenticationClear(),
);
}
if (state is PositionTrackingStarted) {
isTracking = true;
}
if (state is PositionTrackingIdle) {
isTracking = false;
}
},
child: BlocBuilder<PositionBloc, PositionState>(
builder: (ctx, state) {
return Stack(
children: <Widget>[
GoogleMap(
mapType: MapType.normal,
initialCameraPosition: _kGooglePlex,
myLocationEnabled: true,
myLocationButtonEnabled: true,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
),
Container(
child: Image.asset("assets/images/logo.png"),
width: 70,
height: 70,
alignment: Alignment.topLeft,
margin: EdgeInsets.only(left: 10.0),
),
Container(
child: FlatButton(
color: (state is PositionTrackingStarted)
? Colors.redAccent
: Colors.green,
onPressed: () async {
if (state is PositionTrackingStarted) {
BlocProvider.of<PositionBloc>(ctx).add(
PositionStopTracking(),
);
}
if (state is PositionTrackingIdle) {
BlocProvider.of<PositionBloc>(ctx).add(
PositionStartTracking(),
);
}
},
child: Text(
(isChecking)
? "Please wait"
: (state is PositionTrackingStarted
? "Stop Tracking"
: "Start Tracking"),
style: TextStyle(color: Colors.white),
),
),
margin: EdgeInsets.only(bottom: 50.0),
alignment: Alignment.bottomCenter,
)
],
);
},
),
),
);
}
}

View File

@ -1,165 +0,0 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:geosmart/config.dart';
import 'package:geosmart/model/setting.dart';
import 'package:geosmart/page/map.dart';
import 'package:geosmart/service/setting_service.dart';
import 'package:geosmart/service/unique_id_service.dart';
class Setting extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new _SettingState();
}
}
class _SettingState extends State<Setting> {
final _hostController = TextEditingController();
SettingService _settingBloc;
UniqueIDService _uniqueIDBloc;
String id;
String host;
@override
void initState() {
_settingBloc = new SettingService();
if (!Config.dynamicHostSetting) {
_settingBloc.setSetting(new SettingModel(Config.api, null));
}
_settingBloc.getSetting().then((settingModel) {
if (!settingModel.isNullId()) {
this.id = settingModel.id;
}
if (!settingModel.isNullHost()) {
this.host = settingModel.host;
}
_hostController.text = this.host;
if (!settingModel.isNullHost()) {
_uniqueIDBloc = new UniqueIDService(settingModel);
if (_uniqueIDBloc != null) {
this._uniqueIDBloc.getUniqueID().then((uniqueId) {
print("Your Unique ID " + uniqueId.id.toString());
if (uniqueId.id != null && uniqueId.id != "") {
if (!settingModel.isNullId()) {
mapPage();
} else {
this._settingBloc.setSetting(
new SettingModel(this._hostController.text, uniqueId.id),
);
mapPage();
}
} else {
FlutterToast.showToast(msg: "Invalid host address");
}
});
}
}
});
super.initState();
}
mapPage() {
Navigator.of(context).pushReplacement(new MaterialPageRoute(
builder: (BuildContext context) => Map(),
));
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Container(
child: Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/server.png"),
),
),
height: 200,
),
SizedBox(
height: 30,
),
TextField(
controller: this._hostController,
decoration: InputDecoration(
labelText: "Host",
border: OutlineInputBorder(),
),
),
SizedBox(
height: 10.0,
),
Container(
width: double.infinity,
child: FlatButton(
color: Colors.blueAccent,
onPressed: () {
this
._settingBloc
.setSetting(
new SettingModel(this._hostController.text, null),
)
.then((settingModel) {
if (!settingModel.isNullId()) {
this.id = settingModel.id;
}
if (!settingModel.isNullHost()) {
this.host = settingModel.host;
}
_hostController.text = this.host;
if (!settingModel.isNullHost()) {
_uniqueIDBloc = new UniqueIDService(settingModel);
if (_uniqueIDBloc != null) {
this._uniqueIDBloc.getUniqueID().then((uniqueId) {
print("Your Unique ID " + uniqueId.id.toString());
if (uniqueId.id != null && uniqueId.id != "") {
if (!settingModel.isNullId()) {
mapPage();
} else {
this._settingBloc.setSetting(
new SettingModel(
this._hostController.text,
uniqueId.id,
),
);
mapPage();
}
} else {
FlutterToast.showToast(
msg: "Invalid host address",
);
}
});
}
}
});
},
child: Text(
"Save",
style: TextStyle(color: Colors.white),
),
),
)
],
),
width: 200,
height: 400,
),
),
),
);
}
}

View File

@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:geosmart/bloc/bloc.dart';
class SettingPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new _SettingPageState();
}
}
class _SettingPageState extends State<SettingPage> {
final _hostController = TextEditingController();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: BlocListener<SettingBloc, SettingState>(
listener: (ctx, state) {
if (state is SettingFailed) {
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(state.message),
duration: Duration(seconds: 3),
));
}
if (state is SettingSuccess) {
BlocProvider.of<AuthenticationBloc>(ctx).add(
AuthenticationStarted(),
);
}
},
child: Container(
child: Center(
child: Container(
child: Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/server.png"),
),
),
height: 200,
),
SizedBox(
height: 30,
),
TextField(
controller: this._hostController,
decoration: InputDecoration(
labelText: "Host",
border: OutlineInputBorder(),
),
),
SizedBox(
height: 10.0,
),
Container(
width: double.infinity,
child: FlatButton(
color: Colors.blueAccent,
onPressed: () {
BlocProvider.of<SettingBloc>(context).add(
SettingSet(host: _hostController.text),
);
},
child: Text(
"Save",
style: TextStyle(color: Colors.white),
),
),
)
],
),
width: 200,
height: 400,
),
),
),
),
);
}
}

View File

@ -1,60 +0,0 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:geosmart/component/loader.dart';
import 'package:geosmart/page/map.dart';
import 'package:geosmart/page/setting.dart';
import 'package:geosmart/service/setting_service.dart';
class Startup extends StatefulWidget {
@override
State createState() {
return new _StartupState();
}
}
class _StartupState extends State<Startup> {
SettingService _settingService;
@override
void initState() {
_settingService = new SettingService();
_settingService.getSetting().then((settingModel) {
if (settingModel.isNullHost() && settingModel.isNullId()) {
Navigator.of(context).pushReplacement(new MaterialPageRoute(
builder: (BuildContext context) => Setting(),
));
} else {
Navigator.of(context).pushReplacement(new MaterialPageRoute(
builder: (BuildContext context) => Map(),
));
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: Column(
children: <Widget>[
Loader(),
SizedBox(
height: 20.0,
),
Text("Preparing System")
],
),
height: 50,
),
),
);
}
@override
void dispose() {
super.dispose();
}
}

View File

@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:geosmart/component/loader.dart';
class StartupPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: Column(
children: <Widget>[
Loader(),
SizedBox(
height: 20.0,
),
Text("Preparing System")
],
),
height: 50,
),
),
);
}
}

View File

@ -2,12 +2,15 @@ import 'package:dio/dio.dart';
import 'package:geosmart/model/position.dart'; import 'package:geosmart/model/position.dart';
import 'package:geosmart/model/response.dart'; import 'package:geosmart/model/response.dart';
import 'package:geosmart/service/setting_service.dart'; import 'package:geosmart/service/setting_service.dart';
import 'package:meta/meta.dart';
class PositionService { class PositionService {
final Dio _dio = Dio(); final Dio dio;
final SettingService _settingBloc = SettingService(); final SettingService _settingBloc = SettingService();
PositionService(); PositionService({
@required this.dio,
});
Future<ResponseModel> sendPosition(String lat, String lng) async { Future<ResponseModel> sendPosition(String lat, String lng) async {
var m = await _settingBloc.getSetting(); var m = await _settingBloc.getSetting();
@ -18,25 +21,20 @@ class PositionService {
lng: lng, lng: lng,
); );
try { try {
Response response = await _dio.post( Response response = await dio.post(
m.host + "/point/set", m.host + "/point/set",
data: position.toJson(), data: position.toJson(),
); );
return ResponseModel.fromJson(response.data); return ResponseModel.fromJson(response.data);
} on DioError catch (e) { } on DioError catch (e) {
print(e.response); throw (e);
if (e.response != null) {
return ResponseModel.fromJson(e.response.data);
} else {
return ResponseModel.fromNull();
}
} }
} }
Future<ResponseModel> stopTracking() async { Future<ResponseModel> stopTracking() async {
var m = await _settingBloc.getSetting(); var m = await _settingBloc.getSetting();
try { try {
Response response = await _dio.post( Response response = await dio.post(
m.host + "/point/unset", m.host + "/point/unset",
data: { data: {
"id": m.id, "id": m.id,
@ -45,7 +43,7 @@ class PositionService {
); );
return ResponseModel.fromJson(response.data); return ResponseModel.fromJson(response.data);
} on DioError catch (e) { } on DioError catch (e) {
return ResponseModel.fromJson(e.response.data); throw (e);
} }
} }
} }

View File

@ -16,9 +16,16 @@ class SettingService {
return await getSetting(); return await getSetting();
} }
Future<SettingModel> clearSetting() async {
SharedPreferences sharedPreferences = await this.getSharedPreferences();
sharedPreferences.remove(_host);
sharedPreferences.remove(_id);
return await getSetting();
}
Future<SettingModel> getSetting() async { Future<SettingModel> getSetting() async {
SharedPreferences sharedPreferences = await this.getSharedPreferences(); SharedPreferences sharedPreferences = await this.getSharedPreferences();
return new SettingModel( return SettingModel(
sharedPreferences.getString(_host), sharedPreferences.getString(_host),
sharedPreferences.getString(_id), sharedPreferences.getString(_id),
); );

View File

@ -1,22 +1,17 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:geosmart/model/setting.dart';
import 'package:geosmart/model/unique_id_model.dart'; import 'package:geosmart/model/unique_id_model.dart';
class UniqueIDService { class UniqueIDService {
final String _endpoint = "/id/get/unique"; final String _endpoint = "/id/get/unique";
final Dio _dio = Dio();
SettingModel _settingModel;
UniqueIDService(this._settingModel); Future<UniqueIDModel> getUniqueID(String host, Dio dio) async {
Future<UniqueIDModel> getUniqueID() async {
try { try {
Response response = await _dio.get( Response response = await dio.get(
this._settingModel.host + _endpoint, host + _endpoint,
); );
return UniqueIDModel.fromJson(response.data); return UniqueIDModel.fromJson(response.data);
} on DioError catch (e) { } on DioError catch (e) {
return UniqueIDModel.error(); throw (e);
} }
} }
} }

View File

@ -1,6 +1,13 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
alice:
dependency: "direct main"
description:
name: alice
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
archive: archive:
dependency: transitive dependency: transitive
description: description:
@ -22,6 +29,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.1" version: "2.4.1"
bloc:
dependency: transitive
description:
name: bloc
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.1"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -36,6 +50,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.3" version: "1.1.3"
chewie:
dependency: transitive
description:
name: chewie
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.10"
chopper:
dependency: transitive
description:
name: chopper
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.3"
collection: collection:
dependency: transitive dependency: transitive
description: description:
@ -72,17 +100,52 @@ packages:
source: hosted source: hosted
version: "3.0.9" version: "3.0.9"
equatable: equatable:
dependency: transitive dependency: "direct main"
description: description:
name: equatable name: equatable
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.2.3"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_bloc:
dependency: "direct main"
description:
name: flutter_bloc
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.1"
flutter_local_notifications:
dependency: transitive
description:
name: flutter_local_notifications
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.4+2"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: transitive
description: description:
@ -100,13 +163,6 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
fluttertoast:
dependency: "direct main"
description:
name: fluttertoast
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.1"
geolocator: geolocator:
dependency: "direct main" dependency: "direct main"
description: description:
@ -156,6 +212,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.12" version: "2.1.12"
intl:
dependency: transitive
description:
name: intl
url: "https://pub.dartlang.org"
source: hosted
version: "0.16.1"
location_permissions: location_permissions:
dependency: transitive dependency: transitive
description: description:
@ -163,6 +226,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.0+1" version: "3.0.0+1"
logging:
dependency: transitive
description:
name: logging
url: "https://pub.dartlang.org"
source: hosted
version: "0.11.4"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -177,6 +247,34 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.8" version: "1.1.8"
nested:
dependency: transitive
description:
name: nested
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4"
open_file:
dependency: transitive
description:
name: open_file
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
open_iconic_flutter:
dependency: transitive
description:
name: open_iconic_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
package_info:
dependency: transitive
description:
name: package_info
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.1"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -184,6 +282,34 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.6.4" version: "1.6.4"
path_provider:
dependency: transitive
description:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.11"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+2"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4+3"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
pedantic: pedantic:
dependency: transitive dependency: transitive
description: description:
@ -191,6 +317,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.9.0" version: "1.9.0"
permission_handler:
dependency: transitive
description:
name: permission_handler
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.1+1"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
petitparser: petitparser:
dependency: transitive dependency: transitive
description: description:
@ -198,6 +338,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.0" version: "2.4.0"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -205,6 +352,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.2" version: "1.0.2"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.13"
provider:
dependency: transitive
description:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.1"
quiver: quiver:
dependency: transitive dependency: transitive
description: description:
@ -219,6 +380,27 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.24.1" version: "0.24.1"
sensors:
dependency: transitive
description:
name: sensors
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2+2"
shake:
dependency: transitive
description:
name: shake
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
share:
dependency: transitive
description:
name: share
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.4+3"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
@ -315,6 +497,41 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.8" version: "2.0.8"
video_player:
dependency: transitive
description:
name: video_player
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.11+2"
video_player_platform_interface:
dependency: transitive
description:
name: video_player_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
video_player_web:
dependency: transitive
description:
name: video_player_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3+2"
wakelock:
dependency: transitive
description:
name: wakelock
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4+2"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
xml: xml:
dependency: transitive dependency: transitive
description: description:

View File

@ -34,7 +34,9 @@ dependencies:
shared_preferences: ^0.5.7+3 shared_preferences: ^0.5.7+3
rxdart: ^0.24.1 rxdart: ^0.24.1
dio: ^3.0.9 dio: ^3.0.9
fluttertoast: ^5.0.1 flutter_bloc: ^6.0.1
equatable: ^1.2.3
alice: ^0.1.3
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: