feat: import Chinese-localized Buzz source snapshot
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../../shared/l10n/l10n.dart';
|
||||
import 'channel.dart';
|
||||
|
||||
class EphemeralChannelDisplay {
|
||||
final String? detailLabel;
|
||||
final String tooltipLabel;
|
||||
|
||||
const EphemeralChannelDisplay({
|
||||
required this.detailLabel,
|
||||
required this.tooltipLabel,
|
||||
});
|
||||
}
|
||||
|
||||
bool isEphemeralChannel(Channel channel) =>
|
||||
channel.ttlSeconds != null || channel.ttlDeadline != null;
|
||||
|
||||
EphemeralChannelDisplay? ephemeralChannelDisplay(
|
||||
Channel channel, {
|
||||
DateTime? now,
|
||||
AppLocalizations? l10n,
|
||||
}) {
|
||||
if (!isEphemeralChannel(channel)) return null;
|
||||
|
||||
final deadline = channel.ttlDeadline;
|
||||
final remainingSeconds = deadline == null
|
||||
? null
|
||||
: ((deadline.millisecondsSinceEpoch -
|
||||
(now ?? DateTime.now()).millisecondsSinceEpoch) /
|
||||
1000)
|
||||
.ceil();
|
||||
|
||||
if (remainingSeconds == null) {
|
||||
final ttlSeconds = channel.ttlSeconds;
|
||||
return EphemeralChannelDisplay(
|
||||
detailLabel: ttlSeconds == null
|
||||
? null
|
||||
: formatCompactTtl(ttlSeconds, l10n: l10n),
|
||||
tooltipLabel: ttlSeconds == null
|
||||
? l10n?.ephemeralAutoCleanup ??
|
||||
'Ephemeral channel. Cleans up automatically after inactivity.'
|
||||
: l10n?.ephemeralCleanupAfter(
|
||||
formatVerboseTtl(ttlSeconds, l10n: l10n),
|
||||
) ??
|
||||
'Ephemeral channel. Cleans up after ${formatVerboseTtl(ttlSeconds)} of inactivity.',
|
||||
);
|
||||
}
|
||||
|
||||
final compactRemaining = formatCompactRemaining(
|
||||
remainingSeconds,
|
||||
l10n: l10n,
|
||||
);
|
||||
final verboseRemaining = formatVerboseRemaining(
|
||||
remainingSeconds,
|
||||
l10n: l10n,
|
||||
);
|
||||
final absoluteDeadlineLabel = formatAbsoluteDeadline(deadline!, l10n: l10n);
|
||||
|
||||
return EphemeralChannelDisplay(
|
||||
detailLabel: compactRemaining,
|
||||
tooltipLabel: remainingSeconds <= 0
|
||||
? l10n?.ephemeralCleanupDueTooltip ??
|
||||
'Ephemeral channel. Cleanup is due now.'
|
||||
: l10n?.ephemeralScheduled(verboseRemaining, absoluteDeadlineLabel) ??
|
||||
'Ephemeral channel. Cleans up $verboseRemaining. Scheduled for $absoluteDeadlineLabel.',
|
||||
);
|
||||
}
|
||||
|
||||
String formatCompactRemaining(
|
||||
int remainingSeconds, {
|
||||
AppLocalizations? l10n,
|
||||
}) {
|
||||
if (remainingSeconds <= 0) return l10n?.ephemeralCleanupDue ?? 'Cleanup due';
|
||||
if (remainingSeconds <= 60) return l10n?.ephemeralOneMinuteLeft ?? '1m left';
|
||||
if (remainingSeconds < 60 * 60) {
|
||||
final minutes = math.max(1, (remainingSeconds / 60).ceil());
|
||||
return l10n?.ephemeralMinutesLeft(minutes) ?? '${minutes}m left';
|
||||
}
|
||||
if (remainingSeconds < 60 * 60 * 24) {
|
||||
final hours = math.max(1, (remainingSeconds / (60 * 60)).ceil());
|
||||
return l10n?.ephemeralHoursLeft(hours) ?? '${hours}h left';
|
||||
}
|
||||
final days = math.max(1, (remainingSeconds / (60 * 60 * 24)).ceil());
|
||||
return l10n?.ephemeralDaysLeft(days) ?? '${days}d left';
|
||||
}
|
||||
|
||||
String formatVerboseRemaining(
|
||||
int remainingSeconds, {
|
||||
AppLocalizations? l10n,
|
||||
}) {
|
||||
if (remainingSeconds <= 0) return l10n?.timeNow ?? 'now';
|
||||
if (remainingSeconds <= 60) {
|
||||
return l10n?.ephemeralInOneMinute ?? 'in 1 minute';
|
||||
}
|
||||
if (remainingSeconds < 60 * 60) {
|
||||
final minutes = math.max(1, (remainingSeconds / 60).ceil());
|
||||
return l10n?.ephemeralInMinutes(minutes) ??
|
||||
'in $minutes minute${minutes == 1 ? '' : 's'}';
|
||||
}
|
||||
if (remainingSeconds < 60 * 60 * 24) {
|
||||
final hours = math.max(1, (remainingSeconds / (60 * 60)).ceil());
|
||||
return l10n?.ephemeralInHours(hours) ??
|
||||
'in $hours hour${hours == 1 ? '' : 's'}';
|
||||
}
|
||||
final days = math.max(1, (remainingSeconds / (60 * 60 * 24)).ceil());
|
||||
return l10n?.ephemeralInDays(days) ??
|
||||
'in $days day${days == 1 ? '' : 's'}';
|
||||
}
|
||||
|
||||
String formatCompactTtl(int ttlSeconds, {AppLocalizations? l10n}) {
|
||||
if (ttlSeconds < 60) {
|
||||
final seconds = math.max(1, ttlSeconds);
|
||||
return l10n?.ephemeralSeconds(seconds) ?? '${seconds}s TTL';
|
||||
}
|
||||
if (ttlSeconds < 60 * 60) {
|
||||
final minutes = math.max(1, (ttlSeconds / 60).ceil());
|
||||
return l10n?.ephemeralMinutes(minutes) ?? '${minutes}m TTL';
|
||||
}
|
||||
if (ttlSeconds < 60 * 60 * 24) {
|
||||
final hours = math.max(1, (ttlSeconds / (60 * 60)).ceil());
|
||||
return l10n?.ephemeralHours(hours) ?? '${hours}h TTL';
|
||||
}
|
||||
final days = math.max(1, (ttlSeconds / (60 * 60 * 24)).ceil());
|
||||
return l10n?.ephemeralDays(days) ?? '${days}d TTL';
|
||||
}
|
||||
|
||||
String formatVerboseTtl(int ttlSeconds, {AppLocalizations? l10n}) {
|
||||
if (ttlSeconds < 60) {
|
||||
final seconds = math.max(1, ttlSeconds);
|
||||
return l10n?.ephemeralSeconds(seconds) ??
|
||||
'$seconds second${seconds == 1 ? '' : 's'}';
|
||||
}
|
||||
if (ttlSeconds < 60 * 60) {
|
||||
final minutes = math.max(1, (ttlSeconds / 60).ceil());
|
||||
return l10n?.ephemeralMinutes(minutes) ??
|
||||
'$minutes minute${minutes == 1 ? '' : 's'}';
|
||||
}
|
||||
if (ttlSeconds < 60 * 60 * 24) {
|
||||
final hours = math.max(1, (ttlSeconds / (60 * 60)).ceil());
|
||||
return l10n?.ephemeralHours(hours) ??
|
||||
'$hours hour${hours == 1 ? '' : 's'}';
|
||||
}
|
||||
final days = math.max(1, (ttlSeconds / (60 * 60 * 24)).ceil());
|
||||
return l10n?.ephemeralDays(days) ??
|
||||
'$days day${days == 1 ? '' : 's'}';
|
||||
}
|
||||
|
||||
String formatAbsoluteDeadline(DateTime deadline, {AppLocalizations? l10n}) {
|
||||
if (l10n != null) {
|
||||
return DateFormat.yMMMd(l10n.localeName).add_jm().format(deadline.toLocal());
|
||||
}
|
||||
const months = [
|
||||
'Jan',
|
||||
'Feb',
|
||||
'Mar',
|
||||
'Apr',
|
||||
'May',
|
||||
'Jun',
|
||||
'Jul',
|
||||
'Aug',
|
||||
'Sep',
|
||||
'Oct',
|
||||
'Nov',
|
||||
'Dec',
|
||||
];
|
||||
final local = deadline.toLocal();
|
||||
final hour12 = local.hour % 12 == 0 ? 12 : local.hour % 12;
|
||||
final minute = local.minute.toString().padLeft(2, '0');
|
||||
final period = local.hour < 12 ? 'AM' : 'PM';
|
||||
return '${months[local.month - 1]} ${local.day}, $hour12:$minute $period';
|
||||
}
|
||||
Reference in New Issue
Block a user