diff --git a/assets/languages/strings_de.arb b/assets/languages/strings_de.arb index 40b27615..66f1c80c 100644 --- a/assets/languages/strings_de.arb +++ b/assets/languages/strings_de.arb @@ -123,6 +123,7 @@ "legalDisclaimerTitle": "Wichtige rechtliche Hinweise für Investoren & Bestätigung des Wohnsitzes", "legalDisclaimerTitle2": "Weitere rechtliche Hinweise", "legalDisclaimerYes": "Zustimmen", + "legalDocuments": "Rechtsdokumente", "location": "Ort", "logout": "Abmelden", "month": "Monat", diff --git a/assets/languages/strings_en.arb b/assets/languages/strings_en.arb index 2f7e987c..b8206745 100644 --- a/assets/languages/strings_en.arb +++ b/assets/languages/strings_en.arb @@ -123,6 +123,7 @@ "legalDisclaimerTitle": "Important legal notices for investors & confirmation of residence", "legalDisclaimerTitle2": "Further legal notices", "legalDisclaimerYes": "Agree", + "legalDocuments": "Legal documents", "location": "Location", "logout": "Logout", "month": "Month", diff --git a/lib/packages/config/legal_documents_config.dart b/lib/packages/config/legal_documents_config.dart new file mode 100644 index 00000000..eb6b5eb8 --- /dev/null +++ b/lib/packages/config/legal_documents_config.dart @@ -0,0 +1,108 @@ +import 'package:flutter/material.dart'; +import 'package:realunit_wallet/generated/i18n.dart'; +import 'package:realunit_wallet/screens/legal/subpages/legal_document_page.dart'; + +class LegalDocumentConfig { + final IconData icon; + final String Function(BuildContext context) title; + final String assetBaseName; + final Map? pdfUrls; + + const LegalDocumentConfig({ + required this.icon, + required this.title, + required this.assetBaseName, + this.pdfUrls, + }); + + void onTap(BuildContext context) => Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => LegalDocumentPage( + params: LegalDocumentParams( + title: title(context), + assetBaseName: assetBaseName, + pdfUrls: pdfUrls, + ), + ), + ), + ); +} + +class LegalDocumentsConfig { + static final allDocuments = [ + _privacyPolicy, + _registrationAgreement, + _securitiesProspectusBearerShares, + _securitiesProspectusRegisteredShares, + _articlesOfAssociation, + _investmentRegulations, + ]; + + static const _registrationAgreementPdfUrls = { + 'de': + 'https://realunit.de/wp-content/uploads/dlm_uploads/2025/03/250321_RegV-DE-RealUnit-Schweiz-AG_final_signed.pdf', + 'en': + 'https://realunit.de/wp-content/uploads/dlm_uploads/2025/03/250321_RegV-EN-RealUnit-Schweiz-AG_final_signed.pdf', + }; + + static const _securitiesProspectusBearerSharesPdfUrls = { + 'de': + 'https://realunit.de/wp-content/uploads/dlm_uploads/2025/07/VO_RealUnit_Wertpapierprospekt_Inhaberaktie_30.06.2025_eIDAS-signiert.pdf', + }; + + static const _securitiesProspectusRegisteredSharesPdfUrls = { + 'de': + 'https://realunit.de/wp-content/uploads/dlm_uploads/2025/07/VO_RealUnit_Wertpapierprospekt_Namensaktien_30.06.2025_eIDAS-signiert.pdf', + }; + + static const _articlesOfAssociationPdfUrls = { + 'de': + 'https://realunit.de/wp-content/uploads/dlm_uploads/2025/06/250604-RUCH-Statuten-mit-Deckblatt.pdf', + }; + + static const _investmentRegulationsPdfUrls = { + 'de': + 'https://realunit.de/wp-content/uploads/2025/03/250304_Anlagereglement_RealUnitSchweiz-AG.pdf', + }; + + static final _privacyPolicy = LegalDocumentConfig( + icon: Icons.shield_outlined, + title: (context) => S.of(context).legalDisclaimerCheckboxPrivacyPolicy, + assetBaseName: 'privacy_policy', + ); + + static final _registrationAgreement = LegalDocumentConfig( + icon: Icons.description_outlined, + title: (context) => S.of(context).legalDisclaimerCheckboxRegistrationAgreement, + assetBaseName: 'registration_agreement', + pdfUrls: _registrationAgreementPdfUrls, + ); + + static final _securitiesProspectusBearerShares = LegalDocumentConfig( + icon: Icons.article_outlined, + title: (context) => S.of(context).legalDisclaimerCheckboxSecuritiesProspectusBearerShares, + assetBaseName: 'securities_prospectus_bearer_shares', + pdfUrls: _securitiesProspectusBearerSharesPdfUrls, + ); + + static final _securitiesProspectusRegisteredShares = LegalDocumentConfig( + icon: Icons.article_outlined, + title: (context) => S.of(context).legalDisclaimerCheckboxSecuritiesProspectusRegisteredShares, + assetBaseName: 'securities_prospectus_registered_shares', + pdfUrls: _securitiesProspectusRegisteredSharesPdfUrls, + ); + + static final _articlesOfAssociation = LegalDocumentConfig( + icon: Icons.account_balance_outlined, + title: (context) => S.of(context).legalDisclaimerCheckboxArticlesOfAssociation, + assetBaseName: 'articles_of_association', + pdfUrls: _articlesOfAssociationPdfUrls, + ); + + static final _investmentRegulations = LegalDocumentConfig( + icon: Icons.policy_outlined, + title: (context) => S.of(context).legalDisclaimerCheckboxInvestmentRegulations, + assetBaseName: 'investment_regulations', + pdfUrls: _investmentRegulationsPdfUrls, + ); +} diff --git a/lib/router.dart b/lib/router.dart index c3ff5438..e46555da 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -24,6 +24,7 @@ import 'package:realunit_wallet/screens/settings_currencies/settings_currencies_ import 'package:realunit_wallet/screens/settings_edit_node/settings_edit_node_page.dart'; import 'package:realunit_wallet/screens/settings_kyc_status/settings_kyc_status_page.dart'; import 'package:realunit_wallet/screens/settings_languages/settings_languages_page.dart'; +import 'package:realunit_wallet/screens/settings_legal_documents/settings_legal_documents_page.dart'; import 'package:realunit_wallet/screens/settings_network/settings_network_page.dart'; import 'package:realunit_wallet/screens/settings_nodes/settings_nodes_page.dart'; import 'package:realunit_wallet/screens/settings_seed/settings_seed_page.dart'; @@ -148,6 +149,10 @@ void setupRouter() { path: '/kycStatus', builder: (context, state) => const SettingsKycStatusPage(), ), + GoRoute( + path: '/legalDocuments', + builder: (context, state) => const SettingsLegalDocumentsPage(), + ), GoRoute( path: '/network', builder: (context, state) => SettingsNetworkPage(), diff --git a/lib/screens/legal/steps/legal_documents_step.dart b/lib/screens/legal/steps/legal_documents_step.dart index 4534158e..6efe2e66 100644 --- a/lib/screens/legal/steps/legal_documents_step.dart +++ b/lib/screens/legal/steps/legal_documents_step.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:realunit_wallet/generated/i18n.dart'; -import 'package:realunit_wallet/screens/legal/subpages/legal_document_page.dart'; +import 'package:realunit_wallet/packages/config/legal_documents_config.dart'; import 'package:realunit_wallet/screens/legal/widgets/legal_document_button.dart'; import 'package:realunit_wallet/screens/legal/widgets/legal_step_styles.dart'; @@ -30,114 +30,15 @@ class LegalDocumentsStep extends StatelessWidget { ), Column( spacing: 12.0, - children: [ - LegalDocumentButton( - leadingIcon: Icons.shield_outlined, - title: s.legalDisclaimerCheckboxPrivacyPolicy, - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => LegalDocumentPage( - params: LegalDocumentParams( - title: s.legalDisclaimerCheckboxPrivacyPolicy, - assetBaseName: 'privacy_policy', - ), - ), - ), - ), - ), - LegalDocumentButton( - leadingIcon: Icons.description_outlined, - title: s.legalDisclaimerCheckboxRegistrationAgreement, - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => LegalDocumentPage( - params: LegalDocumentParams( - title: s.legalDisclaimerCheckboxRegistrationAgreement, - assetBaseName: 'registration_agreement', - pdfUrls: const { - 'de': - 'https://realunit.de/wp-content/uploads/dlm_uploads/2025/03/250321_RegV-DE-RealUnit-Schweiz-AG_final_signed.pdf', - 'en': - 'https://realunit.de/wp-content/uploads/dlm_uploads/2025/03/250321_RegV-EN-RealUnit-Schweiz-AG_final_signed.pdf', - }, - ), - ), - ), - ), - ), - LegalDocumentButton( - leadingIcon: Icons.article_outlined, - title: s.legalDisclaimerCheckboxSecuritiesProspectusBearerShares, - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => LegalDocumentPage( - params: LegalDocumentParams( - title: s.legalDisclaimerCheckboxSecuritiesProspectusBearerShares, - assetBaseName: 'securities_prospectus_bearer_shares', - pdfUrls: const { - 'de': - 'https://realunit.de/wp-content/uploads/dlm_uploads/2025/07/VO_RealUnit_Wertpapierprospekt_Inhaberaktie_30.06.2025_eIDAS-signiert.pdf', - }, - ), - ), - ), - ), - ), - LegalDocumentButton( - leadingIcon: Icons.article_outlined, - title: s.legalDisclaimerCheckboxSecuritiesProspectusRegisteredShares, - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => LegalDocumentPage( - params: LegalDocumentParams( - title: s.legalDisclaimerCheckboxSecuritiesProspectusRegisteredShares, - assetBaseName: 'securities_prospectus_registered_shares', - pdfUrls: const { - 'de': - 'https://realunit.de/wp-content/uploads/dlm_uploads/2025/07/VO_RealUnit_Wertpapierprospekt_Namensaktien_30.06.2025_eIDAS-signiert.pdf', - }, - ), - ), + children: LegalDocumentsConfig.allDocuments + .map( + (config) => LegalDocumentButton( + leadingIcon: config.icon, + title: config.title(context), + onTap: () => config.onTap(context), ), - ), - ), - LegalDocumentButton( - leadingIcon: Icons.account_balance_outlined, - title: s.legalDisclaimerCheckboxArticlesOfAssociation, - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => LegalDocumentPage( - params: LegalDocumentParams( - title: s.legalDisclaimerCheckboxArticlesOfAssociation, - assetBaseName: 'articles_of_association', - pdfUrls: const { - 'de': - 'https://realunit.de/wp-content/uploads/dlm_uploads/2025/06/250604-RUCH-Statuten-mit-Deckblatt.pdf', - }, - ), - ), - ), - ), - ), - LegalDocumentButton( - leadingIcon: Icons.policy_outlined, - title: s.legalDisclaimerCheckboxInvestmentRegulations, - onTap: () => Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => LegalDocumentPage( - params: LegalDocumentParams( - title: s.legalDisclaimerCheckboxInvestmentRegulations, - assetBaseName: 'investment_regulations', - pdfUrls: const { - 'de': - 'https://realunit.de/wp-content/uploads/2025/03/250304_Anlagereglement_RealUnitSchweiz-AG.pdf', - }, - ), - ), - ), - ), - ), - ], + ) + .toList(), ), ], ); diff --git a/lib/screens/settings/settings_page.dart b/lib/screens/settings/settings_page.dart index 34840a93..ec54af51 100644 --- a/lib/screens/settings/settings_page.dart +++ b/lib/screens/settings/settings_page.dart @@ -80,6 +80,16 @@ class SettingsPage extends StatelessWidget { trailing: _forwardIcon, onTap: () => context.push('/settings/termsOfUse'), ), + SettingOption( + title: S.of(context).legalDocuments, + leading: const Icon( + Icons.description_rounded, + size: 24, + color: RealUnitColors.realUnitBlue, + ), + trailing: _forwardIcon, + onTap: () => context.push('/settings/legalDocuments'), + ), SettingOption( title: S.of(context).contact, leading: const Icon( diff --git a/lib/screens/settings_legal_documents/settings_legal_documents_page.dart b/lib/screens/settings_legal_documents/settings_legal_documents_page.dart new file mode 100644 index 00000000..de3f55d8 --- /dev/null +++ b/lib/screens/settings_legal_documents/settings_legal_documents_page.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:realunit_wallet/generated/i18n.dart'; +import 'package:realunit_wallet/packages/config/legal_documents_config.dart'; +import 'package:realunit_wallet/screens/legal/widgets/legal_document_button.dart'; + +class SettingsLegalDocumentsPage extends StatelessWidget { + const SettingsLegalDocumentsPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(S.of(context).legalDocuments), + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 20.0, + vertical: 16.0, + ), + child: Column( + spacing: 12.0, + children: LegalDocumentsConfig.allDocuments + .map( + (config) => LegalDocumentButton( + leadingIcon: config.icon, + title: config.title(context), + onTap: () => config.onTap(context), + ), + ) + .toList(), + ), + ), + ), + ); + } +} diff --git a/test/screens/settings_legal_documents/settings_legal_documents_page_test.dart b/test/screens/settings_legal_documents/settings_legal_documents_page_test.dart new file mode 100644 index 00000000..0d9b00cc --- /dev/null +++ b/test/screens/settings_legal_documents/settings_legal_documents_page_test.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:realunit_wallet/screens/legal/widgets/legal_document_button.dart'; +import 'package:realunit_wallet/screens/settings_legal_documents/settings_legal_documents_page.dart'; + +import '../../helper/pump_app.dart'; + +void main() { + group('$SettingsLegalDocumentsPage', () { + testWidgets('renders initially correctly', (tester) async { + await tester.pumpApp(const SettingsLegalDocumentsPage()); + + expect(find.byType(SingleChildScrollView), findsOne); + expect(find.byType(LegalDocumentButton), findsNWidgets(6)); + }); + }); +}