mobile bluesky app made with flutter lazurite.stormlightlabs.org/
mobile bluesky flutter
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: move edit profile button to header

+35 -15
+26 -11
lib/features/profile/presentation/profile_screen.dart
··· 585 585 actions: [ 586 586 if (actorScopedProfile != null && isOwnProfile) 587 587 IconButton( 588 + key: const Key('profile_edit_header_button'), 589 + icon: const Icon(Icons.edit_outlined), 590 + tooltip: 'Edit profile', 591 + onPressed: () => context.push('/profile/me/edit'), 592 + ), 593 + if (actorScopedProfile != null && isOwnProfile) 594 + IconButton( 588 595 key: const Key('profile_more_button'), 589 596 icon: const Icon(Icons.more_vert), 590 597 onPressed: () => _showOwnProfileMoreOptions(context, actorScopedProfile), ··· 787 794 final profileUi = 788 795 moderationService?.profileDetailedUi(profile, bsky_moderation.ModerationBehaviorContext.profileView) ?? 789 796 const bsky_moderation.ModerationUI(); 797 + final pronouns = profile.pronouns?.trim(); 790 798 791 799 final metaChildren = <Widget>[ 792 - if (profile.pronouns?.isNotEmpty ?? false) 793 - _buildMetaChip(context, Icons.record_voice_over_outlined, profile.pronouns!), 794 800 if (profile.website?.isNotEmpty ?? false) 795 801 _buildMetaChip( 796 802 context, ··· 812 818 child: Column( 813 819 crossAxisAlignment: CrossAxisAlignment.start, 814 820 children: [ 815 - Text( 816 - (profile.displayName ?? profile.handle).toUpperCase(), 817 - style: textTheme.headlineLarge?.copyWith(fontWeight: FontWeight.w600, letterSpacing: -0.5), 821 + Wrap( 822 + crossAxisAlignment: WrapCrossAlignment.center, 823 + spacing: 10, 824 + runSpacing: 4, 825 + children: [ 826 + Text( 827 + (profile.displayName ?? profile.handle).toUpperCase(), 828 + style: textTheme.headlineLarge?.copyWith(fontWeight: FontWeight.w600, letterSpacing: 0), 829 + ), 830 + if (pronouns != null && pronouns.isNotEmpty) 831 + Text( 832 + pronouns, 833 + style: textTheme.labelLarge?.copyWith( 834 + color: colorScheme.onSurfaceVariant, 835 + fontWeight: FontWeight.w600, 836 + ), 837 + ), 838 + ], 818 839 ), 819 840 const SizedBox(height: 4), 820 841 ··· 867 888 spacing: 8, 868 889 runSpacing: 8, 869 890 children: [ 870 - OutlinedButton.icon( 871 - key: const ValueKey('profile_edit_button'), 872 - onPressed: () => context.push('/profile/me/edit'), 873 - icon: const Icon(Icons.edit_outlined), 874 - label: const Text('Edit Profile'), 875 - ), 876 891 OutlinedButton.icon( 877 892 onPressed: () => context.push('/bookmarks'), 878 893 icon: const Icon(Icons.bookmark_outline),
+9 -4
test/features/profile/presentation/profile_screen_test.dart
··· 169 169 findsOneWidget, 170 170 ); 171 171 expect(find.text('she/her'), findsOneWidget); 172 + final nameTop = tester.getTopLeft(find.text('RIVER TAM')).dy; 173 + final pronounsTop = tester.getTopLeft(find.text('she/her')).dy; 174 + expect((nameTop - pronounsTop).abs(), lessThan(12)); 172 175 expect(find.text('river.example'), findsOneWidget); 173 176 expect(find.byIcon(Icons.open_in_new), findsOneWidget); 174 177 expect(find.text('Joined March 2024'), findsOneWidget); ··· 181 184 expect(find.text('River Tam'), findsOneWidget); 182 185 }); 183 186 184 - testWidgets('shows own profile shortcut buttons', (tester) async { 187 + testWidgets('shows own profile header edit action and shortcut buttons', (tester) async { 185 188 useLargeScreen(tester); 186 189 await tester.pumpWidget(buildSubject()); 187 190 188 - expect(find.text('Edit Profile'), findsOneWidget); 191 + expect(find.byKey(const Key('profile_edit_header_button')), findsOneWidget); 192 + expect(find.text('Edit Profile'), findsNothing); 189 193 expect(find.text('Bookmarks'), findsOneWidget); 190 194 expect(find.text('Liked'), findsOneWidget); 191 195 }); 192 196 193 - testWidgets('edit profile shortcut opens the profile edit route', (tester) async { 197 + testWidgets('header edit profile action opens the profile edit route', (tester) async { 194 198 useLargeScreen(tester); 195 199 final router = GoRouter( 196 200 routes: [ ··· 217 221 await tester.pumpWidget(MaterialApp.router(routerConfig: router)); 218 222 await tester.pumpAndSettle(); 219 223 220 - await tester.tap(find.byKey(const ValueKey('profile_edit_button'))); 224 + await tester.tap(find.byKey(const Key('profile_edit_header_button'))); 221 225 await tester.pumpAndSettle(); 222 226 223 227 expect(find.text('edit-profile'), findsOneWidget); ··· 293 297 294 298 await tester.pumpWidget(widget); 295 299 300 + expect(find.byKey(const Key('profile_edit_header_button')), findsNothing); 296 301 expect(find.text('Edit Profile'), findsNothing); 297 302 expect(find.text('Bookmarks'), findsNothing); 298 303 expect(find.text('Liked'), findsNothing);