diff --git a/android/app/build.gradle b/android/app/build.gradle index e06b32e..aa13dcd 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -25,6 +25,7 @@ if (flutterVersionName == null) { android { namespace "com.example.uninav" compileSdk flutter.compileSdkVersion + compileSdkVersion 34 ndkVersion flutter.ndkVersion compileOptions { @@ -45,7 +46,8 @@ android { applicationId "com.example.uninav" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion flutter.minSdkVersion + // minSdkVersion flutter.minSdkVersion + minSdkVersion 20 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 3de0347..f78e775 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -41,4 +41,6 @@ + + diff --git a/assets/geo/uulm_beta.geojson b/assets/geo/uulm_beta.geojson index 2a9def8..a13f1c9 100644 --- a/assets/geo/uulm_beta.geojson +++ b/assets/geo/uulm_beta.geojson @@ -384,7 +384,7 @@ "properties": { "name": "O25", "layer": "buildings", - "description": "connections: [o26, mensa]" + "description": "connections: [o26, mensa, outside]" }, "geometry": { "type": "Polygon", @@ -2432,6 +2432,38 @@ ] }, "id": "gzMDI" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 2\nconnects: [o25, outside]", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955606, + 48.422081 + ] + }, + "id": "I5NTI" + }, + { + "type": "Feature", + "properties": { + "name": "door", + "description": "type: door\nlevel: 2\nconnects: [o25, mensa]", + "layer": "layer_2" + }, + "geometry": { + "type": "Point", + "coordinates": [ + 9.955426, + 48.422062 + ] + }, + "id": "c1NDY" } ] } \ No newline at end of file diff --git a/lib/components/feature_bottom_sheet.dart b/lib/components/feature_bottom_sheet.dart index e8a7ba5..64ef7ef 100644 --- a/lib/components/feature_bottom_sheet.dart +++ b/lib/components/feature_bottom_sheet.dart @@ -107,7 +107,9 @@ List _buildFeatureContent(Feature feature) { return feature.type.when( building: () => _buildBuildingContent(feature), lectureHall: () => _buildLectureHallContent(feature), - room: () => _buildRoomContent(feature), + room: (number) => _buildRoomContent(feature, number), + pcPool: (number) => _buildPcPoolContent(feature, number), + foodDrink: () => _buildFoodAndDrinkContent(feature), door: (connects) => _buildDoorContent(feature, connects), toilet: (toiletType) => _buildToiletContent(feature, toiletType), stairs: (connectsLevels) => _buildStairsContent(feature, connectsLevels), @@ -130,10 +132,18 @@ List _buildLectureHallContent(Feature feature) { } /// Builds the content for the Room feature type. -List _buildRoomContent(Feature feature) { +List _buildRoomContent(Feature feature, String roomNumber) { return [Text('Room: ${feature.name}')]; } +List _buildPcPoolContent(Feature feature, String roomNumber) { + return [Text('PC Pool: ${feature.name}')]; +} + +List _buildFoodAndDrinkContent(Feature feature) { + return [Text('${feature.name} (Food/Drink)')]; +} + /// Builds the content for the Door feature type. List _buildDoorContent(Feature feature, List connects) { return [ diff --git a/lib/components/map_render_level.dart b/lib/components/map_render_level.dart index c818467..b997666 100644 --- a/lib/components/map_render_level.dart +++ b/lib/components/map_render_level.dart @@ -14,6 +14,7 @@ List renderLevel( int level, ) { return [ + // Lecture Halls LevelLayer( filter: (feature) => feature.level == level && feature.type is LectureHall, @@ -43,19 +44,39 @@ List renderLevel( alignment: Alignment.center, ), ), + + // Rooms (Seminar Rooms) LevelLayer( - filter: (feature) => feature.level == level && feature.type is Room, - polyConstructor: (feature) => feature - .getPolygon( - constructor: (pts) => Polygon( - points: pts, - color: Colors.green.withOpacity(1.2), - borderColor: Colors.green, - borderStrokeWidth: 2, - ), - ) - .unwrap(), - ), + filter: (feature) => feature.level == level && feature.type is Room, + polyConstructor: (feature) => feature + .getPolygon( + constructor: (pts) => Polygon( + points: pts, + color: Colors.green.withOpacity(1.2), + borderColor: Colors.green, + borderStrokeWidth: 2, + ), + ) + .unwrap(), + markerConstructor: (feature) => Marker( + width: 100, + height: 70, + point: feature.getPoint().unwrap(), + child: Column( + children: [ + const Icon( + Icons.co_present_rounded, + color: Colors.amber, + ), + Text( + (feature.type as Room).roomNumber, + style: const TextStyle(color: Colors.black), + ), + ], + ), + alignment: Alignment.center, + )), + // Doors Layer LevelLayer( filter: (feature) => feature.level == level && feature.type is Door, markerConstructor: (feature) { @@ -72,6 +93,72 @@ List renderLevel( ); }, ), + + // Food and Drink Layer + LevelLayer( + filter: (feature) => feature.level == level && feature.type is FoodDrink, + markerConstructor: (feature) { + final point = feature.getPoint().unwrap(); + return Marker( + width: 21, + height: 21, + point: point, + child: const Icon( + Icons.restaurant, + color: Colors.deepOrange, + ), + alignment: Alignment.center, + ); + }, + polyConstructor: (feature) => feature + .getPolygon( + constructor: (pts) => Polygon( + points: pts, + color: Colors.deepOrange.withOpacity(0.2), + borderColor: Colors.deepOrange, + borderStrokeWidth: 2, + ), + ) + .unwrap(), + ), + + // PC Pools layer + LevelLayer( + filter: (feature) => feature.level == level && feature.type is PcPool, + markerConstructor: (feature) { + final point = feature.getPoint().unwrap(); + return Marker( + width: 100, + height: 70, + point: point, + child: Column( + children: [ + const Icon( + Icons.computer, + color: Colors.cyan, + ), + Text( + (feature.type as PcPool).roomNumber, + style: const TextStyle(color: Colors.black), + ), + ], + ), + alignment: Alignment.center, + ); + }, + polyConstructor: (feature) => feature + .getPolygon( + constructor: (pts) => Polygon( + points: pts, + color: Colors.cyan.withOpacity(0.2), + borderColor: Colors.cyan, + borderStrokeWidth: 2, + ), + ) + .unwrap(), + ), + + // Toilets Layer LevelLayer( filter: (feature) => feature.level == level && feature.type is Toilet, markerConstructor: (feature) { @@ -84,12 +171,14 @@ List renderLevel( point: point, child: Icon( findToiletIcon(type), - color: Colors.purple, + color: Colors.blue.shade700, ), alignment: Alignment.center, ); }, ), + + // Stairs layer LevelLayer( filter: (feature) => feature.type is Stairs && @@ -108,6 +197,8 @@ List renderLevel( ); }, ), + + // Lift layer LevelLayer( filter: (feature) => feature.type is Lift && diff --git a/lib/controllers/isar_controller.dart b/lib/controllers/isar_controller.dart.old similarity index 100% rename from lib/controllers/isar_controller.dart rename to lib/controllers/isar_controller.dart.old diff --git a/lib/controllers/isar_controller.g.dart b/lib/controllers/isar_controller.g.dart deleted file mode 100644 index 58a09bd..0000000 --- a/lib/controllers/isar_controller.g.dart +++ /dev/null @@ -1,910 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'isar_controller.dart'; - -// ************************************************************************** -// IsarCollectionGenerator -// ************************************************************************** - -// coverage:ignore-file -// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types - -extension GetSettingsCollection on Isar { - IsarCollection get settings => this.collection(); -} - -const SettingsSchema = CollectionSchema( - name: r'Settings', - id: -8656046621518759136, - properties: { - r'femaleToilets': PropertySchema( - id: 0, - name: r'femaleToilets', - type: IsarType.bool, - ), - r'handicapToilets': PropertySchema( - id: 1, - name: r'handicapToilets', - type: IsarType.bool, - ), - r'maleToilets': PropertySchema( - id: 2, - name: r'maleToilets', - type: IsarType.bool, - ), - r'showComputerPools': PropertySchema( - id: 3, - name: r'showComputerPools', - type: IsarType.bool, - ), - r'showDoors': PropertySchema( - id: 4, - name: r'showDoors', - type: IsarType.bool, - ), - r'showElevators': PropertySchema( - id: 5, - name: r'showElevators', - type: IsarType.bool, - ), - r'showFoodAndDrink': PropertySchema( - id: 6, - name: r'showFoodAndDrink', - type: IsarType.bool, - ), - r'showIcons': PropertySchema( - id: 7, - name: r'showIcons', - type: IsarType.bool, - ), - r'showLectureHalls': PropertySchema( - id: 8, - name: r'showLectureHalls', - type: IsarType.bool, - ), - r'showSeminarRooms': PropertySchema( - id: 9, - name: r'showSeminarRooms', - type: IsarType.bool, - ), - r'showStairs': PropertySchema( - id: 10, - name: r'showStairs', - type: IsarType.bool, - ), - r'showToilets': PropertySchema( - id: 11, - name: r'showToilets', - type: IsarType.bool, - ) - }, - estimateSize: _settingsEstimateSize, - serialize: _settingsSerialize, - deserialize: _settingsDeserialize, - deserializeProp: _settingsDeserializeProp, - idName: r'id', - indexes: {}, - links: {}, - embeddedSchemas: {}, - getId: _settingsGetId, - getLinks: _settingsGetLinks, - attach: _settingsAttach, - version: '3.1.0+1', -); - -int _settingsEstimateSize( - Settings object, - List offsets, - Map> allOffsets, -) { - var bytesCount = offsets.last; - return bytesCount; -} - -void _settingsSerialize( - Settings object, - IsarWriter writer, - List offsets, - Map> allOffsets, -) { - writer.writeBool(offsets[0], object.femaleToilets); - writer.writeBool(offsets[1], object.handicapToilets); - writer.writeBool(offsets[2], object.maleToilets); - writer.writeBool(offsets[3], object.showComputerPools); - writer.writeBool(offsets[4], object.showDoors); - writer.writeBool(offsets[5], object.showElevators); - writer.writeBool(offsets[6], object.showFoodAndDrink); - writer.writeBool(offsets[7], object.showIcons); - writer.writeBool(offsets[8], object.showLectureHalls); - writer.writeBool(offsets[9], object.showSeminarRooms); - writer.writeBool(offsets[10], object.showStairs); - writer.writeBool(offsets[11], object.showToilets); -} - -Settings _settingsDeserialize( - Id id, - IsarReader reader, - List offsets, - Map> allOffsets, -) { - final object = Settings(); - object.femaleToilets = reader.readBool(offsets[0]); - object.handicapToilets = reader.readBool(offsets[1]); - object.id = id; - object.maleToilets = reader.readBool(offsets[2]); - object.showComputerPools = reader.readBool(offsets[3]); - object.showDoors = reader.readBool(offsets[4]); - object.showElevators = reader.readBool(offsets[5]); - object.showFoodAndDrink = reader.readBool(offsets[6]); - object.showIcons = reader.readBool(offsets[7]); - object.showLectureHalls = reader.readBool(offsets[8]); - object.showSeminarRooms = reader.readBool(offsets[9]); - object.showStairs = reader.readBool(offsets[10]); - object.showToilets = reader.readBool(offsets[11]); - return object; -} - -P _settingsDeserializeProp

( - IsarReader reader, - int propertyId, - int offset, - Map> allOffsets, -) { - switch (propertyId) { - case 0: - return (reader.readBool(offset)) as P; - case 1: - return (reader.readBool(offset)) as P; - case 2: - return (reader.readBool(offset)) as P; - case 3: - return (reader.readBool(offset)) as P; - case 4: - return (reader.readBool(offset)) as P; - case 5: - return (reader.readBool(offset)) as P; - case 6: - return (reader.readBool(offset)) as P; - case 7: - return (reader.readBool(offset)) as P; - case 8: - return (reader.readBool(offset)) as P; - case 9: - return (reader.readBool(offset)) as P; - case 10: - return (reader.readBool(offset)) as P; - case 11: - return (reader.readBool(offset)) as P; - default: - throw IsarError('Unknown property with id $propertyId'); - } -} - -Id _settingsGetId(Settings object) { - return object.id; -} - -List> _settingsGetLinks(Settings object) { - return []; -} - -void _settingsAttach(IsarCollection col, Id id, Settings object) { - object.id = id; -} - -extension SettingsQueryWhereSort on QueryBuilder { - QueryBuilder anyId() { - return QueryBuilder.apply(this, (query) { - return query.addWhereClause(const IdWhereClause.any()); - }); - } -} - -extension SettingsQueryWhere on QueryBuilder { - QueryBuilder idEqualTo(Id id) { - return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: id, - upper: id, - )); - }); - } - - QueryBuilder idNotEqualTo(Id id) { - return QueryBuilder.apply(this, (query) { - if (query.whereSort == Sort.asc) { - return query - .addWhereClause( - IdWhereClause.lessThan(upper: id, includeUpper: false), - ) - .addWhereClause( - IdWhereClause.greaterThan(lower: id, includeLower: false), - ); - } else { - return query - .addWhereClause( - IdWhereClause.greaterThan(lower: id, includeLower: false), - ) - .addWhereClause( - IdWhereClause.lessThan(upper: id, includeUpper: false), - ); - } - }); - } - - QueryBuilder idGreaterThan(Id id, - {bool include = false}) { - return QueryBuilder.apply(this, (query) { - return query.addWhereClause( - IdWhereClause.greaterThan(lower: id, includeLower: include), - ); - }); - } - - QueryBuilder idLessThan(Id id, - {bool include = false}) { - return QueryBuilder.apply(this, (query) { - return query.addWhereClause( - IdWhereClause.lessThan(upper: id, includeUpper: include), - ); - }); - } - - QueryBuilder idBetween( - Id lowerId, - Id upperId, { - bool includeLower = true, - bool includeUpper = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addWhereClause(IdWhereClause.between( - lower: lowerId, - includeLower: includeLower, - upper: upperId, - includeUpper: includeUpper, - )); - }); - } -} - -extension SettingsQueryFilter - on QueryBuilder { - QueryBuilder femaleToiletsEqualTo( - bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'femaleToilets', - value: value, - )); - }); - } - - QueryBuilder - handicapToiletsEqualTo(bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'handicapToilets', - value: value, - )); - }); - } - - QueryBuilder idEqualTo(Id value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'id', - value: value, - )); - }); - } - - QueryBuilder idGreaterThan( - Id value, { - bool include = false, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.greaterThan( - include: include, - property: r'id', - value: value, - )); - }); - } - - QueryBuilder idLessThan( - Id value, { - bool include = false, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.lessThan( - include: include, - property: r'id', - value: value, - )); - }); - } - - QueryBuilder idBetween( - Id lower, - Id upper, { - bool includeLower = true, - bool includeUpper = true, - }) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.between( - property: r'id', - lower: lower, - includeLower: includeLower, - upper: upper, - includeUpper: includeUpper, - )); - }); - } - - QueryBuilder maleToiletsEqualTo( - bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'maleToilets', - value: value, - )); - }); - } - - QueryBuilder - showComputerPoolsEqualTo(bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'showComputerPools', - value: value, - )); - }); - } - - QueryBuilder showDoorsEqualTo( - bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'showDoors', - value: value, - )); - }); - } - - QueryBuilder showElevatorsEqualTo( - bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'showElevators', - value: value, - )); - }); - } - - QueryBuilder - showFoodAndDrinkEqualTo(bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'showFoodAndDrink', - value: value, - )); - }); - } - - QueryBuilder showIconsEqualTo( - bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'showIcons', - value: value, - )); - }); - } - - QueryBuilder - showLectureHallsEqualTo(bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'showLectureHalls', - value: value, - )); - }); - } - - QueryBuilder - showSeminarRoomsEqualTo(bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'showSeminarRooms', - value: value, - )); - }); - } - - QueryBuilder showStairsEqualTo( - bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'showStairs', - value: value, - )); - }); - } - - QueryBuilder showToiletsEqualTo( - bool value) { - return QueryBuilder.apply(this, (query) { - return query.addFilterCondition(FilterCondition.equalTo( - property: r'showToilets', - value: value, - )); - }); - } -} - -extension SettingsQueryObject - on QueryBuilder {} - -extension SettingsQueryLinks - on QueryBuilder {} - -extension SettingsQuerySortBy on QueryBuilder { - QueryBuilder sortByFemaleToilets() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'femaleToilets', Sort.asc); - }); - } - - QueryBuilder sortByFemaleToiletsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'femaleToilets', Sort.desc); - }); - } - - QueryBuilder sortByHandicapToilets() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'handicapToilets', Sort.asc); - }); - } - - QueryBuilder sortByHandicapToiletsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'handicapToilets', Sort.desc); - }); - } - - QueryBuilder sortByMaleToilets() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'maleToilets', Sort.asc); - }); - } - - QueryBuilder sortByMaleToiletsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'maleToilets', Sort.desc); - }); - } - - QueryBuilder sortByShowComputerPools() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showComputerPools', Sort.asc); - }); - } - - QueryBuilder sortByShowComputerPoolsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showComputerPools', Sort.desc); - }); - } - - QueryBuilder sortByShowDoors() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showDoors', Sort.asc); - }); - } - - QueryBuilder sortByShowDoorsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showDoors', Sort.desc); - }); - } - - QueryBuilder sortByShowElevators() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showElevators', Sort.asc); - }); - } - - QueryBuilder sortByShowElevatorsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showElevators', Sort.desc); - }); - } - - QueryBuilder sortByShowFoodAndDrink() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showFoodAndDrink', Sort.asc); - }); - } - - QueryBuilder sortByShowFoodAndDrinkDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showFoodAndDrink', Sort.desc); - }); - } - - QueryBuilder sortByShowIcons() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showIcons', Sort.asc); - }); - } - - QueryBuilder sortByShowIconsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showIcons', Sort.desc); - }); - } - - QueryBuilder sortByShowLectureHalls() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showLectureHalls', Sort.asc); - }); - } - - QueryBuilder sortByShowLectureHallsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showLectureHalls', Sort.desc); - }); - } - - QueryBuilder sortByShowSeminarRooms() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showSeminarRooms', Sort.asc); - }); - } - - QueryBuilder sortByShowSeminarRoomsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showSeminarRooms', Sort.desc); - }); - } - - QueryBuilder sortByShowStairs() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showStairs', Sort.asc); - }); - } - - QueryBuilder sortByShowStairsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showStairs', Sort.desc); - }); - } - - QueryBuilder sortByShowToilets() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showToilets', Sort.asc); - }); - } - - QueryBuilder sortByShowToiletsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showToilets', Sort.desc); - }); - } -} - -extension SettingsQuerySortThenBy - on QueryBuilder { - QueryBuilder thenByFemaleToilets() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'femaleToilets', Sort.asc); - }); - } - - QueryBuilder thenByFemaleToiletsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'femaleToilets', Sort.desc); - }); - } - - QueryBuilder thenByHandicapToilets() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'handicapToilets', Sort.asc); - }); - } - - QueryBuilder thenByHandicapToiletsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'handicapToilets', Sort.desc); - }); - } - - QueryBuilder thenById() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'id', Sort.asc); - }); - } - - QueryBuilder thenByIdDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'id', Sort.desc); - }); - } - - QueryBuilder thenByMaleToilets() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'maleToilets', Sort.asc); - }); - } - - QueryBuilder thenByMaleToiletsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'maleToilets', Sort.desc); - }); - } - - QueryBuilder thenByShowComputerPools() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showComputerPools', Sort.asc); - }); - } - - QueryBuilder thenByShowComputerPoolsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showComputerPools', Sort.desc); - }); - } - - QueryBuilder thenByShowDoors() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showDoors', Sort.asc); - }); - } - - QueryBuilder thenByShowDoorsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showDoors', Sort.desc); - }); - } - - QueryBuilder thenByShowElevators() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showElevators', Sort.asc); - }); - } - - QueryBuilder thenByShowElevatorsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showElevators', Sort.desc); - }); - } - - QueryBuilder thenByShowFoodAndDrink() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showFoodAndDrink', Sort.asc); - }); - } - - QueryBuilder thenByShowFoodAndDrinkDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showFoodAndDrink', Sort.desc); - }); - } - - QueryBuilder thenByShowIcons() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showIcons', Sort.asc); - }); - } - - QueryBuilder thenByShowIconsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showIcons', Sort.desc); - }); - } - - QueryBuilder thenByShowLectureHalls() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showLectureHalls', Sort.asc); - }); - } - - QueryBuilder thenByShowLectureHallsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showLectureHalls', Sort.desc); - }); - } - - QueryBuilder thenByShowSeminarRooms() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showSeminarRooms', Sort.asc); - }); - } - - QueryBuilder thenByShowSeminarRoomsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showSeminarRooms', Sort.desc); - }); - } - - QueryBuilder thenByShowStairs() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showStairs', Sort.asc); - }); - } - - QueryBuilder thenByShowStairsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showStairs', Sort.desc); - }); - } - - QueryBuilder thenByShowToilets() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showToilets', Sort.asc); - }); - } - - QueryBuilder thenByShowToiletsDesc() { - return QueryBuilder.apply(this, (query) { - return query.addSortBy(r'showToilets', Sort.desc); - }); - } -} - -extension SettingsQueryWhereDistinct - on QueryBuilder { - QueryBuilder distinctByFemaleToilets() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'femaleToilets'); - }); - } - - QueryBuilder distinctByHandicapToilets() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'handicapToilets'); - }); - } - - QueryBuilder distinctByMaleToilets() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'maleToilets'); - }); - } - - QueryBuilder distinctByShowComputerPools() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'showComputerPools'); - }); - } - - QueryBuilder distinctByShowDoors() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'showDoors'); - }); - } - - QueryBuilder distinctByShowElevators() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'showElevators'); - }); - } - - QueryBuilder distinctByShowFoodAndDrink() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'showFoodAndDrink'); - }); - } - - QueryBuilder distinctByShowIcons() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'showIcons'); - }); - } - - QueryBuilder distinctByShowLectureHalls() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'showLectureHalls'); - }); - } - - QueryBuilder distinctByShowSeminarRooms() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'showSeminarRooms'); - }); - } - - QueryBuilder distinctByShowStairs() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'showStairs'); - }); - } - - QueryBuilder distinctByShowToilets() { - return QueryBuilder.apply(this, (query) { - return query.addDistinctBy(r'showToilets'); - }); - } -} - -extension SettingsQueryProperty - on QueryBuilder { - QueryBuilder idProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'id'); - }); - } - - QueryBuilder femaleToiletsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'femaleToilets'); - }); - } - - QueryBuilder handicapToiletsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'handicapToilets'); - }); - } - - QueryBuilder maleToiletsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'maleToilets'); - }); - } - - QueryBuilder showComputerPoolsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'showComputerPools'); - }); - } - - QueryBuilder showDoorsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'showDoors'); - }); - } - - QueryBuilder showElevatorsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'showElevators'); - }); - } - - QueryBuilder showFoodAndDrinkProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'showFoodAndDrink'); - }); - } - - QueryBuilder showIconsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'showIcons'); - }); - } - - QueryBuilder showLectureHallsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'showLectureHalls'); - }); - } - - QueryBuilder showSeminarRoomsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'showSeminarRooms'); - }); - } - - QueryBuilder showStairsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'showStairs'); - }); - } - - QueryBuilder showToiletsProperty() { - return QueryBuilder.apply(this, (query) { - return query.addPropertyName(r'showToilets'); - }); - } -} diff --git a/lib/controllers/map_controller.dart b/lib/controllers/map_controller.dart index c0356a0..9e1c26d 100644 --- a/lib/controllers/map_controller.dart +++ b/lib/controllers/map_controller.dart @@ -1,14 +1,17 @@ +import 'dart:async'; import 'dart:convert'; import 'package:anyhow/anyhow.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:geojson_vi/geojson_vi.dart'; +import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; import 'package:latlong2/latlong.dart'; import 'package:uninav/components/feature_bottom_sheet.dart'; import 'package:uninav/data/geo/model.dart'; import 'package:uninav/data/geo/parser.dart'; import 'package:uninav/util/geojson_util.dart'; +import 'package:uninav/util/geolocator.dart'; import 'package:uninav/util/geomath.dart'; class MyMapController extends GetxController { @@ -17,6 +20,10 @@ class MyMapController extends GetxController { final RxList features = [].obs; final currentLevel = 1.obs; final levels = [1].obs; + final Rx position = null.obs; + + bool _locationEnsured = false; + @override onInit() async { print("init"); @@ -98,6 +105,8 @@ class MyMapController extends GetxController { feature.geometry, feature.id); if (parsed case Ok(:final ok)) { featuresList.add(ok); + } else { + print('Error parsing feature: $parsed'); } } @@ -137,4 +146,46 @@ class MyMapController extends GetxController { } showFeatureBottomSheet(feature, closestFeatures); } + + Future> getCurrentPosition() async { + if (!_locationEnsured) { + final ensureRes = await ensureLocationPermission(); + if (ensureRes is Err) { + // TODO: check that it works + return ensureRes as Err; + } + } + _locationEnsured = true; + try { + final pos = await Geolocator.getCurrentPosition( + // desiredAccuracy: LocationAccuracy.high, + timeLimit: Duration(minutes: 1), + ); + position.value = pos; + return Ok(pos); + } on TimeoutException catch (e) { + return bail("Timeout while waiting for location lock: $e"); + } + } + + Future> subscribePosition() async { + if (!_locationEnsured) { + final ensureRes = await ensureLocationPermission(); + if (ensureRes is Err) { + // TODO: check that it works + return ensureRes; + } + } + _locationEnsured = true; + Geolocator.getPositionStream( + locationSettings: const LocationSettings( + accuracy: LocationAccuracy.high, + distanceFilter: 100, + //timeLimit: Duration(minutes: 10) + ), + ).listen((pos) { + position.value = pos; + }); + return const Ok(()); + } } diff --git a/lib/controllers/shared_prefs_controller.dart b/lib/controllers/shared_prefs_controller.dart new file mode 100644 index 0000000..51198fe --- /dev/null +++ b/lib/controllers/shared_prefs_controller.dart @@ -0,0 +1,72 @@ +import 'dart:convert'; + +import 'package:get/get.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'shared_prefs_controller.freezed.dart'; +part 'shared_prefs_controller.g.dart'; + +class SharedPrefsController { + late SharedPreferences _sharedPrefs; + + final Rx settings = Settings().obs; + + SharedPrefsController(); + + Future initialize() async { + _sharedPrefs = await SharedPreferences.getInstance(); + try { + final settingsJson = _sharedPrefs.getString("settings"); + if (settingsJson != null) { + settings.value = Settings.fromJson(jsonDecode(settingsJson)); + } else { + settings.value = const Settings(); + } + } catch (e) { + settings.value = const Settings(); + } + } + + Future persistSettings() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('settings', jsonEncode(settings.value)); + } + + Future loadSettings() async { + final prefs = await SharedPreferences.getInstance(); + final settingsJson = prefs.getString('settings'); + return settingsJson != null + ? Settings.fromJson(jsonDecode(settingsJson)) + : const Settings(); + } +} + +@freezed +class Settings with _$Settings { + const factory Settings({ + @Default(1) int id, + @Default(true) bool showIcons, + @Default(true) bool showElevators, + @Default(true) bool showFoodAndDrink, + @Default(true) bool showLectureHalls, + @Default(true) bool showComputerPools, + @Default(true) bool showSeminarRooms, + @Default(true) bool showToilets, + @Default(true) bool showStairs, + @Default(true) bool showDoors, + @Default(false) bool maleToilets, + @Default(false) bool femaleToilets, + @Default(false) bool handicapToilets, + }) = _Settings; + + factory Settings.fromJson(Map json) => + _$SettingsFromJson(json); +} + +enum ToiletPreference { + male, + female, + disabled, +} diff --git a/lib/controllers/shared_prefs_controller.freezed.dart b/lib/controllers/shared_prefs_controller.freezed.dart new file mode 100644 index 0000000..a1688b0 --- /dev/null +++ b/lib/controllers/shared_prefs_controller.freezed.dart @@ -0,0 +1,433 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'shared_prefs_controller.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +Settings _$SettingsFromJson(Map json) { + return _Settings.fromJson(json); +} + +/// @nodoc +mixin _$Settings { + int get id => throw _privateConstructorUsedError; + bool get showIcons => throw _privateConstructorUsedError; + bool get showElevators => throw _privateConstructorUsedError; + bool get showFoodAndDrink => throw _privateConstructorUsedError; + bool get showLectureHalls => throw _privateConstructorUsedError; + bool get showComputerPools => throw _privateConstructorUsedError; + bool get showSeminarRooms => throw _privateConstructorUsedError; + bool get showToilets => throw _privateConstructorUsedError; + bool get showStairs => throw _privateConstructorUsedError; + bool get showDoors => throw _privateConstructorUsedError; + bool get maleToilets => throw _privateConstructorUsedError; + bool get femaleToilets => throw _privateConstructorUsedError; + bool get handicapToilets => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $SettingsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SettingsCopyWith<$Res> { + factory $SettingsCopyWith(Settings value, $Res Function(Settings) then) = + _$SettingsCopyWithImpl<$Res, Settings>; + @useResult + $Res call( + {int id, + bool showIcons, + bool showElevators, + bool showFoodAndDrink, + bool showLectureHalls, + bool showComputerPools, + bool showSeminarRooms, + bool showToilets, + bool showStairs, + bool showDoors, + bool maleToilets, + bool femaleToilets, + bool handicapToilets}); +} + +/// @nodoc +class _$SettingsCopyWithImpl<$Res, $Val extends Settings> + implements $SettingsCopyWith<$Res> { + _$SettingsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? showIcons = null, + Object? showElevators = null, + Object? showFoodAndDrink = null, + Object? showLectureHalls = null, + Object? showComputerPools = null, + Object? showSeminarRooms = null, + Object? showToilets = null, + Object? showStairs = null, + Object? showDoors = null, + Object? maleToilets = null, + Object? femaleToilets = null, + Object? handicapToilets = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + showIcons: null == showIcons + ? _value.showIcons + : showIcons // ignore: cast_nullable_to_non_nullable + as bool, + showElevators: null == showElevators + ? _value.showElevators + : showElevators // ignore: cast_nullable_to_non_nullable + as bool, + showFoodAndDrink: null == showFoodAndDrink + ? _value.showFoodAndDrink + : showFoodAndDrink // ignore: cast_nullable_to_non_nullable + as bool, + showLectureHalls: null == showLectureHalls + ? _value.showLectureHalls + : showLectureHalls // ignore: cast_nullable_to_non_nullable + as bool, + showComputerPools: null == showComputerPools + ? _value.showComputerPools + : showComputerPools // ignore: cast_nullable_to_non_nullable + as bool, + showSeminarRooms: null == showSeminarRooms + ? _value.showSeminarRooms + : showSeminarRooms // ignore: cast_nullable_to_non_nullable + as bool, + showToilets: null == showToilets + ? _value.showToilets + : showToilets // ignore: cast_nullable_to_non_nullable + as bool, + showStairs: null == showStairs + ? _value.showStairs + : showStairs // ignore: cast_nullable_to_non_nullable + as bool, + showDoors: null == showDoors + ? _value.showDoors + : showDoors // ignore: cast_nullable_to_non_nullable + as bool, + maleToilets: null == maleToilets + ? _value.maleToilets + : maleToilets // ignore: cast_nullable_to_non_nullable + as bool, + femaleToilets: null == femaleToilets + ? _value.femaleToilets + : femaleToilets // ignore: cast_nullable_to_non_nullable + as bool, + handicapToilets: null == handicapToilets + ? _value.handicapToilets + : handicapToilets // ignore: cast_nullable_to_non_nullable + as bool, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SettingsImplCopyWith<$Res> + implements $SettingsCopyWith<$Res> { + factory _$$SettingsImplCopyWith( + _$SettingsImpl value, $Res Function(_$SettingsImpl) then) = + __$$SettingsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int id, + bool showIcons, + bool showElevators, + bool showFoodAndDrink, + bool showLectureHalls, + bool showComputerPools, + bool showSeminarRooms, + bool showToilets, + bool showStairs, + bool showDoors, + bool maleToilets, + bool femaleToilets, + bool handicapToilets}); +} + +/// @nodoc +class __$$SettingsImplCopyWithImpl<$Res> + extends _$SettingsCopyWithImpl<$Res, _$SettingsImpl> + implements _$$SettingsImplCopyWith<$Res> { + __$$SettingsImplCopyWithImpl( + _$SettingsImpl _value, $Res Function(_$SettingsImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? showIcons = null, + Object? showElevators = null, + Object? showFoodAndDrink = null, + Object? showLectureHalls = null, + Object? showComputerPools = null, + Object? showSeminarRooms = null, + Object? showToilets = null, + Object? showStairs = null, + Object? showDoors = null, + Object? maleToilets = null, + Object? femaleToilets = null, + Object? handicapToilets = null, + }) { + return _then(_$SettingsImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as int, + showIcons: null == showIcons + ? _value.showIcons + : showIcons // ignore: cast_nullable_to_non_nullable + as bool, + showElevators: null == showElevators + ? _value.showElevators + : showElevators // ignore: cast_nullable_to_non_nullable + as bool, + showFoodAndDrink: null == showFoodAndDrink + ? _value.showFoodAndDrink + : showFoodAndDrink // ignore: cast_nullable_to_non_nullable + as bool, + showLectureHalls: null == showLectureHalls + ? _value.showLectureHalls + : showLectureHalls // ignore: cast_nullable_to_non_nullable + as bool, + showComputerPools: null == showComputerPools + ? _value.showComputerPools + : showComputerPools // ignore: cast_nullable_to_non_nullable + as bool, + showSeminarRooms: null == showSeminarRooms + ? _value.showSeminarRooms + : showSeminarRooms // ignore: cast_nullable_to_non_nullable + as bool, + showToilets: null == showToilets + ? _value.showToilets + : showToilets // ignore: cast_nullable_to_non_nullable + as bool, + showStairs: null == showStairs + ? _value.showStairs + : showStairs // ignore: cast_nullable_to_non_nullable + as bool, + showDoors: null == showDoors + ? _value.showDoors + : showDoors // ignore: cast_nullable_to_non_nullable + as bool, + maleToilets: null == maleToilets + ? _value.maleToilets + : maleToilets // ignore: cast_nullable_to_non_nullable + as bool, + femaleToilets: null == femaleToilets + ? _value.femaleToilets + : femaleToilets // ignore: cast_nullable_to_non_nullable + as bool, + handicapToilets: null == handicapToilets + ? _value.handicapToilets + : handicapToilets // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$SettingsImpl implements _Settings { + const _$SettingsImpl( + {this.id = 1, + this.showIcons = true, + this.showElevators = true, + this.showFoodAndDrink = true, + this.showLectureHalls = true, + this.showComputerPools = true, + this.showSeminarRooms = true, + this.showToilets = true, + this.showStairs = true, + this.showDoors = true, + this.maleToilets = false, + this.femaleToilets = false, + this.handicapToilets = false}); + + factory _$SettingsImpl.fromJson(Map json) => + _$$SettingsImplFromJson(json); + + @override + @JsonKey() + final int id; + @override + @JsonKey() + final bool showIcons; + @override + @JsonKey() + final bool showElevators; + @override + @JsonKey() + final bool showFoodAndDrink; + @override + @JsonKey() + final bool showLectureHalls; + @override + @JsonKey() + final bool showComputerPools; + @override + @JsonKey() + final bool showSeminarRooms; + @override + @JsonKey() + final bool showToilets; + @override + @JsonKey() + final bool showStairs; + @override + @JsonKey() + final bool showDoors; + @override + @JsonKey() + final bool maleToilets; + @override + @JsonKey() + final bool femaleToilets; + @override + @JsonKey() + final bool handicapToilets; + + @override + String toString() { + return 'Settings(id: $id, showIcons: $showIcons, showElevators: $showElevators, showFoodAndDrink: $showFoodAndDrink, showLectureHalls: $showLectureHalls, showComputerPools: $showComputerPools, showSeminarRooms: $showSeminarRooms, showToilets: $showToilets, showStairs: $showStairs, showDoors: $showDoors, maleToilets: $maleToilets, femaleToilets: $femaleToilets, handicapToilets: $handicapToilets)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SettingsImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.showIcons, showIcons) || + other.showIcons == showIcons) && + (identical(other.showElevators, showElevators) || + other.showElevators == showElevators) && + (identical(other.showFoodAndDrink, showFoodAndDrink) || + other.showFoodAndDrink == showFoodAndDrink) && + (identical(other.showLectureHalls, showLectureHalls) || + other.showLectureHalls == showLectureHalls) && + (identical(other.showComputerPools, showComputerPools) || + other.showComputerPools == showComputerPools) && + (identical(other.showSeminarRooms, showSeminarRooms) || + other.showSeminarRooms == showSeminarRooms) && + (identical(other.showToilets, showToilets) || + other.showToilets == showToilets) && + (identical(other.showStairs, showStairs) || + other.showStairs == showStairs) && + (identical(other.showDoors, showDoors) || + other.showDoors == showDoors) && + (identical(other.maleToilets, maleToilets) || + other.maleToilets == maleToilets) && + (identical(other.femaleToilets, femaleToilets) || + other.femaleToilets == femaleToilets) && + (identical(other.handicapToilets, handicapToilets) || + other.handicapToilets == handicapToilets)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + id, + showIcons, + showElevators, + showFoodAndDrink, + showLectureHalls, + showComputerPools, + showSeminarRooms, + showToilets, + showStairs, + showDoors, + maleToilets, + femaleToilets, + handicapToilets); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SettingsImplCopyWith<_$SettingsImpl> get copyWith => + __$$SettingsImplCopyWithImpl<_$SettingsImpl>(this, _$identity); + + @override + Map toJson() { + return _$$SettingsImplToJson( + this, + ); + } +} + +abstract class _Settings implements Settings { + const factory _Settings( + {final int id, + final bool showIcons, + final bool showElevators, + final bool showFoodAndDrink, + final bool showLectureHalls, + final bool showComputerPools, + final bool showSeminarRooms, + final bool showToilets, + final bool showStairs, + final bool showDoors, + final bool maleToilets, + final bool femaleToilets, + final bool handicapToilets}) = _$SettingsImpl; + + factory _Settings.fromJson(Map json) = + _$SettingsImpl.fromJson; + + @override + int get id; + @override + bool get showIcons; + @override + bool get showElevators; + @override + bool get showFoodAndDrink; + @override + bool get showLectureHalls; + @override + bool get showComputerPools; + @override + bool get showSeminarRooms; + @override + bool get showToilets; + @override + bool get showStairs; + @override + bool get showDoors; + @override + bool get maleToilets; + @override + bool get femaleToilets; + @override + bool get handicapToilets; + @override + @JsonKey(ignore: true) + _$$SettingsImplCopyWith<_$SettingsImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/controllers/shared_prefs_controller.g.dart b/lib/controllers/shared_prefs_controller.g.dart new file mode 100644 index 0000000..02b5768 --- /dev/null +++ b/lib/controllers/shared_prefs_controller.g.dart @@ -0,0 +1,41 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'shared_prefs_controller.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$SettingsImpl _$$SettingsImplFromJson(Map json) => + _$SettingsImpl( + id: json['id'] as int? ?? 1, + showIcons: json['showIcons'] as bool? ?? true, + showElevators: json['showElevators'] as bool? ?? true, + showFoodAndDrink: json['showFoodAndDrink'] as bool? ?? true, + showLectureHalls: json['showLectureHalls'] as bool? ?? true, + showComputerPools: json['showComputerPools'] as bool? ?? true, + showSeminarRooms: json['showSeminarRooms'] as bool? ?? true, + showToilets: json['showToilets'] as bool? ?? true, + showStairs: json['showStairs'] as bool? ?? true, + showDoors: json['showDoors'] as bool? ?? true, + maleToilets: json['maleToilets'] as bool? ?? false, + femaleToilets: json['femaleToilets'] as bool? ?? false, + handicapToilets: json['handicapToilets'] as bool? ?? false, + ); + +Map _$$SettingsImplToJson(_$SettingsImpl instance) => + { + 'id': instance.id, + 'showIcons': instance.showIcons, + 'showElevators': instance.showElevators, + 'showFoodAndDrink': instance.showFoodAndDrink, + 'showLectureHalls': instance.showLectureHalls, + 'showComputerPools': instance.showComputerPools, + 'showSeminarRooms': instance.showSeminarRooms, + 'showToilets': instance.showToilets, + 'showStairs': instance.showStairs, + 'showDoors': instance.showDoors, + 'maleToilets': instance.maleToilets, + 'femaleToilets': instance.femaleToilets, + 'handicapToilets': instance.handicapToilets, + }; diff --git a/lib/data/geo/model.dart b/lib/data/geo/model.dart index cbcd82a..f289550 100644 --- a/lib/data/geo/model.dart +++ b/lib/data/geo/model.dart @@ -99,11 +99,13 @@ class FeatureType with _$FeatureType { // multiple feature types like lecture hall, toliet, ... const factory FeatureType.building() = Building; const factory FeatureType.lectureHall() = LectureHall; - const factory FeatureType.room() = Room; + const factory FeatureType.room(String roomNumber) = Room; const factory FeatureType.door(List connects) = Door; const factory FeatureType.toilet(String toilet_type) = Toilet; const factory FeatureType.stairs(List connects_levels) = Stairs; const factory FeatureType.lift(List connects_levels) = Lift; + const factory FeatureType.foodDrink() = FoodDrink; const factory FeatureType.publicTransport( List bus_lines, List tram_lines) = PublicTransport; + const factory FeatureType.pcPool(String roomNumber) = PcPool; } diff --git a/lib/data/geo/model.freezed.dart b/lib/data/geo/model.freezed.dart index fdbd365..a2cf647 100644 --- a/lib/data/geo/model.freezed.dart +++ b/lib/data/geo/model.freezed.dart @@ -277,39 +277,45 @@ mixin _$FeatureType { TResult when({ required TResult Function() building, required TResult Function() lectureHall, - required TResult Function() room, + required TResult Function(String roomNumber) room, required TResult Function(List connects) door, required TResult Function(String toilet_type) toilet, required TResult Function(List connects_levels) stairs, required TResult Function(List connects_levels) lift, + required TResult Function() foodDrink, required TResult Function(List bus_lines, List tram_lines) publicTransport, + required TResult Function(String roomNumber) pcPool, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function()? building, TResult? Function()? lectureHall, - TResult? Function()? room, + TResult? Function(String roomNumber)? room, TResult? Function(List connects)? door, TResult? Function(String toilet_type)? toilet, TResult? Function(List connects_levels)? stairs, TResult? Function(List connects_levels)? lift, + TResult? Function()? foodDrink, TResult? Function(List bus_lines, List tram_lines)? publicTransport, + TResult? Function(String roomNumber)? pcPool, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function()? building, TResult Function()? lectureHall, - TResult Function()? room, + TResult Function(String roomNumber)? room, TResult Function(List connects)? door, TResult Function(String toilet_type)? toilet, TResult Function(List connects_levels)? stairs, TResult Function(List connects_levels)? lift, + TResult Function()? foodDrink, TResult Function(List bus_lines, List tram_lines)? publicTransport, + TResult Function(String roomNumber)? pcPool, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -322,7 +328,9 @@ mixin _$FeatureType { required TResult Function(Toilet value) toilet, required TResult Function(Stairs value) stairs, required TResult Function(Lift value) lift, + required TResult Function(FoodDrink value) foodDrink, required TResult Function(PublicTransport value) publicTransport, + required TResult Function(PcPool value) pcPool, }) => throw _privateConstructorUsedError; @optionalTypeArgs @@ -334,7 +342,9 @@ mixin _$FeatureType { TResult? Function(Toilet value)? toilet, TResult? Function(Stairs value)? stairs, TResult? Function(Lift value)? lift, + TResult? Function(FoodDrink value)? foodDrink, TResult? Function(PublicTransport value)? publicTransport, + TResult? Function(PcPool value)? pcPool, }) => throw _privateConstructorUsedError; @optionalTypeArgs @@ -346,7 +356,9 @@ mixin _$FeatureType { TResult Function(Toilet value)? toilet, TResult Function(Stairs value)? stairs, TResult Function(Lift value)? lift, + TResult Function(FoodDrink value)? foodDrink, TResult Function(PublicTransport value)? publicTransport, + TResult Function(PcPool value)? pcPool, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -410,13 +422,15 @@ class _$BuildingImpl implements Building { TResult when({ required TResult Function() building, required TResult Function() lectureHall, - required TResult Function() room, + required TResult Function(String roomNumber) room, required TResult Function(List connects) door, required TResult Function(String toilet_type) toilet, required TResult Function(List connects_levels) stairs, required TResult Function(List connects_levels) lift, + required TResult Function() foodDrink, required TResult Function(List bus_lines, List tram_lines) publicTransport, + required TResult Function(String roomNumber) pcPool, }) { return building(); } @@ -426,13 +440,15 @@ class _$BuildingImpl implements Building { TResult? whenOrNull({ TResult? Function()? building, TResult? Function()? lectureHall, - TResult? Function()? room, + TResult? Function(String roomNumber)? room, TResult? Function(List connects)? door, TResult? Function(String toilet_type)? toilet, TResult? Function(List connects_levels)? stairs, TResult? Function(List connects_levels)? lift, + TResult? Function()? foodDrink, TResult? Function(List bus_lines, List tram_lines)? publicTransport, + TResult? Function(String roomNumber)? pcPool, }) { return building?.call(); } @@ -442,13 +458,15 @@ class _$BuildingImpl implements Building { TResult maybeWhen({ TResult Function()? building, TResult Function()? lectureHall, - TResult Function()? room, + TResult Function(String roomNumber)? room, TResult Function(List connects)? door, TResult Function(String toilet_type)? toilet, TResult Function(List connects_levels)? stairs, TResult Function(List connects_levels)? lift, + TResult Function()? foodDrink, TResult Function(List bus_lines, List tram_lines)? publicTransport, + TResult Function(String roomNumber)? pcPool, required TResult orElse(), }) { if (building != null) { @@ -467,7 +485,9 @@ class _$BuildingImpl implements Building { required TResult Function(Toilet value) toilet, required TResult Function(Stairs value) stairs, required TResult Function(Lift value) lift, + required TResult Function(FoodDrink value) foodDrink, required TResult Function(PublicTransport value) publicTransport, + required TResult Function(PcPool value) pcPool, }) { return building(this); } @@ -482,7 +502,9 @@ class _$BuildingImpl implements Building { TResult? Function(Toilet value)? toilet, TResult? Function(Stairs value)? stairs, TResult? Function(Lift value)? lift, + TResult? Function(FoodDrink value)? foodDrink, TResult? Function(PublicTransport value)? publicTransport, + TResult? Function(PcPool value)? pcPool, }) { return building?.call(this); } @@ -497,7 +519,9 @@ class _$BuildingImpl implements Building { TResult Function(Toilet value)? toilet, TResult Function(Stairs value)? stairs, TResult Function(Lift value)? lift, + TResult Function(FoodDrink value)? foodDrink, TResult Function(PublicTransport value)? publicTransport, + TResult Function(PcPool value)? pcPool, required TResult orElse(), }) { if (building != null) { @@ -551,13 +575,15 @@ class _$LectureHallImpl implements LectureHall { TResult when({ required TResult Function() building, required TResult Function() lectureHall, - required TResult Function() room, + required TResult Function(String roomNumber) room, required TResult Function(List connects) door, required TResult Function(String toilet_type) toilet, required TResult Function(List connects_levels) stairs, required TResult Function(List connects_levels) lift, + required TResult Function() foodDrink, required TResult Function(List bus_lines, List tram_lines) publicTransport, + required TResult Function(String roomNumber) pcPool, }) { return lectureHall(); } @@ -567,13 +593,15 @@ class _$LectureHallImpl implements LectureHall { TResult? whenOrNull({ TResult? Function()? building, TResult? Function()? lectureHall, - TResult? Function()? room, + TResult? Function(String roomNumber)? room, TResult? Function(List connects)? door, TResult? Function(String toilet_type)? toilet, TResult? Function(List connects_levels)? stairs, TResult? Function(List connects_levels)? lift, + TResult? Function()? foodDrink, TResult? Function(List bus_lines, List tram_lines)? publicTransport, + TResult? Function(String roomNumber)? pcPool, }) { return lectureHall?.call(); } @@ -583,13 +611,15 @@ class _$LectureHallImpl implements LectureHall { TResult maybeWhen({ TResult Function()? building, TResult Function()? lectureHall, - TResult Function()? room, + TResult Function(String roomNumber)? room, TResult Function(List connects)? door, TResult Function(String toilet_type)? toilet, TResult Function(List connects_levels)? stairs, TResult Function(List connects_levels)? lift, + TResult Function()? foodDrink, TResult Function(List bus_lines, List tram_lines)? publicTransport, + TResult Function(String roomNumber)? pcPool, required TResult orElse(), }) { if (lectureHall != null) { @@ -608,7 +638,9 @@ class _$LectureHallImpl implements LectureHall { required TResult Function(Toilet value) toilet, required TResult Function(Stairs value) stairs, required TResult Function(Lift value) lift, + required TResult Function(FoodDrink value) foodDrink, required TResult Function(PublicTransport value) publicTransport, + required TResult Function(PcPool value) pcPool, }) { return lectureHall(this); } @@ -623,7 +655,9 @@ class _$LectureHallImpl implements LectureHall { TResult? Function(Toilet value)? toilet, TResult? Function(Stairs value)? stairs, TResult? Function(Lift value)? lift, + TResult? Function(FoodDrink value)? foodDrink, TResult? Function(PublicTransport value)? publicTransport, + TResult? Function(PcPool value)? pcPool, }) { return lectureHall?.call(this); } @@ -638,7 +672,9 @@ class _$LectureHallImpl implements LectureHall { TResult Function(Toilet value)? toilet, TResult Function(Stairs value)? stairs, TResult Function(Lift value)? lift, + TResult Function(FoodDrink value)? foodDrink, TResult Function(PublicTransport value)? publicTransport, + TResult Function(PcPool value)? pcPool, required TResult orElse(), }) { if (lectureHall != null) { @@ -657,6 +693,8 @@ abstract class _$$RoomImplCopyWith<$Res> { factory _$$RoomImplCopyWith( _$RoomImpl value, $Res Function(_$RoomImpl) then) = __$$RoomImplCopyWithImpl<$Res>; + @useResult + $Res call({String roomNumber}); } /// @nodoc @@ -665,41 +703,68 @@ class __$$RoomImplCopyWithImpl<$Res> implements _$$RoomImplCopyWith<$Res> { __$$RoomImplCopyWithImpl(_$RoomImpl _value, $Res Function(_$RoomImpl) _then) : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? roomNumber = null, + }) { + return _then(_$RoomImpl( + null == roomNumber + ? _value.roomNumber + : roomNumber // ignore: cast_nullable_to_non_nullable + as String, + )); + } } /// @nodoc class _$RoomImpl implements Room { - const _$RoomImpl(); + const _$RoomImpl(this.roomNumber); + + @override + final String roomNumber; @override String toString() { - return 'FeatureType.room()'; + return 'FeatureType.room(roomNumber: $roomNumber)'; } @override bool operator ==(Object other) { return identical(this, other) || - (other.runtimeType == runtimeType && other is _$RoomImpl); + (other.runtimeType == runtimeType && + other is _$RoomImpl && + (identical(other.roomNumber, roomNumber) || + other.roomNumber == roomNumber)); } @override - int get hashCode => runtimeType.hashCode; + int get hashCode => Object.hash(runtimeType, roomNumber); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$RoomImplCopyWith<_$RoomImpl> get copyWith => + __$$RoomImplCopyWithImpl<_$RoomImpl>(this, _$identity); @override @optionalTypeArgs TResult when({ required TResult Function() building, required TResult Function() lectureHall, - required TResult Function() room, + required TResult Function(String roomNumber) room, required TResult Function(List connects) door, required TResult Function(String toilet_type) toilet, required TResult Function(List connects_levels) stairs, required TResult Function(List connects_levels) lift, + required TResult Function() foodDrink, required TResult Function(List bus_lines, List tram_lines) publicTransport, + required TResult Function(String roomNumber) pcPool, }) { - return room(); + return room(roomNumber); } @override @@ -707,15 +772,17 @@ class _$RoomImpl implements Room { TResult? whenOrNull({ TResult? Function()? building, TResult? Function()? lectureHall, - TResult? Function()? room, + TResult? Function(String roomNumber)? room, TResult? Function(List connects)? door, TResult? Function(String toilet_type)? toilet, TResult? Function(List connects_levels)? stairs, TResult? Function(List connects_levels)? lift, + TResult? Function()? foodDrink, TResult? Function(List bus_lines, List tram_lines)? publicTransport, + TResult? Function(String roomNumber)? pcPool, }) { - return room?.call(); + return room?.call(roomNumber); } @override @@ -723,17 +790,19 @@ class _$RoomImpl implements Room { TResult maybeWhen({ TResult Function()? building, TResult Function()? lectureHall, - TResult Function()? room, + TResult Function(String roomNumber)? room, TResult Function(List connects)? door, TResult Function(String toilet_type)? toilet, TResult Function(List connects_levels)? stairs, TResult Function(List connects_levels)? lift, + TResult Function()? foodDrink, TResult Function(List bus_lines, List tram_lines)? publicTransport, + TResult Function(String roomNumber)? pcPool, required TResult orElse(), }) { if (room != null) { - return room(); + return room(roomNumber); } return orElse(); } @@ -748,7 +817,9 @@ class _$RoomImpl implements Room { required TResult Function(Toilet value) toilet, required TResult Function(Stairs value) stairs, required TResult Function(Lift value) lift, + required TResult Function(FoodDrink value) foodDrink, required TResult Function(PublicTransport value) publicTransport, + required TResult Function(PcPool value) pcPool, }) { return room(this); } @@ -763,7 +834,9 @@ class _$RoomImpl implements Room { TResult? Function(Toilet value)? toilet, TResult? Function(Stairs value)? stairs, TResult? Function(Lift value)? lift, + TResult? Function(FoodDrink value)? foodDrink, TResult? Function(PublicTransport value)? publicTransport, + TResult? Function(PcPool value)? pcPool, }) { return room?.call(this); } @@ -778,7 +851,9 @@ class _$RoomImpl implements Room { TResult Function(Toilet value)? toilet, TResult Function(Stairs value)? stairs, TResult Function(Lift value)? lift, + TResult Function(FoodDrink value)? foodDrink, TResult Function(PublicTransport value)? publicTransport, + TResult Function(PcPool value)? pcPool, required TResult orElse(), }) { if (room != null) { @@ -789,7 +864,12 @@ class _$RoomImpl implements Room { } abstract class Room implements FeatureType { - const factory Room() = _$RoomImpl; + const factory Room(final String roomNumber) = _$RoomImpl; + + String get roomNumber; + @JsonKey(ignore: true) + _$$RoomImplCopyWith<_$RoomImpl> get copyWith => + throw _privateConstructorUsedError; } /// @nodoc @@ -863,13 +943,15 @@ class _$DoorImpl implements Door { TResult when({ required TResult Function() building, required TResult Function() lectureHall, - required TResult Function() room, + required TResult Function(String roomNumber) room, required TResult Function(List connects) door, required TResult Function(String toilet_type) toilet, required TResult Function(List connects_levels) stairs, required TResult Function(List connects_levels) lift, + required TResult Function() foodDrink, required TResult Function(List bus_lines, List tram_lines) publicTransport, + required TResult Function(String roomNumber) pcPool, }) { return door(connects); } @@ -879,13 +961,15 @@ class _$DoorImpl implements Door { TResult? whenOrNull({ TResult? Function()? building, TResult? Function()? lectureHall, - TResult? Function()? room, + TResult? Function(String roomNumber)? room, TResult? Function(List connects)? door, TResult? Function(String toilet_type)? toilet, TResult? Function(List connects_levels)? stairs, TResult? Function(List connects_levels)? lift, + TResult? Function()? foodDrink, TResult? Function(List bus_lines, List tram_lines)? publicTransport, + TResult? Function(String roomNumber)? pcPool, }) { return door?.call(connects); } @@ -895,13 +979,15 @@ class _$DoorImpl implements Door { TResult maybeWhen({ TResult Function()? building, TResult Function()? lectureHall, - TResult Function()? room, + TResult Function(String roomNumber)? room, TResult Function(List connects)? door, TResult Function(String toilet_type)? toilet, TResult Function(List connects_levels)? stairs, TResult Function(List connects_levels)? lift, + TResult Function()? foodDrink, TResult Function(List bus_lines, List tram_lines)? publicTransport, + TResult Function(String roomNumber)? pcPool, required TResult orElse(), }) { if (door != null) { @@ -920,7 +1006,9 @@ class _$DoorImpl implements Door { required TResult Function(Toilet value) toilet, required TResult Function(Stairs value) stairs, required TResult Function(Lift value) lift, + required TResult Function(FoodDrink value) foodDrink, required TResult Function(PublicTransport value) publicTransport, + required TResult Function(PcPool value) pcPool, }) { return door(this); } @@ -935,7 +1023,9 @@ class _$DoorImpl implements Door { TResult? Function(Toilet value)? toilet, TResult? Function(Stairs value)? stairs, TResult? Function(Lift value)? lift, + TResult? Function(FoodDrink value)? foodDrink, TResult? Function(PublicTransport value)? publicTransport, + TResult? Function(PcPool value)? pcPool, }) { return door?.call(this); } @@ -950,7 +1040,9 @@ class _$DoorImpl implements Door { TResult Function(Toilet value)? toilet, TResult Function(Stairs value)? stairs, TResult Function(Lift value)? lift, + TResult Function(FoodDrink value)? foodDrink, TResult Function(PublicTransport value)? publicTransport, + TResult Function(PcPool value)? pcPool, required TResult orElse(), }) { if (door != null) { @@ -1036,13 +1128,15 @@ class _$ToiletImpl implements Toilet { TResult when({ required TResult Function() building, required TResult Function() lectureHall, - required TResult Function() room, + required TResult Function(String roomNumber) room, required TResult Function(List connects) door, required TResult Function(String toilet_type) toilet, required TResult Function(List connects_levels) stairs, required TResult Function(List connects_levels) lift, + required TResult Function() foodDrink, required TResult Function(List bus_lines, List tram_lines) publicTransport, + required TResult Function(String roomNumber) pcPool, }) { return toilet(toilet_type); } @@ -1052,13 +1146,15 @@ class _$ToiletImpl implements Toilet { TResult? whenOrNull({ TResult? Function()? building, TResult? Function()? lectureHall, - TResult? Function()? room, + TResult? Function(String roomNumber)? room, TResult? Function(List connects)? door, TResult? Function(String toilet_type)? toilet, TResult? Function(List connects_levels)? stairs, TResult? Function(List connects_levels)? lift, + TResult? Function()? foodDrink, TResult? Function(List bus_lines, List tram_lines)? publicTransport, + TResult? Function(String roomNumber)? pcPool, }) { return toilet?.call(toilet_type); } @@ -1068,13 +1164,15 @@ class _$ToiletImpl implements Toilet { TResult maybeWhen({ TResult Function()? building, TResult Function()? lectureHall, - TResult Function()? room, + TResult Function(String roomNumber)? room, TResult Function(List connects)? door, TResult Function(String toilet_type)? toilet, TResult Function(List connects_levels)? stairs, TResult Function(List connects_levels)? lift, + TResult Function()? foodDrink, TResult Function(List bus_lines, List tram_lines)? publicTransport, + TResult Function(String roomNumber)? pcPool, required TResult orElse(), }) { if (toilet != null) { @@ -1093,7 +1191,9 @@ class _$ToiletImpl implements Toilet { required TResult Function(Toilet value) toilet, required TResult Function(Stairs value) stairs, required TResult Function(Lift value) lift, + required TResult Function(FoodDrink value) foodDrink, required TResult Function(PublicTransport value) publicTransport, + required TResult Function(PcPool value) pcPool, }) { return toilet(this); } @@ -1108,7 +1208,9 @@ class _$ToiletImpl implements Toilet { TResult? Function(Toilet value)? toilet, TResult? Function(Stairs value)? stairs, TResult? Function(Lift value)? lift, + TResult? Function(FoodDrink value)? foodDrink, TResult? Function(PublicTransport value)? publicTransport, + TResult? Function(PcPool value)? pcPool, }) { return toilet?.call(this); } @@ -1123,7 +1225,9 @@ class _$ToiletImpl implements Toilet { TResult Function(Toilet value)? toilet, TResult Function(Stairs value)? stairs, TResult Function(Lift value)? lift, + TResult Function(FoodDrink value)? foodDrink, TResult Function(PublicTransport value)? publicTransport, + TResult Function(PcPool value)? pcPool, required TResult orElse(), }) { if (toilet != null) { @@ -1216,13 +1320,15 @@ class _$StairsImpl implements Stairs { TResult when({ required TResult Function() building, required TResult Function() lectureHall, - required TResult Function() room, + required TResult Function(String roomNumber) room, required TResult Function(List connects) door, required TResult Function(String toilet_type) toilet, required TResult Function(List connects_levels) stairs, required TResult Function(List connects_levels) lift, + required TResult Function() foodDrink, required TResult Function(List bus_lines, List tram_lines) publicTransport, + required TResult Function(String roomNumber) pcPool, }) { return stairs(connects_levels); } @@ -1232,13 +1338,15 @@ class _$StairsImpl implements Stairs { TResult? whenOrNull({ TResult? Function()? building, TResult? Function()? lectureHall, - TResult? Function()? room, + TResult? Function(String roomNumber)? room, TResult? Function(List connects)? door, TResult? Function(String toilet_type)? toilet, TResult? Function(List connects_levels)? stairs, TResult? Function(List connects_levels)? lift, + TResult? Function()? foodDrink, TResult? Function(List bus_lines, List tram_lines)? publicTransport, + TResult? Function(String roomNumber)? pcPool, }) { return stairs?.call(connects_levels); } @@ -1248,13 +1356,15 @@ class _$StairsImpl implements Stairs { TResult maybeWhen({ TResult Function()? building, TResult Function()? lectureHall, - TResult Function()? room, + TResult Function(String roomNumber)? room, TResult Function(List connects)? door, TResult Function(String toilet_type)? toilet, TResult Function(List connects_levels)? stairs, TResult Function(List connects_levels)? lift, + TResult Function()? foodDrink, TResult Function(List bus_lines, List tram_lines)? publicTransport, + TResult Function(String roomNumber)? pcPool, required TResult orElse(), }) { if (stairs != null) { @@ -1273,7 +1383,9 @@ class _$StairsImpl implements Stairs { required TResult Function(Toilet value) toilet, required TResult Function(Stairs value) stairs, required TResult Function(Lift value) lift, + required TResult Function(FoodDrink value) foodDrink, required TResult Function(PublicTransport value) publicTransport, + required TResult Function(PcPool value) pcPool, }) { return stairs(this); } @@ -1288,7 +1400,9 @@ class _$StairsImpl implements Stairs { TResult? Function(Toilet value)? toilet, TResult? Function(Stairs value)? stairs, TResult? Function(Lift value)? lift, + TResult? Function(FoodDrink value)? foodDrink, TResult? Function(PublicTransport value)? publicTransport, + TResult? Function(PcPool value)? pcPool, }) { return stairs?.call(this); } @@ -1303,7 +1417,9 @@ class _$StairsImpl implements Stairs { TResult Function(Toilet value)? toilet, TResult Function(Stairs value)? stairs, TResult Function(Lift value)? lift, + TResult Function(FoodDrink value)? foodDrink, TResult Function(PublicTransport value)? publicTransport, + TResult Function(PcPool value)? pcPool, required TResult orElse(), }) { if (stairs != null) { @@ -1395,13 +1511,15 @@ class _$LiftImpl implements Lift { TResult when({ required TResult Function() building, required TResult Function() lectureHall, - required TResult Function() room, + required TResult Function(String roomNumber) room, required TResult Function(List connects) door, required TResult Function(String toilet_type) toilet, required TResult Function(List connects_levels) stairs, required TResult Function(List connects_levels) lift, + required TResult Function() foodDrink, required TResult Function(List bus_lines, List tram_lines) publicTransport, + required TResult Function(String roomNumber) pcPool, }) { return lift(connects_levels); } @@ -1411,13 +1529,15 @@ class _$LiftImpl implements Lift { TResult? whenOrNull({ TResult? Function()? building, TResult? Function()? lectureHall, - TResult? Function()? room, + TResult? Function(String roomNumber)? room, TResult? Function(List connects)? door, TResult? Function(String toilet_type)? toilet, TResult? Function(List connects_levels)? stairs, TResult? Function(List connects_levels)? lift, + TResult? Function()? foodDrink, TResult? Function(List bus_lines, List tram_lines)? publicTransport, + TResult? Function(String roomNumber)? pcPool, }) { return lift?.call(connects_levels); } @@ -1427,13 +1547,15 @@ class _$LiftImpl implements Lift { TResult maybeWhen({ TResult Function()? building, TResult Function()? lectureHall, - TResult Function()? room, + TResult Function(String roomNumber)? room, TResult Function(List connects)? door, TResult Function(String toilet_type)? toilet, TResult Function(List connects_levels)? stairs, TResult Function(List connects_levels)? lift, + TResult Function()? foodDrink, TResult Function(List bus_lines, List tram_lines)? publicTransport, + TResult Function(String roomNumber)? pcPool, required TResult orElse(), }) { if (lift != null) { @@ -1452,7 +1574,9 @@ class _$LiftImpl implements Lift { required TResult Function(Toilet value) toilet, required TResult Function(Stairs value) stairs, required TResult Function(Lift value) lift, + required TResult Function(FoodDrink value) foodDrink, required TResult Function(PublicTransport value) publicTransport, + required TResult Function(PcPool value) pcPool, }) { return lift(this); } @@ -1467,7 +1591,9 @@ class _$LiftImpl implements Lift { TResult? Function(Toilet value)? toilet, TResult? Function(Stairs value)? stairs, TResult? Function(Lift value)? lift, + TResult? Function(FoodDrink value)? foodDrink, TResult? Function(PublicTransport value)? publicTransport, + TResult? Function(PcPool value)? pcPool, }) { return lift?.call(this); } @@ -1482,7 +1608,9 @@ class _$LiftImpl implements Lift { TResult Function(Toilet value)? toilet, TResult Function(Stairs value)? stairs, TResult Function(Lift value)? lift, + TResult Function(FoodDrink value)? foodDrink, TResult Function(PublicTransport value)? publicTransport, + TResult Function(PcPool value)? pcPool, required TResult orElse(), }) { if (lift != null) { @@ -1501,6 +1629,159 @@ abstract class Lift implements FeatureType { throw _privateConstructorUsedError; } +/// @nodoc +abstract class _$$FoodDrinkImplCopyWith<$Res> { + factory _$$FoodDrinkImplCopyWith( + _$FoodDrinkImpl value, $Res Function(_$FoodDrinkImpl) then) = + __$$FoodDrinkImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$FoodDrinkImplCopyWithImpl<$Res> + extends _$FeatureTypeCopyWithImpl<$Res, _$FoodDrinkImpl> + implements _$$FoodDrinkImplCopyWith<$Res> { + __$$FoodDrinkImplCopyWithImpl( + _$FoodDrinkImpl _value, $Res Function(_$FoodDrinkImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$FoodDrinkImpl implements FoodDrink { + const _$FoodDrinkImpl(); + + @override + String toString() { + return 'FeatureType.foodDrink()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$FoodDrinkImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function(String roomNumber) room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function() foodDrink, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + required TResult Function(String roomNumber) pcPool, + }) { + return foodDrink(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function(String roomNumber)? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function()? foodDrink, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + TResult? Function(String roomNumber)? pcPool, + }) { + return foodDrink?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function(String roomNumber)? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function()? foodDrink, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + TResult Function(String roomNumber)? pcPool, + required TResult orElse(), + }) { + if (foodDrink != null) { + return foodDrink(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(FoodDrink value) foodDrink, + required TResult Function(PublicTransport value) publicTransport, + required TResult Function(PcPool value) pcPool, + }) { + return foodDrink(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(FoodDrink value)? foodDrink, + TResult? Function(PublicTransport value)? publicTransport, + TResult? Function(PcPool value)? pcPool, + }) { + return foodDrink?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(FoodDrink value)? foodDrink, + TResult Function(PublicTransport value)? publicTransport, + TResult Function(PcPool value)? pcPool, + required TResult orElse(), + }) { + if (foodDrink != null) { + return foodDrink(this); + } + return orElse(); + } +} + +abstract class FoodDrink implements FeatureType { + const factory FoodDrink() = _$FoodDrinkImpl; +} + /// @nodoc abstract class _$$PublicTransportImplCopyWith<$Res> { factory _$$PublicTransportImplCopyWith(_$PublicTransportImpl value, @@ -1595,13 +1876,15 @@ class _$PublicTransportImpl implements PublicTransport { TResult when({ required TResult Function() building, required TResult Function() lectureHall, - required TResult Function() room, + required TResult Function(String roomNumber) room, required TResult Function(List connects) door, required TResult Function(String toilet_type) toilet, required TResult Function(List connects_levels) stairs, required TResult Function(List connects_levels) lift, + required TResult Function() foodDrink, required TResult Function(List bus_lines, List tram_lines) publicTransport, + required TResult Function(String roomNumber) pcPool, }) { return publicTransport(bus_lines, tram_lines); } @@ -1611,13 +1894,15 @@ class _$PublicTransportImpl implements PublicTransport { TResult? whenOrNull({ TResult? Function()? building, TResult? Function()? lectureHall, - TResult? Function()? room, + TResult? Function(String roomNumber)? room, TResult? Function(List connects)? door, TResult? Function(String toilet_type)? toilet, TResult? Function(List connects_levels)? stairs, TResult? Function(List connects_levels)? lift, + TResult? Function()? foodDrink, TResult? Function(List bus_lines, List tram_lines)? publicTransport, + TResult? Function(String roomNumber)? pcPool, }) { return publicTransport?.call(bus_lines, tram_lines); } @@ -1627,13 +1912,15 @@ class _$PublicTransportImpl implements PublicTransport { TResult maybeWhen({ TResult Function()? building, TResult Function()? lectureHall, - TResult Function()? room, + TResult Function(String roomNumber)? room, TResult Function(List connects)? door, TResult Function(String toilet_type)? toilet, TResult Function(List connects_levels)? stairs, TResult Function(List connects_levels)? lift, + TResult Function()? foodDrink, TResult Function(List bus_lines, List tram_lines)? publicTransport, + TResult Function(String roomNumber)? pcPool, required TResult orElse(), }) { if (publicTransport != null) { @@ -1652,7 +1939,9 @@ class _$PublicTransportImpl implements PublicTransport { required TResult Function(Toilet value) toilet, required TResult Function(Stairs value) stairs, required TResult Function(Lift value) lift, + required TResult Function(FoodDrink value) foodDrink, required TResult Function(PublicTransport value) publicTransport, + required TResult Function(PcPool value) pcPool, }) { return publicTransport(this); } @@ -1667,7 +1956,9 @@ class _$PublicTransportImpl implements PublicTransport { TResult? Function(Toilet value)? toilet, TResult? Function(Stairs value)? stairs, TResult? Function(Lift value)? lift, + TResult? Function(FoodDrink value)? foodDrink, TResult? Function(PublicTransport value)? publicTransport, + TResult? Function(PcPool value)? pcPool, }) { return publicTransport?.call(this); } @@ -1682,7 +1973,9 @@ class _$PublicTransportImpl implements PublicTransport { TResult Function(Toilet value)? toilet, TResult Function(Stairs value)? stairs, TResult Function(Lift value)? lift, + TResult Function(FoodDrink value)? foodDrink, TResult Function(PublicTransport value)? publicTransport, + TResult Function(PcPool value)? pcPool, required TResult orElse(), }) { if (publicTransport != null) { @@ -1703,3 +1996,188 @@ abstract class PublicTransport implements FeatureType { _$$PublicTransportImplCopyWith<_$PublicTransportImpl> get copyWith => throw _privateConstructorUsedError; } + +/// @nodoc +abstract class _$$PcPoolImplCopyWith<$Res> { + factory _$$PcPoolImplCopyWith( + _$PcPoolImpl value, $Res Function(_$PcPoolImpl) then) = + __$$PcPoolImplCopyWithImpl<$Res>; + @useResult + $Res call({String roomNumber}); +} + +/// @nodoc +class __$$PcPoolImplCopyWithImpl<$Res> + extends _$FeatureTypeCopyWithImpl<$Res, _$PcPoolImpl> + implements _$$PcPoolImplCopyWith<$Res> { + __$$PcPoolImplCopyWithImpl( + _$PcPoolImpl _value, $Res Function(_$PcPoolImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? roomNumber = null, + }) { + return _then(_$PcPoolImpl( + null == roomNumber + ? _value.roomNumber + : roomNumber // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$PcPoolImpl implements PcPool { + const _$PcPoolImpl(this.roomNumber); + + @override + final String roomNumber; + + @override + String toString() { + return 'FeatureType.pcPool(roomNumber: $roomNumber)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PcPoolImpl && + (identical(other.roomNumber, roomNumber) || + other.roomNumber == roomNumber)); + } + + @override + int get hashCode => Object.hash(runtimeType, roomNumber); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PcPoolImplCopyWith<_$PcPoolImpl> get copyWith => + __$$PcPoolImplCopyWithImpl<_$PcPoolImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() building, + required TResult Function() lectureHall, + required TResult Function(String roomNumber) room, + required TResult Function(List connects) door, + required TResult Function(String toilet_type) toilet, + required TResult Function(List connects_levels) stairs, + required TResult Function(List connects_levels) lift, + required TResult Function() foodDrink, + required TResult Function(List bus_lines, List tram_lines) + publicTransport, + required TResult Function(String roomNumber) pcPool, + }) { + return pcPool(roomNumber); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? building, + TResult? Function()? lectureHall, + TResult? Function(String roomNumber)? room, + TResult? Function(List connects)? door, + TResult? Function(String toilet_type)? toilet, + TResult? Function(List connects_levels)? stairs, + TResult? Function(List connects_levels)? lift, + TResult? Function()? foodDrink, + TResult? Function(List bus_lines, List tram_lines)? + publicTransport, + TResult? Function(String roomNumber)? pcPool, + }) { + return pcPool?.call(roomNumber); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? building, + TResult Function()? lectureHall, + TResult Function(String roomNumber)? room, + TResult Function(List connects)? door, + TResult Function(String toilet_type)? toilet, + TResult Function(List connects_levels)? stairs, + TResult Function(List connects_levels)? lift, + TResult Function()? foodDrink, + TResult Function(List bus_lines, List tram_lines)? + publicTransport, + TResult Function(String roomNumber)? pcPool, + required TResult orElse(), + }) { + if (pcPool != null) { + return pcPool(roomNumber); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Building value) building, + required TResult Function(LectureHall value) lectureHall, + required TResult Function(Room value) room, + required TResult Function(Door value) door, + required TResult Function(Toilet value) toilet, + required TResult Function(Stairs value) stairs, + required TResult Function(Lift value) lift, + required TResult Function(FoodDrink value) foodDrink, + required TResult Function(PublicTransport value) publicTransport, + required TResult Function(PcPool value) pcPool, + }) { + return pcPool(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Building value)? building, + TResult? Function(LectureHall value)? lectureHall, + TResult? Function(Room value)? room, + TResult? Function(Door value)? door, + TResult? Function(Toilet value)? toilet, + TResult? Function(Stairs value)? stairs, + TResult? Function(Lift value)? lift, + TResult? Function(FoodDrink value)? foodDrink, + TResult? Function(PublicTransport value)? publicTransport, + TResult? Function(PcPool value)? pcPool, + }) { + return pcPool?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Building value)? building, + TResult Function(LectureHall value)? lectureHall, + TResult Function(Room value)? room, + TResult Function(Door value)? door, + TResult Function(Toilet value)? toilet, + TResult Function(Stairs value)? stairs, + TResult Function(Lift value)? lift, + TResult Function(FoodDrink value)? foodDrink, + TResult Function(PublicTransport value)? publicTransport, + TResult Function(PcPool value)? pcPool, + required TResult orElse(), + }) { + if (pcPool != null) { + return pcPool(this); + } + return orElse(); + } +} + +abstract class PcPool implements FeatureType { + const factory PcPool(final String roomNumber) = _$PcPoolImpl; + + String get roomNumber; + @JsonKey(ignore: true) + _$$PcPoolImplCopyWith<_$PcPoolImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/data/geo/parser.dart b/lib/data/geo/parser.dart index 9b03b79..7e5c09d 100644 --- a/lib/data/geo/parser.dart +++ b/lib/data/geo/parser.dart @@ -20,17 +20,20 @@ Result parseFeature( // try parse yaml if (description_yaml == null) { - print("warn: Description key is missing for feature $name"); + print( + "warn: Description key is missing for feature $name\n\n$geometry\n\n$properties"); } if (layer == null) { - return bail("Layer key \'layer\' is missing for feature $name"); + return bail( + "Layer key \'layer\' is missing for feature $name\n\n$geometry\n\n$properties"); } dynamic yaml; try { yaml = loadYaml(description_yaml); } on YamlException catch (e) { - return bail("Couldn't parse YAML in description for feature $name: $e"); + return bail( + "Couldn't parse YAML in description for feature $name\n\n$description_yaml\n\nError: $e"); } yaml = yaml as YamlMap? ?? {}; @@ -70,8 +73,16 @@ Result parseFeature( case 'lecture_hall': type = FeatureType.lectureHall(); break; - case 'room': - type = FeatureType.room(); + case 'seminar_room': + type = FeatureType.room(getYamlKeyStringify(yaml, 'number') + .expect("Couldn't parse 'number' for seminar_room feature $name")); + break; + case 'pc_pool': + type = FeatureType.pcPool(getYamlKeyStringify(yaml, 'number') + .expect("Couldn't parse 'number' for PcPool feature $name")); + break; + case 'food_drink': + type = FeatureType.foodDrink(); break; case 'door': final list = getYamlList(yaml, 'connects') @@ -84,10 +95,8 @@ Result parseFeature( type = FeatureType.toilet(toiletType); break; case 'public_transport': - final busLines = getYamlList(yaml, 'bus_lines') - .expect("Couldn't parse 'bus_lines' for feature $name"); - final tramLines = getYamlList(yaml, 'tram_lines') - .expect("Couldn't parse 'tram_lines' for feature $name"); + final busLines = getYamlList(yaml, 'bus_lines').unwrapOr([]); + final tramLines = getYamlList(yaml, 'tram_lines').unwrapOr([]); type = FeatureType.publicTransport( stringifyList(busLines) @@ -146,3 +155,15 @@ Result getYamlKey(YamlMap yaml, String key) { return bail("Failed to parse yaml key $key as ${T.toString()}: $e"); } } + +Result getYamlKeyStringify(YamlMap yaml, String key) { + try { + final val = yaml[key] as T?; + if (val == null) { + return bail("Key $key is missing in yaml"); + } + return Ok(val.toString()); + } catch (e) { + return bail("Failed to parse yaml key $key as ${T.toString()}: $e"); + } +} diff --git a/lib/main.dart b/lib/main.dart index 2d5af76..1621bc9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,20 +1,21 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; -import 'package:uninav/controllers/isar_controller.dart'; import 'package:uninav/controllers/map_controller.dart'; +import 'package:uninav/controllers/shared_prefs_controller.dart'; import 'package:uninav/map.dart'; import 'package:uninav/settings.dart'; // TODO: maybe make not async? -void main() async { +void main() { Get.put(MyMapController()); - await Get.find() - .loadGeoJson(await rootBundle.loadString('assets/geo/uulm_beta.geojson')); + rootBundle + .loadString('assets/geo/uulm_beta.geojson') + .then((value) => Get.find().loadGeoJson(value)); - await Get.putAsync(() async { - final controller = IsarController(); - await controller.initializeIsar(); + Get.putAsync(() async { + final controller = SharedPrefsController(); + await controller.initialize(); return controller; }); runApp(const MyApp()); diff --git a/lib/map.dart b/lib/map.dart index a1bf028..7d62167 100644 --- a/lib/map.dart +++ b/lib/map.dart @@ -1,7 +1,9 @@ import 'package:anim_search_bar/anim_search_bar.dart'; +import 'package:anyhow/anyhow.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_map/flutter_map.dart'; +import 'package:flutter_map_location_marker/flutter_map_location_marker.dart'; import 'package:get/get.dart'; import 'package:latlong2/latlong.dart'; import 'package:rust_core/slice.dart'; @@ -42,8 +44,10 @@ class MapPage extends StatelessWidget { floatingActionButton: FloatingActionButton( onPressed: () async { // Add onPressed logic here + var future = Get.find().getCurrentPosition(); + locationBottomSheet(); }, - child: const Icon(Icons.add), + child: const Icon(Icons.location_searching), ), body: Stack( children: [ @@ -105,6 +109,7 @@ class MapPage extends StatelessWidget { Get.find().currentLevel.value, )), ), + CurrentLocationLayer(), ], ), Positioned( @@ -176,3 +181,171 @@ class MapPage extends StatelessWidget { )); } } + +void locationBottomSheet() { + print(Get.find().position.value); + String buttonText = "Search for Location"; + IconData locationIcon = Icons.location_searching; + bool spinner = false; + Get.bottomSheet( + Theme( + data: ThemeData.light(), + child: Container( + constraints: const BoxConstraints( + // minHeight: 300, + ), + width: Get.mediaQuery.size.width, + decoration: const BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), + topRight: Radius.circular(30), + ), + ), + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Center( + child: Container( + width: 50, + height: 5, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + ), + ), + ), + const SizedBox(height: 10), + const Text( + 'Select Location', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + const SizedBox(height: 20), + Row( + children: [ + Expanded( + flex: 2, + child: Container( + height: 300, + color: Colors.transparent, + ), + ), + Expanded( + flex: 1, + child: StatefulBuilder(builder: (context, setState) { + // TODO: make this persist closing the bottom sheet + return ElevatedButton( + style: ElevatedButton.styleFrom( + fixedSize: const Size(300, 300), + backgroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + padding: const EdgeInsets.all(15), + ), + onPressed: () async { + if (spinner) { + return; + } + setState(() { + buttonText = "Searching..."; + locationIcon = Icons.location_searching; + spinner = true; + }); + final pos = await Get.find() + .getCurrentPosition(); + if (!context.mounted) { + return; + } + if (pos case Ok(:final ok)) { + setState(() { + buttonText = "Location found!"; + locationIcon = Icons.my_location; + spinner = false; + }); + } else { + setState(() { + buttonText = "Location not found! Try again"; + locationIcon = Icons.error; + spinner = false; + }); + } + }, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Stack( + alignment: Alignment.center, + children: [ + Icon(locationIcon, + size: 80, + color: Get.theme.colorScheme.inversePrimary), + if (spinner) + CircularProgressIndicator( + color: Get.theme.colorScheme.inversePrimary, + ), + ], + ), + const SizedBox( + height: 12, + ), + Text( + buttonText, + softWrap: true, + textAlign: TextAlign.center, + style: const TextStyle( + color: Colors.black, + fontSize: 16, + fontWeight: FontWeight.bold), + ), + ], + ), + ); + }), + ), + ], + ), + /* + ListTile( + title: const Text( + 'Current Location', + style: TextStyle(color: Colors.white), + ), + onTap: () { + Get.back(); + }, + ), + ListTile( + title: const Text( + 'Search Location', + style: TextStyle(color: Colors.white), + ), + onTap: () { + Get.back(); + }, + ), + const SizedBox(height: 20), + */ + ElevatedButton( + child: const Text( + 'Cancel', + style: TextStyle(color: Colors.black), + ), + onPressed: () { + Get.back(); + }, + ), + ], + ), + ), + ), + isScrollControlled: true, + enterBottomSheetDuration: const Duration(milliseconds: 150), + exitBottomSheetDuration: const Duration(milliseconds: 200), + ); +} diff --git a/lib/nav/graph.dart.old b/lib/nav/graph.dart.old new file mode 100644 index 0000000..e03ef04 --- /dev/null +++ b/lib/nav/graph.dart.old @@ -0,0 +1,647 @@ +import 'package:anyhow/anyhow.dart'; +import 'package:collection/collection.dart'; +import 'package:directed_graph/directed_graph.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter/foundation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:geojson_vi/geojson_vi.dart'; +import 'package:get/get.dart'; +import 'package:latlong2/latlong.dart'; +import 'package:rust_core/iter.dart'; +import 'package:uninav/data/geo/model.dart'; +import 'package:uninav/util/geojson_util.dart'; +import 'package:uninav/util/util.dart'; +import 'dart:collection'; + +part 'graph.freezed.dart'; + +@freezed +class GraphFeature with _$GraphFeature { + const factory GraphFeature.buildingFloor(int floor, Feature building) = + BuildingFloor; + const factory GraphFeature.portal(int fromFloor, String from, int toFloor, + String to, Feature baseFeature) = Portal; + const factory GraphFeature.basicFeature( + int floor, String building, Feature feature) = BasicFeature; + + const GraphFeature._(); + + Result getCenter() { + return when( + buildingFloor: (floor, building) => building.getCenterPoint(), + portal: (fromFloor, from, toFloor, to, baseFeature) => + baseFeature.getCenterPoint(), + basicFeature: (floor, building, feature) => feature.getCenterPoint(), + ); + } + + double distanceTo(GraphFeature other, String unit) => distanceBetweenLatLng( + getCenter().unwrap(), other.getCenter().unwrap(), unit); + + double metersTo(GraphFeature other) => distanceTo(other, "meters"); + + @override + String toString() { + return when( + buildingFloor: (floor, building) => 'Floor (${building.name}:$floor)', + portal: (fromFloor, from, toFloor, to, _) => + 'Portal ($from:$fromFloor -> $to:$toFloor)', + basicFeature: (floor, building, feature) => + 'Feature (${formatFeatureTitle(feature)} ($building:$floor))', + ); + } + + @override + int get hashCode { + return when( + buildingFloor: (floor, building) => Object.hash(floor, building), + portal: (fromFloor, from, toFloor, to, baseFeature) => + Object.hash(fromFloor, from, toFloor, to, baseFeature), + basicFeature: (floor, building, feature) => + Object.hash(floor, building, feature), + ); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is GraphFeature && + other.when( + buildingFloor: (floor, building) => + this is BuildingFloor && + (this as BuildingFloor).floor == floor && + (this as BuildingFloor).building == building, + portal: (fromFloor, from, toFloor, to, baseFeature) => + this is Portal && + (this as Portal).fromFloor == fromFloor && + (this as Portal).from == from && + (this as Portal).toFloor == toFloor && + (this as Portal).to == to && + (this as Portal).baseFeature == baseFeature, + basicFeature: (floor, building, feature) => + this is BasicFeature && + (this as BasicFeature).floor == floor && + (this as BasicFeature).building == building && + (this as BasicFeature).feature == feature, + ); + } +} + +class Graph { + final List<(GraphFeature, double, GraphFeature)> _edges = []; + final HashSet _nodes = HashSet(); + final HashSet<(GraphFeature, GraphFeature)> _edgesSet = HashSet(); + + Iterable get nodes => _nodes.iter(); + + void addNode(GraphFeature node) { + _nodes.add(node); + if (node is BasicFeature && node.feature.name == 'H22') { + print(node); + print(node.hashCode); + } + } + + void addEdge(GraphFeature from, GraphFeature to, double weight) { + addNode(from); + addNode(to); + if (!_edgesSet.contains((from, to))) { + _edgesSet.add((from, to)); + _edges.add((from, weight, to)); + } + if (!_edgesSet.contains((to, from))) { + _edgesSet.add((to, from)); + _edges.add((to, weight, from)); + } + } + + List<(GraphFeature, double, GraphFeature)> getEdges(GraphFeature node) { + return _edges.where((edge) => edge.$1 == node).toList(); + } + + bool contains(GraphFeature node) { + return _nodes.contains(node); + } + + bool containsEdge(GraphFeature from, GraphFeature to) { + return _edgesSet.contains((from, to)); + } + + @override + String toString() { + return 'Graph(_edges: $_edges, _nodes: $_nodes, _edgesSet: $_edgesSet)'; + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is Graph && + listEquals(other._edges, _edges) && + setEquals(other._nodes, _nodes) && + setEquals(other._edgesSet, _edgesSet); + } + + @override + int get hashCode => _edges.hashCode ^ _nodes.hashCode ^ _edgesSet.hashCode; +} + +IList wrap(Feature feature, int floor, String buildingFrom) { + return feature.type + .maybeWhen( + building: () => [GraphFeature.buildingFloor(floor, feature)], + stairs: (floors) => stairPortalGenerator(floors, floor, feature), + lift: (floors) => stairPortalGenerator(floors, floor, feature, 99), + door: (connections) => + doorPortalGenerator(connections, floor, buildingFrom, feature), + orElse: () => [ + GraphFeature.basicFeature( + floor, feature.building ?? buildingFrom, feature) + ], + ) + .lock; +} + +List doorPortalGenerator( + List connections, int floor, String from, Feature feature) { + final portals = []; + + for (final connection in connections.where((c) => !eq(c, from))) { + portals.add(GraphFeature.portal(floor, from, floor, connection, feature)); + } + + return portals; +} + +List stairPortalGenerator( + List floors, int floor, Feature feature, + [int maxDist = 1]) { + final portals = []; + for (int i = 1; i <= maxDist; i++) { + if (floors.contains(floor - i)) { + portals.add(GraphFeature.portal( + floor, feature.building!, floor - i, feature.building!, feature)); + } + if (floors.contains(floor + i)) { + portals.add(GraphFeature.portal( + floor, feature.building!, floor + i, feature.building!, feature)); + } + } + return portals; +} + +Feature unwrap(GraphFeature feature) { + return feature.when( + buildingFloor: (floor, building) => building, + portal: (fromFloor, from, toFloor, to, baseFeature) => baseFeature, + basicFeature: (floor, building, f) => f, + ); +} + +double sum(double left, double right) => left + right; + +// WeightedDirectedGraph createGraph(Feature origin, List allFeatures) { +// +// } + +List findAdjacent( + GraphFeature feature, Iterable allFeatures) { + List adjacentFeatures = []; + + if (feature is BuildingFloor) { + // find all features in the building on the right floor + adjacentFeatures = allFeatures + .where((f) => eq(f.building, feature.building.name) || f.type is Door) + .where((f) => f.type.maybeWhen( + lift: (levels) => levels.contains(feature.floor), + stairs: (levels) => levels.contains(feature.floor), + door: (connections) => + f.level == feature.floor && + connections + .map((e) => e.toLowerCase()) + .contains(feature.building.name.toLowerCase()), + orElse: () => f.level == feature.floor)) + .mapMany((f) => wrap(f, feature.floor, feature.building.name)) + .toList(); + } else if (feature is Portal) { + adjacentFeatures = allFeatures + .where((f) => eq(f.name, feature.to) && f.type is Building) + .mapMany((f) => wrap(f, feature.toFloor, feature.to)) + .toList(); + } else if (feature is BasicFeature) { + adjacentFeatures = allFeatures + .where( + (f) => eq(f.name, feature.feature.building) && f.type is Building) + .mapMany((f) => wrap(f, feature.feature.level!, f.name)) + .toList(); + } + return adjacentFeatures; +} + +Graph makeGraph(GraphFeature origin, List allFeatures, + [Graph? graph]) { + // final usedFeatures = [origin]; + + graph ??= Graph(); + graph.addNode(origin); + + final adjacent = findAdjacent(origin, allFeatures); + for (final feature in adjacent.asSet()..removeAll(graph.nodes)) { + graph.addEdge(origin, feature, origin.metersTo(feature)); + final _ = makeGraph(feature, allFeatures, graph); + // graph.addAll(deeper); + } + + return graph; +} + +List createGraphList( + GraphFeature origin, List allFeatures, + [Set? visited]) { + // final usedFeatures = [origin]; + + visited ??= {origin}; + + final adjacent = findAdjacent(origin, allFeatures); + for (final feature in adjacent.asSet()..removeAll(visited)) { + visited.add(feature); + final deeper = createGraphList(feature, allFeatures, visited); + visited.addAll(deeper); + } + + return visited.toList(); +} + +Map> createGraphMap( + GraphFeature origin, List allFeatures) { + final graphList = createGraphList(origin, allFeatures); + final graphMap = >{}; + for (final node in graphList) { + final adjacents = node.when( + buildingFloor: (floor, building) { + return graphList + .where((f) => + f is Portal && + eq(f.from, building.name) && + f.fromFloor == floor || + f is BasicFeature && + eq(f.building, building.name) && + f.floor == floor) + .map((f) => f.when( + portal: (fromFloor, from, toFloor, to, baseFeature) => ( + f, + f.metersTo(node), + ), + basicFeature: (floor, building, feature) => + (f, f.metersTo(node)), + buildingFloor: (floor, building) => throw StateError( + "BUG: createGraphMap(): BuildingFloors shouldn't " + "be matched by BuildingFloors"), + )); + }, + portal: (fromFloor, from, toFloor, to, baseFeature) { + return graphList + .where((f) => + f is BuildingFloor && + eq(f.building.name, to) && + f.floor == toFloor) + .map((f) => f.when( + portal: (fromFloor, from, toFloor, to, baseFeature) => + throw StateError( + "BUG: createGraphMap(): Portals shouldn't " + "be matched by Portals"), + basicFeature: (floor, building, feature) => throw StateError( + "BUG: createGraphMap(): BasicFeatures shouldn't " + "be matched by BasicFeatures"), + buildingFloor: (floor, building) => ( + f, + f.metersTo(node) + + 5 /* 5 extra meters for all portals. TODO: smarter!*/ + ), + )); + }, + basicFeature: (floor, building, feature) { + return graphList + .where((f) => + f is BuildingFloor && + eq(f.building.name, building) && + f.floor == floor) + .map((f) => f.when( + portal: (fromFloor, from, toFloor, to, baseFeature) => + throw StateError( + "BUG: createGraphMap(): Portal shouldn't be matched " + "by BasicFeature"), + basicFeature: (floor, building, feature) => throw StateError( + "BUG: createGraphMap(): BasicFeatures shouldn't " + "be matched by BasicFeatures"), + buildingFloor: (floor, building) => (f, f.metersTo(node)), + )); + }, + ); + + graphMap[node] = + Map.fromEntries(adjacents.map((tup) => MapEntry(tup.$1, tup.$2))); + } + + return graphMap; +} + +WeightedDirectedGraph createGraph( + GraphFeature origin, List allFeatures) { + final map = createGraphMap(origin, allFeatures); + final graph = WeightedDirectedGraph( + map, + summation: sum, + zero: 0.0, + comparator: (a, b) => compareGraphFeatures(a, b), + ); + return graph; +} + +Result> findShortestPathUndir(GraphFeature origin, + bool Function(GraphFeature) destinationSelector, List allFeatures, + {heuristicVariant = "zero", heuristicMultiplier = 0.2}) { + Graph graph = makeGraph(origin, allFeatures); + + final GraphFeature? destination = + graph.nodes.firstWhereOrNull(destinationSelector); + + if (!(graph.contains(origin) && + destination != null && + graph.contains(destination))) { + return bail("Origin or destination not in graph"); + } + + // euclidean distance heuristic + + double Function(GraphFeature) heuristic = + (GraphFeature node) => 0.0; // standard zero + if (heuristicVariant == "zero") { + heuristic = (GraphFeature node) => 0.0; + } else if (heuristicVariant == "euclidean") { + heuristic = + (GraphFeature node) => node.metersTo(destination) * heuristicMultiplier; + } + + //heuristic(GraphFeature node) => 0.0; + + // openlist + // format: (heuristic, g-val, parent?, node) + PriorityQueue<(double, double, GraphFeature?, GraphFeature)> openlist = + HeapPriorityQueue( + // reverse order (cmp b to a) because lower f-val (shorter distance) is better + (a, b) => (b.$1 + b.$2).compareTo((a.$1 + a.$2)), + ); + + final Map bestPathMap = { + origin: (null, 0.0) + }; + + openlist.add((heuristic(origin), 0.0, null, origin)); + + // closed list + Set closedlist = {}; + + var cost = 0.0; + + while (openlist.isNotEmpty) { + final (f, g, parent, node) = openlist.removeFirst(); + closedlist.add(node); + bestPathMap[node] = (parent, g); + if (node == destination) { + cost = g; + break; + // TODO: restore path + } + + // expand node + final edges = graph.getEdges(node); + for (final entry in edges) { + final adjNode = entry.$3; + final adjCost = entry.$2; + + if (closedlist.contains(adjNode)) { + continue; + } + + bool found = false; + for (final open in openlist.unorderedElements) { + if (open.$4 == adjNode) { + found = true; + if (g + adjCost < open.$2) { + openlist.remove(open); + openlist.add(( + open.$1 /* heuristic stays the same */, + g + adjCost, + adjNode, + open.$4 + )); + } + break; + } + } + + if (!found) { + openlist.add(( + f + heuristic(adjNode), + g + adjCost, + node, + adjNode, + )); + } + } + } + if (bestPathMap.isNotEmpty) { + final path = <(GraphFeature, double)>[]; + (GraphFeature?, double)? currentNode = (destination, cost); + while (currentNode?.$1 != null) { + final nextNode = bestPathMap[currentNode!.$1]; + path.insert( + 0, (currentNode!.$1!, currentNode.$2 - (nextNode?.$2 ?? 0.0))); + currentNode = nextNode; + } + return Ok(path); + } + + return bail("No path found"); +} + +Result> findShortestPath( + GraphFeature origin, GraphFeature destination, List allFeatures, + [heuristicVariant = "zero", heuristicMultiplier = 0.2]) { + var graph = createGraphMap(origin, allFeatures); + + if (!(graph.keys.contains(origin) && + graph.values.firstWhereOrNull((vals) => vals.containsKey(destination)) != + null)) { + return bail("Origin or destination not in graph"); + } + + // euclidean distance heuristic + + double Function(GraphFeature) heuristic = + (GraphFeature node) => 0.0; // standard zero + if (heuristicVariant == "zero") { + heuristic = (GraphFeature node) => 0.0; + } else if (heuristicVariant == "euclidean") { + heuristic = + (GraphFeature node) => node.metersTo(destination) * heuristicMultiplier; + } + + //heuristic(GraphFeature node) => 0.0; + + // openlist + // format: (heuristic, g-val, parent?, node) + PriorityQueue<(double, double, GraphFeature?, GraphFeature)> openlist = + HeapPriorityQueue( + // reverse order (cmp b to a) because lower f-val (shorter distance) is better + (a, b) => (b.$1 + b.$2).compareTo((a.$1 + a.$2)), + ); + + final Map bestPathMap = { + origin: (null, 0.0) + }; + + openlist.add((heuristic(origin), 0.0, null, origin)); + + // closed list + Set closedlist = {}; + + var cost = 0.0; + + while (openlist.isNotEmpty) { + final (f, g, parent, node) = openlist.removeFirst(); + closedlist.add(node); + bestPathMap[node] = (parent, g); + if (node == destination) { + cost = g; + break; + // TODO: restore path + } + + // expand node + final adjacents = graph[node]!; + for (final entry in adjacents.entries) { + final adjNode = entry.key; + final adjCost = entry.value; + + if (closedlist.contains(adjNode)) { + continue; + } + + bool found = false; + for (final open in openlist.unorderedElements) { + if (open.$4 == adjNode) { + found = true; + if (g + adjCost < open.$2) { + openlist.remove(open); + openlist.add(( + open.$1 /* heuristic stays the same */, + g + adjCost, + adjNode, + open.$4 + )); + } + break; + } + } + + if (!found) { + openlist.add(( + f + heuristic(adjNode), + g + adjCost, + node, + adjNode, + )); + } + } + } + if (bestPathMap.isNotEmpty) { + final path = <(GraphFeature, double)>[]; + (GraphFeature?, double)? currentNode = (destination, cost); + while (currentNode?.$1 != null) { + final nextNode = bestPathMap[currentNode!.$1]; + path.insert( + 0, (currentNode!.$1!, currentNode.$2 - (nextNode?.$2 ?? 0.0))); + currentNode = nextNode; + } + return Ok(path); + } + + return bail("No path found"); +} + +/// Compares two [GraphFeature] instances and determines their relative order. +/// +/// The comparison is based on the specific subtypes and properties of the +/// [GraphFeature] instances. The comparison logic is as follows: +/// +/// 1. If both instances are [BuildingFloor], they are compared first by the +/// building name and then by the floor number. +/// 2. If one instance is a [Portal] and the other is a [BuildingFloor] or +/// [BasicFeature], the [Portal] is considered greater. +/// 3. If both instances are [Portal], they are compared first by the `from` +/// property, then by the `to` property, and finally by the `baseFeature` name. +/// 4. If one instance is a [BasicFeature] and the other is a [BuildingFloor] or +/// [Portal], the [BasicFeature] is considered greater. +/// 5. If both instances are [BasicFeature], they are compared first by the +/// building name, then by the floor number, and finally by the feature name. +/// +/// Returns a negative value if [a] is considered "less than" [b], a positive +/// value if [a] is considered "greater than" [b], and zero if they are considered +/// equal. +/// +/// This function can be used as a comparator for sorting or ordering +/// [GraphFeature] instances. +int compareGraphFeatures(GraphFeature a, GraphFeature b) { + return a.when( + buildingFloor: (floorA, buildingA) { + return b.when( + buildingFloor: (floorB, buildingB) { + final buildingComparison = buildingA.name.compareTo(buildingB.name); + if (buildingComparison != 0) { + return buildingComparison; + } + return floorA.compareTo(floorB); + }, + portal: (fromFloorB, fromB, toFloorB, toB, baseFeatureB) => -1, + basicFeature: (floorB, buildingB, featureB) => -1, + ); + }, + portal: (fromFloorA, fromA, toFloorA, toA, baseFeatureA) { + return b.when( + buildingFloor: (floorB, buildingB) => 1, + portal: (fromFloorB, fromB, toFloorB, toB, baseFeatureB) { + final fromComparison = fromA.compareTo(fromB); + if (fromComparison != 0) { + return fromComparison; + } + final toComparison = toA.compareTo(toB); + if (toComparison != 0) { + return toComparison; + } + return baseFeatureA.name.compareTo(baseFeatureB.name); + }, + basicFeature: (floorB, buildingB, featureB) => -1, + ); + }, + basicFeature: (floorA, buildingA, featureA) { + return b.when( + buildingFloor: (floorB, buildingB) => 1, + portal: (fromFloorB, fromB, toFloorB, toB, baseFeatureB) => 1, + basicFeature: (floorB, buildingB, featureB) { + final buildingComparison = buildingA.compareTo(buildingB); + if (buildingComparison != 0) { + return buildingComparison; + } + final floorComparison = floorA.compareTo(floorB); + if (floorComparison != 0) { + return floorComparison; + } + return featureA.name.compareTo(featureB.name); + }, + ); + }, + ); +} diff --git a/lib/settings.dart b/lib/settings.dart index bb1d4c9..93e6e9d 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -2,15 +2,15 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:uninav/components/drawer.dart'; import 'package:uninav/components/hamburger_menu.dart'; -import 'package:uninav/controllers/isar_controller.dart'; +import 'package:uninav/controllers/shared_prefs_controller.dart'; class SettingsPage extends StatelessWidget { const SettingsPage({super.key}); @override Widget build(BuildContext context) { - final isarController = Get.find(); - final settings = isarController.settings; + final persistenceController = Get.find(); + final settings = persistenceController.settings; return Scaffold( appBar: AppBar( @@ -32,90 +32,90 @@ class SettingsPage extends StatelessWidget { ), value: settings.value.showIcons, onChanged: (value) { - settings.update((val) { - val?.showIcons = value; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + showIcons: value, + ); + persistenceController.persistSettings(); }, ), SwitchListTile( title: const Text('Show Elevators'), value: settings.value.showElevators, onChanged: (value) { - settings.update((val) { - val?.showElevators = value; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + showElevators: value, + ); + persistenceController.persistSettings(); }, ), SwitchListTile( title: const Text('Show Food and Drink'), value: settings.value.showFoodAndDrink, onChanged: (value) { - settings.update((val) { - val?.showFoodAndDrink = value; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + showFoodAndDrink: value, + ); + persistenceController.persistSettings(); }, ), SwitchListTile( title: const Text('Show Lecture Halls'), value: settings.value.showLectureHalls, onChanged: (value) { - settings.update((val) { - val?.showLectureHalls = value; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + showLectureHalls: value, + ); + persistenceController.persistSettings(); }, ), SwitchListTile( title: const Text('Show Computer Pools'), value: settings.value.showComputerPools, onChanged: (value) { - settings.update((val) { - val?.showComputerPools = value; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + showComputerPools: value, + ); + persistenceController.persistSettings(); }, ), SwitchListTile( title: const Text('Show Seminar Rooms'), value: settings.value.showSeminarRooms, onChanged: (value) { - settings.update((val) { - val?.showSeminarRooms = value; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + showSeminarRooms: value, + ); + persistenceController.persistSettings(); }, ), SwitchListTile( title: const Text('Show Toilets'), value: settings.value.showToilets, onChanged: (value) { - settings.update((val) { - val?.showToilets = value; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + showToilets: value, + ); + persistenceController.persistSettings(); }, ), SwitchListTile( title: const Text('Show Stairs'), value: settings.value.showStairs, onChanged: (value) { - settings.update((val) { - val?.showStairs = value; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + showStairs: value, + ); + persistenceController.persistSettings(); }, ), SwitchListTile( title: const Text('Show Doors'), value: settings.value.showDoors, onChanged: (value) { - settings.update((val) { - val?.showDoors = value; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + showDoors: value, + ); + persistenceController.persistSettings(); }, ), const SizedBox(height: 12), @@ -127,37 +127,37 @@ class SettingsPage extends StatelessWidget { title: const Text('Male Toilets'), value: settings.value.maleToilets, onChanged: (value) { - settings.update((val) { - val?.maleToilets = value ?? false; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + maleToilets: value ?? false, + ); + persistenceController.persistSettings(); }, ), CheckboxListTile( title: const Text('Female Toilets'), value: settings.value.femaleToilets, onChanged: (value) { - settings.update((val) { - val?.femaleToilets = value ?? false; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + femaleToilets: value ?? false, + ); + persistenceController.persistSettings(); }, ), CheckboxListTile( title: const Text('Handicap Toilets'), value: settings.value.handicapToilets, onChanged: (value) { - settings.update((val) { - val?.handicapToilets = value ?? false; - }); - isarController.persistSettings(); + settings.value = settings.value.copyWith( + handicapToilets: value ?? false, + ); + persistenceController.persistSettings(); }, ), const SizedBox(height: 12), ElevatedButton( onPressed: () { - settings.value = Settings(); - isarController.persistSettings(); + settings.value = const Settings(); + persistenceController.persistSettings(); }, child: const Text("Reset Settings"), ), diff --git a/lib/util/geolocator.dart b/lib/util/geolocator.dart new file mode 100644 index 0000000..e5c87b6 --- /dev/null +++ b/lib/util/geolocator.dart @@ -0,0 +1,48 @@ +import 'package:anyhow/anyhow.dart'; +import 'package:geolocator/geolocator.dart'; + +/// Determine the current position of the device. +/// +/// When the location services are not enabled or permissions +/// are denied the `Future` will return an error. + +Future> ensureLocationPermission() async { + try { + bool serviceEnabled; + LocationPermission permission; + + // Test if location services are enabled. + serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled) { + // Location services are not enabled don't continue + // accessing the position and request users of the + // App to enable the location services. + return bail('Location services are disabled.'); + } + + permission = await Geolocator.checkPermission(); + if (permission == LocationPermission.denied) { + permission = await Geolocator.requestPermission(); + if (permission == LocationPermission.denied) { + // Permissions are denied, next time you could try + // requesting permissions again (this is also where + // Android's shouldShowRequestPermissionRationale + // returned true. According to Android guidelines + // your App should show an explanatory UI now. + return bail('Location permissions are denied'); + } + } + + if (permission == LocationPermission.deniedForever) { + // Permissions are denied forever, handle appropriately. + return bail( + 'Location permissions are permanently denied, we cannot request permissions.'); + } + + // When we reach here, permissions are granted and we can + // continue accessing the position of the device. + return const Ok(()); + } catch (e) { + return bail("Ensuring Location Permission failed: $e"); + } +} diff --git a/lib/util/util.dart b/lib/util/util.dart index c236c36..6984e03 100644 --- a/lib/util/util.dart +++ b/lib/util/util.dart @@ -26,7 +26,9 @@ String formatFeatureTitle(Feature feature) { return feature.type.when( building: () => '${feature.name} (Building)', lectureHall: () => '${feature.name} (Lecture Hall)', - room: () => 'Room ${feature.name}', + room: (number) => 'Room ${feature.building ?? "??"}/$number', + pcPool: (number) => 'PC Pool ${feature.name}', + foodDrink: () => '${feature.name} (Food/Drink)', door: (_) => 'Door', toilet: (type) => 'Toilet (${formatToiletType(feature.type as Toilet)})', stairs: (_) => 'Stairs', diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index adf3885..e7714fe 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,12 +5,16 @@ import FlutterMacOS import Foundation +import geolocator_apple import isar_flutter_libs import path_provider_foundation +import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 6acf2e4..542b102 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -193,14 +193,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" - dartx: - dependency: transitive - description: - name: dartx - sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244" - url: "https://pub.dev" - source: hosted - version: "1.2.0" directed_graph: dependency: "direct main" description: @@ -262,6 +254,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_compass: + dependency: transitive + description: + name: flutter_compass + sha256: be642484f9f6975c1c6edff568281b001f2f1e604de27ecea18d97eebbdef22f + url: "https://pub.dev" + source: hosted + version: "0.8.0" flutter_lints: dependency: "direct dev" description: @@ -278,6 +278,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.0" + flutter_map_location_marker: + dependency: "direct main" + description: + name: flutter_map_location_marker + sha256: "5873a47606b092bf181b6d17dd42a124e9a8d5d9caad58b5f98fc182e799994f" + url: "https://pub.dev" + source: hosted + version: "8.0.8" flutter_test: dependency: "direct dev" description: flutter @@ -320,6 +328,54 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.3" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "694ec58afe97787b5b72b8a0ab78c1a9244811c3c10e72c4362ef3c0ceb005cd" + url: "https://pub.dev" + source: hosted + version: "11.0.0" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: f15d1536cd01b1399578f1da1eb5d566e7a718db6a3648f2c24d2e2f859f0692 + url: "https://pub.dev" + source: hosted + version: "4.5.4" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: bc2aca02423ad429cb0556121f56e60360a2b7d694c8570301d06ea0c00732fd + url: "https://pub.dev" + source: hosted + version: "2.3.7" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "009a21c4bc2761e58dccf07c24f219adaebe0ff707abdfd40b0a763d4003fab9" + url: "https://pub.dev" + source: hosted + version: "4.2.2" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: "49d8f846ebeb5e2b6641fe477a7e97e5dd73f03cbfef3fd5c42177b7300fb0ed" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "53da08937d07c24b0d9952eb57a3b474e29aae2abf9dd717f7e1230995f13f0e" + url: "https://pub.dev" + source: hosted + version: "0.2.3" get: dependency: "direct main" description: @@ -400,14 +456,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0+1" - isar_generator: - dependency: "direct dev" - description: - name: isar_generator - sha256: "76c121e1295a30423604f2f819bc255bc79f852f3bc8743a24017df6068ad133" - url: "https://pub.dev" - source: hosted - version: "3.1.0+1" js: dependency: transitive description: @@ -680,6 +728,62 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.3" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 + url: "https://pub.dev" + source: hosted + version: "2.2.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + url: "https://pub.dev" + source: hosted + version: "2.3.5" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + url: "https://pub.dev" + source: hosted + version: "2.3.2" shelf: dependency: transitive description: @@ -789,14 +893,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.1" - time: - dependency: transitive - description: - name: time - sha256: ad8e018a6c9db36cb917a031853a1aae49467a93e0d464683e029537d848c221 - url: "https://pub.dev" - source: hosted - version: "2.1.4" timing: dependency: transitive description: @@ -957,14 +1053,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" - xxh3: - dependency: transitive - description: - name: xxh3 - sha256: a92b30944a9aeb4e3d4f3c3d4ddb3c7816ca73475cd603682c4f8149690f56d7 - url: "https://pub.dev" - source: hosted - version: "1.0.1" yaml: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 2d90027..04276f1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -51,12 +51,15 @@ dependencies: json_annotation: ^4.8.1 rust_core: ^0.5.3 anyhow: ^1.3.0 - isar: ^3.1.0+1 - isar_flutter_libs: ^3.1.0+1 + # isar: ^3.1.0+1 + # isar_flutter_libs: ^3.1.0+1 path_provider: ^2.1.3 directed_graph: ^0.4.3 fast_immutable_collections: ^10.2.2 collection: ^1.18.0 + flutter_map_location_marker: ^8.0.8 + geolocator: ^11.0.0 + shared_preferences: ^2.2.3 dev_dependencies: flutter_test: @@ -71,7 +74,7 @@ dev_dependencies: build_runner: ^2.4.9 freezed: ^2.5.2 json_serializable: ^6.7.1 - isar_generator: ^3.1.0+1 + # isar_generator: ^3.1.0+1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 65cb334..9f60d7e 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,10 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + GeolocatorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GeolocatorWindows")); IsarFlutterLibsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 439b324..cc56bce 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + geolocator_windows isar_flutter_libs url_launcher_windows )