├── .fvmrc
├── .github
└── workflows
│ └── build-android.yml
├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
├── analysis_options.yaml
├── documentation
├── app.gif
└── scan.png
├── melos.yaml
├── packages
├── app
│ ├── .gitignore
│ ├── .metadata
│ ├── android
│ │ ├── .gitignore
│ │ ├── app
│ │ │ ├── build.gradle
│ │ │ └── src
│ │ │ │ ├── debug
│ │ │ │ └── AndroidManifest.xml
│ │ │ │ ├── main
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ ├── ic_launcher-playstore.png
│ │ │ │ ├── kotlin
│ │ │ │ │ └── com
│ │ │ │ │ │ └── p2panda
│ │ │ │ │ │ └── app
│ │ │ │ │ │ └── MainActivity.kt
│ │ │ │ └── res
│ │ │ │ │ ├── drawable-v21
│ │ │ │ │ ├── background.png
│ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── drawable
│ │ │ │ │ ├── background.png
│ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ ├── ic_launcher_foreground.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ ├── ic_launcher_foreground.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ ├── ic_launcher_foreground.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ ├── ic_launcher_foreground.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ ├── ic_launcher_foreground.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ │ ├── values-night-v31
│ │ │ │ │ └── styles.xml
│ │ │ │ │ ├── values-night
│ │ │ │ │ └── styles.xml
│ │ │ │ │ ├── values-v31
│ │ │ │ │ └── styles.xml
│ │ │ │ │ └── values
│ │ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ └── profile
│ │ │ │ └── AndroidManifest.xml
│ │ ├── build.gradle
│ │ ├── gradle.properties
│ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ └── gradle-wrapper.properties
│ │ └── settings.gradle
│ ├── assets
│ │ ├── fonts
│ │ │ └── Staatliches-Regular.ttf
│ │ ├── images
│ │ │ ├── meliponini.png
│ │ │ ├── meliponini.svg
│ │ │ └── placeholder-bee.png
│ │ ├── schema.lock
│ │ └── seed.lock
│ ├── l10n.yaml
│ ├── lib
│ │ ├── app.dart
│ │ ├── io
│ │ │ ├── assets.dart
│ │ │ ├── files.dart
│ │ │ ├── geolocation.dart
│ │ │ ├── graphql
│ │ │ │ ├── graphql.dart
│ │ │ │ └── queries.dart
│ │ │ ├── images.dart
│ │ │ └── p2panda
│ │ │ │ ├── documents.dart
│ │ │ │ ├── key_pair.dart
│ │ │ │ ├── node.dart
│ │ │ │ ├── p2panda.dart
│ │ │ │ ├── publish.dart
│ │ │ │ ├── schemas.dart
│ │ │ │ └── seed.dart
│ │ ├── locales
│ │ │ ├── app_en.arb
│ │ │ └── app_pt.arb
│ │ ├── main.dart
│ │ ├── models
│ │ │ ├── base.dart
│ │ │ ├── blobs.dart
│ │ │ ├── hive_location.dart
│ │ │ ├── local_names.dart
│ │ │ ├── schema_ids.dart
│ │ │ ├── sightings.dart
│ │ │ ├── species.dart
│ │ │ ├── taxonomy_species.dart
│ │ │ └── used_for.dart
│ │ ├── router.dart
│ │ ├── ui
│ │ │ ├── colors.dart
│ │ │ ├── screens
│ │ │ │ ├── all_sightings.dart
│ │ │ │ ├── all_species.dart
│ │ │ │ ├── create_sighting.dart
│ │ │ │ ├── settings.dart
│ │ │ │ ├── sighting.dart
│ │ │ │ ├── species.dart
│ │ │ │ └── splash.dart
│ │ │ └── widgets
│ │ │ │ ├── action_buttons.dart
│ │ │ │ ├── alert_dialog.dart
│ │ │ │ ├── autocomplete.dart
│ │ │ │ ├── button.dart
│ │ │ │ ├── card.dart
│ │ │ │ ├── card_action_button.dart
│ │ │ │ ├── card_header.dart
│ │ │ │ ├── confirm_dialog.dart
│ │ │ │ ├── counter.dart
│ │ │ │ ├── editable_card.dart
│ │ │ │ ├── error_card.dart
│ │ │ │ ├── expandable_card.dart
│ │ │ │ ├── expandable_fab.dart
│ │ │ │ ├── expansion_tile.dart
│ │ │ │ ├── fab.dart
│ │ │ │ ├── hive_location_field.dart
│ │ │ │ ├── hive_locations_aggregate.dart
│ │ │ │ ├── icon_message_card.dart
│ │ │ │ ├── image.dart
│ │ │ │ ├── image_carousel.dart
│ │ │ │ ├── image_provider.dart
│ │ │ │ ├── info_card.dart
│ │ │ │ ├── loading_overlay.dart
│ │ │ │ ├── local_name_autocomplete.dart
│ │ │ │ ├── local_name_field.dart
│ │ │ │ ├── local_names_dedup_tag_list.dart
│ │ │ │ ├── location_tracker.dart
│ │ │ │ ├── pagination_list.dart
│ │ │ │ ├── read_only_value.dart
│ │ │ │ ├── refresh_provider.dart
│ │ │ │ ├── scaffold.dart
│ │ │ │ ├── sighting_card.dart
│ │ │ │ ├── sighting_popup_menu.dart
│ │ │ │ ├── sightings_list.dart
│ │ │ │ ├── sightings_tiles.dart
│ │ │ │ ├── simple_card.dart
│ │ │ │ ├── species_card.dart
│ │ │ │ ├── species_field.dart
│ │ │ │ ├── species_local_names_aggregate.dart
│ │ │ │ ├── species_popup_menu.dart
│ │ │ │ ├── species_uses_aggregate.dart
│ │ │ │ ├── tag_item.dart
│ │ │ │ ├── taxonomy_autocomplete.dart
│ │ │ │ ├── text_field.dart
│ │ │ │ ├── used_for_dedup_tag_list.dart
│ │ │ │ ├── used_for_field.dart
│ │ │ │ ├── used_for_list.dart
│ │ │ │ ├── used_for_tag_selector.dart
│ │ │ │ └── used_for_text_field.dart
│ │ └── utils
│ │ │ ├── debouncable.dart
│ │ │ └── sleep.dart
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ └── pubspec_overrides.yaml
├── p2panda
│ ├── .gitignore
│ ├── analysis_options.yaml
│ ├── lib
│ │ ├── p2panda.dart
│ │ └── src
│ │ │ ├── bridge_generated.dart
│ │ │ ├── bridge_generated.freezed.dart
│ │ │ ├── ffi.dart
│ │ │ └── ffi
│ │ │ ├── io.dart
│ │ │ ├── stub.dart
│ │ │ └── web.dart
│ ├── native
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ └── src
│ │ │ ├── api.rs
│ │ │ ├── bridge_generated.rs
│ │ │ ├── lib.rs
│ │ │ ├── node.rs
│ │ │ └── operation.rs
│ └── pubspec.yaml
└── p2panda_flutter
│ ├── .gitignore
│ ├── .metadata
│ ├── android
│ ├── .gitignore
│ ├── TLS_VERIFY
│ ├── build.gradle
│ ├── settings.gradle
│ └── src
│ │ └── main
│ │ └── AndroidManifest.xml
│ ├── lib
│ ├── p2panda_flutter.dart
│ └── src
│ │ ├── ffi.dart
│ │ └── ffi
│ │ ├── io.dart
│ │ ├── stub.dart
│ │ └── web.dart
│ ├── pubspec.yaml
│ └── pubspec_overrides.yaml
├── pubspec.lock
├── pubspec.yaml
├── schemas
├── .gitignore
├── schema.lock
├── schema.toml
└── seed.lock
└── scripts
├── build.sh
├── clear.sh
└── release.sh
/.fvmrc:
--------------------------------------------------------------------------------
1 | {
2 | "flutter": "3.22.0"
3 | }
4 |
--------------------------------------------------------------------------------
/.github/workflows/build-android.yml:
--------------------------------------------------------------------------------
1 | name: Build Android APK
2 |
3 | on:
4 | push:
5 | tags:
6 | - v[0-9]+.[0-9]+.[0-9]+
7 |
8 | workflow_dispatch:
9 | inputs:
10 | flavor:
11 | type: choice
12 | description: "APK build flavor"
13 | required: true
14 | options:
15 | - normal
16 | - qa
17 | default: qa
18 |
19 | jobs:
20 | build-apk:
21 | runs-on: ubuntu-latest
22 | steps:
23 | - uses: actions/checkout@v4
24 | - uses: moonrepo/setup-rust@v1
25 | with:
26 | channel: "1.75"
27 | components: rustfmt
28 | - uses: actions/setup-java@v4
29 | with:
30 | distribution: "temurin" # AdoptOpenJDK is now Eclipse Temurin
31 | java-version: "17"
32 | - uses: kuhnroyal/flutter-fvm-config-action@v2
33 | id: fvm-config-action
34 | - name: Using Flutter ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }}
35 | uses: subosito/flutter-action@v2
36 | with:
37 | flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }}
38 | - uses: bluefireteam/melos-action@v3
39 | - name: Install Dart dependencies
40 | run: dart pub get
41 | - name: Generate FFI bindings and build native Android libraries
42 | run: melos build
43 | - name: Build APK
44 | working-directory: ./packages/app
45 | run: flutter build apk --flavor "${{ inputs.flavor }}"
46 | - uses: actions/upload-artifact@v4
47 | with:
48 | name: app-qa-release
49 | path: packages/app/build/app/outputs/flutter-apk/app-qa-release.apk
50 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | .vscode/
12 | migrate_working_dir/
13 |
14 | # IntelliJ
15 | *.iml
16 | *.ipr
17 | *.iws
18 | .idea/
19 |
20 | # Flutter/Dart/Pub
21 | **/doc/api/
22 | **/ios/Flutter/.last_build_id
23 | .dart_tool/
24 | .flutter-plugins
25 | .flutter-plugins-dependencies
26 | .packages
27 | .pub-cache/
28 | .pub/
29 | /build/
30 | .fvm/
31 |
32 | # Rust
33 | /Cargo.lock
34 | /platform-build
35 | /target/
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 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = ["packages/p2panda/native"]
3 | resolver = "2"
4 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | analyzer:
4 | language:
5 | strict-casts: true
6 | strict-inference: true
7 | strict-raw-types: true
8 |
9 | errors:
10 | missing_required_param: error
11 | missing_return: error
12 | record_literal_one_positional_no_trailing_comma: error
13 |
14 | exclude:
15 | - '**.freezed.dart'
16 | - '**.g.dart'
17 |
18 | linter:
19 | rules:
20 | # Allow good old UPPER_CASE_CONSTANT_VARIABLE_NAMES
21 | constant_identifier_names: false
22 | non_constant_identifier_names: false
23 |
24 | # We dont want to use a logging framework (yet)
25 | avoid_print: false
26 |
--------------------------------------------------------------------------------
/documentation/app.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/documentation/app.gif
--------------------------------------------------------------------------------
/documentation/scan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/documentation/scan.png
--------------------------------------------------------------------------------
/melos.yaml:
--------------------------------------------------------------------------------
1 | name: p2panda
2 | repository: https://github.com/p2panda/meli
3 |
4 | packages:
5 | - packages/*
6 |
7 | scripts:
8 | analyze:
9 | exec: flutter analyze .
10 | description: Analyze all Dart packages for code errors and warnings.
11 |
12 | format:
13 | exec: dart format .
14 | description: Format all Dart packages according to linter settings.
15 |
16 | release:
17 | run: bash scripts/release.sh
18 | packageFilters:
19 | flutter: true
20 | scope: "*app*"
21 | description: Compile .apk builds for all architectures
22 |
23 | build:
24 | run: bash scripts/build.sh
25 | description: Compile native p2panda library for Android.
26 |
27 | clear:
28 | run: bash scripts/clear.sh
29 | description: Remove artifacts which got created after building.
30 |
--------------------------------------------------------------------------------
/packages/app/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | #.vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | **/ios/Flutter/.last_build_id
27 | .dart_tool/
28 | .flutter-plugins
29 | .flutter-plugins-dependencies
30 | .packages
31 | .pub-cache/
32 | .pub/
33 | /build/
34 |
35 | # Symbolication related
36 | app.*.symbols
37 |
38 | # Obfuscation related
39 | app.*.map.json
40 |
41 | # Android Studio will place build artifacts here
42 | /android/app/debug
43 | /android/app/profile
44 | /android/app/release
45 |
--------------------------------------------------------------------------------
/packages/app/.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.
5 |
6 | version:
7 | revision: 796c8ef79279f9c774545b3771238c3098dbefab
8 | channel: stable
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
17 | base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
18 | - platform: android
19 | create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
20 | base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
21 |
22 | # User provided section
23 |
24 | # List of Local paths (relative to this file) that should be
25 | # ignored by the migrate tool.
26 | #
27 | # Files that are not part of the templates will be ignored by default.
28 | unmanaged_files:
29 | - 'lib/main.dart'
30 | - 'ios/Runner.xcodeproj/project.pbxproj'
31 |
--------------------------------------------------------------------------------
/packages/app/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 |
--------------------------------------------------------------------------------
/packages/app/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "com.android.application"
3 | id "kotlin-android"
4 | id "dev.flutter.flutter-gradle-plugin"
5 | }
6 |
7 | def localProperties = new Properties()
8 | def localPropertiesFile = rootProject.file('local.properties')
9 | if (localPropertiesFile.exists()) {
10 | localPropertiesFile.withReader('UTF-8') { reader ->
11 | localProperties.load(reader)
12 | }
13 | }
14 |
15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
16 | if (flutterVersionCode == null) {
17 | flutterVersionCode = '1'
18 | }
19 |
20 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
21 | if (flutterVersionName == null) {
22 | flutterVersionName = '1.0'
23 | }
24 |
25 | android {
26 | namespace "com.p2panda.meli"
27 |
28 | // Set to minimum version 33 for `geolocator` package
29 | compileSdkVersion Math.max(flutter.compileSdkVersion, 33)
30 |
31 | // Pin NDK version to assure compatibility with cargo-ndk build (see
32 | // "packages/p2panda/native/build.rs" file for details)
33 | ndkVersion "25.2.9519653"
34 |
35 | compileOptions {
36 | sourceCompatibility JavaVersion.VERSION_17
37 | targetCompatibility JavaVersion.VERSION_17
38 | }
39 |
40 | kotlinOptions {
41 | jvmTarget = '1.8'
42 | }
43 |
44 | sourceSets {
45 | main.java.srcDirs += 'src/main/kotlin'
46 | }
47 |
48 | defaultConfig {
49 | applicationId "org.p2panda.meli"
50 | minSdkVersion 23
51 | targetSdkVersion flutter.targetSdkVersion
52 | versionCode flutterVersionCode.toInteger()
53 | versionName flutterVersionName
54 | manifestPlaceholders = [applicationLabel: "Meli"]
55 | }
56 |
57 | buildTypes {
58 | debug {
59 | applicationIdSuffix ".debug"
60 | debuggable true
61 | manifestPlaceholders = [applicationLabel: "Meli (Debug)"]
62 | }
63 | profile {
64 | applicationIdSuffix ".profile"
65 | debuggable true
66 | manifestPlaceholders = [applicationLabel: "Meli (Profile)"]
67 | }
68 | release {
69 | // We do not intend to upload the .apk to any "App Store" and just
70 | // sign with the debug keys
71 | signingConfig signingConfigs.debug
72 | }
73 | }
74 |
75 | flavorDimensions "appType"
76 |
77 | productFlavors {
78 | normal {
79 | dimension "appType"
80 | }
81 | qa {
82 | dimension "appType"
83 | applicationIdSuffix ".qa"
84 | manifestPlaceholders = [applicationLabel: "Meli (QA)"]
85 | }
86 | }
87 |
88 | variantFilter { variant ->
89 | // Skip qa flavor for debug and profile builds
90 | def names = variant.flavors*.name
91 | if (
92 | names.contains('qa') &&
93 | (
94 | variant.buildType.name == "debug" ||
95 | variant.buildType.name == "profile"
96 | )
97 | ) {
98 | setIgnore(true)
99 | }
100 | }
101 | }
102 |
103 | flutter {
104 | source '../..'
105 | }
106 |
107 | dependencies {}
108 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
17 |
21 |
25 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
39 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/kotlin/com/p2panda/app/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.p2panda.meli
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/drawable-v21/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/drawable-v21/background.png
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/drawable/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/drawable/background.png
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/values-night-v31/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
17 |
20 |
21 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/values-v31/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
17 |
20 |
21 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/packages/app/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/packages/app/android/build.gradle:
--------------------------------------------------------------------------------
1 | allprojects {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | }
7 |
8 | rootProject.buildDir = '../build'
9 | subprojects {
10 | project.buildDir = "${rootProject.buildDir}/${project.name}"
11 | }
12 | subprojects {
13 | project.evaluationDependsOn(':app')
14 | }
15 |
16 | tasks.register("clean", Delete) {
17 | delete rootProject.buildDir
18 | }
19 |
--------------------------------------------------------------------------------
/packages/app/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 |
3 | # We need this for the `geolocator` package
4 | android.useAndroidX=true
5 | android.enableJetifier=true
6 |
--------------------------------------------------------------------------------
/packages/app/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
6 |
--------------------------------------------------------------------------------
/packages/app/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 "7.3.0" apply false
22 | id "org.jetbrains.kotlin.android" version "1.9.0" apply false
23 | }
24 |
25 | include ":app"
26 |
--------------------------------------------------------------------------------
/packages/app/assets/fonts/Staatliches-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/assets/fonts/Staatliches-Regular.ttf
--------------------------------------------------------------------------------
/packages/app/assets/images/meliponini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/assets/images/meliponini.png
--------------------------------------------------------------------------------
/packages/app/assets/images/meliponini.svg:
--------------------------------------------------------------------------------
1 |
2 |
49 |
--------------------------------------------------------------------------------
/packages/app/assets/images/placeholder-bee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2panda/meli/bb82c69ecafdbcf72b6f563b5bc648bdafda5f97/packages/app/assets/images/placeholder-bee.png
--------------------------------------------------------------------------------
/packages/app/assets/schema.lock:
--------------------------------------------------------------------------------
1 | ../../../schemas/schema.lock
--------------------------------------------------------------------------------
/packages/app/l10n.yaml:
--------------------------------------------------------------------------------
1 | arb-dir: lib/locales
2 | template-arb-file: app_en.arb
3 | output-localization-file: app_localizations.dart
--------------------------------------------------------------------------------
/packages/app/lib/app.dart:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: AGPL-3.0-or-later
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_gen/gen_l10n/app_localizations.dart';
5 | import 'package:graphql_flutter/graphql_flutter.dart';
6 | import 'package:shared_preferences/shared_preferences.dart';
7 |
8 | import 'package:app/io/graphql/graphql.dart' as graphql;
9 | import 'package:app/router.dart';
10 | import 'package:app/ui/widgets/image_provider.dart';
11 | import 'package:app/ui/widgets/refresh_provider.dart';
12 |
13 | class MeliApp extends StatefulWidget {
14 | const MeliApp({super.key});
15 |
16 | @override
17 | State createState() => MeliAppState();
18 | }
19 |
20 | class MeliAppState extends State {
21 | final Future _prefs = SharedPreferences.getInstance();
22 | Locale? _locale;
23 |
24 | @override
25 | void initState() {
26 | super.initState();
27 |
28 | // Set locale to user setting if given
29 | _prefs.then((SharedPreferences prefs) {
30 | final String? localString = prefs.getString('locale');
31 | if (localString != null) {
32 | setState(() {
33 | _locale = Locale(localString);
34 | });
35 | }
36 | });
37 | }
38 |
39 | Future changeLocale(String languageCode) async {
40 | final SharedPreferences prefs = await _prefs;
41 | bool success = await prefs.setString('locale', languageCode.toString());
42 |
43 | if (success) {
44 | setState(() {
45 | _locale = Locale(languageCode);
46 | });
47 | }
48 |
49 | return success;
50 | }
51 |
52 | @override
53 | Widget build(BuildContext context) {
54 | ValueNotifier client = ValueNotifier(graphql.client);
55 |
56 | return GraphQLProvider(
57 | client: client,
58 | child: RefreshProvider(
59 | child: MeliCameraProvider(MaterialApp.router(
60 | // Register router for navigation
61 | routerDelegate: router.routerDelegate,
62 | routeInformationProvider: router.routeInformationProvider,
63 | routeInformationParser: router.routeInformationParser,
64 |
65 | // Setup localization
66 | locale: _locale,
67 | localeListResolutionCallback: (locales, supportedLocales) {
68 | // Check if we can fullfil the preferred locale of the device OS
69 | // ordered by priority
70 | if (locales != null) {
71 | final supportedLanguageCodes =
72 | supportedLocales.map((supportedLocale) {
73 | return supportedLocale.languageCode;
74 | });
75 |
76 | for (var locale in locales) {
77 | if (supportedLanguageCodes.contains(locale.languageCode)) {
78 | return locale;
79 | }
80 | }
81 | }
82 |
83 | return const Locale('pt');
84 | },
85 | localizationsDelegates: AppLocalizations.localizationsDelegates,
86 | supportedLocales: AppLocalizations.supportedLocales,
87 |
88 | // Material theme configuration
89 | theme: ThemeData(useMaterial3: true),
90 |
91 | // Disable "debug" banner shown in top right corner during development
92 | debugShowCheckedModeBanner: false,
93 | ))));
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/packages/app/lib/io/assets.dart:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: AGPL-3.0-or-later
2 |
3 | import 'package:flutter/services.dart' show rootBundle;
4 |
5 | Future loadAsset(String path) async {
6 | return await rootBundle.loadString(path);
7 | }
8 |
--------------------------------------------------------------------------------
/packages/app/lib/io/files.dart:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: AGPL-3.0-or-later
2 |
3 | import 'package:path_provider/path_provider.dart' as provider;
4 |
5 | /// Blobs base path.
6 | const String BLOBS_BASE_PATH = 'http://localhost:2020/blobs';
7 |
8 | Future get applicationSupportDirectory async {
9 | final directory = await provider.getApplicationSupportDirectory();
10 | return directory.path;
11 | }
12 |
13 | Future get temporaryDirectory async {
14 | final directory = await provider.getTemporaryDirectory();
15 | return directory.path;
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app/lib/io/geolocation.dart:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: AGPL-3.0-or-later
2 |
3 | import 'dart:async';
4 |
5 | import 'package:geolocator/geolocator.dart';
6 |
7 | /// Throw exception after waiting for x seconds.
8 | const TIMEOUT_DURATION = Duration(seconds: 30);
9 |
10 | /// Determine the current position of the device.
11 | ///
12 | /// When the location services are not enabled or permissions are denied the
13 | /// `Future` will return an error.
14 | Future determinePosition() async {
15 | bool serviceEnabled;
16 | LocationPermission permission;
17 |
18 | // Test if location services are enabled.
19 | serviceEnabled = await Geolocator.isLocationServiceEnabled();
20 | if (!serviceEnabled) {
21 | // Location services are not enabled don't continue accessing the position
22 | // and request users of the App to enable the location services.
23 | throw const LocationServiceDisabledException();
24 | }
25 |
26 | permission = await Geolocator.checkPermission();
27 | if (permission == LocationPermission.denied) {
28 | permission = await Geolocator.requestPermission();
29 | if (permission == LocationPermission.denied) {
30 | // Permissions are denied, next time you could try requesting permissions
31 | // again (this is also where Android's shouldShowRequestPermissionRationale
32 | // returned true. According to Android guidelines your App should show an
33 | // explanatory UI now.
34 | throw const PermissionDeniedException('Permission was denied');
35 | }
36 | }
37 |
38 | if (permission == LocationPermission.deniedForever) {
39 | // Permissions are denied forever, handle appropriately.
40 | throw const PermissionDeniedException('Permission is permamently denied');
41 | }
42 |
43 | // When we reach here, permissions are granted and we can
44 | // continue accessing the position of the device.
45 | return await Geolocator.getCurrentPosition(timeLimit: TIMEOUT_DURATION);
46 | }
47 |
--------------------------------------------------------------------------------
/packages/app/lib/io/graphql/graphql.dart:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: AGPL-3.0-or-later
2 |
3 | import 'package:graphql/client.dart';
4 |
5 | /// GraphQL endpoint URL.
6 | const String HTTP_ENDPOINT = 'http://localhost:2020/graphql';
7 |
8 | final policies = Policies(
9 | fetch: FetchPolicy.networkOnly,
10 | );
11 |
12 | /// GraphQL client making requests against our locally hosted node API.
13 | final GraphQLClient client = GraphQLClient(
14 | link: HttpLink(HTTP_ENDPOINT),
15 | cache: GraphQLCache(),
16 | // Disable caching by overriding default policies. See:
17 | // https://github.com/zino-hofmann/graphql-flutter/issues/692
18 | defaultPolicies: DefaultPolicies(
19 | watchQuery: policies,
20 | query: policies,
21 | mutate: policies,
22 | ),
23 | );
24 |
--------------------------------------------------------------------------------
/packages/app/lib/io/graphql/queries.dart:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: AGPL-3.0-or-later
2 |
3 | import 'package:graphql/client.dart';
4 |
5 | import 'package:app/io/graphql/graphql.dart';
6 |
7 | /// GraphQL mutation to publish entries and operations with.
8 | const String PUBLISH_MUTATION = r'''
9 | mutation Publish($entry: String!, $operation: String!) {
10 | publish(entry: $entry, operation: $operation) {
11 | logId
12 | seqNum
13 | backlink
14 | skiplink
15 | }
16 | }
17 | ''';
18 |
19 | /// GraphQL query to retrieve arguments which are required for the creation
20 | /// of the next entry.
21 | const String NEXT_ARGS_QUERY = r'''
22 | query NextArgs($publicKey: String!, $viewId: String!) {
23 | nextArgs(publicKey: $publicKey, viewId: $viewId) {
24 | logId
25 | seqNum
26 | backlink
27 | skiplink
28 | }
29 | }
30 | ''';
31 |
32 | /// Arguments returned from node which are required for the creation of the
33 | /// next entry.
34 | class NextArgs {
35 | final BigInt logId;
36 | final BigInt seqNum;
37 | final String? backlink;
38 | final String? skiplink;
39 |
40 | NextArgs(
41 | {required this.logId,
42 | required this.seqNum,
43 | this.backlink,
44 | this.skiplink});
45 | }
46 |
47 | /// Helper method to convert GraphQL response to `NextArgs` instance.
48 | NextArgs _toNextArgs(dynamic data) {
49 | // Large integers like `logId` and `seqNum` are coming as strings from the
50 | // GraphQL JSON response as u64 is not supported in JavaScript
51 | return NextArgs(
52 | logId: BigInt.parse(data['logId'] as String),
53 | seqNum: BigInt.parse(data['seqNum'] as String),
54 | backlink: data['backlink'] as String?,
55 | skiplink: data['skiplink'] as String?);
56 | }
57 |
58 | Future