├── tools ├── .gitignore ├── .flake8 ├── requirements.txt ├── encode_url.dart ├── print_common_keys.py ├── language_names.py ├── update.sh └── common_hours.py ├── .github ├── FUNDING.yml └── workflows │ ├── fdroid.yml │ └── build-apk.yml ├── ios ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ ├── AppDelegate.swift │ ├── Runner.entitlements │ └── Base.lproj │ │ └── Main.storyboard ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner.xcodeproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── Share Extension │ ├── ShareViewController.swift │ ├── Share Extension.entitlements │ ├── Info.plist │ └── Base.lproj │ │ └── MainInterface.storyboard ├── .gitignore └── Podfile ├── metadata ├── zh-CN │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 42.txt │ │ ├── 39.txt │ │ ├── 58.txt │ │ ├── 55.txt │ │ ├── 34.txt │ │ ├── 47.txt │ │ ├── 50.txt │ │ ├── 32.txt │ │ ├── 37.txt │ │ ├── 45.txt │ │ └── 29.txt │ └── full_description.txt ├── de-DE │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 42.txt │ │ ├── 58.txt │ │ ├── 60.txt │ │ ├── 34.txt │ │ ├── 37.txt │ │ ├── 39.txt │ │ ├── 50.txt │ │ ├── 55.txt │ │ ├── 29.txt │ │ ├── 32.txt │ │ ├── 45.txt │ │ └── 47.txt │ └── full_description.txt ├── ru │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 39.txt │ │ ├── 34.txt │ │ ├── 42.txt │ │ ├── 50.txt │ │ ├── 47.txt │ │ ├── 32.txt │ │ ├── 45.txt │ │ ├── 37.txt │ │ ├── 55.txt │ │ └── 29.txt │ └── full_description.txt ├── en-GB │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 60.txt │ │ ├── 34.txt │ │ ├── 42.txt │ │ ├── 58.txt │ │ ├── 39.txt │ │ ├── 37.txt │ │ ├── 50.txt │ │ ├── 47.txt │ │ ├── 55.txt │ │ ├── 32.txt │ │ ├── 45.txt │ │ └── 29.txt │ └── full_description.txt ├── en-US │ ├── short_description.txt │ ├── images │ │ ├── icon.png │ │ ├── featureGraphic.jpg │ │ └── phoneScreenshots │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ └── 3.jpg │ ├── changelogs │ │ ├── 48.txt │ │ ├── 60.txt │ │ ├── 34.txt │ │ ├── 42.txt │ │ ├── 58.txt │ │ ├── 39.txt │ │ ├── 37.txt │ │ ├── 50.txt │ │ ├── 55.txt │ │ ├── 47.txt │ │ ├── 32.txt │ │ ├── 45.txt │ │ └── 29.txt │ └── full_description.txt ├── es-ES │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 42.txt │ │ ├── 50.txt │ │ ├── 32.txt │ │ ├── 34.txt │ │ ├── 37.txt │ │ ├── 47.txt │ │ ├── 45.txt │ │ ├── 55.txt │ │ ├── 39.txt │ │ └── 29.txt │ └── full_description.txt ├── it-IT │ ├── short_description.txt │ ├── changelogs │ │ ├── 60.txt │ │ ├── 34.txt │ │ ├── 42.txt │ │ ├── 39.txt │ │ ├── 37.txt │ │ ├── 32.txt │ │ ├── 55.txt │ │ └── 29.txt │ └── full_description.txt ├── pt-BR │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 42.txt │ │ ├── 34.txt │ │ ├── 58.txt │ │ ├── 50.txt │ │ ├── 39.txt │ │ ├── 55.txt │ │ ├── 47.txt │ │ ├── 32.txt │ │ ├── 37.txt │ │ ├── 29.txt │ │ └── 45.txt │ └── full_description.txt ├── cs-CZ │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 34.txt │ │ ├── 42.txt │ │ ├── 60.txt │ │ ├── 39.txt │ │ ├── 58.txt │ │ ├── 37.txt │ │ ├── 50.txt │ │ ├── 55.txt │ │ ├── 47.txt │ │ ├── 32.txt │ │ ├── 45.txt │ │ └── 29.txt │ └── full_description.txt ├── hr │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 55.txt │ │ ├── 42.txt │ │ ├── 34.txt │ │ ├── 39.txt │ │ ├── 58.txt │ │ ├── 47.txt │ │ ├── 32.txt │ │ ├── 45.txt │ │ ├── 50.txt │ │ ├── 37.txt │ │ └── 29.txt │ └── full_description.txt ├── sl │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 42.txt │ │ ├── 58.txt │ │ ├── 34.txt │ │ ├── 47.txt │ │ ├── 32.txt │ │ ├── 39.txt │ │ ├── 55.txt │ │ ├── 37.txt │ │ ├── 45.txt │ │ ├── 29.txt │ │ └── 50.txt │ └── full_description.txt ├── sv-SE │ ├── short_description.txt │ └── full_description.txt ├── uk │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 60.txt │ │ ├── 42.txt │ │ ├── 58.txt │ │ ├── 34.txt │ │ ├── 55.txt │ │ ├── 47.txt │ │ ├── 50.txt │ │ ├── 37.txt │ │ ├── 32.txt │ │ ├── 39.txt │ │ ├── 45.txt │ │ └── 29.txt │ └── full_description.txt ├── da-DK │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 60.txt │ │ ├── 58.txt │ │ ├── 39.txt │ │ ├── 42.txt │ │ ├── 34.txt │ │ ├── 37.txt │ │ ├── 50.txt │ │ ├── 32.txt │ │ ├── 45.txt │ │ ├── 47.txt │ │ ├── 55.txt │ │ └── 29.txt │ └── full_description.txt ├── fi-FI │ ├── short_description.txt │ └── full_description.txt ├── hu │ ├── short_description.txt │ ├── changelogs │ │ ├── 48.txt │ │ ├── 42.txt │ │ ├── 47.txt │ │ ├── 37.txt │ │ ├── 39.txt │ │ ├── 58.txt │ │ ├── 32.txt │ │ ├── 34.txt │ │ ├── 50.txt │ │ ├── 45.txt │ │ ├── 55.txt │ │ └── 29.txt │ └── full_description.txt └── et │ ├── short_description.txt │ ├── changelogs │ ├── 48.txt │ ├── 60.txt │ ├── 34.txt │ ├── 42.txt │ ├── 55.txt │ ├── 58.txt │ ├── 45.txt │ ├── 50.txt │ ├── 47.txt │ ├── 32.txt │ ├── 37.txt │ ├── 39.txt │ └── 29.txt │ └── full_description.txt ├── icon ├── app_icon.png └── app_icon_transparent.png ├── assets ├── roofs │ ├── flat.png │ ├── round.png │ ├── gabled.png │ ├── gambrel.png │ ├── hipped.png │ ├── mansard.png │ ├── skillion.png │ ├── pyramidal.png │ └── half-hipped.png ├── styles │ ├── ofm@2x.png │ ├── sprites@2x.png │ └── buildings.json └── lets-encrypt-r3.pem ├── android ├── app │ ├── proguard-rules.pro │ └── src │ │ ├── main │ │ ├── ic_launcher-playstore.png │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── values │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ └── styles.xml │ │ │ ├── xml │ │ │ │ └── backup_rules.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ └── ic_launcher.xml │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ └── values-night │ │ │ │ └── styles.xml │ │ └── kotlin │ │ │ └── info │ │ │ └── zverev │ │ │ └── ilya │ │ │ └── every_door │ │ │ └── MainActivity.kt │ │ ├── debug │ │ └── AndroidManifest.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── build.gradle └── settings.gradle ├── .gitmodules ├── l10n.yaml ├── lib ├── providers │ ├── poi_filter.dart │ ├── need_update.dart │ ├── note_state.dart │ ├── shared_preferences.dart │ ├── api_status.dart │ ├── language.dart │ ├── edpr.dart │ ├── compass.dart │ ├── overlays.dart │ └── auth.dart ├── helpers │ ├── normalizer.dart │ ├── cache_digger.dart │ ├── yaml_map.dart │ ├── geometry │ │ ├── equirectangular.dart │ │ ├── circle_bounds.dart │ │ └── tile_range.dart │ ├── lifecycle.dart │ ├── tags │ │ ├── payment_tags.dart │ │ └── poi_warnings.dart │ ├── in_countries.dart │ ├── blend_mask.dart │ ├── tile_caches.dart │ ├── cached_svg_source.dart │ ├── location_object.dart │ ├── counter.dart │ └── log_store.dart ├── fields │ ├── room.dart │ ├── section.dart │ ├── radio.dart │ ├── wheelchair.dart │ ├── direction.dart │ ├── helpers │ │ └── new_addr.dart │ └── checkbox.dart ├── models │ ├── imagery │ │ ├── geojson.dart │ │ ├── vector_assets.dart │ │ ├── vector │ │ │ └── cache_kinds.dart │ │ ├── bing.dart │ │ ├── mbtiles.dart │ │ └── vector.dart │ ├── osm_area.dart │ ├── road_name.dart │ ├── filter.dart │ └── payment_local.dart ├── widgets │ ├── attribution.dart │ ├── pin_marker.dart │ ├── walkpath.dart │ ├── track_button.dart │ ├── round_button.dart │ ├── status_pane.dart │ ├── legend.dart │ ├── zoom_buttons.dart │ └── area_status.dart ├── screens │ ├── modes │ │ ├── navigate.dart │ │ └── definitions │ │ │ ├── notes.dart │ │ │ └── classic.dart │ └── settings │ │ └── account_list.dart ├── plugins │ ├── database.dart │ ├── providers.dart │ ├── every_door_plugin.dart │ ├── events.dart │ └── preferences.dart └── l10n │ └── app_bg.arb ├── .metadata ├── LICENSE ├── .gitignore ├── README.md └── analysis_options.yaml /tools/.gitignore: -------------------------------------------------------------------------------- 1 | *.db 2 | decode_url.dart 3 | -------------------------------------------------------------------------------- /tools/.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 100 3 | -------------------------------------------------------------------------------- /tools/requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | polygon-geohasher 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: zverik 2 | liberapay: zverik 3 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /metadata/zh-CN/short_description.txt: -------------------------------------------------------------------------------- 1 | 用于兴趣点(POI)和微地图绘制的移动端 OpenStreetMap 编辑器 2 | -------------------------------------------------------------------------------- /icon/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/icon/app_icon.png -------------------------------------------------------------------------------- /metadata/de-DE/short_description.txt: -------------------------------------------------------------------------------- 1 | OpenStreetMap-Editor für POIs & Micromapping 2 | -------------------------------------------------------------------------------- /metadata/ru/short_description.txt: -------------------------------------------------------------------------------- 1 | Мобильный редактор OpenStreetMap для заведений 2 | -------------------------------------------------------------------------------- /metadata/en-GB/short_description.txt: -------------------------------------------------------------------------------- 1 | Mobile OpenStreetMap editor for POI & micromapping 2 | -------------------------------------------------------------------------------- /metadata/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | Mobile OpenStreetMap editor for POI & micromapping 2 | -------------------------------------------------------------------------------- /metadata/es-ES/short_description.txt: -------------------------------------------------------------------------------- 1 | Editor de OpenStreetMap móvil para PDI y micromapeo 2 | -------------------------------------------------------------------------------- /metadata/it-IT/short_description.txt: -------------------------------------------------------------------------------- 1 | Editor OpenStreetMap mobile per PDI e micromapping 2 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * 新增自行车障碍物和圣诞相关要素。 2 | * 支持 “geo:” 链接。 3 | * 新的自适应图标。 4 | -------------------------------------------------------------------------------- /assets/roofs/flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/assets/roofs/flat.png -------------------------------------------------------------------------------- /assets/roofs/round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/assets/roofs/round.png -------------------------------------------------------------------------------- /metadata/pt-BR/short_description.txt: -------------------------------------------------------------------------------- 1 | Editor OpenStreetMap móvel para POI e micromapeamento 2 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * 涂鸦笔记模式。 2 | * 以本地语言显示星期。 3 | * 楼层标签建议功能。 4 | * 更新了预设和地图影像。 5 | -------------------------------------------------------------------------------- /assets/roofs/gabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/assets/roofs/gabled.png -------------------------------------------------------------------------------- /assets/roofs/gambrel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/assets/roofs/gambrel.png -------------------------------------------------------------------------------- /assets/roofs/hipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/assets/roofs/hipped.png -------------------------------------------------------------------------------- /assets/roofs/mansard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/assets/roofs/mansard.png -------------------------------------------------------------------------------- /assets/roofs/skillion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/assets/roofs/skillion.png -------------------------------------------------------------------------------- /assets/styles/ofm@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/assets/styles/ofm@2x.png -------------------------------------------------------------------------------- /metadata/cs-CZ/short_description.txt: -------------------------------------------------------------------------------- 1 | Mobilní editor OpenStreetMap pro body zájmu a mikromapování 2 | -------------------------------------------------------------------------------- /metadata/hr/short_description.txt: -------------------------------------------------------------------------------- 1 | Mobilni OpenStreetMap uređivač za točke interesa i mikromapiranje 2 | -------------------------------------------------------------------------------- /metadata/sl/short_description.txt: -------------------------------------------------------------------------------- 1 | Mobilni OpenStreetMap urejevalnik za POI in mikrokartografijo 2 | -------------------------------------------------------------------------------- /metadata/sv-SE/short_description.txt: -------------------------------------------------------------------------------- 1 | Mobil OpenStreetMap-editor för POI:er och mikrokartläggning 2 | -------------------------------------------------------------------------------- /metadata/uk/short_description.txt: -------------------------------------------------------------------------------- 1 | Мобільний редактор OpenStreetMap для POI та мікрокартографування 2 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * 修复了描述文字的大小写问题。 2 | * 修复了黄色设施警告不显示的问题。 3 | * 修复了在废弃建筑上标记商铺的问题。 4 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * 启用矢量地图。 2 | * 下载地图和影像数据,以便离线工作。 3 | * 增加指南针按钮。 4 | * 增加预设图标。 5 | -------------------------------------------------------------------------------- /assets/roofs/pyramidal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/assets/roofs/pyramidal.png -------------------------------------------------------------------------------- /metadata/da-DK/short_description.txt: -------------------------------------------------------------------------------- 1 | Mobil OpenStreetMap-editor til interessepunkter og mikrokortlægning 2 | -------------------------------------------------------------------------------- /metadata/fi-FI/short_description.txt: -------------------------------------------------------------------------------- 1 | Mobiili OpenStreetMap-editori pistekohteille ja mikrokartoitukseen 2 | -------------------------------------------------------------------------------- /metadata/hu/short_description.txt: -------------------------------------------------------------------------------- 1 | Mobiltelefonos OpenStreetMap-szerkesztő POI-khoz és mikrotérképezéshez 2 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * 支持插件功能! 2 | * 地图上的设施图标在确认后会变为绿色。 3 | * 修正了美国和以色列的星期顺序。 4 | * 显示指南针方向。 5 | -------------------------------------------------------------------------------- /assets/roofs/half-hipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/assets/roofs/half-hipped.png -------------------------------------------------------------------------------- /assets/styles/sprites@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/assets/styles/sprites@2x.png -------------------------------------------------------------------------------- /icon/app_icon_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/icon/app_icon_transparent.png -------------------------------------------------------------------------------- /metadata/en-US/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/metadata/en-US/images/icon.png -------------------------------------------------------------------------------- /metadata/et/short_description.txt: -------------------------------------------------------------------------------- 1 | Rakendus OpenStreetMapi huvipunktide muutmiseks ja mikrokaardistamiseks 2 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * 更新了预设和地图影像。 2 | * 修复了注记(note)丢失和设施重复的问题。 3 | * 添加了日本的街区编号(block numbers)。 4 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * 更新了预设和影像图层。 2 | * 新增希腊语和印尼语翻译。 3 | * 地图选择器中新增比例尺。 4 | * 在微地图绘制中新增水道要素。 5 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * 修复了冲突问题和缩放等级。 2 | * 修复了在极端纬度地区的编辑问题。 3 | * 新增地籍图影像图层。 4 | * 新增希伯来语和泰米尔语翻译。 5 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -dontwarn javax.annotation.Nullable 2 | -dontwarn javax.annotation.concurrent.GuardedBy 3 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * 现在可以缩放至最小视图。 2 | * 模式之间切换时将保留缩放等级。 3 | * 增加了长椅和摄像头的朝向编辑功能。 4 | * 微地图绘制模式中的颜色显示更加稳定。 5 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * 希望已修复 GPS 问题。 2 | * 更新了 Bing 影像密钥,并移除 Maxar。 3 | * 新增银行卡支付选项设置。 4 | * 名称大小写处理更智能。 5 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * 新增最近行走路径显示功能。 2 | * GeoScribbles 绘图默认处于锁定状态。 3 | * 网站字段支持二维码扫描。 4 | * 当前位置现在每秒更新一次。 5 | -------------------------------------------------------------------------------- /metadata/zh-CN/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * 变更集标签。 2 | * 将确认间隔延长至 2 个月。 3 | * 创建新 POI 时,名称字段将自动获得焦点。 4 | * 对带有 `fixme` 标签或过旧的设施显示警告。 5 | -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Added cycle barriers and xmas features. 2 | * Support "geo:" links. 3 | * New adaptive icon. 4 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Added cycle barriers and xmas features. 2 | * Support "geo:" links. 3 | * New adaptive icon. 4 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Added cycle barriers and xmas features. 2 | * Support "geo:" links. 3 | * New adaptive icon. 4 | -------------------------------------------------------------------------------- /metadata/en-US/images/featureGraphic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/metadata/en-US/images/featureGraphic.jpg -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Tilføjet cykelbarrierer og juleobjekter. 2 | * Understøtter "geo:" links. 3 | * Nyt adaptivt ikon. 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/flutter"] 2 | path = vendor/flutter 3 | url = https://github.com/flutter/flutter.git 4 | branch = stable 5 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /metadata/en-US/images/phoneScreenshots/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/metadata/en-US/images/phoneScreenshots/1.jpg -------------------------------------------------------------------------------- /metadata/en-US/images/phoneScreenshots/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/metadata/en-US/images/phoneScreenshots/2.jpg -------------------------------------------------------------------------------- /metadata/en-US/images/phoneScreenshots/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/metadata/en-US/images/phoneScreenshots/3.jpg -------------------------------------------------------------------------------- /metadata/ru/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Добавил велопреграды и рождественские штуки. 2 | * Поддержка ссылок "geo:". 3 | * Новая адаптивная иконка. 4 | -------------------------------------------------------------------------------- /android/app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/android/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Додано велосипедні бар'єри та різдвяні елементи. 2 | * Підтримка посилань "geo:". 3 | * Нова адаптивна іконка. 4 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Fahrradsperren und Weihnachts-Dinge hinzugefügt. 2 | * Unterstützung von `geo:`-Links. 3 | * Neues adaptives Icon. 4 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/60.txt: -------------------------------------------------------------------------------- 1 | * Suggesting popular tags without matching presets. 2 | * Caching preset icons. 3 | * Address editing improvements. 4 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/60.txt: -------------------------------------------------------------------------------- 1 | * Suggesting popular tags without matching presets. 2 | * Caching preset icons. 3 | * Address editing improvements. 4 | -------------------------------------------------------------------------------- /metadata/et/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Lisasime rattabarjäärid ja jõuludega seotud teenused. 2 | * „geo:“ linkide tugi. 3 | * Uus suurusega kohanduv ikoo. 4 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Dodane biciklističke barijere i Božićne značajke. 2 | * Podrška za "geo:" poveznice. 3 | * Nova prilagodljiva ikona. 4 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Dodane so bile ovire za kolesa in božične funkcije. 2 | * Podpora za povezave »geo:«. 3 | * Nova prilagodljiva ikona. 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /metadata/es-ES/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Añadido barreras para bicicletas y elementos navideños. 2 | * Compatible con enlaces «geo:». 3 | * Nuevo icono adaptativo. 4 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Kerékpáros akadályok és karácsonyi térképelemek hozzáadva. 2 | * A „geo:” hivatkozások támogatása. 3 | * Új alkalmazkodó ikon. 4 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/48.txt: -------------------------------------------------------------------------------- 1 | * Adicionadas barreiras para bicicletas e elementos de Natal. 2 | * Suporte para links "geo:". 3 | * Novo ícone adaptável. 4 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/60.txt: -------------------------------------------------------------------------------- 1 | * Пропонування популярних тегів без відповідних пресетів. 2 | * Кешування значків пресетів. 3 | * Покращення редагування адрес. 4 | -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Updated presets and imagery. 2 | * Fixed issues with lost notes and duplicate amenities. 3 | * Added block numbers for Japan. 4 | -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Scribble notes mode. 2 | * Days of week in a local language. 3 | * Floor tags suggestions. 4 | * Updates to presets and imagery. 5 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Updated presets and imagery. 2 | * Fixed issues with lost notes and duplicate amenities. 3 | * Added block numbers for Japan. 4 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Updated presets and imagery. 2 | * Fixed issues with lost notes and duplicate amenities. 3 | * Added block numbers for Japan. 4 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Scribble notes mode. 2 | * Days of week in a local language. 3 | * Floor tags suggestions. 4 | * Updates to presets and imagery. 5 | -------------------------------------------------------------------------------- /metadata/ru/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Починил заглавные буквы в поле description. 2 | * Починил жёлтые плашки предупреждений. 3 | * Починил закрытие магазинов в зданиях. 4 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx3248M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | dev.steenbakker.mobile_scanner.useUnbundled=true 5 | -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/60.txt: -------------------------------------------------------------------------------- 1 | * Navrhování populárních značek bez odpovídajících předvoleb 2 | * Ukládání ikon předvoleb do mezipaměti. 3 | * Vylepšení úpravy adres. 4 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Scribble notes mode. 2 | * Days of the week in a local language. 3 | * Floor tags suggestions. 4 | * Updates to presets and imagery. 5 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * Vector tiles everywhere. 2 | * Download data and imagery to work offline. 3 | * Added a compass button. 4 | * Presets now have icons. 5 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * Vector tiles everywhere. 2 | * Download data and imagery to work offline. 3 | * Added a compass button. 4 | * Presets now have icons. 5 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Режим нотаток-каракулів. 2 | * Дні тижня місцевою мовою. 3 | * Пропозиції щодо тегів поверхів. 4 | * Оновлення пресетів та зображень. 5 | -------------------------------------------------------------------------------- /l10n.yaml: -------------------------------------------------------------------------------- 1 | arb-dir: lib/l10n 2 | template-arb-file: app_en.arb 3 | output-localization-file: app_localizations.dart 4 | synthetic-package: false 5 | output-dir: lib/generated/l10n -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Fixed capitalization for descriptions. 2 | * Fixed yellow amenity warnings not shown. 3 | * Fixed marking a shop on a building disused. 4 | -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * Vektorové dlaždice všude. 2 | * Stáhnutí dat a snímků pro práci offline. 3 | * Přidáno tlačítko kompasu. 4 | * Předvolby mají nyní ikony. 5 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Fixed capitalisation for descriptions. 2 | * Fixed yellow amenity warnings not shown. 3 | * Fixed marking a shop on a disused building. 4 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Fixed capitalization for descriptions. 2 | * Fixed yellow amenity warnings not shown. 3 | * Fixed marking a shop on a building disused. 4 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * Векторні плитки всюди. 2 | * Завантаження даних та зображень для роботи офлайн. 3 | * Додано кнопку компаса. 4 | * Пресети тепер мають значки. 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/60.txt: -------------------------------------------------------------------------------- 1 | * Foreslår populære tags uden matchende forudindstillinger. 2 | * Caching af forudindstillede ikoner. 3 | * Forbedringer af adresseredigering. 4 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Firkálási jegyzetek mód. 2 | * A hét napjai a helyi nyelven. 3 | * Emelet címkék javaslatai. 4 | * Címkesablonok és légi felvételek frissítései. 5 | -------------------------------------------------------------------------------- /metadata/it-IT/changelogs/60.txt: -------------------------------------------------------------------------------- 1 | * Suggerimento di tag popolari senza preset corrispondenti. 2 | * Caching icone dei preset. 3 | * Miglioramento nella modifica degli indirizzi. 4 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Modo de rabiscos. 2 | * Dias da semana em um idioma local. 3 | * Sugestões de etiquetas de andar. 4 | * Atualizações de predefinições e imagens. 5 | -------------------------------------------------------------------------------- /metadata/ru/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Обновил заготовки тегов и подложки. 2 | * Починил проблемы с дублированием заведений и пропажей заметок. 3 | * Добавил block_number для Японии. 4 | -------------------------------------------------------------------------------- /metadata/ru/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Режим рисования пальцем по карте. 2 | * Переводим дни недели в местный язык. 3 | * Предложения тегов этажей. 4 | * Обновления заготовок и подложек. 5 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Način za beležke Scribble. 2 | * Dnevi v tednu v lokalnem jeziku. 3 | * Predlogi za oznake nadstropij. 4 | * Posodobitve prednastavitev in slik. 5 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * Vektorske ploščice povsod. 2 | * Prenesi podatke in slike za delo brez povezave. 3 | * Dodan gumb za kompas. 4 | * Prednastavitve imajo zdaj ikone. 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Hopefully fixed GPS issues. 2 | * Updated Bing imagery key and removed Maxar. 3 | * New card payment settings. 4 | * Smarter name capitalization. 5 | -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * Vektorfliser overalt. 2 | * Download data og luftfoto for at arbejde offline. 3 | * Tilføjet en kompasknap. 4 | * Forudindstillinger har nu ikoner. 5 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Hopefully fixed GPS issues. 2 | * Updated Bing imagery key and removed Maxar. 3 | * New card payment settings. 4 | * Smarter name capitalisation. 5 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Hopefully fixed GPS issues. 2 | * Updated Bing imagery key and removed Maxar. 3 | * New card payment settings. 4 | * Smarter name capitalization. 5 | -------------------------------------------------------------------------------- /metadata/it-IT/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Aggiornati preset e immagini aeree. 2 | * Risolti problemi con note perse e servizi duplicati. 3 | * Aggiunto numeri di quartiere per il Giappone. 4 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Оновлено пресети та зображення. 2 | * Виправлено проблеми із втраченими нотатками та дублюванням зручностей. 3 | * Додано номери кварталів для Японії. 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #00B0F6 4 | -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Fixed conflicts and zoom levels. 2 | * Fixed editing in extreme latitudes. 3 | * Added cadastre imagery layers. 4 | * Translations into Hebrew and Tamil. 5 | -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Rettet store bogstaver til beskrivelser. 2 | * Rettet manglende gule advarsler om faciliteter. 3 | * Rettet markering af en butik på bygning som nedlagt. 4 | -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Tilstand for skriblerier. 2 | * Ugedage på et lokalt sprog. 3 | * Forslag til etage-tags. 4 | * Opdateringer til forudindstillinger og baggrundsbilleder. 5 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Fixed conflicts and zoom levels. 2 | * Fixed editing in extreme latitudes. 3 | * Added cadastre imagery layers. 4 | * Translations into Hebrew and Tamil. 5 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Fixed conflicts and zoom levels. 2 | * Fixed editing in extreme latitudes. 3 | * Added cadastre imagery layers. 4 | * Translations into Hebrew and Tamil. 5 | -------------------------------------------------------------------------------- /metadata/et/changelogs/60.txt: -------------------------------------------------------------------------------- 1 | * Populaarsete siltide soovitamine ilma vastavate eelseadistusteta. 2 | * Eelseadistatud ikoonide puhveradmine. 3 | * Senisest parem aadressi muutmisvaade. 4 | -------------------------------------------------------------------------------- /metadata/it-IT/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Modalità note scribble. 2 | * Giorni di settimana in una lingua locale. 3 | * Suggerimenti per i tag dei piani. 4 | * Aggiornamento preset e immagini. 5 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Posodobljene prednastavitve in slike. 2 | * Popravljene težave z izgubljenimi opombami in podvojenimi amenities. 3 | * Dodane številke blokov za Japonsko. 4 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zverik/every_door/main/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Podpora doplňků! 2 | * Značky na mapě se změní na zelenou u potvrzených bodů. 3 | * Správné pořadí dnů v týdnu pro USA a Izrael. 4 | * Zobrazení směru kompasu. 5 | -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Opdaterede forudindstillinger og baggrundsbilleder. 2 | * Løste problemer med mistede noter og duplikerede faciliteter. 3 | * Tilføjet bloknumre for Japan. 4 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Kritzelnotizen-Modus. 2 | * Wochentage in lokaler Sprache. 3 | * Vorschläge für Stockwerk-Erfassung. 4 | * Updates für Voreinstellungen und Hintergrundbilder. 5 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * Vektorkacheln überall. 2 | * Daten und Bilder zum Offline-Arbeiten runterladen. 3 | * Kompass-Button hinzugefügt. 4 | * Voreinstellungen haben jetzt Symbole. 5 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Plugin support! 2 | * Markers on the map turn green for confirmed amenities. 3 | * Correct weekday order for US and Israel. 4 | * Displaying compass direction. 5 | -------------------------------------------------------------------------------- /metadata/et/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Uuendasime eelseadistusi ja ortofotosid. 2 | * Parandasime kadunud märkmetega ja topeltteenustega seotud vead. 3 | * Lisandusid kvartalite numbrid Jaapani jaoks. 4 | -------------------------------------------------------------------------------- /metadata/et/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Märkmete kritseldamise režiim. 2 | * Nädalapäevad kohalikus keeles. 3 | * Soovituse korruste siltide lisamiseks. 4 | * Eelseadistuste ja ortofotode uuendused. 5 | -------------------------------------------------------------------------------- /metadata/it-IT/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Corrette maiuscole per le descrizioni. 2 | * Corretti avvisi di amenity non mostrati. 3 | * Correzione segnalazione di un negozio su edificio come in disuso. 4 | -------------------------------------------------------------------------------- /metadata/ru/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Починил конфликты и уровни масштаба. 2 | * Починил редактирование на крайнем севере. 3 | * Добавил кадастровые слои. 4 | * Переводы на иврит и тамильский язык. 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Updated presets and imagery layers. 2 | * Greek and Indonesian translations. 3 | * Scale bar for the map chooser. 4 | * Added waterway features to micromapping. 5 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/60.txt: -------------------------------------------------------------------------------- 1 | * Vorschlagen beliebter Tags ohne passende Voreinstellungen. 2 | * Zwischenspeichern von Voreinstellungs-Symbolen. 3 | * Verbesserungen bei der Adressbearbeitung. 4 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Updated presets and imagery layers. 2 | * Greek and Indonesian translations. 3 | * Scale bar for the map chooser. 4 | * Added waterway features to micromapping. 5 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Plugin support! 2 | * Markers on the map turn green for confirmed amenities. 3 | * Correct weekday order for the US and Israel. 4 | * Displaying compass direction. 5 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Updated presets and imagery layers. 2 | * Greek and Indonesian translations. 3 | * Scale bar for the map chooser. 4 | * Added waterway features to micromapping. 5 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Podrška za dodatke! 2 | * Oznake na karti postaju zelene za potvrđene usluge. 3 | * Ispravan redoslijed dana u tjednu za SAD i Izrael. 4 | * Prikaz smjera kompasa. 5 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Predefinições e imagens atualizadas. 2 | * Problemas com notas perdidas e serviços duplicados foram corrigidos. 3 | * Números de quadra adicionados para o Japão. 4 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * Mosaicos de vetor por toda parte. 2 | * Baixe dados e imagens para trabalhar offline. 3 | * Adicionado um botão de bússola. 4 | * As predefinições agora têm ícones. 5 | -------------------------------------------------------------------------------- /metadata/ru/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * обновили заготовки и слои 2 | * переводы на греческий и индонезийский 3 | * линейка масштаба при добавлении объекта 4 | * поддержка речных объектов в микромаппинге 5 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Posodobljene prednastavitve in sloji slik. 2 | * Grški in indonezijski prevod. 3 | * Skala za izbirnik zemljevida. 4 | * Dodane funkcije vodnih poti za mikromapiranje. 5 | -------------------------------------------------------------------------------- /metadata/et/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Lisamoodulite tugi! 2 | * Kinnitatud teenuste markerid muutuvad roheliseks. 3 | * Nädalapäevade järjekord parandatud USA ja Iisraeli jaoks. 4 | * Lisasime kompassi suuna. 5 | -------------------------------------------------------------------------------- /metadata/et/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * Vektorpaanid on kasutusel kõikjal. 2 | * Võimalus andmeid ja pilte laadida alla tööks valalsrežiimis. 3 | * Lisandus kompassi nupp. 4 | * Eelseadistustel on nüüd ikoonid. 5 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Crtkaranje u modusu rada za bilješke. 2 | * Dani u tjednu na lokalnom jeziku. 3 | * Prijedlozi oznaka katova. 4 | * Ažuriranja predodređenih oznaka i pozadinskih karti. 5 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Címkesablonok és légi felvételek frissítve. 2 | * Görög és indonéz fordítás. 3 | * Méretezősáv a térképválasztónál. 4 | * Vízi térképelemek hozzáadva a mikrotérképezéshez. 5 | -------------------------------------------------------------------------------- /metadata/ru/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | — Можно отдалять карту до предела. 2 | — Масштаб сохраняется между режимами. 3 | — Редактор направления для скамеек и камер. 4 | — Стабильные цвета в режиме микромаппинга. 5 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * Lahko povečaš do maksimuma. 2 | * Stopnje povečave se ohranijo med načini. 3 | * Urejevalnik smeri za klopi in kamere. 4 | * Stabilizirane barve v načinu mikromapiranja. 5 | -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * You can zoom out to the max. 2 | * Zoom levels are preserved between modes. 3 | * Direction editor for benches and cameras. 4 | * Stabilized colors in the micromapping mode. 5 | -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Forhåbentlig løst GPS-problemer. 2 | * Opdateret Bing-billednøgle og fjernet Maxar. 3 | * Nye indstillinger for kortbetaling. 4 | * Smartere brug af store bogstaver i navne. 5 | -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Rettet konflikter og zoomniveauer. 2 | * Rettet redigering på ekstreme breddegrader. 3 | * Tilføjet cadastre-baggrundsbilledlag. 4 | * Oversættelser til hebraisk og tamilsk. 5 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Aktualisierte Voreinstellungen und Hintergrundbilder. 2 | * Probleme mit Notizen und doppelten Einträgen behoben. 3 | * Block-Nummern für japanische Adressen hinzugefügt. 4 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * You can zoom out to the max. 2 | * Zoom levels are preserved between modes. 3 | * Direction editor for benches and cameras. 4 | * Stabilised colours in the micromapping mode. 5 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * You can zoom out to the max. 2 | * Zoom levels are preserved between modes. 3 | * Direction editor for benches and cameras. 4 | * Stabilized colors in the micromapping mode. 5 | -------------------------------------------------------------------------------- /metadata/es-ES/changelogs/42.txt: -------------------------------------------------------------------------------- 1 | * Modo de notas garabateadas. 2 | * Días de la semana en el idioma local. 3 | * Sugerencias de etiquetas de piso. 4 | * Actualizaciones de ajustes preestablecidos e imágenes. 5 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Ažurirane predefinirane oznake i pozadinske zračne snimke. 2 | * Ispravljeni problemi s izgubljenim bilješkama i dupliciranim sadržajima. 3 | * Dodani brojevi blokova za Japan. 4 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Ispravljena upotreba velikih slova u opisima. 2 | * Ispravljena žuta upozorenja o uslugama koja se nisu prikazivala. 3 | * Ispravljeno označavanje trgovine na napuštenoj zgradi. 4 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * Vektorske pločice posvuda. 2 | * Preuzimanje podataka i slika za rad bez internetske veze. 3 | * Dodan je gumb za kompas. 4 | * Unaprijed definirane postavke sada imaju ikone. 5 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * GPS-problémák remélhetőleg javítva. 2 | * A Bing légi felvétel kulcsa frissítve és a Maxar eltávolítva. 3 | * Új bankkártyás fizetési beállítások. 4 | * Okosabb név nagybetűzés. 5 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Nagybetűs írásmód javítva a leírásoknál. 2 | * Javítva a sárga létesítmény-figyelmeztetések meg nem jelenése. 3 | * Javítva az épületen lévő bolt nem használtként való jelölése. 4 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Conflitos e níveis de zoom corrigidos. 2 | * Edição corrigida em latitudes extremas. 3 | * Camadas de imagens de cadastro adicionadas. 4 | * Traduções para hebraico e tâmil. 5 | -------------------------------------------------------------------------------- /metadata/ru/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * выводим недавно пройденный маршрут; 2 | * режим рисования изначально заблокирован; 3 | * сканер QR-кодов для поля веб-сайта; 4 | * координаты теперь обновляются ежесекундно. 5 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Popravljena velika začetnica za opise. 2 | * Popravljena rumena opozorila za amenity, ki se niso prikazovala. 3 | * Popravljeno označevanje trgovine na neuporabljani stavbi. 4 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Podpora za vtičnike! 2 | * Oznake na zemljevidu se ob potrjenih storitvah obarvajo zeleno. 3 | * Popravljen vrstni red dni v tednu za ZDA in Izrael. 4 | * Prikaz smeri kompasa. 5 | -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Added the recent walked path display. 2 | * GeoScribbles drawing is locked by default. 3 | * QR code scanner for the website field. 4 | * Location is now updated once a second. 5 | -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * Du kan zoome ud til maksimum. 2 | * Zoomniveauer bevares mellem tilstande. 3 | * Retningseditor for bænke og kameraer. 4 | * Stabiliserede farver i mikrokortlægnings-tilstand. 5 | -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Tilføjet visning af nyligt gået sti. 2 | * GeoScribbles-tegning er låst som standard. 3 | * QR-kodescanner til hjemmesidefeltet. 4 | * Position opdateres nu en gang i sekundet. 5 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Added the recently walked path display. 2 | * GeoScribbles drawing is locked by default. 3 | * QR code scanner for the website field. 4 | * Location is now updated once a second. 5 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Added the recent walked path display. 2 | * GeoScribbles drawing is locked by default. 3 | * QR code scanner for the website field. 4 | * Location is now updated once a second. 5 | -------------------------------------------------------------------------------- /metadata/et/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Lisandus viimati käidud tee vaade. 2 | * GeoScribbles'i joonistus on vakimisi lukus. 3 | * QR-koodi skanner veebisaidi välja jaoks. 4 | * Asukohta uuendatakse nüüd kord sekundis. 5 | -------------------------------------------------------------------------------- /metadata/et/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Andmekonfliktide ja suumitasemete parandused. 2 | * Muutmine suurtel laiuskraadidel toimib paremini . 3 | * Lisandus kadastrikaartide ülekate. 4 | * Heebrea ja tamili keelte tõlked. 5 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Ažurirane predodređene oznake i slojevi pozadinskih karti 2 | * Grčki i indonezijski prijevodi. 3 | * Mjerilo za odabir karte. 4 | * Dodane značajke plovnog puta u mikromapiranje. 5 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Correção do uso de maiúsculas nas descrições. 2 | * Correção de avisos amarelos de serviços que não eram exibidos. 3 | * Correção de marcação de uma loja em um prédio desativado. 4 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Підтримка плагінів! 2 | * Маркери на карті стають зеленими для підтверджених зручностей. 3 | * Правильний порядок днів тижня для США та Ізраїлю. 4 | * Відображення напрямку компаса. 5 | -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Opdaterede forudindstillinger og baggrundsbilledlag. 2 | * Græske og indonesiske oversættelser. 3 | * Skalabjælke til kortvælger. 4 | * Tilføjet vandvejsobjekter til mikrokortlægning. 5 | -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Understøttelse af udvidelser! 2 | * Markører på kortet skifter til grønt for bekræftede faciliteter. 3 | * Korrekt ugedagsrækkefølge for USA og Israel. 4 | * Visning af kompasretning. 5 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * GPS-Probleme (hoffentlich) behoben. 2 | * Bing-API-Schlüssel aktualisiert und Maxar entfernt. 3 | * Neue Einstellungen für Kartenzahlungen. 4 | * Verbesserte Großschreibung von Namen. 5 | -------------------------------------------------------------------------------- /metadata/et/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Uuendatud eelseadistused ja kaardikihid. 2 | * Kreeka ja indoneesia keelte tõlked. 3 | * Kaardivalija riba suuruse muutumine. 4 | * Mikrokaardistamise jaoks lisandusid veeteede objektid. 5 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * Možete zumirati do maksimuma. 2 | * Razine zumiranja su sačuvane između različitih modusa rada. 3 | * Uređivač smjera za klupe i kamere. 4 | * Stabilizirane boje u modusu mikromapiranja. 5 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Dodan je prikaz nedavno prijeđenog puta. 2 | * Crtanje GeoScribblesom je inicijalno zaključano. 3 | * Čitač QR koda za polje web-stranice. 4 | * Lokacija se sada ažurira jednom u sekundi. 5 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/58.txt: -------------------------------------------------------------------------------- 1 | * Vektorcsempék mindenhol. 2 | * Adatok és légi felvételek letöltése kapcsolat nélküli munkához. 3 | * Hozzáadva egy iránytű gomb. 4 | * A címkesablonok mostantól rendelkeznek ikonokkal. 5 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Оновлено пресети та шари зображень. 2 | * Переклади грецькою та індонезійською мовами. 3 | * Масштабна шкала для вибору карти. 4 | * Додано об'єкти водних шляхів до мікрокартографування. 5 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Виправлено конфлікти та рівні масштабування. 2 | * Виправлено редагування в екстремальних широтах. 3 | * Додано шари кадастрових зображень. 4 | * Переклади на іврит та тамільську мови. 5 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/info/zverev/ilya/every_door/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package info.zverev.ilya.every_door 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/providers/poi_filter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 2 | import 'package:every_door/models/filter.dart'; 3 | 4 | final poiFilterProvider = StateProvider((ref) => PoiFilter()); 5 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Großschreibung für Beschreibungen korrigiert. 2 | * Gelbe Warnungen werden für Einrichtungen nicht mehr angezeigt. 3 | * Lädens können nicht mehr auf einem `disused` Gebäude erfasst werden. 4 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Ispravljeni konflikti i razine zumiranja. 2 | * Popravljeno uređivanje na ekstremnim geografskim širinama. 3 | * Dodani slojevi katastarskih slika. 4 | * Prijevodi na hebrejski i tamilski. 5 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * Kicsinyíthet a legnagyobbig. 2 | * A nagyítási szintek megőrzésre kerülnek a módok között. 3 | * Irányszerkesztő a padoknál és kameráknál. 4 | * Stabilizált színek a mikrotérképezési módban. 5 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Suporte a extensões! 2 | * Os marcadores no mapa ficam verdes para os serviços confirmados. 3 | * Ordem correta dos dias da semana para EUA e Israel. 4 | * Exibição da direção da bússola. 5 | -------------------------------------------------------------------------------- /metadata/ru/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Возможно, починили проблемы с GPS. 2 | * Обновил ключ для снимков Bing и убрал Maxar. 3 | * Новые настройки видов оплаты картой. 4 | * Умнее переключаем заглавные и строчные буквы в названиях. 5 | -------------------------------------------------------------------------------- /metadata/ru/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Поддержка плагинов! 2 | * Цифры на карте становятся зелёными, когда подтверждаешь заведение. 3 | * Правильный порядок дней недели для некоторых стран. 4 | * Отображаем направление компаса. 5 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Upajmo, da so težave z GPS-om odpravljene. 2 | * Posodobljen ključ za slike Bing in odstranjen Maxar. 3 | * Nove nastavitve za plačevanje s kartico. 4 | * Pametnejše velike začetnice imen. 5 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Dodano prikazovanje zadnje prehojene poti. 2 | * GeoScribbles risanje je privzeto zaklenjeno. 3 | * Skener QR kode za polje spletne strani. 4 | * Lokacija se zdaj posodablja enkrat na sekundo. 5 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Сподіваємося, що проблеми з GPS виправлено. 2 | * Оновлено ключ зображень Bing та видалено Maxar. 3 | * Нові налаштування оплати карткою. 4 | * Розумніше використання великих літер у імені. 5 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Konflikte und Zoomstufen wurden behoben. 2 | * Bearbeitung in extremen Breitengraden korrigiert. 3 | * Kataster-Hintergrundbilder hinzugefügt. 4 | * Übersetzung ins Hebräische und Tamilische. 5 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Plugin-Unterstützung! 2 | * Markierungen auf der Karte werden grün für bestätigte Einrichtungen. 3 | * Korrekte Wochentagsreihenfolge für die USA und Israel. 4 | * Anzeige der Himmelsrichtung. 5 | -------------------------------------------------------------------------------- /metadata/et/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * Nüüd saad kasutada maksimaalset suumi. 2 | * Suumid jäävade režiimide vahetamisel meelde. 3 | * Pinkide ja kaamerate suuna muutmise võimalus. 4 | * Stabiilsemad värvid mikrokaardistamise vaates. 5 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Nadamo se da su problemi s GPS-om riješeni. 2 | * Ažuriran je ključ za slike Binga i uklonjen je Maxar. 3 | * Nove postavke plaćanja karticama. 4 | * Pametnije korištenje velikih slova u imenima. 5 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Címkesablonok és légi felvételek frissítve. 2 | * Javítva lettek az elveszett jegyzetekkel és a kettőzött létesítményekkel kapcsolatos problémák. 3 | * Háztömbök számozása hozzáadva a japánoknak. 4 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Javítva az ütközések és a nagyítási szintek. 2 | * Javítva az extrém szélességi körökön való szerkesztés. 3 | * Hozzáadva a kataszter légifelvétel-rétegek. 4 | * Fordítás héber és tamil nyelvre. 5 | -------------------------------------------------------------------------------- /metadata/it-IT/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Speriamo di aver risolto i problemi GPS. 2 | * Aggiornato chiave delle immagini Bing e rimosso Maxar. 3 | * Nuove impostazioni di pagamento con carta. 4 | * Maiuscole dei nomi più intelligenti. 5 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Predefinições e camadas de imagens atualizadas. 2 | * Traduções para grego e indonésio. 3 | * Barra de escala para o seletor de mapas. 4 | * Recursos de hidrovias adicionados ao micromapeamento. 5 | -------------------------------------------------------------------------------- /metadata/ru/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | — Хэштеги для пакетов правок. 2 | — Интервал подтверждения теперь два месяца. 3 | — Вводим название сразу после создания заведения. 4 | — Предупреждения для заведений с fixme или просто очень старых. 5 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * Ви можете максимально зменшити масштаб. 2 | * Рівні масштабування зберігаються між режимами. 3 | * Редактор напрямків для лавок та камер. 4 | * Стабілізовані кольори в режимі мікрокартографування. 5 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Виправлено використання великих літер для описів. 2 | * Виправлено помилку, через яку не відображалися жовті попередження про зручності. 3 | * Виправлено позначення магазину на занедбаній будівлі. 4 | -------------------------------------------------------------------------------- /metadata/cs-CZ/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Changeset hashtags. 2 | * Increased confirmation interval to 2 months. 3 | * Name field is focused when creating a new POI. 4 | * Warnings for amenities that have a `fixme` tag or that are too old. 5 | -------------------------------------------------------------------------------- /metadata/en-US/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Changeset hashtags. 2 | * Increased confirmation interval to 2 months. 3 | * Name field is focused when creating a new POI. 4 | * Warnings for amenities that have a `fixme` tag or that are too old. 5 | -------------------------------------------------------------------------------- /metadata/es-ES/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Solucionado los conflictos y los niveles de zoom. 2 | * Solucionado la edición en latitudes extremas. 3 | * Añadido capas de imágenes catastrales. 4 | * Añadido traducciones al hebreo y al tamil. 5 | -------------------------------------------------------------------------------- /metadata/et/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Loodetavasti õnnestus GPS-i vead parandada. 2 | * Uuenes Bingi ortofotode võti ja Maxar sai eemaldatud. 3 | * Uued seadistused kaardimaksete kirjeldamiseks. 4 | * Nutikam viis muutmisel suurtähtedeks. 5 | -------------------------------------------------------------------------------- /metadata/it-IT/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * Puoi ridurre lo zoom al massimo. 2 | * I livelli di zoom sono conservati tra le modalità. 3 | * Editor di direzione per panchine e telecamere. 4 | * Colori stabilizzati nella modalità micromapping. 5 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * Você pode diminuir o zoom ao máximo. 2 | * Os níveis de zoom são preservados entre os modos. 3 | * Editor de direção para assentos e câmeras. 4 | * Cores estabilizadas no modo de micromapeamento. 5 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Problemas de GPS corrigidos (espero). 2 | * Chave de imagens do Bing atualizada e Maxar removido. 3 | * Novas configurações de pagamento com cartão. 4 | * Capitalização de nomes mais inteligente. 5 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Changeset Hashtags. 2 | * Bestätigungs-Intervall auf 2 Monate erhöht. 3 | * Fokus auf der Namens-Eingabe, wenn ein neuer POI erstellt wird. 4 | * Warnung für Objekte mit `fixme`-Tag oder zu alte Objekte. 5 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * Sie können bis zum Maximum herauszoomen. 2 | * Die Zoomstufen bleiben zwischen den Modi erhalten. 3 | * Editor für die Richtung von Bänken und Kameras. 4 | * Vereinheitlichte Farben im Mikromapping-Modus. 5 | -------------------------------------------------------------------------------- /metadata/en-GB/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Changeset hashtags. 2 | * Increased confirmation interval to 2 months. 3 | * The name field is focused when creating a new POI. 4 | * Warnings for amenities that have a `fixme` tag or that are too old. 5 | -------------------------------------------------------------------------------- /metadata/es-ES/changelogs/32.txt: -------------------------------------------------------------------------------- 1 | * Puedes alejar la imagen al máximo. 2 | * Los niveles de zoom se mantienen entre los distintos modos. 3 | * Editor de dirección para bancos y cámaras. 4 | * Colores estabilizados en el modo de micromapeo. 5 | -------------------------------------------------------------------------------- /metadata/es-ES/changelogs/34.txt: -------------------------------------------------------------------------------- 1 | * Actualizado los ajustes preestablecidos y las imágenes. 2 | * Solucionado los problemas relacionados con la pérdida de notas y la duplicación de servicios. 3 | * Añadido números de manzana para Japón. 4 | -------------------------------------------------------------------------------- /metadata/et/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Kirjelduste suur- ja väiketähtede vigade parandus. 2 | * Parandasime olukorra, kus kollased teenuste hoiatused polnud näha. 3 | * Parandasime poodide ja hoonete märkimise kasutuselt eemaldatuks (disused:). 4 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Hashtags alteradas. 2 | * Intervalo de confirmação aumentado para 2 meses. 3 | * O campo Nome é destacado ao criar um novo POI. 4 | * Avisos para serviços com a etiqueta `fixme` ou que são muito antigas. 5 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Додано відображення нещодавно пройдених шляхів. 2 | * Малювання GeoScribbles заблоковано за замовчуванням. 3 | * Сканер QR-кодів для поля веб-сайту. 4 | * Місцезнаходження тепер оновлюється раз на секунду. 5 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Anzeige des zuletzt zurückgelegten Weges hinzugefügt. 2 | * GeoScribbles sind standardmäßig gesperrt. 3 | * QR-Code-Scanner für das Webseiten-Feld. 4 | * Der Standort wird nun einmal pro Sekunde aktualisiert. 5 | -------------------------------------------------------------------------------- /metadata/de-DE/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Aktualisierte Voreinstellungen und Hintergrundbilder. 2 | * Übersetzung in Griechische und Indonesisch. 3 | * Maßstabsleiste für die Kartenauswahl. 4 | * `waterway`-Merkmale zum Micromapping-Modus hinzugefügt. 5 | -------------------------------------------------------------------------------- /metadata/es-ES/changelogs/37.txt: -------------------------------------------------------------------------------- 1 | * Esperamos haber solucionado los problemas de GPS. 2 | * Actualizado la llave de imágenes de Bing y eliminado Maxar. 3 | * Nuevas opciones de pago con tarjeta. 4 | * Mayúsculas más inteligentes en los nombres. 5 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Hozzáadva a legutóbb bejárt útvonal megjelenítése. 2 | * A GeoScribbles rajzolás alapértelmezetten zárolva van. 3 | * QR-kódbeolvasó a webhely mezőhöz. 4 | * A helyzet mostantól másodpercenként egyszer frissül. 5 | -------------------------------------------------------------------------------- /metadata/it-IT/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Supporto per i plugin! 2 | * I segnalini sulla mappa diventano verdi per i luoghi confermati. 3 | * Corretto l'ordine dei giorni settimanali per US e Israele. 4 | * Viene mostrata la direzione della bussola. 5 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * Bővítménytámogatás! 2 | * A térképen lévő jelölők zöldre váltanak a jóváhagyott létesítményeknél. 3 | * A hét napjainak helyes sorrendje az Egyesült Államokban és Izraelben. 4 | * Az iránytű irányának megjelenítése. 5 | -------------------------------------------------------------------------------- /metadata/pt-BR/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Adicionada a exibição do caminho percorrido recentemente. 2 | * O desenho de rabiscos é bloqueado por padrão. 3 | * Leitor de QR code para o campo de website. 4 | * A localização agora é atualizada a cada segundo. 5 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Hashtagi za spremembe. 2 | * Podaljšanje intervala za potrditev na 2 meseca. 3 | * Pri ustvarjanju novega POI je izpostavljeno polje za ime. 4 | * Opozorila za objekte, ki imajo oznako »fixme« ali so preveč stari. 5 | -------------------------------------------------------------------------------- /metadata/da-DK/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Ændringssæt-hashtags. 2 | * Øget bekræftelsesinterval til 2 måneder. 3 | * Navnefeltet er i fokus, når man opretter et nyt interessepunkt. 4 | * Advarsler for faciliteter, der har et `fixme` tag eller som er for gamle. 5 | -------------------------------------------------------------------------------- /metadata/hr/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Promijenjeni hashtagovi. 2 | * Interval potvrde povećan na 2 mjeseca. 3 | * Polje za naziv je fokusirano prilikom izrade nove točke interesa. 4 | * Upozorenja za sadržaje koji imaju oznaku `fixme` ili koji su prestari. 5 | -------------------------------------------------------------------------------- /metadata/uk/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Хештеги набору змін. 2 | * Збільшено інтервал підтвердження до 2 місяців. 3 | * Поле назви стає фокусним під час створення нової точки інтересу. 4 | * Попередження щодо зручностей, які мають тег `fixme` або занадто старі. 5 | -------------------------------------------------------------------------------- /metadata/et/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Muudatuskomplekti teemaviited. 2 | * Kinnituse välp on nüüd pikenenud 2 kuuni. 3 | * Uue huvipunkti lisamisel on nime väli esimesena fookuses. 4 | * Hoiatused, kui teenustel on „Vajab parandamist“ silt või nad on liiga vanad. 5 | -------------------------------------------------------------------------------- /metadata/sl/changelogs/50.txt: -------------------------------------------------------------------------------- 1 | * Popravljeni so bili konflikti in stopnje povečave. 2 | * Popravljeno je bilo urejanje v ekstremnih zemljepisnih širinah. 3 | * Dodane so bile katastrske slikovne plasti. 4 | * Dodani so bili prevodi v hebrejščino in tamilščino. 5 | -------------------------------------------------------------------------------- /metadata/es-ES/changelogs/47.txt: -------------------------------------------------------------------------------- 1 | * Actualización de los ajustes preestablecidos y las capas de imágenes. 2 | * Traducciones al griego y al indonesio. 3 | * Barra de escala para el selector de mapas. 4 | * Añadido características de vías fluviales al micromapeo. 5 | -------------------------------------------------------------------------------- /metadata/it-IT/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Hashtag per il gruppo di modifiche. 2 | * Intervallo di conferma aumentato a 2 mesi. 3 | * Il campo dei nomi è focalizzato quando si crea un nuovo POI. 4 | * Avvisi per luoghi che hanno un tag `fixme` o che sono troppo vecchi. 5 | -------------------------------------------------------------------------------- /lib/helpers/normalizer.dart: -------------------------------------------------------------------------------- 1 | import "package:unorm_dart/unorm_dart.dart" as unorm; 2 | 3 | String normalizeString(String s) { 4 | var combining = RegExp(r"[\u0300-\u036F\u3099-\u309C]"); 5 | return unorm.nfkd(s.toLowerCase().trim()).replaceAll(combining, ''); 6 | } 7 | -------------------------------------------------------------------------------- /metadata/es-ES/changelogs/45.txt: -------------------------------------------------------------------------------- 1 | * Añadido la visualización de la ruta recorrida recientemente. 2 | * El dibujo GeoScribbles está bloqueado por defecto. 3 | * Escáner de códigos QR para el campo del sitio web. 4 | * La ubicación ahora se actualiza una vez por segundo. 5 | -------------------------------------------------------------------------------- /metadata/es-ES/changelogs/55.txt: -------------------------------------------------------------------------------- 1 | * ¡Compatible con extensiones! 2 | * Los marcadores del mapa se vuelven verdes cuando se confirman los servicios. 3 | * Orden correcto de los días de la semana para EE.UU. e Israel. 4 | * Visualización de la dirección de la brújula. 5 | -------------------------------------------------------------------------------- /metadata/es-ES/changelogs/39.txt: -------------------------------------------------------------------------------- 1 | * Corregido la capitalización para las descripciones. 2 | * Corregido el error por el que no se mostraban las advertencias amarillas sobre los servicios. 3 | * Corregido el error por el que se marcaba una tienda en un edificio en desuso. 4 | -------------------------------------------------------------------------------- /lib/helpers/cache_digger.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' show Point; 2 | 3 | class BaseTile extends Point { 4 | final int? depth; 5 | 6 | const BaseTile(super.x, super.y, [this.depth]); 7 | 8 | BaseTile withDepth(int depth) => BaseTile(x, y, depth); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /metadata/zh-CN/full_description.txt: -------------------------------------------------------------------------------- 1 | 此编辑器无需你费心思考。只需走进一个商场,启动 Every Door,你就会看到周围已被标注的商铺:点一下对勾,表示这些商铺仍然存在;若有未标注的商铺,就添加上去。这就是整个流程:凭借这个简单的编辑器,你可以轻松让整座城镇保持最新地图数据。 2 | 3 | 此外,它还有一个微绘图模式,可用于核实和添加长椅、路灯等设施;还有一个“入口模式”,用于添加建筑属性和出入口——这些信息会自动与建筑轮廓合并。 4 | 5 | Every Door 使用 iD 编辑器的预设和其他数据。 6 | -------------------------------------------------------------------------------- /metadata/hu/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Módosításcsomagok kettős keresztes (#) címkéi. 2 | * A megerősítési időszak megnövelve 2 hónapra. 3 | * A név mező fókuszba kerül egy új POI létrehozásakor. 4 | * Figyelmeztetések olyan létesítményeknél, amelyeknek „fixme” címkéjük van vagy túl öregek. 5 | -------------------------------------------------------------------------------- /metadata/es-ES/changelogs/29.txt: -------------------------------------------------------------------------------- 1 | * Cambios en los hashtags. 2 | * Aumento del intervalo de confirmación a 2 meses. 3 | * El campo «name» se selecciona automáticamente al crear un nuevo PDI. 4 | * Advertencias para servicios que tienen una etiqueta «fixme» o que son demasiado antiguos. 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Oct 01 12:06:31 EEST 2023 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Share Extension/ShareViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShareViewController.swift 3 | // Share Extension 4 | // 5 | // Created by user937662 on 6/12/25. 6 | // 7 | 8 | import UIKit 9 | import Social 10 | import listen_sharing_intent 11 | 12 | class ShareViewController: RSIShareViewController { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 18116933e77adc82f80866c928266a5b4f1ed645 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /ios/Share Extension/Share Extension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.info.zverev.everydoor 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /lib/fields/room.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/fields/text.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class RoomPresetField extends TextPresetField { 5 | const RoomPresetField({String? label}) 6 | : super( 7 | key: 'addr:door', 8 | label: label ?? 'Room Number', 9 | icon: Icons.door_front_door_outlined, 10 | keyboardType: TextInputType.visiblePassword, 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /lib/providers/need_update.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | 4 | final needMapUpdateProvider = ChangeNotifierProvider((_) => NeedMapUpdateNotifier()); 5 | 6 | /// Simple provider to notify the POI list that it needs to be updated. 7 | class NeedMapUpdateNotifier extends ChangeNotifier { 8 | /// Calls notifyListeners(). 9 | void trigger() { 10 | notifyListeners(); 11 | } 12 | } -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.associated-domains 6 | 7 | applinks:plugins.every-door.app 8 | 9 | com.apple.security.application-groups 10 | 11 | group.info.zverev.everydoor 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /assets/styles/buildings.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "id": "buildings", 4 | "sources": { 5 | "openmaptiles": { 6 | "type": "vector", 7 | "url": "https://tiles.openfreemap.org/planet" 8 | } 9 | }, 10 | "layers": [ 11 | { 12 | "id": "building", 13 | "type": "line", 14 | "source": "openmaptiles", 15 | "source-layer": "building", 16 | "minzoom": 18, 17 | "maxzoom": 24, 18 | "paint": { 19 | "line-color": "rgba(255, 255, 255, 1)" 20 | } 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /metadata/et/full_description.txt: -------------------------------------------------------------------------------- 1 | See kaardimuutmise tarvik ei sunni sind ülemõtlema. Mine ostukesusesse ja käivita Every Door. Enda ümbruses näed kaardistatud poode: klõpsi kinnitusmärget nende puhul, kes on alles ja lisa need, mis on puudu. Ja see ongi olemuselt kogu töövoog, mis võimaldab sinu suurema või väiksema ümbruse andmed hoida uuendatuna. 2 | 3 | Lisaks on olemas pinkide ja tänavavalgustite mikrokaardistamise võimalus ning eraldi vaade hoonete sissepääsude ja muude andmete uuendamiseks. 4 | 5 | Every Doori eelseadistused ja muud andmed on võetud „iD Editor“-i andmekogust. 6 | -------------------------------------------------------------------------------- /metadata/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 | This editor does not make you think. Just go to a mall, and start Every Door. You'll see mapped shops around you: tap on the checkmark for any that are still there, and add shops that are not on the map. That's the entire process: you can keep your entire town up-to-date thanks to this simple editor. 2 | 3 | There is also a micromapping mode for verifying and adding benches and street lamps. And an entrance mode for adding building attributes and entrances — which are merged automatically into building contours. 4 | 5 | Every Door uses presets and other data from iD editor. 6 | -------------------------------------------------------------------------------- /metadata/uk/full_description.txt: -------------------------------------------------------------------------------- 1 | Цей редактор не змушує вас думати. Просто зайдіть у торговий центр і запустіть «Кожні двері». Ви побачите на карті магазини навколо себе: натисніть на галочку для тих, що ще є, і додайте магазини, яких немає на карті. Ось і весь процес: завдяки цьому простому редактору ви можете оновлювати все своє місто. 2 | 3 | Також є режим мікрокартографування для перевірки та додавання лавок і вуличних ліхтарів. І режим входу для додавання атрибутів будівель і входів, які автоматично об’єднуються в контури будівель. 4 | 5 | «Кожні двері» використовує пресети та інші дані з редактора iD. 6 | -------------------------------------------------------------------------------- /lib/models/imagery/geojson.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/models/imagery.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_map_geojson2/flutter_map_geojson2.dart'; 4 | 5 | class GeoJsonImagery extends Imagery { 6 | final GeoJsonProvider source; 7 | 8 | GeoJsonImagery({ 9 | required super.id, 10 | super.category, 11 | super.name, 12 | super.icon, 13 | super.attribution, 14 | required this.source, 15 | }) : super(overlay: true); 16 | 17 | @override 18 | Widget buildLayer({bool reset = false}) { 19 | return GeoJsonLayer(data: source); 20 | } 21 | } -------------------------------------------------------------------------------- /metadata/en-GB/full_description.txt: -------------------------------------------------------------------------------- 1 | This editor does not make you think. Just go to a shopping centre, and start Every Door. You'll see mapped shops around you: tap on the checkmark for any that are still there, and add shops that are not on the map. That's the entire process: you can keep your entire town up-to-date thanks to this simple editor. 2 | 3 | There is also a micromapping mode for verifying and adding benches and street lamps. And an entrance mode for adding building attributes and entrances — which are merged automatically into building contours. 4 | 5 | Every Door uses presets and other data from iD editor. 6 | -------------------------------------------------------------------------------- /metadata/hr/full_description.txt: -------------------------------------------------------------------------------- 1 | Ovaj uređivač vas ne tjera na razmišljanje. Jednostavno otiđite u trgovački centar i pokrenite Every Door. Vidjeti ćete mapirane trgovine oko sebe: dotaknite kvačicu za sve koje su još tamo i dodajte trgovine koje nisu na karti. To je cijeli proces: možete ažurirati cijeli svoj grad zahvaljujući ovom jednostavnom uređivaču. 2 | 3 | Tu je i način mikromapiranja za provjeru i dodavanje klupa i uličnih svjetiljki. I način ulaza za dodavanje atributa zgrade i ulaza — koji se automatski spajaju u konture zgrade. 4 | 5 | Every Door koristi predefinirane oznake i druge podatke iz iD uređivača. 6 | -------------------------------------------------------------------------------- /metadata/cs-CZ/full_description.txt: -------------------------------------------------------------------------------- 1 | Tento editor vás nenutí přemýšlet. Stačí zajít do nákupního centra a zapnout Every Door. Kolem sebe uvidíte zmapované obchody: klepněte na fajfku pro ty, které se zde stále nacházejí, a přidejte obchody, které na mapě nejsou. To není vše: díky tomuto jednoduchému editoru můžete udržovat aktuální celé své město. 2 | 3 | Aplikace také nabízí režim mikromapování pro ověřování a přidávání laviček a pouličního osvětlení. Také má režim vchodů pro přidávání atributů a vchodů do budov – ty jsou následně automaticky spojeny s obrysy budov. 4 | 5 | Aplikace Every Door používá předvolby a další data z editoru iD. 6 | -------------------------------------------------------------------------------- /metadata/it-IT/full_description.txt: -------------------------------------------------------------------------------- 1 | Questo editor non ti fa pensare. Vai da un centro commerciale e avvia EveryDoor. Vedrai i negozi mappati intorno a te: tocca il segno di spunta per quelli che sono ancora lì, e aggiungi i negozi che non sono sulla mappa. Questo è l'intero processo: puoi mantenere aggiornata la tua città grazie a questo semplice editor. 2 | 3 | C'è anche una modalità micromapping per verificare e aggiungere panche e lampioni. E una modalità per l'aggiunta di attributi agli edifici e di ingressi — che vengono fusi automaticamente nei contorni degli edifici. 4 | 5 | EveryDoor utilizza preset e altri dati dell'editor iD. 6 | -------------------------------------------------------------------------------- /lib/widgets/attribution.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/models/imagery.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AttributionWidget extends StatelessWidget { 5 | final Imagery? imagery; 6 | 7 | const AttributionWidget(this.imagery, {super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | final src = imagery?.attribution; 12 | if (src == null) return Container(); 13 | return Align( 14 | alignment: Alignment.bottomRight, 15 | child: Padding( 16 | padding: const EdgeInsets.all(4.0), 17 | child: Text(src), 18 | ), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /metadata/da-DK/full_description.txt: -------------------------------------------------------------------------------- 1 | Denne editor tvinger dig ikke til at tænke. Bare gå til et indkøbscenter, og start Every Door. Du vil se kortlagte butikker omkring dig: Tryk på fluebenet for dem, der stadig er der, og tilføj butikker, der ikke er på kortet. Det er hele processen: Du kan holde hele din by opdateret takket være denne enkle editor. 2 | 3 | Der er også en mikrokortlægning-tilstand til at verificere og tilføje bænke og gadelamper. Og en indgangstilstand til at tilføje bygningsegenskaber og indgange. — som automatisk flettes sammen med bygningskonturer. 4 | 5 | Every Door bruger forudindstillinger og andre data fra iD-editoren. 6 | -------------------------------------------------------------------------------- /lib/fields/section.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/models/amenity.dart'; 2 | import 'package:every_door/models/field.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class SectionPresetField extends PresetField { 6 | final String title; 7 | 8 | SectionPresetField(this.title) : super(key: '-', label: ''); 9 | 10 | @override 11 | Widget buildWidget(OsmChange element) { 12 | return Container( 13 | padding: const EdgeInsets.only(top: 15.0, bottom: 5.0), 14 | child: Text(title), // TODO: formatting 15 | ); 16 | } 17 | 18 | @override 19 | bool hasRelevantKey(Map tags) => false; 20 | } 21 | -------------------------------------------------------------------------------- /metadata/sl/full_description.txt: -------------------------------------------------------------------------------- 1 | Ta urejevalnik vas ne sili v razmišljanje. Preprosto pojdite v nakupovalno središče in zaženite Every Door. Prikazale se bodo trgovine v vaši bližini: tapnite na kljukico za tiste, ki so še vedno tam, in dodajte trgovine, ki niso na zemljevidu. To je celoten postopek: s tem preprostim urejevalnikom lahko poskrbite, da bo vaše mesto vedno posodobljeno. 2 | 3 | Na voljo je tudi način mikromapiranja za preverjanje in dodajanje klopi in uličnih svetilk. In način za dodajanje atributov stavb in vhodov, ki se samodejno združijo v obrise stavb. 4 | 5 | Every Door uporablja prednastavitve in druge podatke iz urejevalnika iD. 6 | -------------------------------------------------------------------------------- /metadata/es-ES/full_description.txt: -------------------------------------------------------------------------------- 1 | Este editor no te hace pensar. Solo tienes que ir a un centro comercial y abrir Every Door. Verás las tiendas que hay a tu alrededor en el mapa: pulsa la marca de verificación de las que sigan allí y añade las que no estén en el mapa. Eso es todo: gracias a este sencillo editor, podrás mantener toda tu ciudad actualizada. 2 | 3 | También hay un modo de micromapeo para verificar y añadir bancos y farolas. Y un modo de entrada para añadir atributos de edificios y entradas, que se fusionan automáticamente con los contornos de los edificios. 4 | 5 | Every Door utiliza ajustes preestablecidos y otros datos del editor iD. 6 | -------------------------------------------------------------------------------- /metadata/sv-SE/full_description.txt: -------------------------------------------------------------------------------- 1 | Denna editor tvingar dig inte att tänka. Gå bara till ett varuhus och starta Every Door. Du kommer att se kartlagda butiker runt dig: bocka i rutan för de som fortfarande finns kvar och lägg till butiker som inte finns på kartan. Det är hela processen: du kan hålla hela din stad uppdaterad genom att använda denna enkla editor. 2 | 3 | Det finns också ett mikrokartläggningsläge för att verifiera och lägga till bänkar och gatulampor. Och ett entré-läge för att lägga till byggnadsattribut och entréer — som automatiskt fästs i byggnadskonturer. 4 | 5 | Every Door använder förinställningar och annan data från iD editor. 6 | -------------------------------------------------------------------------------- /metadata/fi-FI/full_description.txt: -------------------------------------------------------------------------------- 1 | Tämän editorin kanssa ei tarvitse ihmetellä. Riittää, että menet kauppakeskukseen ja avaat Every Doorin. Näet kartoitettuja kauppoja ympärilläsi: paina valintamerkkiä, jos kauppa on vielä olemassa, ja lisää puuttuvat kaupat kartalle. Siinä koko prosessi: voit pitää koko kaupungin ajan tasalla tämän yksinkertaisen editorin ansiosta. 2 | 3 | Mikrokartoitus-tilassa voi myös tarkistaa ja lisätä sekä penkkejä että katuvaloja. Sisäänkäynnit-tilassa rakennuksiin voi lisätä ominaisuuksia ja sisäänkäyntejä – jotka yhdistetään automaattisesti rakennuksen ääriviivaan. 4 | 5 | Every Door käyttää iD-editorin kohdetyyppejä ja muita tietoja. 6 | -------------------------------------------------------------------------------- /metadata/ru/full_description.txt: -------------------------------------------------------------------------------- 1 | Этот редактор не заставляет вас думать. Просто зайдите в торговый центр и запустите Every Door. Вы увидите отмеченные на карте магазины вокруг вас: нажмите на галочку для тех, которые всё ещё там, и добавьте магазины, которых нет на карте. Вот и весь процесс: вы можете поддерживать весь свой город в актуальном состоянии благодаря этому простому редактору. 2 | 3 | Также есть режим микрокартирования для проверки и добавления скамеек и уличных фонарей. И режим входа для добавления атрибутов здания и входов — которые автоматически объединяются в контуры здания. 4 | 5 | Every Door использует предустановки и другие данные из редактора iD. 6 | -------------------------------------------------------------------------------- /metadata/pt-BR/full_description.txt: -------------------------------------------------------------------------------- 1 | Este editor não te faz pensar. Basta ir a um shopping e iniciar o Every Door. Você verá lojas mapeadas ao seu redor: toque na marca de verificado para confirmar que aquela loja ainda está lá e adicione as outras que não estão ainda no mapa. Esse é o processo completo: você pode manter toda a sua cidade atualizada graças a este editor simples. 2 | 3 | Há também um modo de micromapeamento para verificar e adicionar assentos e postes de luz. E um modo de entrada para adicionar atributos e entradas de edifícios — que são mesclados automaticamente aos contornos dos edifícios. 4 | 5 | O Every Door usa predefinições e outros dados do editor iD. 6 | -------------------------------------------------------------------------------- /lib/helpers/yaml_map.dart: -------------------------------------------------------------------------------- 1 | import 'package:yaml/yaml.dart'; 2 | 3 | extension YamlMapConverter on YamlMap { 4 | dynamic _convertNode(YamlNode v) { 5 | if (v is YamlMap) { 6 | return v.toMap(); 7 | } else if (v is YamlList) { 8 | return v.nodes.map((e) => _convertNode(e)).toList(); 9 | } else if (v is YamlScalar) { 10 | return v.value; 11 | } else { 12 | return v; 13 | } 14 | } 15 | 16 | Map toMap() { 17 | var map = {}; 18 | nodes.forEach((k, v) { 19 | if (k is YamlScalar) { 20 | map[k.value.toString()] = _convertNode(v); 21 | } 22 | }); 23 | return map; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/helpers/geometry/equirectangular.dart: -------------------------------------------------------------------------------- 1 | import 'package:latlong2/latlong.dart'; 2 | import 'dart:math' as math; 3 | 4 | class Equirectangular extends Haversine { 5 | const Equirectangular(); 6 | 7 | @override 8 | double distance(LatLng p1, LatLng p2) { 9 | final f1 = p1.latitudeInRad; 10 | final f2 = p2.latitudeInRad; 11 | final x = (p2.longitudeInRad - p1.longitudeInRad) * math.cos((f1 + f2) / 2); 12 | final y = f2 - f1; 13 | return math.sqrt(x*x + y*y) * earthRadius; 14 | } 15 | } 16 | 17 | class DistanceEquirectangular extends Distance { 18 | const DistanceEquirectangular({super.roundResult = false}) 19 | : super(calculator: const Equirectangular()); 20 | } -------------------------------------------------------------------------------- /tools/encode_url.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_print 2 | 3 | import 'dart:io'; 4 | import 'package:encrypt/encrypt.dart'; 5 | 6 | String encryptUrl(String url) { 7 | const kDefaultAesKey = '+p08T46G5YGKftKBHUeg0A=='; 8 | final encrypter = Encrypter(AES(Key.fromBase64(kDefaultAesKey), mode: AESMode.ctr)); 9 | final decrypted = encrypter.encrypt(url, iv: IV.allZerosOfLength(16)); 10 | return decrypted.base64; 11 | } 12 | 13 | void main(List args) { 14 | if (args.isEmpty) { 15 | print('Encodes an URL with AES, to put into lib/providers/imagery.dart'); 16 | print('Usage: dart encode_url.dart "url"'); 17 | exit(1); 18 | } 19 | print(encryptUrl(args[0])); 20 | } 21 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /metadata/de-DE/full_description.txt: -------------------------------------------------------------------------------- 1 | Dieser Editor verhindet, dass du zuviel denken musst. Z.B. kannst du einfach in ein Einkaufszentrum gehen und Every Door starten. Du wirst schon in OpenStreetMap erfasste Dinge um dich sehen: bestätige Dinge, die da sind, und erfasse Läden, die noch nicht auf der Karte sind. Das ist schon Alles: du kannst dank diesem simplen Editor die Daten deiner ganze Stadt in OpenStreetMap auf dem Laufenden halten. 2 | 3 | Es gibt auch einen Micromapping-Modus zum Verifizieren und Hinzufügen von Sitzbänken und Strassenlaternen. Und einen Eingangs-Modus zum Hinzufügen von Gebäude-Attributen und -Eingängen (die automatisch in der Gebäudekontour hinzugefügt werden). 4 | 5 | Every Door verwendet die Voreinstellungen und andere Daten vom iD Editor. 6 | -------------------------------------------------------------------------------- /lib/helpers/geometry/circle_bounds.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_map/flutter_map.dart' show LatLngBounds; 2 | import 'package:latlong2/latlong.dart' show LatLng; 3 | import 'dart:math' as math; 4 | 5 | LatLngBounds boundsFromRadius(LatLng center, num radiusMeters) { 6 | const double equatorRadius = 6378137.0; 7 | const double degreeLength = equatorRadius * 2 * math.pi / 360.0; 8 | final dy = radiusMeters.toDouble() / degreeLength; 9 | final dx = dy / math.cos(center.latitudeInRad); 10 | // For testing: (59.9598294, 30.3194758) + 100 m 11 | // should result in (59.9607281, 30.3212749) 12 | return LatLngBounds( 13 | LatLng(center.latitude - dy, center.longitude - dx), 14 | LatLng(center.latitude + dy, center.longitude + dx), 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /lib/providers/note_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/providers/shared_preferences.dart'; 2 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 | 4 | final noteIsOsmProvider = 5 | NotifierProvider(NoteStateProvider.new); 6 | 7 | class NoteStateProvider extends Notifier { 8 | static const kPrefsKey = 'is_osm_note'; 9 | 10 | @override 11 | bool build() { 12 | final prefs = ref.read(sharedPrefsProvider).requireValue; 13 | bool? newOSM = prefs.getBool(kPrefsKey); 14 | return newOSM ?? false; 15 | } 16 | 17 | Future set(bool noteIsOsm) async { 18 | state = noteIsOsm; 19 | final prefs = ref.read(sharedPrefsProvider).requireValue; 20 | await prefs.setBool(kPrefsKey, state); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022, Ilya Zverev 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | // https://stackoverflow.com/a/77738936/1297601 7 | subprojects { 8 | afterEvaluate { project -> 9 | if (project.hasProperty('android')) { 10 | project.android { 11 | if (namespace == null) { 12 | namespace project.group 13 | } 14 | } 15 | } 16 | } 17 | } 18 | } 19 | 20 | rootProject.buildDir = '../build' 21 | subprojects { 22 | project.buildDir = "${rootProject.buildDir}/${project.name}" 23 | project.evaluationDependsOn(':app') 24 | } 25 | 26 | tasks.register("clean", Delete) { 27 | delete rootProject.buildDir 28 | } 29 | -------------------------------------------------------------------------------- /metadata/hu/full_description.txt: -------------------------------------------------------------------------------- 1 | Ez a szerkesztő nem készteti Önt gondolkodásra. Csak menjen el egy bevásárlóközpontba, és indítsa el az Every Door alkalmazást. Látni fogja a feltérképezett üzleteket Ön körül: koppintson az ellenőrzőjelre bármely üzletnél, amely még mindig ott található, és adja hozzá azokat az üzleteket, amelyek nincsenek a térképen. Ennyi a teljes folyamat: az egész várost naprakészen tarthatja ennek az egyszerű szerkesztőnek köszönhetően. 2 | 3 | Van egy mikrotérképezési mód is a padok és utcai lámpák ellenőrzéséhez és hozzáadásához. És egy bejáratok mód az épületek attribútumainak és bejáratainak hozzáadásához – amelyek automatikusan egyesítve lesznek az épületek körvonalaiba. 4 | 5 | Az Every Door alkalmazás az iD-szerkesztőből származó címkesablonokat és egyéb adatokat használja. 6 | -------------------------------------------------------------------------------- /lib/screens/modes/navigate.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/widgets/map.dart'; 2 | import 'package:every_door/widgets/status_pane.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class NavigationPane extends StatefulWidget { 6 | const NavigationPane({super.key}); 7 | 8 | @override 9 | State createState() => _NavigationPaneState(); 10 | } 11 | 12 | class _NavigationPaneState extends State { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Stack( 16 | children: [ 17 | CustomMap( 18 | allowRotation: false, 19 | onlyOSM: true, 20 | track: false, 21 | drawPinMarker: false, 22 | updateState: true, 23 | ), 24 | ApiStatusPane(), 25 | ], 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/plugins/database.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/constants.dart'; 2 | import 'package:flutter/foundation.dart' show kDebugMode; 3 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 4 | import 'package:sqflite/sqflite.dart'; 5 | 6 | final pluginDatabaseProvider = Provider((_) => PluginDatabaseHelper._()); 7 | 8 | class PluginDatabaseHelper { 9 | static const _kDatabaseName = 'every_door_plugins.db'; 10 | 11 | PluginDatabaseHelper._(); 12 | 13 | Database? _db; 14 | 15 | Future get database async { 16 | _db ??= await createDatabase(); 17 | return _db!; 18 | } 19 | 20 | Future createDatabase() async { 21 | if (kEraseDatabase && kDebugMode) { 22 | await deleteDatabase(_kDatabaseName); 23 | } 24 | 25 | return await openDatabase(_kDatabaseName); 26 | } 27 | } -------------------------------------------------------------------------------- /lib/providers/shared_preferences.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 2 | import 'package:shared_preferences/shared_preferences.dart'; 3 | import 'package:shared_preferences/util/legacy_to_async_migration_util.dart'; 4 | 5 | final sharedPrefsProvider = FutureProvider( 6 | (_) async => SharedPreferencesWithCache.create( 7 | cacheOptions: SharedPreferencesWithCacheOptions())); 8 | 9 | Future migrateSharedPreferences() async { 10 | final SharedPreferences prefs = await SharedPreferences.getInstance(); 11 | await migrateLegacySharedPreferencesToSharedPreferencesAsyncIfNecessary( 12 | legacySharedPreferencesInstance: prefs, 13 | sharedPreferencesAsyncOptions: SharedPreferencesOptions(), 14 | migrationCompletedKey: 'spMigrationCompleted', 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "8.9.3" apply false 22 | id "org.jetbrains.kotlin.android" version "2.1.0" apply false 23 | } 24 | 25 | include ":app" 26 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 13.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/models/imagery/vector_assets.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/helpers/tile_caches.dart'; 2 | import 'package:every_door/models/imagery/vector.dart'; 3 | import 'package:every_door/models/imagery/vector/style_reader.dart'; 4 | 5 | class VectorAssetsImagery extends VectorImagery { 6 | // We need those to initialize the layer. 7 | final String stylePath; 8 | final String? spritesBase; 9 | 10 | VectorAssetsImagery({ 11 | required super.id, 12 | required this.stylePath, 13 | this.spritesBase, 14 | super.fast, 15 | super.category, 16 | super.name, 17 | super.icon, 18 | super.attribution, 19 | super.overlay = false, 20 | super.best = false, 21 | super.cachingStore = kTileCacheBase, 22 | }); 23 | 24 | @override 25 | Future initialize() async { 26 | style ??= await EdStyleReader(url: stylePath) 27 | .readAssets(spritesBase: spritesBase); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/widgets/pin_marker.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/helpers/blend_mask.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_map/flutter_map.dart'; 4 | import 'package:latlong2/latlong.dart'; 5 | 6 | /// This is the black pin in the current effective location. 7 | /// Also used for the editor object location and for the map 8 | /// chooser. Basically the marker in the center of a map. 9 | class PinMarker extends Marker { 10 | PinMarker(LatLng location, {Color color = Colors.white, bool blend = true}) 11 | : super( 12 | point: location, 13 | rotate: true, 14 | alignment: Alignment(0.0, -0.7), 15 | child: blend 16 | ? BlendMask( 17 | blendMode: BlendMode.difference, 18 | child: Icon(Icons.location_pin, color: color), 19 | ) 20 | : Icon(Icons.location_pin, color: color), 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /lib/l10n/app_bg.arb: -------------------------------------------------------------------------------- 1 | { 2 | "dataDownloadSuccessful": "Изтеглянето е успешно", 3 | "@dataDownloadSuccessful": { 4 | "description": "Alert title for when the data was successfully downloaded." 5 | }, 6 | "faqTagging": "Всички въпроси за таговете", 7 | "@faqTagging": {}, 8 | "loadingStart": "Инициализиране…", 9 | "@loadingStart": { 10 | "description": "Initial message for the loading screen, virtually unseen." 11 | }, 12 | "loadingPresets": "Зареждане на заготовките…", 13 | "@loadingPresets": { 14 | "description": "Loading screen message for loading presets." 15 | }, 16 | "loadingChanges": "Зареждане на промените…", 17 | "@loadingChanges": { 18 | "description": "Loading screen message for loading stored changes." 19 | }, 20 | "loadingLocation": "Определяне на позицията…", 21 | "@loadingLocation": { 22 | "description": "Loading screen message for firing up GPS and waiting for a location." 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/helpers/lifecycle.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | typedef FutureVoidCallback = Future Function(); 4 | 5 | class LifecycleEventHandler extends WidgetsBindingObserver { 6 | final FutureVoidCallback? detached; 7 | final FutureVoidCallback? resumed; 8 | bool isActive = true; 9 | 10 | LifecycleEventHandler({this.detached, this.resumed}); 11 | 12 | @override 13 | void didChangeAppLifecycleState(AppLifecycleState state) async { 14 | switch (state) { 15 | case AppLifecycleState.resumed: 16 | if (resumed != null && !isActive) 17 | await resumed!(); 18 | isActive = true; 19 | break; 20 | case AppLifecycleState.inactive: 21 | case AppLifecycleState.paused: 22 | case AppLifecycleState.detached: 23 | case AppLifecycleState.hidden: 24 | if (detached != null && isActive) 25 | await detached!(); 26 | isActive = false; 27 | break; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /lib/widgets/walkpath.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/providers/path.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_map/flutter_map.dart'; 4 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 | 6 | /// A polyline for a [FlutterMap] that displays the recently 7 | /// walked path. 8 | class WalkPathPolyline extends ConsumerWidget { 9 | final bool faint; 10 | 11 | const WalkPathPolyline({super.key, this.faint = false}); 12 | 13 | @override 14 | Widget build(BuildContext context, WidgetRef ref) { 15 | final walkPath = ref.watch(pathProvider); 16 | 17 | if (walkPath.isEmpty) return Container(); 18 | 19 | return PolylineLayer(polylines: [ 20 | Polyline( 21 | points: walkPath, 22 | color: Colors.blue.withValues(alpha: 0.5), 23 | pattern: StrokePattern.dotted(spacingFactor: faint ? 2.0 : 2.5), 24 | strokeWidth: faint ? 5.0 : 4.0, 25 | borderColor: Colors.black26, 26 | borderStrokeWidth: faint ? 0.0 : 3.0, 27 | ), 28 | ]); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/widgets/track_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/helpers/multi_icon.dart'; 2 | import 'package:every_door/providers/geolocation.dart'; 3 | import 'package:every_door/widgets/map_button.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 6 | import 'package:latlong2/latlong.dart'; 7 | import 'package:every_door/generated/l10n/app_localizations.dart' show AppLocalizations; 8 | 9 | class TrackButton extends ConsumerWidget { 10 | const TrackButton({super.key}); 11 | 12 | @override 13 | Widget build(BuildContext context, WidgetRef ref) { 14 | final LatLng? trackLocation = ref.watch(geolocationProvider); 15 | final loc = AppLocalizations.of(context)!; 16 | 17 | return MapButton( 18 | enabled: !ref.watch(trackingProvider) && trackLocation != null, 19 | icon: MultiIcon(fontIcon: Icons.my_location), 20 | tooltip: loc.mapLocate, 21 | onPressed: (_) { 22 | ref.read(geolocationProvider.notifier).enableTracking(context); 23 | }, 24 | ); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/helpers/tags/payment_tags.dart: -------------------------------------------------------------------------------- 1 | const kCardPaymentOptions = { 2 | // Debit cards 3 | 'debit_cards', 4 | 'bancomat', 'bancontact', 'cb', 'girocard', 'gpn_debit', 5 | 'laser', 'maestro', 'postfinance_card', 'v_pay', 'visa_debit', 6 | 'mastercard_debit', 'visa_electron', 7 | // Credit cards 8 | 'credit_cards', 9 | 'american_express', 'diners_club', 'discover_card', 'jcb', 10 | 'mastercard', 'unionpay', 'visa', 'mir', 'belkart', 'pro100', 11 | // Contactless 12 | 'contactless', 13 | 'mastercard_contactless', 'paypass', 'visa_contactless', 14 | 'girocard_contactless', 'quickpass', 'QUICpay', 15 | 'apple_pay', 'google_pay' 16 | // Digital wallets 17 | 'troika', 'wechat', 'alipay', 'blik', 'gcash', 'touchngo', 18 | 'huawei_pay', 'interac', 'line_pay', 'mipay', 'samsung_pay', 19 | 'satispay', 'swish', 'twint', 20 | }; 21 | 22 | const kNotCards = { 23 | 'cash', 'notes', 'coins', 'cheque', 24 | 'bitcoin', 'cryptocurrencies', 'bitcoincash', 'litecoin', 25 | 'none', 'others', 'app', 'sms', 'wire_transfer', 'prepaid_ticket', 26 | }; 27 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/providers/api_status.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 2 | import 'package:every_door/generated/l10n/app_localizations.dart' show AppLocalizations; 3 | 4 | final apiStatusProvider = StateProvider((ref) => ApiStatus.idle); 5 | 6 | enum ApiStatus { 7 | idle, 8 | downloading, 9 | downloadingPlugin, 10 | updatingDatabase, 11 | uploading, 12 | uploadingNotes, 13 | uploadingPlugin, 14 | } 15 | 16 | String getApiStatusLoc(ApiStatus status, AppLocalizations loc) { 17 | switch (status) { 18 | case ApiStatus.idle: 19 | return 'Idle'; 20 | case ApiStatus.downloading: 21 | return loc.apiStatusDownloading; 22 | case ApiStatus.downloadingPlugin: 23 | return 'Downloading plugin data'; // TODO: translate 24 | case ApiStatus.updatingDatabase: 25 | return loc.apiStatusUpdatingDB; 26 | case ApiStatus.uploading: 27 | return loc.apiStatusUploading; 28 | case ApiStatus.uploadingNotes: 29 | return loc.apiStatusUploadingNotes; 30 | case ApiStatus.uploadingPlugin: 31 | return 'Uploading plugin data'; // TODO: translate 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/helpers/in_countries.dart: -------------------------------------------------------------------------------- 1 | import 'package:country_coder/country_coder.dart'; 2 | import 'package:latlong2/latlong.dart' show LatLng; 3 | 4 | Future isInsideRegions(LatLng location, List regions) async { 5 | if (!CountryCoder.instance.ready) { 6 | await Future.doWhile(() => Future.delayed(Duration(milliseconds: 100)) 7 | .then((_) => !CountryCoder.instance.ready)); 8 | } 9 | 10 | final queried = CountryCoder.instance.smallestOrMatchingRegion(lon: location.longitude, lat: location.latitude); 11 | if (queried == null) return false; // Outside any of the regions. 12 | 13 | for (final region in regions) { 14 | final boundsRegion = CountryCoder.instance.region(query: region); 15 | 16 | if (boundsRegion != null) { 17 | if (queried.id == boundsRegion.id) return true; 18 | if (queried.groups.contains(boundsRegion.id)) return true; 19 | } 20 | } 21 | 22 | return false; 23 | } 24 | 25 | Future buildingsHaveAddresses(LatLng location) async { 26 | return !(await isInsideRegions(location, [ 27 | 'Q55', // Netherlands 28 | 'Q38', // Italy 29 | 'Q142', // France 30 | ])); 31 | } 32 | -------------------------------------------------------------------------------- /lib/plugins/providers.dart: -------------------------------------------------------------------------------- 1 | import 'package:eval_annotation/eval_annotation.dart'; 2 | import 'package:every_door/providers/compass.dart'; 3 | import 'package:every_door/providers/geolocation.dart'; 4 | import 'package:every_door/providers/location.dart'; 5 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 6 | import 'package:latlong2/latlong.dart' show LatLng; 7 | 8 | @Bind() 9 | class PluginProviders { 10 | final Ref _ref; 11 | 12 | PluginProviders(this._ref); 13 | 14 | /// Get the current location of the main screen. 15 | LatLng get location => _ref.read(effectiveLocationProvider); 16 | 17 | /// Learn whether we're moving the map automatically with the user 18 | /// movement. 19 | bool get isTracking => _ref.read(trackingProvider); 20 | 21 | /// Get the compass direction. 22 | double? get compass => _ref.read(compassProvider)?.heading; 23 | 24 | /// Teleports the map to the given location. 25 | set location(LatLng value) => 26 | _ref.read(effectiveLocationProvider.notifier).set(value); 27 | 28 | /// Changes the map zoom level. 29 | set zoom(double value) => _ref.read(zoomProvider.notifier).state = value; 30 | 31 | // TODO: do we need watching? 32 | } 33 | -------------------------------------------------------------------------------- /lib/plugins/every_door_plugin.dart: -------------------------------------------------------------------------------- 1 | import 'package:eval_annotation/eval_annotation.dart'; 2 | import 'package:every_door/plugins/interface.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | /// Parent class for every plugin. None of the methods need to be implemented, 6 | /// although it would be weird. 7 | @Bind(bridge: true) 8 | class EveryDoorPlugin { 9 | /// Set up listeners and stuff. This gets called when the plugin is enabled, 10 | /// either during the start-up, or after the installation. 11 | Future install(EveryDoorApp app) async {} 12 | 13 | /// Uninstall plugin. Usually does not need to be overridden, but can e.g. store 14 | /// data somewhere. Called when the plugin is manually uninstalled. 15 | /// NOT called when the app is closed and unloaded. 16 | Future uninstall(EveryDoorApp app) async {} 17 | 18 | /// Returns a widget for the plugin settings. The best option would be 19 | /// to return a [Column] with a list of [ListTile]. 20 | /// Use [EveryDoorApp.preferences] for storing those. Use 21 | /// [EveryDoorApp.repaint] method when you usually would call setState(). 22 | Widget? buildSettingsPane(EveryDoorApp app, BuildContext context) { 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ios/Share Extension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AppGroupId 6 | $(CUSTOM_GROUP_ID) 7 | CFBundleVersion 8 | $(FLUTTER_BUILD_NUMBER) 9 | NSExtension 10 | 11 | NSExtensionAttributes 12 | 13 | NSExtensionActivationRule 14 | SUBQUERY ( 15 | extensionItems, 16 | $extensionItem, 17 | SUBQUERY ( 18 | $extensionItem.attachments, 19 | $attachment, 20 | ( 21 | ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.zip-archive" 22 | || ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.plain-text" 23 | ) 24 | ).@count == 1 25 | ).@count == 1 26 | 27 | 28 | NSExtensionMainStoryboard 29 | MainInterface 30 | NSExtensionPointIdentifier 31 | com.apple.share-services 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /tools/print_common_keys.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sqlite3 3 | import sys 4 | import re 5 | 6 | 7 | MAX_WIDTH = 78 8 | 9 | 10 | if __name__ == '__main__': 11 | if len(sys.argv) < 2: 12 | sys.stderr.write('Prints most common keys from taginfo\n') 13 | sys.stderr.write('Usage: {} []\n'.format(sys.argv[0])) 14 | sys.exit(1) 15 | 16 | taginfo = sqlite3.connect(sys.argv[1]) 17 | cur = taginfo.cursor() 18 | cur.execute( 19 | "select key from keys order by count_all desc limit ?", 20 | (5000 if len(sys.argv) < 3 else int(sys.argv[2]),)) 21 | s = ' ' 22 | RE_KEY = re.compile(r'^[a-z][a-z0-9_:-]+$') 23 | print('const kCommonKeys = {') 24 | for row in cur: 25 | k = row[0] 26 | if (k.startswith('source:') or k.startswith('tiger') or k.startswith('massgis') or 27 | k.startswith('KSJ2') or k.startswith('gns') or k.startswith('naptan') or 28 | '_1' in k or '_2' in k or not RE_KEY.match(k)): 29 | continue 30 | if len(s) + len(k) + 4 > MAX_WIDTH: 31 | print(s.rstrip()) 32 | s = ' ' 33 | s += f"'{k}', " 34 | if s: 35 | print(s.rstrip()) 36 | print('};') 37 | -------------------------------------------------------------------------------- /lib/helpers/blend_mask.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/rendering.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | // Copied from https://stackoverflow.com/a/77039320/1297601 5 | class BlendMask extends SingleChildRenderObjectWidget { 6 | final BlendMode blendMode; 7 | final double opacity; 8 | 9 | BlendMask({ 10 | required this.blendMode, 11 | this.opacity = 1.0, 12 | super.key, 13 | super.child, 14 | }); 15 | 16 | @override 17 | RenderObject createRenderObject(context) { 18 | return RenderBlendMask(blendMode, opacity); 19 | } 20 | 21 | @override 22 | void updateRenderObject(BuildContext context, RenderBlendMask renderObject) { 23 | renderObject.blendMode = blendMode; 24 | renderObject.opacity = opacity; 25 | } 26 | } 27 | 28 | class RenderBlendMask extends RenderProxyBox { 29 | BlendMode blendMode; 30 | double opacity; 31 | 32 | RenderBlendMask(this.blendMode, this.opacity); 33 | 34 | @override 35 | void paint(context, offset) { 36 | context.canvas.saveLayer( 37 | offset & size, 38 | Paint() 39 | ..blendMode = blendMode 40 | ..color = Color.fromARGB((opacity * 255).round(), 255, 255, 255)); 41 | 42 | super.paint(context, offset); 43 | 44 | context.canvas.restore(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/models/osm_area.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/constants.dart'; 2 | import 'package:flutter_map/flutter_map.dart' show LatLngBounds; 3 | import 'package:latlong2/latlong.dart' show LatLng; 4 | 5 | class OsmDownloadedArea { 6 | final LatLngBounds bounds; 7 | final DateTime downloaded; 8 | 9 | const OsmDownloadedArea(this.bounds, this.downloaded); 10 | 11 | bool get isObsolete => DateTime.now().difference(downloaded) > kObsoleteData; 12 | 13 | static const kTableName = 'areas'; 14 | static const kTableFields = [ 15 | 'min_lat real', 16 | 'min_lon real', 17 | 'max_lat real', 18 | 'max_lon real', 19 | 'downloaded integer', 20 | ]; 21 | 22 | factory OsmDownloadedArea.fromJson(Map data) { 23 | return OsmDownloadedArea( 24 | LatLngBounds( 25 | LatLng(data['min_lat'], data['min_lon']), 26 | LatLng(data['max_lat'], data['max_lon']), 27 | ), 28 | DateTime.fromMillisecondsSinceEpoch(data['downloaded']), 29 | ); 30 | } 31 | 32 | Map toJson() { 33 | return { 34 | 'min_lat': bounds.south, 35 | 'min_lon': bounds.west, 36 | 'max_lat': bounds.north, 37 | 'max_lon': bounds.east, 38 | 'downloaded': downloaded.millisecondsSinceEpoch, 39 | }; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/fields/radio.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/widgets/radio_field.dart'; 2 | import 'package:every_door/models/amenity.dart'; 3 | import 'package:every_door/models/field.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class RadioPresetField extends PresetField { 7 | List options; 8 | 9 | RadioPresetField({ 10 | required super.key, 11 | required super.label, 12 | super.icon, 13 | super.prerequisite, 14 | super.locationSet, 15 | required this.options, 16 | }); 17 | 18 | @override 19 | Widget buildWidget(OsmChange element) => RadioFieldIntl(this, element); 20 | } 21 | 22 | class RadioFieldIntl extends StatefulWidget { 23 | final RadioPresetField field; 24 | final OsmChange element; 25 | 26 | const RadioFieldIntl(this.field, this.element); 27 | 28 | @override 29 | State createState() => _RadioFieldIntlState(); 30 | } 31 | 32 | class _RadioFieldIntlState extends State { 33 | @override 34 | Widget build(BuildContext context) { 35 | return RadioField( 36 | options: widget.field.options, 37 | value: widget.element[widget.field.key], 38 | onChange: (value) { 39 | setState(() { 40 | widget.element[widget.field.key] = value; 41 | }); 42 | }, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | /android/app/prod 48 | /android/app/beta 49 | 50 | # Python stuff 51 | __pycache__/ 52 | venv/ 53 | 54 | # Project files 55 | assets/presets.db 56 | assets/plugin.edp 57 | assets/*.db-journal 58 | coverage/ 59 | lib/l10n/app_zh.arb 60 | lib/generated/ 61 | lib/commit_info.g.dart 62 | *.apk 63 | 64 | # I just keep them there 65 | /plugins/ 66 | /.dart_eval/ 67 | /tools/svg/ 68 | -------------------------------------------------------------------------------- /lib/models/imagery/vector/cache_kinds.dart: -------------------------------------------------------------------------------- 1 | // This is for sorting cached files into kinds. The position in this 2 | // list is more important than the access date. First is the most important, 3 | // last is the least. Unknown types have the most priority. 4 | // See [CachedFileKind] for enum names for each of the items. 5 | final _fileKinds = [ 6 | RegExp(r'^\d+_\d+_\d+_.+\.pbf$'), // downloaded vector tiles 7 | RegExp(r'.*-dem-\d.+\.png$'), // downloaded dem tiles 8 | RegExp(r'^\d+_\d+_\d+_.+\.(png|jpg|jpeg|webp)$'), // downloaded raster tiles 9 | RegExp(r'^icon-atlas-'), // sprites 10 | RegExp(r'^[a-zA-Z0-9.-]+-v[a-zA-Z0-9.-]+-\d+-\d+-\d+\.png'), // rendered raster 11 | ]; 12 | 13 | enum CachedFileKind implements Comparable { 14 | unknown(-1), 15 | vector(0), 16 | dem(1), 17 | raster(2), 18 | sprite(3), 19 | rendered(4); 20 | 21 | final int _kind; 22 | 23 | const CachedFileKind(this._kind); 24 | 25 | factory CachedFileKind.match(String path) { 26 | final idx = _fileKinds.indexWhere((r) => r.hasMatch(path)); 27 | return values.firstWhere((v) => v._kind == idx, orElse: () => unknown); 28 | } 29 | 30 | @override 31 | int compareTo(CachedFileKind other) => _kind.compareTo(other._kind); 32 | 33 | @override 34 | String toString() => _kind.toString(); 35 | } 36 | -------------------------------------------------------------------------------- /lib/models/road_name.dart: -------------------------------------------------------------------------------- 1 | import 'package:latlong2/latlong.dart' show LatLng; 2 | import 'package:proximity_hash/geohash.dart'; 3 | 4 | class RoadNameRecord { 5 | final String geohash; 6 | final String name; 7 | final DateTime? downloaded; 8 | 9 | const RoadNameRecord(this.name, this.geohash, [this.downloaded]); 10 | 11 | LatLng get center { 12 | final coords = GeoHasher().decode(geohash); 13 | return LatLng(coords[1], coords[0]); 14 | } 15 | 16 | @override 17 | bool operator ==(Object other) => 18 | other is RoadNameRecord && other.geohash == geohash && other.name == name; 19 | 20 | @override 21 | int get hashCode => name.hashCode + geohash.hashCode; 22 | 23 | static const kTableName = 'road_names'; 24 | static const kTableFields = [ 25 | 'name text', 26 | 'geohash text', 27 | 'downloaded integer', 28 | ]; 29 | 30 | Map toJson() { 31 | return { 32 | 'name': name, 33 | 'geohash': geohash, 34 | 'downloaded': (downloaded ?? DateTime.now()).millisecondsSinceEpoch, 35 | }; 36 | } 37 | 38 | factory RoadNameRecord.fromJson(Map data) { 39 | return RoadNameRecord( 40 | data['name'], 41 | data['geohash'], 42 | DateTime.fromMillisecondsSinceEpoch(data['downloaded']), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/widgets/round_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/helpers/multi_icon.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class RoundButton extends StatelessWidget { 5 | final MultiIcon icon; 6 | final String? tooltip; 7 | final Function()? onPressed; 8 | final bool small; 9 | final Color? background; 10 | final Color? foreground; 11 | 12 | const RoundButton({ 13 | required this.icon, 14 | this.tooltip, 15 | this.onPressed, 16 | this.small = false, 17 | this.background, 18 | this.foreground, 19 | }); 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | final widget = ElevatedButton( 24 | child: Padding( 25 | padding: EdgeInsets.symmetric( 26 | horizontal: 0.0, 27 | vertical: small ? 10.0 : 15.0, 28 | ), 29 | child: icon.getWidget( 30 | size: small ? 20.0 : 30.0, 31 | color: foreground ?? Colors.white, 32 | ), 33 | ), 34 | style: ElevatedButton.styleFrom( 35 | shape: CircleBorder(), 36 | backgroundColor: background, 37 | foregroundColor: foreground, 38 | ), 39 | onPressed: () { 40 | if (onPressed != null) onPressed!(); 41 | }, 42 | ); 43 | 44 | return tooltip == null && icon.tooltip == null 45 | ? widget 46 | : Tooltip(message: tooltip ?? icon.tooltip, child: widget); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/screens/settings/account_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/providers/auth.dart'; 2 | import 'package:every_door/screens/settings/account.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 | 6 | class AccountListPage extends ConsumerWidget { 7 | const AccountListPage({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context, WidgetRef ref) { 11 | return Scaffold( 12 | appBar: AppBar( 13 | title: Text("Accounts"), // TODO 14 | ), 15 | body: ListView( 16 | children: [ 17 | for (final account in ref.watch(authProvider).values) 18 | ListTile( 19 | title: Text(account.provider.title ?? account.name), 20 | subtitle: account.value == null 21 | ? null 22 | : Text(account.value?.displayName ?? ''), 23 | leading: account.provider.icon?.getWidget( 24 | context: context, 25 | icon: true, 26 | size: 30.0, 27 | ), 28 | trailing: Icon(Icons.navigate_next), 29 | onTap: () { 30 | Navigator.of(context).push(MaterialPageRoute( 31 | builder: (_) => AccountPage(account.name), 32 | )); 33 | }, 34 | ), 35 | ], 36 | ), 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.github/workflows/fdroid.yml: -------------------------------------------------------------------------------- 1 | name: Build apk like F-Droid 2 | 3 | on: 4 | [workflow_dispatch] 5 | 6 | jobs: 7 | build-and-test: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | with: 12 | submodules: true 13 | fetch-depth: 0 14 | - uses: actions/setup-java@v4 15 | with: 16 | java-version: '17' 17 | distribution: 'adopt' 18 | - run: sed -i -e 's/^#f\|^ *mobile_scanner.*$//' pubspec.yaml 19 | - run: mv lib/fields/helpers/qr_code.dart.fdroid lib/fields/helpers/qr_code.dart 20 | - run: echo '{}' > lib/l10n/app_zh.arb 21 | - run: rm -f lib/l10n/app_nap.arb 22 | - run: export PUB_CACHE=$(pwd)/.pub-cache 23 | - run: vendor/flutter/bin/flutter config --no-analytics 24 | - run: vendor/flutter/bin/flutter pub get 25 | - run: curl -L https://textual.ru/presets.db -o assets/presets.db 26 | - run: vendor/flutter/bin/dart run build_runner build 27 | - run: vendor/flutter/bin/flutter build apk --release --flavor prod --split-per-abi --target-platform=android-arm64 28 | - name: Rename APK 29 | run: mv build/app/outputs/flutter-apk/app*.apk build/app/outputs/flutter-apk/EveryDoor-$(git log -n 1 --format='%h').apk 30 | - name: Archive APK 31 | uses: actions/upload-artifact@v4 32 | with: 33 | name: everydoor-apk 34 | path: build/app/outputs/flutter-apk/EveryDoor*.apk 35 | retention-days: 60 36 | -------------------------------------------------------------------------------- /lib/helpers/tile_caches.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_map/flutter_map.dart'; 2 | import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart'; 3 | import 'package:http/io_client.dart'; 4 | 5 | const kTileCacheBase = 'base'; 6 | const kTileCacheImagery = 'satellite'; 7 | const kTileCacheDownload = 'download'; 8 | 9 | class CachedBingTileProvider extends FMTCTileProvider { 10 | CachedBingTileProvider() 11 | : super( 12 | stores: { 13 | kTileCacheImagery: BrowseStoreStrategy.readUpdateCreate, 14 | kTileCacheDownload: BrowseStoreStrategy.read, 15 | }, 16 | httpClient: IOClient(), 17 | ); 18 | 19 | String _tileToQuadkey(int x, int y, int z) { 20 | String quad = ''; 21 | for (int i = z; i > 0; i--) { 22 | int digit = 0; 23 | int mask = 1 << (i - 1); 24 | if ((x & mask) != 0) digit += 1; 25 | if ((y & mask) != 0) digit += 2; 26 | quad += digit.toString(); 27 | } 28 | return quad; 29 | } 30 | 31 | @override 32 | String getTileUrl(TileCoordinates coordinates, TileLayer options) { 33 | final quadkey = _tileToQuadkey( 34 | coordinates.x.round(), 35 | coordinates.y.round(), 36 | coordinates.z.round(), 37 | ); 38 | final tileUrl = super.getTileUrl(coordinates, options); 39 | return tileUrl 40 | .replaceFirst('_QUADKEY_', quadkey) 41 | .replaceFirst('_CULTURE_', 'en'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/plugins/events.dart: -------------------------------------------------------------------------------- 1 | import 'package:eval_annotation/eval_annotation.dart'; 2 | import 'package:every_door/providers/events.dart'; 3 | import 'package:every_door/screens/modes/definitions/base.dart'; 4 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 | import 'package:latlong2/latlong.dart' show LatLng; 6 | 7 | /// Plugin events wrapper. Use this class to listen to events. Listeners 8 | /// are automatically deactivated when the plugin is inactive. All callback 9 | /// should be asynchronous functions, even when they don't use await. 10 | @Bind() 11 | class PluginEvents { 12 | final String _pluginId; 13 | final Ref _ref; 14 | 15 | const PluginEvents(this._pluginId, this._ref); 16 | 17 | /// Listen to editing mode instantiations. The [callback] is called on 18 | /// each mode when initializing the plugin, and then every time a new 19 | /// mode is added. The [callback] should be an async function. 20 | void onModeCreated(Function(BaseModeDefinition mode) callback) { 21 | _ref.read(eventsProvider.notifier).onModeCreated(_pluginId, callback); 22 | } 23 | 24 | /// Invoked when the "upload" button is pressed. 25 | void onUpload(Function() callback) { 26 | _ref.read(eventsProvider.notifier).onUpload(_pluginId, callback); 27 | } 28 | 29 | /// Invoked when the "download" button is pressed. 30 | void onDownload(Function(LatLng) callback) { 31 | _ref.read(eventsProvider.notifier).onDownload(_pluginId, callback); 32 | } 33 | } -------------------------------------------------------------------------------- /lib/helpers/cached_svg_source.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui' show Color; 2 | 3 | import 'package:flutter_cache_manager/flutter_cache_manager.dart'; 4 | import 'package:jovial_svg/jovial_svg.dart'; 5 | 6 | class CachedSvgSource extends ScalableImageSource { 7 | final String url; 8 | final bool compact; 9 | final bool bigFloats; 10 | final Color? currentColor; 11 | final Map? headers; 12 | final String? cacheKey; 13 | 14 | CachedSvgSource( 15 | this.url, { 16 | this.compact = false, 17 | this.bigFloats = false, 18 | this.currentColor, 19 | this.headers, 20 | this.cacheKey, 21 | }); 22 | 23 | CacheManager get _cacheManager => DefaultCacheManager(); 24 | 25 | @override 26 | Future createSI() async { 27 | final file = 28 | await _cacheManager.getSingleFile(url, headers: headers, key: cacheKey); 29 | 30 | return ScalableImage.fromSvgString( 31 | await file.readAsString(), 32 | compact: compact, 33 | bigFloats: bigFloats, 34 | currentColor: currentColor, 35 | ); 36 | } 37 | 38 | @override 39 | bool operator ==(Object other) { 40 | if (other is! CachedSvgSource) return false; 41 | return other.url == url && 42 | other.currentColor == currentColor && 43 | other.headers == headers && 44 | other.cacheKey == cacheKey; 45 | } 46 | 47 | @override 48 | int get hashCode => Object.hash(url, currentColor, cacheKey, headers); 49 | } 50 | -------------------------------------------------------------------------------- /lib/widgets/status_pane.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/providers/api_status.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 4 | import 'package:every_door/generated/l10n/app_localizations.dart' show AppLocalizations; 5 | 6 | class ApiStatusPane extends ConsumerWidget { 7 | const ApiStatusPane({super.key}); 8 | 9 | @override 10 | Widget build(BuildContext context, WidgetRef ref) { 11 | final apiStatus = ref.watch(apiStatusProvider); 12 | if (apiStatus == ApiStatus.idle) return Container(); 13 | 14 | final loc = AppLocalizations.of(context)!; 15 | return Center( 16 | child: Container( 17 | padding: EdgeInsets.all(20.0), 18 | margin: EdgeInsets.all(20.0), 19 | decoration: BoxDecoration( 20 | borderRadius: BorderRadius.circular(10.0), 21 | color: Colors.white.withValues(alpha: 0.8), 22 | ), 23 | child: Column( 24 | mainAxisSize: MainAxisSize.min, 25 | mainAxisAlignment: MainAxisAlignment.center, 26 | crossAxisAlignment: CrossAxisAlignment.center, 27 | children: [ 28 | CircularProgressIndicator(), 29 | SizedBox(height: 20.0), 30 | Text( 31 | getApiStatusLoc(apiStatus, loc), 32 | textAlign: TextAlign.center, 33 | style: TextStyle(fontSize: 20.0), 34 | ), 35 | ], 36 | ), 37 | ), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/providers/language.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/providers/presets.dart'; 2 | import 'package:every_door/providers/shared_preferences.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 | 6 | final languageProvider = 7 | NotifierProvider(LanguageController.new); 8 | 9 | class LanguageController extends Notifier { 10 | static const kLocaleKey = 'stored_locale'; 11 | static const kNull = '-'; 12 | 13 | @override 14 | Locale? build() { 15 | ref.read(sharedPrefsProvider).whenData((prefs) { 16 | final l = prefs.getStringList(kLocaleKey); 17 | if (l != null) { 18 | state = Locale.fromSubtags( 19 | languageCode: l[0], 20 | countryCode: l[1] == kNull ? null : l[1], 21 | scriptCode: l[2] == kNull ? null : l[2], 22 | ); 23 | } 24 | }); 25 | return null; 26 | } 27 | 28 | Future set(Locale? newValue) async { 29 | if (state != newValue) { 30 | state = newValue; 31 | final prefs = ref.read(sharedPrefsProvider).requireValue; 32 | if (newValue == null) { 33 | await prefs.remove(kLocaleKey); 34 | } else { 35 | await prefs.setStringList(kLocaleKey, [ 36 | newValue.languageCode, 37 | newValue.countryCode ?? kNull, 38 | newValue.scriptCode ?? kNull, 39 | ]); 40 | } 41 | // Clear caches. 42 | ref.read(presetProvider).clearFieldCache(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/providers/edpr.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert' show json, utf8; 2 | 3 | import 'package:country_coder/country_coder.dart'; 4 | import 'package:every_door/constants.dart'; 5 | import 'package:every_door/models/plugin.dart'; 6 | import 'package:every_door/providers/location.dart'; 7 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 8 | import 'package:http/http.dart' as http; 9 | import 'package:logging/logging.dart'; 10 | 11 | final _logger = Logger('EdprProvider'); 12 | 13 | final edprProvider = FutureProvider>((ref) async { 14 | // For now without customization. 15 | final location = ref.read(effectiveLocationProvider); 16 | final countries = CountryCoder.instance.load(); 17 | final countryResults = countries.regionsContaining( 18 | lat: location.latitude, lon: location.longitude); 19 | final countryIds = 20 | countryResults.map((c) => (c.iso1A2 ?? c.id).toUpperCase()).join(','); 21 | 22 | final url = Uri.https(kEdprEndpoint, '/api/list', { 23 | 'countries': countryIds, 24 | 'exp': '1', 25 | }); 26 | var response = await http.get(url); 27 | if (response.statusCode != 200) { 28 | throw Exception('Failed to query plugins list: ${response.statusCode}'); 29 | } 30 | 31 | try { 32 | final List data = json.decode(utf8.decode(response.bodyBytes)); 33 | final result = data.map((item) => RemotePlugin(item)); 34 | return result.toList(); 35 | } catch (e, stack) { 36 | _logger.severe('Failed to process EDPR list data: $e', e, stack); 37 | rethrow; 38 | } 39 | }); 40 | -------------------------------------------------------------------------------- /lib/providers/compass.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:logging/logging.dart'; 3 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 4 | import 'package:flutter_compass_v2/flutter_compass_v2.dart'; 5 | import 'dart:math' show pi; 6 | 7 | final compassProvider = 8 | NotifierProvider(CompassController.new); 9 | 10 | class CompassData { 11 | // radians, zero is North 12 | final double? heading; 13 | 14 | const CompassData(this.heading); 15 | } 16 | 17 | class CompassController extends Notifier { 18 | static final _logger = Logger('CompassController'); 19 | StreamSubscription? _sub; 20 | 21 | @override 22 | CompassData? build() { 23 | final compassEvents = FlutterCompass.events; 24 | if (compassEvents == null) { 25 | _logger.warning("Compass events not available on this platform."); 26 | return null; 27 | } 28 | 29 | _sub = compassEvents.listen( 30 | (CompassEvent event) { 31 | if (event.heading != null) { 32 | final double headingRadians = event.heading! * pi / 180.0; 33 | state = CompassData(headingRadians); 34 | } else { 35 | _logger.fine('Compass is calibrating, heading is null.'); 36 | state = CompassData(null); 37 | } 38 | }, 39 | onError: (error) { 40 | _logger.severe('Error reading compass data: $error'); 41 | state = null; 42 | }, 43 | ); 44 | 45 | ref.onDispose(() => _sub?.cancel()); 46 | return null; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/helpers/location_object.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/helpers/geometry/equirectangular.dart'; 2 | import 'package:latlong2/latlong.dart' show LatLng; 3 | 4 | class LocationObject { 5 | final LatLng location; 6 | final T value; 7 | 8 | const LocationObject(this.location, this.value); 9 | 10 | @override 11 | String toString() => 'LocObj($location, $value)'; 12 | } 13 | 14 | class LocationObjectSet { 15 | final _objects = >[]; 16 | 17 | LocationObjectSet([Iterable>? initList]) { 18 | if (initList != null) addAll(initList); 19 | } 20 | 21 | void add(LatLng location, T value) { 22 | _objects.add(LocationObject(location, value)); 23 | } 24 | 25 | void addAll(Iterable> objects) { 26 | _objects.addAll(objects); 27 | } 28 | 29 | void sortByDistance(LatLng location, {bool unique = false}) { 30 | if (_objects.length <= 1) return; 31 | 32 | const distance = DistanceEquirectangular(); 33 | _objects.sort((a, b) => distance(location, a.location) 34 | .compareTo(distance(location, b.location))); 35 | 36 | if (unique) { 37 | final newList = >[]; 38 | final seen = {}; 39 | for (final obj in _objects) { 40 | if (!seen.contains(obj.value)) { 41 | newList.add(obj); 42 | seen.add(obj.value); 43 | } 44 | } 45 | _objects.clear(); 46 | _objects.addAll(newList); 47 | } 48 | } 49 | 50 | List take(int count) => _objects.take(count).map((o) => o.value).toList(); 51 | } 52 | -------------------------------------------------------------------------------- /lib/models/imagery/bing.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/helpers/tile_caches.dart'; 2 | import 'package:every_door/models/imagery/tms.dart'; 3 | import 'package:every_door/providers/imagery.dart'; 4 | import 'package:flutter_map/flutter_map.dart' show TileProvider; 5 | 6 | class BingImagery extends TmsImagery { 7 | final _tileProvider = CachedBingTileProvider(); 8 | 9 | BingImagery({ 10 | required super.id, 11 | super.category, 12 | super.name, 13 | super.icon, 14 | super.attribution, 15 | required super.url, 16 | super.minZoom, 17 | super.maxZoom, 18 | super.best = false, 19 | super.tileSize = 256, 20 | super.encrypted = false, 21 | }); 22 | 23 | @override 24 | TmsImagery copyWith({ 25 | String? url, 26 | int? tileSize, 27 | String? attribution, 28 | int? minZoom, 29 | int? maxZoom, 30 | }) { 31 | return BingImagery( 32 | id: id, 33 | category: category, 34 | name: name, 35 | attribution: attribution ?? this.attribution, 36 | icon: icon, 37 | url: url ?? this.url, 38 | minZoom: minZoom ?? this.minZoom, 39 | maxZoom: maxZoom ?? this.maxZoom, 40 | best: best, 41 | tileSize: tileSize ?? this.tileSize, 42 | ); 43 | } 44 | 45 | @override 46 | TileProvider getTileProvider() => _tileProvider; 47 | 48 | @override 49 | String prepareUrl() { 50 | return ImageryProvider.bingUrlTemplate 51 | ?.replaceFirst('{quadkey}', '_QUADKEY_') 52 | .replaceFirst('{culture}', '_CULTURE_') ?? 53 | ''; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tools/language_names.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import csv 3 | import sqlite3 4 | import re 5 | import sys 6 | 7 | 8 | if __name__ == '__main__': 9 | if len(sys.argv) < 4: 10 | print('Takes a CSV extracted from Simple English Wikipedia ' 11 | 'with columns lang_name, native_name, iso_code and ' 12 | 'prepares a file for Every Door.') 13 | print('Usage: {} '.format(sys.argv[0])) 14 | sys.exit(1) 15 | 16 | result = [] 17 | taginfo = sqlite3.connect(sys.argv[2]) 18 | tcur = taginfo.cursor() 19 | with open(sys.argv[1], 'r') as f: 20 | for row in csv.reader(f): 21 | name_en = row[0].strip() 22 | name_loc = row[1].strip() 23 | iso_code = row[2].strip() 24 | if ',' in name_loc: 25 | name_loc = name_loc[:name_loc.index(',')].strip() 26 | if ',' in name_en: 27 | name_en = name_en[:name_en.index(',')].strip() 28 | tcur.execute("select count_all from keys where key = ?", ('name:' + iso_code,)) 29 | row = tcur.fetchone() 30 | count = 0 if not row else row[0] 31 | result.append('|'.join([iso_code, name_en, name_loc, str(count)])) 32 | 33 | dart = open(sys.argv[3], 'r').read() 34 | repl_str = '\\n'.join(result).replace("'", "\\'") 35 | dart = re.sub(r"(_kLanguageData =\s+')[^;]*;", 36 | lambda m: m.group(1) + repl_str + "';", dart) 37 | with open(sys.argv[3], 'w') as f: 38 | f.write(dart) 39 | -------------------------------------------------------------------------------- /lib/fields/wheelchair.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/widgets/radio_field.dart'; 2 | import 'package:every_door/models/amenity.dart'; 3 | import 'package:every_door/models/field.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:every_door/generated/l10n/app_localizations.dart' show AppLocalizations; 6 | 7 | class WheelchairPresetField extends PresetField { 8 | WheelchairPresetField({ 9 | required super.label, 10 | }) : super(key: 'wheelchair', icon: Icons.accessible); 11 | 12 | @override 13 | Widget buildWidget(OsmChange element) => WheelchairInputField(this, element); 14 | } 15 | 16 | class WheelchairInputField extends StatefulWidget { 17 | final WheelchairPresetField field; 18 | final OsmChange element; 19 | 20 | const WheelchairInputField(this.field, this.element); 21 | 22 | @override 23 | State createState() => _WheelchairInputFieldState(); 24 | } 25 | 26 | class _WheelchairInputFieldState extends State { 27 | @override 28 | Widget build(BuildContext context) { 29 | final loc = AppLocalizations.of(context)!; 30 | final vYes = loc.fieldWheelchairYes; 31 | final vLimited = loc.fieldWheelchairLimited; 32 | final vNo = loc.fieldWheelchairNo; 33 | 34 | return RadioField( 35 | options: const ['yes', 'limited', 'no'], 36 | labels: [vYes, vLimited, vNo], 37 | value: widget.element[widget.field.key], 38 | onChange: (value) { 39 | setState(() { 40 | widget.element[widget.field.key] = value; 41 | }); 42 | }, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '13.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | 36 | target 'Share Extension' do 37 | inherit! :search_paths 38 | end 39 | end 40 | 41 | post_install do |installer| 42 | installer.pods_project.targets.each do |target| 43 | flutter_additional_ios_build_settings(target) 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /.github/workflows/build-apk.yml: -------------------------------------------------------------------------------- 1 | name: Build Android apk 2 | 3 | on: 4 | [workflow_dispatch] 5 | 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | build-and-test: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | with: 15 | submodules: true 16 | fetch-depth: 0 17 | - uses: actions/setup-java@v4 18 | with: 19 | java-version: '17' 20 | distribution: 'adopt' 21 | - run: echo '{}' > lib/l10n/app_zh.arb 22 | - run: rm -f lib/l10n/app_nap.arb 23 | - run: vendor/flutter/bin/flutter pub get 24 | - run: curl -L https://textual.ru/presets.db -o assets/presets.db 25 | name: Download presets database 26 | - run: vendor/flutter/bin/dart run build_runner build 27 | - run: vendor/flutter/bin/flutter test 28 | - run: vendor/flutter/bin/flutter build apk --flavor beta 29 | - uses: noriban/sign-android-release@v5 30 | name: Sign app APK 31 | id: sign_app 32 | with: 33 | releaseDirectory: build/app/outputs/flutter-apk 34 | signingKeyBase64: ${{ secrets.KEYSTORE_JKS }} 35 | alias: github 36 | keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} 37 | keyPassword: ${{ secrets.KEYSTORE_PASSWORD }} 38 | - name: Rename APK 39 | run: mv ${{steps.sign_app.outputs.signedReleaseFile}} build/app/outputs/flutter-apk/EveryDoor-$(git log -n 1 --format='%h').apk 40 | - name: Archive APK 41 | uses: actions/upload-artifact@v4 42 | with: 43 | name: everydoor-apk 44 | path: build/app/outputs/flutter-apk/EveryDoor*.apk 45 | retention-days: 60 46 | -------------------------------------------------------------------------------- /lib/fields/direction.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/constants.dart'; 2 | import 'package:every_door/models/amenity.dart'; 3 | import 'package:every_door/models/field.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:every_door/generated/l10n/app_localizations.dart' show AppLocalizations; 6 | 7 | import 'helpers/direction_page.dart'; 8 | 9 | class DirectionPresetField extends PresetField { 10 | DirectionPresetField( 11 | {required super.key, 12 | required super.label, 13 | super.prerequisite}); 14 | 15 | @override 16 | Widget buildWidget(OsmChange element) => DirectionField(this, element); 17 | } 18 | 19 | class DirectionField extends StatelessWidget { 20 | final OsmChange element; 21 | final PresetField field; 22 | 23 | const DirectionField(this.field, this.element); 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | final loc = AppLocalizations.of(context)!; 28 | return Padding( 29 | padding: EdgeInsets.only(right: 10.0), 30 | child: ElevatedButton( 31 | onPressed: () async { 32 | String? value = await Navigator.push( 33 | context, 34 | MaterialPageRoute( 35 | builder: (context) => DirectionValuePage( 36 | element.location, element[field.key]))); 37 | if (value != null) { 38 | element[field.key] = value == '-' ? null : value; 39 | } 40 | }, 41 | child: Text( 42 | element[field.key] ?? '${loc.fieldDirectionSet}...', 43 | style: kFieldTextStyle, 44 | ), 45 | ), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/widgets/legend.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/constants.dart'; 2 | import 'package:every_door/helpers/legend.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:every_door/generated/l10n/app_localizations.dart' show AppLocalizations; 5 | 6 | class LegendPane extends StatelessWidget { 7 | final LegendController _legend; 8 | 9 | LegendPane(this._legend, {super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | final legend = List.of(_legend.legend); 14 | if (legend.isEmpty) return Container(); 15 | 16 | final loc = AppLocalizations.of(context)!; 17 | return Container( 18 | padding: EdgeInsets.all(10.0), 19 | constraints: BoxConstraints(minHeight: 150.0), 20 | child: Column( 21 | crossAxisAlignment: CrossAxisAlignment.start, 22 | children: [ 23 | for (final item in legend) 24 | Row( 25 | crossAxisAlignment: CrossAxisAlignment.start, 26 | children: [ 27 | if (item.color != null) 28 | Icon(Icons.circle, color: item.color, size: 20.0), 29 | if (item.icon != null) item.icon!.getWidget(icon: false, size: 20.0), 30 | SizedBox(width: 5.0), 31 | Expanded( 32 | child: Padding( 33 | padding: const EdgeInsets.only(bottom: 5.0), 34 | child: Text(item.isOther ? loc.legendOther : item.label, 35 | style: kFieldTextStyle), 36 | ), 37 | ), 38 | ], 39 | ) 40 | ], 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/helpers/counter.dart: -------------------------------------------------------------------------------- 1 | class Counter { 2 | final _data = {}; 3 | 4 | Counter([Iterable? initial]) { 5 | if (initial != null) addAll(initial); 6 | } 7 | 8 | void add(T item, [int? count]) { 9 | _data[item] = (_data[item] ?? 0) + (count ?? 1); 10 | } 11 | 12 | void addAll(Iterable items, [int? count]) { 13 | for (final item in items) add(item, count); 14 | } 15 | 16 | int? remove(T item) { 17 | return _data.remove(item); 18 | } 19 | 20 | int get length => _data.length; 21 | bool get isEmpty => _data.isEmpty; 22 | bool get isNotEmpty => _data.isNotEmpty; 23 | 24 | int operator [](T item) => _data[item] ?? 0; 25 | 26 | void operator []=(T item, int value) { 27 | _data[item] = value; 28 | } 29 | 30 | Iterable> mostOccurent([int? count]) { 31 | final entries = _data.entries.toList(); 32 | entries.sort((a, b) => b.value.compareTo(a.value)); 33 | final result = entries.map((e) => CounterEntry(e.key, e.value)); 34 | return count == null ? result : result.take(count); 35 | } 36 | 37 | Iterable mostOccurentItems({int? count, int? cutoff}) { 38 | return mostOccurent(count) 39 | .where((e) => cutoff == null || e.count >= cutoff) 40 | .map((e) => e.item); 41 | } 42 | 43 | @override 44 | String toString() { 45 | final data = _data.entries.map((e) => '${e.key}:${e.value}').join(';'); 46 | return 'Counter($data)'; 47 | } 48 | } 49 | 50 | class CounterEntry { 51 | final T item; 52 | final int count; 53 | 54 | const CounterEntry(this.item, this.count); 55 | 56 | @override 57 | String toString() => 'CounterEntry($item, $count)'; 58 | } 59 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/widgets/zoom_buttons.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/helpers/multi_icon.dart'; 2 | import 'package:every_door/widgets/map_button.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:every_door/generated/l10n/app_localizations.dart' show AppLocalizations; 5 | import 'package:flutter_map/flutter_map.dart'; 6 | 7 | class ZoomButtonsWidget extends StatelessWidget { 8 | final Alignment alignment; 9 | final EdgeInsets padding; 10 | 11 | const ZoomButtonsWidget({ 12 | this.alignment = Alignment.bottomRight, 13 | required this.padding, 14 | }); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | final loc = AppLocalizations.of(context)!; 19 | final controller = MapController.of(context); 20 | return Align( 21 | alignment: alignment, 22 | child: Padding( 23 | padding: padding, 24 | child: Column( 25 | mainAxisSize: MainAxisSize.min, 26 | children: [ 27 | MapButton( 28 | icon: MultiIcon(fontIcon: Icons.add), 29 | tooltip: loc.mapZoomIn, 30 | onPressed: (_) { 31 | controller.move( 32 | controller.camera.center, 33 | controller.camera.zoom + 1, 34 | ); 35 | }, 36 | ), 37 | MapButton( 38 | icon: MultiIcon(fontIcon: Icons.remove), 39 | tooltip: loc.mapZoomOut, 40 | onPressed: (_) { 41 | controller.move( 42 | controller.camera.center, 43 | controller.camera.zoom - 1, 44 | ); 45 | }, 46 | ), 47 | ], 48 | ), 49 | ), 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/helpers/log_store.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_print 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:logging/logging.dart'; 5 | 6 | final logStore = LogStore(); 7 | 8 | class LogStore { 9 | final List lines = []; 10 | 11 | bool get isEmpty => lines.isEmpty; 12 | bool get isNotEmpty => lines.isNotEmpty; 13 | 14 | void clear() { 15 | lines.clear(); 16 | } 17 | 18 | List last(int count) => 19 | lines.length <= count ? lines : lines.sublist(lines.length - count); 20 | 21 | String _formatTime(DateTime time) { 22 | final hour = time.hour.toString().padLeft(2, '0'); 23 | final minute = time.minute.toString().padLeft(2, '0'); 24 | final second = time.second.toString().padLeft(2, '0'); 25 | return '$hour:$minute:$second'; 26 | } 27 | 28 | void _addLine(String? str, [DateTime? time]) { 29 | if (str == null) return; 30 | lines.add('[${_formatTime(time ?? DateTime.now())}] $str'); 31 | } 32 | 33 | void addFromLogger(LogRecord record) { 34 | final line = 35 | '${record.level.name.substring(0, 1)}/${record.loggerName}: ${record.message}'; 36 | print(line); 37 | if (record.error != null) print(record.error); 38 | _addLine(line, record.time); 39 | _addLine(record.error?.toString()); 40 | _addLine(record.stackTrace?.toString(), record.time); 41 | } 42 | 43 | void addFromFlutter(FlutterErrorDetails details) { 44 | _addLine('Flutter: ${details.exceptionAsString()}'); 45 | _addLine(details.stack?.toString()); 46 | } 47 | 48 | void addFromZone(Object error, StackTrace stack) { 49 | print('Async error: $error'); 50 | print(stack); 51 | _addLine('Async: $error'); 52 | _addLine(stack.toString()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ios/Share Extension/Base.lproj/MainInterface.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /lib/models/filter.dart: -------------------------------------------------------------------------------- 1 | import 'amenity.dart'; 2 | import 'floor.dart'; 3 | import 'address.dart'; 4 | 5 | class PoiFilter { 6 | static const nullFloor = Floor(floor: 'null', level: 0.123456); 7 | static const nullAddress = StreetAddress(housenumber: 'null', street: 'null'); 8 | 9 | final Floor? floor; 10 | final StreetAddress? address; 11 | final bool includeNoData; // TODO: what does this even mean 12 | final bool notChecked; 13 | 14 | PoiFilter( 15 | {this.floor, 16 | this.address, 17 | this.includeNoData = true, 18 | this.notChecked = false}); 19 | 20 | PoiFilter copyWith( 21 | {Floor? floor, 22 | StreetAddress? address, 23 | bool? includeNoData, 24 | bool? notChecked}) { 25 | return PoiFilter( 26 | floor: floor == nullFloor ? null : (floor ?? this.floor), 27 | address: address == nullAddress ? null : address ?? this.address, 28 | includeNoData: includeNoData ?? this.includeNoData, 29 | notChecked: notChecked ?? this.notChecked, 30 | ); 31 | } 32 | 33 | bool get isEmpty => floor == null && address == null && !notChecked; 34 | bool get isNotEmpty => floor != null || address != null || notChecked; 35 | 36 | bool matches(OsmChange amenity) { 37 | if (notChecked && !amenity.isOld) return false; 38 | final tags = amenity.getFullTags(); 39 | bool matchesAddr = 40 | address == null || address == StreetAddress.fromTags(tags); 41 | final floors = MultiFloor.fromTags(tags); 42 | bool matchesFloor = floor == null || 43 | ((floor?.isEmpty ?? true) 44 | ? floors.isEmpty 45 | : floors.floors.contains(floor)); 46 | return matchesAddr && matchesFloor; 47 | } 48 | 49 | @override 50 | String toString() => 'PoiFilter(address: $address, floor: $floor)'; 51 | } 52 | -------------------------------------------------------------------------------- /lib/widgets/area_status.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/providers/api_status.dart'; 2 | import 'package:every_door/providers/area.dart'; 3 | import 'package:every_door/providers/uploader.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 6 | import 'package:every_door/generated/l10n/app_localizations.dart' show AppLocalizations; 7 | 8 | class AreaStatusPanel extends ConsumerWidget { 9 | const AreaStatusPanel({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context, WidgetRef ref) { 13 | final statusWatch = ref.watch(areaStatusProvider); 14 | if (statusWatch.hasError) return Container(); 15 | 16 | final areaStatus = statusWatch.valueOrNull; 17 | final apiStatus = ref.watch(apiStatusProvider); 18 | if (areaStatus == null || 19 | areaStatus == AreaStatus.fresh || 20 | apiStatus != ApiStatus.idle) return Container(); 21 | 22 | final loc = AppLocalizations.of(context)!; 23 | return GestureDetector( 24 | child: Container( 25 | padding: EdgeInsets.symmetric(vertical: 4.0), 26 | height: 50.0, 27 | color: 28 | areaStatus == AreaStatus.missing ? Colors.redAccent : Colors.yellow, 29 | child: Center( 30 | child: Text( 31 | areaStatus == AreaStatus.missing 32 | ? loc.messageNoData 33 | : loc.messageDataObsolete, 34 | textAlign: TextAlign.center, 35 | style: TextStyle( 36 | color: areaStatus == AreaStatus.missing 37 | ? Colors.white 38 | : Colors.black, 39 | ), 40 | ), 41 | ), 42 | ), 43 | onTap: () { 44 | ref.read(uploaderProvider).download(context); 45 | }, 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/fields/helpers/new_addr.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/widgets/address_form.dart'; 2 | import 'package:every_door/models/address.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 | import 'package:latlong2/latlong.dart' show LatLng; 6 | 7 | class NewAddressPane extends ConsumerStatefulWidget { 8 | final LatLng location; 9 | final StreetAddress? initialAddress; 10 | 11 | const NewAddressPane({required this.location, this.initialAddress}); 12 | 13 | @override 14 | ConsumerState createState() => _NewAddressPaneState(); 15 | } 16 | 17 | class _NewAddressPaneState extends ConsumerState { 18 | StreetAddress address = StreetAddress(); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Column( 23 | children: [ 24 | AddressForm( 25 | location: widget.location, 26 | initialAddress: widget.initialAddress, 27 | onChange: (addr) { 28 | setState(() { 29 | address = addr; 30 | }); 31 | }, 32 | ), 33 | Row( 34 | mainAxisAlignment: MainAxisAlignment.end, 35 | children: [ 36 | TextButton( 37 | child: Text(MaterialLocalizations.of(context).cancelButtonLabel), 38 | onPressed: () { 39 | Navigator.pop(context); 40 | }, 41 | ), 42 | TextButton( 43 | onPressed: address.isEmpty 44 | ? null 45 | : () { 46 | Navigator.pop(context, address); 47 | }, 48 | child: Text(MaterialLocalizations.of(context).okButtonLabel), 49 | ), 50 | ], 51 | ) 52 | ], 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/plugins/preferences.dart: -------------------------------------------------------------------------------- 1 | import 'package:eval_annotation/eval_annotation.dart'; 2 | import 'package:every_door/providers/shared_preferences.dart'; 3 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 4 | import 'package:shared_preferences/shared_preferences.dart'; 5 | 6 | /// Shadows the shared_preferences module from plugins. Nothing wrong with 7 | /// using it directly, but this allows us to track preferences by plugin. 8 | /// Basically adds a prefix to every key, and accesses the app-wide 9 | /// [SharedPreferencesWithCache] instance. 10 | @Bind() 11 | class PluginPreferences { 12 | final String _pluginId; 13 | final Ref _ref; 14 | 15 | PluginPreferences(this._pluginId, this._ref); 16 | 17 | String _key(String name) => "pp_${_pluginId}_$name"; 18 | 19 | SharedPreferencesWithCache get _sp => 20 | _ref.read(sharedPrefsProvider).requireValue; 21 | 22 | Future setString(String name, String value) async { 23 | await _sp.setString(_key(name), value); 24 | } 25 | 26 | Future setInt(String name, int value) async => 27 | await _sp.setInt(_key(name), value); 28 | 29 | Future setBool(String name, bool value) async => 30 | await _sp.setBool(_key(name), value); 31 | 32 | Future setDouble(String name, double value) async => 33 | await _sp.setDouble(_key(name), value); 34 | 35 | Future setStringList(String name, List value) async => 36 | await _sp.setStringList(_key(name), value); 37 | 38 | String? getString(String name) => _sp.getString(_key(name)); 39 | 40 | int? getInt(String name) => _sp.getInt(_key(name)); 41 | 42 | bool? getBool(String name) => _sp.getBool(_key(name)); 43 | 44 | double? getDouble(String name) => _sp.getDouble(_key(name)); 45 | 46 | List? getStringList(String name) => _sp.getStringList(_key(name)); 47 | } 48 | -------------------------------------------------------------------------------- /lib/providers/overlays.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/models/imagery.dart'; 2 | import 'package:every_door/providers/editor_mode.dart'; 3 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 4 | 5 | final overlayImageryProvider = 6 | NotifierProvider>(OverlayImagery.new); 7 | 8 | class OverlayImagery extends Notifier> { 9 | final Map _imagery = {}; 10 | final List _order = []; 11 | final Map> _modes = {}; 12 | 13 | @override 14 | List build() { 15 | ref.listen(editorModeProvider, (o, n) { 16 | _updateState(); 17 | }); 18 | return []; 19 | } 20 | 21 | void _updateState() { 22 | final mode = ref.read(editorModeProvider); 23 | final layers = _order.where((k) => _modes[k]?.contains(mode.name) ?? true); 24 | state = layers 25 | .map((k) => _imagery[k]) 26 | .whereType() 27 | .toList(); 28 | } 29 | 30 | Future addLayer(String key, Imagery imagery, 31 | {Set? modes, String? pluginId}) async { 32 | await imagery.initialize(); 33 | if (pluginId != null) { 34 | key = 'plugin_${pluginId}#$key'; 35 | } 36 | _imagery[key] = imagery; 37 | _order.add(key); 38 | if (modes != null) _modes[key] = modes; 39 | _updateState(); 40 | } 41 | 42 | void removeLayer(String key) { 43 | _imagery.remove(key); 44 | _order.remove(key); 45 | _modes.remove(key); 46 | _updateState(); 47 | } 48 | 49 | void removeLayers(String prefix) { 50 | _imagery.removeWhere((k, _) => k.startsWith(prefix)); 51 | _order.removeWhere((k) => k.startsWith(prefix)); 52 | _modes.removeWhere((k, _) => k.startsWith(prefix)); 53 | _updateState(); 54 | } 55 | 56 | void removePluginLayers(String pluginId) { 57 | removeLayers('plugin_$pluginId#'); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/screens/modes/definitions/notes.dart: -------------------------------------------------------------------------------- 1 | import 'package:eval_annotation/eval_annotation.dart'; 2 | import 'package:every_door/helpers/multi_icon.dart'; 3 | import 'package:every_door/models/note.dart'; 4 | import 'package:every_door/models/plugin.dart'; 5 | import 'package:every_door/plugins/interface.dart'; 6 | import 'package:every_door/providers/notes.dart'; 7 | import 'package:every_door/screens/modes/definitions/base.dart'; 8 | import 'package:flutter/material.dart'; 9 | import 'package:every_door/generated/l10n/app_localizations.dart' 10 | show AppLocalizations; 11 | import 'package:flutter_map/flutter_map.dart'; 12 | 13 | @Bind(bridge: true, implicitSupers: true) 14 | abstract class NotesModeDefinition extends BaseModeDefinition { 15 | List notes = []; 16 | 17 | NotesModeDefinition(super.ref); 18 | 19 | NotesModeDefinition.fromPlugin(EveryDoorApp app): this(app.ref); 20 | 21 | @override 22 | MultiIcon getIcon(BuildContext context, bool outlined) { 23 | final loc = AppLocalizations.of(context)!; 24 | return MultiIcon( 25 | fontIcon: !outlined ? Icons.note_alt : Icons.note_alt_outlined, 26 | tooltip: loc.navNotesMode, 27 | ); 28 | } 29 | 30 | @override 31 | Future updateNearest(LatLngBounds bounds) async { 32 | final notes = 33 | await ref.read(notesProvider.notifier).fetchAllNotes(bounds: bounds); 34 | this.notes = notes.where((n) => !n.deleting).toList(); 35 | notifyListeners(); 36 | } 37 | 38 | @override 39 | void updateFromJson(Map data, Plugin plugin) { 40 | if (data.containsKey('locked')) { 41 | ref.read(drawingLockedProvider.notifier).state = data['locked']!; 42 | } 43 | } 44 | } 45 | 46 | class DefaultNotesModeDefinition extends NotesModeDefinition { 47 | DefaultNotesModeDefinition(super.ref); 48 | 49 | @override 50 | String get name => "notes"; 51 | } 52 | -------------------------------------------------------------------------------- /tools/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e -u -o pipefail 3 | [ $# -lt 1 ] && echo "Usage: $0 []" && exit 1 4 | 5 | HERE="$(dirname "$0")" 6 | ASSETS="$HERE/../assets" 7 | PRESETS_DB="$ASSETS/presets.db" 8 | PRESETS_ZIP="$ASSETS/presets.gz" 9 | NSI_FEATURES="$HERE/../lib/helpers/nsi_features.dart" 10 | 11 | TAGINFO_DB="$1" 12 | [ ! -e "$TAGINFO_DB/taginfo-db.db" ] && echo "Could not open $TAGINFO_DB/taginfo-db.db" && exit 2 13 | 14 | GIT_PATH="${2-}" 15 | if [ -n "$GIT_PATH" ]; then 16 | [ ! -d "$GIT_PATH/id-tagging-schema" ] && echo "Could not find $GIT_PATH/id-tagging-schema" && exit 2 17 | [ ! -d "$GIT_PATH/name-suggestion-index" ] && echo "Could not find $GIT_PATH/name-suggestion-index" && exit 2 18 | [ ! -d "$GIT_PATH/editor-layer-index" ] && echo "Could not find $GIT_PATH/editor-layer-index" && exit 2 19 | fi 20 | 21 | if [ ! -d "$HERE/venv" ]; then 22 | echo 'Building Python environment' 23 | python3 -m venv "$HERE/venv" 24 | "$HERE/venv/bin/pip" install -r "$HERE/requirements.txt" 25 | fi 26 | PYTHON="$HERE/venv/bin/python" 27 | 28 | mkdir -p "$ASSETS" 29 | rm -f "$PRESETS_DB" "$PRESETS_ZIP" 30 | echo 'Processing presets and NSI' 31 | "$PYTHON" "$HERE/json_to_sqlite.py" "$PRESETS_DB" "$GIT_PATH" 32 | echo 'Processing taginfo database' 33 | "$PYTHON" "$HERE/add_taginfo.py" "$PRESETS_DB" "$TAGINFO_DB" 34 | echo 'Processing imagery index' 35 | "$PYTHON" "$HERE/add_imagery.py" "$PRESETS_DB" "$GIT_PATH" 36 | 37 | echo 'Preparing NSI features' 38 | if [ -n "$GIT_PATH" ]; then 39 | cp "$GIT_PATH/name-suggestion-index/dist/featureCollection.min.json" nsi_fc.json 40 | else 41 | curl -s 'https://cdn.jsdelivr.net/npm/name-suggestion-index@latest/dist/json/featureCollection.min.json' > nsi_fc.json 42 | fi 43 | echo "const String nsiFeaturesRaw = '''" > "$NSI_FEATURES" 44 | cat nsi_fc.json >> "$NSI_FEATURES" 45 | echo "''';" >> "$NSI_FEATURES" 46 | rm nsi_fc.json 47 | -------------------------------------------------------------------------------- /lib/models/payment_local.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/constants.dart'; 2 | import 'package:latlong2/latlong.dart'; 3 | import 'package:proximity_hash/geohash.dart'; 4 | 5 | class LocalPayment { 6 | static const kGeohashPrecision = 5; // 2.4 km 7 | 8 | final int id; 9 | final LatLng center; 10 | final Set options; 11 | 12 | LocalPayment({ 13 | required this.id, 14 | required this.center, 15 | required this.options, 16 | }) { 17 | if (options.isEmpty) 18 | throw Exception('Cannot instantiate LocalPayment with empty options.'); 19 | } 20 | 21 | LocalPayment update(Set newOptions) => 22 | LocalPayment(id: id, center: center, options: newOptions); 23 | 24 | @override 25 | bool operator ==(Object other) => other is LocalPayment && other.id == id; 26 | 27 | @override 28 | int get hashCode => id.hashCode; 29 | 30 | @override 31 | String toString() => 'LocalPayment($center, "${options.join(",")}")'; 32 | 33 | static const kTableName = 'payment'; 34 | static const kTableFields = [ 35 | 'id integer', 36 | 'lat integer', 37 | 'lon integer', 38 | 'geohash text', 39 | 'options text', 40 | ]; 41 | 42 | Map toJson() { 43 | return { 44 | 'id': id, 45 | 'lat': (center.latitude * kCoordinatePrecision).round(), 46 | 'lon': (center.longitude * kCoordinatePrecision).round(), 47 | 'geohash': GeoHasher().encode(center.longitude, center.latitude, 48 | precision: kGeohashPrecision), 49 | 'options': options.join(';'), 50 | }; 51 | } 52 | 53 | factory LocalPayment.fromJson(Map data) { 54 | return LocalPayment( 55 | id: data['id'], 56 | center: LatLng( 57 | data['lat'] / kCoordinatePrecision, 58 | data['lon'] / kCoordinatePrecision, 59 | ), 60 | options: data['options'].split(';').toSet(), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /assets/lets-encrypt-r3.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw 3 | TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh 4 | cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw 5 | WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg 6 | RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 7 | AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP 8 | R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx 9 | sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm 10 | NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg 11 | Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG 12 | /kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC 13 | AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB 14 | Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA 15 | FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw 16 | AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw 17 | Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB 18 | gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W 19 | PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl 20 | ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz 21 | CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm 22 | lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 23 | avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 24 | yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O 25 | yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids 26 | hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ 27 | HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv 28 | MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX 29 | nLRbwHOoq7hHwg== 30 | -----END CERTIFICATE----- 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Every Door 2 | 3 | The best mobile editor for adding shops and amenities to OpenStreetMap. 4 | 5 | Help test it for [iOS](https://apps.apple.com/app/every-door/id1621945342) and 6 | Android ([F-Droid](https://f-droid.org/packages/info.zverev.ilya.every_door/), [Google Play](https://play.google.com/store/apps/details?id=info.zverev.ilya.every_door), [GitHub](https://github.com/Zverik/every_door/releases/latest), [Huawei AppGallery](https://appgallery.cloud.huawei.com/app/C109364057)). 7 | 8 | Please read the [Contributor's Guide](https://every-door.app/develop/) to learn how 9 | to report bugs, translate the app, and submit improvements. 10 | 11 | The roadmap is in [this project](https://github.com/users/Zverik/projects/1/views/2). 12 | 13 | Amenity mode Editing a library Micromapping mode 14 | 15 | [More screenshots](https://wiki.openstreetmap.org/wiki/Every_Door) 16 | 17 | ## Author, License, and Sponsors 18 | 19 | The editor was written by Ilya Zverev © 2022-2025 and published under the ISC license. 20 | 21 | The author is sponsored by many individual contributors through [GitHub](https://github.com/sponsors/Zverik) 22 | and [Liberapay](https://liberapay.com/zverik). Thank you everybody! 23 | 24 | The NLNet Foundation is [sponsoring](https://nlnet.nl/project/EveryDoor/) the development in 2025 25 | through the [NGI Commons Fund](https://nlnet.nl/commonsfund) with funds from the European Commission. 26 | 27 | Want to sponsor the development? [Contact Ilya](mailto:ilya@zverev.info) directly or through 28 | [his company](https://avatudkaart.ee/). 29 | -------------------------------------------------------------------------------- /lib/models/imagery/mbtiles.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/models/imagery/tiles.dart'; 2 | import 'package:every_door/providers/cur_imagery.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | import 'package:flutter_map/flutter_map.dart' show TileLayer; 5 | import 'package:flutter_map_mbtiles/flutter_map_mbtiles.dart'; 6 | import 'package:mbtiles/mbtiles.dart'; 7 | 8 | class MbTilesImagery extends TileImagery { 9 | final MbTiles mbtiles; 10 | 11 | const MbTilesImagery({ 12 | required super.id, 13 | super.category, 14 | super.name, 15 | super.icon, 16 | super.attribution, 17 | required super.url, 18 | super.minZoom, 19 | super.maxZoom, 20 | super.overlay = false, 21 | super.best = false, 22 | super.tileSize = 256, 23 | super.opacity = 1.0, 24 | required this.mbtiles, 25 | }); 26 | 27 | MbTilesImagery.from(TileImageryData data, {required MbTiles mbtiles}) 28 | : this( 29 | id: data.id, 30 | category: data.category, 31 | name: data.name, 32 | icon: data.icon, 33 | attribution: data.attribution, 34 | overlay: data.overlay, 35 | best: data.best, 36 | url: data.url, 37 | minZoom: data.minZoom, 38 | maxZoom: data.maxZoom, 39 | tileSize: data.tileSize, 40 | opacity: data.opacity, 41 | mbtiles: mbtiles, 42 | ); 43 | 44 | @override 45 | Widget buildLayer({bool reset = false}) { 46 | final layer = TileLayer( 47 | urlTemplate: url, 48 | tileProvider: MbTilesTileProvider( 49 | mbtiles: mbtiles, 50 | silenceTileNotFound: false, 51 | ), 52 | minNativeZoom: minZoom, 53 | maxNativeZoom: maxZoom, 54 | maxZoom: 22, 55 | tileDimension: tileSize, 56 | userAgentPackageName: kUserAgentPackageName, 57 | reset: reset ? tileResetController.stream : null, 58 | ); 59 | return isOpaque ? layer : Opacity(opacity: opacity, child: layer); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/helpers/tags/poi_warnings.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/constants.dart'; 2 | import 'package:every_door/helpers/tags/element_kind.dart'; 3 | import 'package:every_door/models/amenity.dart'; 4 | import 'package:every_door/generated/l10n/app_localizations.dart' show AppLocalizations; 5 | 6 | const _kTagsWithoutYesValue = { 7 | 'amenity', 8 | 'shop', 9 | 'craft', 10 | 'tourism', 11 | 'historic', 12 | 'club', 13 | 'highway', 14 | 'railway', 15 | 'office', 16 | 'healthcare', 17 | 'leisure', 18 | 'natural', 19 | 'emergency', 20 | 'waterway', 21 | 'man_made', 22 | 'power', 23 | 'aeroway', 24 | 'aerialway', 25 | 'marker', 26 | 'public_transport', 27 | 'traffic_sign', 28 | 'hazard', 29 | 'telecom', 30 | 'landuse', 31 | 'military', 32 | 'boundary', 33 | 'advertising', 34 | 'playground', 35 | 'traffic_calming', 36 | }; 37 | 38 | String? getWarningForAmenity(OsmChange amenity, AppLocalizations loc) { 39 | if (amenity.isFixmeNote()) { 40 | return loc.warningFixmeNote; 41 | } 42 | 43 | String? fixmeValue = amenity['fixme']; 44 | if (fixmeValue != null) { 45 | if (fixmeValue.length > 50) { 46 | fixmeValue = fixmeValue.substring(0, 50) + '…'; 47 | } 48 | return loc.warningFixme(fixmeValue); 49 | } 50 | 51 | final mainKey = amenity.mainKey; 52 | if (mainKey != null && 53 | _kTagsWithoutYesValue.contains(mainKey) && 54 | amenity[mainKey] == 'yes') { 55 | return loc.warningWrongTag('$mainKey=${amenity[mainKey]}'); 56 | } 57 | 58 | final int ageInDays = DateTime.now() 59 | .difference(amenity.element?.timestamp ?? DateTime.now()) 60 | .inDays; 61 | if (ElementKind.amenity.matchesChange(amenity) && ageInDays >= kOldAmenityWarning && amenity.isOld) { 62 | return loc.warningTooOld(loc.years((ageInDays / 365).round())); 63 | } 64 | 65 | if (!ElementKind.everything.matchesChange(amenity)) { 66 | return loc.warningUnsupported; 67 | } 68 | 69 | return null; 70 | } 71 | -------------------------------------------------------------------------------- /tools/common_hours.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sqlite3 3 | import sys 4 | import re 5 | from collections import Counter 6 | 7 | 8 | RE_START = re.compile(r'(?:^|Mo|Tu|We|Th|Fr|Sa|Su|;)\s*(\d?\d:\d\d)-') 9 | RE_END = re.compile(r'-(\d?\d:\d\d)(?:$|;)') 10 | RE_BREAK = re.compile(r'-(\d?\d:\d\d),\s*(\d?\d:\d\d)-') 11 | 12 | 13 | if __name__ == '__main__': 14 | if len(sys.argv) < 2: 15 | print('Find the most common opening_hours parts.') 16 | print('Usage: {} '.format(sys.argv[0])) 17 | sys.exit(1) 18 | 19 | conn = sqlite3.connect(sys.argv[1]) 20 | cur = conn.cursor() 21 | cur.execute("select value, count_all from tags where key = 'opening_hours' and count_all >= 5") 22 | 23 | starts = Counter() 24 | ends = Counter() 25 | breaks = Counter() 26 | break_starts = Counter() 27 | break_ends = Counter() 28 | for row in cur: 29 | for start in RE_START.finditer(row[0]): 30 | starts[start.group(1).zfill(5)] += row[1] 31 | for end in RE_END.finditer(row[0]): 32 | ends[end.group(1).zfill(5)] += row[1] 33 | for _break in RE_BREAK.finditer(row[0]): 34 | breaks[_break.group(1).zfill(5) + '-' + _break.group(2).zfill(5)] += row[1] 35 | break_starts[_break.group(1).zfill(5)] += row[1] 36 | break_ends[_break.group(2).zfill(5)] += row[1] 37 | 38 | print('Starts:') 39 | for v in starts.most_common(14): 40 | print(f' {v[0]} {v[1]}') 41 | print('') 42 | print('Ends:') 43 | for v in ends.most_common(14): 44 | print(f' {v[0]} {v[1]}') 45 | print('') 46 | print('Breaks:') 47 | for v in breaks.most_common(6): 48 | print(f' {v[0]} {v[1]}') 49 | print('') 50 | print('Break starts:') 51 | for v in break_starts.most_common(6): 52 | print(f' {v[0]} {v[1]}') 53 | print('') 54 | print('Break ends:') 55 | for v in break_ends.most_common(6): 56 | print(f' {v[0]} {v[1]}') 57 | -------------------------------------------------------------------------------- /lib/screens/modes/definitions/classic.dart: -------------------------------------------------------------------------------- 1 | import 'package:eval_annotation/eval_annotation.dart'; 2 | import 'package:every_door/helpers/legend.dart'; 3 | import 'package:every_door/plugins/interface.dart'; 4 | import 'package:every_door/models/amenity.dart'; 5 | import 'package:every_door/models/plugin.dart'; 6 | import 'package:every_door/screens/editor.dart'; 7 | import 'package:every_door/screens/editor/types.dart'; 8 | import 'package:every_door/screens/modes/definitions/base.dart'; 9 | import 'package:every_door/widgets/poi_marker.dart'; 10 | import 'package:flutter/material.dart'; 11 | import 'package:flutter_map/flutter_map.dart'; 12 | import 'package:latlong2/latlong.dart' show LatLng; 13 | 14 | @Bind(bridge: true, implicitSupers: true) 15 | abstract class ClassicModeDefinition extends BaseModeDefinition { 16 | List nearestPOI = []; 17 | 18 | ClassicModeDefinition(super.ref); 19 | 20 | ClassicModeDefinition.fromPlugin(EveryDoorApp app): this(app.ref); 21 | 22 | @override 23 | void updateFromJson(Map data, Plugin plugin) {} 24 | 25 | @override 26 | updateNearest(LatLngBounds bounds) async { 27 | nearestPOI = await super.getNearestChanges(bounds); 28 | notifyListeners(); 29 | } 30 | 31 | void openEditor({ 32 | required BuildContext context, 33 | OsmChange? element, 34 | LatLng? location, 35 | }) async { 36 | if (element == null) { 37 | Navigator.push( 38 | context, 39 | MaterialPageRoute( 40 | builder: (context) => TypeChooserPage(location: location), 41 | fullscreenDialog: true, 42 | ), 43 | ); 44 | } else { 45 | Navigator.push( 46 | context, 47 | MaterialPageRoute( 48 | builder: (_) => PoiEditorPage(amenity: element), 49 | fullscreenDialog: true, 50 | ), 51 | ); 52 | } 53 | } 54 | 55 | Widget buildMarker(OsmChange element) { 56 | return ColoredMarker( 57 | color: kLegendOtherColor, 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | formatter: 13 | # This is until we get Dart 3.8 as a baseline. 14 | trailing_commas: preserve 15 | 16 | linter: 17 | # The lint rules applied to this project can be customized in the 18 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 19 | # included above or to enable additional rules. A list of all available lints 20 | # and their documentation is published at 21 | # https://dart-lang.github.io/linter/lints/index.html. 22 | # 23 | # Instead of disabling a lint rule for the entire project in the 24 | # section below, it can also be suppressed for a single line of code 25 | # or a specific dart file by using the `// ignore: name_of_lint` and 26 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 27 | # producing the lint. 28 | rules: 29 | curly_braces_in_flow_control_structures: false 30 | prefer_const_constructors: false 31 | prefer_const_constructors_in_immutables: false 32 | use_key_in_widget_constructors: false 33 | sort_child_properties_last: false 34 | prefer_interpolation_to_compose_strings: false 35 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 36 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 37 | 38 | # Additional information about this file can be found at 39 | # https://dart.dev/guides/language/analysis-options 40 | 41 | analyzer: 42 | exclude: 43 | - vendor/** 44 | -------------------------------------------------------------------------------- /lib/fields/checkbox.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/fields/combo.dart'; 2 | import 'package:every_door/widgets/radio_field.dart'; 3 | import 'package:every_door/models/amenity.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:every_door/models/field.dart'; 6 | import 'package:every_door/generated/l10n/app_localizations.dart' show AppLocalizations; 7 | 8 | class CheckboxPresetField extends PresetField { 9 | final bool tristate; 10 | List? options; 11 | 12 | CheckboxPresetField({ 13 | required super.key, 14 | required super.label, 15 | super.icon, 16 | super.prerequisite, 17 | required this.tristate, 18 | this.options, 19 | }); 20 | 21 | @override 22 | Widget buildWidget(OsmChange element) => CheckboxInputField(this, element); 23 | } 24 | 25 | class CheckboxInputField extends StatefulWidget { 26 | final CheckboxPresetField field; 27 | final OsmChange element; 28 | 29 | const CheckboxInputField(this.field, this.element); 30 | 31 | @override 32 | State createState() => _CheckboxInputFieldState(); 33 | } 34 | 35 | class _CheckboxInputFieldState extends State { 36 | @override 37 | Widget build(BuildContext context) { 38 | const falseValues = {'no', 'false', '0', 'off'}; 39 | final loc = AppLocalizations.of(context)!; 40 | final vYes = widget.field.options?.length == 2 41 | ? (widget.field.options![1].label ?? loc.fieldCheckboxYes) 42 | : loc.fieldCheckboxYes; 43 | final vNo = loc.fieldCheckboxNo; 44 | 45 | final keyValue = widget.element[widget.field.key]; 46 | String? value = falseValues.contains(keyValue) 47 | ? 'no' 48 | : keyValue; 49 | String yesValue = widget.field.options?.length == 2 50 | ? widget.field.options![1].value 51 | : 'yes'; 52 | 53 | return RadioField( 54 | options: widget.field.tristate ? [yesValue, 'no'] : [yesValue], 55 | labels: [vYes, vNo], 56 | value: value, 57 | onChange: (newValue) { 58 | widget.element[widget.field.key] = newValue; 59 | }, 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/models/imagery/vector.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/constants.dart'; 2 | import 'package:every_door/helpers/tile_caches.dart'; 3 | import 'package:every_door/models/imagery.dart'; 4 | import 'package:every_door/models/imagery/vector/style_reader.dart'; 5 | import 'package:every_door/models/plugin.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:logging/logging.dart'; 8 | import 'package:vector_map_tiles/vector_map_tiles.dart'; 9 | 10 | class VectorImagery extends Imagery { 11 | static final _logger = Logger('VectorImagery'); 12 | Style? style; 13 | final bool fast; 14 | 15 | // We need those to initialize the layer. 16 | final String? url; 17 | final String? apiKey; 18 | final Plugin? plugin; 19 | final Map? headers; 20 | 21 | VectorImagery({ 22 | required super.id, 23 | this.style, 24 | this.fast = true, 25 | this.url, 26 | this.apiKey, 27 | this.plugin, 28 | this.headers, 29 | super.category, 30 | super.name, 31 | super.icon, 32 | super.attribution, 33 | super.overlay = false, 34 | super.best = false, 35 | String cachingStore = kTileCacheImagery, 36 | }); 37 | 38 | @override 39 | Future initialize() async { 40 | if (style == null && url != null) { 41 | style = await EdStyleReader( 42 | url: url!, 43 | apiKey: apiKey, 44 | plugin: plugin, 45 | httpHeaders: headers, 46 | ).read(); 47 | } 48 | } 49 | 50 | @override 51 | Widget buildLayer({bool reset = false}) { 52 | final style = this.style; 53 | if (style == null) { 54 | _logger.warning('Non-initialized vector layer: $id'); 55 | return Container(); 56 | } 57 | 58 | return VectorTileLayer( 59 | theme: style.theme, 60 | tileProviders: style.providers, 61 | sprites: style.sprites, 62 | maximumZoom: 22.0, 63 | fileCacheMaximumSizeInBytes: kVectorCacheSizeMB * 1024 * 1024, 64 | // Vector looks cooler, but super slow on far zooms. 65 | layerMode: fast ? VectorTileLayerMode.raster : VectorTileLayerMode.vector, 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/helpers/geometry/tile_range.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' show Point; 2 | 3 | import 'package:every_door/helpers/tile_calculator.dart'; 4 | import 'package:flutter_map/flutter_map.dart' 5 | show TileCoordinates, LatLngBounds; 6 | 7 | class DiscreteTileRange { 8 | /// Bounds are inclusive 9 | final Point min; 10 | final Point max; 11 | final int zoom; 12 | 13 | const DiscreteTileRange._(this.zoom, this.min, this.max); 14 | 15 | factory DiscreteTileRange(int zoom, Point a, Point b) { 16 | final int minX; 17 | final int maxX; 18 | if (a.x > b.x) { 19 | minX = b.x; 20 | maxX = a.x; 21 | } else { 22 | minX = a.x; 23 | maxX = b.x; 24 | } 25 | final int minY; 26 | final int maxY; 27 | if (a.y > b.y) { 28 | minY = b.y; 29 | maxY = a.y; 30 | } else { 31 | minY = a.y; 32 | maxY = b.y; 33 | } 34 | return DiscreteTileRange._( 35 | zoom, Point(minX, minY), Point(maxX, maxY)); 36 | } 37 | 38 | factory DiscreteTileRange.fromBounds(int zoom, LatLngBounds bounds) { 39 | final calc = TileCalculator(zoom); 40 | final c1 = calc.locationToTile(bounds.northWest); 41 | final c2 = calc.locationToTile(bounds.southEast); 42 | return DiscreteTileRange(zoom, c1, c2); 43 | } 44 | 45 | int get width => max.x - min.x + 1; 46 | int get height => max.y - min.y + 1; 47 | int get count => width * height; 48 | 49 | LatLngBounds toBounds() { 50 | final calc = TileCalculator(zoom); 51 | return LatLngBounds( 52 | calc.tileOrigin(min), 53 | calc.tileOrigin(max + Point(1, 1)), 54 | ); 55 | } 56 | 57 | Iterable get coordinates sync* { 58 | for (var j = min.y; j <= max.y; j++) { 59 | for (var i = min.x; i <= max.x; i++) { 60 | yield TileCoordinates(i, j, zoom); 61 | } 62 | } 63 | } 64 | 65 | Iterable get tiles sync* { 66 | for (var j = min.y; j <= max.y; j++) { 67 | for (var i = min.x; i <= max.x; i++) { 68 | yield Tile(i, j, zoom); 69 | } 70 | } 71 | } 72 | 73 | @override 74 | String toString() => 'DiscreteTileRange($min, $max)'; 75 | } 76 | -------------------------------------------------------------------------------- /lib/providers/auth.dart: -------------------------------------------------------------------------------- 1 | import 'package:every_door/helpers/auth/controller.dart'; 2 | import 'package:every_door/helpers/auth/osm.dart'; 3 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 4 | 5 | final authProvider = 6 | NotifierProvider>( 7 | AuthMapController.new); 8 | 9 | class AuthMapController extends Notifier> { 10 | @override 11 | Map build() { 12 | final osm = AuthController( 13 | 'osm', 14 | OsmAuthProvider( 15 | clientId: 'r_ZDi6JezDDBHj8WSU286d5A7FntAJSMpkB2FGEcaG8', 16 | clientSecret: 'DRFc8pDeGt4D2E3j-WdfdTq02o_fnek-WQeWgvXfvTg', 17 | endpoint: 'api.openstreetmap.org', 18 | authEndpoint: 'www.openstreetmap.org', 19 | )); 20 | osm.addListener(onValueChanged); 21 | return {'osm': osm}; 22 | } 23 | 24 | OsmUserDetails? get osmUser => state['osm']?.value as OsmUserDetails?; 25 | 26 | void update(AuthController controller) { 27 | if (controller.name == 'osm') { 28 | // TODO: clear everything 29 | throw ArgumentError("Cannot replace the OSM auth provider for now"); 30 | } 31 | 32 | final old = state[controller.name]; 33 | if (old != null) { 34 | old.removeListener(onValueChanged); 35 | } 36 | controller.addListener(onValueChanged); 37 | final newState = Map.of(state); 38 | newState[controller.name] = controller; 39 | state = newState; 40 | } 41 | 42 | void remove(String name) { 43 | if (!state.containsKey(name)) return; 44 | final newState = Map.of(state); 45 | final old = newState.remove(name); 46 | old?.removeListener(onValueChanged); 47 | state = newState; 48 | } 49 | 50 | void removePrefixed(String prefix) { 51 | final newState = Map.of(state); 52 | newState.forEach((k, v) { 53 | if (k.startsWith(prefix)) v.removeListener(onValueChanged); 54 | }); 55 | newState.removeWhere((k, v) => k.startsWith(prefix)); 56 | if (newState.length == state.length) return; 57 | state = newState; 58 | } 59 | 60 | void onValueChanged() { 61 | // Trigger the notify, given the comparison function is [identical]. 62 | state = Map.of(state); 63 | } 64 | } 65 | --------------------------------------------------------------------------------