Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
b3bc0b1
fix: favorite button (#3435)
LynxLynxx Sep 17, 2025
41ab3aa
Merge branch 'main' into feat/face-performance-optimization-3352
LynxLynxx Sep 17, 2025
f97e6d3
Merge branch 'main' into feat/face-performance-optimization-3352
damian-molinski Oct 7, 2025
aa30c39
chore: disable Sentry in profile mode (#3489)
damian-molinski Oct 7, 2025
cada6b5
feat(cat-voices): discovery widget optimization (#3460)
LynxLynxx Oct 8, 2025
9b9551c
Merge branch 'main' into feat/face-performance-optimization-3352
damian-molinski Oct 9, 2025
d439fbf
feat(cat-voices): Images and Videos fails gracefully (#3494)
LynxLynxx Oct 9, 2025
3d5aaf7
Merge branch 'main' into feat/face-performance-optimization-3352
LynxLynxx Oct 9, 2025
e7aab8a
Merge branch 'feat/face-performance-optimization-3352' of github.com:…
LynxLynxx Oct 9, 2025
397c53b
Merge main into feat/face-performance-optimization-3352
damian-molinski Oct 9, 2025
65d7380
Merge
damian-molinski Oct 9, 2025
57218f9
Merge branch 'main' into feat/face-performance-optimization-3352
dt-iohk Oct 9, 2025
0e1b163
feat(cat-voices): responsive breakpoints update (#3498)
LynxLynxx Oct 10, 2025
e714f41
Merge branch 'main' into feat/face-performance-optimization-3352
LynxLynxx Oct 13, 2025
45cb0c0
feat(cat-voices): stress test env (#3520)
damian-molinski Oct 14, 2025
d082a3c
feat(cat-voices): Catalyst Developer Profiler (#3533)
LynxLynxx Oct 15, 2025
8db53f6
feat(cat-voices): workspace mocked data (#3524)
LynxLynxx Oct 16, 2025
ca83128
merge with main
LynxLynxx Oct 16, 2025
6818626
Merge branch 'main' of github.com:input-output-hk/catalyst-voices int…
LynxLynxx Oct 16, 2025
239092e
fix: uncomment runner in earthly
LynxLynxx Oct 17, 2025
3fc476e
feat(cat-voices): Expansion of CatalystProfiler coverage (#3547)
LynxLynxx Oct 17, 2025
5491a7b
feat(cat-voices): `CatalystVoicesDev` package (#3558)
LynxLynxx Oct 21, 2025
bb99cee
feat(cat-voices): Progressive loading indicator in app splash screen …
LynxLynxx Oct 22, 2025
c3e7afb
feat(cat-voices): documents indexing performance (#3555)
damian-molinski Oct 22, 2025
8ee0cbc
Merge main into feat/face-performance-optimization-3352
damian-molinski Oct 23, 2025
f293bd7
feat(cat-voices): Filter out internal extensions exception (#3586)
LynxLynxx Oct 24, 2025
62386f6
Merge branch 'main' into feat/face-performance-optimization-3352
LynxLynxx Oct 27, 2025
bfc2e08
chore: update README (#3613)
LynxLynxx Oct 29, 2025
c48b879
feat(cat-voices): keychain state snackbars (#3610)
LynxLynxx Oct 29, 2025
42cdc03
Merge branch 'main' of github.com:input-output-hk/catalyst-voices int…
LynxLynxx Oct 30, 2025
c95310e
Merge branch 'main' into feat/face-performance-optimization-3352
LynxLynxx Oct 30, 2025
bd6230a
refactor(cat-voices): delete keychain dialog (#3618)
LynxLynxx Oct 30, 2025
1127fdd
feat(cat-voices): enable browser crypto api in wasm (#3640)
dt-iohk Nov 4, 2025
ab23ad4
feat(cat-voices): Enable wasm support for Catalyst Voices (#3622)
dt-iohk Nov 5, 2025
162834c
fix(cat-voices): revert local changes (#3651)
dt-iohk Nov 5, 2025
ff53a1a
docs(cat-voices): wasm performance documentation (#3658)
dt-iohk Nov 6, 2025
f2f790d
Merge branch 'main' into feat/face-performance-optimization-3352
dt-iohk Nov 7, 2025
3c35510
refactor(cat-voices): Reporting service fail gracefully (#3636)
LynxLynxx Nov 10, 2025
68f0961
Merge branch 'main' into feat/face-performance-optimization-3352
damian-molinski Nov 10, 2025
26bf385
Merge branch 'main' into feat/face-performance-optimization-3352
LynxLynxx Nov 12, 2025
daf891c
Merge branch 'main' into feat/face-performance-optimization-3352
dt-iohk Nov 12, 2025
0c5465f
feat(cat-voices): release mode for flutter rust bridge (#3676)
dt-iohk Nov 12, 2025
376f937
feat(cat-voices): Versioning web build assets (#3643)
LynxLynxx Nov 14, 2025
5b9b6da
feat(cat-voices): fine tune cache control for voices (#3687)
LynxLynxx Nov 14, 2025
f6fb0e4
feat(cat-voices): New app version banner (#3714)
LynxLynxx Nov 14, 2025
41f997a
Merge branch 'main' into feat/face-performance-optimization-3352
LynxLynxx Nov 18, 2025
8cab9c5
Merge branch 'main' into feat/face-performance-optimization-3352
dt-iohk Nov 19, 2025
02a65fd
Merge branch 'main' into feat/face-performance-optimization-3352
dt-iohk Nov 19, 2025
bb5429d
Merge branch 'main' into feat/face-performance-optimization-3352
damian-molinski Nov 19, 2025
ad7b011
refactor(cat-voices): revert wasm workaround for js undefined (#3741)
dt-iohk Nov 19, 2025
3da967f
Merge branch 'main' into feat/face-performance-optimization-3352
bstolinski Nov 19, 2025
13b2aa8
feat(cat-voices): find manual version files through wildcard (#3723)
LynxLynxx Nov 19, 2025
e4129c3
feat(cat-voices): profile app size (#3736)
bstolinski Nov 20, 2025
ae2be38
Merge branch 'main' into feat/face-performance-optimization-3352
LynxLynxx Nov 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .config/dictionaries/project.dic
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ postcss
Pozhylenkov
Precache
Precertificate
precompressed
preprod
proguard
projectcatalyst
Expand Down
9 changes: 9 additions & 0 deletions .vscode/launch.recommended.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"deviceId": "chrome",
"program": "lib/configs/main_web.dart",
"args": [
"--wasm",
"--dart-define",
"SENTRY_DSN=REPLACE_WITH_SENTRY_DSN_URL",
"--web-header",
Expand All @@ -34,6 +35,7 @@
"deviceId": "chrome",
"program": "lib/configs/main_web.dart",
"args": [
"--wasm",
"--dart-define",
"SENTRY_DSN=REPLACE_WITH_SENTRY_DSN_URL",
"--web-header",
Expand All @@ -52,6 +54,7 @@
"deviceId": "chrome",
"program": "lib/configs/main_web.dart",
"args": [
"--wasm",
"--dart-define",
"SENTRY_DSN=REPLACE_WITH_SENTRY_DSN_URL",
"--web-header",
Expand All @@ -70,6 +73,7 @@
"deviceId": "chrome",
"program": "lib/configs/main_web.dart",
"args": [
"--wasm",
"--dart-define",
"SENTRY_DSN=REPLACE_WITH_SENTRY_DSN_URL",
"--web-header",
Expand All @@ -88,6 +92,7 @@
"deviceId": "chrome",
"program": "lib/configs/main_web.dart",
"args": [
"--wasm",
"--dart-define",
"SENTRY_DSN=REPLACE_WITH_SENTRY_DSN_URL",
"--web-header",
Expand All @@ -106,6 +111,7 @@
"deviceId": "chrome",
"program": "lib/configs/main_web.dart",
"args": [
"--wasm",
"--dart-define",
"SENTRY_DSN=REPLACE_WITH_SENTRY_DSN_URL",
"--web-header",
Expand All @@ -124,6 +130,7 @@
"deviceId": "chrome",
"program": "lib/configs/main_web.dart",
"args": [
"--wasm",
"--dart-define",
"SENTRY_DSN=REPLACE_WITH_SENTRY_DSN_URL",
"--web-header",
Expand All @@ -142,6 +149,7 @@
"deviceId": "chrome",
"program": "lib/configs/main_web.dart",
"args": [
"--wasm",
"--dart-define",
"SENTRY_DSN=REPLACE_WITH_SENTRY_DSN_URL",
"--web-header",
Expand All @@ -160,6 +168,7 @@
"deviceId": "chrome",
"program": "lib/configs/main_web.dart",
"args": [
"--wasm",
"--dart-define",
"SENTRY_DSN=REPLACE_WITH_SENTRY_DSN_URL",
"--web-header",
Expand Down
7 changes: 5 additions & 2 deletions catalyst_voices/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
devtools_options.yaml

# Documentation
docs/
docs/dartdoc
docs/licenses
docs/*.dot

# Generated files from code generation tools
*.g.dart
Expand Down Expand Up @@ -169,4 +171,5 @@ coverage/
### Tests ###
# Those files are generated by melos test-report script
test_reports/*.junit-report.xml
test_reports/*.tests-output.json
test_reports/*.tests-output.json
scripts/version_web_assets/test/helper/tmp
42 changes: 27 additions & 15 deletions catalyst_voices/Caddyfile
Original file line number Diff line number Diff line change
@@ -1,30 +1,42 @@
{
admin :8081
metrics
admin :8081
metrics
}
http://:8080 {
root * /app
root * /app

# Compress on-the-fly if not precompressed
encode

handle /healthz {
respond `{"status":"ok"}` 200
}

handle {
try_files {path} /index.html
file_server
file_server {
# default order br zstd gzip
precompressed
}
}

header {
Cross-Origin-Opener-Policy "same-origin"
Cross-Origin-Embedder-Policy "require-corp"
header {
Cross-Origin-Opener-Policy "same-origin"
Cross-Origin-Embedder-Policy "require-corp"
Cross-Origin-Resource-Policy "same-origin"

/ Cache-Control "public, max-age=3600, must-revalidate"
}
?Cache-Control "public, max-age=3600, must-revalidate"
}

handle_errors {
rewrite * /50x.html
file_server
}
@index_html path /index.html
header @index_html Cache-Control "no-cache, must-revalidate"

log
}
import /app/versioned_assets.caddy

handle_errors {
rewrite * /50x.html
file_server
}

log
}
9 changes: 8 additions & 1 deletion catalyst_voices/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,14 @@ build-web:
--TARGET=lib/configs/main_web.dart \
--UPLOAD_DEBUG_SYMBOLS=$UPLOAD_DEBUG_SYMBOLS \
--SENTRY_ORG='iohk-j4' \
--SENTRY_PROJECT='catalyst-voices'
--SENTRY_PROJECT='catalyst-voices' \
--WASM=true

# Version web assets with content-based MD5 hashes for cache busting
RUN dart run /frontend/scripts/version_web_assets/version_web_assets.dart --build-dir=$WORKDIR/build/web --wasm=true

DO flutter-ci+COMPRESS_WEB_FILES

SAVE ARTIFACT --keep-ts web

package:
Expand Down
43 changes: 40 additions & 3 deletions catalyst_voices/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ This repository contains the Catalyst Voices app and packages.

* [Catalyst Voices](#catalyst-voices)
* [Requirements](#requirements)
* [Recommended VS code plugins](#recommended-vs-code-plugins)
* [Platforms](#platforms)
* [Getting Started](#getting-started)
* [Bootstrapping](#bootstrapping)
* [Packages](#packages)
* [Environment Type vs Flavor](#environment-type-vs-flavor)
* [Environment types](#environment-types)
* [Stress Test](#stress-test)
* [Debug Performance Flags](#debug-performance-flags)
* [Flavor types](#flavor-types)
* [Environment variables](#environment-variables)
* [Environment config](#environment-config)
* [Code Generation](#code-generation)
* [Running Code Generation](#running-code-generation)
* [Code Generation](#code-generation)
*[Running Code Generation](#running-code-generation)
* [Basic Generation](#basic-generation)
* [Local Saving](#local-saving)
*[Local Saving](#local-saving)
* [GitHub Token / PAT Setup](#github-token--pat-setup)
* [Security Notes](#security-notes)
* [Running Tests](#running-tests)
Expand Down Expand Up @@ -76,6 +79,7 @@ just bootstrap
| [catalyst_voices_services](./packages/internal/catalyst_voices_services/) | Services |[example](./packages/internal/catalyst_voices_services/)|
| [catalyst_voices_shared](./packages/internal/catalyst_voices_shared/) | Shared code |[example](./packages/internal/catalyst_voices_shared/)|
| [catalyst_voices_view_models](./packages/internal/catalyst_voices_view_models/) | ViewModels |[example](./packages/internal/catalyst_voices_view_models/)|
| [catalyst_voices_dev](./packages/internal/catalyst_voices_dev/) | Dev | [example](./packages/internal/catalyst_voices_dev/)|

### Environment Type vs Flavor

Expand Down Expand Up @@ -122,6 +126,39 @@ flutter run --target lib/configs/main.dart --dart-define=ENV_NAME=prod -d chrome
> Catalyst Voices works on the Web only.
> We plan to add support for other targets later.

#### Stress Test

Each environment can be launched in stress test.
It will use local version of Gateway and produce as many proposals as configured (defaults to 100).
Use following `--dart-define` variables to configure your setup:

* `--dart-define=STRESS_TEST=true` to enable
* `--dart-define=STRESS_TEST_PROPOSAL_INDEX_COUNT=100` says how many proposals will be produced
* `--dart-define=STRESS_TEST_DECOMPRESSED=false` if signed documents should be compressed or not

#### Debug Performance Flags

Each environment can be launched with additional debug performance flags on web in `Profile` mode
There is four performance flags to choose from:

* **debugProfileBuildsEnabled:** Adds Timeline events for every Widget built.
* **debugProfileBuildsEnabledUserWidgets:** Adds Timeline events for every user-created Widget built.
* **debugProfileLayoutsEnabled:** Adds Timeline events for every RenderObject layout.
* **debugProfilePaintsEnabled:** Adds Timeline events for every RenderObject painted.

To use following `--dart-define` variables to configure your setup:

* `--dart-define=DEBUG_PROFILE_BUILDS_ENABLED` to enable debugProfileBuildsEnabled
* `--dart-define=DEBUG_PROFILE_BUILDS_ENABLED_USER_WIDGETS` to enable debugProfileBuildsEnabledUserWidgets
* `--dart-define=DEBUG_PROFILE_LAYOUTS_ENABLED` to enable debugProfileLayoutsEnabled
* `--dart-define=DEBUG_PROFILE_PAINTS_ENABLED` to enable debugProfilePaintsEnabled

There is `--dart-define` variable to enable all four performance flags at once:

* `--dart-define=DEBUG_PROFILE_DEVELOPER_PROFILER_ENABLE_ALL`

Remember to also use `--profile` mode when running the app.

### Flavor types

You should use flavor types instead of environment variables when running the app on mobile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import 'package:catalyst_voices_shared/catalyst_voices_shared.dart';
import 'package:flutter/material.dart';
import 'package:synchronized/synchronized.dart';

final _logger = Logger('AppPrecacheImageAssets');

class GlobalPrecacheImages extends StatefulWidget {
final Widget child;

Expand Down Expand Up @@ -59,6 +61,22 @@ class ImagePrecacheService {
}
}

Future<void> _cacheImageAsset(AssetGenImage asset, BuildContext context) async {
try {
await asset.cache(context: context);
} catch (error) {
_logger.info('Failed to cache image asset: $error');
}
}

Future<void> _cacheSvgAsset(SvgGenImage svg, BuildContext context) async {
try {
await svg.cache(context: context);
} catch (error) {
_logger.info('Failed to cache SVG asset: $error');
}
}

Future<void> _precacheAssets(
BuildContext context, {
List<SvgGenImage> svgs = const [],
Expand All @@ -71,8 +89,8 @@ class ImagePrecacheService {
_assets.addAll(assets);

await Future.wait([
..._svgs.map((e) => e.cache(context: context)),
..._assets.map((e) => e.cache(context: context)),
..._svgs.map((e) => _cacheSvgAsset(e, context)),
..._assets.map((e) => _cacheImageAsset(e, context)),
]);

if (!_isInitialized.isCompleted) _isInitialized.complete(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:catalyst_voices/common/signal_handler.dart';
import 'package:catalyst_voices/notification/catalyst_messenger.dart';
import 'package:catalyst_voices/notification/specialized/account_needs_verification_banner.dart';
import 'package:catalyst_voices/notification/specialized/banner/account_needs_verification_banner.dart';
import 'package:catalyst_voices/routes/routes.dart';
import 'package:catalyst_voices/widgets/snackbar/voices_snackbar.dart';
import 'package:catalyst_voices/widgets/snackbar/voices_snackbar_type.dart';
Expand Down Expand Up @@ -30,12 +30,7 @@ class _GlobalSessionListenerState extends State<GlobalSessionListener>

@override
Widget build(BuildContext context) {
// TODO(damian-molinski): refactor it to use signals
return BlocListener<SessionCubit, SessionState>(
listenWhen: _listenToSessionChangesWhen,
listener: _onSessionChanged,
child: widget.child,
);
return widget.child;
}

@override
Expand All @@ -47,28 +42,23 @@ class _GlobalSessionListenerState extends State<GlobalSessionListener>
: AccountContributorNeedsVerificationBanner();
CatalystMessenger.of(context).add(notification);
case CancelAccountNeedsVerificationSignal():
CatalystMessenger.of(
context,
).cancelWhere((notification) => notification is AccountNeedsVerificationBanner);
CatalystMessenger.of(context).cancelWhere(
(notification) => notification is AccountNeedsVerificationBanner,
);
case KeychainLockedSignal():
_handleKeychainLock();
case KeychainUnlockedSignal():
_handleKeychainUnlock();
}
}

bool _listenToSessionChangesWhen(SessionState prev, SessionState next) {
// We deliberately check if previous was guest because we don't
// want to show the snackbar after the registration is completed.
final keychainUnlocked = prev.isGuest && next.isActive;
final keychainLocked = prev.isActive && next.isGuest;

return keychainUnlocked || keychainLocked;
}

void _onLockedKeychain(BuildContext context) {
void _handleKeychainLock() {
VoicesSnackBar(
type: VoicesSnackBarType.error,
behavior: SnackBarBehavior.floating,
icon: VoicesAssets.icons.lockClosed.buildIcon(),
title: context.l10n.lockSnackbarTitle,
message: context.l10n.lockSnackbarMessage,
icon: VoicesAssets.icons.lockClosed.buildIcon(),
).show(context);

final routerContext = AppRouterFactory.rootNavigatorKey.currentContext;
Expand All @@ -78,21 +68,13 @@ class _GlobalSessionListenerState extends State<GlobalSessionListener>
}
}

void _onSessionChanged(BuildContext context, SessionState state) {
if (state.isActive) {
_onUnlockedKeychain(context);
} else if (state.isGuest) {
_onLockedKeychain(context);
}
}

void _onUnlockedKeychain(BuildContext context) {
void _handleKeychainUnlock() {
VoicesSnackBar(
type: VoicesSnackBarType.success,
behavior: SnackBarBehavior.floating,
icon: VoicesAssets.icons.lockOpen.buildIcon(),
title: context.l10n.unlockSnackbarTitle,
message: context.l10n.unlockSnackbarMessage,
icon: VoicesAssets.icons.lockOpen.buildIcon(),
).show(context);

final routerContext = AppRouterFactory.rootNavigatorKey.currentContext;
Expand Down
Loading