Rename mobile app to Buzz (#955)

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Pinky <44b8e82baa6e0e254e0208d68f335c283c94e7b78dd1fa10d5a49d3f13dd0435@sprout-oss.stage.blox.sqprod.co>
This commit is contained in:
Wes
2026-06-10 13:38:11 -07:00
committed by GitHub
co-authored by Pinky
parent 929cc8861e
commit c63e018b05
105 changed files with 239 additions and 231 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
{
"SPROUT_RELAY_URL": "http://localhost:3000",
"SPROUT_DEV_PUBKEY": "<your-hex-pubkey-here>"
"BUZZ_RELAY_URL": "http://localhost:3000",
"BUZZ_DEV_PUBKEY": "<your-hex-pubkey-here>"
}
+2 -2
View File
@@ -1,6 +1,6 @@
# Sprout Mobile
# Buzz Mobile
Flutter mobile client for Sprout.
Flutter mobile client for Buzz.
## Setup
+2 -2
View File
@@ -6,7 +6,7 @@ plugins {
}
android {
namespace = "com.sprout.sprout_mobile"
namespace = "com.buzz.buzz_mobile"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
@@ -21,7 +21,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.sprout.sprout_mobile"
applicationId = "com.buzz.buzz_mobile"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
@@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.CAMERA" />
<application
android:label="Sprout"
android:label="Buzz"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
@@ -1,4 +1,4 @@
package com.sprout.sprout_mobile
package com.buzz.buzz_mobile
import android.graphics.Bitmap
import android.graphics.BitmapFactory
@@ -222,7 +222,7 @@ class MainActivity : FlutterActivity() {
}
companion object {
private const val MEDIA_UPLOAD_CHANNEL = "sprout/media_upload"
private const val MEDIA_UPLOAD_CHANNEL = "buzz/media_upload"
private const val SANITIZE_IMAGE_FOR_UPLOAD_METHOD = "sanitizeImageForUpload"
private const val TRANSCODE_IMAGE_TO_JPEG_METHOD = "transcodeImageToJpeg"
private const val TRANSCODE_VIDEO_TO_MP4_METHOD = "transcodeVideoToMp4"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 488 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 62 KiB

+1 -1
View File
@@ -5,5 +5,5 @@
// without patching tracked files by writing
// `mobile/ios/Flutter/AppOverrides.xcconfig` containing
// `BUNDLE_IDENTIFIER = your.app.id` (gitignored).
BUNDLE_IDENTIFIER = com.sprout.sproutMobile
BUNDLE_IDENTIFIER = com.buzz.buzzMobile
#include? "AppOverrides.xcconfig"
+1 -1
View File
@@ -4,7 +4,7 @@
// Defaults for the iOS Release build. Internal/custom builds (e.g. an
// enterprise-signed distribution) override these without patching tracked
// files by writing `mobile/ios/Flutter/AppOverrides.xcconfig` (gitignored).
BUNDLE_IDENTIFIER = com.sprout.sproutMobile
BUNDLE_IDENTIFIER = com.buzz.buzzMobile
CODE_SIGN_STYLE = Automatic
CODE_SIGN_IDENTITY = iPhone Developer
#include? "AppOverrides.xcconfig"
+6 -6
View File
@@ -483,7 +483,7 @@
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_IDENTIFIER)";
PRODUCT_NAME = Sprout;
PRODUCT_NAME = Buzz;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
@@ -504,7 +504,7 @@
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sprout.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Sprout";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Buzz.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Buzz";
};
name = Debug;
};
@@ -520,7 +520,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_IDENTIFIER).RunnerTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sprout.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Sprout";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Buzz.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Buzz";
};
name = Release;
};
@@ -536,7 +536,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_IDENTIFIER).RunnerTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sprout.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Sprout";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Buzz.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Buzz";
};
name = Profile;
};
@@ -665,7 +665,7 @@
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_IDENTIFIER)";
PRODUCT_NAME = Sprout;
PRODUCT_NAME = Buzz;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -688,7 +688,7 @@
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_IDENTIFIER)";
PRODUCT_NAME = Sprout;
PRODUCT_NAME = Buzz;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
+1 -1
View File
@@ -18,7 +18,7 @@ import UserNotifications
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
mediaUploadChannel = FlutterMethodChannel(
name: "sprout/media_upload",
name: "buzz/media_upload",
binaryMessenger: engineBridge.applicationRegistrar.messenger()
)
mediaUploadChannel?.setMethodCallHandler { [weak self] call, result in
Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 689 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 KiB

After

Width:  |  Height:  |  Size: 22 KiB

+4 -4
View File
@@ -7,7 +7,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Sprout</string>
<string>Buzz</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -15,7 +15,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Sprout</string>
<string>Buzz</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
@@ -27,9 +27,9 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>Sprout needs camera access to scan QR codes for device pairing.</string>
<string>Buzz needs camera access to scan QR codes for device pairing.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Sprout needs photo library access so you can attach images to messages.</string>
<string>Buzz needs photo library access so you can attach images to messages.</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
+1 -1
View File
@@ -59,7 +59,7 @@ class App extends HookConsumerWidget {
});
return MaterialApp(
title: 'Sprout',
title: 'Buzz',
theme: AppTheme.light(colorScheme: lightScheme),
darkTheme: AppTheme.dark(colorScheme: darkScheme),
themeMode: effectiveMode,
@@ -127,7 +127,7 @@ class ToolItem extends TranscriptItem {
final String id;
String title;
String toolName;
String? sproutToolName;
String? buzzToolName;
ToolStatus status;
Map<String, dynamic> args;
String result;
@@ -139,7 +139,7 @@ class ToolItem extends TranscriptItem {
required this.id,
required this.title,
required this.toolName,
this.sproutToolName,
this.buzzToolName,
required this.status,
required this.args,
required this.result,
@@ -3,10 +3,10 @@ import 'dart:convert';
import 'observer_models.dart';
// ---------------------------------------------------------------------------
// Sprout tool catalogs
// Buzz tool catalogs
// ---------------------------------------------------------------------------
const _sproutReadTools = <String>{
const _buzzReadTools = <String>{
'get_messages',
'get_channel_history',
'get_thread',
@@ -27,7 +27,7 @@ const _sproutReadTools = <String>{
'get_contact_list',
};
const _sproutWriteTools = <String>{
const _buzzWriteTools = <String>{
'send_message',
'send_diff_message',
'edit_message',
@@ -61,12 +61,12 @@ const _sproutWriteTools = <String>{
'set_contact_list',
};
final _sproutToolNames = <String>{..._sproutReadTools, ..._sproutWriteTools};
final _buzzToolNames = <String>{..._buzzReadTools, ..._buzzWriteTools};
final _sproutToolNamesByLength = _sproutToolNames.toList()
final _buzzToolNamesByLength = _buzzToolNames.toList()
..sort((a, b) => b.length.compareTo(a.length));
final _sproutToolTitleAliases = <(RegExp, String)>[
final _buzzToolTitleAliases = <(RegExp, String)>[
(RegExp(r'\bsending message to channel\b'), 'send_message'),
(RegExp(r'\bretrieving recent messages from channel\b'), 'get_messages'),
(RegExp(r'\bgetting channel details\b'), 'get_channel'),
@@ -119,12 +119,12 @@ String _normalizeToolNameText(String value) {
.replaceAll(RegExp(r'^_+|_+$'), '');
}
String? _findSproutToolName(String value, bool includeShortNames) {
final alias = _findSproutToolAlias(value);
String? _findBuzzToolName(String value, bool includeShortNames) {
final alias = _findBuzzToolAlias(value);
if (alias != null) return alias;
final normalized = _normalizeToolNameText(value);
for (final name in _sproutToolNamesByLength) {
for (final name in _buzzToolNamesByLength) {
if ((!includeShortNames && name.length < 8) || !normalized.contains(name)) {
continue;
}
@@ -133,13 +133,13 @@ String? _findSproutToolName(String value, bool includeShortNames) {
return null;
}
String? _findSproutToolAlias(String value) {
String? _findBuzzToolAlias(String value) {
final normalizedPhrase = value
.trim()
.toLowerCase()
.replaceAll(RegExp(r'[_-]+'), ' ')
.replaceAll(RegExp(r'\s+'), ' ');
for (final (pattern, name) in _sproutToolTitleAliases) {
for (final (pattern, name) in _buzzToolTitleAliases) {
if (pattern.hasMatch(normalizedPhrase)) return name;
}
return null;
@@ -159,12 +159,12 @@ bool _isGenericToolTitle(String value) {
}
String _normalizeToolName(String title) {
final knownName = _findSproutToolName(title, true);
final knownName = _findBuzzToolName(title, true);
if (knownName != null) return knownName;
final normalized = _normalizeToolNameText(
title,
).replaceAll(RegExp(r'^sprout_'), '');
).replaceAll(RegExp(r'^buzz_'), '');
return RegExp(r'[a-z][a-z0-9_]+').firstMatch(normalized)?[0] ?? normalized;
}
@@ -235,7 +235,7 @@ _parsePromptText(String text) {
PromptSection? eventSection;
for (final section in sections) {
if (section.title.toLowerCase().startsWith('sprout event')) {
if (section.title.toLowerCase().startsWith('buzz event')) {
eventSection = section;
break;
}
@@ -250,7 +250,7 @@ _parsePromptText(String text) {
userText: eventContent,
userTitle: eventKind != null && eventKind.isNotEmpty
? _titleCase(eventKind)
: 'Sprout event',
: 'Buzz event',
);
}
@@ -324,16 +324,16 @@ Map<String, dynamic> _extractToolArgs(Map<String, dynamic> update) {
return const {};
}
({String title, String toolName, String? sproutToolName}) _extractToolIdentity(
({String title, String toolName, String? buzzToolName}) _extractToolIdentity(
Map<String, dynamic> update,
) {
final candidates = _collectToolNameCandidates(update);
String? knownName;
for (final c in candidates) {
knownName = _findSproutToolName(c, true);
knownName = _findBuzzToolName(c, true);
if (knownName != null) break;
}
knownName ??= _findSproutToolName(_safeJsonEncode(update), false);
knownName ??= _findBuzzToolName(_safeJsonEncode(update), false);
String? firstSpecific;
for (final candidate in candidates) {
if (!_isGenericToolTitle(candidate)) {
@@ -346,7 +346,7 @@ Map<String, dynamic> _extractToolArgs(Map<String, dynamic> update) {
return (
title: title,
toolName: knownName ?? _normalizeToolName(firstSpecific ?? title),
sproutToolName: knownName,
buzzToolName: knownName,
);
}
@@ -529,7 +529,7 @@ List<TranscriptItem> buildTranscript(List<ObserverFrame> events) {
String id,
String title,
String toolName,
String? sproutToolName,
String? buzzToolName,
ToolStatus status,
Map<String, dynamic> args,
String result,
@@ -537,16 +537,16 @@ List<TranscriptItem> buildTranscript(List<ObserverFrame> events) {
String timestamp,
) {
final existing = itemsById[id];
final canonicalSproutToolName =
sproutToolName ?? _findSproutToolName(toolName, true);
final canonicalBuzzToolName =
buzzToolName ?? _findBuzzToolName(toolName, true);
if (existing is ToolItem) {
if (!_isGenericToolTitle(title)) {
existing.title = title;
}
if (canonicalSproutToolName != null) {
existing.sproutToolName = canonicalSproutToolName;
existing.toolName = canonicalSproutToolName;
} else if (existing.sproutToolName == null &&
if (canonicalBuzzToolName != null) {
existing.buzzToolName = canonicalBuzzToolName;
existing.toolName = canonicalBuzzToolName;
} else if (existing.buzzToolName == null &&
!_isGenericToolTitle(toolName)) {
existing.toolName = toolName;
}
@@ -560,8 +560,8 @@ List<TranscriptItem> buildTranscript(List<ObserverFrame> events) {
final item = ToolItem(
id: id,
title: title,
toolName: canonicalSproutToolName ?? toolName,
sproutToolName: canonicalSproutToolName,
toolName: canonicalBuzzToolName ?? toolName,
buzzToolName: canonicalBuzzToolName,
status: status,
args: args,
result: result,
@@ -688,7 +688,7 @@ List<TranscriptItem> buildTranscript(List<ObserverFrame> events) {
'tool:$toolId',
identity.title,
identity.toolName,
identity.sproutToolName,
identity.buzzToolName,
_normalizeToolStatus(_asString(update['status']) ?? 'executing'),
_extractToolArgs(update),
_extractToolResult(update),
@@ -708,7 +708,7 @@ List<TranscriptItem> buildTranscript(List<ObserverFrame> events) {
'tool:$toolId',
identity.title,
identity.toolName,
identity.sproutToolName,
identity.buzzToolName,
status,
_extractToolArgs(update),
_extractToolResult(update),
@@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
String channelMutesKey(String pubkey) => 'sprout.channel-mutes.v1:$pubkey';
String channelMutesKey(String pubkey) => 'buzz.channel-mutes.v1:$pubkey';
class ChannelMuteEntry {
final bool muted;
@@ -2,8 +2,7 @@ import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
String channelSectionsKey(String pubkey) =>
'sprout.channel-sections.v1:$pubkey';
String channelSectionsKey(String pubkey) => 'buzz.channel-sections.v1:$pubkey';
class ChannelSection {
final String id;
@@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
String channelStarsKey(String pubkey) => 'sprout.channel-stars.v1:$pubkey';
String channelStarsKey(String pubkey) => 'buzz.channel-stars.v1:$pubkey';
class ChannelStarEntry {
final bool starred;
@@ -159,7 +159,7 @@ const emojiCategories = <({String label, IconData icon, List<String> emoji})>[
),
(
label: 'Nature',
icon: LucideIcons.sprout,
icon: LucideIcons.leaf,
emoji: [
'\u{1F331}',
'\u{1F332}',
@@ -8,18 +8,17 @@ import 'package:uuid/uuid.dart';
import 'read_state_format.dart';
import 'read_state_time.dart';
const _clientIdKeyPrefix = 'sprout.nip-rs.client-id';
const _slotIdKeyPrefix = 'sprout.nip-rs.slot-id';
const _clientIdKeyPrefix = 'buzz.nip-rs.client-id';
const _slotIdKeyPrefix = 'buzz.nip-rs.slot-id';
const _uuid = Uuid();
String localReadStateKey(String pubkey) =>
'sprout.channel-read-state.v2:$pubkey';
String localReadStateKey(String pubkey) => 'buzz.channel-read-state.v2:$pubkey';
String localPublishableContextKey(String pubkey) =>
'sprout.channel-read-state.publishable.v1:$pubkey';
'buzz.channel-read-state.publishable.v1:$pubkey';
String localSourceCreatedAtKey(String pubkey) =>
'sprout.channel-read-state.source-created-at.v1:$pubkey';
'buzz.channel-read-state.source-created-at.v1:$pubkey';
String clientIdKey(String pubkey) => '$_clientIdKeyPrefix:$pubkey';
@@ -212,7 +212,7 @@ List<TimelineMessage> formatTimeline(
String? currentPubkey,
}) {
// 1. Collect deletion targets. Both kind:5 (NIP-09) and kind:9005
// (Sprout-native) are deletion markers; mirror desktop's behavior.
// (Buzz-native) are deletion markers; mirror desktop's behavior.
final deletedIds = <String>{};
for (final event in events) {
if (event.kind != EventKind.deletion &&
@@ -29,7 +29,7 @@ class CustomEmoji {
const int kindEmojiSet = 30030;
/// d-tag for a member's own custom emoji set.
const String customEmojiSetDTag = 'sprout:custom-emoji';
const String customEmojiSetDTag = 'buzz:custom-emoji';
final RegExp _shortcodeRe = RegExp(r'^[a-z0-9_-]+$');
@@ -67,13 +67,13 @@ class PairingPage extends HookConsumerWidget {
// Branding
Icon(
LucideIcons.sprout,
LucideIcons.hexagon,
size: 64,
color: context.colors.primary,
),
const SizedBox(height: Grid.xs),
Text(
'Welcome to Sprout',
'Welcome to Buzz',
style: context.textTheme.headlineSmall,
),
const SizedBox(height: Grid.xxs),
@@ -123,7 +123,7 @@ class PairingPage extends HookConsumerWidget {
TextField(
controller: codeController,
decoration: const InputDecoration(
hintText: 'nostrpair://... or sprout://...',
hintText: 'nostrpair://... or buzz://...',
prefixIcon: Icon(LucideIcons.link),
isDense: true,
),
@@ -284,7 +284,7 @@ class _SasVerificationView extends StatelessWidget {
const SizedBox(height: Grid.lg),
Text(
'You are about to transfer your Sprout identity\nto this device. Only confirm if you initiated\nthis pairing from your desktop.',
'You are about to transfer your Buzz identity\nto this device. Only confirm if you initiated\nthis pairing from your desktop.',
textAlign: TextAlign.center,
style: context.textTheme.bodySmall?.copyWith(
color: context.colors.onSurfaceVariant,
@@ -75,7 +75,7 @@ class PairingNotifier extends Notifier<PairingState> {
if (trimmed.startsWith('nostrpair://')) {
return _pairNipAb(trimmed);
}
// Legacy sprout:// flow.
// Legacy buzz:// flow.
return _pairLegacy(trimmed);
}
@@ -526,7 +526,7 @@ class PairingNotifier extends Notifier<PairingState> {
);
}
// ── Legacy sprout:// flow ───────────────────────────────────────────────
// ── Legacy buzz:// flow ───────────────────────────────────────────────
Future<void> _pairLegacy(String rawInput) async {
state = const PairingState(status: PairingStatus.connecting);
@@ -593,8 +593,8 @@ class PairingNotifier extends Notifier<PairingState> {
Workspace _parseLegacyInput(String raw) {
var payload = raw.trim();
if (payload.startsWith('sprout://')) {
payload = payload.substring('sprout://'.length);
if (payload.startsWith('buzz://')) {
payload = payload.substring('buzz://'.length);
}
final normalized = base64Url.normalize(payload);
+2 -2
View File
@@ -12,7 +12,7 @@ import 'package:pointycastle/digests/sha256.dart';
import 'relay_provider.dart';
const _mediaUploadPath = '/media/upload';
const _mediaUploadPlatformChannelName = 'sprout/media_upload';
const _mediaUploadPlatformChannelName = 'buzz/media_upload';
const _sanitizeImageForUploadMethod = 'sanitizeImageForUpload';
const _transcodeVideoToMp4Method = 'transcodeVideoToMp4';
const _transcodeImageToJpegMethod = 'transcodeImageToJpeg';
@@ -298,7 +298,7 @@ class MediaUploadService {
return nostr.Event.from(
kind: _uploadAuthKind,
content: 'Upload sprout-media',
content: 'Upload buzz-media',
tags: tags,
secretKey: privkeyHex,
verify: false,
+1 -1
View File
@@ -1,6 +1,6 @@
import 'nostr_models.dart';
/// Canonical [NostrFilter] constructors for common Sprout queries.
/// Canonical [NostrFilter] constructors for common Buzz queries.
///
/// Centralising filter shapes keeps relay queries consistent across providers
/// and makes kind/tag conventions easy to audit.
+2 -2
View File
@@ -38,7 +38,7 @@ abstract final class EventKind {
static const channelEventKinds = [
deletion, // 5
reaction, // 7
nip29DeleteEvent, // 9005 — Sprout-native deletion
nip29DeleteEvent, // 9005 — Buzz-native deletion
...channelMessageEventKinds,
40001, // legacy pre-migration stream messages
streamMessageEdit, // 40003
@@ -337,7 +337,7 @@ List<MemberEntry> membersFromEvent(NostrEvent event) {
];
}
/// Parse a Sprout command response from the relay's OK message content.
/// Parse a Buzz command response from the relay's OK message content.
///
/// Command kinds (e.g. 41010, 30620, 46020) return `"response:{...}"` in the
/// OK message. Returns `null` if the message is not a command response or the
+1 -1
View File
@@ -1,6 +1,6 @@
import 'package:http/http.dart' as http;
/// Lightweight HTTP context for talking to the Sprout relay.
/// Lightweight HTTP context for talking to the Buzz relay.
///
/// In the pure-nostr architecture, all data flow happens over the relay
/// WebSocket. This client now exists only to provide a base URL (and a
+2 -2
View File
@@ -28,12 +28,12 @@ class RelayConfig {
/// Compile-time environment config via --dart-define.
///
/// Run with:
/// flutter run --dart-define=SPROUT_RELAY_URL=http://localhost:3000
/// flutter run --dart-define=BUZZ_RELAY_URL=http://localhost:3000
///
/// Or create a `.env.json` and use --dart-define-from-file=.env.json
class Env {
static const relayUrl = String.fromEnvironment(
'SPROUT_RELAY_URL',
'BUZZ_RELAY_URL',
defaultValue: 'http://localhost:3000',
);
}
+1 -1
View File
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
/// Accent colors matching the desktop Sprout app.
/// Accent colors matching the desktop Buzz app.
class AccentColor {
final String name;
final Color light;
+2 -2
View File
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'accent_colors.dart';
// Catppuccin Latte (mauve accent) — matches Sprout desktop light theme
// Catppuccin Latte (mauve accent) — matches Buzz desktop light theme
const lightColorScheme = ColorScheme(
brightness: Brightness.light,
primary: Color(0xFF8839EF), // Latte Mauve
@@ -35,7 +35,7 @@ const lightColorScheme = ColorScheme(
surfaceContainerHighest: Color(0xFFFFFFFF),
);
// Catppuccin Macchiato (mauve accent) — matches Sprout desktop dark theme
// Catppuccin Macchiato (mauve accent) — matches Buzz desktop dark theme
const darkColorScheme = ColorScheme(
brightness: Brightness.dark,
primary: Color(0xFFA875F5), // Macchiato Mauve (saturated)
+3 -3
View File
@@ -7,9 +7,9 @@ import 'adaptive_theme.dart';
import 'color_scheme.dart';
import 'theme_catalog.dart';
const _themeModeKey = 'sprout_theme_mode';
const _accentKey = 'sprout_accent_color';
const _schemeKey = 'sprout_color_scheme';
const _themeModeKey = 'buzz_theme_mode';
const _accentKey = 'buzz_accent_color';
const _schemeKey = 'buzz_color_scheme';
/// Pre-loaded SharedPreferences instance, overridden in main().
final savedPrefsProvider = Provider<SharedPreferences>(
@@ -5,14 +5,14 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'workspace.dart';
class WorkspaceStorage {
static const _keyWorkspaces = 'sprout_workspaces';
static const _keyActiveId = 'sprout_active_workspace_id';
static const _keyWorkspaces = 'buzz_workspaces';
static const _keyActiveId = 'buzz_active_workspace_id';
// Legacy keys for migration.
static const _legacyRelayUrl = 'sprout_relay_url';
static const _legacyToken = 'sprout_token';
static const _legacyPubkey = 'sprout_pubkey';
static const _legacyNsec = 'sprout_nsec';
static const _legacyRelayUrl = 'buzz_relay_url';
static const _legacyToken = 'buzz_token';
static const _legacyPubkey = 'buzz_pubkey';
static const _legacyNsec = 'buzz_nsec';
final FlutterSecureStorage _secure;
+2 -2
View File
@@ -1,5 +1,5 @@
name: sprout_mobile
description: Sprout mobile client
name: buzz
description: Buzz mobile client
publish_to: 'none'
version: 0.3.16+1
@@ -4,14 +4,14 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:hooks_riverpod/misc.dart';
import 'package:sprout_mobile/features/activity/activity_page.dart';
import 'package:sprout_mobile/features/activity/activity_provider.dart';
import 'package:sprout_mobile/features/activity/feed_item.dart';
import 'package:sprout_mobile/features/channels/channel.dart';
import 'package:sprout_mobile/features/channels/channels_provider.dart';
import 'package:sprout_mobile/features/profile/user_cache_provider.dart';
import 'package:sprout_mobile/features/profile/user_profile.dart';
import 'package:sprout_mobile/shared/theme/theme.dart';
import 'package:buzz/features/activity/activity_page.dart';
import 'package:buzz/features/activity/activity_provider.dart';
import 'package:buzz/features/activity/feed_item.dart';
import 'package:buzz/features/channels/channel.dart';
import 'package:buzz/features/channels/channels_provider.dart';
import 'package:buzz/features/profile/user_cache_provider.dart';
import 'package:buzz/features/profile/user_profile.dart';
import 'package:buzz/shared/theme/theme.dart';
void main() {
Widget buildTestable({required List<Override> overrides}) {
@@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/activity/feed_item.dart';
import 'package:buzz/features/activity/feed_item.dart';
void main() {
group('FeedItem.fromJson', () {
@@ -4,10 +4,10 @@ import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:nostr/nostr.dart' as nostr;
import 'package:sprout_mobile/features/channels/agent_activity/observer_models.dart';
import 'package:sprout_mobile/features/channels/agent_activity/observer_subscription.dart';
import 'package:sprout_mobile/shared/crypto/nip44.dart';
import 'package:sprout_mobile/shared/relay/relay.dart';
import 'package:buzz/features/channels/agent_activity/observer_models.dart';
import 'package:buzz/features/channels/agent_activity/observer_subscription.dart';
import 'package:buzz/shared/crypto/nip44.dart';
import 'package:buzz/shared/relay/relay.dart';
void main() {
test('provider initializes without circular dependency error', () {
@@ -1,6 +1,6 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/channels/agent_activity/observer_models.dart';
import 'package:sprout_mobile/features/channels/agent_activity/transcript_builder.dart';
import 'package:buzz/features/channels/agent_activity/observer_models.dart';
import 'package:buzz/features/channels/agent_activity/transcript_builder.dart';
void main() {
test('aggregates assistant chunks until another item seals the message', () {
@@ -54,7 +54,7 @@ void main() {
expect((items[2] as MessageItem).text, 'Done');
});
test('normalizes sprout tool calls and applies result updates', () {
test('normalizes buzz tool calls and applies result updates', () {
final items = buildTranscript([
_updateFrame(
seq: 1,
@@ -82,14 +82,14 @@ void main() {
expect(items, hasLength(1));
expect(items.single, isA<ToolItem>());
final tool = items.single as ToolItem;
expect(tool.sproutToolName, 'send_message');
expect(tool.buzzToolName, 'send_message');
expect(tool.toolName, 'send_message');
expect(tool.status, ToolStatus.completed);
expect(tool.args, {'content': 'hi'});
expect(tool.result, 'posted #activity-test-channel');
});
test('parses sprout prompt text into user message and metadata', () {
test('parses buzz prompt text into user message and metadata', () {
final items = buildTranscript([
ObserverFrame(
seq: 1,
@@ -102,7 +102,7 @@ void main() {
'prompt': [
{
'content':
'[Sprout event: stream message]\n'
'[Buzz event: stream message]\n'
'Content: @claude can you do that again?\n\n'
'[Channel]\n'
'#activity-test-channel',
@@ -5,18 +5,18 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:sprout_mobile/features/channels/channel.dart';
import 'package:sprout_mobile/features/channels/channel_detail_page.dart';
import 'package:sprout_mobile/features/channels/channel_management_provider.dart';
import 'package:sprout_mobile/features/channels/channel_messages_provider.dart';
import 'package:sprout_mobile/features/channels/channel_typing_provider.dart';
import 'package:sprout_mobile/features/channels/channels_provider.dart';
import 'package:sprout_mobile/features/channels/read_state/read_state_provider.dart';
import 'package:sprout_mobile/features/profile/profile_provider.dart';
import 'package:sprout_mobile/features/profile/user_cache_provider.dart';
import 'package:sprout_mobile/features/profile/user_profile.dart';
import 'package:sprout_mobile/shared/relay/relay.dart';
import 'package:sprout_mobile/shared/theme/theme.dart';
import 'package:buzz/features/channels/channel.dart';
import 'package:buzz/features/channels/channel_detail_page.dart';
import 'package:buzz/features/channels/channel_management_provider.dart';
import 'package:buzz/features/channels/channel_messages_provider.dart';
import 'package:buzz/features/channels/channel_typing_provider.dart';
import 'package:buzz/features/channels/channels_provider.dart';
import 'package:buzz/features/channels/read_state/read_state_provider.dart';
import 'package:buzz/features/profile/profile_provider.dart';
import 'package:buzz/features/profile/user_cache_provider.dart';
import 'package:buzz/features/profile/user_profile.dart';
import 'package:buzz/shared/relay/relay.dart';
import 'package:buzz/shared/theme/theme.dart';
// ---------------------------------------------------------------------------
// Test fixtures
@@ -1,6 +1,6 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/channels/channel_management_provider.dart';
import 'package:sprout_mobile/shared/relay/relay.dart';
import 'package:buzz/features/channels/channel_management_provider.dart';
import 'package:buzz/shared/relay/relay.dart';
/// Tests for [channelDetailsFromEvent].
///
@@ -2,8 +2,8 @@ import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:sprout_mobile/features/channels/channel_messages_provider.dart';
import 'package:sprout_mobile/shared/relay/relay.dart';
import 'package:buzz/features/channels/channel_messages_provider.dart';
import 'package:buzz/shared/relay/relay.dart';
void main() {
test(
@@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/channels/channel_stars/channel_stars_storage.dart';
import 'package:buzz/features/channels/channel_stars/channel_stars_storage.dart';
/// Tests for [ChannelStarStore] parsing and [mergeStores] last-writer-wins.
void main() {
@@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/channels/channel.dart';
import 'package:buzz/features/channels/channel.dart';
void main() {
group('Channel.fromJson', () {
@@ -2,13 +2,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:hooks_riverpod/misc.dart';
import 'package:sprout_mobile/features/channels/channel.dart';
import 'package:sprout_mobile/features/channels/channels_page.dart';
import 'package:sprout_mobile/features/channels/channels_provider.dart';
import 'package:sprout_mobile/features/channels/read_state/read_state_provider.dart';
import 'package:sprout_mobile/features/profile/profile_provider.dart';
import 'package:sprout_mobile/features/profile/user_profile.dart';
import 'package:sprout_mobile/shared/theme/theme.dart';
import 'package:buzz/features/channels/channel.dart';
import 'package:buzz/features/channels/channels_page.dart';
import 'package:buzz/features/channels/channels_provider.dart';
import 'package:buzz/features/channels/read_state/read_state_provider.dart';
import 'package:buzz/features/profile/profile_provider.dart';
import 'package:buzz/features/profile/user_profile.dart';
import 'package:buzz/shared/theme/theme.dart';
void main() {
Widget buildTestable({required List<Override> overrides}) {
@@ -1,9 +1,9 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:sprout_mobile/features/channels/channel_management_provider.dart';
import 'package:sprout_mobile/features/channels/channels_provider.dart';
import 'package:sprout_mobile/shared/relay/relay.dart';
import 'package:buzz/features/channels/channel_management_provider.dart';
import 'package:buzz/features/channels/channels_provider.dart';
import 'package:buzz/shared/relay/relay.dart';
/// Tests for [ChannelsNotifier] in the pure-Nostr world.
///
@@ -10,11 +10,11 @@ import 'package:http/testing.dart' as http_testing;
import 'package:image_picker/image_picker.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:nostr/nostr.dart' as nostr;
import 'package:sprout_mobile/features/channels/channel.dart';
import 'package:sprout_mobile/features/channels/channel_management_provider.dart';
import 'package:sprout_mobile/features/channels/compose_bar.dart';
import 'package:sprout_mobile/shared/relay/relay.dart';
import 'package:sprout_mobile/shared/theme/theme.dart';
import 'package:buzz/features/channels/channel.dart';
import 'package:buzz/features/channels/channel_management_provider.dart';
import 'package:buzz/features/channels/compose_bar.dart';
import 'package:buzz/shared/relay/relay.dart';
import 'package:buzz/shared/theme/theme.dart';
final _pngBytes = Uint8List.fromList([
0x89,
@@ -96,7 +96,7 @@ final _apngBytes = Uint8List.fromList([
0x00,
]);
const _mediaUploadPlatformChannel = MethodChannel('sprout/media_upload');
const _mediaUploadPlatformChannel = MethodChannel('buzz/media_upload');
void _setMockMediaUploadPlatformHandler(
Future<Object?> Function(MethodCall call)? handler,
@@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/channels/date_formatters.dart';
import 'package:buzz/features/channels/date_formatters.dart';
/// Helper: build a unix-second timestamp from a local DateTime.
int _ts(DateTime local) => local.millisecondsSinceEpoch ~/ 1000;
@@ -3,9 +3,9 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:hooks_riverpod/misc.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:sprout_mobile/features/channels/message_content.dart';
import 'package:sprout_mobile/features/channels/media_viewer_page.dart';
import 'package:sprout_mobile/shared/theme/theme.dart';
import 'package:buzz/features/channels/message_content.dart';
import 'package:buzz/features/channels/media_viewer_page.dart';
import 'package:buzz/shared/theme/theme.dart';
Widget _testable(Widget child, {List<Override> overrides = const []}) {
return ProviderScope(
@@ -245,16 +245,14 @@ void main() {
testWidgets('renders markdown link', (tester) async {
await tester.pumpWidget(
_testable(
const MessageContent(
content: 'Check [Sprout](https://example.com)',
),
const MessageContent(content: 'Check [Buzz](https://example.com)'),
),
);
final allText = _allRichText(tester);
expect(allText, contains('Sprout'));
expect(allText, contains('Buzz'));
// Should not show raw markdown syntax.
expect(allText, isNot(contains('[Sprout]')));
expect(allText, isNot(contains('[Buzz]')));
expect(allText, isNot(contains('(https://example.com)')));
});
@@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/channels/message_media.dart';
import 'package:buzz/features/channels/message_media.dart';
void main() {
group('classifyMediaUrl', () {
@@ -1,8 +1,8 @@
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/channels/read_state/read_state_format.dart';
import 'package:sprout_mobile/shared/relay/nostr_models.dart';
import 'package:buzz/features/channels/read_state/read_state_format.dart';
import 'package:buzz/shared/relay/nostr_models.dart';
void main() {
group('read state event validation', () {
@@ -4,9 +4,9 @@ import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:nostr/nostr.dart' as nostr;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sprout_mobile/features/channels/read_state/read_state_format.dart';
import 'package:sprout_mobile/features/channels/read_state/read_state_manager.dart';
import 'package:sprout_mobile/shared/relay/relay.dart';
import 'package:buzz/features/channels/read_state/read_state_format.dart';
import 'package:buzz/features/channels/read_state/read_state_manager.dart';
import 'package:buzz/shared/relay/relay.dart';
void main() {
test('dispose flushes a pending publish after marking disposed', () async {
@@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/channels/read_state/read_state_time.dart';
import 'package:buzz/features/channels/read_state/read_state_time.dart';
void main() {
test('dateTimeToUnixSeconds converts DateTime values and nulls', () {
@@ -1,8 +1,8 @@
import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/channels/timeline_message.dart';
import 'package:sprout_mobile/shared/relay/relay.dart';
import 'package:buzz/features/channels/timeline_message.dart';
import 'package:buzz/shared/relay/relay.dart';
// ---------------------------------------------------------------------------
// Helpers
@@ -328,7 +328,7 @@ void main() {
expect(result[0].content, 'keep');
});
test('filters messages deleted via kind:9005 (Sprout-native)', () {
test('filters messages deleted via kind:9005 (Buzz-native)', () {
// Agents emit kind:9005 deletes via the CLI. Mobile must mirror desktop
// and treat 9005 as a deletion marker, otherwise agent-deleted messages
// stay rendered until manual refresh.
@@ -2,10 +2,10 @@ import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:sprout_mobile/features/channels/channel.dart';
import 'package:sprout_mobile/features/channels/channels_provider.dart';
import 'package:sprout_mobile/features/channels/read_state/read_state_provider.dart';
import 'package:sprout_mobile/features/channels/unread_badge/unread_badge_provider.dart';
import 'package:buzz/features/channels/channel.dart';
import 'package:buzz/features/channels/channels_provider.dart';
import 'package:buzz/features/channels/read_state/read_state_provider.dart';
import 'package:buzz/features/channels/unread_badge/unread_badge_provider.dart';
/// Unit tests for [unreadBadgeProvider].
///
@@ -1,6 +1,6 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/custom_emoji/custom_emoji.dart';
import 'package:sprout_mobile/shared/relay/nostr_models.dart';
import 'package:buzz/features/custom_emoji/custom_emoji.dart';
import 'package:buzz/shared/relay/nostr_models.dart';
NostrEvent _event(String pubkey, List<List<String>> emojiTags) {
return NostrEvent(
@@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/features/forum/forum_models.dart';
import 'package:buzz/features/forum/forum_models.dart';
// ---------------------------------------------------------------------------
// Helpers
@@ -1,17 +1,17 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:sprout_mobile/features/channels/channel.dart';
import 'package:sprout_mobile/features/forum/forum_models.dart';
import 'package:sprout_mobile/features/forum/forum_post_card.dart';
import 'package:sprout_mobile/features/forum/forum_posts_view.dart';
import 'package:sprout_mobile/features/forum/forum_provider.dart';
import 'package:sprout_mobile/features/forum/forum_thread_page.dart';
import 'package:sprout_mobile/features/profile/profile_provider.dart';
import 'package:sprout_mobile/features/profile/user_cache_provider.dart';
import 'package:sprout_mobile/features/profile/user_profile.dart';
import 'package:sprout_mobile/shared/relay/relay.dart';
import 'package:sprout_mobile/shared/theme/theme.dart';
import 'package:buzz/features/channels/channel.dart';
import 'package:buzz/features/forum/forum_models.dart';
import 'package:buzz/features/forum/forum_post_card.dart';
import 'package:buzz/features/forum/forum_posts_view.dart';
import 'package:buzz/features/forum/forum_provider.dart';
import 'package:buzz/features/forum/forum_thread_page.dart';
import 'package:buzz/features/profile/profile_provider.dart';
import 'package:buzz/features/profile/user_cache_provider.dart';
import 'package:buzz/features/profile/user_profile.dart';
import 'package:buzz/shared/relay/relay.dart';
import 'package:buzz/shared/theme/theme.dart';
// ---------------------------------------------------------------------------
// Test fixtures
@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:sprout_mobile/features/pairing/pairing_page.dart';
import 'package:sprout_mobile/features/pairing/pairing_provider.dart';
import 'package:buzz/features/pairing/pairing_page.dart';
import 'package:buzz/features/pairing/pairing_provider.dart';
import '../../helpers/widget_helpers.dart';
@@ -15,7 +15,7 @@ void main() {
WidgetHelpers.testable(child: const PairingPage()),
);
expect(find.text('Welcome to Sprout'), findsOneWidget);
expect(find.text('Welcome to Buzz'), findsOneWidget);
expect(find.text('Scan QR Code'), findsOneWidget);
expect(find.text('or paste pairing code'), findsOneWidget);
expect(find.text('Connect'), findsOneWidget);
@@ -2,10 +2,10 @@ import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:sprout_mobile/features/pairing/pairing_provider.dart';
import 'package:sprout_mobile/shared/auth/auth.dart';
import 'package:buzz/features/pairing/pairing_provider.dart';
import 'package:buzz/shared/auth/auth.dart';
/// Tests for [PairingNotifier]'s legacy `sprout://` payload parsing and
/// Tests for [PairingNotifier]'s legacy `buzz://` payload parsing and
/// SSRF-prevention validation.
///
/// The pairing flow used to validate by calling `GET /api/users/me/profile`
@@ -16,7 +16,7 @@ import 'package:sprout_mobile/shared/auth/auth.dart';
///
/// What we still cover here:
/// - Initial state.
/// - Parsing every documented payload format (raw base64, `sprout://`
/// - Parsing every documented payload format (raw base64, `buzz://`
/// prefix, whitespace).
/// - Failure modes that return BEFORE any network call: invalid base64,
/// wrong shape (non-object, missing fields, missing nsec), and SSRF
@@ -57,6 +57,18 @@ void main() {
expect(fakeAuth.lastWorkspace, isNull);
});
test('accepts buzz scheme prefix', () async {
container = createContainer();
final code = 'buzz://${_encodePairingCode()}';
await container.read(pairingProvider.notifier).pair(code);
final state = container.read(pairingProvider);
expect(state.status, PairingStatus.error);
expect(state.errorMessage, contains('missing nsec'));
expect(fakeAuth.lastWorkspace, isNull);
});
test('invalid base64 sets format error', () async {
container = createContainer();
@@ -1,8 +1,8 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:sprout_mobile/features/profile/presence_cache_provider.dart';
import 'package:sprout_mobile/shared/relay/relay.dart';
import 'package:buzz/features/profile/presence_cache_provider.dart';
import 'package:buzz/shared/relay/relay.dart';
/// Tests for [PresenceCacheNotifier] in the pure-Nostr world.
///
@@ -1,11 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:sprout_mobile/features/profile/user_cache_provider.dart';
import 'package:sprout_mobile/features/profile/user_profile.dart';
import 'package:sprout_mobile/features/pulse/compose_note_page.dart';
import 'package:sprout_mobile/features/pulse/pulse_models.dart';
import 'package:sprout_mobile/shared/theme/theme.dart';
import 'package:buzz/features/profile/user_cache_provider.dart';
import 'package:buzz/features/profile/user_profile.dart';
import 'package:buzz/features/pulse/compose_note_page.dart';
import 'package:buzz/features/pulse/pulse_models.dart';
import 'package:buzz/shared/theme/theme.dart';
class _FakeUserCacheNotifier extends UserCacheNotifier {
final Map<String, UserProfile> _users;
@@ -87,7 +87,7 @@ void main() {
id: 'note2',
pubkey: 'alice_pk',
createdAt: DateTime.now().millisecondsSinceEpoch ~/ 1000 - 60,
content: '#sprout\n![image](https://example.com/big.png)',
content: '#buzz\n![image](https://example.com/big.png)',
tags: const [
[
'imeta',
+1 -1
View File
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:hooks_riverpod/misc.dart';
import 'package:sprout_mobile/shared/theme/theme.dart';
import 'package:buzz/shared/theme/theme.dart';
class WidgetHelpers {
static Widget testable({
@@ -8,7 +8,7 @@ import 'package:http/http.dart' as http;
import 'package:http/testing.dart' as http_testing;
import 'package:image_picker/image_picker.dart';
import 'package:nostr/nostr.dart' as nostr;
import 'package:sprout_mobile/shared/relay/media_upload.dart';
import 'package:buzz/shared/relay/media_upload.dart';
final _pngBytes = Uint8List.fromList([
0x89,
@@ -204,7 +204,7 @@ final _animatedWebpBytes = Uint8List.fromList([
0x00,
]);
const _mediaUploadPlatformChannel = MethodChannel('sprout/media_upload');
const _mediaUploadPlatformChannel = MethodChannel('buzz/media_upload');
void _setMockMediaUploadPlatformHandler(
Future<Object?> Function(MethodCall call)? handler,
@@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:sprout_mobile/shared/relay/nostr_models.dart';
import 'package:buzz/shared/relay/nostr_models.dart';
void main() {
test('NostrFilter serializes and preserves authors', () {

Some files were not shown because too many files have changed in this diff Show More