大幅変更&環境バージョンアップ
This commit is contained in:
227
lib/nrog/pages/auth_page.dart
Normal file
227
lib/nrog/pages/auth_page.dart
Normal file
@ -0,0 +1,227 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
import 'package:keyboard_dismisser/keyboard_dismisser.dart';
|
||||
import 'package:gifunavi/model/auth_user.dart';
|
||||
import 'package:gifunavi/nrog/pages/home_page.dart';
|
||||
import 'package:gifunavi/provider/auth_provider.dart';
|
||||
import 'package:gifunavi/services/auth_service.dart';
|
||||
import 'package:gifunavi/widgets/c_form_text_field.dart';
|
||||
import 'package:gifunavi/widgets/c_password_text_filed.dart';
|
||||
|
||||
class AuthPage extends ConsumerStatefulWidget {
|
||||
const AuthPage({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<AuthPage> createState() => _AuthPageState();
|
||||
}
|
||||
|
||||
class _AuthPageState extends ConsumerState<AuthPage> {
|
||||
final _formkey = GlobalKey<FormState>();
|
||||
final FocusNode focusEmail = FocusNode();
|
||||
final FocusNode focusPwd = FocusNode();
|
||||
var _authMode = 'login';
|
||||
bool _isLoginProgress = false;
|
||||
|
||||
final TextEditingController _emailTextEditingController =
|
||||
TextEditingController();
|
||||
final TextEditingController _passwordTextEditingController =
|
||||
TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_emailTextEditingController.addListener(() => setState(() {}));
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
checkUser();
|
||||
});
|
||||
}
|
||||
|
||||
void _submit() async {
|
||||
setState(() {
|
||||
_isLoginProgress = true;
|
||||
});
|
||||
if (_formkey.currentState!.validate()) {
|
||||
AuthService authService = AuthService();
|
||||
AuthUser? user = await authService.userLogin(
|
||||
_emailTextEditingController.text,
|
||||
_passwordTextEditingController.text);
|
||||
if (user != null) {
|
||||
setState(() {
|
||||
ref.read(authUserStateProvider.notifier).addLogin(user);
|
||||
});
|
||||
}
|
||||
}
|
||||
setState(() {
|
||||
_isLoginProgress = false;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _submitToken(String token) async {
|
||||
setState(() {
|
||||
_isLoginProgress = true;
|
||||
});
|
||||
AuthService authService = AuthService();
|
||||
AuthUser? user = await authService.userFromToken(token);
|
||||
//////////////print("---user is ${user} ---");
|
||||
if (user != null) {
|
||||
setState(() {
|
||||
_isLoginProgress = false;
|
||||
ref.read(authUserStateProvider.notifier).addLogin(user);
|
||||
});
|
||||
} else {}
|
||||
}
|
||||
|
||||
void checkUser() async {
|
||||
String? token =
|
||||
await ref.read(authUserStateProvider.notifier).tokenFromDevice();
|
||||
//////////////print("--- red token is ${token} ---");
|
||||
await _submitToken(token!);
|
||||
final id = ref.read(authUserStateProvider).id;
|
||||
if (id != null) {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(builder: (ctx) => const HomePage()));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (ref.read(authUserStateProvider).id != null) {
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(builder: (ctx) => const HomePage()));
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: true,
|
||||
body: KeyboardDismisser(
|
||||
gestures: const [
|
||||
GestureType.onTap,
|
||||
//GestureType.onVerticalDragDown
|
||||
],
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
buildAuthCard(),
|
||||
buildLogo(),
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Positioned buildLogo() {
|
||||
return Positioned(
|
||||
top: -170,
|
||||
left: MediaQuery.of(context).size.width / 2 - 100,
|
||||
child: Center(
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
width: 200,
|
||||
height: 200,
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/appicon.png'),
|
||||
fit: BoxFit.fill),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildAuthCard() {
|
||||
return Card(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Form(
|
||||
key: _formkey,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 40, bottom: 10, left: 12, right: 12),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: CFormTextField(
|
||||
cFocus: focusEmail,
|
||||
cController: _emailTextEditingController),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: CPasswordTextField(
|
||||
cController: _passwordTextEditingController,
|
||||
cFocusNode: focusPwd,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
buildControlls(),
|
||||
// SizedBox(height: MediaQuery.of(context).viewInsets.bottom,)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildControlls() {
|
||||
if (_isLoginProgress) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
final usr = ref.read(authUserStateProvider);
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 12.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: _submit,
|
||||
child: Text(_authMode == "login" ? "Submit" : "Register",
|
||||
style: GoogleFonts.lato(
|
||||
color: Theme.of(context).colorScheme.secondary))),
|
||||
)
|
||||
],
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
if (_authMode == 'login') {
|
||||
_authMode = 'register';
|
||||
} else {
|
||||
_authMode = 'login';
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
_authMode == "login"
|
||||
? "${usr.id} Dont have account, please Register"
|
||||
: "Already Registered, Login",
|
||||
style: GoogleFonts.lato(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
decoration: TextDecoration.underline,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
119
lib/nrog/pages/home_page.dart
Normal file
119
lib/nrog/pages/home_page.dart
Normal file
@ -0,0 +1,119 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_map_location_marker/flutter_map_location_marker.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:gifunavi/provider/map_state_provider.dart';
|
||||
import 'package:gifunavi/widgets/base_layer_widget.dart';
|
||||
|
||||
class HomePage extends ConsumerStatefulWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<HomePage> createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends ConsumerState<HomePage> {
|
||||
StreamSubscription? subscription;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final mapStateInstance = ref.watch(mapStateNotifierProvider);
|
||||
return Scaffold(
|
||||
//drawer: DrawerPage(),
|
||||
appBar: AppBar(
|
||||
title: const Text("Rogaining"),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
//Get.toNamed(AppPages.HISTORY);
|
||||
},
|
||||
icon: const Icon(Icons.history)),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
// final tk = indexController.currentUser[0]["token"];
|
||||
// if (tk != null) {
|
||||
// destinationController.fixMapBound(tk);
|
||||
// }
|
||||
},
|
||||
icon: const Icon(Icons.refresh)),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
//Get.toNamed(AppPages.SEARCH);
|
||||
},
|
||||
child: Container(
|
||||
height: 32,
|
||||
width: 75,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue,
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
),
|
||||
child: const Center(
|
||||
child: Icon(Icons.search),
|
||||
),
|
||||
),
|
||||
),
|
||||
//CatWidget(indexController: indexController,),
|
||||
],
|
||||
),
|
||||
body: Center(
|
||||
child: FlutterMap(
|
||||
mapController: mapStateInstance.mapController,
|
||||
options: MapOptions(
|
||||
maxZoom: 18.4,
|
||||
onMapReady: () {
|
||||
// indexController.is_mapController_loaded.value = true;
|
||||
subscription = mapStateInstance.mapController?.mapEventStream
|
||||
.listen((MapEvent mapEvent) {
|
||||
if (mapEvent is MapEventMoveStart) {
|
||||
//print(DateTime.now().toString() + ' [MapEventMoveStart] START');
|
||||
// do something
|
||||
}
|
||||
// if (mapEvent is MapEventMoveEnd &&
|
||||
// indexController.currentUser.isEmpty) {
|
||||
//print(DateTime.now().toString() + ' [MapEventMoveStart] END');
|
||||
// indexController.loadLocationsBound();
|
||||
//indexController.rogMapController!.move(c.center, c.zoom);
|
||||
// }
|
||||
});
|
||||
},
|
||||
center: const LatLng(37.15319600454702, 139.58765950528198),
|
||||
//bounds:
|
||||
zoom: 18,
|
||||
interactiveFlags: InteractiveFlag.pinchZoom | InteractiveFlag.drag,
|
||||
|
||||
onPositionChanged: (MapPosition pos, isvalue) {
|
||||
//indexController.currentBound = [pos.bounds!];
|
||||
},
|
||||
// onTap: (_, __) => popupController
|
||||
// .hideAllPopups(), // Hide popup when the map is tapped.
|
||||
),
|
||||
children: [
|
||||
const BaseLayer(),
|
||||
CurrentLocationLayer(
|
||||
followOnLocationUpdate: FollowOnLocationUpdate.once,
|
||||
turnOnHeadingUpdate: TurnOnHeadingUpdate.never,
|
||||
style: const LocationMarkerStyle(
|
||||
marker: DefaultLocationMarker(
|
||||
child: Icon(
|
||||
Icons.navigation,
|
||||
color: Colors.yellowAccent,
|
||||
),
|
||||
),
|
||||
markerSize: const Size(27, 27),
|
||||
markerDirection: MarkerDirection.heading,
|
||||
),
|
||||
),
|
||||
const MarkerLayer(markers: [])
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
126
lib/nrog/pages/permission_page.dart
Normal file
126
lib/nrog/pages/permission_page.dart
Normal file
@ -0,0 +1,126 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:gifunavi/nrog/pages/auth_page.dart';
|
||||
|
||||
class PermissionPage extends StatefulWidget {
|
||||
const PermissionPage({super.key});
|
||||
|
||||
@override
|
||||
State<PermissionPage> createState() => _PermissionPageState();
|
||||
}
|
||||
|
||||
class _PermissionPageState extends State<PermissionPage> {
|
||||
bool hasNavigated = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_checkPermissionStatus();
|
||||
});
|
||||
}
|
||||
|
||||
_checkPermissionStatus() async {
|
||||
PermissionStatus status = await Permission.location.status;
|
||||
|
||||
if (status.isGranted == false) {
|
||||
if (context.mounted) {
|
||||
showAlert(context);
|
||||
}
|
||||
} else if (status.isPermanentlyDenied) {
|
||||
await requestPermission();
|
||||
} else {
|
||||
if (mounted) {
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(builder: (_) => const AuthPage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Scaffold(
|
||||
body: Text(""),
|
||||
);
|
||||
}
|
||||
|
||||
void showAlert(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => AlertDialog(
|
||||
title: const Text('ロケーション許可'),
|
||||
content: const SingleChildScrollView(
|
||||
child: ListBody(
|
||||
children: <Widget>[
|
||||
Text('このアプリでは、位置情報の収集を行います。'),
|
||||
Text(
|
||||
'岐阜ナビアプリではチェックポイントの自動チェックインの機能を可能にするために、現在地のデータが収集されます。アプリを閉じている時や、使用していないときにも収集されます。位置情報は、個人を特定できない統計的な情報として、ユーザーの個人情報とは一切結びつかない形で送信されます。お知らせの配信、位置情報の利用を許可しない場合は、この後表示されるダイアログで「許可しない」を選択してください。'),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
ElevatedButton(
|
||||
child: const Text('OK'),
|
||||
onPressed: () {
|
||||
requestPermission();
|
||||
},
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> requestPermission() async {
|
||||
PermissionStatus permission = await Permission.location.status;
|
||||
if (permission == PermissionStatus.permanentlyDenied) {
|
||||
showPermanentAlert();
|
||||
} else {
|
||||
PermissionStatus newPermission = await Permission.location.request();
|
||||
if (newPermission != PermissionStatus.granted) {
|
||||
exit(0);
|
||||
} else {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(builder: (_) => const AuthPage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void showPermanentAlert() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => AlertDialog(
|
||||
title: const Text('無効'),
|
||||
content: const SingleChildScrollView(
|
||||
child: ListBody(
|
||||
children: <Widget>[
|
||||
Text('位置情報が無効になっています'),
|
||||
Text(
|
||||
'このアプリケーションへの位置情報アクセスが無効になっています。続行するには設定>プライバシーとセキュリティ>位置情報サービス>岐阜ナビ で有効にしてください。'),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
ElevatedButton(
|
||||
child: const Text('OK'),
|
||||
onPressed: () async {
|
||||
await openAppSettings().then(
|
||||
(value) async {
|
||||
if (value) {
|
||||
if (await Permission
|
||||
.location.status.isPermanentlyDenied ==
|
||||
true &&
|
||||
await Permission.location.status.isGranted ==
|
||||
false) {
|
||||
requestPermission(); /* opens app settings until permission is granted */
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user