手戻り修正、APK出力

This commit is contained in:
2024-04-24 11:30:38 +09:00
parent 4d40a10f9a
commit 8945748d07
9 changed files with 213 additions and 52 deletions

View File

@ -1,3 +1,9 @@
plugins {
id 'com.android.application'
id 'kotlin-android'
}
def localProperties = new Properties() def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties') def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) { if (localPropertiesFile.exists()) {
@ -21,8 +27,6 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0' flutterVersionName = '1.0'
} }
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties() def keystoreProperties = new Properties()
@ -33,7 +37,7 @@ if (keystorePropertiesFile.exists()) {
android { android {
compileSdkVersion 33 compileSdkVersion 34
lintOptions { lintOptions {
checkReleaseBuilds false checkReleaseBuilds false
@ -56,7 +60,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.dvox.gifunavi" applicationId "com.dvox.gifunavi"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 33 targetSdkVersion 34
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
multiDexEnabled true multiDexEnabled true
@ -64,10 +68,16 @@ android {
signingConfigs { signingConfigs {
release { release {
keyAlias keystoreProperties['keyAlias'] if (project.hasProperty("RELEASE_STORE_FILE")) {
keyPassword keystoreProperties['keyPassword'] storeFile file(RELEASE_STORE_FILE)
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null storePassword RELEASE_STORE_PASSWORD
storePassword keystoreProperties['storePassword'] keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
//keyAlias keystoreProperties['keyAlias']
//keyPassword keystoreProperties['keyPassword']
//storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
//storePassword keystoreProperties['SachikoMiyata123']
} }
} }
buildTypes { buildTypes {

View File

@ -1,3 +1,7 @@
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
RELEASE_STORE_FILE=release-key.keystore
RELEASE_STORE_PASSWORD=SachikoMiyata123
RELEASE_KEY_ALIAS=release_key
RELEASE_KEY_PASSWORD=SachikoMiyata123

View File

@ -59,8 +59,8 @@ class Destination {
this.buypoint_image, this.buypoint_image,
this.forced_checkin = false, this.forced_checkin = false,
this.recipt_times = 0, this.recipt_times = 0,
this.tags, this.tags}); //, ... use_qr_code をDBに追加したらオープン
this.use_qr_code = false}); // this.use_qr_code = false});
factory Destination.fromMap(Map<String, dynamic> json) { factory Destination.fromMap(Map<String, dynamic> json) {
bool selec = json['selected'] == 0 ? false : true; bool selec = json['selected'] == 0 ? false : true;
@ -96,8 +96,8 @@ class Destination {
buypoint_image: json["buypoint_image"], buypoint_image: json["buypoint_image"],
forced_checkin: forcedCheckin, forced_checkin: forcedCheckin,
recipt_times: json["recipt_times"], recipt_times: json["recipt_times"],
tags: json["tags"], tags: json["tags"] ); //,
use_qr_code: useQrCode); // use_qr_code: useQrCode);
} }
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
@ -131,8 +131,8 @@ class Destination {
'buypoint_image': buypoint_image, 'buypoint_image': buypoint_image,
'forced_checkin': forcedCheckin, 'forced_checkin': forcedCheckin,
'recipt_times': recipt_times, 'recipt_times': recipt_times,
'tags': tags, 'tags': tags //,
'use_qr_code': use_qr_code //'use_qr_code': use_qr_code
}; };
} }
} }

View File

@ -450,8 +450,8 @@ class CameraPage extends StatelessWidget {
// buyPointPhotoがtrueの場合は、BuyPointCameraウィジェットを返します。 // buyPointPhotoがtrueの場合は、BuyPointCameraウィジェットを返します。
//print("--- buy point camera ${destination.toString()}"); //print("--- buy point camera ${destination.toString()}");
return BuyPointCamera(destination: destination); return BuyPointCamera(destination: destination);
}else if(destination.use_qr_code){ //}else if(destination.use_qr_code){
return QRCodeScannerPage(destination: destination); // return QRCodeScannerPage(destination: destination);
} else if (destinationController.isInRog.value) { } else if (destinationController.isInRog.value) {
// isInRogがtrueの場合は、カメラページのUIを構築します。 // isInRogがtrueの場合は、カメラページのUIを構築します。
// AppBarには、目的地の情報を表示します。 // AppBarには、目的地の情報を表示します。

View File

@ -32,6 +32,7 @@ import 'package:rogapp/widgets/debug_widget.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:rogapp/utils/const.dart';
// 目的地に関連する状態管理とロジックを担当するクラスです。 // 目的地に関連する状態管理とロジックを担当するクラスです。
// //
@ -405,30 +406,35 @@ class DestinationController extends GetxController {
// print("~~~~ calling start ~~~~"); // print("~~~~ calling start ~~~~");
print("---- in start -----"); print("---- in start -----");
chekcs = 1; // スタート地点で前のゴールから24時間経過 chekcs = 1; // スタート地点で前のゴールから24時間経過
isInCheckin.value = true; isInCheckin.value = true;
isAtStart.value = true; isAtStart.value = true;
if (shouldShowBottomSheet) { if (shouldShowBottomSheet) {
shouldShowBottomSheet = false; // bottom_sheet を起動させない。 shouldShowBottomSheet = false; // bottom_sheet を起動させない。
Widget bottomSheet = BottomSheetNew(destination: d); Widget bottomSheet = BottomSheetNew(destination: d);
await showModalBottomSheet( await showModalBottomSheet(
constraints: constraints:
BoxConstraints.loose(Size(Get.width, Get.height * 0.85)), BoxConstraints.loose(Size(Get.width, Get.height * 0.85)),
context: Get.context!, context: Get.context!,
isScrollControlled: true, isScrollControlled: true,
builder: ((context) => bottomSheet) builder: ((context) => bottomSheet)
).whenComplete(() { ).whenComplete(() {
shouldShowBottomSheet = true; // bottom_sheet 起動許可 shouldShowBottomSheet = true; // bottom_sheet 起動許可
skipGps = false; skipGps = false;
chekcs = 0; // ボトムシートモード=1, chekcs = 0; // ボトムシートモード=1,
isAtStart.value = false; isAtStart.value = false;
isInCheckin.value = false; isInCheckin.value = false;
}); });
} }
return; return;
// 以下の条件分岐を追加
} else if (ds.isNotEmpty && ds[0].checkedin == true) {
// 目的地がDBに存在し、すでにチェックインしている場合は自動ポップアップを表示しない
debugPrint("チェックイン済み");
return;
} else if (isInRog.value == true && } else if (isInRog.value == true &&
indexController.rogMode.value == 1 && indexController.rogMode.value == 1 &&
@ -597,7 +603,7 @@ class DestinationController extends GetxController {
// print( // print(
// "==== date diff is ${DateTime.now().difference(last_goal_at).inHours} ===="); // "==== date diff is ${DateTime.now().difference(last_goal_at).inHours} ====");
if (isuserLoggedIn && if (isuserLoggedIn &&
(d.cp == -2 || d.cp == 0 ) && // Goal CP (d.cp == -2 || d.cp == 0 || d.cp == -1 ) && // Goal CP
locationAlreadyCheckedIn && locationAlreadyCheckedIn &&
skip_10s == false) { skip_10s == false) {
//check for rogaining //check for rogaining
@ -763,7 +769,7 @@ class DestinationController extends GetxController {
if (autoCheckin) { if (autoCheckin) {
if (!checkingIn) { if (!checkingIn) {
makeCheckin(d, true, ""); makeCheckin(d, true, "");
if (d.cp != -1) { if (d.cp != -1 && d.cp != 0 && d.cp != -2) {
rogainingCounted.value = true; rogainingCounted.value = true;
} }
} }
@ -774,7 +780,7 @@ class DestinationController extends GetxController {
if (d.hidden_location != null && if (d.hidden_location != null &&
d.hidden_location == 0 && d.hidden_location == 0 &&
isInRog.value == true && isInRog.value == true &&
d.cp != -1) { d.cp != -1 && d.cp != 0 && d.cp != -2) {
chekcs = 3; chekcs = 3;
isInCheckin.value = true; isInCheckin.value = true;
photos.clear(); photos.clear();
@ -887,7 +893,10 @@ class DestinationController extends GetxController {
LatLng(currentLat, currentLon)); LatLng(currentLat, currentLon));
Destination des = festuretoDestination(fs); Destination des = festuretoDestination(fs);
if (distFs <= des.checkin_radious! && skipGps == false) { if (distFs <= des.checkin_radious!
&& skipGps == false
//&& des.isCheckedIn == false
&& des.cp!=0 && des.cp!=-1 && des.cp!=-2) {
await startTimerLocation(fs, distFs); await startTimerLocation(fs, distFs);
// Note: You cannot break out of forEach. If you need to stop processing, you might have to reconsider using forEach. // Note: You cannot break out of forEach. If you need to stop processing, you might have to reconsider using forEach.
} }
@ -1015,7 +1024,15 @@ class DestinationController extends GetxController {
// print("~~~~ inserted into db ~~~~"); // print("~~~~ inserted into db ~~~~");
} }
await _saveImageFromPath(imageurl); if (imageurl == null || imageurl.isEmpty) {
if (photos.isNotEmpty) {
// imageurlが空の場合は、destinationのcheckin_imageプロパティを使用する
debugPrint("photos = ${photos}");
imageurl = photos[0].path;
}
debugPrint("imageurl = ${imageurl}");
await _saveImageFromPath(imageurl!);
}
populateDestinations(); populateDestinations();

View File

@ -131,6 +131,30 @@ class IndexController extends GetxController {
super.onClose(); super.onClose();
} }
/*
@override
void onReady() async {
await readUserToken();
final token = userToken;
if (token != null && token.isNotEmpty) {
await loadUserDetailsForToken(token);
fixMapBound(token);
} else {
// ユーザートークンが存在しない場合はログイン画面にリダイレクト
Get.offAllNamed(AppPages.LOGIN);
}
// 地図のイベントリスナーを設定
indexController.mapController.mapEventStream.listen((MapEvent mapEvent) {
if (mapEvent is MapEventMoveEnd) {
indexController.loadLocationsBound();
}
});
super.onReady();
}
*/
Future<void> _updateConnectionStatus(ConnectivityResult result) async { Future<void> _updateConnectionStatus(ConnectivityResult result) async {
connectionStatus = result; connectionStatus = result;
connectionStatusName.value = result.name; connectionStatusName.value = result.name;
@ -232,6 +256,10 @@ class IndexController extends GetxController {
}); });
currentUser.clear(); currentUser.clear();
cats.clear(); cats.clear();
// ユーザートークンをデバイスから削除
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.remove("user_token");
} }
// 要検討:エラーハンドリングが行われていますが、エラーメッセージをローカライズすることを検討してください。 // 要検討:エラーハンドリングが行われていますが、エラーメッセージをローカライズすることを検討してください。
@ -361,6 +389,9 @@ class IndexController extends GetxController {
return; return;
} }
// MapControllerの初期化が完了するまで待機
await waitForMapControllerReady();
// Akira 追加:2024-4-6 #2800 // Akira 追加:2024-4-6 #2800
//await waitForMapControllerReady(); // MapControllerの初期化が完了するまで待機 //await waitForMapControllerReady(); // MapControllerの初期化が完了するまで待機
// Akira 追加:2024-4-6 #2800 // Akira 追加:2024-4-6 #2800
@ -451,7 +482,7 @@ class IndexController extends GetxController {
Future<void> waitForMapControllerReady() async { Future<void> waitForMapControllerReady() async {
if (!isMapControllerReady.value) { if (!isMapControllerReady.value) {
await Future.doWhile(() async { await Future.doWhile(() async {
await Future.delayed(const Duration(milliseconds: 500)); await Future.delayed(const Duration(milliseconds: 100));
return !isMapControllerReady.value; return !isMapControllerReady.value;
}); });
} }

View File

@ -275,25 +275,27 @@ class LocationController extends GetxController {
// ロゲ開始前、終了後、GPS=low の場合は更新しない。 // ロゲ開始前、終了後、GPS=low の場合は更新しない。
// //
if (destinationController.isInRog.value && isGpsSignalWeak == false) { if (isGpsSignalWeak == false) {
final adjustedLocation = adjustCurrentLocation(position); //if (destinationController.isInRog.value && isGpsSignalWeak == false) {
if (adjustedLocation != null) { final adjustedLocation = adjustCurrentLocation(position);
final locationMarkerPosition = LocationMarkerPosition( if (adjustedLocation != null) {
latitude: adjustedLocation.latitude, final locationMarkerPosition = LocationMarkerPosition(
longitude: adjustedLocation.longitude, latitude: adjustedLocation.latitude,
accuracy: position?.accuracy ?? 0, longitude: adjustedLocation.longitude,
); accuracy: position?.accuracy ?? 0,
handleLocationUpdate(locationMarkerPosition); );
//locationMarkerPositionStreamController.add(locationMarkerPosition); // 位置データ送信 handleLocationUpdate(locationMarkerPosition);
} else { //locationMarkerPositionStreamController.add(locationMarkerPosition); // 位置データ送信
// 位置情報が取得できなかった場合、 } else {
// locationMarkerPositionStreamControllerにnullを追加します。 // 位置情報が取得できなかった場合、
locationMarkerPositionStreamController.add(null); // null 送信? // locationMarkerPositionStreamControllerにnullを追加します。
//forceUpdateLocation(Position? position); locationMarkerPositionStreamController.add(null); // null 送信?
//forceUpdateLocation(Position? position);
}
//}else{
// debugPrint("GPS処理対象外");
}
//}else{
// debugPrint("GPS処理対象外");
} }
}, },

View File

@ -1,4 +1,7 @@
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:geojson_vi/geojson_vi.dart'; import 'package:geojson_vi/geojson_vi.dart';
import 'package:geolocator/geolocator.dart'; import 'package:geolocator/geolocator.dart';
@ -123,6 +126,20 @@ class BottomSheetNew extends GetView<BottomSheetController> {
} }
} }
Future<void> saveTemporaryImage(Destination destination) async {
final serverUrl = ConstValues.currentServer();
final imagePath = '${serverUrl}/media/compressed/${destination.photos}';
final tempDir = await getTemporaryDirectory();
final tempFile = await File('${tempDir.path}/temp_image.jpg').create(recursive: true);
final response = await http.get(Uri.parse(imagePath));
await tempFile.writeAsBytes(response.bodyBytes);
destinationController.photos.clear();
destinationController.photos.add(tempFile);
}
// アクションボタン(チェックイン、ゴールなど)を表示するためのメソッドです。 // アクションボタン(チェックイン、ゴールなど)を表示するためのメソッドです。
// 現在の状態に基づいて、適切なボタンを返します。 // 現在の状態に基づいて、適切なボタンを返します。
// ボタンがタップされたときの処理も含まれています。 // ボタンがタップされたときの処理も含まれています。
@ -145,17 +162,83 @@ class BottomSheetNew extends GetView<BottomSheetController> {
destinationController.currentLat, destinationController.currentLon), destinationController.currentLat, destinationController.currentLon),
LatLng(cdest.lat!, cdest.lon!)); LatLng(cdest.lat!, cdest.lon!));
if (destinationController.rogainingCounted.value == true && // Check conditions to show confirmation dialog
if (destinationController.isInRog.value == false &&
(destinationController.distanceToStart() <= 500 || destinationController.isGpsSignalWeak() ) && //追加 Akira 2024-4-5
(destination.cp == -1 || destination.cp == 0 ) &&
destinationController.rogainingCounted.value == false) {
// ゲームが始まってなければ
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.secondary,
),
onPressed: destinationController.isInRog.value == false &&
(destinationController.distanceToStart() <= 100 || destinationController.isGpsSignalWeak() ) && //追加 Akira 2024-4-5
(destination.cp == -1 || destination.cp == 0 ) &&
destinationController.rogainingCounted.value == false ? () async {
// Show confirmation dialog
Get.dialog(
AlertDialog(
title: const Text("確認"), //confirm
content: const Text(
"ロゲを開始すると、今までのロゲデータが全てクリアされます。本当に開始しますか?"), //are you sure
actions: <Widget>[
TextButton(
child: const Text("いいえ"), //no
onPressed: () {
Get.back(); // Close the dialog
},
),
TextButton(
child: const Text("はい"), //yes
onPressed: () async {
await saveTemporaryImage(destination);
// Clear data and start game logic here
destinationController.isInRog.value = true;
destinationController.resetRogaining();
destinationController.addToRogaining(
destinationController.currentLat,
destinationController.currentLon,
destination.location_id!,
);
saveGameState();
await ExternalService().startRogaining();
Get.back(); // Close the dialog and potentially navigate away
},
),
],
),
barrierDismissible:
false, // User must tap a button to close the dialog
);
}
: null,
child: Obx(
()=> Text(
destinationController.isInRog.value ? '競技中' : 'ロゲ開始',
style: TextStyle(color: Colors.white),
),
),
);
//print("counted ${destinationController.rogainingCounted.value}");
}else if (destinationController.rogainingCounted.value == true &&
// destinationController.distanceToStart() <= 500 && ... GPS信号が弱い時でもOKとする。 // destinationController.distanceToStart() <= 500 && ... GPS信号が弱い時でもOKとする。
(destinationController.distanceToStart() <= 500 || destinationController.isGpsSignalWeak() ) && (destinationController.distanceToStart() <= 500 || destinationController.isGpsSignalWeak() ) &&
destination.cp == -1 && (destination.cp == 0 || destination.cp == -2 || destination.cp == -1) &&
// (destination.cp == 0 || destination.cp == -2 ) &&
DestinationController.ready_for_goal == true) { DestinationController.ready_for_goal == true) {
//goal //goal
return ElevatedButton( return ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.red), style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
onPressed: destinationController.rogainingCounted.value == true && onPressed: destinationController.rogainingCounted.value == true &&
destinationController.distanceToStart() <= 500 && destinationController.distanceToStart() <= 500 &&
destination.cp == -1 && (destination.cp == 0 || destination.cp == -2|| destination.cp == -1) &&
DestinationController.ready_for_goal == true DestinationController.ready_for_goal == true
? () async { ? () async {
destinationController.isAtGoal.value = true; destinationController.isAtGoal.value = true;
@ -204,7 +287,7 @@ class BottomSheetNew extends GetView<BottomSheetController> {
print('Error processing check-in: $e'); print('Error processing check-in: $e');
} }
}, },
/* /*
// Check conditions to show confirmation dialog // Check conditions to show confirmation dialog
if (destinationController.isInRog.value == false && if (destinationController.isInRog.value == false &&
(destinationController.distanceToStart() <= 500 || destinationController.isGpsSignalWeak() ) && //追加 Akira 2024-4-5 (destinationController.distanceToStart() <= 500 || destinationController.isGpsSignalWeak() ) && //追加 Akira 2024-4-5
@ -257,7 +340,9 @@ class BottomSheetNew extends GetView<BottomSheetController> {
return; return;
} }
}, },
*/
*/
child: Text( child: Text(
destination.cp == -1 && destination.cp == -1 &&
destinationController.isInRog.value == false && destinationController.isInRog.value == false &&

View File

@ -37,6 +37,7 @@ class _MapWidgetState extends State<MapWidget> with WidgetsBindingObserver {
StreamSubscription? subscription; StreamSubscription? subscription;
Timer? _timer; Timer? _timer;
bool curr_marker_display = false;
Map<LatLng, Marker> _markerCache = {}; Map<LatLng, Marker> _markerCache = {};
List<Marker> _markers = []; List<Marker> _markers = [];
@ -52,7 +53,12 @@ class _MapWidgetState extends State<MapWidget> with WidgetsBindingObserver {
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
_startIdleTimer(); _startIdleTimer();
//_initMarkers(); // MapControllerの初期化が完了するまで待機
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
indexController.isMapControllerReady.value = true;
});
});
// indexController.mapController = MapController(initCompleter: mapControllerCompleter); // indexController.mapController = MapController(initCompleter: mapControllerCompleter);
@ -171,7 +177,9 @@ class _MapWidgetState extends State<MapWidget> with WidgetsBindingObserver {
//}else{ //}else{
// labelText=i.properties!['cp']; // labelText=i.properties!['cp'];
} }
//debugPrint("Text=${labelText}"); if( i.properties!['cp'] <= 0 ) {
debugPrint("Text=${labelText}");
}
final double maxWidth = labelText.length * 16.0; final double maxWidth = labelText.length * 16.0;
GeoJSONMultiPoint p = i.geometry as GeoJSONMultiPoint; GeoJSONMultiPoint p = i.geometry as GeoJSONMultiPoint;
return InkWell( return InkWell(
@ -398,7 +406,11 @@ class _MapWidgetState extends State<MapWidget> with WidgetsBindingObserver {
stream: locationController.locationMarkerPositionStream, stream: locationController.locationMarkerPositionStream,
builder: (context, snapshot) { builder: (context, snapshot) {
if (!snapshot.hasData) { if (!snapshot.hasData) {
debugPrint("====== Not display current marker"); //debugPrint("====== Not display current marker");
curr_marker_display = true;
}else if(curr_marker_display){
debugPrint("====== Displayed current marker");
curr_marker_display = false;
} }
return Container(); return Container();
}, },