update fixes

This commit is contained in:
2023-11-24 11:58:17 +05:30
parent 23fde37e3d
commit d8fd352a62
11 changed files with 187 additions and 64 deletions

BIN
assets/images/money.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

@ -27,17 +27,17 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>写真撮影ためカメラアクセスします</string>
<string>「岐阜ナビは旅のさまざまなチェックポイントで写真撮影して共有するためカメラへのアクセスが必要です。これにより、訪問を確認し、体験を向上させることができます。」</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>このアプリでは、位置情報の収集を行います。</string>
<string>「岐阜ナビはアプリが閉じられているときでも位置情報へのアクセスが必要です。これにより、チェックポイントでの自動チェックインを提供し、旅の間のナビゲーション体験を向上させます。</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>このアプリでは、バックグラウンドで位置情報を収集します。</string>
<string>「自動チェックインを有効にし、ナビゲーションを改善するために、岐阜ナビはアプリが使用されていないときでも継続的に位置情報へのアクセスを必要とします。</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>このアプリでは、開始時点で位置情報を収集します。</string>
<string>「岐阜ナビにアプリ使用中の位置情報へのアクセスを許可することで、チェックポイントでのチェックインを有効にし、位置に基づいた情報とガイダンスを提供します。</string>
<key>NSMicrophoneUsageDescription</key>
<string>プロフィールに動画を投稿してください。</string>
<string>「岐阜ナビは、ナビゲーション体験を向上させるために、音声コマンドやオーディオフィードバックなどの機能にマイクへのアクセスが必要です。」</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>写真ライブラリへのアクセス警告</string>
<string>「岐阜ナビはチェックポイントで撮影した写真を保存・管理し、他人と旅の様子を共有するために、写真ライブラリへのアクセスが必要です。」</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Need to save image in phone Album</string>
<key>UILaunchStoryboardName</key>
@ -45,9 +45,7 @@
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>NSCameraUsageDescription</key>
<string>ロゲイニングのゴールでは写真撮影が必要です。</string>
<key>NSMicrophoneUsageDescription</key>
<string> 収録音声の保存が必要です。</string>
<string>「岐阜ナビはチェックポイントで撮影した写真を写真ライブラリに保存し、あなたの旅行の記録を保持し、友人と共有することができます。</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>

View File

@ -6,25 +6,30 @@ class GpsData {
double lon;
int is_checkin;
int created_at;
int is_synced;
GpsData(
{required this.id,
required this.team_name,
required this.event_code,
required this.lat,
required this.lon,
required this.created_at,
this.is_checkin = 0});
GpsData({
required this.id,
required this.team_name,
required this.event_code,
required this.lat,
required this.lon,
required this.created_at,
this.is_checkin = 0,
this.is_synced = 0,
});
factory GpsData.fromMap(Map<String, dynamic> json) {
return GpsData(
id: json["id"],
team_name: json["team_name"],
event_code: json["event_code"],
lat: json["lat"],
lon: json["lon"],
is_checkin: json["is_checkin"],
created_at: json["created_at"]);
id: json["id"],
team_name: json["team_name"],
event_code: json["event_code"],
lat: json["lat"],
lon: json["lon"],
is_checkin: json["is_checkin"],
created_at: json["created_at"],
is_synced: json["is_synced"] ?? 0,
);
}
Map<String, dynamic> toMap() {
@ -35,7 +40,8 @@ class GpsData {
'lat': lat,
'lon': lon,
'is_checkin': is_checkin,
'created_at': created_at
'created_at': created_at,
'is_synced': is_synced,
};
}
}

View File

@ -72,6 +72,16 @@ ImageProvider getFinishImage() {
}
}
ImageProvider getReceiptImage() {
DestinationController destinationController =
Get.find<DestinationController>();
if (destinationController.photos.isNotEmpty) {
return FileImage(destinationController.photos[0]);
} else {
return const AssetImage('assets/images/money.png');
}
}
class CameraPage extends StatelessWidget {
bool? manulaCheckin = false;
bool? buyPointPhoto = false;
@ -454,7 +464,7 @@ class BuyPointCamera extends StatelessWidget {
height: 370,
decoration: BoxDecoration(
image: DecorationImage(
image: getFinishImage(), fit: BoxFit.cover)),
image: getReceiptImage(), fit: BoxFit.cover)),
),
),
),

View File

@ -510,7 +510,7 @@ class DestinationController extends GetxController {
lat: la,
lon: ln,
is_checkin: isCheckin,
created_at: DateTime.now().microsecondsSinceEpoch);
created_at: DateTime.now().millisecondsSinceEpoch);
var res = await db.insertGps(gps_data);
print("==gps res == ${res}");
}
@ -559,10 +559,10 @@ class DestinationController extends GetxController {
LengthUnit.Meter, LatLng(latFs, lonFs), LatLng(la, ln));
Destination des = festuretoDestination(fs);
print(
"--- position is ---- ${position.longitude}, --- ${position.longitude}----");
//print(
// "--- position is ---- ${position.longitude}, --- ${position.longitude}----");
print("--- distFs ---- $distFs, --- ${des.checkin_radious}----");
//print("--- distFs ---- $distFs, --- ${des.checkin_radious}----");
if (distFs <= des.checkin_radious! && skipGps == false) {
//print("--- 789 ---- $skip_gps----");
//near a location
@ -571,6 +571,7 @@ class DestinationController extends GetxController {
break;
}
}
pushGPStoServer();
//print("--- 123 ---- $skip_gps----");
} catch (e) {
//print("An error occurred: $e");
@ -581,6 +582,19 @@ class DestinationController extends GetxController {
}
}
Future<void> pushGPStoServer() async {
try {
await Future.delayed(const Duration(minutes: 5));
ExternalService().pushGPS();
} catch (e) {
//print("An error occurred: $e");
await pushGPStoServer();
} finally {
//print("--- End of pushGPStoServer function, calling recursively ---");
await pushGPStoServer();
}
}
void addToRogaining(double lat, double lon, int destinationId) async {
DatabaseHelper db = DatabaseHelper.instance;
List<Destination> d = await db.getDestinationById(destinationId);
@ -665,7 +679,7 @@ class DestinationController extends GetxController {
DateTime now = DateTime.now();
String formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss').format(now);
await addGPStoDB(destination.lat!, destination.lon!, isCheckin: 1);
await addGPStoDB(currentLat, currentLon, isCheckin: 1);
// print("------ checkin event $eventCode ------");
ExternalService()
@ -869,9 +883,6 @@ class DestinationController extends GetxController {
// ---------- database ------------------///
void addDestinations(Destination dest) {
// print(
// '------ destination controller in add destination ${dest.checkin_radious} ---- :::::');
DatabaseHelper db = DatabaseHelper.instance;
db.getDestinationByLatLon(dest.lat!, dest.lon!).then((value) {
if (value.isNotEmpty) {
@ -947,40 +958,16 @@ class DestinationController extends GetxController {
}
void populateDestinations() {
//print(
// "--------- destination controller populsting destinations ----------- ::::::");
DatabaseHelper db = DatabaseHelper.instance;
destinations.clear();
db.getDestinations().then((value) {
destinationCount.value = 0;
for (Destination d in value) {
// print(
// "------ destination controller populating destination-------- ${d.checkedin}-------- :::::");
//print("-----populated----- ${d.toMap()}");
destinations.add(d);
}
if (destinations.isEmpty) {
rogainingCounted.value = false;
}
// destinationCount.value = 0;
//print(
// "------ destination controller destinationcount-------- $destinationCount-------- :::::");
// MatrixService.getDestinations(value).then((mat){
// print(" matrix is ------- ${mat}");
// matrix = mat;
// try{
// getRoutePoints();
// destinationCount.value = destinations.length;
// }
// catch(_){
// skip_gps = false;
// return;
// }
// });
});
}

View File

@ -130,6 +130,26 @@ class DrawerPage extends StatelessWidget {
width: 0,
height: 0,
),
indexController.currentUser.isNotEmpty
? ListTile(
leading: const Icon(Icons.delete_forever),
title: Text("ユーザーデータを削除する".tr),
onTap: () {
String token = indexController.currentUser[0]['token'];
AuthService.deleteUser(token).then((value) {
if (value.isNotEmpty) {
indexController.logout();
Get.toNamed(AppPages.TRAVEL);
Get.snackbar("ユーザーデータを削除する",
"データを削除するためにユーザーの同意が設定されています アプリとサーバーでユーザーデータが削除されました");
}
});
},
)
: const SizedBox(
width: 0,
height: 0,
),
// ListTile(
// leading: const Icon(Icons.person),
// title: Text("profile".tr),

View File

@ -45,9 +45,16 @@ class _PermissionHandlerScreenState extends State<PermissionHandlerScreen> {
content: const SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text('このアプリでは、位置情報の収集を行います。'),
Text('ぎふナビ "アプリへようこそ!\n'),
Text('収集データ:\n'),
Text(
'岐阜ナビアプリではチェックポイントの自動チェックインの機能を可能にするために、現在地のデータが収集されます。アプリを閉じている時や、使用していないときにも収集されます。位置情報は、個人を特定できない統計的な情報として、ユーザーの個人情報とは一切結びつかない形で送信されます。お知らせの配信、位置情報の利用を許可しない場合は、この後表示されるダイアログで「許可しない」を選択してください。'),
'岐阜ナビアプリをより快適にご利用いただくために、チェックポイントの自動チェックインのための位置情報を収集しています。また、撮影した画像やチェックインした時間を収集し、チャレンジの勝者を決定します。\n'),
Text('お客様のデータの使用方法:\n'),
Text(
'お客様のデータは、アプリを改善し、競争力のある魅力的な体験を提供するのに役立ちます。お客様の位置情報と画像は、個人を特定できない統計データとして処理され、いかなる個人情報にもリンクされないようにしています\n'),
Text('お客様の管理:\n'),
Text(
'お客様はご自身のデータを完全に管理することができます。アプリの設定でいつでも同意を撤回することができます。位置情報の収集に同意しなくても、ぎふナビを楽しむことはできますが、自動チェックインや競技への参加など、一部の機能が制限されることを覚えておいてください。位置情報、画像、時刻情報の利用に同意する場合は「許可」を選択してください。許可しない場合は、「許可しない」を選択してください。あなたの選択は、アプリの他の機能を使用することに影響しません。\n'),
],
),
),

View File

@ -5,9 +5,11 @@ import 'package:intl/intl.dart';
import 'package:rogapp/model/rog.dart';
import 'package:rogapp/pages/destination/destination_controller.dart';
import 'package:rogapp/pages/index/index_controller.dart';
import 'package:rogapp/utils/database_gps.dart';
import 'package:rogapp/utils/database_helper.dart';
import 'dart:convert';
import '../model/gps_data.dart';
import '../utils/const.dart';
//
@ -340,6 +342,73 @@ class ExternalService {
return Future.value(false);
}
String timestampToTimeString(int timestamp) {
// Convert timestamp to DateTime and format it as needed
var dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
// Format dateTime to a time string (e.g., '12:00:00')
// Adjust the format as needed
return "${dateTime.hour}:${dateTime.minute}:${dateTime.second}";
}
Future<bool> pushGPS() async {
final IndexController indexController = Get.find<IndexController>();
//int userId = indexController.currentUser[0]["user"]["id"];
//print("--- Pressed -----");
String team = indexController.currentUser[0]["user"]['team_name'];
//print("--- _team : ${_team}-----");
String eventCode = indexController.currentUser[0]["user"]["event_code"];
List<GpsData> gpsDataList = [];
if (indexController.connectionStatusName.value != "wifi" &&
indexController.connectionStatusName.value != "mobile") {
return Future.value(false);
} else {
// Step 1: Fetch data from the local database
gpsDataList =
await GpsDatabaseHelper.instance.getUnsyncedGPSData(team, eventCode);
// Step 2: Transform data into the required format
var payload = {
'team_name': team,
'event_code': eventCode,
'waypoints': gpsDataList.map((gpsData) {
return {
'latitude': gpsData.lat.toString(),
'longitude': gpsData.lon.toString(),
// Convert the timestamp to a formatted time string
'time': timestampToTimeString(gpsData.created_at),
};
}).toList(),
};
print("calling push gps step 2 ${payload}");
String urlS =
'https://rogaining.sumasen.net/gifuroge/get_waypoint_datas_from_rogapp';
//print('++++++++$url');
var url = Uri.parse(urlS); // Replace with your server URL
var response = await http.post(
url,
headers: {"Content-Type": "application/json"},
body: json.encode(payload),
);
print("GPS Data res ${response.statusCode}");
if (response.statusCode == 200) {
// Handle success
// make local data as synced
await GpsDatabaseHelper.instance.setSyncData(gpsDataList);
print("GPS Data sent successfully");
} else {
// Handle error
print("Failed to send data");
}
}
return Future.value(false);
}
static Future<Map<String, dynamic>> usersEventCode(
String teamcode, String password) async {
Map<String, dynamic> res = {};

View File

@ -37,7 +37,8 @@ class GpsDatabaseHelper {
lat REAL,
lon REAL,
is_checkin int,
created_at INTEGER
created_at INTEGER,
is_synced INTEGER DEFAULT 0
)
''');
}
@ -70,4 +71,26 @@ class GpsDatabaseHelper {
print("--------- db list $gpsDatas");
return gpsDatas;
}
Future<List<GpsData>> getUnsyncedGPSData(
String team_name, String event_code) async {
Database db = await instance.database;
var gpss = await db.query('gps',
where: 'team_name = ? and event_code = ? and is_synced = 0',
whereArgs: [team_name, event_code],
orderBy: 'created_at');
return gpss.isNotEmpty ? gpss.map((e) => GpsData.fromMap(e)).toList() : [];
}
Future<void> setSyncData(List<GpsData> data) async {
Database db = await instance.database;
for (var record in data) {
await db.update(
'gps',
{'is_synced': 1},
where: 'id = ?',
whereArgs: [record.id],
);
}
}
}

View File

@ -65,6 +65,7 @@ class BottomSheetNew extends GetView<BottomSheetController> {
}
} else {
GeoJsonFeature<dynamic> gf = indexController.currentFeature[0];
print("=== photo sss ${gf.properties!["photos"]}");
if (gf.properties!["photos"] == null || gf.properties!["photos"] == "") {
return const Image(image: AssetImage('assets/images/empty_image.png'));
} else {
@ -80,9 +81,11 @@ class BottomSheetNew extends GetView<BottomSheetController> {
},
);
} else {
String imageUrl = Uri.encodeFull(
'$serverUrl/media/compressed/${gf.properties!["photos"]}');
return Image(
image: NetworkImage(
'$serverUrl/media/compressed/${gf.properties!["photos"]}',
imageUrl,
),
errorBuilder: (BuildContext context, Object exception,
StackTrace? stackTrace) {
@ -495,8 +498,7 @@ class BottomSheetNew extends GetView<BottomSheetController> {
// ),
destinationController.rogainingCounted.value == true &&
destination.cp == -1 &&
destinationController.distanceToStart() <= 500
destination.cp == -1
? ElevatedButton(
onPressed: () async {
destinationController.isAtGoal.value = true;

View File

@ -113,6 +113,7 @@ flutter:
- assets/images/japanese_fun.jpeg
- assets/images/appicon.png
- assets/images/login_image.jpg
- assets/images/money.png
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see