re factor rog

This commit is contained in:
2024-04-01 09:26:56 +05:30
parent dd36ab8399
commit edbf52825b
54 changed files with 2597 additions and 435 deletions

View File

@ -0,0 +1,397 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
class FeatureCollection {
final String type;
final List<Feature> features;
FeatureCollection({required this.type, required this.features});
factory FeatureCollection.fromJson(Map<String, dynamic> json) {
return FeatureCollection(
type: json['type'],
features:
List<Feature>.from(json['features'].map((x) => Feature.fromJson(x))),
);
}
}
class Feature {
final int id;
final String type;
final Geometry geometry;
final Properties properties;
Feature(
{required this.id,
required this.type,
required this.geometry,
required this.properties});
factory Feature.fromJson(Map<String, dynamic> json) {
return Feature(
id: json['id'],
type: json['type'],
geometry: Geometry.fromJson(json['geometry']),
properties: Properties.fromJson(json['properties']),
);
}
String toJson() => json.encode(toMap());
Map<String, dynamic> toMap() {
return {
'id': id,
'type': type,
'geometry': geometry.toMap(), // Assuming Geometry has a toMap method
'properties':
properties.toMap(), // Assuming Properties has a toMap method
};
}
Feature.fromMap(Map<String, dynamic> map)
: id = map['id'],
type = map['type'],
geometry = Geometry.fromMap(map['geometry']),
properties = Properties.fromJson(map['properties']);
static empty() {}
}
class Geometry {
final String type;
final List<List<double>> coordinates;
Geometry({required this.type, required this.coordinates});
Geometry copyWith({
String? type,
List<List<double>>? coordinates,
}) {
return Geometry(
type: type ?? this.type,
coordinates: coordinates ?? this.coordinates,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'type': type,
'coordinates': coordinates,
};
}
factory Geometry.fromMap(Map<String, dynamic> map) {
return Geometry(
type: map['type'] as String,
coordinates: List<List<double>>.from(
(map['coordinates'] as List<dynamic>).map<List<double>>(
(coordinateList) {
// Ensure 'coordinateList' is treated as a List of dynamic elements.
// Then, for each element in the list, explicitly cast or convert it to double.
return List<double>.from(coordinateList.map((coordinate) {
// 'coordinate' is dynamic, needs explicit conversion to double.
// The conversion depends on the original data type of 'coordinate';
// if it's already a number, you can use .toDouble(); if it's a String, you might need double.parse.
return double.parse(coordinate.toString());
}));
},
),
),
);
}
String toJson() => json.encode(toMap());
factory Geometry.fromJson(Map<String, dynamic> source) {
final geom = Geometry.fromMap(source);
return geom;
}
get latitude => coordinates[0][1];
get longitude => coordinates[0][0];
}
class Properties {
// Include all properties fields
final int locationId;
final String subLocId;
final double cp;
final String? name;
final String? address;
final String? phone;
final String? email;
final String? webcontents;
final String? videos;
final String? category;
final int? series;
final double? lat;
final double? lon;
final int? listOrder;
final String? photos;
final double? checkinRadious;
final bool? autoCheckin;
bool? selected = false;
bool? checkedin = false;
final double? checkinPoint;
final double? buyPoint;
final bool? hiddenLocation;
String? checkinImage;
String? buypointImage;
bool? forcedCheckin = false;
final String? tags;
Properties(
{required this.locationId,
required this.subLocId,
required this.cp,
this.name,
this.address,
this.phone,
this.email,
this.webcontents,
this.videos,
this.category,
this.series,
this.lat,
this.lon,
this.listOrder,
this.photos,
this.checkinRadious,
this.autoCheckin,
this.selected,
this.checkedin,
this.checkinPoint,
this.buyPoint,
this.hiddenLocation,
this.checkinImage,
this.buypointImage,
this.forcedCheckin,
this.tags});
factory Properties.fromJson(Map<String, dynamic> json) {
Properties prop;
try {
prop = Properties(
locationId: json['location_id'],
subLocId: json['sub_loc_id'],
cp: json['cp'],
name: json['name'] ?? '',
address: json['address'] ?? '',
phone: json['phone'] ?? '',
email: json['email'] ?? '',
webcontents: json['webcontents'] ?? '',
videos: json['videos'] ?? '',
category: json['category'] ?? '',
series: json['series'] ?? 0,
lat: json['lat'] ?? 0.0,
lon: json['lon'] ?? 0.0,
listOrder: json['list_order'] ?? 0,
photos: json['photos'] ?? '',
checkinRadious: json['checkin_radious'] ?? 0.0,
autoCheckin: json['auto_checkin'] == 0 ? false : true,
selected: json['selected'] == 0 ? false : true,
checkedin: json['checkedin'] == 0 ? false : true,
checkinPoint: json['checkin_point'] ?? 0.0,
buyPoint: json['buy_point'] ?? 0.0,
hiddenLocation: json['hidden_location'] == 0 ? false : true,
checkinImage: json['checkin_image'] ?? '',
buypointImage: json['buypoint_image'] ?? '',
forcedCheckin: json['forced_checkin'] == 0 ? false : true,
tags: json['tags'] ?? '');
//print("from json --- $prop");
} catch (e) {
//print("from json --- $e");
return Properties(locationId: 0, subLocId: '', cp: 0.0, name: '');
}
return prop;
}
factory Properties.toJson(Properties prop) {
return Properties(
locationId: prop.locationId,
subLocId: prop.subLocId,
cp: prop.cp,
name: prop.name,
address: prop.address,
phone: prop.phone,
email: prop.email,
webcontents: prop.webcontents,
videos: prop.videos,
category: prop.category,
series: prop.series,
lat: prop.lat,
lon: prop.lon,
listOrder: prop.listOrder,
photos: prop.photos,
checkinRadious: prop.checkinRadious,
autoCheckin: prop.autoCheckin,
selected: prop.selected,
checkedin: prop.checkedin,
checkinPoint: prop.checkinPoint,
buyPoint: prop.buyPoint,
hiddenLocation: prop.hiddenLocation,
checkinImage: prop.checkinImage,
buypointImage: prop.buypointImage,
forcedCheckin: prop.forcedCheckin,
tags: prop.tags);
}
Properties copyWith({
int? locationId,
String? subLocId,
double? cp,
String? name,
String? address,
String? phone,
String? email,
String? webcontents,
String? videos,
String? category,
int? series,
double? lat,
double? lon,
int? listOrder,
String? photos,
double? checkinRadious,
bool? autoCheckin,
bool? selected,
bool? checkedin,
double? checkinPoint,
double? buyPoint,
bool? hiddenLocation,
String? checkinImage,
String? buypointImage,
bool? forcedCheckin,
String? tags,
}) {
return Properties(
locationId: locationId ?? this.locationId,
subLocId: subLocId ?? this.subLocId,
cp: cp ?? this.cp,
name: name ?? this.name,
address: address ?? this.address,
phone: phone ?? this.phone,
email: email ?? this.email,
webcontents: webcontents ?? this.webcontents,
videos: videos ?? this.videos,
category: category ?? this.category,
series: series ?? this.series,
lat: lat ?? this.lat,
lon: lon ?? this.lon,
listOrder: listOrder ?? this.listOrder,
photos: photos ?? this.photos,
checkinRadious: checkinRadious ?? this.checkinRadious,
autoCheckin: autoCheckin ?? this.autoCheckin,
selected: selected ?? this.selected,
checkedin: checkedin ?? this.checkedin,
checkinPoint: checkinPoint ?? this.checkinPoint,
buyPoint: buyPoint ?? this.buyPoint,
hiddenLocation: hiddenLocation ?? this.hiddenLocation,
checkinImage: checkinImage ?? this.checkinImage,
buypointImage: buypointImage ?? this.buypointImage,
forcedCheckin: forcedCheckin ?? this.forcedCheckin,
tags: tags ?? this.tags,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'locationId': locationId,
'subLocId': subLocId,
'cp': cp,
'name': name,
'address': address,
'phone': phone,
'email': email,
'webcontents': webcontents,
'videos': videos,
'category': category,
'series': series,
'lat': lat,
'lon': lon,
'listOrder': listOrder,
'photos': photos,
'checkinRadious': checkinRadious,
'autoCheckin': autoCheckin,
'selected': selected,
'checkedin': checkedin,
'checkinPoint': checkinPoint,
'buyPoint': buyPoint,
'hiddenLocation': hiddenLocation,
'checkinImage': checkinImage,
'buypointImage': buypointImage,
'forcedCheckin': forcedCheckin,
'tags': tags,
};
}
String toJson() => json.encode(toMap());
@override
String toString() {
return 'Properties(locationId: $locationId, subLocId: $subLocId, cp: $cp, name: $name, address: $address, phone: $phone, email: $email, webcontents: $webcontents, videos: $videos, category: $category, series: $series, lat: $lat, lon: $lon, listOrder: $listOrder, photos: $photos, checkinRadious: $checkinRadious, autoCheckin: $autoCheckin, selected: $selected, checkedin: $checkedin, checkinPoint: $checkinPoint, buyPoint: $buyPoint, hiddenLocation: $hiddenLocation, checkinImage: $checkinImage, buypointImage: $buypointImage, forcedCheckin: $forcedCheckin, tags: $tags)';
}
@override
bool operator ==(covariant Properties other) {
if (identical(this, other)) return true;
return other.locationId == locationId &&
other.subLocId == subLocId &&
other.cp == cp &&
other.name == name &&
other.address == address &&
other.phone == phone &&
other.email == email &&
other.webcontents == webcontents &&
other.videos == videos &&
other.category == category &&
other.series == series &&
other.lat == lat &&
other.lon == lon &&
other.listOrder == listOrder &&
other.photos == photos &&
other.checkinRadious == checkinRadious &&
other.autoCheckin == autoCheckin &&
other.selected == selected &&
other.checkedin == checkedin &&
other.checkinPoint == checkinPoint &&
other.buyPoint == buyPoint &&
other.hiddenLocation == hiddenLocation &&
other.checkinImage == checkinImage &&
other.buypointImage == buypointImage &&
other.forcedCheckin == forcedCheckin &&
other.tags == tags;
}
@override
int get hashCode {
return locationId.hashCode ^
subLocId.hashCode ^
cp.hashCode ^
name.hashCode ^
address.hashCode ^
phone.hashCode ^
email.hashCode ^
webcontents.hashCode ^
videos.hashCode ^
category.hashCode ^
series.hashCode ^
lat.hashCode ^
lon.hashCode ^
listOrder.hashCode ^
photos.hashCode ^
checkinRadious.hashCode ^
autoCheckin.hashCode ^
selected.hashCode ^
checkedin.hashCode ^
checkinPoint.hashCode ^
buyPoint.hashCode ^
hiddenLocation.hashCode ^
checkinImage.hashCode ^
buypointImage.hashCode ^
forcedCheckin.hashCode ^
tags.hashCode;
}
}

View File

@ -0,0 +1,82 @@
import 'dart:convert';
class CheckpointVisit {
final String id;
final String checkpointId;
final String teamName;
final String userName;
final String eventCode;
final DateTime visitTime;
CheckpointVisit({
required this.id,
required this.checkpointId,
required this.teamName,
required this.userName,
required this.eventCode,
required this.visitTime,
});
CheckpointVisit copyWith({
String? id,
String? checkpointId,
String? teamName,
String? userName,
String? eventCode,
DateTime? visitTime,
}) {
return CheckpointVisit(
id: id ?? this.id,
checkpointId: checkpointId ?? this.checkpointId,
teamName: teamName ?? this.teamName,
userName: userName ?? this.userName,
eventCode: eventCode ?? this.eventCode,
visitTime: visitTime ?? this.visitTime,
);
}
Map<String, dynamic> toMap() {
return {
'id': id,
'checkpointId': checkpointId,
'teamName': teamName,
'userName': userName,
'eventCode': eventCode,
'visitTime': visitTime.millisecondsSinceEpoch,
};
}
factory CheckpointVisit.fromMap(Map<String, dynamic> map) {
return CheckpointVisit(
id: map['id'],
checkpointId: map['checkpointId'],
teamName: map['teamName'],
userName: map['userName'],
eventCode: map['eventCode'],
visitTime: DateTime.fromMillisecondsSinceEpoch(map['visitTime']),
);
}
String toJson() => json.encode(toMap());
factory CheckpointVisit.fromJson(String source) =>
CheckpointVisit.fromMap(json.decode(source));
@override
String toString() {
return 'CheckpointVisit(id: $id, checkpointId: $checkpointId, teamName: $teamName, userName: $userName, eventCode: $eventCode, visitTime: $visitTime)';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is CheckpointVisit &&
other.id == id &&
other.checkpointId == checkpointId &&
other.teamName == teamName &&
other.userName == userName &&
other.eventCode == eventCode &&
other.visitTime == visitTime;
}
}

View File

@ -0,0 +1,329 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import 'package:rogapp/features/data/checkpoint.dart';
import 'package:rogapp/features/data/user_location.dart';
final dataProviderProvider = Provider<DataProvider>((ref) {
return DataProvider();
});
// Convert a Feature object to a Map
Map<String, dynamic> featureToMap(Feature feature) {
var properties = feature.properties;
try {
return {
'id': feature.id,
'type': feature.type,
'name': properties.name ?? '',
'address': properties.address ?? '',
'phone': properties.phone ?? '',
'email': properties.email ?? '',
'webcontents': properties.webcontents ?? '',
'videos': properties.videos ?? '',
'category': properties.category ?? '',
'series': properties.series,
'lat': feature.geometry.latitude,
'lon': feature.geometry.longitude,
'list_order': properties.listOrder,
'photos': properties.photos ?? '',
'checkin_radious': properties.checkinRadious,
'sub_loc_id': properties.subLocId,
'auto_checkin': properties.autoCheckin! ? 1 : 0,
'selected': properties.selected == null
? 0
: properties.selected!
? 1
: 0,
'checkedin': properties.checkedin == null
? 0
: properties.checkedin!
? 1
: 0,
'cp': properties.cp,
'checkin_point': properties.checkinPoint,
'buy_point': properties.buyPoint,
'hidden_location': properties.hiddenLocation,
'checkin_image': properties.checkinImage,
'buypoint_image': properties.buypointImage,
'forced_checkin': properties.forcedCheckin == null
? 0
: properties.forcedCheckin!
? 1
: 0,
'tags': properties.tags ?? '',
'location_id': properties.locationId,
};
} catch (e) {
//print("--- feature to map Error: $e");
return {};
}
}
// Convert a Map to a Feature object
Feature mapToFeature(Map<String, dynamic> map) {
Feature feat;
//print("mapToFeature id --- ${Properties.fromJson(map)}");
//print("mapToFeature --- ${map['type']}");
feat = Feature(
id: map['id'],
type: map['type'],
geometry: Geometry(
type: map['type'] ?? 'Point',
coordinates: [
[map['lon'], map['lat']]
],
),
properties: Properties.fromJson(map),
);
//print("mapToFeature --- $feat");
return feat;
}
class DataProvider {
static Database? _database;
Future<Database> get database async {
if (_database != null) return _database!;
_database = await initDB();
return _database!;
}
initDB() async {
var documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "GameDB.db");
return await openDatabase(path,
version: 1, onOpen: (db) {}, onCreate: _onCreate);
}
_onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE Checkpoints (
location_id INTEGER PRIMARY KEY,
id INTEGER,
type TEXT,
name TEXT,
address TEXT,
phone TEXT,
email TEXT,
webcontents TEXT,
videos TEXT,
category TEXT,
series INTEGER,
lat REAL,
lon REAL,
list_order INTEGER,
photos TEXT,
checkin_radious REAL,
sub_loc_id TEXT,
auto_checkin INTEGER,
selected INTEGER,
checkedin INTEGER,
cp REAL,
checkin_point REAL,
buy_point REAL,
hidden_location INTEGER,
checkin_image TEXT,
buypoint_image TEXT,
forced_checkin INTEGER,
recipt_times INTEGER,
tags TEXT
)
''');
await db.execute('''
CREATE TABLE GPSLocations (
timestamp TEXT PRIMARY KEY,
latitude REAL,
longitude REAL,
event_code TEXT,
team_name TEXT,
user_name TEXT,
attempt_count INTEGER
)
''');
await db.execute('''
CREATE TABLE GameState (
key TEXT PRIMARY KEY,
value TEXT,
event_code TEXT,
team_name TEXT,
user_name TEXT,
attempt_count INTEGER
)
''');
await db.execute('''
CREATE TABLE CheckpointVisits (
id INTEGER PRIMARY KEY AUTOINCREMENT,
checkpointId INTEGER,
photoTaken BOOLEAN,
receiptPhotoTaken BOOLEAN,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
event_code TEXT,
team_name TEXT,
user_name TEXT,
attempt_count INTEGER DEFAULT 1,
FOREIGN KEY (checkpointId) REFERENCES Checkpoints(location_id)
)
''');
}
Future<void> recordCheckpointVisit(
int locationId, String userName, String teamName, String eventCode,
{bool photoTaken = false, bool? receiptPhotoTaken}) async {
final db = await database;
// Fetching buy_point to determine if a receipt is required
var checkpointQueryResult = await db.query(
'Checkpoints',
columns: ['buy_point'],
where: 'location_id = ?',
whereArgs: [locationId],
);
var buyPoint = checkpointQueryResult.isNotEmpty
? checkpointQueryResult.first['buy_point'] as double?
: null;
var requiresReceipt = buyPoint != null && buyPoint > 0.0;
await db.insert(
'CheckpointVisits',
{
'checkpointId': locationId,
'user_name': userName,
'team_name': teamName,
'event_code': eventCode,
'photoTaken': photoTaken ? 1 : 0,
'receiptPhotoTaken':
requiresReceipt ? (receiptPhotoTaken == true ? 1 : 0) : null,
},
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<Map<String, dynamic>> getIncompleteTasks(int locationId,
String userName, String teamName, String eventCode) async {
final db = await database;
var checkpoint = await db.query(
'Checkpoints',
where: 'location_id = ?',
whereArgs: [locationId],
);
var buyPointValue =
checkpoint.isNotEmpty ? checkpoint.first['buy_point'] as double? : null;
var requiresReceipt = buyPointValue != null && buyPointValue > 0.0;
// Fetch visits considering all relevant identifiers
List<Map> visits = await db.query(
'CheckpointVisits',
where:
'checkpointId = ? AND user_name = ? AND team_name = ? AND event_code = ?',
whereArgs: [locationId, userName, teamName, eventCode],
);
if (visits.isNotEmpty) {
var lastVisit = visits.last;
return {
'photoTaken': lastVisit['photoTaken'] == 1,
'receiptPhotoTaken':
requiresReceipt ? lastVisit['receiptPhotoTaken'] == 1 : true,
};
}
// Default return values when no visits found
return {
'photoTaken': false,
'receiptPhotoTaken': requiresReceipt ? false : true,
};
}
Future<void> insertMarker(Feature marker) async {
//print("--- inserting ${featureToMap(marker)} ---");
final db = await database;
try {
await db.insert(
'Checkpoints',
featureToMap(marker),
conflictAlgorithm: ConflictAlgorithm.replace,
);
} catch (e) {
print("--- ${e.toString()} ---");
}
}
Future<List<Feature>> getMarkers() async {
final db = await database;
var res = await db.query('Checkpoints');
List<Feature> list =
res.isNotEmpty ? res.map((c) => mapToFeature(c)).toList() : [];
//print("--- checkpoints ${res} ---");
return list;
}
Future<int> deleteMarker(int id) async {
final db = await database;
return db.delete('Checkpoints', where: 'id = ?', whereArgs: [id]);
}
Future<void> insertGPSLocation(UserLocation location) async {
final db = await database;
await db.insert(
'GPSLocations',
location
.toMap(), // Implement a method in UserLocation to convert the object to a Map
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<List<UserLocation>> getGPSLocations() async {
final db = await database;
var res = await db.query('GPSLocations');
List<UserLocation> locations =
res.isNotEmpty ? res.map((c) => UserLocation.fromMap(c)).toList() : [];
return locations;
}
Future<void> updateGameState(
String key,
String value,
String userName,
String teamName,
String eventCode,
) async {
final db = await database;
await db.insert(
'GameState',
{
'key': key,
'value': value,
'team_name': teamName,
'event_code': eventCode,
'user_name': userName,
},
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<String?> getGameState(
String key,
String userName,
String teamName,
String eventCode,
) async {
final db = await database;
List<Map<String, dynamic>> results = await db.query(
'GameState',
where: 'key = ? AND team_name = ? AND event_code = ? AND user_name = ?',
whereArgs: [key, teamName, eventCode, userName],
);
if (results.isNotEmpty) {
return results.first['value'] as String?;
}
return null;
}
}

View File

@ -0,0 +1,17 @@
enum EventType {
atStart,
starting,
started,
inCheckin,
checkiningIn,
checkedIn,
atGoal,
finishingGoal,
finishedGoal,
}
class GameEvent {
final EventType type;
final DateTime timestamp;
GameEvent({this.type = EventType.atStart, required this.timestamp});
}

View File

@ -0,0 +1,24 @@
class User {
User.User();
//AuthUser.from({required this.id, required this.email, required this.is_rogaining, required this.group, required this.zekken_number, required this.event_code, required this.team_name});
User.fromMap(Map<String, dynamic> map)
: id = int.parse(map["id"].toString()),
email = map["email"].toString(),
is_rogaining = bool.parse(map["is_rogaining"].toString()),
group = map["group"].toString(),
zekken_number = map["zekken_number"].toString(),
event_code = map["event_code"].toString(),
team_name = map["team_name"].toString(),
auth_token = map["token"];
int? id;
String? email;
bool? is_rogaining;
String? group;
String? zekken_number;
String? event_code;
String? team_name;
String? auth_token;
}

View File

@ -0,0 +1,59 @@
import 'dart:convert';
import 'package:geolocator/geolocator.dart';
// ignore_for_file: public_member_api_docs, sort_constructors_first
class UserLocation {
final double latitude;
final double longitude;
final DateTime timestamp;
UserLocation(
{required this.latitude,
required this.longitude,
required this.timestamp});
static UserLocation empty() {
return UserLocation(
latitude: 0.0, longitude: 0.0, timestamp: DateTime.now());
}
factory UserLocation.fromPosition(Position position) {
return UserLocation(
latitude: position.latitude,
longitude: position.longitude,
timestamp: position.timestamp);
}
UserLocation copyWith({
double? latitude,
double? longitude,
DateTime? timestamp,
}) {
return UserLocation(
latitude: latitude ?? this.latitude,
longitude: longitude ?? this.longitude,
timestamp: timestamp ?? this.timestamp,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'latitude': latitude,
'longitude': longitude,
'timestamp': timestamp.millisecondsSinceEpoch,
};
}
factory UserLocation.fromMap(Map<String, dynamic> map) {
return UserLocation(
latitude: map['latitude'] as double,
longitude: map['longitude'] as double,
timestamp: DateTime.fromMillisecondsSinceEpoch(map['timestamp'] as int),
);
}
String toJson() => json.encode(toMap());
factory UserLocation.fromJson(String source) =>
UserLocation.fromMap(json.decode(source) as Map<String, dynamic>);
}