325 lines
10 KiB
Dart
325 lines
10 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:geolocator/geolocator.dart';
|
|
import 'package:rogapp/model/destination.dart';
|
|
import 'package:rogapp/pages/index/index_controller.dart';
|
|
import 'package:rogapp/utils/const.dart';
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
import 'package:rogapp/pages/destination/destination_controller.dart';
|
|
|
|
|
|
class BottomSheetBase extends StatelessWidget {
|
|
|
|
BottomSheetBase({super.key, required this.destination,this.isAlreadyCheckedIn = false});
|
|
|
|
final IndexController indexController = Get.find<IndexController>();
|
|
final DestinationController destinationController = Get.find<DestinationController>();
|
|
|
|
final bool isAlreadyCheckedIn; // すでにチェックイン済みかどうかのフラグ
|
|
final Destination destination; // 目的地オブジェクト
|
|
|
|
|
|
// そのポイントの写真を取得するメソッド
|
|
//
|
|
Image getImage() {
|
|
String serverUrl = ConstValues.currentServer();
|
|
|
|
// currentDestinationFeature(destinationそのもの)のphotoデータのチェック
|
|
// Nouffer のコードでは、indexController.rogMode によって、destination(currentDestinationFeature) かGeoJSONFeature(currentFeature)の違いで処理が分かれていた。
|
|
// しかし、現在のコードでは GeoJSONFeature gf = indexController.currentFeature[0]; は使われていない。
|
|
//
|
|
if (indexController.currentDestinationFeature[0].photos! == "") {
|
|
// 定義されていなければ、empty_image.png を選択
|
|
return const Image(image: AssetImage('assets/images/empty_image.png'));
|
|
} else {
|
|
String photo = indexController.currentDestinationFeature[0].photos!;
|
|
if (photo.contains('http')) {
|
|
// photo にhttpの文字が含まれていれば、ネットから拾ってくる。エラーならempty_image.pngを表示。
|
|
return Image(
|
|
image: NetworkImage(
|
|
indexController.currentDestinationFeature[0].photos!,
|
|
),
|
|
errorBuilder:
|
|
(BuildContext context, Object exception, StackTrace? stackTrace) {
|
|
return Image.asset("assets/images/empty_image.png");
|
|
},
|
|
);
|
|
} else {
|
|
// photo にhttpの文字が含まれていなければ、指定サーバー($serverUrl/media/compressed/*)から拾ってくる。エラーならempty_image.pngを表示。
|
|
return Image(
|
|
image: NetworkImage(
|
|
'$serverUrl/media/compressed/${indexController.currentDestinationFeature[0].photos!}',
|
|
),
|
|
errorBuilder:
|
|
(BuildContext context, Object exception, StackTrace? stackTrace) {
|
|
return Image.asset("assets/images/empty_image.png");
|
|
},
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// URLを開くためのメソッドです。
|
|
// url_launcherパッケージを使用して、指定されたURLを開きます。
|
|
//
|
|
void _launchURL(url) async {
|
|
if (!await launchUrl(url)) throw 'Could not launch $url';
|
|
}
|
|
|
|
// 指定されたlocationidが目的地リストに含まれているかどうかを確認するメソッドです。
|
|
// destinationController.destinationsリストを走査し、locationidが一致する目的地があるかどうかを返します。
|
|
//
|
|
bool isInDestination(String locationid) {
|
|
int lid = int.parse(locationid);
|
|
if (destinationController.destinations
|
|
.where((element) => element.location_id == lid)
|
|
.isNotEmpty) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SingleChildScrollView(
|
|
child: Column(
|
|
children: buildWidgets(context),
|
|
),
|
|
);
|
|
}
|
|
|
|
// このメソッドはList<Widget>を返します。
|
|
List<Widget> buildWidgets(BuildContext context) {
|
|
return [
|
|
Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Row(
|
|
children: [
|
|
MaterialButton(
|
|
onPressed: () {
|
|
Get.back();
|
|
},
|
|
color: Colors.blue,
|
|
textColor: Colors.white,
|
|
padding: const EdgeInsets.all(16),
|
|
shape: const CircleBorder(),
|
|
child: const Icon(Icons.arrow_back_ios, size: 14),
|
|
),
|
|
Expanded(
|
|
child: Container(
|
|
alignment: Alignment.center,
|
|
child: Obx(() => Text("${destination.sub_loc_id} : ${destination.name}",
|
|
style: const TextStyle(fontSize: 15.0, fontWeight: FontWeight.bold))),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Row(
|
|
children: [Expanded(child: SizedBox(height: 260.0, child: Obx(() => getImage())))],
|
|
),
|
|
Obx(() => Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: getDetails(context),
|
|
)),
|
|
const SizedBox(height: 60.0),
|
|
];
|
|
}
|
|
|
|
Widget getDetails(BuildContext context) {
|
|
return Column(
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.roundabout_left),
|
|
const SizedBox(
|
|
width: 8.0,
|
|
),
|
|
destination.address != null && destination.address!.isNotEmpty
|
|
? getDetailsItem(
|
|
context,
|
|
"address".tr,
|
|
destination.address ?? '',
|
|
)
|
|
: const SizedBox(
|
|
width: 0.0,
|
|
height: 0,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.phone),
|
|
const SizedBox(
|
|
width: 8.0,
|
|
),
|
|
destination.phone != null && destination.phone!.isNotEmpty
|
|
? getDetailsItem(
|
|
context,
|
|
"telephone".tr,
|
|
destination.phone ?? '',
|
|
)
|
|
: const SizedBox(
|
|
width: 0.0,
|
|
height: 0,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.email),
|
|
const SizedBox(
|
|
width: 8.0,
|
|
),
|
|
destination.email != null && destination.email!.isNotEmpty
|
|
? getDetailsItem(
|
|
context,
|
|
"email".tr,
|
|
destination.email ?? '',
|
|
)
|
|
: const SizedBox(
|
|
width: 0.0,
|
|
height: 0,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Row(
|
|
children: [
|
|
const Icon(Icons.language),
|
|
const SizedBox(
|
|
width: 8.0,
|
|
),
|
|
destination.webcontents != null &&
|
|
destination.webcontents!.isNotEmpty
|
|
? getDetailsItem(
|
|
context,
|
|
"web".tr,
|
|
destination.webcontents ?? '',
|
|
isUrl: true,
|
|
)
|
|
: const SizedBox(
|
|
width: 0.0,
|
|
height: 0,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Row(
|
|
children: [
|
|
const SizedBox(
|
|
width: 8.0,
|
|
),
|
|
indexController.currentFeature[0]
|
|
.properties!["remark"] !=
|
|
null &&
|
|
(indexController.currentFeature[0]
|
|
.properties!["remark"] as String)
|
|
.isNotEmpty
|
|
? getDetailsItem(
|
|
context,
|
|
"remarks".tr,
|
|
indexController.currentFeature[0]
|
|
.properties!["remark"] ??
|
|
'',
|
|
isUrl: false)
|
|
: const SizedBox(
|
|
width: 0.0,
|
|
height: 0,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
children: [
|
|
ElevatedButton(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Theme.of(context).colorScheme.onPrimaryContainer),
|
|
onPressed: () async {
|
|
// print(
|
|
// "dist to start ${destinationController.distanceToStart()}");
|
|
Get.back();
|
|
//print("---- go to ----");
|
|
// GeoJSONMultiPoint mp = indexController
|
|
// .currentFeature[0] as GeoJSONMultiPoint;
|
|
Position position =
|
|
await Geolocator.getCurrentPosition(
|
|
desiredAccuracy:
|
|
LocationAccuracy.bestForNavigation,
|
|
forceAndroidLocationManager: true);
|
|
//print("------- position -------- $position");
|
|
Destination ds = Destination(
|
|
lat: position.latitude,
|
|
lon: position.longitude);
|
|
|
|
Destination tp = Destination(
|
|
lat: destination.lat, lon: destination.lon);
|
|
|
|
destinationController
|
|
.destinationMatrixFromCurrentPoint([ds, tp]);
|
|
|
|
// TODO: Implement "ここへ行く" functionality
|
|
},
|
|
child: Text(
|
|
"ルート",
|
|
style: TextStyle(
|
|
color: Theme.of(context).colorScheme.onPrimary,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(
|
|
width: 10,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
|
|
|
|
Widget getDetailsItem(BuildContext context, String label, String text,
|
|
{bool isUrl = false}) {
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text(label),
|
|
const SizedBox(
|
|
width: 10.0,
|
|
),
|
|
InkWell(
|
|
onTap: () {
|
|
if (isUrl) {
|
|
_launchURL(destination.webcontents);
|
|
}
|
|
},
|
|
child: SizedBox(
|
|
width: MediaQuery.of(context).size.width -
|
|
(MediaQuery.of(context).size.width * 0.35),
|
|
child: Text(
|
|
text,
|
|
textAlign: TextAlign.justify,
|
|
style: TextStyle(
|
|
color: isUrl ? Colors.blue : Colors.black,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
} |