diff --git a/.github/workflows/android_package.yaml b/.github/workflows/android_package.yaml
new file mode 100644
index 0000000..ca0f212
--- /dev/null
+++ b/.github/workflows/android_package.yaml
@@ -0,0 +1,91 @@
+name: Build and sign application for Android
+
+on:
+ push:
+ tags:
+ - "v[0-9]+.[0-9]+.[0-9]+"
+ - "v[0-9]+.[0-9]+.[0-9]+([0-9]+)"
+
+ workflow_dispatch:
+ inputs:
+ name:
+ description: "Release-Build-Android"
+ default: "Generate release build for Android"
+
+
+permissions:
+ contents: write
+
+jobs:
+ build:
+ environment: packaging
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ path: app
+
+ - name: Checkout "eidmsdk_flutter"
+ uses: actions/checkout@v4
+ with:
+ repository: slovensko-digital/eidmsdk-flutter
+ token: ${{ secrets.GH_PAT }}
+ path: eidmsdk_flutter
+
+ - name: Checkout "autogram_sign"
+ uses: actions/checkout@v4
+ with:
+ repository: slovensko-digital/avm-client-dart
+ token: ${{ secrets.GH_PAT }}
+ path: autogram_sign
+
+ - uses: actions/setup-java@v1
+ with:
+ java-version: '17.x'
+
+ - uses: subosito/flutter-action@v1
+ with:
+ flutter-version: '3.16.5'
+ channel: 'stable'
+
+ - name: Install dependencies
+ working-directory: ./app
+ run: flutter pub get
+
+ - name: Test
+ working-directory: ./app
+ run: flutter test
+
+ - name: Decode Keystore
+ env:
+ ENCODED_STRING: ${{ secrets.GOOGLE_KEYSTORE_BASE_64 }}
+ working-directory: ./app
+ run: echo $ENCODED_STRING | base64 -d > release_keystore.jks
+
+ - name: Build
+ env:
+ AVM_KEYSTORE_FILE: ../../release_keystore.jks
+ AVM_KEYSTORE_PASSWORD: ${{ secrets.GOOGLE_RELEASE_KEYSTORE_PASSWORD }}
+ AVM_KEY_ALIAS: ${{ secrets.GOOGLE_RELEASE_KEYSTORE_ALIAS }}
+ AVM_KEY_PASSWORD: ${{ secrets.GOOGLE_RELEASE_KEY_PASSWORD }}
+ working-directory: ./app
+ run: flutter build appbundle --release
+
+ - name: Upload Release Build to Artifacts
+ uses: actions/upload-artifact@v3
+ with:
+ name: release-artifacts
+ path: ./app/build/app/outputs/bundle/release/app-release.aab
+
+ - name: Create release if tag pushed
+ uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844
+ if: startsWith(github.ref, 'refs/tags/')
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ draft: true
+ prerelease: true
+ files: |
+ ./app/build/app/outputs/bundle/release/app-release.aab
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5b00a1d..d6c10a1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,49 @@
# Changelog
+## NEXT - v1.0.2(33)
+
+- Refactor Settings model
+
+## 2024-06-17 - v1.0.1(1)
+
+- Update about text in iOS build
+
+## 2024-06-17 - v1.0.0(32)
+
+- Update about text
+
+## 2024-06-15 - v1.0.0(31)
+
+- Remove iPad from target devices as iPads have no NFC
+- set minimum iOS version to 12 as apple required
+
+## 2024-06-14 - v1.0.0(30)
+
+- Update Android and iOS icons
+- Update texts
+- Set default signatureType without TimeStamp
+
+## 2024-06-13 - v1.0.0(29)
+
+- Fix Signature Type setting UX
+
+## 2024-06-13 - v1.0.0(28)
+
+- #4 | Displaying Onboarding screen for Remote Document Signing only 1st time
+- #7 | When signing remote Document (from QR code or URL), then cannot change Signing Type
+
+## 2024-05-29 - v1.0.0(27)
+
+- Android: Setup release build signing key for Google Play
+
+## 2024-05-28 - v1.0.0(26)
+
+- Displaying Privacy Policy and Terms of Service documents in Onboarding and Main menu
+- Storing "version" value from loaded documents above
+
## 2024-05-07 - v1.0.0(25)
-- Android: Fix auto verify Deep links - no need to manually enable domain association
+- Android: Fix auto verify Deep links - no need to manually enable domain association
## 2024-05-07 - v1.0.0(24)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..3660c79
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,287 @@
+ EUROPEAN UNION PUBLIC LICENCE v. 1.2
+ EUPL © the European Union 2007, 2016
+
+This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined
+below) which is provided under the terms of this Licence. Any use of the Work,
+other than as authorauthorised under this Licence is prohibited (to the extent such
+use is covered by a right of the copyright holder of the Work).
+
+The Work is provided under the terms of this Licence when the Licensor (as
+defined below) has placed the following notice immediately following the
+copyright notice for the Work:
+
+ Licensed under the EUPL
+
+or has expressed by any other means his willingness to license under the EUPL.
+
+1. Definitions
+
+In this Licence, the following terms have the following meaning:
+
+- ‘The Licence’: this Licence.
+
+- ‘The Original Work’: the work or software distributed or communicated by the
+ Licensor under this Licence, available as Source Code and also as Executable
+ Code as the case may be.
+
+- ‘Derivative Works’: the works or software that could be created by the
+ Licensee, based upon the Original Work or modifications thereof. This Licence
+ does not define the extent of modification or dependence on the Original Work
+ required in order to classify a work as a Derivative Work; this extent is
+ determined by copyright law applicable in the country mentioned in Article 15.
+
+- ‘The Work’: the Original Work or its Derivative Works.
+
+- ‘The Source Code’: the human-readable form of the Work which is the most
+ convenient for people to study and modify.
+
+- ‘The Executable Code’: any code which has generally been compiled and which is
+ meant to be interpreted by a computer as a program.
+
+- ‘The Licensor’: the natural or legal person that distributes or communicates
+ the Work under the Licence.
+
+- ‘Contributor(s)’: any natural or legal person who modifies the Work under the
+ Licence, or otherwise contributes to the creation of a Derivative Work.
+
+- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
+ the Work under the terms of the Licence.
+
+- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
+ renting, distributing, communicating, transmitting, or otherwise making
+ available, online or offline, copies of the Work or providing access to its
+ essential functionalities at the disposal of any other natural or legal
+ person.
+
+2. Scope of the rights granted by the Licence
+
+The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+sublicensable licence to do the following, for the duration of copyright vested
+in the Original Work:
+
+- use the Work in any circumstance and for all usage,
+- reproduce the Work,
+- modify the Work, and make Derivative Works based upon the Work,
+- communicate to the public, including the right to make available or display
+ the Work or copies thereof to the public and perform publicly, as the case may
+ be, the Work,
+- distribute the Work or copies thereof,
+- lend and rent the Work or copies thereof,
+- sublicense rights in the Work or copies thereof.
+
+Those rights can be exercised on any media, supports and formats, whether now
+known or later invented, as far as the applicable law permits so.
+
+In the countries where moral rights apply, the Licensor waives his right to
+exercise his moral right to the extent allowed by law in order to make effective
+the licence of the economic rights here above listed.
+
+The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to
+any patents held by the Licensor, to the extent necessary to make use of the
+rights granted on the Work under this Licence.
+
+3. Communication of the Source Code
+
+The Licensor may provide the Work either in its Source Code form, or as
+Executable Code. If the Work is provided as Executable Code, the Licensor
+provides in addition a machine-readable copy of the Source Code of the Work
+along with each copy of the Work that the Licensor distributes or indicates, in
+a notice following the copyright notice attached to the Work, a repository where
+the Source Code is easily and freely accessible for as long as the Licensor
+continues to distribute or communicate the Work.
+
+4. Limitations on copyright
+
+Nothing in this Licence is intended to deprive the Licensee of the benefits from
+any exception or limitation to the exclusive rights of the rights owners in the
+Work, of the exhaustion of those rights or of other applicable limitations
+thereto.
+
+5. Obligations of the Licensee
+
+The grant of the rights mentioned above is subject to some restrictions and
+obligations imposed on the Licensee. Those obligations are the following:
+
+Attribution right: The Licensee shall keep intact all copyright, patent or
+trademarks notices and all notices that refer to the Licence and to the
+disclaimer of warranties. The Licensee must include a copy of such notices and a
+copy of the Licence with every copy of the Work he/she distributes or
+communicates. The Licensee must cause any Derivative Work to carry prominent
+notices stating that the Work has been modified and the date of modification.
+
+Copyleft clause: If the Licensee distributes or communicates copies of the
+Original Works or Derivative Works, this Distribution or Communication will be
+done under the terms of this Licence or of a later version of this Licence
+unless the Original Work is expressly distributed only under this version of the
+Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
+(becoming Licensor) cannot offer or impose any additional terms or conditions on
+the Work or Derivative Work that alter or restrict the terms of the Licence.
+
+Compatibility clause: If the Licensee Distributes or Communicates Derivative
+Works or copies thereof based upon both the Work and another work licensed under
+a Compatible Licence, this Distribution or Communication can be done under the
+terms of this Compatible Licence. For the sake of this clause, ‘Compatible
+Licence’ refers to the licences listed in the appendix attached to this Licence.
+Should the Licensee's obligations under the Compatible Licence conflict with
+his/her obligations under this Licence, the obligations of the Compatible
+Licence shall prevail.
+
+Provision of Source Code: When distributing or communicating copies of the Work,
+the Licensee will provide a machine-readable copy of the Source Code or indicate
+a repository where this Source will be easily and freely available for as long
+as the Licensee continues to distribute or communicate the Work.
+
+Legal Protection: This Licence does not grant permission to use the trade names,
+trademarks, service marks, or names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the copyright notice.
+
+6. Chain of Authorship
+
+The original Licensor warrants that the copyright in the Original Work granted
+hereunder is owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each Contributor warrants that the copyright in the modifications he/she brings
+to the Work are owned by him/her or licensed to him/her and that he/she has the
+power and authority to grant the Licence.
+
+Each time You accept the Licence, the original Licensor and subsequent
+Contributors grant You a licence to their contributions to the Work, under the
+terms of this Licence.
+
+7. Disclaimer of Warranty
+
+The Work is a work in progress, which is continuously improved by numerous
+Contributors. It is not a finished work and may therefore contain defects or
+‘bugs’ inherent to this type of development.
+
+For the above reason, the Work is provided under the Licence on an ‘as is’ basis
+and without warranties of any kind concerning the Work, including without
+limitation merchantability, fitness for a particular purpose, absence of defects
+or errors, accuracy, non-infringement of intellectual property rights other than
+copyright as stated in Article 6 of this Licence.
+
+This disclaimer of warranty is an essential part of the Licence and a condition
+for the grant of any rights to the Work.
+
+8. Disclaimer of Liability
+
+Except in the cases of wilful misconduct or damages directly caused to natural
+persons, the Licensor will in no event be liable for any direct or indirect,
+material or moral, damages of any kind, arising out of the Licence or of the use
+of the Work, including without limitation, damages for loss of goodwill, work
+stoppage, computer failure or malfunction, loss of data or any commercial
+damage, even if the Licensor has been advised of the possibility of such damage.
+However, the Licensor will be liable under statutory product liability laws as
+far such laws apply to the Work.
+
+9. Additional agreements
+
+While distributing the Work, You may choose to conclude an additional agreement,
+defining obligations or services consistent with this Licence. However, if
+accepting obligations, You may act only on your own behalf and on your sole
+responsibility, not on behalf of the original Licensor or any other Contributor,
+and only if You agree to indemnify, defend, and hold each Contributor harmless
+for any liability incurred by, or claims asserted against such Contributor by
+the fact You have accepted any warranty or additional liability.
+
+10. Acceptance of the Licence
+
+The provisions of this Licence can be accepted by clicking on an icon ‘I agree’
+placed under the bottom of a window displaying the text of this Licence or by
+affirming consent in any other similar way, in accordance with the rules of
+applicable law. Clicking on that icon indicates your clear and irrevocable
+acceptance of this Licence and all of its terms and conditions.
+
+Similarly, you irrevocably accept this Licence and all of its terms and
+conditions by exercising any rights granted to You by Article 2 of this Licence,
+such as the use of the Work, the creation by You of a Derivative Work or the
+Distribution or Communication by You of the Work or copies thereof.
+
+11. Information to the public
+
+In case of any Distribution or Communication of the Work by means of electronic
+communication by You (for example, by offering to download the Work from a
+remote location) the distribution channel or media (for example, a website) must
+at least provide to the public the information requested by the applicable law
+regarding the Licensor, the Licence and the way it may be accessible, concluded,
+stored and reproduced by the Licensee.
+
+12. Termination of the Licence
+
+The Licence and the rights granted hereunder will terminate automatically upon
+any breach by the Licensee of the terms of the Licence.
+
+Such a termination will not terminate the licences of any person who has
+received the Work from the Licensee under the Licence, provided such persons
+remain in full compliance with the Licence.
+
+13. Miscellaneous
+
+Without prejudice of Article 9 above, the Licence represents the complete
+agreement between the Parties as to the Work.
+
+If any provision of the Licence is invalid or unenforceable under applicable
+law, this will not affect the validity or enforceability of the Licence as a
+whole. Such provision will be construed or reformed so as necessary to make it
+valid and enforceable.
+
+The European Commission may publish other linguistic versions or new versions of
+this Licence or updated versions of the Appendix, so far this is required and
+reasonable, without reducing the scope of the rights granted by the Licence. New
+versions of the Licence will be published with a unique version number.
+
+All linguistic versions of this Licence, approved by the European Commission,
+have identical value. Parties can take advantage of the linguistic version of
+their choice.
+
+14. Jurisdiction
+
+Without prejudice to specific agreement between parties,
+
+- any litigation resulting from the interpretation of this License, arising
+ between the European Union institutions, bodies, offices or agencies, as a
+ Licensor, and any Licensee, will be subject to the jurisdiction of the Court
+ of Justice of the European Union, as laid down in article 272 of the Treaty on
+ the Functioning of the European Union,
+
+- any litigation arising between other parties and resulting from the
+ interpretation of this License, will be subject to the exclusive jurisdiction
+ of the competent court where the Licensor resides or conducts its primary
+ business.
+
+15. Applicable Law
+
+Without prejudice to specific agreement between parties,
+
+- this Licence shall be governed by the law of the European Union Member State
+ where the Licensor has his seat, resides or has his registered office,
+
+- this licence shall be governed by Belgian law if the Licensor has no seat,
+ residence or registered office inside a European Union Member State.
+
+Appendix
+
+‘Compatible Licences’ according to Article 5 EUPL are:
+
+- GNU General Public License (GPL) v. 2, v. 3
+- GNU Affero General Public License (AGPL) v. 3
+- Open Software License (OSL) v. 2.1, v. 3.0
+- Eclipse Public License (EPL) v. 1.0
+- CeCILL v. 2.0, v. 2.1
+- Mozilla Public Licence (MPL) v. 2
+- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
+- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
+ works other than software
+- European Union Public Licence (EUPL) v. 1.1, v. 1.2
+- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
+ Reciprocity (LiLiQ-R+).
+
+The European Commission may update this Appendix to later versions of the above
+licences without producing a new version of the EUPL, as long as they provide
+the rights granted in Article 2 of this Licence and protect the covered Source
+Code from exclusive appropriation.
+
+All other changes or additions to this Appendix require the production of a new
+EUPL version.
diff --git a/README.md b/README.md
index 8cad7fc..1441f22 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,27 @@
-# Autogram Mobile App (AVM)
+# Autogram v mobile (AVM)
-Flutter app for Android and iOS.
+Flutter aplikácia pre Android a iOS. Podpisovač Autogram v mobile umožňuje podpisovanie elektronickým občianskym preukazom s NFC rozhraním. Detailnejšie info o arhitektúre projektu sa nachádzajú v repozitári [AVM server](https://github.com/slovensko-digital/avm-server).
-## Entry points
+[Autogram v mobile](https://sluzby.slovensko.digital/autogram-v-mobile/) vytvorili freevision s.r.o., Služby Slovensko.Digital s.r.o. s dobrovoľníkmi pod EUPL v1.2 licenciou. Prevádzkovateľom je Služby Slovensko.Digital s.r.o.. Prípadné issues riešime v [GitHub projekte](https://github.com/orgs/slovensko-digital/projects/5) alebo rovno v tomto repozitári.
+
+Celý projekt sa skladá z viacerých častí:
+- **Server**
+ - [AVM server](https://github.com/slovensko-digital/avm-server) - Ruby on Rails API server poskytujúci funkcionalitu zdieľania a podpisovania dokumentov.
+ - [AVM service](https://github.com/slovensko-digital/avm-service) - Java microservice využívajúci Digital Signature Service knižnicu pre elektronické podpisovanie a generovanie vizualizácie dokumentov.
+- **Mobilná aplikácia**
+ - [AVM app Flutter](https://github.com/slovensko-digital/avm-app-flutter) - Flutter aplikácia pre iOS a Android.
+ - [AVM client Dart](https://github.com/slovensko-digital/avm-client-dart) - Dart API klient pre komunikáciu s AVM serverom.
+ - [eID mSDK Flutter](https://github.com/slovensko-digital/eidmsdk-flutter) - Flutter wrapper "štátneho" [eID mSDK](https://github.com/eIDmSDK) pre komunikáciu s občianskym preukazom.
+- [**Autogram extension**](https://github.com/slovensko-digital/autogram-extension) - Rozšírenie do prehliadača, ktoré umožňuje podpisovanie priamo na štátnych portáloch.
+
+
+## Dart aplikácia
+### Entry points
- [main](lib/main.dart) - main app
- [preview](lib/preview.dart) - [Widgetbook](https://www.widgetbook.io/blog/getting-started) app
-## Key concepts
+### Key concepts
- Business logic should be separated in **Bloc** and placed in [lib/bloc/](lib/bloc)
- `NameCubit`
@@ -18,18 +32,18 @@ Flutter app for Android and iOS.
- are placed in [`lib/ui`](lib/ui)
- should have reasonable previews with `@widgetbook.UseCase` without relying on any `Bloc` or `Provider` types
-## Implemented app flows
+### Implemented app flows
-### Onboarding
+#### Onboarding
-User onboarding - starts with one [`Onboarding`](lib/ui/onboarding.dart):
+User onboarding - started with [`Onboarding`](lib/ui/onboarding.dart):
1. Accept Privacy Policy using [`OnboardingAcceptDocumentScreen`](lib/ui/screens/onboarding_accept_document_screen.dart)
2. Accept Terms of Service using same [`OnboardingAcceptDocumentScreen`](lib/ui/screens/onboarding_accept_document_screen.dart)
3. optionally [`OnboardingSelectSigningCertificateScreen`](lib/ui/screens/onboarding_select_signing_certificate_screen.dart)
4. Presenting finish - [`OnboardingFinishedScreen`](lib/ui/screens/onboarding_finished_screen.dart)
-### Sign single document
+#### Sign single document
Signing of single (PDF, TXT, image, eForms XML, ...) document using
[`Eidmsdk`](../eidmsdk_flutter/lib/eidmsdk.dart) and
@@ -49,14 +63,15 @@ Signing of single (PDF, TXT, image, eForms XML, ...) document using
6. [`PresentSignedDocumentScreen`](lib/ui/screens/present_signed_document_screen.dart) - here, the
(success / error) result is presented and signed document is saved into "Downloads".
-### Remote document signing
+#### Remote document signing
-Similar to [Sign single document](#sign-single-document), but starts with:
+Started with [`RemoteDocumentSigning`](lib/ui/remote_document_signing.dart).
+It's similar to [Sign single document](#sign-single-document), but starts with:
- [`StartRemoteDocumentSigningScreen`](lib/ui/screens/start_remote_document_signing_screen.dart)
- [`QRCodeScannerScreen`](lib/ui/screens/qr_code_scanner_screen.dart)
-## Scripts
+### Scripts
FVM init and Pub get:
@@ -110,7 +125,7 @@ Build **WEB**:
fvm flutter build web --target=lib/preview.dart
```
-## Identifiers and links
+### Identifiers and links
- Android Application ID, [Apple Bundle/App ID](https://developer.apple.com/account/resources/identifiers/bundleId/edit/832594XXZD): `digital.slovensko.avm`
- Apple Team ID: `44U4JSRX4Z` (Služby Slovensko.Digital, s.r.o.)
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 2955684..be42fcb 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -57,11 +57,18 @@ android {
}
}
+ signingConfigs {
+ release {
+ storeFile file(System.getenv("AVM_KEYSTORE_FILE"))
+ storePassword System.getenv("AVM_KEYSTORE_PASSWORD")
+ keyAlias System.getenv("AVM_KEY_ALIAS")
+ keyPassword System.getenv("AVM_KEY_PASSWORD")
+ }
+ }
+
buildTypes {
release {
- // TODO: Add your own signing config for the release build.
- // Signing with the debug keys for now, so `flutter run --release` works.
- signingConfig signingConfigs.debug
+ signingConfig signingConfigs.release
}
}
}
diff --git a/android/app/src/main/ic_launcher-playstore.png b/android/app/src/main/ic_launcher-playstore.png
index 9b80e81..62440ff 100644
Binary files a/android/app/src/main/ic_launcher-playstore.png and b/android/app/src/main/ic_launcher-playstore.png differ
diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml
index f74085f..1a85d7d 100644
--- a/android/app/src/main/res/drawable-v21/launch_background.xml
+++ b/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -9,4 +9,4 @@
android:gravity="center"
android:src="@mipmap/launch_image" />
-->
-
+
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml
index 5d1844a..92ea0d6 100644
--- a/android/app/src/main/res/drawable/ic_launcher_background.xml
+++ b/android/app/src/main/res/drawable/ic_launcher_background.xml
@@ -1,21 +1,9 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/android/app/src/main/res/drawable/ic_launcher_foreground.xml b/android/app/src/main/res/drawable/ic_launcher_foreground.xml
index e0a605a..c7ef6c6 100644
--- a/android/app/src/main/res/drawable/ic_launcher_foreground.xml
+++ b/android/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -1,17 +1,19 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
index 304732f..f0bf5d4 100644
--- a/android/app/src/main/res/drawable/launch_background.xml
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -9,4 +9,4 @@
android:gravity="center"
android:src="@mipmap/launch_image" />
-->
-
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index d3f33eb..bbd3e02 100644
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,5 +1,5 @@
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index d3f33eb..bbd3e02 100644
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,5 +1,5 @@
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
index 96576d2..217f23c 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
index ae082ca..3707fa9 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
index 4371585..4b06629 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
index 0f20191..1fde131 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index 2645e6c..a8c0e95 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
index 5e08a66..e2fd64b 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index f44e8fd..486bab1 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index e9083a3..15c98e1 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index d0aa0ba..378dec1 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index 7ff15a5..5e97ce9 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 5276798..3551f10 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -481,11 +481,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
VALIDATE_PRODUCT = YES;
};
name = Profile;
@@ -615,11 +615,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
};
name = Debug;
};
@@ -664,13 +664,13 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
VALIDATE_PRODUCT = YES;
};
name = Release;
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
index d36b1fa..b31b083 100644
--- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -1,122 +1,116 @@
{
"images" : [
{
- "size" : "20x20",
+ "filename" : "Ikonka-20@2x.png",
"idiom" : "iphone",
- "filename" : "Icon-App-20x20@2x.png",
- "scale" : "2x"
+ "scale" : "2x",
+ "size" : "20x20"
},
{
- "size" : "20x20",
+ "filename" : "Ikonka-20@3x.png",
"idiom" : "iphone",
- "filename" : "Icon-App-20x20@3x.png",
- "scale" : "3x"
+ "scale" : "3x",
+ "size" : "20x20"
},
{
- "size" : "29x29",
+ "filename" : "Ikonka-29@2x.png",
"idiom" : "iphone",
- "filename" : "Icon-App-29x29@1x.png",
- "scale" : "1x"
+ "scale" : "2x",
+ "size" : "29x29"
},
{
- "size" : "29x29",
+ "filename" : "Ikonka-29@3x.png",
"idiom" : "iphone",
- "filename" : "Icon-App-29x29@2x.png",
- "scale" : "2x"
+ "scale" : "3x",
+ "size" : "29x29"
},
{
- "size" : "29x29",
+ "filename" : "Ikonka-40@2x.png",
"idiom" : "iphone",
- "filename" : "Icon-App-29x29@3x.png",
- "scale" : "3x"
+ "scale" : "2x",
+ "size" : "40x40"
},
{
- "size" : "40x40",
+ "filename" : "Ikonka-40@3x.png",
"idiom" : "iphone",
- "filename" : "Icon-App-40x40@2x.png",
- "scale" : "2x"
+ "scale" : "3x",
+ "size" : "40x40"
},
{
- "size" : "40x40",
+ "filename" : "Ikonka-60@2x.png",
"idiom" : "iphone",
- "filename" : "Icon-App-40x40@3x.png",
- "scale" : "3x"
+ "scale" : "2x",
+ "size" : "60x60"
},
{
- "size" : "60x60",
+ "filename" : "Ikonka-60@3x.png",
"idiom" : "iphone",
- "filename" : "Icon-App-60x60@2x.png",
- "scale" : "2x"
+ "scale" : "3x",
+ "size" : "60x60"
},
{
- "size" : "60x60",
- "idiom" : "iphone",
- "filename" : "Icon-App-60x60@3x.png",
- "scale" : "3x"
- },
- {
- "size" : "20x20",
+ "filename" : "Ikonka-20.png",
"idiom" : "ipad",
- "filename" : "Icon-App-20x20@1x.png",
- "scale" : "1x"
+ "scale" : "1x",
+ "size" : "20x20"
},
{
- "size" : "20x20",
+ "filename" : "Ikonka-20@2x.png",
"idiom" : "ipad",
- "filename" : "Icon-App-20x20@2x.png",
- "scale" : "2x"
+ "scale" : "2x",
+ "size" : "20x20"
},
{
- "size" : "29x29",
+ "filename" : "Ikonka-29.png",
"idiom" : "ipad",
- "filename" : "Icon-App-29x29@1x.png",
- "scale" : "1x"
+ "scale" : "1x",
+ "size" : "29x29"
},
{
- "size" : "29x29",
+ "filename" : "Ikonka-29@2x.png",
"idiom" : "ipad",
- "filename" : "Icon-App-29x29@2x.png",
- "scale" : "2x"
+ "scale" : "2x",
+ "size" : "29x29"
},
{
- "size" : "40x40",
+ "filename" : "Ikonka-40.png",
"idiom" : "ipad",
- "filename" : "Icon-App-40x40@1x.png",
- "scale" : "1x"
+ "scale" : "1x",
+ "size" : "40x40"
},
{
- "size" : "40x40",
+ "filename" : "Ikonka-40@2x.png",
"idiom" : "ipad",
- "filename" : "Icon-App-40x40@2x.png",
- "scale" : "2x"
+ "scale" : "2x",
+ "size" : "40x40"
},
{
- "size" : "76x76",
+ "filename" : "Ikonka-76.png",
"idiom" : "ipad",
- "filename" : "Icon-App-76x76@1x.png",
- "scale" : "1x"
+ "scale" : "1x",
+ "size" : "76x76"
},
{
- "size" : "76x76",
+ "filename" : "Ikonka-76@2x.png",
"idiom" : "ipad",
- "filename" : "Icon-App-76x76@2x.png",
- "scale" : "2x"
+ "scale" : "2x",
+ "size" : "76x76"
},
{
- "size" : "83.5x83.5",
+ "filename" : "Ikonka-83.5@2x.png",
"idiom" : "ipad",
- "filename" : "Icon-App-83.5x83.5@2x.png",
- "scale" : "2x"
+ "scale" : "2x",
+ "size" : "83.5x83.5"
},
{
- "size" : "1024x1024",
+ "filename" : "Ikonka-1024.png",
"idiom" : "ios-marketing",
- "filename" : "Icon-App-1024x1024@1x.png",
- "scale" : "1x"
+ "scale" : "1x",
+ "size" : "1024x1024"
}
],
"info" : {
- "version" : 1,
- "author" : "xcode"
+ "author" : "xcode",
+ "version" : 1
}
}
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
deleted file mode 100644
index ea53eaf..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
deleted file mode 100644
index d0416ef..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
deleted file mode 100644
index 6456dba..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
deleted file mode 100644
index d65d47a..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
deleted file mode 100644
index ee33af0..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
deleted file mode 100644
index f620265..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
deleted file mode 100644
index ab76cc4..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
deleted file mode 100644
index 6456dba..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
deleted file mode 100644
index a05d77c..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
deleted file mode 100644
index 3e1dbc3..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
deleted file mode 100644
index 3e1dbc3..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
deleted file mode 100644
index b25f74c..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
deleted file mode 100644
index 3692e81..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
deleted file mode 100644
index ff1666e..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
deleted file mode 100644
index ca7c76d..0000000
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-1024.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-1024.png
new file mode 100644
index 0000000..e6adc40
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-1024.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-20.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-20.png
new file mode 100644
index 0000000..026aa6b
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-20.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-20@2x.png
new file mode 100644
index 0000000..988cad8
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-20@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-20@3x.png
new file mode 100644
index 0000000..7bb6b1e
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-20@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-29.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-29.png
new file mode 100644
index 0000000..ca91dd0
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-29.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-29@2x.png
new file mode 100644
index 0000000..8894bf1
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-29@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-29@3x.png
new file mode 100644
index 0000000..27f72b4
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-29@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-40.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-40.png
new file mode 100644
index 0000000..988cad8
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-40.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-40@2x.png
new file mode 100644
index 0000000..64cc42e
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-40@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-40@3x.png
new file mode 100644
index 0000000..ad9bd99
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-40@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-60@2x.png
new file mode 100644
index 0000000..ad9bd99
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-60@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-60@3x.png
new file mode 100644
index 0000000..ab6b655
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-60@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-76.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-76.png
new file mode 100644
index 0000000..54032f2
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-76.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-76@2x.png
new file mode 100644
index 0000000..6186eb9
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-76@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-83.5@2x.png
new file mode 100644
index 0000000..57eef8a
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Ikonka-83.5@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/Contents.json b/ios/Runner/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/lib/bloc/get_document_signature_type_cubit.dart b/lib/bloc/get_document_signature_type_cubit.dart
new file mode 100644
index 0000000..2c9045b
--- /dev/null
+++ b/lib/bloc/get_document_signature_type_cubit.dart
@@ -0,0 +1,45 @@
+import 'package:flutter_bloc/flutter_bloc.dart' show Cubit;
+import 'package:injectable/injectable.dart';
+import 'package:logging/logging.dart';
+
+import '../data/signature_type.dart';
+import '../use_case/get_document_signature_type_use_case.dart';
+import 'get_document_signature_type_state.dart';
+
+export 'get_document_signature_type_state.dart';
+
+/// Cubit to get the Document [SignatureType].
+@injectable
+class GetDocumentSignatureTypeCubit
+ extends Cubit {
+ static final _log = Logger((GetDocumentSignatureTypeCubit).toString());
+
+ final GetDocumentSignatureTypeUseCase _getDocumentSignatureType;
+
+ GetDocumentSignatureTypeCubit({
+ required GetDocumentSignatureTypeUseCase getDocumentSignatureType,
+ }) : _getDocumentSignatureType = getDocumentSignatureType,
+ super(const GetDocumentSignatureTypeInitialState());
+
+ /// Sets the [signatureType] directly.
+ void setSignatureType(SignatureType? signatureType) {
+ emit(GetDocumentSignatureTypeSuccessState(signatureType));
+ }
+
+ /// Gets the Document [SignatureType].
+ Future getDocumentSignatureType(String documentId) async {
+ emit(const GetDocumentSignatureTypeLoadingState());
+
+ try {
+ final signatureType = await _getDocumentSignatureType(documentId);
+
+ _log.info("Got Document SignatureType: ${signatureType?.name}.");
+
+ emit(GetDocumentSignatureTypeSuccessState(signatureType));
+ } catch (error, stackTrace) {
+ _log.severe("Error getting Document SignatureType.", error, stackTrace);
+
+ emit(GetDocumentSignatureTypeErrorState(error));
+ }
+ }
+}
diff --git a/lib/bloc/get_document_signature_type_state.dart b/lib/bloc/get_document_signature_type_state.dart
new file mode 100644
index 0000000..202b3be
--- /dev/null
+++ b/lib/bloc/get_document_signature_type_state.dart
@@ -0,0 +1,42 @@
+import 'package:flutter/foundation.dart' show immutable;
+
+import '../data/signature_type.dart';
+import 'get_document_signature_type_cubit.dart';
+
+/// State for [GetDocumentSignatureTypeCubit].
+@immutable
+sealed class GetDocumentSignatureTypeState {
+ const GetDocumentSignatureTypeState();
+
+ @override
+ String toString() => "$runtimeType()";
+}
+
+class GetDocumentSignatureTypeInitialState
+ extends GetDocumentSignatureTypeState {
+ const GetDocumentSignatureTypeInitialState();
+}
+
+class GetDocumentSignatureTypeLoadingState
+ extends GetDocumentSignatureTypeState {
+ const GetDocumentSignatureTypeLoadingState();
+}
+
+class GetDocumentSignatureTypeErrorState extends GetDocumentSignatureTypeState {
+ final Object error;
+
+ const GetDocumentSignatureTypeErrorState(this.error);
+
+ @override
+ String toString() => "$runtimeType(error: $error)";
+}
+
+class GetDocumentSignatureTypeSuccessState
+ extends GetDocumentSignatureTypeState {
+ final SignatureType? signatureType;
+
+ const GetDocumentSignatureTypeSuccessState(this.signatureType);
+
+ @override
+ String toString() => "$runtimeType(signatureType: $signatureType)";
+}
diff --git a/lib/bloc/select_signing_certificate_cubit.dart b/lib/bloc/select_signing_certificate_cubit.dart
index 5f6641f..58b8634 100644
--- a/lib/bloc/select_signing_certificate_cubit.dart
+++ b/lib/bloc/select_signing_certificate_cubit.dart
@@ -15,7 +15,7 @@ export 'select_signing_certificate_state.dart';
@injectable
class SelectSigningCertificateCubit
extends Cubit {
- static final _log = Logger("SelectCertificateCubit");
+ static final _log = Logger((SelectSigningCertificateCubit).toString());
static const _defaultLanguage = 'sk';
final Eidmsdk _eidmsdk;
diff --git a/lib/bloc/select_signing_certificate_state.dart b/lib/bloc/select_signing_certificate_state.dart
index 1f31ed5..16142aa 100644
--- a/lib/bloc/select_signing_certificate_state.dart
+++ b/lib/bloc/select_signing_certificate_state.dart
@@ -8,25 +8,20 @@ import 'select_signing_certificate_cubit.dart';
sealed class SelectSigningCertificateState {
const SelectSigningCertificateState();
- SelectSigningCertificateLoadingState toLoading() {
- return const SelectSigningCertificateLoadingState();
- }
+ SelectSigningCertificateLoadingState toLoading() =>
+ const SelectSigningCertificateLoadingState();
- SelectSigningCertificateErrorState toError(Object error) {
- return SelectSigningCertificateErrorState(error);
- }
+ SelectSigningCertificateErrorState toError(Object error) =>
+ SelectSigningCertificateErrorState(error);
- SelectSigningCertificateSuccessState toSuccess(Certificate certificate) {
- return SelectSigningCertificateSuccessState(certificate);
- }
+ SelectSigningCertificateSuccessState toSuccess(Certificate certificate) =>
+ SelectSigningCertificateSuccessState(certificate);
- SelectSigningCertificateCanceledState toCanceled() {
- return const SelectSigningCertificateCanceledState();
- }
+ SelectSigningCertificateCanceledState toCanceled() =>
+ const SelectSigningCertificateCanceledState();
- SelectSigningCertificateNoCertificateState toNoCertificate() {
- return const SelectSigningCertificateNoCertificateState();
- }
+ SelectSigningCertificateNoCertificateState toNoCertificate() =>
+ const SelectSigningCertificateNoCertificateState();
@override
String toString() {
diff --git a/lib/data/settings.dart b/lib/data/settings.dart
index 99845db..16340c7 100644
--- a/lib/data/settings.dart
+++ b/lib/data/settings.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+
import 'package:eidmsdk/types.dart';
import 'package:flutter/foundation.dart';
import 'package:notified_preferences/notified_preferences.dart';
@@ -5,8 +7,8 @@ import 'package:notified_preferences/notified_preferences.dart';
import 'pdf_signing_option.dart';
import 'signature_type.dart';
-/// Interface for general app settings.
-abstract interface class ISettings {
+/// General app settings.
+abstract interface class Settings {
/// Accepted Privacy Policy document version value.
ValueNotifier get acceptedPrivacyPolicyVersion;
@@ -22,16 +24,27 @@ abstract interface class ISettings {
/// The signing [SignatureType] value.
ValueNotifier get signatureType;
+ /// Whether passed onboarding screen for "Remote Document Signing" feature.
+ ValueNotifier get remoteDocumentSigningOnboardingPassed;
+
/// Clear all setting.
Future clear();
+
+ /// Creates and returns new [Settings].
+ static Future create([
+ FutureOr? preferences,
+ ]) async {
+ final settings = _SettingsImpl();
+ await settings.initialize(preferences);
+
+ return settings;
+ }
}
-/// General app settings.
-///
-/// Uses **Shared Preferences** - need to call [Settings.initialize] before use.
-// TODO Make only "Settings" type and private _SettingsImpl that will be returned by factory fun
-// TODO Also register it using Injectable
-class Settings with NotifiedPreferences implements ISettings {
+/// [Settings] implementation that uses [SharedPreferences].
+/// Note, [clear] is from [NotifiedPreferences].
+// TODO Register Settings using Injectable as singleton - would need to pass instance into DI so no need to use "async"
+class _SettingsImpl with NotifiedPreferences implements Settings {
@override
late final ValueNotifier acceptedPrivacyPolicyVersion =
createSetting(
@@ -57,7 +70,7 @@ class Settings with NotifiedPreferences implements ISettings {
@override
late final ValueNotifier signatureType = createEnumSetting(
key: 'signing.signatureType',
- initialValue: SignatureType.unset,
+ initialValue: SignatureType.withoutTimestamp,
values: SignatureType.values,
);
@@ -68,4 +81,11 @@ class Settings with NotifiedPreferences implements ISettings {
initialValue: null,
fromJson: (json) => Certificate.fromJson(json),
);
+
+ @override
+ late final ValueNotifier remoteDocumentSigningOnboardingPassed =
+ createSetting(
+ key: "onboarding.remoteDocumentSigning.passed",
+ initialValue: false,
+ );
}
diff --git a/lib/deep_links.dart b/lib/deep_links.dart
index 4186a24..94c2180 100644
--- a/lib/deep_links.dart
+++ b/lib/deep_links.dart
@@ -31,12 +31,12 @@ DeepLinkAction parseDeepLinkAction(Uri uri) {
"/api/v1/qr-code" => () {
if (!uri.queryParameters.containsKey("guid")) {
throw ArgumentError.value(
- uri.toString(), "uri", "'guid' param is missing value.");
+ uri.toString(), "uri", '"guid" param is missing a value.');
}
if (!uri.queryParameters.containsKey("key")) {
throw ArgumentError.value(
- uri.toString(), "uri", "'key' param is missing value.");
+ uri.toString(), "uri", '"key" param is missing a value.');
}
return SignRemoteDocumentAction(
diff --git a/lib/di.config.dart b/lib/di.config.dart
index 71ecf93..2fc7be1 100644
--- a/lib/di.config.dart
+++ b/lib/di.config.dart
@@ -20,14 +20,16 @@ import 'package:injectable/injectable.dart' as _i2;
import 'app_service.dart' as _i3;
import 'bloc/create_document_cubit.dart' as _i15;
+import 'bloc/get_document_signature_type_cubit.dart' as _i20;
import 'bloc/paired_device_list_cubit.dart' as _i8;
import 'bloc/present_signed_document_cubit.dart' as _i9;
import 'bloc/preview_document_cubit.dart' as _i10;
import 'bloc/select_signing_certificate_cubit.dart' as _i11;
import 'bloc/sign_document_cubit.dart' as _i14;
import 'data/pdf_signing_option.dart' as _i18;
-import 'di.dart' as _i19;
+import 'di.dart' as _i21;
import 'services/encryption_key_registry.dart' as _i5;
+import 'use_case/get_document_signature_type_use_case.dart' as _i19;
import 'use_case/get_document_version_use_case.dart' as _i6;
extension GetItInjectableX on _i1.GetIt {
@@ -45,8 +47,8 @@ extension GetItInjectableX on _i1.GetIt {
gh.singleton<_i3.AppService>(() => _i3.AppService());
gh.lazySingleton<_i4.Eidmsdk>(() => extrernalModule.eidmsdk);
gh.singleton<_i5.EncryptionKeyRegistry>(() => _i5.EncryptionKeyRegistry());
- gh.lazySingleton<_i6.GetDocumentVersionUseCase>(
- () => _i6.GetDocumentVersionUseCase());
+ gh.lazySingleton<_i6.GetHtmlDocumentVersionUseCase>(
+ () => _i6.GetHtmlDocumentVersionUseCase());
gh.lazySingleton<_i7.IAutogramService>(
() => extrernalModule.create(gh<_i5.EncryptionKeyRegistry>()));
gh.factory<_i8.PairedDeviceListCubit>(
@@ -97,11 +99,17 @@ extension GetItInjectableX on _i1.GetIt {
file: file,
pdfSigningOption: pdfSigningOption,
));
+ gh.lazySingleton<_i19.GetDocumentSignatureTypeUseCase>(
+ () => _i19.GetDocumentSignatureTypeUseCase(gh<_i7.IAutogramService>()));
+ gh.factory<_i20.GetDocumentSignatureTypeCubit>(() =>
+ _i20.GetDocumentSignatureTypeCubit(
+ getDocumentSignatureType:
+ gh<_i19.GetDocumentSignatureTypeUseCase>()));
return this;
}
}
-class _$ExtrernalModule extends _i19.ExtrernalModule {
+class _$ExtrernalModule extends _i21.ExtrernalModule {
@override
_i4.Eidmsdk get eidmsdk => _i4.Eidmsdk();
}
diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart
index 170ff77..cf01787 100644
--- a/lib/l10n/app_localizations.dart
+++ b/lib/l10n/app_localizations.dart
@@ -271,6 +271,12 @@ abstract class AppLocalizations {
/// **'Podpisovanie PDF'**
String get signingPdfContainerTitle;
+ /// No description provided for @signatureTypeErrorHeading.
+ ///
+ /// In sk, this message translates to:
+ /// **'Chyba pri načítaní parametrov podpisu'**
+ String get signatureTypeErrorHeading;
+
/// No description provided for @signatureTypeTitle.
///
/// In sk, this message translates to:
@@ -346,9 +352,15 @@ abstract class AppLocalizations {
/// No description provided for @eidSDKLicenseText.
///
/// In sk, this message translates to:
- /// **'Na komunikáciu s čipom občianskeho preukazu je použitá knižnica eID mSDK od Ministerstva vnútra Slovenskej republiky. Knižnica eID mSDK a podmienky jej použitia sú zverejnené na stránke\n„https://github.com/eidmsdk“.'**
+ /// **'Na komunikáciu s čipom občianskeho preukazu je použitá knižnica eID mSDK od Ministerstva vnútra Slovenskej republiky. Knižnica eID mSDK a podmienky jej použitia sú zverejnené na stránke „https://github.com/eidmsdk“'**
String get eidSDKLicenseText;
+ /// No description provided for @aboutAuthorsText.
+ ///
+ /// In sk, this message translates to:
+ /// **'Autormi tohto projektu sú freevision s.r.o., Služby Slovensko.Digital, s.r.o. a ďalší dobrovoľníci. Prevádzku zabezpečuje Služby Slovensko.Digital, s.r.o. Zdrojové kódy sú dpstupné na GitHub-e organizácie Slovensko.Digital.'**
+ String get aboutAuthorsText;
+
/// No description provided for @thirdPartyLicensesLabel.
///
/// In sk, this message translates to:
@@ -394,13 +406,13 @@ abstract class AppLocalizations {
/// No description provided for @signRemoteDocumentBody1.
///
/// In sk, this message translates to:
- /// **'Mobilom môžete podpisovať aj dokumenty nachádzajúce sa vo vašom počítači, či v informačnom systéme pomocou rozšírenia Autogramu vo vašom internetovom prehladávači.'**
+ /// **'Mobilom môžete podpisovať aj dokumenty nachádzajúce sa vo vašom počítači, či v informačnom systéme pomocou rozšírenia “Autogram na štátnych weboch“ vo vašom internetovom prehladávači.'**
String get signRemoteDocumentBody1;
/// No description provided for @signRemoteDocumentBody2.
///
/// In sk, this message translates to:
- /// **'1. Pri podpisovaní v internetovom prehliadači vo vašom počítači vyberte možnosť “podísať v mobile”.\n2. Telefónom naskenujte QR kód z vášho počítača.'**
+ /// **'1. Pri podpisovaní v internetovom prehliadači vo vašom počítači vyberte možnosť “Podpísať mobilom”.\n2. Telefónom naskenujte QR kód z vášho počítača.'**
String get signRemoteDocumentBody2;
/// No description provided for @openDocumentTitle.
@@ -421,11 +433,11 @@ abstract class AppLocalizations {
/// **'Náhľad dokumentu'**
String get previewDocumentTitle;
- /// No description provided for @previewDocumentErrorTitle.
+ /// No description provided for @previewDocumentErrorHeading.
///
/// In sk, this message translates to:
/// **'Chyba pri načítaní vizualizácie dokumentu'**
- String get previewDocumentErrorTitle;
+ String get previewDocumentErrorHeading;
/// No description provided for @shareDocumentText.
///
@@ -454,7 +466,7 @@ abstract class AppLocalizations {
/// No description provided for @selectSigningCertificateBody.
///
/// In sk, this message translates to:
- /// **'Na podpisovanie mobilom potrebujete disponovať vhodným podpisovým certifikátom. Ak si prajete iba overiť podpisy v dokumentoch, tento krok je nepovinný a môžete ho preskočiť. Podpisový certifikát si môžete nastaviť neskôr počas podpisovania prvého dokumentu.\n\n\nAk si prajete nastaviť podpisový certifikát, pripravte si prosím občiansky preukaz a nasledujte inštrukcie na obrazovke.'**
+ /// **'Na podpisovanie mobilom potrebujete disponovať vhodným podpisovým certifikátom. Podpisový certifikát si môžete nastaviť aj neskôr počas podpisovania prvého dokumentu.\n\n\nAk si prajete nastaviť podpisový certifikát teraz, pripravte si, prosím, občiansky preukaz a nasledujte inštrukcie na obrazovke.'**
String get selectSigningCertificateBody;
/// No description provided for @selectSigningCertificateCanceledHeading.
@@ -478,7 +490,7 @@ abstract class AppLocalizations {
/// No description provided for @selectSigningCertificateNoCertificateBody.
///
/// In sk, this message translates to:
- /// **'Nepodarilo sa nájsť certifikát pre kvalifikovaný elektronický podpis.\n\nCertifikát je potrebné vydať v aplikácii eID, prípadne použiť iný občiansky preukaz.\nNávod na vydanie certifikátu nájdete na '**
+ /// **'Nepodarilo sa nájsť certifikát pre kvalifikovaný elektronický podpis.\n\nCertifikát je potrebné vydať v aplikácii eID klient, prípadne použiť iný občiansky preukaz.\nNávod na vydanie certifikátu nájdete na '**
String get selectSigningCertificateNoCertificateBody;
/// No description provided for @selectSigningCertificateNoCertificateGuideUrl.
diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart
index 6d95bb8..82acb06 100644
--- a/lib/l10n/app_localizations_sk.dart
+++ b/lib/l10n/app_localizations_sk.dart
@@ -102,6 +102,9 @@ class AppLocalizationsSk extends AppLocalizations {
@override
String get signingPdfContainerTitle => 'Podpisovanie PDF';
+ @override
+ String get signatureTypeErrorHeading => 'Chyba pri načítaní parametrov podpisu';
+
@override
String get signatureTypeTitle => 'Predvolený typ podpisu';
@@ -179,7 +182,10 @@ class AppLocalizationsSk extends AppLocalizations {
String get aboutTitle => 'O aplikácii';
@override
- String get eidSDKLicenseText => 'Na komunikáciu s čipom občianskeho preukazu je použitá knižnica eID mSDK od Ministerstva vnútra Slovenskej republiky. Knižnica eID mSDK a podmienky jej použitia sú zverejnené na stránke\n„https://github.com/eidmsdk“.';
+ String get eidSDKLicenseText => 'Na komunikáciu s čipom občianskeho preukazu je použitá knižnica eID mSDK od Ministerstva vnútra Slovenskej republiky. Knižnica eID mSDK a podmienky jej použitia sú zverejnené na stránke „https://github.com/eidmsdk“';
+
+ @override
+ String get aboutAuthorsText => 'Autormi tohto projektu sú freevision s.r.o., Služby Slovensko.Digital, s.r.o. a ďalší dobrovoľníci. Prevádzku zabezpečuje Služby Slovensko.Digital, s.r.o. Zdrojové kódy sú dpstupné na GitHub-e organizácie Slovensko.Digital.';
@override
String get thirdPartyLicensesLabel => 'Licencie knižníc tretích strán';
@@ -203,10 +209,10 @@ class AppLocalizationsSk extends AppLocalizations {
String get qrCodeScannerUnsupportedContentErrorMessage => 'Naskenovali ste nepodporovaný alebo neznámy obsah QR kódu.';
@override
- String get signRemoteDocumentBody1 => 'Mobilom môžete podpisovať aj dokumenty nachádzajúce sa vo vašom počítači, či v informačnom systéme pomocou rozšírenia Autogramu vo vašom internetovom prehladávači.';
+ String get signRemoteDocumentBody1 => 'Mobilom môžete podpisovať aj dokumenty nachádzajúce sa vo vašom počítači, či v informačnom systéme pomocou rozšírenia “Autogram na štátnych weboch“ vo vašom internetovom prehladávači.';
@override
- String get signRemoteDocumentBody2 => '1. Pri podpisovaní v internetovom prehliadači vo vašom počítači vyberte možnosť “podísať v mobile”.\n2. Telefónom naskenujte QR kód z vášho počítača.';
+ String get signRemoteDocumentBody2 => '1. Pri podpisovaní v internetovom prehliadači vo vašom počítači vyberte možnosť “Podpísať mobilom”.\n2. Telefónom naskenujte QR kód z vášho počítača.';
@override
String get openDocumentTitle => 'Otváranie dokumentu';
@@ -218,7 +224,7 @@ class AppLocalizationsSk extends AppLocalizations {
String get previewDocumentTitle => 'Náhľad dokumentu';
@override
- String get previewDocumentErrorTitle => 'Chyba pri načítaní vizualizácie dokumentu';
+ String get previewDocumentErrorHeading => 'Chyba pri načítaní vizualizácie dokumentu';
@override
String get shareDocumentText => '\n\nSúbor z aplikácie Autogram v mobile';
@@ -235,7 +241,7 @@ class AppLocalizationsSk extends AppLocalizations {
String get selectSigningCertificateTitle => 'Nastavenie certifikátu';
@override
- String get selectSigningCertificateBody => 'Na podpisovanie mobilom potrebujete disponovať vhodným podpisovým certifikátom. Ak si prajete iba overiť podpisy v dokumentoch, tento krok je nepovinný a môžete ho preskočiť. Podpisový certifikát si môžete nastaviť neskôr počas podpisovania prvého dokumentu.\n\n\nAk si prajete nastaviť podpisový certifikát, pripravte si prosím občiansky preukaz a nasledujte inštrukcie na obrazovke.';
+ String get selectSigningCertificateBody => 'Na podpisovanie mobilom potrebujete disponovať vhodným podpisovým certifikátom. Podpisový certifikát si môžete nastaviť aj neskôr počas podpisovania prvého dokumentu.\n\n\nAk si prajete nastaviť podpisový certifikát teraz, pripravte si, prosím, občiansky preukaz a nasledujte inštrukcie na obrazovke.';
@override
String get selectSigningCertificateCanceledHeading => 'Čítanie certifikátu bolo prerušené';
@@ -247,7 +253,7 @@ class AppLocalizationsSk extends AppLocalizations {
String get selectSigningCertificateNoCertificateHeading => 'Certifikát nebol nájdený';
@override
- String get selectSigningCertificateNoCertificateBody => 'Nepodarilo sa nájsť certifikát pre kvalifikovaný elektronický podpis.\n\nCertifikát je potrebné vydať v aplikácii eID, prípadne použiť iný občiansky preukaz.\nNávod na vydanie certifikátu nájdete na ';
+ String get selectSigningCertificateNoCertificateBody => 'Nepodarilo sa nájsť certifikát pre kvalifikovaný elektronický podpis.\n\nCertifikát je potrebné vydať v aplikácii eID klient, prípadne použiť iný občiansky preukaz.\nNávod na vydanie certifikátu nájdete na ';
@override
String get selectSigningCertificateNoCertificateGuideUrl => 'https://navody.digital/zivotne-situacie/aktivacia-eid/krok/certifikaty';
diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb
index 75b11d6..29870f6 100644
--- a/lib/l10n/app_sk.arb
+++ b/lib/l10n/app_sk.arb
@@ -34,6 +34,7 @@
"signRemoteDocumentTitle": "Podpísať vzdialený dokument",
"aboutLabel": "O aplikácii",
"signingPdfContainerTitle": "Podpisovanie PDF",
+ "signatureTypeErrorHeading": "Chyba pri načítaní parametrov podpisu",
"signatureTypeTitle": "Predvolený typ podpisu",
"signatureTypeSummary": "{name, select, withoutTimestamp {Vlastnoručný podpis} withTimestamp {Osvedčený podpis} other {Spýtať sa pri podpisovaní}}",
"signatureTypeValueTitle": "{name, select, withoutTimestamp {Vlastnoručný podpis} withTimestamp {Osvedčený podpis} other {-}}",
@@ -47,7 +48,8 @@
"termsOfServiceUrl": "https://sluzby.slovensko.digital/autogram-v-mobile/vseobecne-obchodne-podmienky",
"aboutTitle": "O aplikácii",
- "eidSDKLicenseText": "Na komunikáciu s čipom občianskeho preukazu je použitá knižnica eID mSDK od Ministerstva vnútra Slovenskej republiky. Knižnica eID mSDK a podmienky jej použitia sú zverejnené na\u00A0stránke\n„https://github.com/eidmsdk“.",
+ "eidSDKLicenseText": "Na komunikáciu s čipom občianskeho preukazu je použitá knižnica eID mSDK od Ministerstva vnútra Slovenskej republiky. Knižnica eID mSDK a podmienky jej použitia sú zverejnené na\u00A0stránke „https://github.com/eidmsdk“",
+ "aboutAuthorsText": "Autormi tohto projektu sú freevision\u00A0s.r.o., Služby\u00A0Slovensko.Digital,\u00A0s.r.o. a ďalší dobrovoľníci. Prevádzku zabezpečuje Služby\u00A0Slovensko.Digital,\u00A0s.r.o. Zdrojové kódy sú dpstupné na GitHub-e organizácie Slovensko.Digital.",
"thirdPartyLicensesLabel": "Licencie knižníc tretích strán",
"introHeading": "Nový, lepší a krajší podpisovač v mobile",
@@ -59,25 +61,25 @@
"qrCodeScannerInfoBody": "Prosím nasmerujte kameru\nna QR kód na obrazovke",
"qrCodeScannerUnsupportedContentErrorMessage": "Naskenovali ste nepodporovaný alebo neznámy obsah QR kódu.",
- "signRemoteDocumentBody1": "Mobilom môžete podpisovať aj dokumenty nachádzajúce sa vo vašom počítači, či v informačnom systéme pomocou rozšírenia Autogramu vo vašom internetovom prehladávači.",
- "signRemoteDocumentBody2": "1. Pri podpisovaní v internetovom prehliadači vo vašom počítači vyberte možnosť “podísať v mobile”.\n2. Telefónom naskenujte QR kód z vášho počítača.",
+ "signRemoteDocumentBody1": "Mobilom môžete podpisovať aj dokumenty nachádzajúce sa vo vašom počítači, či v informačnom systéme pomocou rozšírenia “Autogram na štátnych weboch“ vo vašom internetovom prehladávači.",
+ "signRemoteDocumentBody2": "1. Pri podpisovaní v internetovom prehliadači vo vašom počítači vyberte možnosť “Podpísať mobilom”.\n2. Telefónom naskenujte QR kód z vášho počítača.",
"openDocumentTitle": "Otváranie dokumentu",
"openDocumentErrorTitle": "Chyba pri vytváraní dokumentu",
"previewDocumentTitle": "Náhľad dokumentu",
- "previewDocumentErrorTitle": "Chyba pri načítaní vizualizácie dokumentu",
+ "previewDocumentErrorHeading": "Chyba pri načítaní vizualizácie dokumentu",
"shareDocumentText": "\n\nSúbor z aplikácie Autogram v mobile",
"documentVisualizationCannotVisualizeTypeError": "Neviem vizualizovať {type} typ.",
"selectCertificateTitle": "Výber typu podpisu",
"selectSigningCertificateTitle": "Nastavenie certifikátu",
- "selectSigningCertificateBody": "Na podpisovanie mobilom potrebujete disponovať vhodným podpisovým certifikátom. Ak si prajete iba overiť podpisy v dokumentoch, tento krok je nepovinný a môžete ho preskočiť. Podpisový certifikát si môžete nastaviť neskôr počas podpisovania prvého dokumentu.\n\n\nAk si prajete nastaviť podpisový certifikát, pripravte si prosím občiansky preukaz a nasledujte inštrukcie na obrazovke.",
+ "selectSigningCertificateBody": "Na podpisovanie mobilom potrebujete disponovať vhodným podpisovým certifikátom. Podpisový certifikát si môžete nastaviť aj neskôr počas podpisovania prvého dokumentu.\n\n\nAk si prajete nastaviť podpisový certifikát teraz, pripravte si, prosím, občiansky preukaz a nasledujte inštrukcie na obrazovke.",
"selectSigningCertificateCanceledHeading": "Čítanie certifikátu bolo prerušené",
"selectSigningCertificateCanceledBody": "Skúste prosím znovu načítať certifikát z vášho občianskeho preukazu.",
"selectSigningCertificateNoCertificateHeading": "Certifikát nebol nájdený",
- "selectSigningCertificateNoCertificateBody": "Nepodarilo sa nájsť certifikát pre kvalifikovaný elektronický podpis.\n\nCertifikát je potrebné vydať v aplikácii eID, prípadne použiť iný občiansky preukaz.\nNávod na vydanie certifikátu nájdete na ",
+ "selectSigningCertificateNoCertificateBody": "Nepodarilo sa nájsť certifikát pre kvalifikovaný elektronický podpis.\n\nCertifikát je potrebné vydať v aplikácii eID klient, prípadne použiť iný občiansky preukaz.\nNávod na vydanie certifikátu nájdete na ",
"selectSigningCertificateNoCertificateGuideUrl": "https://navody.digital/zivotne-situacie/aktivacia-eid/krok/certifikaty",
"selectSigningCertificateErrorHeading": "Chyba pri načítavaní certifikátov z občianskeho preukazu.",
diff --git a/lib/main.dart b/lib/main.dart
index 0cbe831..f2c70e6 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -27,15 +27,13 @@ void main() async {
configureDependencies();
// Init Settings
- final settings = Settings();
- await settings.initialize();
+ final settings = await Settings.create();
// Run App
runApp(
MultiProvider(
providers: [
- // ISettings
- Provider.value(value: settings),
+ Provider.value(value: settings),
],
child: const App(),
),
diff --git a/lib/ui/onboarding.dart b/lib/ui/onboarding.dart
index d05e8c9..0bba5a0 100644
--- a/lib/ui/onboarding.dart
+++ b/lib/ui/onboarding.dart
@@ -11,7 +11,7 @@ import 'screens/onboarding_select_signing_certificate_screen.dart';
/// Helper for Onboarding flow.
///
-/// Reads [ISettings].
+/// Reads [Settings].
///
/// Onboarding flow:
/// 1. Accept Privacy Policy - [OnboardingAcceptDocumentScreen]
@@ -26,7 +26,7 @@ abstract class Onboarding {
/// Refresh [onboardingRequired] value.
static void refreshOnboardingRequired(BuildContext context) {
- final settings = context.read();
+ final settings = context.read();
bool flag;
if (settings.acceptedPrivacyPolicyVersion.value == null) {
@@ -42,7 +42,7 @@ abstract class Onboarding {
/// Starts 1st Onboarding screen.
static Future startOnboarding(BuildContext context) {
- final settings = context.read();
+ final settings = context.read();
final strings = context.strings;
final screen = OnboardingAcceptDocumentScreen(
title: strings.privacyPolicyTitle,
@@ -69,7 +69,7 @@ abstract class Onboarding {
}
static void _handlePrivacyPolicyAccepted(BuildContext context) {
- final settings = context.read();
+ final settings = context.read();
final strings = context.strings;
final screen = OnboardingAcceptDocumentScreen(
title: strings.termsOfServiceTitle,
@@ -85,7 +85,7 @@ abstract class Onboarding {
}
static void _handleTermsOfServiceAccepted(BuildContext context) {
- final settings = context.read();
+ final settings = context.read();
final hasSigningCertificate = settings.signingCertificate.value != null;
final Widget screen;
diff --git a/lib/ui/remote_document_signing.dart b/lib/ui/remote_document_signing.dart
new file mode 100644
index 0000000..19dba95
--- /dev/null
+++ b/lib/ui/remote_document_signing.dart
@@ -0,0 +1,52 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import '../app_service.dart';
+import '../data/settings.dart';
+import '../di.dart';
+import 'onboarding.dart';
+import 'screens/qr_code_scanner_screen.dart';
+import 'screens/start_remote_document_signing_screen.dart';
+
+/// Helper for "Remote Document Signing" flow.
+///
+/// Reads and sets [Settings.remoteDocumentSigningOnboardingPassed].
+///
+/// And then displays:
+/// 1. When `false` - [StartRemoteDocumentSigningScreen]
+/// 2. When `true` - [QRCodeScannerScreen] directly
+///
+/// See also:
+/// - [Onboarding]
+abstract class RemoteDocumentSigning {
+ /// Starts 1st screen in this flow.
+ ///
+ /// When [forceReplace] is `true`, then [Navigator.pushReplacement] is used.
+ static Future startRemoteDocumentSigning(
+ BuildContext context, [
+ bool forceReplace = false,
+ ]) async {
+ final settings = context.read();
+ final onboardingPassed =
+ settings.remoteDocumentSigningOnboardingPassed.value;
+ Widget screen = onboardingPassed
+ ? const QRCodeScannerScreen()
+ : const StartRemoteDocumentSigningScreen();
+ final result = await _navigateToScreen(context, screen, forceReplace);
+
+ if (result is String) {
+ getIt.get().newIncomingUri(result);
+ }
+ }
+
+ static Future _navigateToScreen(
+ BuildContext context,
+ Widget screen, [
+ bool replace = false,
+ ]) {
+ final navigator = Navigator.of(context);
+ final route = MaterialPageRoute(builder: (_) => screen);
+
+ return replace ? navigator.pushReplacement(route) : navigator.push(route);
+ }
+}
diff --git a/lib/ui/screens/about_screen.dart b/lib/ui/screens/about_screen.dart
index 29a0f7d..08e5e8b 100644
--- a/lib/ui/screens/about_screen.dart
+++ b/lib/ui/screens/about_screen.dart
@@ -43,9 +43,10 @@ class _Body extends StatelessWidget {
),
const SizedBox(height: 16),
const AppVersionText(),
- const SizedBox(height: 64),
+ const SizedBox(height: 16),
+ Text(strings.aboutAuthorsText),
+ const SizedBox(height: 16),
Text(strings.eidSDKLicenseText),
- const SizedBox(height: 64),
const Spacer(),
TextButton(
style: TextButton.styleFrom(
diff --git a/lib/ui/screens/main_menu_screen.dart b/lib/ui/screens/main_menu_screen.dart
index 6f17d76..3e8e7b4 100644
--- a/lib/ui/screens/main_menu_screen.dart
+++ b/lib/ui/screens/main_menu_screen.dart
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;
import '../../strings_context.dart';
+import '../remote_document_signing.dart';
import '../widgets/app_version_text.dart';
import 'about_screen.dart';
import 'settings_screen.dart';
@@ -95,9 +96,8 @@ class MainMenuScreen extends StatelessWidget {
}
static Future _showSignRemoteDocument(BuildContext context) {
- const screen = StartRemoteDocumentSigningScreen();
-
- return _openScreen(context, screen);
+ // forceReplace=true so it's same as in _openScreen
+ return RemoteDocumentSigning.startRemoteDocumentSigning(context, true);
}
static Future _showPrivacyPolicy(BuildContext context) {
diff --git a/lib/ui/screens/main_screen.dart b/lib/ui/screens/main_screen.dart
index 26c99c4..6542592 100644
--- a/lib/ui/screens/main_screen.dart
+++ b/lib/ui/screens/main_screen.dart
@@ -18,6 +18,7 @@ import '../../services/encryption_key_registry.dart';
import '../../strings_context.dart';
import '../app_theme.dart';
import '../onboarding.dart';
+import '../remote_document_signing.dart';
import '../widgets/autogram_logo.dart';
import 'main_menu_screen.dart';
import 'open_document_screen.dart';
@@ -130,10 +131,7 @@ class _MainScreenState extends State {
}
Future _showQrCodeScanner() {
- const screen = StartRemoteDocumentSigningScreen();
- final route = MaterialPageRoute(builder: (_) => screen);
-
- return Navigator.of(context).push(route);
+ return RemoteDocumentSigning.startRemoteDocumentSigning(context);
}
Future _openNewFile(FutureOr file) {
diff --git a/lib/ui/screens/onboarding_accept_document_screen.dart b/lib/ui/screens/onboarding_accept_document_screen.dart
index 455fa5e..4dbcd46 100644
--- a/lib/ui/screens/onboarding_accept_document_screen.dart
+++ b/lib/ui/screens/onboarding_accept_document_screen.dart
@@ -18,7 +18,7 @@ import 'show_document_screen.dart';
/// [Onboarding] screen to accept document - Privacy Policy or Terms of Service.
///
-/// Uses [GetDocumentVersionUseCase].
+/// Uses [GetHtmlDocumentVersionUseCase].
///
/// See also:
/// - [ShowDocumentScreen]
@@ -103,7 +103,7 @@ class _OnboardingAcceptDocumentScreenState
}
void _onAccept() async {
- final getDocumentVersion = getIt.get();
+ final getDocumentVersion = getIt.get();
try {
setState(() {
@@ -143,10 +143,6 @@ class _OnboardingAcceptDocumentScreenState
type: OnboardingAcceptDocumentScreen,
)
Widget previewOnboardingAcceptDocumentScreen(BuildContext context) {
- getIt.registerLazySingleton(
- () => GetDocumentVersionUseCase(),
- );
-
final strings = context.strings;
final title = context.knobs.string(
label: "Title",
diff --git a/lib/ui/screens/onboarding_select_signing_certificate_screen.dart b/lib/ui/screens/onboarding_select_signing_certificate_screen.dart
index 6033cf1..8d6ce13 100644
--- a/lib/ui/screens/onboarding_select_signing_certificate_screen.dart
+++ b/lib/ui/screens/onboarding_select_signing_certificate_screen.dart
@@ -15,12 +15,12 @@ import '../widgets/loading_indicator.dart';
import '../widgets/step_indicator.dart';
/// [Onboarding] screen to select and save signing certificate into
-/// [ISettings.signingCertificate].
+/// [Settings.signingCertificate].
/// This screen can be skipped.
///
/// Uses [SelectSigningCertificateCubit].
///
-/// Consumes [ISettings].
+/// Consumes [Settings].
class OnboardingSelectSigningCertificateScreen extends StatelessWidget {
final ValueSetter onCertificateSelected;
final ValueSetter? onSkipRequested;
@@ -46,7 +46,7 @@ class OnboardingSelectSigningCertificateScreen extends StatelessWidget {
Widget _buildBody(BuildContext context) {
return BlocProvider(
create: (context) {
- final settings = context.read();
+ final settings = context.read();
final signingCertificate = settings.signingCertificate;
return GetIt.instance.get(
@@ -86,7 +86,7 @@ class OnboardingSelectSigningCertificateScreen extends StatelessWidget {
BuildContext context,
Certificate certificate,
) {
- context.read().signingCertificate.value = certificate;
+ context.read().signingCertificate.value = certificate;
onCertificateSelected.call(context);
}
}
diff --git a/lib/ui/screens/open_document_screen.dart b/lib/ui/screens/open_document_screen.dart
index 3287c3c..2689330 100644
--- a/lib/ui/screens/open_document_screen.dart
+++ b/lib/ui/screens/open_document_screen.dart
@@ -28,7 +28,7 @@ class OpenDocumentScreen extends StatelessWidget {
Widget build(BuildContext context) {
final body = BlocProvider(
create: (context) {
- final settings = context.read();
+ final settings = context.read();
final pdfSigningOption = settings.signingPdfContainer.value;
return GetIt.instance.get(
diff --git a/lib/ui/screens/preview_document_screen.dart b/lib/ui/screens/preview_document_screen.dart
index 01104de..ed08e0c 100644
--- a/lib/ui/screens/preview_document_screen.dart
+++ b/lib/ui/screens/preview_document_screen.dart
@@ -119,7 +119,7 @@ class _Body extends StatelessWidget {
onSignRequested: onSignRequested,
),
PreviewDocumentErrorState state => ErrorContent(
- title: context.strings.previewDocumentErrorTitle,
+ title: context.strings.previewDocumentErrorHeading,
error: state.error,
),
};
diff --git a/lib/ui/screens/select_certificate_screen.dart b/lib/ui/screens/select_certificate_screen.dart
index f4b91aa..aefa393 100644
--- a/lib/ui/screens/select_certificate_screen.dart
+++ b/lib/ui/screens/select_certificate_screen.dart
@@ -1,25 +1,31 @@
import 'package:eidmsdk/types.dart' show Certificate;
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:get_it/get_it.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;
+import '../../bloc/get_document_signature_type_cubit.dart';
import '../../bloc/select_signing_certificate_cubit.dart';
import '../../certificate_extensions.dart';
import '../../data/document_signing_type.dart';
import '../../data/settings.dart';
import '../../data/signature_type.dart';
+import '../../di.dart';
import '../../oids.dart';
import '../../strings_context.dart';
import '../app_theme.dart';
import '../fragment/select_signing_certificate_fragment.dart';
+import '../widgets/error_content.dart';
+import '../widgets/loading_content.dart';
import '../widgets/signature_type_picker.dart';
import 'sign_document_screen.dart';
-/// Screen for selecting the signature type using [SignatureTypePicker].
-/// Expecting to have at most 1 QES [Certificate].
+/// Screen for
+/// - loading and presenting [Certificate]
+/// - and then selecting the [SignatureType] using [SignatureTypePicker].
///
-/// Uses [SelectSigningCertificateCubit].
+/// Uses [SelectSigningCertificateCubit] and [GetDocumentSignatureTypeCubit].
+///
+/// Consumes [Settings].
///
/// Navigates next to [SignDocumentScreen].
class SelectCertificateScreen extends StatelessWidget {
@@ -36,10 +42,10 @@ class SelectCertificateScreen extends StatelessWidget {
Widget build(BuildContext context) {
return BlocProvider(
create: (context) {
- final settings = context.read();
+ final settings = context.read();
final signingCertificate = settings.signingCertificate;
- return GetIt.instance.get(
+ return getIt.get(
param1: signingCertificate,
)..getCertificates();
},
@@ -57,6 +63,8 @@ class SelectCertificateScreen extends StatelessWidget {
),
body: _Body(
state: state,
+ signingType: signingType,
+ documentId: documentId,
onSignDocumentRequested: (certificate, signatureType) {
_onSignDocumentRequested(
context: context,
@@ -79,7 +87,7 @@ class SelectCertificateScreen extends StatelessWidget {
required Certificate certificate,
required SignatureType signatureType,
}) {
- context.read().signingCertificate.value = certificate;
+ context.read().signingCertificate.value = certificate;
final screen = SignDocumentScreen(
documentId: documentId,
@@ -102,12 +110,17 @@ class SelectCertificateScreen extends StatelessWidget {
/// [SelectCertificateScreen] body.
class _Body extends StatelessWidget {
final SelectSigningCertificateState state;
+
+ final DocumentSigningType signingType;
+ final String documentId;
final void Function(Certificate certificate, SignatureType signatureType)?
onSignDocumentRequested;
final VoidCallback? onReloadCertificatesRequested;
const _Body({
required this.state,
+ this.signingType = DocumentSigningType.local,
+ this.documentId = '',
this.onSignDocumentRequested,
this.onReloadCertificatesRequested,
});
@@ -126,6 +139,8 @@ class _Body extends StatelessWidget {
successBuilder: (context, certificate) {
return _SelectSignatureTypeContent(
certificate: certificate,
+ signingType: signingType,
+ documentId: documentId,
onSignDocumentRequested: (final SignatureType signatureType) {
onSignDocumentRequested?.call(certificate, signatureType);
},
@@ -136,13 +151,25 @@ class _Body extends StatelessWidget {
}
}
+/// Success content where [Certificate] was loaded.
+/// Only thing is to determine [SignatureType] for given Document, either when:
+/// - [DocumentSigningType.local] - from [Settings.signatureType]
+/// - [DocumentSigningType.remote] - by calling [GetDocumentSignatureTypeCubit.getDocumentSignatureType]
+///
+/// Uses [GetDocumentSignatureTypeCubit].
+///
+/// Consumes [Settings].
class _SelectSignatureTypeContent extends StatefulWidget {
final String? subject;
+ final DocumentSigningType signingType;
+ final String documentId;
final ValueSetter? onSignDocumentRequested;
final VoidCallback? onReloadCertificatesRequested;
_SelectSignatureTypeContent({
required Certificate certificate,
+ required this.signingType,
+ required this.documentId,
required this.onSignDocumentRequested,
required this.onReloadCertificatesRequested,
}) : subject = certificate.tbsCertificate.subject[X500Oids.cn];
@@ -160,24 +187,68 @@ class _SelectSignatureTypeContentState
void initState() {
super.initState();
- _signatureType = context.read().signatureType.value;
+ if (widget.signingType == DocumentSigningType.local) {
+ _signatureType = context.read().signatureType.value;
+ }
}
@override
Widget build(BuildContext context) {
final strings = context.strings;
+ final body = BlocProvider(
+ create: (context) {
+ final cubit = getIt.get();
+
+ switch (widget.signingType) {
+ // TODO Refactor this flow; Need to work with Settings in cubit ctor
+ // And refactor this widget to be Stateful and work only with Cubit state
+ case DocumentSigningType.local:
+ cubit.setSignatureType(_signatureType);
+ break;
+
+ case DocumentSigningType.remote:
+ cubit.getDocumentSignatureType(widget.documentId);
+ break;
+ }
+
+ return cubit;
+ },
+ child: BlocConsumer(
+ listener: (context, state) {
+ if (state is GetDocumentSignatureTypeSuccessState) {
+ setState(() {
+ _signatureType =
+ (state.signatureType ?? SignatureType.withoutTimestamp);
+ });
+ }
+ },
+ builder: (context, state) {
+ return switch (state) {
+ GetDocumentSignatureTypeInitialState _ => const LoadingContent(),
+ GetDocumentSignatureTypeLoadingState _ => const LoadingContent(),
+ GetDocumentSignatureTypeErrorState state => ErrorContent(
+ title: strings.signatureTypeErrorHeading,
+ error: state.error,
+ ),
+ GetDocumentSignatureTypeSuccessState state => SignatureTypePicker(
+ value: _signatureType,
+ canChange: (widget.signingType == DocumentSigningType.local),
+ onValueChanged: (final SignatureType value) {
+ setState(() {
+ _signatureType = value;
+ });
+ },
+ ),
+ };
+ },
+ ),
+ );
return Column(
children: [
Expanded(
- child: SignatureTypePicker(
- value: _signatureType,
- onValueChanged: (final SignatureType value) {
- setState(() {
- _signatureType = value;
- });
- },
- ),
+ child: body,
),
// Primary button
diff --git a/lib/ui/screens/settings_screen.dart b/lib/ui/screens/settings_screen.dart
index 90fc8ea..2cb3a96 100644
--- a/lib/ui/screens/settings_screen.dart
+++ b/lib/ui/screens/settings_screen.dart
@@ -6,7 +6,7 @@ import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;
import '../../certificate_extensions.dart';
import '../../data/pdf_signing_option.dart';
-import '../../data/settings.dart' show ISettings;
+import '../../data/settings.dart';
import '../../data/signature_type.dart';
import '../../oids.dart';
import '../../strings_context.dart';
@@ -16,12 +16,12 @@ import '../widgets/option_picker.dart';
import '../widgets/preference_tile.dart';
import 'paired_device_list_screen.dart';
-/// App setting screen for editing [ISettings].
+/// App setting screen for editing [Settings].
///
/// Contains:
-/// - editor for [ISettings.signingPdfContainer]
-/// - display for [ISettings.signingCertificate]
-/// - editor for [ISettings.signatureType]
+/// - editor for [Settings.signingPdfContainer]
+/// - display for [Settings.signingCertificate]
+/// - editor for [Settings.signatureType]
/// - navigate to [PairedDeviceListScreen]
class SettingsScreen extends StatelessWidget {
const SettingsScreen({super.key});
@@ -45,7 +45,7 @@ class SettingsScreen extends StatelessWidget {
/// [SettingsScreen] body.
class _Body extends StatelessWidget {
- final ISettings settings;
+ final Settings settings;
const _Body({required this.settings});
@@ -87,7 +87,7 @@ class _Body extends StatelessWidget {
Widget _buildSettingsList(BuildContext context) {
final strings = context.strings;
- // ISettings.signingPdfContainer
+ // Settings.signingPdfContainer
final signingPdfContainerSetting =
_ValueListenableBoundTile(
setting: settings.signingPdfContainer,
@@ -96,7 +96,7 @@ class _Body extends StatelessWidget {
summaryGetter: (value) => value.label,
);
- // ISettings.signingCertificate
+ // Settings.signingCertificate
final signingCertificate = PreferenceTile(
title: strings.signingCertificateTitle,
summary: () {
@@ -116,7 +116,11 @@ class _Body extends StatelessWidget {
final signatureType = _ValueListenableBoundTile(
setting: settings.signatureType,
- values: SignatureType.values,
+ values: const [
+ SignatureType.unset,
+ SignatureType.withTimestamp,
+ SignatureType.withoutTimestamp,
+ ],
title: strings.signatureTypeTitle,
summaryGetter: (value) => strings.signatureTypeSummary(value.name),
);
@@ -140,8 +144,8 @@ class _Body extends StatelessWidget {
divider,
signatureType,
divider,
- pairedDevices,
- divider,
+ // pairedDevices, TODO: uncomment when pairing works
+ // divider,
],
);
}
@@ -261,8 +265,8 @@ Widget previewSettingsScreen(BuildContext context) {
);
}
-/// Mock [ISettings] impl. for preview.
-class _MockSettings implements ISettings {
+/// Mock [Settings] impl. for preview.
+class _MockSettings implements Settings {
@override
late final ValueNotifier acceptedPrivacyPolicyVersion =
ValueNotifier(null);
@@ -283,6 +287,10 @@ class _MockSettings implements ISettings {
late final ValueNotifier signingCertificate =
ValueNotifier(null);
+ @override
+ late final ValueNotifier remoteDocumentSigningOnboardingPassed =
+ ValueNotifier(false);
+
@override
Future clear() {
final props = [
@@ -291,6 +299,7 @@ class _MockSettings implements ISettings {
signingPdfContainer,
signatureType,
signingCertificate,
+ remoteDocumentSigningOnboardingPassed
];
for (final prop in props) {
diff --git a/lib/ui/screens/start_remote_document_signing_screen.dart b/lib/ui/screens/start_remote_document_signing_screen.dart
index abf59bc..05cf7fc 100644
--- a/lib/ui/screens/start_remote_document_signing_screen.dart
+++ b/lib/ui/screens/start_remote_document_signing_screen.dart
@@ -1,9 +1,9 @@
import 'package:flutter/material.dart';
import 'package:logging/logging.dart' show Logger;
+import 'package:provider/provider.dart' show ReadContext;
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;
-import '../../app_service.dart';
-import '../../di.dart';
+import '../../data/settings.dart';
import '../../strings_context.dart';
import '../app_theme.dart' show kPrimaryButtonMinimumSize, kScreenMargin;
import 'qr_code_scanner_screen.dart';
@@ -67,14 +67,17 @@ class StartRemoteDocumentSigningScreen extends StatelessWidget {
}
Future _startQrCodeScanner(BuildContext context) async {
+ // Mark that already seen this screen
+ context.read().remoteDocumentSigningOnboardingPassed.value = true;
+
const screen = QRCodeScannerScreen();
final route = MaterialPageRoute(builder: (_) => screen);
final result = await Navigator.of(context).push(route);
_logger.info('QR code scanner result: "$result".');
- if (result is String) {
- getIt.get().newIncomingUri(result);
+ if (context.mounted) {
+ Navigator.of(context).maybePop(result);
}
}
}
diff --git a/lib/ui/widgets/signature_type_picker.dart b/lib/ui/widgets/signature_type_picker.dart
index 509d34a..fc48990 100644
--- a/lib/ui/widgets/signature_type_picker.dart
+++ b/lib/ui/widgets/signature_type_picker.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'package:widgetbook/widgetbook.dart';
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;
import '../../data/signature_type.dart';
@@ -6,17 +7,22 @@ import '../../strings_context.dart';
import '../app_theme.dart';
import 'certificate_picker.dart';
-/// Displays two options to select the [SignatureType] options.
+/// Displays two options to select the [SignatureType] options; either
+/// [SignatureType.withTimestamp] or [SignatureType.withoutTimestamp].
+///
+/// When [canChange] is `false`, value selection by user is disabled.
///
/// See also:
/// - [CertificatePicker]
class SignatureTypePicker extends StatelessWidget {
final SignatureType? value;
+ final bool canChange;
final ValueChanged onValueChanged;
const SignatureTypePicker({
super.key,
required this.value,
+ this.canChange = true,
required this.onValueChanged,
});
@@ -36,6 +42,7 @@ class SignatureTypePicker extends StatelessWidget {
Widget _listItem(SignatureType value) {
return _ListItem(
value: value, // value from param
+ canSelect: canChange,
selectedValue: this.value, // value from Widget
onSelected: () {
onValueChanged(value);
@@ -47,11 +54,13 @@ class SignatureTypePicker extends StatelessWidget {
/// [SignatureTypePicker] - [ListView] item.
class _ListItem extends StatelessWidget {
final SignatureType value;
+ final bool canSelect;
final SignatureType? selectedValue;
final VoidCallback onSelected;
const _ListItem({
required this.value,
+ required this.canSelect,
required this.selectedValue,
required this.onSelected,
});
@@ -62,24 +71,29 @@ class _ListItem extends StatelessWidget {
final titleText = strings.signatureTypeValueTitle(value.name);
final subtitleText = strings.signatureTypeValueSubtitle(value.name);
- // NOT using RadioListTile because need to scale-up and style Radio
+ final enabled = (canSelect || value == selectedValue);
+ final radio = Radio(
+ value: value,
+ groupValue: selectedValue,
+ onChanged: enabled
+ ? (final SignatureType? value) {
+ if (value != null) {
+ if (selectedValue != value) {
+ onSelected();
+ }
+ }
+ }
+ : null,
+ activeColor: kRadioActiveColor,
+ );
+ // NOT using RadioListTile because need to scale-up and style Radio
return ListTile(
- onTap: onSelected,
+ onTap: (canSelect ? onSelected : null),
+ enabled: enabled,
leading: Transform.scale(
scale: kRadioScale,
- child: Radio(
- value: value,
- groupValue: selectedValue,
- onChanged: (final SignatureType? value) {
- if (value != null) {
- if (selectedValue != value) {
- onSelected();
- }
- }
- },
- activeColor: kRadioActiveColor,
- ),
+ child: radio,
),
title: Text(
titleText,
@@ -92,16 +106,24 @@ class _ListItem extends StatelessWidget {
@widgetbook.UseCase(
path: '[Lists]',
- name: 'SignatureTypePicker',
+ name: '',
type: SignatureTypePicker,
)
Widget previewSignatureTypePicker(BuildContext context) {
- SignatureType? selectedValue;
+ final bool canChange = context.knobs.boolean(
+ label: "Can change",
+ initialValue: true,
+ );
+ SignatureType? selectedValue = context.knobs.listOrNull(
+ label: "Signature type",
+ options: [SignatureType.withTimestamp, SignatureType.withoutTimestamp],
+ );
return StatefulBuilder(
builder: (context, setState) {
return SignatureTypePicker(
value: selectedValue,
+ canChange: canChange,
onValueChanged: (value) {
setState(() => selectedValue = value);
},
diff --git a/lib/use_case/get_document_signature_type_use_case.dart b/lib/use_case/get_document_signature_type_use_case.dart
new file mode 100644
index 0000000..4da08cd
--- /dev/null
+++ b/lib/use_case/get_document_signature_type_use_case.dart
@@ -0,0 +1,26 @@
+import 'package:autogram_sign/autogram_sign.dart'
+ show IAutogramService, SigningParametersLevel;
+import 'package:injectable/injectable.dart' show lazySingleton;
+
+import '../data/signature_type.dart';
+
+/// Gets the Document [SignatureType].
+@lazySingleton
+class GetDocumentSignatureTypeUseCase {
+ final IAutogramService autogramService;
+
+ GetDocumentSignatureTypeUseCase(this.autogramService);
+
+ /// Gets the [SignatureType] of Document with given [documentId].
+ Future call(String documentId) async {
+ final params = await autogramService.getDocumentParameters(documentId);
+
+ return switch (params.level) {
+ null => null,
+ SigningParametersLevel.cadesBaselineT => SignatureType.withTimestamp,
+ SigningParametersLevel.padesBaselineT => SignatureType.withTimestamp,
+ SigningParametersLevel.xadesBaselineT => SignatureType.withTimestamp,
+ _ => SignatureType.withoutTimestamp
+ };
+ }
+}
diff --git a/lib/use_case/get_document_version_use_case.dart b/lib/use_case/get_document_version_use_case.dart
index 63838c7..4604d0d 100644
--- a/lib/use_case/get_document_version_use_case.dart
+++ b/lib/use_case/get_document_version_use_case.dart
@@ -5,11 +5,10 @@ import 'package:html/parser.dart' as html show parse;
import 'package:http/http.dart' as http;
import 'package:injectable/injectable.dart';
-/// Gets the document - Privacy Policy or Terms of Service - version.
-///
-/// Impl. reads value from "version" `meta` tag.
+/// Gets the HTML document version by reading value
+/// from "version" HTML `meta` tag.
@lazySingleton
-class GetDocumentVersionUseCase {
+class GetHtmlDocumentVersionUseCase {
static final http.Client _client = http.Client();
/// Gets the document version on this [url].
@@ -21,17 +20,7 @@ class GetDocumentVersionUseCase {
url, "url", "GET on URL yields no text content.");
}
- final document = html.parse(text);
- final meta =
- document.querySelector('html > head > meta[name="version"][content]');
- final version = (meta?.attributes["content"]?.trim() ?? '');
-
- if (version.isEmpty) {
- throw ArgumentError.value(
- url, "url", "Required meta tag is not present.");
- }
-
- return version;
+ return parseVersion(text);
}
/// Gets the HTML content from given [url].
diff --git a/lib/widgetbook_app.directories.g.dart b/lib/widgetbook_app.directories.g.dart
index 4b83093..c752a52 100644
--- a/lib/widgetbook_app.directories.g.dart
+++ b/lib/widgetbook_app.directories.g.dart
@@ -278,7 +278,7 @@ final directories = <_i1.WidgetbookNode>[
_i1.WidgetbookLeafComponent(
name: 'SignatureTypePicker',
useCase: _i1.WidgetbookUseCase(
- name: 'SignatureTypePicker',
+ name: '',
builder: _i23.previewSignatureTypePicker,
),
),
diff --git a/pubspec.lock b/pubspec.lock
index fd31bbd..59de53e 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -37,10 +37,10 @@ packages:
dependency: transitive
description:
name: archive
- sha256: "6bd38d335f0954f5fad9c79e614604fbf03a0e5b975923dd001b6ea965ef5b4b"
+ sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
url: "https://pub.dev"
source: hosted
- version: "3.6.0"
+ version: "3.6.1"
args:
dependency: transitive
description:
@@ -63,7 +63,7 @@ packages:
path: "../autogram_sign"
relative: true
source: path
- version: "0.4.0"
+ version: "0.4.1"
barcode:
dependency: transitive
description:
@@ -347,10 +347,10 @@ packages:
dependency: transitive
description:
name: firebase_core_platform_interface
- sha256: c437ae5d17e6b5cc7981cf6fd458a5db4d12979905f9aafd1fea930428a9fe63
+ sha256: "1003a5a03a61fc9a22ef49f37cbcb9e46c86313a7b2e7029b9390cf8c6fc32cb"
url: "https://pub.dev"
source: hosted
- version: "5.0.0"
+ version: "5.1.0"
firebase_core_web:
dependency: transitive
description:
@@ -392,10 +392,10 @@ packages:
dependency: "direct main"
description:
name: flutter_bloc
- sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2
+ sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a
url: "https://pub.dev"
source: hosted
- version: "8.1.5"
+ version: "8.1.6"
flutter_hooks:
dependency: "direct main"
description:
@@ -791,10 +791,10 @@ packages:
dependency: transitive
description:
name: platform
- sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
+ sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
url: "https://pub.dev"
source: hosted
- version: "3.1.4"
+ version: "3.1.5"
plugin_platform_interface:
dependency: transitive
description:
@@ -847,10 +847,10 @@ packages:
dependency: transitive
description:
name: pubspec_parse
- sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
+ sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
url: "https://pub.dev"
source: hosted
- version: "1.2.3"
+ version: "1.3.0"
qr:
dependency: transitive
description:
@@ -1132,10 +1132,10 @@ packages:
dependency: "direct main"
description:
name: url_launcher
- sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
+ sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
url: "https://pub.dev"
source: hosted
- version: "6.2.6"
+ version: "6.3.0"
url_launcher_android:
dependency: transitive
description:
@@ -1308,10 +1308,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_android
- sha256: "2282ba2320af34b2bd5320156c664d73f3f022341ed78847bc87723bf88c142f"
+ sha256: "0d21cfc3bfdd2e30ab2ebeced66512b91134b39e72e97b43db2d47dda1c4e53a"
url: "https://pub.dev"
source: hosted
- version: "3.16.2"
+ version: "3.16.3"
webview_flutter_platform_interface:
dependency: transitive
description:
@@ -1340,10 +1340,10 @@ packages:
dependency: "direct main"
description:
name: widgetbook
- sha256: be0588cd864a70bd2817ca2fab0dbd147c460b712cfe53fd13e6fd46b5c3f368
+ sha256: "872e7e9065ef6e85a1e93b3b41830f90af575c5a898b6c573acdc972fad0fb29"
url: "https://pub.dev"
source: hosted
- version: "3.7.1"
+ version: "3.8.0"
widgetbook_annotation:
dependency: "direct main"
description:
@@ -1356,10 +1356,10 @@ packages:
dependency: "direct dev"
description:
name: widgetbook_generator
- sha256: d81512780bb4d137d59f0694328f446433fe5228cf8191e918046cc4f09c128b
+ sha256: "7a5baf68bb76cbd8aeb093050172f99bb83b44360bf2a72c2b19b3785e3d29d0"
url: "https://pub.dev"
source: hosted
- version: "3.7.0"
+ version: "3.8.0"
win32:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 3525c3f..fa2cca1 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,7 +1,7 @@
name: autogram
description: "Autogram v mobile"
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
-version: 1.0.0+25
+version: 1.0.2+33
environment:
sdk: '>=3.2.3 <4.0.0'
@@ -15,16 +15,16 @@ dependencies:
path: ../eidmsdk_flutter
autogram_sign:
path: ../autogram_sign
+ package_info_plus:
+ share_plus:
+ wakelock_plus:
flutter_svg:
- package_info_plus: ^5.0.1
http:
chopper: '>=7.4.0 <8.0.0'
injectable: ^2.2.0
get_it: ^7.6.1
flutter_hooks: ^0.20.5
localstorage: ^4.0.1+4
- share_plus: ^7.2.2
- wakelock_plus:
pdf:
printing: ^5.12.0
webview_flutter:
diff --git a/test/use_case/get_document_version_use_case_test.dart b/test/use_case/get_html_document_version_use_case_test.dart
similarity index 79%
rename from test/use_case/get_document_version_use_case_test.dart
rename to test/use_case/get_html_document_version_use_case_test.dart
index 07f406b..c53a1d7 100644
--- a/test/use_case/get_document_version_use_case_test.dart
+++ b/test/use_case/get_html_document_version_use_case_test.dart
@@ -1,17 +1,17 @@
import 'package:autogram/use_case/get_document_version_use_case.dart';
import 'package:test/test.dart';
-/// Tests for the [GetDocumentVersionUseCase] class.
+/// Tests for the [GetHtmlDocumentVersionUseCase] class.
void main() {
group('GetDocumentVersionUseCase', () {
test('parseVersion throws ArgumentError for empty HTML', () {
expect(
- () => GetDocumentVersionUseCase.parseVersion(""),
+ () => GetHtmlDocumentVersionUseCase.parseVersion(""),
throwsA(predicate((e) => e is ArgumentError && e.name == 'text')),
);
expect(
- () => GetDocumentVersionUseCase.parseVersion(''),
+ () => GetHtmlDocumentVersionUseCase.parseVersion(''),
throwsA(predicate((e) => e is ArgumentError && e.name == 'text')),
);
});
@@ -20,14 +20,14 @@ void main() {
'parseVersion throws ArgumentError for HTML with missing or invalid meta',
() {
expect(
- () => GetDocumentVersionUseCase.parseVersion(
+ () => GetHtmlDocumentVersionUseCase.parseVersion(
'',
),
throwsA(predicate((e) => e is ArgumentError && e.name == 'text')),
);
expect(
- () => GetDocumentVersionUseCase.parseVersion("""
+ () => GetHtmlDocumentVersionUseCase.parseVersion("""
@@ -38,7 +38,7 @@ void main() {
throwsA(predicate((e) => e is ArgumentError && e.name == 'text')),
);
expect(
- () => GetDocumentVersionUseCase.parseVersion("""
+ () => GetHtmlDocumentVersionUseCase.parseVersion("""
@@ -49,7 +49,7 @@ void main() {
throwsA(predicate((e) => e is ArgumentError && e.name == 'text')),
);
expect(
- () => GetDocumentVersionUseCase.parseVersion("""
+ () => GetHtmlDocumentVersionUseCase.parseVersion("""
@@ -63,14 +63,14 @@ void main() {
test('parseVersion returns value for valid meta with value', () {
expect(
- () => GetDocumentVersionUseCase.parseVersion(
+ () => GetHtmlDocumentVersionUseCase.parseVersion(
'',
),
throwsA(predicate((e) => e is ArgumentError && e.name == 'text')),
);
expect(
- () => GetDocumentVersionUseCase.parseVersion("""
+ () => GetHtmlDocumentVersionUseCase.parseVersion("""
@@ -81,7 +81,7 @@ void main() {
throwsA(predicate((e) => e is ArgumentError && e.name == 'text')),
);
expect(
- GetDocumentVersionUseCase.parseVersion("""
+ GetHtmlDocumentVersionUseCase.parseVersion("""