Skip to content
13 changes: 10 additions & 3 deletions lib/bloc/assets_overview/bloc/asset_overview_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,17 @@ class AssetOverviewBloc extends Bloc<AssetOverviewEvent, AssetOverviewState> {
return;
}

await _sdk.waitForEnabledCoinsToPassThreshold(event.coins);
final supportedCoins = await event.coins.filterSupportedCoins();
if (supportedCoins.isEmpty) {
_log.warning('No supported coins to load portfolio overview for');
return;
}

await _sdk.waitForEnabledCoinsToPassThreshold(supportedCoins);

final activeCoins = await event.coins.removeInactiveCoins(_sdk);
final activeCoins = await supportedCoins.removeInactiveCoins(_sdk);
if (activeCoins.isEmpty) {
_log.warning('No active coins to load portfolio overview for');
return;
}

Expand Down Expand Up @@ -136,7 +143,7 @@ class AssetOverviewBloc extends Bloc<AssetOverviewEvent, AssetOverviewState> {

emit(
PortfolioAssetsOverviewLoadSuccess(
selectedAssetIds: event.coins.map((coin) => coin.id.id).toList(),
selectedAssetIds: activeCoins.map((coin) => coin.id.id).toList(),
assetPortionPercentages: assetPortionPercentages,
totalInvestment: totalInvestment,
totalValue: FiatValue.usd(profitAmount),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import 'dart:math' as math;

/// A strategy for implementing exponential backoff with paired intervals.
/// The pattern is: 1min, 1min, 2min, 2min, 4min, 4min, 8min, 8min, etc.
Comment thread
takenagain marked this conversation as resolved.
/// This reduces API calls while still providing reasonable update frequency.
class UpdateFrequencyBackoffStrategy {
UpdateFrequencyBackoffStrategy({
this.baseInterval = const Duration(minutes: 1),
this.maxInterval = const Duration(hours: 1),
});

/// The base interval for the first attempts (default: 2 minutes)
final Duration baseInterval;

/// The maximum interval to backoff to (default: 1 hour)
final Duration maxInterval;

int _attemptCount = 0;

/// Reset the backoff strategy to start from the beginning
void reset() {
_attemptCount = 0;
}

/// Get the current attempt count
int get attemptCount => _attemptCount;

/// Get the next interval duration and increment the attempt count
Duration getNextInterval() {
final interval = getCurrentInterval();
_attemptCount++;
return interval;
}

/// Get the current interval duration without incrementing the attempt count
Duration getCurrentInterval() {
// Calculate which "pair" we're in (0, 1, 2, 3, ...)
// Each pair has 2 attempts with the same interval
final pairIndex = _attemptCount ~/ 2;

// Calculate the multiplier: 2^pairIndex
final multiplier = math.pow(2, pairIndex).toInt();

// Calculate the interval
final intervalMs = baseInterval.inMilliseconds * multiplier;

// Cap at maximum interval
final cappedIntervalMs = math.min(intervalMs, maxInterval.inMilliseconds);

return Duration(milliseconds: cappedIntervalMs);
}

/// Check if we should update the cache on the current attempt
/// Returns true for cache update attempts, false for cache-only reads
bool shouldUpdateCache() {
// Update cache on every attempt for now, but this could be modified
// to only update on certain intervals if needed
return true;
}

/// Get a preview of the next N intervals without affecting the state
List<Duration> previewNextIntervals(int count) {
final currentAttempt = _attemptCount;
final intervals = <Duration>[];

for (int i = 0; i < count; i++) {
final pairIndex = (currentAttempt + i) ~/ 2;
final multiplier = math.pow(2, pairIndex).toInt();
final intervalMs = baseInterval.inMilliseconds * multiplier;
final cappedIntervalMs = math.min(intervalMs, maxInterval.inMilliseconds);
intervals.add(Duration(milliseconds: cappedIntervalMs));
}

return intervals;
}
}
Loading
Loading