Files
App/docs/activitypub/UI_IMPLEMENTATION.md

299 lines
8.2 KiB
Markdown

# ActivityPub UI Implementation
## Overview
Complete UI implementation for ActivityPub features in Solian client, including search, following, and followers screens.
## Created Files
### 1. Widgets (`lib/widgets/activitypub/`)
#### `activitypub.dart`
- **Purpose**: Export file for ActivityPub widgets
- **Exports**: `ActivityPubUserListItem`
#### `user_list_item.dart`
- **Purpose**: Reusable list item widget for displaying ActivityPub users
- **Features**:
- Avatar with remote instance indicator (public icon)
- Display name with instance badge (e.g., "mastodon.social")
- Bio with truncation (max 2 lines)
- Followed at timestamp (relative time)
- Follow/Unfollow buttons with loading states
- Tap callback for navigation to profile
### 2. Screens (`lib/screens/activitypub/`)
#### `activitypub.dart`
- **Purpose**: Export file for ActivityPub screens
- **Exports**: `ActivityPubSearchScreen`, `ActivityPubListScreen`
#### `search.dart`
- **Purpose**: Search and follow ActivityPub users from other instances
- **Features**:
- Search bar with 500ms debounce
- Real-time search results
- Instant follow/unfollow actions
- Local tracking of followed users
- Empty states for no search and no results
- Refresh support via pull-to-refresh
- User feedback via snack bars
- **User Flow**:
1. User enters search query (e.g., `@alice@mastodon.social`)
2. Results appear after debounce
3. User taps "Follow" → Follow request sent
4. Success message shown
5. Button updates to "Unfollow"
#### `list.dart`
- **Purpose**: Display following/followers lists
- **Features**:
- Reusable for both Following and Followers
- Local state management
- Per-user loading states during actions
- Empty states with helpful hints
- Refresh support
- Auto-update lists when actions occur
- **Types**:
- `ActivityPubListType.following`: Shows users you follow
- `ActivityPubListType.followers`: Shows users who follow you
- **User Flow**:
1. User opens Following/Followers screen
2. List loads from API
3. User can unfollow (Following tab) or follow (Followers tab)
4. List updates automatically
5. Success/error messages shown
## Design Patterns
### Follows Project Conventions
1. **Material 3 Design**: All widgets use Material 3 components
2. **Styled Widget Package**: Used for `.padding()`, `.textColor()`, etc.
3. **Riverpod State Management**: Hooks for local state, providers for global state
4. **Error Handling**: `showErrorAlert()` from `alert.dart` for user feedback
5. **Success Feedback**: `showSnackBar()` for quick notifications
6. **Localization**: All strings use `.tr()` with placeholder args
### Color Scheme & Theming
- **Remote Badge**: Uses `Theme.colorScheme.primary` for indicator
- **Instance Tag**: Uses `Theme.colorScheme.secondaryContainer`
- **Text Colors**: Adaptive based on theme (dark/light)
- **States**: Loading indicators with standard `CircularProgressIndicator`
### Spacing & Layout
- **List Item Padding**: `EdgeInsets.only(left: 16, right: 12)`
- **Avatar Size**: 24px radius (48px diameter)
- **Badge Size**: Small (10px font) with 6px horizontal padding
- **Button Size**: Minimum 88px width, 36px height
## Translations Added
### New Keys in `assets/i18n/en-US.json`
```json
{
"searchFediverse": "Search Fediverse",
"searchFediverseHint": "Search by address, e.g. {}",
"searchFediverseEmpty": "Search for users on other ActivityPub instances",
"searchFediverseNoResults": "No users found for this search",
"following": "Following",
"followers": "Followers",
"follow": "Follow",
"unfollow": "Unfollow",
"followedUser": "Followed @{}",
"unfollowedUser": "Unfollowed @{}",
"followingEmpty": "You're not following anyone yet",
"followersEmpty": "No followers yet",
"followingEmptyHint": "Start by searching for users or explore other instances"
}
```
## Usage Examples
### Using Search Screen
```dart
import 'package:go_router/go_router.dart';
import 'package:island/screens/activitypub/activitypub.dart';
// In navigation or route
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ActivityPubSearchScreen(),
),
);
// Or using go_router
context.push('/activitypub/search');
```
### Using List Screen
```dart
// Following
ActivityPubListScreen(
type: ActivityPubListType.following,
);
// Followers
ActivityPubListScreen(
type: ActivityPubListType.followers,
);
```
### Using User List Item Widget
```dart
ActivityPubUserListItem(
user: user,
isFollowing: isFollowing,
isLoading: isLoading,
onFollow: () => handleFollow(user),
onUnfollow: () => handleUnfollow(user),
onTap: () => navigateToProfile(user),
);
```
## Integration Points
### Navigation Integration
To add ActivityPub screens to navigation:
1. **Option A**: Add to existing tab/navigation structure
2. **Option B**: Add as standalone routes in `go_router`
3. **Option C**: Add to profile menu overflow menu
### Service Integration
All screens use `activityPubServiceProvider`:
```dart
import 'package:island/services/activitypub_service.dart';
final service = ref.read(activityPubServiceProvider);
```
### Error Handling
All errors are caught and displayed using:
```dart
try {
// API call
} catch (err) {
showErrorAlert(err);
}
```
## Testing Checklist
- [ ] Search for existing Mastodon user
- [ ] Search for Pleroma user
- [ ] Follow a user
- [ ] Unfollow a user
- [ ] View following list
- [ ] View followers list
- [ ] Test empty states
- [ ] Test loading states
- [ ] Test error handling
- [ ] Test dark mode
- [ ] Test RTL languages (if supported)
## Technical Details
### Dependencies
**Already in project**:
-`cached_network_image` - For avatar images
-`easy_localization` - For translations
-`hooks_riverpod` - For state management
-`flutter_hooks` - For hooks (useState, useEffect, etc.)
-`material_symbols_icons` - For icons
-`relative_time` - For timestamp formatting
-`island/services/activitypub_service.dart` - API service (created earlier)
-`island/widgets/alert.dart` - Error/success dialogs
-`island/models/activitypub.dart` - Data models (created earlier)
### Performance Considerations
1. **Debounced Search**: 500ms delay prevents excessive API calls
2. **Local State Tracking**: `followingUris` Set prevents duplicate API calls
3. **Conditional Rebuilds**: Widget only rebuilds when necessary
4. **Image Caching**: Uses `CachedNetworkImageProvider` for avatars
### Accessibility
1. **Semantic Labels**: All ListTile widgets have proper content
2. **Touch Targets**: Minimum 44px touch targets for buttons
3. **Color Contrast**: Follows Material 3 color guidelines
4. **Loading Indicators**: Visual feedback during async operations
## Future Enhancements
### Potential Additions
1. **Profile Integration**: Show ActivityPub profile details
2. **Post Timeline**: Show federated posts from followed users
3. **Instance Blocking**: Block entire ActivityPub instances
4. **Advanced Search**: Filter by instance, user type, etc.
5. **Batch Actions**: Follow/unfollow multiple users at once
6. **Suggested Users**: Show recommended users to follow
7. **Recent Activity**: Show recent interactions
8. **Notifications**: Follow/unfollow notifications
### Localization
Need to add same keys to other language files:
- `es-ES.json`
- `ja-JP.json`
- `ko-KR.json`
- etc.
## Browser Testing
Test with real ActivityPub instances:
- mastodon.social
- pixelfed.social
- lemmy.world
- pleroma.site
- fosstodon.org
## Troubleshooting
### Common Issues
1. **Search returns no results**
- Check if user exists on remote instance
- Verify instance is accessible
- Try full URL instead of handle
2. **Follow button not working**
- Check if user is already following
- Verify server is online
- Check API logs
3. **Avatar not loading**
- Check remote avatar URL
- Verify network connection
- Check image cache
## Summary
**Fully functional ActivityPub UI** with:
- Search screen for discovering fediverse users
- Following/Followers list screens
- Reusable user list item component
- Proper error handling and user feedback
- Material 3 design
- Responsive layout
- Local state management
- Debounced search
- Empty states and loading indicators
**Ready for integration into main app navigation!** 🎉