Screens / account
Public profile
Shows someone’s public page: avatar, bio and short counters, an optimistic Follow toggle or Edit profile for yourself, then posts as a list and media as a grid.
Import
Public profile is part of Fliin Pro. With a license key, sign in once with fliin login, then add it in a Flutter app where fliin init has run:
fliin login
fliin add profileAlso installs: alert, app-bar, avatar, button, core, empty-state, page, post-card, result-card, skeleton, spinner, tabs, text
Examples
Loaded
Someone's profile: their details, counts and posts. standalone holds its own controller over the service you pass; give it yours to reach your backend.
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
class ProfileLoadedExample extends StatelessWidget {
const ProfileLoadedExample({super.key});
@override
Widget build(BuildContext context) {
return ProfileScreen.standalone(
service: SampleProfileService(latency: const Duration(milliseconds: 600)),
profileId: sampleProfileUser.id,
initial: ProfileLoaded(
sampleProfileUser,
posts: sampleProfilePosts.take(6).toList(),
more: const ProfileMoreAvailable('6'),
),
initialTab: ProfileTab.posts,
now: () => sampleProfileNow,
onBack: () {},
onEditProfile: () {},
onOpen: (_) {},
onMessage: () {},
onMore: () {},
);
}
}Following
A profile the user already follows: the main action turns into Following.
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
class ProfileFollowingExample extends StatelessWidget {
const ProfileFollowingExample({super.key});
@override
Widget build(BuildContext context) {
return ProfileScreen.standalone(
service: SampleProfileService(latency: const Duration(milliseconds: 600)),
profileId: sampleProfileUser.id,
initial: ProfileLoaded(
sampleProfileUser.withFollowed(true),
posts: sampleProfilePosts.take(6).toList(),
more: const ProfileMoreAvailable('6'),
),
initialTab: ProfileTab.posts,
now: () => sampleProfileNow,
onBack: () {},
onEditProfile: () {},
onOpen: (_) {},
onMessage: () {},
onMore: () {},
);
}
}Own
The user's own profile: editing replaces following and messaging.
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
class ProfileOwnExample extends StatelessWidget {
const ProfileOwnExample({super.key});
@override
Widget build(BuildContext context) {
return ProfileScreen.standalone(
service: SampleProfileService(latency: const Duration(milliseconds: 600)),
profileId: sampleProfileUser.id,
initial: ProfileLoaded(sampleOwnProfileUser, posts: sampleProfilePosts.skip(6).take(4).toList()),
initialTab: ProfileTab.posts,
now: () => sampleProfileNow,
onBack: () {},
onEditProfile: () {},
onOpen: (_) {},
onMessage: () {},
onMore: () {},
);
}
}Media
initialTab: ProfileTab.media opens the grid of photos.
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
class ProfileMediaExample extends StatelessWidget {
const ProfileMediaExample({super.key});
@override
Widget build(BuildContext context) {
return ProfileScreen.standalone(
service: SampleProfileService(latency: const Duration(milliseconds: 600)),
profileId: sampleProfileUser.id,
initial: ProfileLoaded(sampleProfileUser, posts: sampleProfilePosts),
initialTab: ProfileTab.media,
now: () => sampleProfileNow,
onBack: () {},
onEditProfile: () {},
onOpen: (_) {},
onMessage: () {},
onMore: () {},
);
}
}Loading
While the service answers, placeholders keep the shape of the profile.
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
class ProfileLoadingExample extends StatelessWidget {
const ProfileLoadingExample({super.key});
@override
Widget build(BuildContext context) {
return ProfileScreen.standalone(
service: SampleProfileService(latency: const Duration(milliseconds: 600)),
profileId: sampleProfileUser.id,
initial: const ProfileLoading(),
initialTab: ProfileTab.posts,
now: () => sampleProfileNow,
onBack: () {},
onEditProfile: () {},
onOpen: (_) {},
onMessage: () {},
onMore: () {},
);
}
}Error
When loading fails, the screen says so and offers to try again.
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
class ProfileErrorExample extends StatelessWidget {
const ProfileErrorExample({super.key});
@override
Widget build(BuildContext context) {
return ProfileScreen.standalone(
service: SampleProfileService(latency: const Duration(milliseconds: 600)),
profileId: sampleProfileUser.id,
initial: const ProfileFailed(),
initialTab: ProfileTab.posts,
now: () => sampleProfileNow,
onBack: () {},
onEditProfile: () {},
onOpen: (_) {},
onMessage: () {},
onMore: () {},
);
}
}Offline
Without a connection, the screen asks to reconnect rather than showing an error.
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
class ProfileOfflineExample extends StatelessWidget {
const ProfileOfflineExample({super.key});
@override
Widget build(BuildContext context) {
return ProfileScreen.standalone(
service: SampleProfileService(latency: const Duration(milliseconds: 600)),
profileId: sampleProfileUser.id,
initial: const ProfileOffline(),
initialTab: ProfileTab.posts,
now: () => sampleProfileNow,
onBack: () {},
onEditProfile: () {},
onOpen: (_) {},
onMessage: () {},
onMore: () {},
);
}
}List
The posts whole, one under the other, as in a feed: postsLayout: ProfilePostsLayout.list. Each card likes in place, opens its comments and shares.
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
class ProfileListExample extends StatelessWidget {
const ProfileListExample({super.key});
@override
Widget build(BuildContext context) {
return ProfileScreen.standalone(
service: SampleProfileService(latency: const Duration(milliseconds: 600)),
profileId: sampleProfileUser.id,
initial: ProfileLoaded(
sampleProfileUser,
posts: sampleProfilePosts.take(6).toList(),
more: const ProfileMoreAvailable('6'),
),
postsLayout: ProfilePostsLayout.list,
now: () => sampleProfileNow,
onBack: () {},
onOpen: (_) {},
onShare: (_) {},
onMessage: () {},
onMore: () {},
);
}
}Highlights
Your content between the header and the tabs: aboveTabs, here a row of highlights, and tabs that keeps only the media grid.
import 'package:your_app/ui/fliin/components/avatar/fl_avatar.dart';
import 'package:your_app/ui/fliin/components/text/fl_text.dart';
import 'package:your_app/ui/fliin/core/fliin.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
class ProfileHighlightsExample extends StatelessWidget {
const ProfileHighlightsExample({super.key});
@override
Widget build(BuildContext context) {
return ProfileScreen.standalone(
service: SampleProfileService(latency: const Duration(milliseconds: 600)),
profileId: sampleProfileUser.id,
initial: ProfileLoaded(
sampleProfileUser,
posts: sampleProfilePosts.take(6).toList(),
more: const ProfileMoreAvailable('6'),
),
tabs: const [ProfileTab.media],
aboveTabs: const _Highlights(),
now: () => sampleProfileNow,
onBack: () {},
onOpen: (_) {},
onMessage: () {},
onMore: () {},
);
}
}
class _Highlights extends StatelessWidget {
const _Highlights();
static const _names = ['Studio', 'Cups', 'Bowls', 'Markets', 'Kiln'];
@override
Widget build(BuildContext context) {
final space = FlScope.of(context).space;
final images = [for (final post in sampleProfilePosts) ...post.images];
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: EdgeInsetsDirectional.fromSTEB(space.lg, 0, space.lg, space.lg),
child: Row(
spacing: space.lg,
children: [
for (final (index, name) in _names.indexed)
Column(
spacing: space.xs,
children: [
FlAvatar(
image: images[index % images.length],
initials: name.substring(0, 1),
semanticLabel: name,
size: FlAvatarSize.lg,
),
ExcludeSemantics(child: FlText(name, type: FlTextType.bodyXs)),
],
),
],
),
);
}
}Routing
fliin add profile prints the route for the router it finds in your pubspec, a file next to the page that wires its navigation. Each of them:
go_router
// lib/profile_route.dart, next to profile_page.dart.
import 'package:go_router/go_router.dart';
import 'profile_page.dart';
/// Add profileRoute to the routes of your GoRouter.
final profileRoute = GoRoute(
path: '/profile/:id',
builder: (context, state) => ProfilePage(
id: state.pathParameters['id']!,
// Alone in the stack (deep link, go): your app's home.
onBack: () => context.canPop() ? context.pop() : context.go('/'),
onEditProfile: () => context.push('/settings/profile'),
onOpen: (post) => context.push('/post/${Uri.encodeComponent(post.id)}'),
),
);navigator
// lib/profile_route.dart, next to profile_page.dart.
import 'package:flutter/material.dart';
import 'edit_profile_route.dart';
import 'post_route.dart';
import 'profile_page.dart';
/// Opens “Public profile”: `Navigator.of(context).push(profileRoute(id))`.
Route<void> profileRoute(String id) => MaterialPageRoute<void>(
builder: (context) => ProfilePage(
id: id,
onBack: () => Navigator.of(context).maybePop(),
onEditProfile: () => Navigator.of(context).push(editProfileRoute()),
onOpen: (post) => Navigator.of(context).push(postRoute(post.id)),
),
);State
The controller is a ChangeNotifier from widgets.dart, with no package. fliin add profile prints the page that holds it with the state management it finds, its imports written for your package; below they read your_app. Your backend implements the Service interface of the screen's _data.dart file:
none
// lib/profile_page.dart
// Your backend: implement ProfileService (profile_data.dart) and pass it instead of the sample service.
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
class ProfilePage extends StatelessWidget {
const ProfilePage({
super.key,
required this.id,
required this.onBack,
required this.onEditProfile,
required this.onOpen,
});
final String id;
final VoidCallback onBack;
final VoidCallback onEditProfile;
final ValueChanged<ProfilePost> onOpen;
@override
Widget build(BuildContext context) => ProfileScreen.standalone(
service: SampleProfileService(),
profileId: id,
onBack: onBack,
onEditProfile: onEditProfile,
onOpen: onOpen,
);
}provider
// lib/profile_page.dart
// Your backend: implement ProfileService (profile_data.dart) and pass it instead of the sample service.
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
class ProfilePage extends StatelessWidget {
const ProfilePage({
super.key,
required this.id,
required this.onBack,
required this.onEditProfile,
required this.onOpen,
});
final String id;
final VoidCallback onBack;
final VoidCallback onEditProfile;
final ValueChanged<ProfilePost> onOpen;
@override
Widget build(BuildContext context) => ChangeNotifierProvider(
create: (_) => ProfileController(service: SampleProfileService(), profileId: id)..load(),
child: Builder(
builder: (context) => ProfileScreen(
controller: context.read<ProfileController>(),
onBack: onBack,
onEditProfile: onEditProfile,
onOpen: onOpen,
),
),
);
}riverpod
// lib/profile_page.dart
// Your backend: implement ProfileService (profile_data.dart) and pass it instead of the sample service.
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final profileControllerProvider = Provider.autoDispose.family<ProfileController, String>((ref, id) {
final controller = ProfileController(service: SampleProfileService(), profileId: id)..load();
ref.onDispose(controller.dispose);
return controller;
});
class ProfilePage extends ConsumerWidget {
const ProfilePage({
super.key,
required this.id,
required this.onBack,
required this.onEditProfile,
required this.onOpen,
});
final String id;
final VoidCallback onBack;
final VoidCallback onEditProfile;
final ValueChanged<ProfilePost> onOpen;
@override
Widget build(BuildContext context, WidgetRef ref) => ProfileScreen(
controller: ref.watch(profileControllerProvider(id)),
onBack: onBack,
onEditProfile: onEditProfile,
onOpen: onOpen,
);
}bloc
// lib/profile_page.dart
// Your backend: implement ProfileService (profile_data.dart) and pass it instead of the sample service.
import 'package:your_app/ui/fliin/screens/profile/profile_controller.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_data.dart';
import 'package:your_app/ui/fliin/screens/profile/profile_screen.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
/// The screen's controller as a bloc, for your BlocListener and BlocBuilder:
/// one emission per controller notification. `version` tells them apart
/// when `state` does not change (mode, filters, text…, read them on
/// `controller`). The screen listens to the controller itself.
class ProfileCubit extends Cubit<({ProfileState state, int version})> {
ProfileCubit(this.controller) : super((state: controller.state, version: 0)) {
controller.addListener(_changed);
}
final ProfileController controller;
void _changed() => emit((state: controller.state, version: state.version + 1));
@override
Future<void> close() {
controller
..removeListener(_changed)
..dispose();
return super.close();
}
}
class ProfilePage extends StatelessWidget {
const ProfilePage({
super.key,
required this.id,
required this.onBack,
required this.onEditProfile,
required this.onOpen,
});
final String id;
final VoidCallback onBack;
final VoidCallback onEditProfile;
final ValueChanged<ProfilePost> onOpen;
@override
Widget build(BuildContext context) => BlocProvider(
create: (_) => ProfileCubit(ProfileController(service: SampleProfileService(), profileId: id)..load()),
child: Builder(
builder: (context) => ProfileScreen(
controller: context.read<ProfileCubit>().controller,
onBack: onBack,
onEditProfile: onEditProfile,
onOpen: onOpen,
),
),
);
}The snippets lead to edit-profile, post: install these screens too and paste their snippets.
API
ProfileTab: enum {posts, media}
ProfileTab.posts: static final ProfileTab
ProfileTab.media: static final ProfileTab
ProfilePostsLayout: enum {grid, list}
ProfilePostsLayout.grid: static final ProfilePostsLayout
ProfilePostsLayout.list: static final ProfilePostsLayout
ProfileScreen: class extends StatefulWidget
ProfileScreen.new: const new({super.key, required ProfileController controller, ProfileTab initialTab, VoidCallback? onBack, VoidCallback? onEditProfile, ValueChanged<ProfilePost>? onOpen, VoidCallback? onMessage, VoidCallback? onMore, ValueChanged<ProfilePost>? onShare, ProfilePostsLayout postsLayout, List<ProfileTab> tabs, Widget? aboveTabs, DateTime Function() now})
ProfileScreen.standalone: const new({super.key, required ProfileService service, required String profileId, ProfileState? initial, ProfileTab initialTab, VoidCallback? onBack, VoidCallback? onEditProfile, ValueChanged<ProfilePost>? onOpen, VoidCallback? onMessage, VoidCallback? onMore, ValueChanged<ProfilePost>? onShare, ProfilePostsLayout postsLayout, List<ProfileTab> tabs, Widget? aboveTabs, DateTime Function() now})
ProfileScreen.controller: get ProfileController?
ProfileScreen.service: get ProfileService?
ProfileScreen.profileId: get String?
ProfileScreen.initial: get ProfileState?
ProfileScreen.initialTab: get ProfileTab
ProfileScreen.onBack: get VoidCallback?
ProfileScreen.onEditProfile: get VoidCallback?
ProfileScreen.onOpen: get ValueChanged<ProfilePost>?
ProfileScreen.onMessage: get VoidCallback?
ProfileScreen.onMore: get VoidCallback?
ProfileScreen.now: get DateTime Function()
ProfileScreen.onShare: get ValueChanged<ProfilePost>?
ProfileScreen.postsLayout: get ProfilePostsLayout
ProfileScreen.tabs: get List<ProfileTab>
ProfileScreen.aboveTabs: get Widget?
ProfileScreen.createState: State<ProfileScreen>()
ProfileState: sealed class permits {ProfileFailed, ProfileLoaded, ProfileLoading, ProfileOffline}
ProfileState.new: const new()
ProfileLoading: final class extends ProfileState
ProfileLoading.new: const new()
ProfileFailed: final class extends ProfileState
ProfileFailed.new: const new()
ProfileOffline: final class extends ProfileState
ProfileOffline.new: const new()
ProfileMore: sealed class permits {ProfileMoreAvailable, ProfileMoreEnd, ProfileMoreFailed, ProfileMoreLoading}
ProfileMore.new: const new()
ProfileMoreAvailable: final class extends ProfileMore
ProfileMoreAvailable.new: const new(String? after)
ProfileMoreAvailable.after: get String?
ProfileMoreLoading: final class extends ProfileMore
ProfileMoreLoading.new: const new(String? after)
ProfileMoreLoading.after: get String?
ProfileMoreFailed: final class extends ProfileMore
ProfileMoreFailed.new: const new(String? after, {required bool offline})
ProfileMoreFailed.after: get String?
ProfileMoreFailed.offline: get bool
ProfileMoreEnd: final class extends ProfileMore
ProfileMoreEnd.new: const new()
ProfileNotice: enum {followFailed, likeFailed}
ProfileNotice.followFailed: static final ProfileNotice
ProfileNotice.likeFailed: static final ProfileNotice
ProfileLoaded: final class extends ProfileState
ProfileLoaded.new: const new(ProfileUser user, {List<ProfilePost> posts, ProfileMore more, ProfileNotice? notice})
ProfileLoaded.user: get ProfileUser
ProfileLoaded.posts: get List<ProfilePost>
ProfileLoaded.more: get ProfileMore
ProfileLoaded.notice: get ProfileNotice?
ProfileController: class extends ChangeNotifier
ProfileController.new: new({required ProfileService service, required String profileId, ProfileState initial})
ProfileController.service: get ProfileService
ProfileController.profileId: get String
ProfileController.state: get ProfileState
ProfileController.load: Future<void>()
ProfileController.loadMore: Future<bool>()
ProfileController.toggleFollow: bool()
ProfileController.toggleLike: bool(String postId)
ProfileController.dispose: void()
ProfileUser: final class
ProfileUser.new: const new({required String id, required String name, required String handle, required String initials, ImageProvider? avatar, String bio, int posts, int followers, int following, bool followed, bool me})
ProfileUser.id: get String
ProfileUser.name: get String
ProfileUser.handle: get String
ProfileUser.initials: get String
ProfileUser.avatar: get ImageProvider?
ProfileUser.bio: get String
ProfileUser.posts: get int
ProfileUser.followers: get int
ProfileUser.following: get int
ProfileUser.followed: get bool
ProfileUser.me: get bool
ProfileUser.withFollowed: ProfileUser(bool followed)
ProfilePost: final class
ProfilePost.new: const new({required String id, required DateTime at, String text, List<ImageProvider> images, int likes, bool liked, int comments})
ProfilePost.id: get String
ProfilePost.at: get DateTime
ProfilePost.text: get String
ProfilePost.images: get List<ImageProvider>
ProfilePost.likes: get int
ProfilePost.liked: get bool
ProfilePost.comments: get int
ProfilePost.withLiked: ProfilePost(bool liked)
ProfilePostPage: final class
ProfilePostPage.new: const new(List<ProfilePost> posts, {String? next})
ProfilePostPage.posts: get List<ProfilePost>
ProfilePostPage.next: get String?
ProfileNoNetwork: final class implements Exception
ProfileNoNetwork.new: const new()
ProfileNoNetwork.toString: String()
ProfileService: abstract interface class
ProfileService.new: new()
ProfileService.load: abstract Future<ProfileUser>(String profileId)
ProfileService.posts: abstract Future<ProfilePostPage>(String profileId, {String? after})
ProfileService.setFollowing: abstract Future<void>(String profileId, bool following)
ProfileService.setLiked: abstract Future<void>(String postId, bool liked)
sampleProfileNow: get DateTime
sampleProfileUser: const dynamic
sampleOwnProfileUser: const dynamic
sampleProfilePosts: get List<ProfilePost>
SampleProfileService: final class implements ProfileService
SampleProfileService.new: new({ProfileUser profile, List<ProfilePost>? posts, int pageSize, Duration latency})
SampleProfileService.profile: get ProfileUser
SampleProfileService.pageSize: get int
SampleProfileService.latency: get Duration
SampleProfileService.load: Future<ProfileUser>(String profileId)
SampleProfileService.posts: Future<ProfilePostPage>(String profileId, {String? after})
SampleProfileService.setFollowing: Future<void>(String profileId, bool following)
SampleProfileService.setLiked: Future<void>(String postId, bool liked)
profileL10n: const Map<String, Map<String, String>>
ProfileStrings: final class
ProfileStrings.new: const new(String language)
ProfileStrings.of: factory new(BuildContext context)
ProfileStrings.language: get String
ProfileStrings.title: get String
ProfileStrings.back: get String
ProfileStrings.loading: get String
ProfileStrings.follow: get String
ProfileStrings.followingButton: get String
ProfileStrings.followed: String(String name, bool followed)
ProfileStrings.edit: get String
ProfileStrings.message: get String
ProfileStrings.more: get String
ProfileStrings.post: String(String age, String text)
ProfileStrings.handle: String(String handle)
ProfileStrings.postsTab: get String
ProfileStrings.mediaTab: get String
ProfileStrings.postsLabel: get String
ProfileStrings.followersLabel: get String
ProfileStrings.followingLabel: get String
ProfileStrings.posts: String(int count)
ProfileStrings.followers: String(int count)
ProfileStrings.following: String(int count)
ProfileStrings.like: String(String age)
ProfileStrings.liked: String(bool liked)
ProfileStrings.comment: String(String age)
ProfileStrings.share: String(String age)
ProfileStrings.photo: String(String age)
ProfileStrings.photoOf: String(int index, int count, String age)
ProfileStrings.likes: String(int count)
ProfileStrings.comments: String(int count)
ProfileStrings.photos: String(int count)
ProfileStrings.noPosts: get String
ProfileStrings.noMedia: get String
ProfileStrings.loadingMore: get String
ProfileStrings.moreFailed: get String
ProfileStrings.moreOffline: get String
ProfileStrings.followFailed: get String
ProfileStrings.likeFailed: get String
ProfileStrings.errorTitle: get String
ProfileStrings.errorMessage: get String
ProfileStrings.offlineTitle: get String
ProfileStrings.offlineMessage: get String
ProfileStrings.retry: get String
ProfileStrings.format: get FlCountFormat
ProfileStrings.count: FlPostCount(int count, String Function(int count) read)
ProfileStrings.age: String(FlPostAge age)Strings
Every label in English, French and Arabic. The screen follows the closest Localizations; the same table is in the manifest, ready for your ARB files.
| Key | en | fr | ar |
|---|---|---|---|
profileTitle | Profile | Profil | الملف الشخصي |
profileBack | Back | Retour | رجوع |
profileLoading | Loading the profile | Chargement du profil | جارٍ تحميل الملف الشخصي |
profileFollow | Follow | Suivre | متابعة |
profileFollowingButton | Following | Abonné | تتابعه |
profileFollowed | You follow {name} | Vous suivez {name} | أنت تتابع {name} |
profileUnfollowed | You no longer follow {name} | Vous ne suivez plus {name} | لم تعد تتابع {name} |
profileEdit | Edit profile | Modifier le profil | تعديل الملف الشخصي |
profileMessage | Message | Message | مراسلة |
profileMore | More actions | Plus d’actions | مزيد من الإجراءات |
profilePost | Post from {age}: {text} | Publication de {age} : {text} | منشور {age}: {text} |
profileHandle | @{handle} | @{handle} | @{handle} |
profilePostsTab | Posts | Publications | المنشورات |
profileMediaTab | Media | Médias | الوسائط |
profilePostsLabel | Posts | Publications | منشورات |
profileFollowersLabel | Followers | Abonnés | متابِعون |
profileFollowingLabel | Following | Abonnements | يتابع |
profilePostsOne | {count} post | {count} publication | منشور واحد |
profilePostsMany | {count} posts | {count} publications | المنشورات: {count} |
profileFollowersOne | {count} follower | {count} abonné | متابِع واحد |
profileFollowersMany | {count} followers | {count} abonnés | المتابِعون: {count} |
profileFollowingOne | Follows {count} person | {count} abonnement | يتابع شخصًا واحدًا |
profileFollowingMany | Follows {count} people | {count} abonnements | يتابع: {count} |
profileLike | Like, post from {age} | J’aime, publication de {age} | إعجاب، منشور {age} |
profileLiked | Liked | J’aime ajouté | تم الإعجاب |
profileUnliked | Like removed | J’aime retiré | أُلغي الإعجاب |
profileComment | Comment, post from {age} | Commenter, publication de {age} | تعليق، منشور {age} |
profileShare | Share, post from {age} | Partager, publication de {age} | مشاركة، منشور {age} |
profilePhoto | Photo, post from {age} | Photo, publication de {age} | صورة، منشور {age} |
profilePhotoOf | Photo {index} of {count}, post from {age} | Photo {index} sur {count}, publication de {age} | صورة {index} من {count}، منشور {age} |
profileLikesOne | {count} like | {count} J’aime | إعجاب واحد |
profileLikesMany | {count} likes | {count} J’aime | الإعجابات: {count} |
profileCommentsOne | {count} comment | {count} commentaire | تعليق واحد |
profileCommentsMany | {count} comments | {count} commentaires | التعليقات: {count} |
profilePhotosOne | {count} photo | {count} photo | صورة واحدة |
profilePhotosMany | {count} photos | {count} photos | الصور: {count} |
profileNoPosts | No posts yet. | Aucune publication pour l’instant. | لا منشورات بعد. |
profileNoMedia | No photos yet. | Aucune photo pour l’instant. | لا صور بعد. |
profileLoadingMore | Loading more posts | Chargement de la suite | جارٍ تحميل المزيد |
profileMoreFailed | Posts couldn’t load. | Les publications n’ont pas pu se charger. | تعذّر تحميل المنشورات. |
profileMoreOffline | You are offline. Posts can’t load. | Vous êtes hors ligne. Les publications ne peuvent pas se charger. | أنت غير متصل. لا يمكن تحميل المنشورات. |
profileFollowFailed | Couldn’t update who you follow. | Impossible de mettre à jour vos abonnements. | تعذّر تحديث من تتابع. |
profileLikeFailed | Your like wasn’t saved. | Votre J’aime n’a pas été enregistré. | لم يُحفظ إعجابك. |
profileErrorTitle | This profile could not load | Impossible de charger ce profil | تعذّر تحميل هذا الملف الشخصي |
profileErrorMessage | Something went wrong on our side. | Un problème est survenu de notre côté. | حدثت مشكلة من جهتنا. |
profileOfflineTitle | You are offline | Vous êtes hors ligne | أنت غير متصل |
profileOfflineMessage | Check your connection, then try again. | Vérifiez votre connexion, puis réessayez. | تحقق من اتصالك ثم أعد المحاولة. |
profileRetry | Try again | Réessayer | أعد المحاولة |
profileNow | Now | À l’instant | الآن |
profileMinutes | {count} min | {count} min | {count} د |
profileHours | {count} h | {count} h | {count} س |
profileDays | {count} d | {count} j | {count} ي |
profileDate | {month}/{day}/{year} | {day}/{month}/{year} | {day}/{month}/{year} |
profileDecimal | . | , | ٫ |
profileGroup | , | ٬ | |
profileThousands | K | k | ألف |
profileMillions | M | M | مليون |
profileBillions | B | Md | مليار |
profileDigits | 0123456789 | 0123456789 | ٠١٢٣٤٥٦٧٨٩ |
Reference renders
The 16 images published with version 0.3.2, rendered by the shared harness on macOS with Flutter 3.47.7. Each shows every state side by side, at the size of an iPhone (390 × 844) or of an Android phone (412 × 915). fliin verify profile compares your copy to them.
















Use it to
- show someone's public page with follower counts
- toggle following a person with one tap, saved by the server afterwards
- show the images someone posted as a grid
- offer to edit your own profile from your public page
- switch between the posts and the media of an account
- Not for
- the user's account settings: use account settings (account-settings)
- the form that changes the name or photo: use edit profile (edit-profile)
- States