Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/vocdoni/vocdoni-mobile
Decentralized, transparent, verifiable and anonymous voting app
https://github.com/vocdoni/vocdoni-mobile
decentralized decentralized-voting e-gov e-government evoting flutter governance open-gov vote vote-application voting voting-app voting-application
Last synced: 3 days ago
JSON representation
Decentralized, transparent, verifiable and anonymous voting app
- Host: GitHub
- URL: https://github.com/vocdoni/vocdoni-mobile
- Owner: vocdoni
- License: bsd-3-clause
- Created: 2020-12-04T11:27:24.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2023-02-20T17:36:40.000Z (over 1 year ago)
- Last Synced: 2024-04-01T16:19:17.853Z (8 months ago)
- Topics: decentralized, decentralized-voting, e-gov, e-government, evoting, flutter, governance, open-gov, vote, vote-application, voting, voting-app, voting-application
- Language: Dart
- Homepage:
- Size: 3.25 MB
- Stars: 12
- Watchers: 5
- Forks: 3
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Code of conduct: code-of-conduct.md
- Authors: AUTHORS
Awesome Lists containing this project
README
# Vocdoni Mobile Client
Official implementation of the Vocdoni core features.## Flavors
The app can run in three diferent modes:
* Development
- Uses the development blockchain
* Beta (Android only)
- Uses the development blockchain
* Production
- Uses the production blockchainFlavors are available on Android. The iOS project uses `dev` and `production` depending on the XCode target.
## Development
### Data Architecture and internal Models
The State Management architecture of the app is built on top of the [Eventual package](https://pub.dev/packages/eventual). Eventual allows to track updates on objects and rebuild their corresponding UI accordingly.
#### Model classes
They can be of the type:
* Single models
* AppStateModel, AccountModel, EntityModel, ProcessModel, FeedModel
* A model can contain references to other models
* Pools of data
* Typically, they contain a collection of single models
* Usually used as global variables
* Their goal is to track whether the collection changes, but not the individual items
* They contain all the model instances known to the system
* Any modification on a model should happen in models obtained from a global pool, since the pool manages persistenceThis separation allows for efficient and granular widget tree rebuilds whenever the state is updated. If a single value changes, only the relevant children should rebuild.
#### Usage
**Initialize and read Global Model's data in `globals.dart`**
```dart
// entitiesPersistence = EntitiesPersistence();
await Global.entitiesPersistence.readAll();// ...
// entityPool = EntityPoolModel();
await Globals.entityPool.readFromStorage(); // will import and arrange the persisted data
```**Consume Models in specific places**
Typically, a Pool with all the EntityModel's known to the app and then, individual `EntityModel` instances when the user selects one.
```dart
// Globals.entityPool// ...
// Widget
@override
Widget build(BuildContext context) {
// From the pool, we grab the first entity model
final myEntity = Globals.entityPool.value.first;// Consume many values (EventualNotifier) locally
return EventualBuilder(
notifiers: [myEntity.feed, myEntity.processes], // EventualNotifier values that may change over time
builder: (context) {
// rebuilt whenever either of myEntity.feed or myEntity.processes change// ...
)
);
}
```In the example above, updates on specifig Feed items, will not affect the current widget. But as soon as we call `myEntity.feed.refresh()` on this instance, the Builder will be triggered because of the changes in `isLoading`, `hasError` and `hasValue`.
#### Extra methods
Certain models implement the `ModelRefreshable` interface. This ensures that callers can call `refresh()` to request a refetch of remote data, based on the current model's ID or metadata.
Other models (mainly pools) also implement the `ModelPersistable` interface, so that `readFromStorage()` and `writeToStorage()` can be called.
#### General
It is important not to mix the models (account, entity, process, feed, app state) with the Persistence classes. Persistence classes map diretly to `dvote-protobuf` classes, which allow for binary serialization and consistently have a 1:1 mapping.
Models can contain both data which is persisted (entity metadata, process metadata) as well as data that is ephemeral (current participants on a vote, selected account). When `readFromStorage` is called, data needs to be deserialized and restored properly, often across multiple models.
### Internationalization
![Translations](https://hosted.weblate.org/widgets/vocdoni/-/mobile/svg-badge.svg)
- Add `import 'package:vocdoni/lib/i18n.dart';` on your widget file
- Access the new string with `getText(context, "My new string to translate")`
- Parse the new strings with `make lang-extract`
- Translate the files on `assets/i18n/*.json`The app's strings translation can be found on [Weblate](https://hosted.weblate.org/projects/vocdoni/mobile/).
#### Translation management
Weblate monitors `origin/i18n` and pulls from it as new strings are available. After a new translation is added, Weblate compiles the new JSON files in a git remote of its own.
To pull from it, run `make init`. This will add a `weblate` git remote besides `origin`. This way:
- `weblate/i18n` has the translated strings to integrate into the app
- `origin/i18n` contains the empty strings that Weblate will show to translatorsThe translation flow is an iterative loop that looks like:
- Lock the weblate repository
- `git checkout i18n`
- `git pull weblate i18n` (update our local repo)
- `git push origin i18n` (update the GitHub branch)
- `git checkout main` (check out the latest code)
- `git merge i18n` (integrate the latest translations)
- `git push origin main` (update the GitHub branch)
- `git checkout i18n`
- `git merge main` (integrate the latest code into i18n)
- `make lang-parse` (extract the new strings)
- `git add assets/i18n/*` (stage the language files for commit)
- `git commit -m "Updated strings"`
- `git push origin i18n` (push the new strings for Weblate)
- `git checkout main`
- Unlock the Weblate repository**Important**:
- Make sure to use the right key prefixes:
- `"action.createIdentity"` instead of `"main.createIdentity"`
- In the keys, use no symbols beyond the dot separator
- Use placeholders for data replacement instead of concatenating it later
- `"question.doYouWantToRemoveName"` => `"Do you want to remove {{NAME}}?"`### Dependencies
The project makes use of the [DVote Flutter](https://pub.dev/packages/dvote) plugin. Please, [see the repository](https://github.com/vocdoni/dvote-flutter) for more details.
## Integration
### Deep linking
The app accepts Deep Links from the following domains:
- `app.vocdoni.net`
- `app.dev.vocdoni.net`
- `vocdoni.page.link`
- `vocdonidev.page.link`To enable them:
- Place `linking/assetlink.json` on `https://app.vocdoni.net/.well-known/assetlinks.json`
- Also place `linking/assetlink.json` on `https://app.dev.vocdoni.net/.well-known/assetlinks.json`
- Place `linking/apple-app-site-association` on `https://app.vocdoni.net/.well-known/apple-app-site-association`#### Supported Paths and Parameters
- `app.vocdoni.net` and `app.dev.vocdoni.net`
- `https://app.vocdoni.net/entities/#/`
- ~~`https://app.vocdoni.net/entities/#/`~~
- ~~`https://app.vocdoni.net/news/#/`~~
- `https://app.vocdoni.net/validation/#//`The same applies to `app.dev.vocdoni.net`
- `vocdoni.page.link` and `vocdonidev.page.link`
- They wrap dynamic links
- The `link` query string parameter is extracted, which should contain a link like the ones above from `app.vocdoni.net` and `app.dev.vocdoni.net`#### Supported Schemas
The app also accepts URI's using the `vocdoni:` schema, with the same paths and parameters as above:
- `vocdoni://vocdoni.app/entities/#/`
- ~~`vocdoni://vocdoni.app/processes/#//`~~
- ~~`vocdoni://vocdoni.app/posts/#//`~~
- `vocdoni://vocdoni.app/validation/#//`#### Show an entity
On developoment, you can test it by running `make launch-ios-org` or `make launch-android-org`
### Push notifications
The `data` field of incoming push notifications [is expected to contain](https://gitlab.com/vocdoni/client-mobile/-/issues/197) three keys:
```
{
notification: { ... },
data: {
uri: "https://vocdoni.link/processes/0x1234.../0x2345...",
event: "new-process", // enum, see below
message: "..." // same as notification > body
}
}
```- The `uri` field will be used the same as a deep link and will determine where the app navigates to.
- The `event` can be one of:
- `entity-updated`: The metadata of the entity has changed (but not the process list or the news feed)
- `new-post`: A new post has been added to the Feed
- `new-process`: A process has been created
- `process-ended`: The end block has been reached
- The `message` is a copy of the relevant text contained within `notification` (not always present)### Permissions
In order to drop unused permissions, edit `ios/Podfile` and make sure to uncomment the permissions that are not needed after `target.build_configurations.each`.
## Troubleshooting
- The `r_scan` plugin breaks the build on iOS and/or is rejected by Google Play
- Edit `pubspec.yaml` and comment/uncomment the dependencies accordingly
- ~~Can't compile iOS because `App.framework` is built for another architecture~~
- ~~Run `rm -Rf ios/Flutter/App.framework` and try again~~